get_child_views = async (table, viewname, nrecurse = 2) => {
  const rels = await Field.find(
    { reftable_name: table.name },
    { cached: true }
  );
  const possibleThroughTables = new Set();
  let child_views = [];
  for (const relation of rels) {
    const related_table = Table.findOne({ id: relation.table_id });
    const views = await View.find_table_views_where(
      related_table.id,
      ({ state_fields, viewrow }) =>
        viewrow.name !== viewname && state_fields.every((sf) => !sf.required)
    );
    child_views.push({ relation, related_table, views });
    possibleThroughTables.add(`${related_table.name}.${relation.name}`);
  }
  if (nrecurse > 0)
    for (const possibleThroughTable of possibleThroughTables) {
      const [tableName, fieldName] = possibleThroughTable.split(".");
      const reltable = Table.findOne({ name: tableName });
      const relfields = await reltable.getFields();
      const relfield = relfields.find((f) => f.name === fieldName);
      const cviews = await get_child_views(reltable, null, nrecurse - 1);
      for (const { relation, related_table, views } of cviews)
        child_views.push({
          relation,
          related_table,
          through: relfield,
          throughTable: reltable,
          views,
        });
    }
  return child_views;
}
Get Child Views
@function
@param {Table|object} table
@param {string} viewname
@param nrecurse
@returns {Promise<object[]>}