get_inbound_path_suffixes = async (
  targetTbl,
  srcTable,
  levelPath,
  tableCache,
  fieldCache
) => {
  const result = [];
  // fks from targetTbl
  for (const fkToRelTbl of targetTbl.getForeignKeys()) {
    const relTblName = fkToRelTbl.reftable_name;
    if (relTblName === srcTable.name) continue;
    // inbounds to the target of fk
    const inboundFks = fieldCache[relTblName]
      ? fieldCache[relTblName].filter(
          (field) =>
            field.table_id !== targetTbl.id &&
            !levelPath.find(
              (val) => val.tbl === targetTbl.name && val.fk === fkToRelTbl.name
            )
        )
      : [];
    for (const inboundFk of inboundFks) {
      const inboundTable = tableCache[inboundFk.table_id];
      if (inboundTable) {
        const relTblRefs = inboundTable
          .getForeignKeys()
          .filter((f) => f.reftable_name === relTblName);
        // the inbound comes from 'srcTable'
        if (inboundTable.id === srcTable.id) {
          const levels = levelPath.map((val) => val.fk).join(".");
          for (const inboundRelTblKey of relTblRefs) {
            const newSuffix = `.${srcTable.name}.${inboundRelTblKey.name}.${
              targetTbl.name
            }$${fkToRelTbl.name}${levels ? `.${levels}` : ""}`;
            if (result.indexOf(newSuffix) === -1) {
              result.push(newSuffix);
            }
          }
        } else {
          // check if there are refs to 'srcTable'
          const srcRefs = inboundTable
            .getForeignKeys()
            .filter((f) => f.reftable_name === srcTable.name);
          for (const srcTblRef of srcRefs) {
            for (const relTblRef of relTblRefs) {
              if (levelPath.length > 0) {
                let levels = `${levelPath[0].tbl}$${fkToRelTbl.name}`;
                for (let i = 0; i < levelPath.length; i++) {
                  levels = `${levels}.${levelPath[i].fk}`;
                }
                const newSuffix =
                  `.${srcTable.name}.${inboundTable.name}$${srcTblRef.name}.${relTblRef.name}.` +
                  `${levels}`;
                if (result.indexOf(newSuffix) === -1) {
                  result.push(newSuffix);
                }
              } else {
                const newSuffix = `.${srcTable.name}.${inboundTable.name}$${srcTblRef.name}.${relTblRef.name}.${targetTbl.name}$${fkToRelTbl.name}`;
                if (result.indexOf(newSuffix) === -1) {
                  result.push(newSuffix);
                }
              }
            }
          }
        }
      }
    }
  }
  return result;
}
helper for 'get_inbound_relation_opts'
@param {Table} targetTbl table to check for an Inbound relation
@param {Table} srcTable table of the top view
@param {string[]} levelPath inbound levels already visited
@param {*} tableCache helper cache so that we don't have to call Table.findOne() all the time
@param {*} fieldCache helper cache so that we don't have to call Field.find() all the time
@returns