joist-core 2.3.0-next.99 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/EntityManager.cjs +1 -1
- package/build/EntityManager.cjs.map +1 -1
- package/build/EntityManager.d.cts +9 -8
- package/build/EntityManager.d.cts.map +1 -1
- package/build/EntityManager.d.mts +9 -8
- package/build/EntityManager.d.mts.map +1 -1
- package/build/EntityManager.js +1 -1
- package/build/EntityManager.js.map +1 -1
- package/build/dataloaders/findCountDataLoader.cjs +2 -0
- package/build/dataloaders/findCountDataLoader.cjs.map +1 -1
- package/build/dataloaders/findCountDataLoader.d.cts.map +1 -1
- package/build/dataloaders/findCountDataLoader.d.mts.map +1 -1
- package/build/dataloaders/findCountDataLoader.js +2 -0
- package/build/dataloaders/findCountDataLoader.js.map +1 -1
- package/build/dataloaders/findDataLoader.cjs +1 -0
- package/build/dataloaders/findDataLoader.cjs.map +1 -1
- package/build/dataloaders/findDataLoader.d.cts.map +1 -1
- package/build/dataloaders/findDataLoader.d.mts.map +1 -1
- package/build/dataloaders/findDataLoader.js +2 -1
- package/build/dataloaders/findDataLoader.js.map +1 -1
- package/build/dataloaders/findIdsDataLoader.cjs +2 -0
- package/build/dataloaders/findIdsDataLoader.cjs.map +1 -1
- package/build/dataloaders/findIdsDataLoader.d.cts.map +1 -1
- package/build/dataloaders/findIdsDataLoader.d.mts.map +1 -1
- package/build/dataloaders/findIdsDataLoader.js +2 -0
- package/build/dataloaders/findIdsDataLoader.js.map +1 -1
- package/build/dataloaders/findPaginatedDataLoader.cjs +2 -0
- package/build/dataloaders/findPaginatedDataLoader.cjs.map +1 -1
- package/build/dataloaders/findPaginatedDataLoader.d.cts.map +1 -1
- package/build/dataloaders/findPaginatedDataLoader.d.mts.map +1 -1
- package/build/dataloaders/findPaginatedDataLoader.js +2 -0
- package/build/dataloaders/findPaginatedDataLoader.js.map +1 -1
- package/build/index.cjs +6 -3
- package/build/index.cjs.map +1 -1
- package/build/index.d.cts +6 -4
- package/build/index.d.cts.map +1 -1
- package/build/index.d.mts +6 -4
- package/build/index.d.mts.map +1 -1
- package/build/index.js +6 -5
- package/build/index.js.map +1 -1
- package/build/keys.cjs +6 -1
- package/build/keys.cjs.map +1 -1
- package/build/keys.d.cts +3 -1
- package/build/keys.d.cts.map +1 -1
- package/build/keys.d.mts +3 -1
- package/build/keys.d.mts.map +1 -1
- package/build/keys.js +6 -2
- package/build/keys.js.map +1 -1
- package/build/queries/find/QueryParser.cjs +1 -2
- package/build/queries/find/QueryParser.cjs.map +1 -1
- package/build/queries/find/QueryParser.d.cts.map +1 -1
- package/build/queries/find/QueryParser.d.mts.map +1 -1
- package/build/queries/find/QueryParser.js +2 -3
- package/build/queries/find/QueryParser.js.map +1 -1
- package/build/queries/find/QueryVisitor.cjs +17 -0
- package/build/queries/find/QueryVisitor.cjs.map +1 -1
- package/build/queries/find/QueryVisitor.d.cts +3 -1
- package/build/queries/find/QueryVisitor.d.cts.map +1 -1
- package/build/queries/find/QueryVisitor.d.mts +3 -1
- package/build/queries/find/QueryVisitor.d.mts.map +1 -1
- package/build/queries/find/QueryVisitor.js +17 -1
- package/build/queries/find/QueryVisitor.js.map +1 -1
- package/build/queries/sql/Expr.cjs +18 -1
- package/build/queries/sql/Expr.cjs.map +1 -1
- package/build/queries/sql/Expr.d.cts +13 -3
- package/build/queries/sql/Expr.d.cts.map +1 -1
- package/build/queries/sql/Expr.d.mts +13 -3
- package/build/queries/sql/Expr.d.mts.map +1 -1
- package/build/queries/sql/Expr.js +18 -2
- package/build/queries/sql/Expr.js.map +1 -1
- package/build/queries/sql/JoinTree.cjs +72 -0
- package/build/queries/sql/JoinTree.cjs.map +1 -0
- package/build/queries/sql/JoinTree.d.cts +107 -0
- package/build/queries/sql/JoinTree.d.cts.map +1 -0
- package/build/queries/sql/JoinTree.d.mts +107 -0
- package/build/queries/sql/JoinTree.d.mts.map +1 -0
- package/build/queries/sql/JoinTree.js +71 -0
- package/build/queries/sql/JoinTree.js.map +1 -0
- package/build/queries/sql/Tables.cjs +103 -6
- package/build/queries/sql/Tables.cjs.map +1 -1
- package/build/queries/sql/Tables.d.cts +72 -13
- package/build/queries/sql/Tables.d.cts.map +1 -1
- package/build/queries/sql/Tables.d.mts +72 -13
- package/build/queries/sql/Tables.d.mts.map +1 -1
- package/build/queries/sql/Tables.js +101 -10
- package/build/queries/sql/Tables.js.map +1 -1
- package/build/queries/sql/custom.cjs +52 -0
- package/build/queries/sql/custom.cjs.map +1 -0
- package/build/queries/sql/custom.d.cts +85 -0
- package/build/queries/sql/custom.d.cts.map +1 -0
- package/build/queries/sql/custom.d.mts +85 -0
- package/build/queries/sql/custom.d.mts.map +1 -0
- package/build/queries/sql/custom.js +49 -0
- package/build/queries/sql/custom.js.map +1 -0
- package/build/queries/sql/execute.cjs +68 -28
- package/build/queries/sql/execute.cjs.map +1 -1
- package/build/queries/sql/execute.d.cts +110 -11
- package/build/queries/sql/execute.d.cts.map +1 -1
- package/build/queries/sql/execute.d.mts +110 -11
- package/build/queries/sql/execute.d.mts.map +1 -1
- package/build/queries/sql/execute.js +69 -29
- package/build/queries/sql/execute.js.map +1 -1
- package/build/queries/sql/expressions/types.d.cts +5 -5
- package/build/queries/sql/expressions/types.d.cts.map +1 -1
- package/build/queries/sql/expressions/types.d.mts +5 -5
- package/build/queries/sql/expressions/types.d.mts.map +1 -1
- package/build/queries/sql/keywords.cjs +1 -1
- package/build/queries/sql/keywords.cjs.map +1 -1
- package/build/queries/sql/keywords.d.cts +1 -1
- package/build/queries/sql/keywords.d.mts +1 -1
- package/build/queries/sql/keywords.js +1 -1
- package/build/queries/sql/keywords.js.map +1 -1
- package/build/queries/sql/query.cjs +100 -38
- package/build/queries/sql/query.cjs.map +1 -1
- package/build/queries/sql/query.d.cts +96 -46
- package/build/queries/sql/query.d.cts.map +1 -1
- package/build/queries/sql/query.d.mts +96 -46
- package/build/queries/sql/query.d.mts.map +1 -1
- package/build/queries/sql/query.js +102 -40
- package/build/queries/sql/query.js.map +1 -1
- package/build/queries/valueFilters.cjs +28 -36
- package/build/queries/valueFilters.cjs.map +1 -1
- package/build/queries/valueFilters.d.cts +2 -4
- package/build/queries/valueFilters.d.cts.map +1 -1
- package/build/queries/valueFilters.d.mts +2 -4
- package/build/queries/valueFilters.d.mts.map +1 -1
- package/build/queries/valueFilters.js +29 -36
- package/build/queries/valueFilters.js.map +1 -1
- package/build/serde/serde.cjs.map +1 -1
- package/build/serde/serde.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryParser.cjs","names":["ConditionBuilder","abbreviation","filterSoftDeletes","getBaseMeta","isScope","parseEntityFilter","isAlias","kq","kqDot","getAliasMgmt","resolveScope","newAlias","isScopeJoinFilter","fail","isNilIdValue","getConstructorFromTaggedId","groupBy","mapToDb","keyToNumber","maybeResolveReferenceToId","getMaybeCtiAlias","alias","lazyExcludedSelects","getMetadataForTable","isDeferredCondition","predicateBrand","isDeferredAliasCondition","deferredAliasSym","stiSubtypeFilter"],"sources":["../../../src/queries/find/QueryParser.ts"],"sourcesContent":["import { groupBy } from \"joist-utils\";\nimport { getConstructorFromTaggedId, getMetadataForTable } from \"src/configure.ts\";\nimport type { Entity } from \"src/Entity.ts\";\nimport { type EntityMetadata, type Field, getBaseMeta } from \"src/EntityMetadata.ts\";\nimport { keyToNumber, maybeResolveReferenceToId } from \"src/keys.ts\";\nimport { ConditionBuilder } from \"src/queries/ConditionBuilder.ts\";\nimport { type ConditionInput, predicateBrand } from \"src/queries/conditions.ts\";\nimport { filterSoftDeletes, lazyExcludedSelects, stiSubtypeFilter } from \"src/queries/entityQueryUtils.ts\";\nimport {\n type AliasMgmt,\n getAliasMgmt,\n getMaybeCtiAlias,\n isAlias,\n alias as newAlias,\n} from \"src/queries/find/Aliases.ts\";\nimport { deferredAliasSym, isDeferredAliasCondition } from \"src/queries/find/DeferredAlias.ts\";\nimport type { ExpressionFilter, OrderBy } from \"src/queries/find/EntityFilter.ts\";\nimport { pruneUnusedJoins } from \"src/queries/find/QueryParser.pruning.ts\";\nimport { visitConditions } from \"src/queries/find/QueryVisitor.ts\";\nimport { type Scope, isScope, isScopeJoinFilter, resolveScope } from \"src/queries/find/scopes.ts\";\nimport type { ColumnCondition, ParsedExpressionFilter, RawCondition } from \"src/queries/parsedConditions.ts\";\nimport { isDeferredCondition } from \"src/queries/sql/Expr.ts\";\nimport { kq, kqDot } from \"src/queries/sql/keywords.ts\";\nimport {\n type ParsedEntityFilter,\n isNilIdValue,\n mapToDb,\n parseEntityFilter,\n parseValueFilter,\n} from \"src/queries/valueFilters.ts\";\nimport { abbreviation, fail } from \"src/utils.ts\";\n\n// `skipCondition` lives in its own leaf module, shared by domain aliases and SQL expressions\n// without a load-order cycle; `index.ts` re-exports it directly.\n\nexport interface PrimaryTable {\n join: \"primary\";\n alias: string;\n table: string;\n}\n\nexport interface JoinTable {\n join: \"inner\" | \"outer\";\n alias: string;\n table: string;\n col1: string;\n col2: string;\n distinct?: boolean;\n /**\n * Metadata used by `optimizeCollectionJoins` to rewrite collection joins into EXISTS.\n *\n * I.e. for `Author.books.reviews`:\n * ```sql\n * authors a\n * LEFT JOIN books b ON a.id = b.author_id\n * LEFT JOIN book_reviews br ON b.id = br.book_id\n * ```\n * `books b` has `parentAlias: \"a\"` and `rootAlias: \"b\"`, while `book_reviews br` has\n * `parentAlias: \"b\"` and `rootAlias: \"br\"`.\n *\n * I.e. for `Author.tags`, the m2m join table is the collection root:\n * ```sql\n * authors a\n * LEFT JOIN authors_to_tags att ON a.id = att.author_id\n * LEFT JOIN tags t ON att.tag_id = t.id\n * ```\n * `authors_to_tags att` has `alias: \"att\"` and `rootAlias: \"att\"`, while `tags t` has `alias: \"t\"`\n * but still has `rootAlias: \"att\"` because it belongs to the m2m subtree rooted at the join table.\n */\n collection?: {\n /** The collection relation type, i.e. `o2m` for `Author.books`, or `m2m` for `Author.tags`. */\n kind: \"o2m\" | \"m2m\";\n /** The alias that owns this collection path, i.e. `a` for `Author.books`, or `att` for `Author.tags -> tags`. */\n parentAlias: string;\n /** The top-level alias in this collection subtree, i.e. `b` for `Author.books.reviews`, or `att` for `Author.tags`. */\n rootAlias: string;\n };\n}\n\n/**\n * Creates a `CROSS JOIN`, currently used for our `em.find` batching.\n *\n * I.e. queries like:\n *\n * ```sql\n * WITH _find (tag, arg1, arg2) AS (VALUES\n * (0::int, 'a'::varchar, 'a'::varchar),\n * (1, 'b', 'b'),\n * (2, 'c', 'c')\n * )\n * SELECT a.*, array_agg(_find.tag) AS _tags\n * FROM authors a\n * CROSS JOIN _find AS _find\n * WHERE a.first_name = _find.arg0 OR a.last_name = _find.arg1\n * GROUP BY a.id\n * ```\n */\nexport interface CrossJoinTable {\n join: \"cross\";\n /** The new alias for the joined table. */\n alias: string;\n /** The table name to join into the query. */\n table: string;\n}\n\n/**\n * Adds `WITH` CTE clauses to the query.\n *\n * I.e. queries like:\n *\n * ```sql\n * WITH _find (tag, arg0, arg1) AS (\n * VALUES ($1::int, $2::character varying, $3::character varying), ($4, $5, $6)\n * )\n * ```\n */\nexport interface ParsedCteClause {\n /** The new alias for the CTE, i.e. `_find` in the above query. */\n alias: string;\n /** The columns, i.e. `tag, arg0, arg1` in the above query. */\n columns?: { columnName: string; dbType: string }[];\n /** The subquery for the AS of the CTE clause. */\n query: { kind: \"raw\"; sql: string; bindings: readonly any[] } | { kind: \"ast\"; query: ParsedFindQuery };\n /** Whether to include a `RECURSIVE` keyword after the `WITH`. */\n recursive?: boolean;\n}\n\n/**\n * Creates `LATERAL JOIN`s, currently used by `findCount` and JSON preloading.\n */\nexport interface LateralJoinTable {\n join: \"lateral\";\n alias: string;\n /** Used for join dependency tracking. */\n fromAlias: string;\n /** Used more for bookkeeping/consistency with other join tables than the query itself. */\n table: string;\n /** The subquery that will look for/roll-up N children. */\n query: ParsedFindQuery;\n /** Optional settings for the subquery, i.e. per-parent pagination. */\n settings?: { limit?: number; offset?: number };\n}\n\nexport type ParsedTable = PrimaryTable | JoinTable | CrossJoinTable | LateralJoinTable;\n\nexport interface ParsedOrderBy {\n alias: string;\n column: string;\n order: OrderBy;\n}\n\nexport type ParsedGroupBy = { alias: string; column: string } | { expression: string };\n\nexport type ParsedSelect = string | ParsedSelectWithBindings;\ntype ParsedSelectWithBindings = { sql: string; bindings: any[]; aliases: string[] };\n\n/** The result of parsing an `em.find` filter. */\nexport interface ParsedFindQuery {\n selects: ParsedSelect[];\n /** The primary table plus any joins. */\n tables: ParsedTable[];\n /** The query's conditions. */\n condition?: ParsedExpressionFilter;\n /** Extremely optional group bys; we generally don't support adhoc/aggregate queries, but the auto-batching infra uses these. */\n groupBys?: ParsedGroupBy[];\n /** Any optional orders to add before the default 'order by id'. */\n orderBys: ParsedOrderBy[];\n /** Optional CTE to prefix to the query, i.e. for recursive relations. */\n ctes?: ParsedCteClause[];\n}\n\n/**\n * Parses an `em.find` filter into a logical `ParsedFindQuery` AST, leaving optimization/pruning to callers.\n *\n * The main execution flow is:\n * parseFindQuery -> beforeFind plugins -> optimizeCollectionJoins -> pruneUnusedJoins -> execute SQL.\n */\nexport function parseFindQuery(\n meta: EntityMetadata,\n filter: any,\n opts: {\n conditions?: ExpressionFilter;\n orderBy?: any;\n pruneJoins?: boolean;\n keepAliases?: string[];\n softDeletes?: \"include\" | \"exclude\";\n allowMultipleLeftJoins?: boolean;\n optimizeJoinsToExists?: boolean;\n } = {},\n): ParsedFindQuery {\n const selects: string[] = [];\n const tables: ParsedTable[] = [];\n const orderBys: ParsedOrderBy[] = [];\n const query: ParsedFindQuery = { selects, tables, orderBys };\n const { orderBy, conditions: optsExpression, softDeletes = \"exclude\", pruneJoins = false, keepAliases = [] } = opts;\n const cb = new ConditionBuilder();\n // Where each user-created `alias(...)` is bound in this parse's join literal; alias-built conditions\n // (`a.firstName.eq(...)`) are resolved against it once the whole tree is walked\n const aliasBindings = new Map<AliasMgmt, { meta: EntityMetadata; alias: string }>();\n\n const aliases: Record<string, number> = {};\n function getAlias(tableName: string): string {\n const abbrev = abbreviation(tableName);\n const i = aliases[abbrev] || 0;\n aliases[abbrev] = i + 1;\n return i === 0 ? abbrev : `${abbrev}${i}`;\n }\n\n /** Adds a `deleted_at IS NULL` condition for `alias`, i.e. for the primary table or a collection join. */\n function addSoftDeleteCondition(meta: EntityMetadata, alias: string, targetCb: ConditionBuilder): void {\n if (filterSoftDeletes(meta, softDeletes)) {\n const column = meta.allFields[getBaseMeta(meta).timestampFields!.deletedAt!].serde?.columns[0]!;\n targetCb.addSimpleCondition({\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n cond: { kind: \"is-null\" },\n pruneable: true,\n });\n }\n }\n\n function addTable(\n meta: EntityMetadata,\n alias: string,\n join: ParsedTable[\"join\"],\n col1: string,\n col2: string,\n filter: any,\n fieldName?: string,\n targetCb: ConditionBuilder = cb,\n /** Whether this table is the \"other side\" of a collection, i.e. `books` in `em.find(Author, { books: ... })`. */\n isCollection: boolean = false,\n ): void {\n // look at filter, is it `{ book: \"b2\" }` or `{ book: { ... } }`\n const scopeFilter = isScope(filter);\n const ef = scopeFilter ? undefined : parseEntityFilter(meta, filter);\n if (!scopeFilter && !ef && join !== \"primary\" && !isAlias(filter)) {\n return;\n }\n\n if (join === \"primary\") {\n tables.push({ alias, table: meta.tableName, join });\n addTablePerClassJoinsAndClassTag({ selects, tables, orderBys }, meta, alias, true);\n } else if (meta.inheritanceType === \"cti\" && fieldName && !(fieldName in meta.fields)) {\n // For cti, our meta might be a subtype while the FK is actually on the base table. This should only be the case\n // when the fk is on another table (e.g. o2o/o2m). In these cases, we'll be passed a field name and can verify if\n // its directly in our meta, if not we should assume it's in the base type and join that in first.\n meta.baseTypes.forEach((bt, i) => {\n tables.push({\n alias: `${alias}_b${i}`,\n table: bt.tableName,\n join: \"outer\",\n col1,\n col2: `${kq(`${alias}_b${i}`)}.${col2.split(\".\")[1]}`,\n distinct: false,\n });\n // and we still need to join in our subtype as well in case its own fields are queried against\n tables.push({\n alias: `${alias}`,\n table: meta.tableName,\n join: \"outer\",\n col1: kqDot(alias, \"id\"),\n col2: kqDot(`${alias}_b${i}`, \"id\"),\n distinct: false,\n });\n });\n } else if (join === \"lateral\" || join === \"cross\") {\n fail(\"Unexpected lateral join\");\n } else {\n tables.push({ alias, table: meta.tableName, join, col1, col2 });\n // Maybe only do this if we're the primary, or have a field that needs it?\n addTablePerClassJoinsAndClassTag({ selects, tables, orderBys }, meta, alias, false);\n }\n\n if (needsStiDiscriminator(meta)) {\n addStiSubtypeFilter(targetCb, meta, alias);\n }\n\n // Only the primary table & collection joins filter soft-deletes, to match the in-memory relation\n // semantics of \"o2m/m2m collections filter out soft-deletes, but m2o/o2o references still return\n // them\". I.e. `book.author.get` returns a soft-deleted author, so `em.find(Book, { author: ... })`\n // should still match the book, as long as the book itself is not soft-deleted.\n if (join === \"primary\" || isCollection) {\n addSoftDeleteCondition(meta, alias, targetCb);\n }\n\n // The user's locally declared aliases, i.e. `const [a, b] = aliases(Author, Book)`,\n // aren't guaranteed to line up with the aliases we've assigned internally, like `a`\n // might actually be `a1` if there are two `authors` tables in the query, so push the\n // canonical alias value for the current clause into the Alias.\n if (filter && typeof filter === \"object\" && \"as\" in filter && isAlias(filter.as)) {\n aliasBindings.set(getAliasMgmt(filter.as), { meta, alias });\n } else if (isAlias(filter)) {\n aliasBindings.set(getAliasMgmt(filter), { meta, alias });\n }\n\n addFilterAt(meta, alias, filter, targetCb, ef, join);\n }\n\n function addFilterAt(\n meta: EntityMetadata,\n tableAlias: string,\n filter: any,\n targetCb: ConditionBuilder,\n parsed: ParsedEntityFilter | undefined = parseEntityFilter(meta, filter),\n parentJoin: ParsedTable[\"join\"] = \"primary\",\n ): void {\n if (isScope(filter)) {\n addScopeFilterAt(meta, tableAlias, filter, targetCb, parentJoin);\n } else if (parsed && parsed.kind === \"join\") {\n addSubFilter(meta, tableAlias, parsed.subFilter, targetCb, parentJoin);\n } else if (parsed) {\n const column = meta.fields[\"id\"].serde!.columns[0];\n targetCb.addValueFilter(tableAlias, column, parsed);\n }\n }\n\n function addScopeFilterAt<T extends Entity>(\n meta: EntityMetadata<T>,\n tableAlias: string,\n scope: Scope<T>,\n targetCb: ConditionBuilder,\n parentJoin: ParsedTable[\"join\"],\n ): void {\n for (const fragment of resolveScope(scope).fragments) {\n if (fragment.kind === \"filter\") {\n addFilterAt(meta, tableAlias, fragment.filter, targetCb, undefined, parentJoin);\n } else {\n const a = newAlias(meta.cstr);\n const result = fragment.fn(a);\n aliasBindings.set(getAliasMgmt(a), { meta, alias: tableAlias });\n if (isScopeJoinFilter(result)) {\n // Parse the join tree first so its `as:` bindings re-root the aliases that\n // `conditions` reference, then add the conditions against the now-bound aliases.\n addFilterAt(meta, tableAlias, result.where, targetCb, undefined, parentJoin);\n checkDomainCondition(result.conditions);\n targetCb.maybeAddExpression(result.conditions);\n } else {\n const conditions = Array.isArray(result) ? result : [result];\n for (const condition of conditions) checkDomainCondition(condition);\n if (conditions.length > 0) targetCb.maybeAddExpression({ and: conditions });\n }\n }\n }\n }\n\n function addSubFilter(\n meta: EntityMetadata,\n tableAlias: string,\n subFilter: object,\n targetCb: ConditionBuilder,\n parentJoin: ParsedTable[\"join\"],\n ): void {\n // subFilter really means we're matching against the entity columns/further joins\n Object.keys(subFilter).forEach((key) => {\n // Skip the `{ as: ... }` alias binding\n if (key === \"as\") return;\n if (key === \"and\" || key === \"or\") {\n addLogicalFilter(meta, tableAlias, key, (subFilter as any)[key], targetCb, parentJoin);\n return;\n }\n const field = findFilterField(meta, key) ?? fail(`Field '${key}' not found on ${meta.tableName}`);\n const fa = `${tableAlias}${field.aliasSuffix}`;\n if (field.kind === \"primitive\" || field.kind === \"primaryKey\" || field.kind === \"enum\") {\n const column = field.serde.columns[0];\n parseValueFilter((subFilter as any)[key]).forEach((filter) => {\n targetCb.addValueFilter(fa, column, filter);\n });\n } else if (field.kind === \"m2o\") {\n const column = field.serde.columns[0];\n const sub = (subFilter as any)[key];\n const joinKind = field.required && parentJoin !== \"outer\" ? \"inner\" : \"outer\";\n if (isAlias(sub)) {\n const a = getAlias(field.otherMetadata().tableName);\n addTable(\n field.otherMetadata(),\n a,\n joinKind,\n kqDot(fa, column.columnName),\n kqDot(a, \"id\"),\n sub,\n undefined,\n targetCb,\n );\n }\n const f = parseEntityFilter(field.otherMetadata(), sub);\n // Probe the filter and see if it's just an id, if so we can avoid the join; m2os don't need\n // a join for soft-delete filtering because references don't filter out soft-deletes.\n if (!f) {\n // skip\n } else if (f.kind === \"join\") {\n const a = getAlias(field.otherMetadata().tableName);\n addTable(\n field.otherMetadata(),\n a,\n joinKind,\n kqDot(fa, column.columnName),\n kqDot(a, \"id\"),\n sub,\n undefined,\n targetCb,\n );\n } else {\n targetCb.addValueFilter(fa, column, f);\n }\n } else if (field.kind === \"poly\") {\n const f = parseEntityFilter(meta, (subFilter as any)[key]);\n if (!f) {\n // skip\n } else if (f.kind === \"join\") {\n throw new Error(\"Joins through polys are not supported\");\n } else {\n // We're left with basically a ValueFilter against the ids\n // For now only support eq/ne/in/is-null\n if (f.kind === \"eq\" || f.kind === \"ne\") {\n if (isNilIdValue(f.value)) return;\n const comp = field.components.find((p) => {\n const otherMeta = p.otherMetadata();\n const cstr = getConstructorFromTaggedId(f.value as string);\n // tagged ids from subclasses always map to the base class, so we should compare to the base class if we don't directly match\n return otherMeta.cstr === cstr || otherMeta.baseType === cstr.name;\n });\n if (!comp) fail(`Invalid tagged id passed to ${meta.type}.${key}: ${f.value}`);\n const column = field.serde.columns.find((c) => c.columnName === comp.columnName)!;\n targetCb.addValueFilter(fa, column, f);\n } else if (f.kind === \"is-null\") {\n // Add a condition for every component--these can be AND-d with the rest of the simple/inline conditions\n field.components.forEach((comp) => {\n const column = field.serde.columns.find((c) => c.columnName === comp.columnName)!;\n targetCb.addSimpleCondition({\n kind: \"column\",\n alias: fa,\n column: comp.columnName,\n dbType: column.dbType,\n cond: f,\n });\n });\n } else if (f.kind === \"not-null\") {\n const conditions = field.components.map((comp) => {\n const column = field.serde.columns.find((c) => c.columnName === comp.columnName)!;\n return {\n kind: \"column\",\n alias: fa,\n column: comp.columnName,\n dbType: column.dbType,\n cond: { kind: \"not-null\" },\n };\n }) satisfies ColumnCondition[];\n targetCb.addParsedExpression({ kind: \"exp\", op: \"or\", conditions });\n } else if (f.kind === \"in\") {\n // An empty `in` matches nothing, so emit a single always-false condition (consistent\n // with a non-poly m2o `{ relation: [] }`); otherwise grouping by constructor would yield\n // zero conditions and prune the filter entirely, incorrectly matching every row.\n if (f.value.length === 0) {\n targetCb.addValueFilter(fa, field.serde.columns[0], { kind: \"in\", value: [] });\n return;\n }\n // Split up the ids by constructor\n const idsByConstructor = groupBy(f.value, (id) => getConstructorFromTaggedId(id as string).name);\n // Or together `parent_book_id in (1,2,3) OR parent_author_id IN (4,5,6)`\n // ...if there is a `parent IN [b:1, b:2, a:1, null]` we'd need to pull the `null` out and do an `OR (all columns are null)`...\n const conditions = Object.entries(idsByConstructor).map(([cstrName, ids]) => {\n const column =\n field.serde.columns.find(\n // tagged ids from subclasses always map to the base class, so we should compare to the base class if we don't directly match\n (c) => c.otherMetadata().cstr.name === cstrName || c.otherMetadata().baseType === cstrName,\n ) ?? fail(`Invalid tagged ids passed to ${meta.type}.${key}: ${ids}`);\n return {\n kind: \"column\",\n alias: fa,\n column: column.columnName,\n dbType: column.dbType,\n cond: mapToDb(column, { kind: \"in\", value: ids }),\n } satisfies ColumnCondition;\n });\n targetCb.addParsedExpression({ kind: \"exp\", op: \"or\", conditions });\n } else {\n throw new Error(`Filters on polys for ${f.kind} are not supported`);\n }\n }\n } else if (field.kind === \"o2o\") {\n // We have to always join into o2os, i.e. we can't probe the filter like we do for m2os\n const otherMeta = field.otherMetadata();\n const a = getAlias(otherMeta.tableName);\n const otherField = otherMeta.allFields[field.otherFieldName];\n const otherColumn =\n // if our other is a poly, we need to find a matching column rather than just picking the first\n otherField.kind === \"poly\"\n ? otherField.components.find((c) => c.otherMetadata() === meta || c.otherMetadata() === getBaseMeta(meta))!\n .columnName\n : otherField.serde!.columns[0].columnName;\n addTable(\n field.otherMetadata(),\n a,\n \"outer\",\n kqDot(tableAlias, \"id\"),\n kqDot(a, otherColumn),\n (subFilter as any)[key],\n field.otherFieldName,\n targetCb,\n );\n } else if (field.kind === \"o2m\") {\n const otherMeta = field.otherMetadata();\n const otherField = otherMeta.allFields[field.otherFieldName];\n let otherColumn = otherField.serde!.columns[0].columnName;\n if (otherField.kind === \"poly\") {\n const otherComponent =\n otherField.components.find((c) => c.otherMetadata() === meta) ??\n fail(`No poly component found for ${otherField.fieldName}`);\n otherColumn = otherComponent.columnName;\n }\n const isCtiBaseFk =\n otherMeta.inheritanceType === \"cti\" && field.otherFieldName && !(field.otherFieldName in otherMeta.fields);\n const a = getAlias(otherMeta.tableName);\n addTable(\n otherMeta,\n a,\n \"outer\",\n kqDot(tableAlias, \"id\"),\n kqDot(a, otherColumn),\n (subFilter as any)[key],\n field.otherFieldName,\n targetCb,\n true,\n );\n if (!isCtiBaseFk) {\n const table = tables.find((t) => t.alias === a);\n if (table && (table.join === \"inner\" || table.join === \"outer\")) {\n table.collection = { parentAlias: tableAlias, rootAlias: a, kind: \"o2m\" };\n }\n }\n } else if (field.kind === \"m2m\") {\n const sub = (subFilter as any)[key];\n const f = parseEntityFilter(field.otherMetadata(), sub);\n if (!f && !isAlias(sub)) return;\n\n const ja = getAlias(field.joinTableName);\n tables.push({\n join: \"outer\",\n alias: ja,\n table: field.joinTableName,\n col1: kqDot(tableAlias, \"id\"),\n col2: kqDot(ja, field.columnNames[0]),\n collection: { parentAlias: tableAlias, rootAlias: ja, kind: \"m2m\" },\n });\n\n if (isAlias(sub) || f?.kind === \"join\" || filterSoftDeletes(field.otherMetadata(), softDeletes)) {\n const a = getAlias(field.otherMetadata().tableName);\n addTable(\n field.otherMetadata(),\n a,\n \"outer\",\n kqDot(ja, field.columnNames[1]),\n kqDot(a, \"id\"),\n sub,\n undefined,\n targetCb,\n true,\n );\n const table = tables.find((t) => t.alias === a);\n if (table && (table.join === \"inner\" || table.join === \"outer\")) {\n table.collection = { parentAlias: ja, rootAlias: ja, kind: \"m2m\" };\n }\n } else if (f) {\n const otherMeta = field.otherMetadata();\n const column: any = {\n columnName: field.columnNames[1],\n dbType: otherMeta.idDbType,\n mapToDb(value: any) {\n return value === null || isNilIdValue(value)\n ? value\n : keyToNumber(otherMeta, maybeResolveReferenceToId(value));\n },\n };\n targetCb.addSimpleCondition({\n kind: \"column\",\n alias: ja,\n column: field.columnNames[1],\n dbType: otherMeta.idDbType,\n cond: mapToDb(column, f),\n });\n }\n } else if (field.kind === \"m2mEnum\") {\n // Membership filter, e.g. `{ logoColors: Color.Red }` / `{ logoColors: [Red, Green] }`: join the\n // join table and filter its enum-id column, mapping enum codes -> their numeric ids.\n const ja = getAlias(field.joinTableName);\n tables.push({\n join: \"outer\",\n alias: ja,\n table: field.joinTableName,\n col1: kqDot(tableAlias, \"id\"),\n col2: kqDot(ja, field.columnNames[0]),\n collection: { parentAlias: tableAlias, rootAlias: ja, kind: \"m2m\" },\n });\n const column: any = {\n columnName: field.columnNames[1],\n dbType: \"int\",\n mapToDb(value: any) {\n return value === null || value === undefined ? value : field.enumDetailType.getByCode(value).id;\n },\n };\n parseValueFilter((subFilter as any)[key]).forEach((filter) => {\n targetCb.addValueFilter(ja, column, filter);\n });\n } else {\n throw new Error(`Unsupported field ${key}`);\n }\n });\n }\n\n function addLogicalFilter(\n meta: EntityMetadata,\n tableAlias: string,\n op: \"and\" | \"or\",\n value: unknown,\n targetCb: ConditionBuilder,\n parentJoin: ParsedTable[\"join\"],\n ): void {\n const filters = Array.isArray(value) ? value : [value];\n const conditions = filters.flatMap((filter) => {\n const branchCb = new ConditionBuilder();\n addFilterAt(meta, tableAlias, filter, branchCb, undefined, parentJoin);\n const condition = branchCb.toExpressionFilter();\n return condition ? [condition] : [];\n });\n if (conditions.length > 0) targetCb.addParsedExpression({ kind: \"exp\", op, conditions });\n }\n\n function addOrderBy(meta: EntityMetadata, alias: string, orderBy: Record<string, any>): void {\n const entries = Object.entries(orderBy);\n if (entries.length === 0) return;\n for (const [key, value] of entries) {\n if (!value) continue; // prune undefined\n const field = meta.allFields[key] ?? fail(`${key} not found on ${meta.tableName}`);\n if (field.kind === \"primitive\" || field.kind === \"primaryKey\" || field.kind === \"enum\") {\n const column = field.serde.columns[0];\n orderBys.push({\n alias: `${alias}${field.aliasSuffix ?? \"\"}`,\n column: column.columnName,\n order: value as OrderBy,\n });\n } else if (field.kind === \"m2o\") {\n // Do we already this table joined in?\n let table = tables.find((t) => t.table === field.otherMetadata().tableName);\n if (table) {\n addTablePerClassJoinsAndClassTag(query, field.otherMetadata(), table.alias, false);\n addOrderBy(field.otherMetadata(), table.alias, value);\n } else {\n const table = field.otherMetadata().tableName;\n const a = getAlias(table);\n const column = field.serde.columns[0].columnName;\n const fa = getMaybeCtiAlias(meta, field, meta, alias);\n // If we don't have a join, don't force this to be an inner join\n tables.push({\n alias: a,\n table,\n join: \"outer\",\n col1: kqDot(fa, column),\n col2: kqDot(a, \"id\"),\n distinct: false,\n });\n addTablePerClassJoinsAndClassTag(query, field.otherMetadata(), a, false);\n addOrderBy(field.otherMetadata(), a, value);\n }\n } else {\n throw new Error(`Unsupported field ${key}`);\n }\n }\n }\n\n // always add the main table\n const alias = getAlias(meta.tableName);\n if (meta.hasLazyColumns) {\n selects.push(...lazyExcludedSelects(meta, alias));\n } else {\n selects.push(`${kq(alias)}.*`);\n }\n addTable(meta, alias, \"primary\", \"n/a\", \"n/a\", filter);\n\n // If they passed extra `conditions: ...`, parse that\n if (optsExpression) {\n checkDomainCondition(optsExpression);\n cb.maybeAddExpression(optsExpression);\n }\n\n Object.assign(query, {\n condition: cb.toExpressionFilter(),\n });\n\n // Resolve alias-built conditions against this parse's bindings, before anything reads their\n // aliases (the id-not-null injection just below, and join pruning)\n resolveAliasConditions(query, aliasBindings);\n\n if (query.tables.some((t) => t.join === \"outer\")) {\n maybeAddIdNotNulls(query);\n }\n\n if (orderBy) {\n if (Array.isArray(orderBy)) {\n for (const ob of orderBy) addOrderBy(meta, alias, ob);\n } else {\n addOrderBy(meta, alias, orderBy);\n }\n }\n maybeAddOrderBy(query, meta, alias);\n\n if (pruneJoins) {\n pruneUnusedJoins(query, keepAliases);\n }\n return query;\n}\n\n/**\n * Look for conditions doing `some_column IS NULL` in an outer join that\n * need an `id IS NOT NULL` to make sure they don't match inadvertently on\n * the child row simply not existing.\n *\n * Note: Instead of injecting an extra `id IS NOT NULL` condition, I had tried\n * using all INNER JOINs and flipping joins to OUTER only if the user explicit\n * had `id IS NULL` in their filter, but that didn't work for queries that wanted\n * to do an `OR` across two different children (which queries both children being\n * OUTER JOINs, and detecting that case seemed complicated).\n */\nexport function maybeAddIdNotNulls(query: ParsedFindQuery): void {\n visitConditions(query, {\n visitCond(c: ColumnCondition) {\n // Check `c.prunable` to make sure we don't catch our injected `deleted_at is null` conditions\n if (c.cond.kind !== \"is-null\" || c.column === \"id\" || c.pruneable) {\n return c;\n }\n // This is an `some_column IS NULL`, is it in an outer join?\n const table = query.tables.find((t) => t.alias === c.alias);\n if (table && table.join === \"outer\") {\n const meta = getMetadataForTable(table.table);\n return {\n kind: \"exp\",\n op: \"and\",\n conditions: [\n c,\n {\n kind: \"column\",\n alias: c.alias,\n column: \"id\",\n dbType: meta.idDbType,\n cond: { kind: \"not-null\" },\n },\n ],\n } satisfies ParsedExpressionFilter;\n }\n return c;\n },\n });\n}\n\n/** Returns the `a` from `\"a\".*`. */\nexport function parseAlias(alias: string): string {\n return alias.split(\".\")[0].replaceAll(`\"`, \"\");\n}\n\n/** Finds a filter field by fieldName or generated fieldIdName. */\nexport function findFilterField(meta: EntityMetadata, key: string): (Field & { aliasSuffix: string }) | undefined {\n return (\n meta.allFields[key] ??\n meta.polyComponentFields?.[key] ??\n Object.values(meta.allFields).find((field) => field.fieldIdName === key) ??\n Object.values(meta.polyComponentFields ?? {}).find((field) => field.fieldIdName === key)\n );\n}\n\n/** Adds any user-configured default order, plus an \"always order by id\" for determinism. */\nexport function maybeAddOrderBy(query: ParsedFindQuery, meta: EntityMetadata, alias: string): void {\n const { orderBys } = query;\n if (meta.orderBy) {\n const field = meta.allFields[meta.orderBy] ?? fail(`${meta.orderBy} not found on ${meta.tableName}`);\n const column = field.serde!.columns[0].columnName;\n const hasAlready = orderBys.find((o) => o.alias === alias && o.column === column);\n if (!hasAlready) {\n orderBys.push({ alias, column, order: \"ASC\" });\n }\n }\n // Even if they already added orders, add id as the last one to get deterministic output\n const hasIdOrder = orderBys.find((o) => o.alias === alias && o.column === \"id\");\n if (!hasIdOrder) {\n orderBys.push({ alias, column: \"id\", order: \"ASC\" });\n }\n}\n\nexport function addTablePerClassJoinsAndClassTag(\n query: ParsedFindQuery,\n meta: EntityMetadata,\n alias: string,\n isPrimary: boolean,\n): void {\n if (!needsClassPerTableJoins(meta)) return;\n const { selects, tables } = query;\n // When `.load(SmallPublisher)` is called, join in base tables like `Publisher`\n meta.baseTypes.forEach((bt, i) => {\n if (isPrimary) {\n selects.push(`${alias}_b${i}.*`);\n }\n tables.push({\n alias: `${alias}_b${i}`,\n table: bt.tableName,\n join: \"outer\",\n col1: kqDot(alias, \"id\"),\n col2: `${alias}_b${i}.id`,\n distinct: false,\n });\n });\n\n // We always join in the base table in case a query happens to use\n // it as a filter, but we only need to do the subtype joins + selects\n // if this is the primary table\n if (isPrimary) {\n // Watch for subTypes that share column names. It'd be great to do\n // this statically at codegen time, like a meta.sharedSubtypeColumns.\n const stColumns: { stAlias: string; columnName: string }[] = [];\n\n // When `.load(Publisher)` is called, join in sub tables like `SmallPublisher` and `LargePublisher`\n meta.subTypes.forEach((st, i) => {\n const stAlias = `${alias}_s${i}`;\n selects.push(`${stAlias}.*`);\n tables.push({\n alias: stAlias,\n table: st.tableName,\n join: \"outer\",\n col1: kqDot(alias, \"id\"),\n col2: `${alias}_s${i}.id`,\n distinct: false,\n });\n for (const field of Object.values(st.fields)) {\n if (field.fieldName !== \"id\" && field.serde) {\n for (const c of field.serde?.columns) {\n stColumns.push({ stAlias, columnName: c.columnName });\n }\n }\n }\n });\n\n // Nominate a specific `id` column to avoid ambiguity\n selects.push(`${kq(alias)}.id as id`);\n\n // Add an explicit coalesce for shared columns\n Object.values(groupBy(stColumns, (c) => c.columnName))\n .filter((columns) => columns.length > 1)\n .forEach((columns) => {\n const { columnName } = columns[0];\n selects.push(`COALESCE(${columns.map((c) => `${c.stAlias}.${columnName}`).join(\", \")}) as ${columnName}`);\n });\n\n // If our meta has no subtypes, we're a left type and don't need a __class\n const cases = meta.subTypes.map((st, i) => `WHEN ${alias}_s${i}.id IS NOT NULL THEN '${st.type}'`);\n if (cases.length > 0) {\n selects.push(`CASE ${cases.join(\" \")} ELSE '_' END as __class`);\n }\n }\n}\n\n/** Rejects SQL predicates throughout a domain condition tree before optional-filter pruning. */\nfunction checkDomainCondition(condition: ConditionInput | undefined): void {\n if (!condition) return;\n if (isDeferredCondition(condition) || (predicateBrand in condition && condition[predicateBrand] === \"sql\")) {\n fail(\"SQL predicates are only supported by em.query/em.execute; use alias(...) predicates in em.find and scopes.\");\n }\n if (\"and\" in condition && condition.and) {\n for (const child of condition.and) checkDomainCondition(child);\n } else if (\"or\" in condition && condition.or) {\n for (const child of condition.or) checkDomainCondition(child);\n }\n}\n\n/** Resolves every `DeferredAliasCondition` in `query` against the parse's alias bindings. */\nfunction resolveAliasConditions(\n query: ParsedFindQuery,\n bindings: Map<AliasMgmt, { meta: EntityMetadata; alias: string }>,\n): void {\n function resolve(handle: AliasMgmt): { meta: EntityMetadata; alias: string } {\n return bindings.get(handle) ?? fail(`Alias for ${handle.tableName} is not bound to this query's join literal`);\n }\n function maybeResolve<C extends ColumnCondition | RawCondition>(c: C): C | undefined {\n return isDeferredAliasCondition(c) ? c[deferredAliasSym](resolve) : undefined;\n }\n visitConditions(query, { visitCond: maybeResolve, visitRaw: maybeResolve });\n}\n\nexport function getTables(query: ParsedFindQuery): [PrimaryTable, JoinTable[], LateralJoinTable[], CrossJoinTable[]] {\n let primary: PrimaryTable;\n const joins: JoinTable[] = [];\n const laterals: LateralJoinTable[] = [];\n const crosses: CrossJoinTable[] = [];\n for (const table of query.tables) {\n if (table.join === \"primary\") {\n primary = table;\n } else if (table.join === \"lateral\") {\n laterals.push(table);\n } else if (table.join === \"cross\") {\n crosses.push(table);\n } else {\n joins.push(table);\n }\n }\n return [primary!, joins, laterals, crosses];\n}\n\nfunction needsClassPerTableJoins(meta: EntityMetadata): boolean {\n return meta.inheritanceType === \"cti\" && (meta.subTypes.length > 0 || meta.baseTypes.length > 0);\n}\n\nfunction needsStiDiscriminator(meta: EntityMetadata): boolean {\n return meta.inheritanceType === \"sti\" && !meta.stiDiscriminatorField;\n}\n\nfunction addStiSubtypeFilter(cb: ConditionBuilder, subtypeMeta: EntityMetadata, alias: string): void {\n const cond = stiSubtypeFilter(subtypeMeta, alias);\n if (cond) cb.addSimpleCondition(cond);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"QueryParser.cjs","names":["ConditionBuilder","abbreviation","filterSoftDeletes","getBaseMeta","isScope","parseEntityFilter","isAlias","kq","kqDot","getAliasMgmt","resolveScope","newAlias","isScopeJoinFilter","fail","getConstructorFromTaggedId","groupBy","mapToDb","keyToNumber","maybeResolveReferenceToId","getMaybeCtiAlias","alias","lazyExcludedSelects","getMetadataForTable","isDeferredCondition","predicateBrand","isDeferredAliasCondition","deferredAliasSym","stiSubtypeFilter"],"sources":["../../../src/queries/find/QueryParser.ts"],"sourcesContent":["import { groupBy } from \"joist-utils\";\nimport { getConstructorFromTaggedId, getMetadataForTable } from \"src/configure.ts\";\nimport type { Entity } from \"src/Entity.ts\";\nimport { type EntityMetadata, type Field, getBaseMeta } from \"src/EntityMetadata.ts\";\nimport { keyToNumber, maybeResolveReferenceToId } from \"src/keys.ts\";\nimport { ConditionBuilder } from \"src/queries/ConditionBuilder.ts\";\nimport { type ConditionInput, predicateBrand } from \"src/queries/conditions.ts\";\nimport { filterSoftDeletes, lazyExcludedSelects, stiSubtypeFilter } from \"src/queries/entityQueryUtils.ts\";\nimport {\n type AliasMgmt,\n getAliasMgmt,\n getMaybeCtiAlias,\n isAlias,\n alias as newAlias,\n} from \"src/queries/find/Aliases.ts\";\nimport { deferredAliasSym, isDeferredAliasCondition } from \"src/queries/find/DeferredAlias.ts\";\nimport type { ExpressionFilter, OrderBy } from \"src/queries/find/EntityFilter.ts\";\nimport { pruneUnusedJoins } from \"src/queries/find/QueryParser.pruning.ts\";\nimport { visitConditions } from \"src/queries/find/QueryVisitor.ts\";\nimport { type Scope, isScope, isScopeJoinFilter, resolveScope } from \"src/queries/find/scopes.ts\";\nimport type { ColumnCondition, ParsedExpressionFilter, RawCondition } from \"src/queries/parsedConditions.ts\";\nimport { isDeferredCondition } from \"src/queries/sql/Expr.ts\";\nimport { kq, kqDot } from \"src/queries/sql/keywords.ts\";\nimport { type ParsedEntityFilter, mapToDb, parseEntityFilter, parseValueFilter } from \"src/queries/valueFilters.ts\";\nimport { abbreviation, fail } from \"src/utils.ts\";\n\n// `skipCondition` lives in its own leaf module, shared by domain aliases and SQL expressions\n// without a load-order cycle; `index.ts` re-exports it directly.\n\nexport interface PrimaryTable {\n join: \"primary\";\n alias: string;\n table: string;\n}\n\nexport interface JoinTable {\n join: \"inner\" | \"outer\";\n alias: string;\n table: string;\n col1: string;\n col2: string;\n distinct?: boolean;\n /**\n * Metadata used by `optimizeCollectionJoins` to rewrite collection joins into EXISTS.\n *\n * I.e. for `Author.books.reviews`:\n * ```sql\n * authors a\n * LEFT JOIN books b ON a.id = b.author_id\n * LEFT JOIN book_reviews br ON b.id = br.book_id\n * ```\n * `books b` has `parentAlias: \"a\"` and `rootAlias: \"b\"`, while `book_reviews br` has\n * `parentAlias: \"b\"` and `rootAlias: \"br\"`.\n *\n * I.e. for `Author.tags`, the m2m join table is the collection root:\n * ```sql\n * authors a\n * LEFT JOIN authors_to_tags att ON a.id = att.author_id\n * LEFT JOIN tags t ON att.tag_id = t.id\n * ```\n * `authors_to_tags att` has `alias: \"att\"` and `rootAlias: \"att\"`, while `tags t` has `alias: \"t\"`\n * but still has `rootAlias: \"att\"` because it belongs to the m2m subtree rooted at the join table.\n */\n collection?: {\n /** The collection relation type, i.e. `o2m` for `Author.books`, or `m2m` for `Author.tags`. */\n kind: \"o2m\" | \"m2m\";\n /** The alias that owns this collection path, i.e. `a` for `Author.books`, or `att` for `Author.tags -> tags`. */\n parentAlias: string;\n /** The top-level alias in this collection subtree, i.e. `b` for `Author.books.reviews`, or `att` for `Author.tags`. */\n rootAlias: string;\n };\n}\n\n/**\n * Creates a `CROSS JOIN`, currently used for our `em.find` batching.\n *\n * I.e. queries like:\n *\n * ```sql\n * WITH _find (tag, arg1, arg2) AS (VALUES\n * (0::int, 'a'::varchar, 'a'::varchar),\n * (1, 'b', 'b'),\n * (2, 'c', 'c')\n * )\n * SELECT a.*, array_agg(_find.tag) AS _tags\n * FROM authors a\n * CROSS JOIN _find AS _find\n * WHERE a.first_name = _find.arg0 OR a.last_name = _find.arg1\n * GROUP BY a.id\n * ```\n */\nexport interface CrossJoinTable {\n join: \"cross\";\n /** The new alias for the joined table. */\n alias: string;\n /** The table name to join into the query. */\n table: string;\n}\n\n/**\n * Adds `WITH` CTE clauses to the query.\n *\n * I.e. queries like:\n *\n * ```sql\n * WITH _find (tag, arg0, arg1) AS (\n * VALUES ($1::int, $2::character varying, $3::character varying), ($4, $5, $6)\n * )\n * ```\n */\nexport interface ParsedCteClause {\n /** The new alias for the CTE, i.e. `_find` in the above query. */\n alias: string;\n /** The columns, i.e. `tag, arg0, arg1` in the above query. */\n columns?: { columnName: string; dbType: string }[];\n /** The subquery for the AS of the CTE clause. */\n query: { kind: \"raw\"; sql: string; bindings: readonly any[] } | { kind: \"ast\"; query: ParsedFindQuery };\n /** Whether to include a `RECURSIVE` keyword after the `WITH`. */\n recursive?: boolean;\n}\n\n/**\n * Creates `LATERAL JOIN`s, currently used by `findCount` and JSON preloading.\n */\nexport interface LateralJoinTable {\n join: \"lateral\";\n alias: string;\n /** Used for join dependency tracking. */\n fromAlias: string;\n /** Used more for bookkeeping/consistency with other join tables than the query itself. */\n table: string;\n /** The subquery that will look for/roll-up N children. */\n query: ParsedFindQuery;\n /** Optional settings for the subquery, i.e. per-parent pagination. */\n settings?: { limit?: number; offset?: number };\n}\n\nexport type ParsedTable = PrimaryTable | JoinTable | CrossJoinTable | LateralJoinTable;\n\nexport interface ParsedOrderBy {\n alias: string;\n column: string;\n order: OrderBy;\n}\n\nexport type ParsedGroupBy = { alias: string; column: string } | { expression: string };\n\nexport type ParsedSelect = string | ParsedSelectWithBindings;\ntype ParsedSelectWithBindings = { sql: string; bindings: any[]; aliases: string[] };\n\n/** The result of parsing an `em.find` filter. */\nexport interface ParsedFindQuery {\n selects: ParsedSelect[];\n /** The primary table plus any joins. */\n tables: ParsedTable[];\n /** The query's conditions. */\n condition?: ParsedExpressionFilter;\n /** Extremely optional group bys; we generally don't support adhoc/aggregate queries, but the auto-batching infra uses these. */\n groupBys?: ParsedGroupBy[];\n /** Any optional orders to add before the default 'order by id'. */\n orderBys: ParsedOrderBy[];\n /** Optional CTE to prefix to the query, i.e. for recursive relations. */\n ctes?: ParsedCteClause[];\n}\n\n/**\n * Parses an `em.find` filter into a logical `ParsedFindQuery` AST, leaving optimization/pruning to callers.\n *\n * The main execution flow is:\n * parseFindQuery -> beforeFind plugins -> optimizeCollectionJoins -> pruneUnusedJoins -> execute SQL.\n */\nexport function parseFindQuery(\n meta: EntityMetadata,\n filter: any,\n opts: {\n conditions?: ExpressionFilter;\n orderBy?: any;\n pruneJoins?: boolean;\n keepAliases?: string[];\n softDeletes?: \"include\" | \"exclude\";\n allowMultipleLeftJoins?: boolean;\n optimizeJoinsToExists?: boolean;\n } = {},\n): ParsedFindQuery {\n const selects: string[] = [];\n const tables: ParsedTable[] = [];\n const orderBys: ParsedOrderBy[] = [];\n const query: ParsedFindQuery = { selects, tables, orderBys };\n const { orderBy, conditions: optsExpression, softDeletes = \"exclude\", pruneJoins = false, keepAliases = [] } = opts;\n const cb = new ConditionBuilder();\n // Where each user-created `alias(...)` is bound in this parse's join literal; alias-built conditions\n // (`a.firstName.eq(...)`) are resolved against it once the whole tree is walked\n const aliasBindings = new Map<AliasMgmt, { meta: EntityMetadata; alias: string }>();\n\n const aliases: Record<string, number> = {};\n function getAlias(tableName: string): string {\n const abbrev = abbreviation(tableName);\n const i = aliases[abbrev] || 0;\n aliases[abbrev] = i + 1;\n return i === 0 ? abbrev : `${abbrev}${i}`;\n }\n\n /** Adds a `deleted_at IS NULL` condition for `alias`, i.e. for the primary table or a collection join. */\n function addSoftDeleteCondition(meta: EntityMetadata, alias: string, targetCb: ConditionBuilder): void {\n if (filterSoftDeletes(meta, softDeletes)) {\n const column = meta.allFields[getBaseMeta(meta).timestampFields!.deletedAt!].serde?.columns[0]!;\n targetCb.addSimpleCondition({\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n cond: { kind: \"is-null\" },\n pruneable: true,\n });\n }\n }\n\n function addTable(\n meta: EntityMetadata,\n alias: string,\n join: ParsedTable[\"join\"],\n col1: string,\n col2: string,\n filter: any,\n fieldName?: string,\n targetCb: ConditionBuilder = cb,\n /** Whether this table is the \"other side\" of a collection, i.e. `books` in `em.find(Author, { books: ... })`. */\n isCollection: boolean = false,\n ): void {\n // look at filter, is it `{ book: \"b2\" }` or `{ book: { ... } }`\n const scopeFilter = isScope(filter);\n const ef = scopeFilter ? undefined : parseEntityFilter(meta, filter);\n if (!scopeFilter && !ef && join !== \"primary\" && !isAlias(filter)) {\n return;\n }\n\n if (join === \"primary\") {\n tables.push({ alias, table: meta.tableName, join });\n addTablePerClassJoinsAndClassTag({ selects, tables, orderBys }, meta, alias, true);\n } else if (meta.inheritanceType === \"cti\" && fieldName && !(fieldName in meta.fields)) {\n // For cti, our meta might be a subtype while the FK is actually on the base table. This should only be the case\n // when the fk is on another table (e.g. o2o/o2m). In these cases, we'll be passed a field name and can verify if\n // its directly in our meta, if not we should assume it's in the base type and join that in first.\n meta.baseTypes.forEach((bt, i) => {\n tables.push({\n alias: `${alias}_b${i}`,\n table: bt.tableName,\n join: \"outer\",\n col1,\n col2: `${kq(`${alias}_b${i}`)}.${col2.split(\".\")[1]}`,\n distinct: false,\n });\n // and we still need to join in our subtype as well in case its own fields are queried against\n tables.push({\n alias: `${alias}`,\n table: meta.tableName,\n join: \"outer\",\n col1: kqDot(alias, \"id\"),\n col2: kqDot(`${alias}_b${i}`, \"id\"),\n distinct: false,\n });\n });\n } else if (join === \"lateral\" || join === \"cross\") {\n fail(\"Unexpected lateral join\");\n } else {\n tables.push({ alias, table: meta.tableName, join, col1, col2 });\n // Maybe only do this if we're the primary, or have a field that needs it?\n addTablePerClassJoinsAndClassTag({ selects, tables, orderBys }, meta, alias, false);\n }\n\n if (needsStiDiscriminator(meta)) {\n addStiSubtypeFilter(targetCb, meta, alias);\n }\n\n // Only the primary table & collection joins filter soft-deletes, to match the in-memory relation\n // semantics of \"o2m/m2m collections filter out soft-deletes, but m2o/o2o references still return\n // them\". I.e. `book.author.get` returns a soft-deleted author, so `em.find(Book, { author: ... })`\n // should still match the book, as long as the book itself is not soft-deleted.\n if (join === \"primary\" || isCollection) {\n addSoftDeleteCondition(meta, alias, targetCb);\n }\n\n // The user's locally declared aliases, i.e. `const [a, b] = aliases(Author, Book)`,\n // aren't guaranteed to line up with the aliases we've assigned internally, like `a`\n // might actually be `a1` if there are two `authors` tables in the query, so push the\n // canonical alias value for the current clause into the Alias.\n if (filter && typeof filter === \"object\" && \"as\" in filter && isAlias(filter.as)) {\n aliasBindings.set(getAliasMgmt(filter.as), { meta, alias });\n } else if (isAlias(filter)) {\n aliasBindings.set(getAliasMgmt(filter), { meta, alias });\n }\n\n addFilterAt(meta, alias, filter, targetCb, ef, join);\n }\n\n function addFilterAt(\n meta: EntityMetadata,\n tableAlias: string,\n filter: any,\n targetCb: ConditionBuilder,\n parsed: ParsedEntityFilter | undefined = parseEntityFilter(meta, filter),\n parentJoin: ParsedTable[\"join\"] = \"primary\",\n ): void {\n if (isScope(filter)) {\n addScopeFilterAt(meta, tableAlias, filter, targetCb, parentJoin);\n } else if (parsed && parsed.kind === \"join\") {\n addSubFilter(meta, tableAlias, parsed.subFilter, targetCb, parentJoin);\n } else if (parsed) {\n const column = meta.fields[\"id\"].serde!.columns[0];\n targetCb.addValueFilter(tableAlias, column, parsed);\n }\n }\n\n function addScopeFilterAt<T extends Entity>(\n meta: EntityMetadata<T>,\n tableAlias: string,\n scope: Scope<T>,\n targetCb: ConditionBuilder,\n parentJoin: ParsedTable[\"join\"],\n ): void {\n for (const fragment of resolveScope(scope).fragments) {\n if (fragment.kind === \"filter\") {\n addFilterAt(meta, tableAlias, fragment.filter, targetCb, undefined, parentJoin);\n } else {\n const a = newAlias(meta.cstr);\n const result = fragment.fn(a);\n aliasBindings.set(getAliasMgmt(a), { meta, alias: tableAlias });\n if (isScopeJoinFilter(result)) {\n // Parse the join tree first so its `as:` bindings re-root the aliases that\n // `conditions` reference, then add the conditions against the now-bound aliases.\n addFilterAt(meta, tableAlias, result.where, targetCb, undefined, parentJoin);\n checkDomainCondition(result.conditions);\n targetCb.maybeAddExpression(result.conditions);\n } else {\n const conditions = Array.isArray(result) ? result : [result];\n for (const condition of conditions) checkDomainCondition(condition);\n if (conditions.length > 0) targetCb.maybeAddExpression({ and: conditions });\n }\n }\n }\n }\n\n function addSubFilter(\n meta: EntityMetadata,\n tableAlias: string,\n subFilter: object,\n targetCb: ConditionBuilder,\n parentJoin: ParsedTable[\"join\"],\n ): void {\n // subFilter really means we're matching against the entity columns/further joins\n Object.keys(subFilter).forEach((key) => {\n // Skip the `{ as: ... }` alias binding\n if (key === \"as\") return;\n if (key === \"and\" || key === \"or\") {\n addLogicalFilter(meta, tableAlias, key, (subFilter as any)[key], targetCb, parentJoin);\n return;\n }\n const field = findFilterField(meta, key) ?? fail(`Field '${key}' not found on ${meta.tableName}`);\n const fa = `${tableAlias}${field.aliasSuffix}`;\n if (field.kind === \"primitive\" || field.kind === \"primaryKey\" || field.kind === \"enum\") {\n const column = field.serde.columns[0];\n parseValueFilter((subFilter as any)[key]).forEach((filter) => {\n targetCb.addValueFilter(fa, column, filter);\n });\n } else if (field.kind === \"m2o\") {\n const column = field.serde.columns[0];\n const sub = (subFilter as any)[key];\n const joinKind = field.required && parentJoin !== \"outer\" ? \"inner\" : \"outer\";\n if (isAlias(sub)) {\n const a = getAlias(field.otherMetadata().tableName);\n addTable(\n field.otherMetadata(),\n a,\n joinKind,\n kqDot(fa, column.columnName),\n kqDot(a, \"id\"),\n sub,\n undefined,\n targetCb,\n );\n }\n const f = parseEntityFilter(field.otherMetadata(), sub);\n // Probe the filter and see if it's just an id, if so we can avoid the join; m2os don't need\n // a join for soft-delete filtering because references don't filter out soft-deletes.\n if (!f) {\n // skip\n } else if (f.kind === \"join\") {\n const a = getAlias(field.otherMetadata().tableName);\n addTable(\n field.otherMetadata(),\n a,\n joinKind,\n kqDot(fa, column.columnName),\n kqDot(a, \"id\"),\n sub,\n undefined,\n targetCb,\n );\n } else {\n targetCb.addValueFilter(fa, column, f);\n }\n } else if (field.kind === \"poly\") {\n const f = parseEntityFilter(meta, (subFilter as any)[key]);\n if (!f) {\n // skip\n } else if (f.kind === \"join\") {\n throw new Error(\"Joins through polys are not supported\");\n } else {\n // We're left with basically a ValueFilter against the ids\n // For now only support eq/ne/in/is-null\n if (f.kind === \"eq\" || f.kind === \"ne\") {\n const comp = field.components.find((p) => {\n const otherMeta = p.otherMetadata();\n const cstr = getConstructorFromTaggedId(f.value as string);\n // tagged ids from subclasses always map to the base class, so we should compare to the base class if we don't directly match\n return otherMeta.cstr === cstr || otherMeta.baseType === cstr.name;\n });\n if (!comp) fail(`Invalid tagged id passed to ${meta.type}.${key}: ${f.value}`);\n const column = field.serde.columns.find((c) => c.columnName === comp.columnName)!;\n targetCb.addValueFilter(fa, column, f);\n } else if (f.kind === \"is-null\") {\n // Add a condition for every component--these can be AND-d with the rest of the simple/inline conditions\n field.components.forEach((comp) => {\n const column = field.serde.columns.find((c) => c.columnName === comp.columnName)!;\n targetCb.addSimpleCondition({\n kind: \"column\",\n alias: fa,\n column: comp.columnName,\n dbType: column.dbType,\n cond: f,\n });\n });\n } else if (f.kind === \"not-null\") {\n const conditions = field.components.map((comp) => {\n const column = field.serde.columns.find((c) => c.columnName === comp.columnName)!;\n return {\n kind: \"column\",\n alias: fa,\n column: comp.columnName,\n dbType: column.dbType,\n cond: { kind: \"not-null\" },\n };\n }) satisfies ColumnCondition[];\n targetCb.addParsedExpression({ kind: \"exp\", op: \"or\", conditions });\n } else if (f.kind === \"in\") {\n // An empty `in` matches nothing, so emit a single always-false condition (consistent\n // with a non-poly m2o `{ relation: [] }`); otherwise grouping by constructor would yield\n // zero conditions and prune the filter entirely, incorrectly matching every row.\n if (f.value.length === 0) {\n targetCb.addValueFilter(fa, field.serde.columns[0], { kind: \"in\", value: [] });\n return;\n }\n // Split up the ids by constructor\n const idsByConstructor = groupBy(f.value, (id) => getConstructorFromTaggedId(id as string).name);\n // Or together `parent_book_id in (1,2,3) OR parent_author_id IN (4,5,6)`\n // ...if there is a `parent IN [b:1, b:2, a:1, null]` we'd need to pull the `null` out and do an `OR (all columns are null)`...\n const conditions = Object.entries(idsByConstructor).map(([cstrName, ids]) => {\n const column =\n field.serde.columns.find(\n // tagged ids from subclasses always map to the base class, so we should compare to the base class if we don't directly match\n (c) => c.otherMetadata().cstr.name === cstrName || c.otherMetadata().baseType === cstrName,\n ) ?? fail(`Invalid tagged ids passed to ${meta.type}.${key}: ${ids}`);\n return {\n kind: \"column\",\n alias: fa,\n column: column.columnName,\n dbType: column.dbType,\n cond: mapToDb(column, { kind: \"in\", value: ids }),\n } satisfies ColumnCondition;\n });\n targetCb.addParsedExpression({ kind: \"exp\", op: \"or\", conditions });\n } else {\n throw new Error(`Filters on polys for ${f.kind} are not supported`);\n }\n }\n } else if (field.kind === \"o2o\") {\n // We have to always join into o2os, i.e. we can't probe the filter like we do for m2os\n const otherMeta = field.otherMetadata();\n const a = getAlias(otherMeta.tableName);\n const otherField = otherMeta.allFields[field.otherFieldName];\n const otherColumn =\n // if our other is a poly, we need to find a matching column rather than just picking the first\n otherField.kind === \"poly\"\n ? otherField.components.find((c) => c.otherMetadata() === meta || c.otherMetadata() === getBaseMeta(meta))!\n .columnName\n : otherField.serde!.columns[0].columnName;\n addTable(\n field.otherMetadata(),\n a,\n \"outer\",\n kqDot(tableAlias, \"id\"),\n kqDot(a, otherColumn),\n (subFilter as any)[key],\n field.otherFieldName,\n targetCb,\n );\n } else if (field.kind === \"o2m\") {\n const otherMeta = field.otherMetadata();\n const otherField = otherMeta.allFields[field.otherFieldName];\n let otherColumn = otherField.serde!.columns[0].columnName;\n if (otherField.kind === \"poly\") {\n const otherComponent =\n otherField.components.find((c) => c.otherMetadata() === meta) ??\n fail(`No poly component found for ${otherField.fieldName}`);\n otherColumn = otherComponent.columnName;\n }\n const isCtiBaseFk =\n otherMeta.inheritanceType === \"cti\" && field.otherFieldName && !(field.otherFieldName in otherMeta.fields);\n const a = getAlias(otherMeta.tableName);\n addTable(\n otherMeta,\n a,\n \"outer\",\n kqDot(tableAlias, \"id\"),\n kqDot(a, otherColumn),\n (subFilter as any)[key],\n field.otherFieldName,\n targetCb,\n true,\n );\n if (!isCtiBaseFk) {\n const table = tables.find((t) => t.alias === a);\n if (table && (table.join === \"inner\" || table.join === \"outer\")) {\n table.collection = { parentAlias: tableAlias, rootAlias: a, kind: \"o2m\" };\n }\n }\n } else if (field.kind === \"m2m\") {\n const sub = (subFilter as any)[key];\n const f = parseEntityFilter(field.otherMetadata(), sub);\n if (!f && !isAlias(sub)) return;\n\n const ja = getAlias(field.joinTableName);\n tables.push({\n join: \"outer\",\n alias: ja,\n table: field.joinTableName,\n col1: kqDot(tableAlias, \"id\"),\n col2: kqDot(ja, field.columnNames[0]),\n collection: { parentAlias: tableAlias, rootAlias: ja, kind: \"m2m\" },\n });\n\n if (isAlias(sub) || f?.kind === \"join\" || filterSoftDeletes(field.otherMetadata(), softDeletes)) {\n const a = getAlias(field.otherMetadata().tableName);\n addTable(\n field.otherMetadata(),\n a,\n \"outer\",\n kqDot(ja, field.columnNames[1]),\n kqDot(a, \"id\"),\n sub,\n undefined,\n targetCb,\n true,\n );\n const table = tables.find((t) => t.alias === a);\n if (table && (table.join === \"inner\" || table.join === \"outer\")) {\n table.collection = { parentAlias: ja, rootAlias: ja, kind: \"m2m\" };\n }\n } else if (f) {\n const otherMeta = field.otherMetadata();\n const column: any = {\n columnName: field.columnNames[1],\n dbType: otherMeta.idDbType,\n mapToDb(value: any) {\n return value === null ? value : keyToNumber(otherMeta, maybeResolveReferenceToId(value));\n },\n };\n targetCb.addSimpleCondition({\n kind: \"column\",\n alias: ja,\n column: field.columnNames[1],\n dbType: otherMeta.idDbType,\n cond: mapToDb(column, f),\n });\n }\n } else if (field.kind === \"m2mEnum\") {\n // Membership filter, e.g. `{ logoColors: Color.Red }` / `{ logoColors: [Red, Green] }`: join the\n // join table and filter its enum-id column, mapping enum codes -> their numeric ids.\n const ja = getAlias(field.joinTableName);\n tables.push({\n join: \"outer\",\n alias: ja,\n table: field.joinTableName,\n col1: kqDot(tableAlias, \"id\"),\n col2: kqDot(ja, field.columnNames[0]),\n collection: { parentAlias: tableAlias, rootAlias: ja, kind: \"m2m\" },\n });\n const column: any = {\n columnName: field.columnNames[1],\n dbType: \"int\",\n mapToDb(value: any) {\n return value === null || value === undefined ? value : field.enumDetailType.getByCode(value).id;\n },\n };\n parseValueFilter((subFilter as any)[key]).forEach((filter) => {\n targetCb.addValueFilter(ja, column, filter);\n });\n } else {\n throw new Error(`Unsupported field ${key}`);\n }\n });\n }\n\n function addLogicalFilter(\n meta: EntityMetadata,\n tableAlias: string,\n op: \"and\" | \"or\",\n value: unknown,\n targetCb: ConditionBuilder,\n parentJoin: ParsedTable[\"join\"],\n ): void {\n const filters = Array.isArray(value) ? value : [value];\n const conditions = filters.flatMap((filter) => {\n const branchCb = new ConditionBuilder();\n addFilterAt(meta, tableAlias, filter, branchCb, undefined, parentJoin);\n const condition = branchCb.toExpressionFilter();\n return condition ? [condition] : [];\n });\n if (conditions.length > 0) targetCb.addParsedExpression({ kind: \"exp\", op, conditions });\n }\n\n function addOrderBy(meta: EntityMetadata, alias: string, orderBy: Record<string, any>): void {\n const entries = Object.entries(orderBy);\n if (entries.length === 0) return;\n for (const [key, value] of entries) {\n if (!value) continue; // prune undefined\n const field = meta.allFields[key] ?? fail(`${key} not found on ${meta.tableName}`);\n if (field.kind === \"primitive\" || field.kind === \"primaryKey\" || field.kind === \"enum\") {\n const column = field.serde.columns[0];\n orderBys.push({\n alias: `${alias}${field.aliasSuffix ?? \"\"}`,\n column: column.columnName,\n order: value as OrderBy,\n });\n } else if (field.kind === \"m2o\") {\n // Do we already this table joined in?\n let table = tables.find((t) => t.table === field.otherMetadata().tableName);\n if (table) {\n addTablePerClassJoinsAndClassTag(query, field.otherMetadata(), table.alias, false);\n addOrderBy(field.otherMetadata(), table.alias, value);\n } else {\n const table = field.otherMetadata().tableName;\n const a = getAlias(table);\n const column = field.serde.columns[0].columnName;\n const fa = getMaybeCtiAlias(meta, field, meta, alias);\n // If we don't have a join, don't force this to be an inner join\n tables.push({\n alias: a,\n table,\n join: \"outer\",\n col1: kqDot(fa, column),\n col2: kqDot(a, \"id\"),\n distinct: false,\n });\n addTablePerClassJoinsAndClassTag(query, field.otherMetadata(), a, false);\n addOrderBy(field.otherMetadata(), a, value);\n }\n } else {\n throw new Error(`Unsupported field ${key}`);\n }\n }\n }\n\n // always add the main table\n const alias = getAlias(meta.tableName);\n if (meta.hasLazyColumns) {\n selects.push(...lazyExcludedSelects(meta, alias));\n } else {\n selects.push(`${kq(alias)}.*`);\n }\n addTable(meta, alias, \"primary\", \"n/a\", \"n/a\", filter);\n\n // If they passed extra `conditions: ...`, parse that\n if (optsExpression) {\n checkDomainCondition(optsExpression);\n cb.maybeAddExpression(optsExpression);\n }\n\n Object.assign(query, {\n condition: cb.toExpressionFilter(),\n });\n\n // Resolve alias-built conditions against this parse's bindings, before anything reads their\n // aliases (the id-not-null injection just below, and join pruning)\n resolveAliasConditions(query, aliasBindings);\n\n if (query.tables.some((t) => t.join === \"outer\")) {\n maybeAddIdNotNulls(query);\n }\n\n if (orderBy) {\n if (Array.isArray(orderBy)) {\n for (const ob of orderBy) addOrderBy(meta, alias, ob);\n } else {\n addOrderBy(meta, alias, orderBy);\n }\n }\n maybeAddOrderBy(query, meta, alias);\n\n if (pruneJoins) {\n pruneUnusedJoins(query, keepAliases);\n }\n return query;\n}\n\n/**\n * Look for conditions doing `some_column IS NULL` in an outer join that\n * need an `id IS NOT NULL` to make sure they don't match inadvertently on\n * the child row simply not existing.\n *\n * Note: Instead of injecting an extra `id IS NOT NULL` condition, I had tried\n * using all INNER JOINs and flipping joins to OUTER only if the user explicit\n * had `id IS NULL` in their filter, but that didn't work for queries that wanted\n * to do an `OR` across two different children (which queries both children being\n * OUTER JOINs, and detecting that case seemed complicated).\n */\nexport function maybeAddIdNotNulls(query: ParsedFindQuery): void {\n visitConditions(query, {\n visitCond(c: ColumnCondition) {\n // Check `c.prunable` to make sure we don't catch our injected `deleted_at is null` conditions\n if (c.cond.kind !== \"is-null\" || c.column === \"id\" || c.pruneable) {\n return c;\n }\n // This is an `some_column IS NULL`, is it in an outer join?\n const table = query.tables.find((t) => t.alias === c.alias);\n if (table && table.join === \"outer\") {\n const meta = getMetadataForTable(table.table);\n return {\n kind: \"exp\",\n op: \"and\",\n conditions: [\n c,\n {\n kind: \"column\",\n alias: c.alias,\n column: \"id\",\n dbType: meta.idDbType,\n cond: { kind: \"not-null\" },\n },\n ],\n } satisfies ParsedExpressionFilter;\n }\n return c;\n },\n });\n}\n\n/** Returns the `a` from `\"a\".*`. */\nexport function parseAlias(alias: string): string {\n return alias.split(\".\")[0].replaceAll(`\"`, \"\");\n}\n\n/** Finds a filter field by fieldName or generated fieldIdName. */\nexport function findFilterField(meta: EntityMetadata, key: string): (Field & { aliasSuffix: string }) | undefined {\n return (\n meta.allFields[key] ??\n meta.polyComponentFields?.[key] ??\n Object.values(meta.allFields).find((field) => field.fieldIdName === key) ??\n Object.values(meta.polyComponentFields ?? {}).find((field) => field.fieldIdName === key)\n );\n}\n\n/** Adds any user-configured default order, plus an \"always order by id\" for determinism. */\nexport function maybeAddOrderBy(query: ParsedFindQuery, meta: EntityMetadata, alias: string): void {\n const { orderBys } = query;\n if (meta.orderBy) {\n const field = meta.allFields[meta.orderBy] ?? fail(`${meta.orderBy} not found on ${meta.tableName}`);\n const column = field.serde!.columns[0].columnName;\n const hasAlready = orderBys.find((o) => o.alias === alias && o.column === column);\n if (!hasAlready) {\n orderBys.push({ alias, column, order: \"ASC\" });\n }\n }\n // Even if they already added orders, add id as the last one to get deterministic output\n const hasIdOrder = orderBys.find((o) => o.alias === alias && o.column === \"id\");\n if (!hasIdOrder) {\n orderBys.push({ alias, column: \"id\", order: \"ASC\" });\n }\n}\n\nexport function addTablePerClassJoinsAndClassTag(\n query: ParsedFindQuery,\n meta: EntityMetadata,\n alias: string,\n isPrimary: boolean,\n): void {\n if (!needsClassPerTableJoins(meta)) return;\n const { selects, tables } = query;\n // When `.load(SmallPublisher)` is called, join in base tables like `Publisher`\n meta.baseTypes.forEach((bt, i) => {\n if (isPrimary) {\n selects.push(`${alias}_b${i}.*`);\n }\n tables.push({\n alias: `${alias}_b${i}`,\n table: bt.tableName,\n join: \"outer\",\n col1: kqDot(alias, \"id\"),\n col2: `${alias}_b${i}.id`,\n distinct: false,\n });\n });\n\n // We always join in the base table in case a query happens to use\n // it as a filter, but we only need to do the subtype joins + selects\n // if this is the primary table\n if (isPrimary) {\n // Watch for subTypes that share column names. It'd be great to do\n // this statically at codegen time, like a meta.sharedSubtypeColumns.\n const stColumns: { stAlias: string; columnName: string }[] = [];\n\n // When `.load(Publisher)` is called, join in sub tables like `SmallPublisher` and `LargePublisher`\n meta.subTypes.forEach((st, i) => {\n const stAlias = `${alias}_s${i}`;\n selects.push(`${stAlias}.*`);\n tables.push({\n alias: stAlias,\n table: st.tableName,\n join: \"outer\",\n col1: kqDot(alias, \"id\"),\n col2: `${alias}_s${i}.id`,\n distinct: false,\n });\n for (const field of Object.values(st.fields)) {\n if (field.fieldName !== \"id\" && field.serde) {\n for (const c of field.serde?.columns) {\n stColumns.push({ stAlias, columnName: c.columnName });\n }\n }\n }\n });\n\n // Nominate a specific `id` column to avoid ambiguity\n selects.push(`${kq(alias)}.id as id`);\n\n // Add an explicit coalesce for shared columns\n Object.values(groupBy(stColumns, (c) => c.columnName))\n .filter((columns) => columns.length > 1)\n .forEach((columns) => {\n const { columnName } = columns[0];\n selects.push(`COALESCE(${columns.map((c) => `${c.stAlias}.${columnName}`).join(\", \")}) as ${columnName}`);\n });\n\n // If our meta has no subtypes, we're a left type and don't need a __class\n const cases = meta.subTypes.map((st, i) => `WHEN ${alias}_s${i}.id IS NOT NULL THEN '${st.type}'`);\n if (cases.length > 0) {\n selects.push(`CASE ${cases.join(\" \")} ELSE '_' END as __class`);\n }\n }\n}\n\n/** Rejects SQL predicates throughout a domain condition tree before optional-filter pruning. */\nfunction checkDomainCondition(condition: ConditionInput | undefined): void {\n if (!condition) return;\n if (isDeferredCondition(condition) || (predicateBrand in condition && condition[predicateBrand] === \"sql\")) {\n fail(\"SQL predicates are only supported by em.query/em.execute; use alias(...) predicates in em.find and scopes.\");\n }\n if (\"and\" in condition && condition.and) {\n for (const child of condition.and) checkDomainCondition(child);\n } else if (\"or\" in condition && condition.or) {\n for (const child of condition.or) checkDomainCondition(child);\n }\n}\n\n/** Resolves every `DeferredAliasCondition` in `query` against the parse's alias bindings. */\nfunction resolveAliasConditions(\n query: ParsedFindQuery,\n bindings: Map<AliasMgmt, { meta: EntityMetadata; alias: string }>,\n): void {\n function resolve(handle: AliasMgmt): { meta: EntityMetadata; alias: string } {\n return bindings.get(handle) ?? fail(`Alias for ${handle.tableName} is not bound to this query's join literal`);\n }\n function maybeResolve<C extends ColumnCondition | RawCondition>(c: C): C | undefined {\n return isDeferredAliasCondition(c) ? c[deferredAliasSym](resolve) : undefined;\n }\n visitConditions(query, { visitCond: maybeResolve, visitRaw: maybeResolve });\n}\n\nexport function getTables(query: ParsedFindQuery): [PrimaryTable, JoinTable[], LateralJoinTable[], CrossJoinTable[]] {\n let primary: PrimaryTable;\n const joins: JoinTable[] = [];\n const laterals: LateralJoinTable[] = [];\n const crosses: CrossJoinTable[] = [];\n for (const table of query.tables) {\n if (table.join === \"primary\") {\n primary = table;\n } else if (table.join === \"lateral\") {\n laterals.push(table);\n } else if (table.join === \"cross\") {\n crosses.push(table);\n } else {\n joins.push(table);\n }\n }\n return [primary!, joins, laterals, crosses];\n}\n\nfunction needsClassPerTableJoins(meta: EntityMetadata): boolean {\n return meta.inheritanceType === \"cti\" && (meta.subTypes.length > 0 || meta.baseTypes.length > 0);\n}\n\nfunction needsStiDiscriminator(meta: EntityMetadata): boolean {\n return meta.inheritanceType === \"sti\" && !meta.stiDiscriminatorField;\n}\n\nfunction addStiSubtypeFilter(cb: ConditionBuilder, subtypeMeta: EntityMetadata, alias: string): void {\n const cond = stiSubtypeFilter(subtypeMeta, alias);\n if (cond) cb.addSimpleCondition(cond);\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryParser.d.cts","names":[],"sources":["../../../src/queries/find/QueryParser.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"QueryParser.d.cts","names":[],"sources":["../../../src/queries/find/QueryParser.ts"],"mappings":";;;;UA6BiB;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;;;;;;;;;;;;;;;;;;;;;;EAsBA;;IAEE;;IAEA;;IAEA;;;;;;;;;;;;;;;;;;;;;UAsBa;EACf;;EAEA;;EAEA;;;;;;;;;;;;;UAce;;EAEf;;EAEA;IAAY;IAAoB;;;EAEhC;IAAS;IAAa;IAAa;;IAA+B;IAAa,OAAO;;;EAEtF;;;;;UAMe;EACf;EACA;;EAEA;;EAEA;;EAEA,OAAO;;EAEP;IAAa;IAAgB;;;KAGnB,cAAc,eAAe,YAAY,iBAAiB;UAErD;EACf;EACA;EACA,OAAO;;KAGG;EAAkB;EAAe;;EAAqB;;KAEtD,wBAAwB;KAC/B;EAA6B;EAAa;EAAiB;;;UAG/C;EACf,SAAS;;EAET,QAAQ;;EAER,YAAY;;EAEZ,WAAW;;EAEX,UAAU;;EAEV,OAAO;;;;;;;;iBASO,eACd,MAAM,gBACN,aACA;EACE,aAAa;EACb;EACA;EACA;EACA;EACA;EACA;IAED;;;;;;;;;;;;iBAqhBa,mBAAmB,OAAO;;iBAgC1B,WAAW;;iBAKX,gBAAgB,MAAM,gBAAgB,eAAe;EAAU;;;iBAU/D,gBAAgB,OAAO,iBAAiB,MAAM,gBAAgB;iBAiB9D,iCACd,OAAO,iBACP,MAAM,gBACN,eACA;iBA8Fc,UAAU,OAAO,mBAAmB,cAAc,aAAa,oBAAoB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryParser.d.mts","names":[],"sources":["../../../src/queries/find/QueryParser.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"QueryParser.d.mts","names":[],"sources":["../../../src/queries/find/QueryParser.ts"],"mappings":";;;;UA6BiB;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;;;;;;;;;;;;;;;;;;;;;;EAsBA;;IAEE;;IAEA;;IAEA;;;;;;;;;;;;;;;;;;;;;UAsBa;EACf;;EAEA;;EAEA;;;;;;;;;;;;;UAce;;EAEf;;EAEA;IAAY;IAAoB;;;EAEhC;IAAS;IAAa;IAAa;;IAA+B;IAAa,OAAO;;;EAEtF;;;;;UAMe;EACf;EACA;;EAEA;;EAEA;;EAEA,OAAO;;EAEP;IAAa;IAAgB;;;KAGnB,cAAc,eAAe,YAAY,iBAAiB;UAErD;EACf;EACA;EACA,OAAO;;KAGG;EAAkB;EAAe;;EAAqB;;KAEtD,wBAAwB;KAC/B;EAA6B;EAAa;EAAiB;;;UAG/C;EACf,SAAS;;EAET,QAAQ;;EAER,YAAY;;EAEZ,WAAW;;EAEX,UAAU;;EAEV,OAAO;;;;;;;;iBASO,eACd,MAAM,gBACN,aACA;EACE,aAAa;EACb;EACA;EACA;EACA;EACA;EACA;IAED;;;;;;;;;;;;iBAqhBa,mBAAmB,OAAO;;iBAgC1B,WAAW;;iBAKX,gBAAgB,MAAM,gBAAgB,eAAe;EAAU;;;iBAU/D,gBAAgB,OAAO,iBAAiB,MAAM,gBAAgB;iBAiB9D,iCACd,OAAO,iBACP,MAAM,gBACN,eACA;iBA8Fc,UAAU,OAAO,mBAAmB,cAAc,aAAa,oBAAoB"}
|
|
@@ -4,7 +4,7 @@ import { predicateBrand } from "../conditions.js";
|
|
|
4
4
|
import { deferredAliasSym, isDeferredAliasCondition } from "./DeferredAlias.js";
|
|
5
5
|
import { alias, getAliasMgmt, getMaybeCtiAlias, isAlias } from "./Aliases.js";
|
|
6
6
|
import { isScope, isScopeJoinFilter, resolveScope } from "./scopes.js";
|
|
7
|
-
import {
|
|
7
|
+
import { mapToDb, parseEntityFilter, parseValueFilter } from "../valueFilters.js";
|
|
8
8
|
import { ConditionBuilder } from "../ConditionBuilder.js";
|
|
9
9
|
import { filterSoftDeletes, lazyExcludedSelects, stiSubtypeFilter } from "../entityQueryUtils.js";
|
|
10
10
|
import { pruneUnusedJoins } from "./QueryParser.pruning.js";
|
|
@@ -173,7 +173,6 @@ function parseFindQuery(meta, filter, opts = {}) {
|
|
|
173
173
|
const f = parseEntityFilter(meta, subFilter[key]);
|
|
174
174
|
if (!f) {} else if (f.kind === "join") throw new Error("Joins through polys are not supported");
|
|
175
175
|
else if (f.kind === "eq" || f.kind === "ne") {
|
|
176
|
-
if (isNilIdValue(f.value)) return;
|
|
177
176
|
const comp = field.components.find((p) => {
|
|
178
177
|
const otherMeta = p.otherMetadata();
|
|
179
178
|
const cstr = getConstructorFromTaggedId(f.value);
|
|
@@ -290,7 +289,7 @@ function parseFindQuery(meta, filter, opts = {}) {
|
|
|
290
289
|
columnName: field.columnNames[1],
|
|
291
290
|
dbType: otherMeta.idDbType,
|
|
292
291
|
mapToDb(value) {
|
|
293
|
-
return value === null
|
|
292
|
+
return value === null ? value : keyToNumber(otherMeta, maybeResolveReferenceToId(value));
|
|
294
293
|
}
|
|
295
294
|
};
|
|
296
295
|
targetCb.addSimpleCondition({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryParser.js","names":["newAlias","alias"],"sources":["../../../src/queries/find/QueryParser.ts"],"sourcesContent":["import { groupBy } from \"joist-utils\";\nimport { getConstructorFromTaggedId, getMetadataForTable } from \"src/configure.ts\";\nimport type { Entity } from \"src/Entity.ts\";\nimport { type EntityMetadata, type Field, getBaseMeta } from \"src/EntityMetadata.ts\";\nimport { keyToNumber, maybeResolveReferenceToId } from \"src/keys.ts\";\nimport { ConditionBuilder } from \"src/queries/ConditionBuilder.ts\";\nimport { type ConditionInput, predicateBrand } from \"src/queries/conditions.ts\";\nimport { filterSoftDeletes, lazyExcludedSelects, stiSubtypeFilter } from \"src/queries/entityQueryUtils.ts\";\nimport {\n type AliasMgmt,\n getAliasMgmt,\n getMaybeCtiAlias,\n isAlias,\n alias as newAlias,\n} from \"src/queries/find/Aliases.ts\";\nimport { deferredAliasSym, isDeferredAliasCondition } from \"src/queries/find/DeferredAlias.ts\";\nimport type { ExpressionFilter, OrderBy } from \"src/queries/find/EntityFilter.ts\";\nimport { pruneUnusedJoins } from \"src/queries/find/QueryParser.pruning.ts\";\nimport { visitConditions } from \"src/queries/find/QueryVisitor.ts\";\nimport { type Scope, isScope, isScopeJoinFilter, resolveScope } from \"src/queries/find/scopes.ts\";\nimport type { ColumnCondition, ParsedExpressionFilter, RawCondition } from \"src/queries/parsedConditions.ts\";\nimport { isDeferredCondition } from \"src/queries/sql/Expr.ts\";\nimport { kq, kqDot } from \"src/queries/sql/keywords.ts\";\nimport {\n type ParsedEntityFilter,\n isNilIdValue,\n mapToDb,\n parseEntityFilter,\n parseValueFilter,\n} from \"src/queries/valueFilters.ts\";\nimport { abbreviation, fail } from \"src/utils.ts\";\n\n// `skipCondition` lives in its own leaf module, shared by domain aliases and SQL expressions\n// without a load-order cycle; `index.ts` re-exports it directly.\n\nexport interface PrimaryTable {\n join: \"primary\";\n alias: string;\n table: string;\n}\n\nexport interface JoinTable {\n join: \"inner\" | \"outer\";\n alias: string;\n table: string;\n col1: string;\n col2: string;\n distinct?: boolean;\n /**\n * Metadata used by `optimizeCollectionJoins` to rewrite collection joins into EXISTS.\n *\n * I.e. for `Author.books.reviews`:\n * ```sql\n * authors a\n * LEFT JOIN books b ON a.id = b.author_id\n * LEFT JOIN book_reviews br ON b.id = br.book_id\n * ```\n * `books b` has `parentAlias: \"a\"` and `rootAlias: \"b\"`, while `book_reviews br` has\n * `parentAlias: \"b\"` and `rootAlias: \"br\"`.\n *\n * I.e. for `Author.tags`, the m2m join table is the collection root:\n * ```sql\n * authors a\n * LEFT JOIN authors_to_tags att ON a.id = att.author_id\n * LEFT JOIN tags t ON att.tag_id = t.id\n * ```\n * `authors_to_tags att` has `alias: \"att\"` and `rootAlias: \"att\"`, while `tags t` has `alias: \"t\"`\n * but still has `rootAlias: \"att\"` because it belongs to the m2m subtree rooted at the join table.\n */\n collection?: {\n /** The collection relation type, i.e. `o2m` for `Author.books`, or `m2m` for `Author.tags`. */\n kind: \"o2m\" | \"m2m\";\n /** The alias that owns this collection path, i.e. `a` for `Author.books`, or `att` for `Author.tags -> tags`. */\n parentAlias: string;\n /** The top-level alias in this collection subtree, i.e. `b` for `Author.books.reviews`, or `att` for `Author.tags`. */\n rootAlias: string;\n };\n}\n\n/**\n * Creates a `CROSS JOIN`, currently used for our `em.find` batching.\n *\n * I.e. queries like:\n *\n * ```sql\n * WITH _find (tag, arg1, arg2) AS (VALUES\n * (0::int, 'a'::varchar, 'a'::varchar),\n * (1, 'b', 'b'),\n * (2, 'c', 'c')\n * )\n * SELECT a.*, array_agg(_find.tag) AS _tags\n * FROM authors a\n * CROSS JOIN _find AS _find\n * WHERE a.first_name = _find.arg0 OR a.last_name = _find.arg1\n * GROUP BY a.id\n * ```\n */\nexport interface CrossJoinTable {\n join: \"cross\";\n /** The new alias for the joined table. */\n alias: string;\n /** The table name to join into the query. */\n table: string;\n}\n\n/**\n * Adds `WITH` CTE clauses to the query.\n *\n * I.e. queries like:\n *\n * ```sql\n * WITH _find (tag, arg0, arg1) AS (\n * VALUES ($1::int, $2::character varying, $3::character varying), ($4, $5, $6)\n * )\n * ```\n */\nexport interface ParsedCteClause {\n /** The new alias for the CTE, i.e. `_find` in the above query. */\n alias: string;\n /** The columns, i.e. `tag, arg0, arg1` in the above query. */\n columns?: { columnName: string; dbType: string }[];\n /** The subquery for the AS of the CTE clause. */\n query: { kind: \"raw\"; sql: string; bindings: readonly any[] } | { kind: \"ast\"; query: ParsedFindQuery };\n /** Whether to include a `RECURSIVE` keyword after the `WITH`. */\n recursive?: boolean;\n}\n\n/**\n * Creates `LATERAL JOIN`s, currently used by `findCount` and JSON preloading.\n */\nexport interface LateralJoinTable {\n join: \"lateral\";\n alias: string;\n /** Used for join dependency tracking. */\n fromAlias: string;\n /** Used more for bookkeeping/consistency with other join tables than the query itself. */\n table: string;\n /** The subquery that will look for/roll-up N children. */\n query: ParsedFindQuery;\n /** Optional settings for the subquery, i.e. per-parent pagination. */\n settings?: { limit?: number; offset?: number };\n}\n\nexport type ParsedTable = PrimaryTable | JoinTable | CrossJoinTable | LateralJoinTable;\n\nexport interface ParsedOrderBy {\n alias: string;\n column: string;\n order: OrderBy;\n}\n\nexport type ParsedGroupBy = { alias: string; column: string } | { expression: string };\n\nexport type ParsedSelect = string | ParsedSelectWithBindings;\ntype ParsedSelectWithBindings = { sql: string; bindings: any[]; aliases: string[] };\n\n/** The result of parsing an `em.find` filter. */\nexport interface ParsedFindQuery {\n selects: ParsedSelect[];\n /** The primary table plus any joins. */\n tables: ParsedTable[];\n /** The query's conditions. */\n condition?: ParsedExpressionFilter;\n /** Extremely optional group bys; we generally don't support adhoc/aggregate queries, but the auto-batching infra uses these. */\n groupBys?: ParsedGroupBy[];\n /** Any optional orders to add before the default 'order by id'. */\n orderBys: ParsedOrderBy[];\n /** Optional CTE to prefix to the query, i.e. for recursive relations. */\n ctes?: ParsedCteClause[];\n}\n\n/**\n * Parses an `em.find` filter into a logical `ParsedFindQuery` AST, leaving optimization/pruning to callers.\n *\n * The main execution flow is:\n * parseFindQuery -> beforeFind plugins -> optimizeCollectionJoins -> pruneUnusedJoins -> execute SQL.\n */\nexport function parseFindQuery(\n meta: EntityMetadata,\n filter: any,\n opts: {\n conditions?: ExpressionFilter;\n orderBy?: any;\n pruneJoins?: boolean;\n keepAliases?: string[];\n softDeletes?: \"include\" | \"exclude\";\n allowMultipleLeftJoins?: boolean;\n optimizeJoinsToExists?: boolean;\n } = {},\n): ParsedFindQuery {\n const selects: string[] = [];\n const tables: ParsedTable[] = [];\n const orderBys: ParsedOrderBy[] = [];\n const query: ParsedFindQuery = { selects, tables, orderBys };\n const { orderBy, conditions: optsExpression, softDeletes = \"exclude\", pruneJoins = false, keepAliases = [] } = opts;\n const cb = new ConditionBuilder();\n // Where each user-created `alias(...)` is bound in this parse's join literal; alias-built conditions\n // (`a.firstName.eq(...)`) are resolved against it once the whole tree is walked\n const aliasBindings = new Map<AliasMgmt, { meta: EntityMetadata; alias: string }>();\n\n const aliases: Record<string, number> = {};\n function getAlias(tableName: string): string {\n const abbrev = abbreviation(tableName);\n const i = aliases[abbrev] || 0;\n aliases[abbrev] = i + 1;\n return i === 0 ? abbrev : `${abbrev}${i}`;\n }\n\n /** Adds a `deleted_at IS NULL` condition for `alias`, i.e. for the primary table or a collection join. */\n function addSoftDeleteCondition(meta: EntityMetadata, alias: string, targetCb: ConditionBuilder): void {\n if (filterSoftDeletes(meta, softDeletes)) {\n const column = meta.allFields[getBaseMeta(meta).timestampFields!.deletedAt!].serde?.columns[0]!;\n targetCb.addSimpleCondition({\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n cond: { kind: \"is-null\" },\n pruneable: true,\n });\n }\n }\n\n function addTable(\n meta: EntityMetadata,\n alias: string,\n join: ParsedTable[\"join\"],\n col1: string,\n col2: string,\n filter: any,\n fieldName?: string,\n targetCb: ConditionBuilder = cb,\n /** Whether this table is the \"other side\" of a collection, i.e. `books` in `em.find(Author, { books: ... })`. */\n isCollection: boolean = false,\n ): void {\n // look at filter, is it `{ book: \"b2\" }` or `{ book: { ... } }`\n const scopeFilter = isScope(filter);\n const ef = scopeFilter ? undefined : parseEntityFilter(meta, filter);\n if (!scopeFilter && !ef && join !== \"primary\" && !isAlias(filter)) {\n return;\n }\n\n if (join === \"primary\") {\n tables.push({ alias, table: meta.tableName, join });\n addTablePerClassJoinsAndClassTag({ selects, tables, orderBys }, meta, alias, true);\n } else if (meta.inheritanceType === \"cti\" && fieldName && !(fieldName in meta.fields)) {\n // For cti, our meta might be a subtype while the FK is actually on the base table. This should only be the case\n // when the fk is on another table (e.g. o2o/o2m). In these cases, we'll be passed a field name and can verify if\n // its directly in our meta, if not we should assume it's in the base type and join that in first.\n meta.baseTypes.forEach((bt, i) => {\n tables.push({\n alias: `${alias}_b${i}`,\n table: bt.tableName,\n join: \"outer\",\n col1,\n col2: `${kq(`${alias}_b${i}`)}.${col2.split(\".\")[1]}`,\n distinct: false,\n });\n // and we still need to join in our subtype as well in case its own fields are queried against\n tables.push({\n alias: `${alias}`,\n table: meta.tableName,\n join: \"outer\",\n col1: kqDot(alias, \"id\"),\n col2: kqDot(`${alias}_b${i}`, \"id\"),\n distinct: false,\n });\n });\n } else if (join === \"lateral\" || join === \"cross\") {\n fail(\"Unexpected lateral join\");\n } else {\n tables.push({ alias, table: meta.tableName, join, col1, col2 });\n // Maybe only do this if we're the primary, or have a field that needs it?\n addTablePerClassJoinsAndClassTag({ selects, tables, orderBys }, meta, alias, false);\n }\n\n if (needsStiDiscriminator(meta)) {\n addStiSubtypeFilter(targetCb, meta, alias);\n }\n\n // Only the primary table & collection joins filter soft-deletes, to match the in-memory relation\n // semantics of \"o2m/m2m collections filter out soft-deletes, but m2o/o2o references still return\n // them\". I.e. `book.author.get` returns a soft-deleted author, so `em.find(Book, { author: ... })`\n // should still match the book, as long as the book itself is not soft-deleted.\n if (join === \"primary\" || isCollection) {\n addSoftDeleteCondition(meta, alias, targetCb);\n }\n\n // The user's locally declared aliases, i.e. `const [a, b] = aliases(Author, Book)`,\n // aren't guaranteed to line up with the aliases we've assigned internally, like `a`\n // might actually be `a1` if there are two `authors` tables in the query, so push the\n // canonical alias value for the current clause into the Alias.\n if (filter && typeof filter === \"object\" && \"as\" in filter && isAlias(filter.as)) {\n aliasBindings.set(getAliasMgmt(filter.as), { meta, alias });\n } else if (isAlias(filter)) {\n aliasBindings.set(getAliasMgmt(filter), { meta, alias });\n }\n\n addFilterAt(meta, alias, filter, targetCb, ef, join);\n }\n\n function addFilterAt(\n meta: EntityMetadata,\n tableAlias: string,\n filter: any,\n targetCb: ConditionBuilder,\n parsed: ParsedEntityFilter | undefined = parseEntityFilter(meta, filter),\n parentJoin: ParsedTable[\"join\"] = \"primary\",\n ): void {\n if (isScope(filter)) {\n addScopeFilterAt(meta, tableAlias, filter, targetCb, parentJoin);\n } else if (parsed && parsed.kind === \"join\") {\n addSubFilter(meta, tableAlias, parsed.subFilter, targetCb, parentJoin);\n } else if (parsed) {\n const column = meta.fields[\"id\"].serde!.columns[0];\n targetCb.addValueFilter(tableAlias, column, parsed);\n }\n }\n\n function addScopeFilterAt<T extends Entity>(\n meta: EntityMetadata<T>,\n tableAlias: string,\n scope: Scope<T>,\n targetCb: ConditionBuilder,\n parentJoin: ParsedTable[\"join\"],\n ): void {\n for (const fragment of resolveScope(scope).fragments) {\n if (fragment.kind === \"filter\") {\n addFilterAt(meta, tableAlias, fragment.filter, targetCb, undefined, parentJoin);\n } else {\n const a = newAlias(meta.cstr);\n const result = fragment.fn(a);\n aliasBindings.set(getAliasMgmt(a), { meta, alias: tableAlias });\n if (isScopeJoinFilter(result)) {\n // Parse the join tree first so its `as:` bindings re-root the aliases that\n // `conditions` reference, then add the conditions against the now-bound aliases.\n addFilterAt(meta, tableAlias, result.where, targetCb, undefined, parentJoin);\n checkDomainCondition(result.conditions);\n targetCb.maybeAddExpression(result.conditions);\n } else {\n const conditions = Array.isArray(result) ? result : [result];\n for (const condition of conditions) checkDomainCondition(condition);\n if (conditions.length > 0) targetCb.maybeAddExpression({ and: conditions });\n }\n }\n }\n }\n\n function addSubFilter(\n meta: EntityMetadata,\n tableAlias: string,\n subFilter: object,\n targetCb: ConditionBuilder,\n parentJoin: ParsedTable[\"join\"],\n ): void {\n // subFilter really means we're matching against the entity columns/further joins\n Object.keys(subFilter).forEach((key) => {\n // Skip the `{ as: ... }` alias binding\n if (key === \"as\") return;\n if (key === \"and\" || key === \"or\") {\n addLogicalFilter(meta, tableAlias, key, (subFilter as any)[key], targetCb, parentJoin);\n return;\n }\n const field = findFilterField(meta, key) ?? fail(`Field '${key}' not found on ${meta.tableName}`);\n const fa = `${tableAlias}${field.aliasSuffix}`;\n if (field.kind === \"primitive\" || field.kind === \"primaryKey\" || field.kind === \"enum\") {\n const column = field.serde.columns[0];\n parseValueFilter((subFilter as any)[key]).forEach((filter) => {\n targetCb.addValueFilter(fa, column, filter);\n });\n } else if (field.kind === \"m2o\") {\n const column = field.serde.columns[0];\n const sub = (subFilter as any)[key];\n const joinKind = field.required && parentJoin !== \"outer\" ? \"inner\" : \"outer\";\n if (isAlias(sub)) {\n const a = getAlias(field.otherMetadata().tableName);\n addTable(\n field.otherMetadata(),\n a,\n joinKind,\n kqDot(fa, column.columnName),\n kqDot(a, \"id\"),\n sub,\n undefined,\n targetCb,\n );\n }\n const f = parseEntityFilter(field.otherMetadata(), sub);\n // Probe the filter and see if it's just an id, if so we can avoid the join; m2os don't need\n // a join for soft-delete filtering because references don't filter out soft-deletes.\n if (!f) {\n // skip\n } else if (f.kind === \"join\") {\n const a = getAlias(field.otherMetadata().tableName);\n addTable(\n field.otherMetadata(),\n a,\n joinKind,\n kqDot(fa, column.columnName),\n kqDot(a, \"id\"),\n sub,\n undefined,\n targetCb,\n );\n } else {\n targetCb.addValueFilter(fa, column, f);\n }\n } else if (field.kind === \"poly\") {\n const f = parseEntityFilter(meta, (subFilter as any)[key]);\n if (!f) {\n // skip\n } else if (f.kind === \"join\") {\n throw new Error(\"Joins through polys are not supported\");\n } else {\n // We're left with basically a ValueFilter against the ids\n // For now only support eq/ne/in/is-null\n if (f.kind === \"eq\" || f.kind === \"ne\") {\n if (isNilIdValue(f.value)) return;\n const comp = field.components.find((p) => {\n const otherMeta = p.otherMetadata();\n const cstr = getConstructorFromTaggedId(f.value as string);\n // tagged ids from subclasses always map to the base class, so we should compare to the base class if we don't directly match\n return otherMeta.cstr === cstr || otherMeta.baseType === cstr.name;\n });\n if (!comp) fail(`Invalid tagged id passed to ${meta.type}.${key}: ${f.value}`);\n const column = field.serde.columns.find((c) => c.columnName === comp.columnName)!;\n targetCb.addValueFilter(fa, column, f);\n } else if (f.kind === \"is-null\") {\n // Add a condition for every component--these can be AND-d with the rest of the simple/inline conditions\n field.components.forEach((comp) => {\n const column = field.serde.columns.find((c) => c.columnName === comp.columnName)!;\n targetCb.addSimpleCondition({\n kind: \"column\",\n alias: fa,\n column: comp.columnName,\n dbType: column.dbType,\n cond: f,\n });\n });\n } else if (f.kind === \"not-null\") {\n const conditions = field.components.map((comp) => {\n const column = field.serde.columns.find((c) => c.columnName === comp.columnName)!;\n return {\n kind: \"column\",\n alias: fa,\n column: comp.columnName,\n dbType: column.dbType,\n cond: { kind: \"not-null\" },\n };\n }) satisfies ColumnCondition[];\n targetCb.addParsedExpression({ kind: \"exp\", op: \"or\", conditions });\n } else if (f.kind === \"in\") {\n // An empty `in` matches nothing, so emit a single always-false condition (consistent\n // with a non-poly m2o `{ relation: [] }`); otherwise grouping by constructor would yield\n // zero conditions and prune the filter entirely, incorrectly matching every row.\n if (f.value.length === 0) {\n targetCb.addValueFilter(fa, field.serde.columns[0], { kind: \"in\", value: [] });\n return;\n }\n // Split up the ids by constructor\n const idsByConstructor = groupBy(f.value, (id) => getConstructorFromTaggedId(id as string).name);\n // Or together `parent_book_id in (1,2,3) OR parent_author_id IN (4,5,6)`\n // ...if there is a `parent IN [b:1, b:2, a:1, null]` we'd need to pull the `null` out and do an `OR (all columns are null)`...\n const conditions = Object.entries(idsByConstructor).map(([cstrName, ids]) => {\n const column =\n field.serde.columns.find(\n // tagged ids from subclasses always map to the base class, so we should compare to the base class if we don't directly match\n (c) => c.otherMetadata().cstr.name === cstrName || c.otherMetadata().baseType === cstrName,\n ) ?? fail(`Invalid tagged ids passed to ${meta.type}.${key}: ${ids}`);\n return {\n kind: \"column\",\n alias: fa,\n column: column.columnName,\n dbType: column.dbType,\n cond: mapToDb(column, { kind: \"in\", value: ids }),\n } satisfies ColumnCondition;\n });\n targetCb.addParsedExpression({ kind: \"exp\", op: \"or\", conditions });\n } else {\n throw new Error(`Filters on polys for ${f.kind} are not supported`);\n }\n }\n } else if (field.kind === \"o2o\") {\n // We have to always join into o2os, i.e. we can't probe the filter like we do for m2os\n const otherMeta = field.otherMetadata();\n const a = getAlias(otherMeta.tableName);\n const otherField = otherMeta.allFields[field.otherFieldName];\n const otherColumn =\n // if our other is a poly, we need to find a matching column rather than just picking the first\n otherField.kind === \"poly\"\n ? otherField.components.find((c) => c.otherMetadata() === meta || c.otherMetadata() === getBaseMeta(meta))!\n .columnName\n : otherField.serde!.columns[0].columnName;\n addTable(\n field.otherMetadata(),\n a,\n \"outer\",\n kqDot(tableAlias, \"id\"),\n kqDot(a, otherColumn),\n (subFilter as any)[key],\n field.otherFieldName,\n targetCb,\n );\n } else if (field.kind === \"o2m\") {\n const otherMeta = field.otherMetadata();\n const otherField = otherMeta.allFields[field.otherFieldName];\n let otherColumn = otherField.serde!.columns[0].columnName;\n if (otherField.kind === \"poly\") {\n const otherComponent =\n otherField.components.find((c) => c.otherMetadata() === meta) ??\n fail(`No poly component found for ${otherField.fieldName}`);\n otherColumn = otherComponent.columnName;\n }\n const isCtiBaseFk =\n otherMeta.inheritanceType === \"cti\" && field.otherFieldName && !(field.otherFieldName in otherMeta.fields);\n const a = getAlias(otherMeta.tableName);\n addTable(\n otherMeta,\n a,\n \"outer\",\n kqDot(tableAlias, \"id\"),\n kqDot(a, otherColumn),\n (subFilter as any)[key],\n field.otherFieldName,\n targetCb,\n true,\n );\n if (!isCtiBaseFk) {\n const table = tables.find((t) => t.alias === a);\n if (table && (table.join === \"inner\" || table.join === \"outer\")) {\n table.collection = { parentAlias: tableAlias, rootAlias: a, kind: \"o2m\" };\n }\n }\n } else if (field.kind === \"m2m\") {\n const sub = (subFilter as any)[key];\n const f = parseEntityFilter(field.otherMetadata(), sub);\n if (!f && !isAlias(sub)) return;\n\n const ja = getAlias(field.joinTableName);\n tables.push({\n join: \"outer\",\n alias: ja,\n table: field.joinTableName,\n col1: kqDot(tableAlias, \"id\"),\n col2: kqDot(ja, field.columnNames[0]),\n collection: { parentAlias: tableAlias, rootAlias: ja, kind: \"m2m\" },\n });\n\n if (isAlias(sub) || f?.kind === \"join\" || filterSoftDeletes(field.otherMetadata(), softDeletes)) {\n const a = getAlias(field.otherMetadata().tableName);\n addTable(\n field.otherMetadata(),\n a,\n \"outer\",\n kqDot(ja, field.columnNames[1]),\n kqDot(a, \"id\"),\n sub,\n undefined,\n targetCb,\n true,\n );\n const table = tables.find((t) => t.alias === a);\n if (table && (table.join === \"inner\" || table.join === \"outer\")) {\n table.collection = { parentAlias: ja, rootAlias: ja, kind: \"m2m\" };\n }\n } else if (f) {\n const otherMeta = field.otherMetadata();\n const column: any = {\n columnName: field.columnNames[1],\n dbType: otherMeta.idDbType,\n mapToDb(value: any) {\n return value === null || isNilIdValue(value)\n ? value\n : keyToNumber(otherMeta, maybeResolveReferenceToId(value));\n },\n };\n targetCb.addSimpleCondition({\n kind: \"column\",\n alias: ja,\n column: field.columnNames[1],\n dbType: otherMeta.idDbType,\n cond: mapToDb(column, f),\n });\n }\n } else if (field.kind === \"m2mEnum\") {\n // Membership filter, e.g. `{ logoColors: Color.Red }` / `{ logoColors: [Red, Green] }`: join the\n // join table and filter its enum-id column, mapping enum codes -> their numeric ids.\n const ja = getAlias(field.joinTableName);\n tables.push({\n join: \"outer\",\n alias: ja,\n table: field.joinTableName,\n col1: kqDot(tableAlias, \"id\"),\n col2: kqDot(ja, field.columnNames[0]),\n collection: { parentAlias: tableAlias, rootAlias: ja, kind: \"m2m\" },\n });\n const column: any = {\n columnName: field.columnNames[1],\n dbType: \"int\",\n mapToDb(value: any) {\n return value === null || value === undefined ? value : field.enumDetailType.getByCode(value).id;\n },\n };\n parseValueFilter((subFilter as any)[key]).forEach((filter) => {\n targetCb.addValueFilter(ja, column, filter);\n });\n } else {\n throw new Error(`Unsupported field ${key}`);\n }\n });\n }\n\n function addLogicalFilter(\n meta: EntityMetadata,\n tableAlias: string,\n op: \"and\" | \"or\",\n value: unknown,\n targetCb: ConditionBuilder,\n parentJoin: ParsedTable[\"join\"],\n ): void {\n const filters = Array.isArray(value) ? value : [value];\n const conditions = filters.flatMap((filter) => {\n const branchCb = new ConditionBuilder();\n addFilterAt(meta, tableAlias, filter, branchCb, undefined, parentJoin);\n const condition = branchCb.toExpressionFilter();\n return condition ? [condition] : [];\n });\n if (conditions.length > 0) targetCb.addParsedExpression({ kind: \"exp\", op, conditions });\n }\n\n function addOrderBy(meta: EntityMetadata, alias: string, orderBy: Record<string, any>): void {\n const entries = Object.entries(orderBy);\n if (entries.length === 0) return;\n for (const [key, value] of entries) {\n if (!value) continue; // prune undefined\n const field = meta.allFields[key] ?? fail(`${key} not found on ${meta.tableName}`);\n if (field.kind === \"primitive\" || field.kind === \"primaryKey\" || field.kind === \"enum\") {\n const column = field.serde.columns[0];\n orderBys.push({\n alias: `${alias}${field.aliasSuffix ?? \"\"}`,\n column: column.columnName,\n order: value as OrderBy,\n });\n } else if (field.kind === \"m2o\") {\n // Do we already this table joined in?\n let table = tables.find((t) => t.table === field.otherMetadata().tableName);\n if (table) {\n addTablePerClassJoinsAndClassTag(query, field.otherMetadata(), table.alias, false);\n addOrderBy(field.otherMetadata(), table.alias, value);\n } else {\n const table = field.otherMetadata().tableName;\n const a = getAlias(table);\n const column = field.serde.columns[0].columnName;\n const fa = getMaybeCtiAlias(meta, field, meta, alias);\n // If we don't have a join, don't force this to be an inner join\n tables.push({\n alias: a,\n table,\n join: \"outer\",\n col1: kqDot(fa, column),\n col2: kqDot(a, \"id\"),\n distinct: false,\n });\n addTablePerClassJoinsAndClassTag(query, field.otherMetadata(), a, false);\n addOrderBy(field.otherMetadata(), a, value);\n }\n } else {\n throw new Error(`Unsupported field ${key}`);\n }\n }\n }\n\n // always add the main table\n const alias = getAlias(meta.tableName);\n if (meta.hasLazyColumns) {\n selects.push(...lazyExcludedSelects(meta, alias));\n } else {\n selects.push(`${kq(alias)}.*`);\n }\n addTable(meta, alias, \"primary\", \"n/a\", \"n/a\", filter);\n\n // If they passed extra `conditions: ...`, parse that\n if (optsExpression) {\n checkDomainCondition(optsExpression);\n cb.maybeAddExpression(optsExpression);\n }\n\n Object.assign(query, {\n condition: cb.toExpressionFilter(),\n });\n\n // Resolve alias-built conditions against this parse's bindings, before anything reads their\n // aliases (the id-not-null injection just below, and join pruning)\n resolveAliasConditions(query, aliasBindings);\n\n if (query.tables.some((t) => t.join === \"outer\")) {\n maybeAddIdNotNulls(query);\n }\n\n if (orderBy) {\n if (Array.isArray(orderBy)) {\n for (const ob of orderBy) addOrderBy(meta, alias, ob);\n } else {\n addOrderBy(meta, alias, orderBy);\n }\n }\n maybeAddOrderBy(query, meta, alias);\n\n if (pruneJoins) {\n pruneUnusedJoins(query, keepAliases);\n }\n return query;\n}\n\n/**\n * Look for conditions doing `some_column IS NULL` in an outer join that\n * need an `id IS NOT NULL` to make sure they don't match inadvertently on\n * the child row simply not existing.\n *\n * Note: Instead of injecting an extra `id IS NOT NULL` condition, I had tried\n * using all INNER JOINs and flipping joins to OUTER only if the user explicit\n * had `id IS NULL` in their filter, but that didn't work for queries that wanted\n * to do an `OR` across two different children (which queries both children being\n * OUTER JOINs, and detecting that case seemed complicated).\n */\nexport function maybeAddIdNotNulls(query: ParsedFindQuery): void {\n visitConditions(query, {\n visitCond(c: ColumnCondition) {\n // Check `c.prunable` to make sure we don't catch our injected `deleted_at is null` conditions\n if (c.cond.kind !== \"is-null\" || c.column === \"id\" || c.pruneable) {\n return c;\n }\n // This is an `some_column IS NULL`, is it in an outer join?\n const table = query.tables.find((t) => t.alias === c.alias);\n if (table && table.join === \"outer\") {\n const meta = getMetadataForTable(table.table);\n return {\n kind: \"exp\",\n op: \"and\",\n conditions: [\n c,\n {\n kind: \"column\",\n alias: c.alias,\n column: \"id\",\n dbType: meta.idDbType,\n cond: { kind: \"not-null\" },\n },\n ],\n } satisfies ParsedExpressionFilter;\n }\n return c;\n },\n });\n}\n\n/** Returns the `a` from `\"a\".*`. */\nexport function parseAlias(alias: string): string {\n return alias.split(\".\")[0].replaceAll(`\"`, \"\");\n}\n\n/** Finds a filter field by fieldName or generated fieldIdName. */\nexport function findFilterField(meta: EntityMetadata, key: string): (Field & { aliasSuffix: string }) | undefined {\n return (\n meta.allFields[key] ??\n meta.polyComponentFields?.[key] ??\n Object.values(meta.allFields).find((field) => field.fieldIdName === key) ??\n Object.values(meta.polyComponentFields ?? {}).find((field) => field.fieldIdName === key)\n );\n}\n\n/** Adds any user-configured default order, plus an \"always order by id\" for determinism. */\nexport function maybeAddOrderBy(query: ParsedFindQuery, meta: EntityMetadata, alias: string): void {\n const { orderBys } = query;\n if (meta.orderBy) {\n const field = meta.allFields[meta.orderBy] ?? fail(`${meta.orderBy} not found on ${meta.tableName}`);\n const column = field.serde!.columns[0].columnName;\n const hasAlready = orderBys.find((o) => o.alias === alias && o.column === column);\n if (!hasAlready) {\n orderBys.push({ alias, column, order: \"ASC\" });\n }\n }\n // Even if they already added orders, add id as the last one to get deterministic output\n const hasIdOrder = orderBys.find((o) => o.alias === alias && o.column === \"id\");\n if (!hasIdOrder) {\n orderBys.push({ alias, column: \"id\", order: \"ASC\" });\n }\n}\n\nexport function addTablePerClassJoinsAndClassTag(\n query: ParsedFindQuery,\n meta: EntityMetadata,\n alias: string,\n isPrimary: boolean,\n): void {\n if (!needsClassPerTableJoins(meta)) return;\n const { selects, tables } = query;\n // When `.load(SmallPublisher)` is called, join in base tables like `Publisher`\n meta.baseTypes.forEach((bt, i) => {\n if (isPrimary) {\n selects.push(`${alias}_b${i}.*`);\n }\n tables.push({\n alias: `${alias}_b${i}`,\n table: bt.tableName,\n join: \"outer\",\n col1: kqDot(alias, \"id\"),\n col2: `${alias}_b${i}.id`,\n distinct: false,\n });\n });\n\n // We always join in the base table in case a query happens to use\n // it as a filter, but we only need to do the subtype joins + selects\n // if this is the primary table\n if (isPrimary) {\n // Watch for subTypes that share column names. It'd be great to do\n // this statically at codegen time, like a meta.sharedSubtypeColumns.\n const stColumns: { stAlias: string; columnName: string }[] = [];\n\n // When `.load(Publisher)` is called, join in sub tables like `SmallPublisher` and `LargePublisher`\n meta.subTypes.forEach((st, i) => {\n const stAlias = `${alias}_s${i}`;\n selects.push(`${stAlias}.*`);\n tables.push({\n alias: stAlias,\n table: st.tableName,\n join: \"outer\",\n col1: kqDot(alias, \"id\"),\n col2: `${alias}_s${i}.id`,\n distinct: false,\n });\n for (const field of Object.values(st.fields)) {\n if (field.fieldName !== \"id\" && field.serde) {\n for (const c of field.serde?.columns) {\n stColumns.push({ stAlias, columnName: c.columnName });\n }\n }\n }\n });\n\n // Nominate a specific `id` column to avoid ambiguity\n selects.push(`${kq(alias)}.id as id`);\n\n // Add an explicit coalesce for shared columns\n Object.values(groupBy(stColumns, (c) => c.columnName))\n .filter((columns) => columns.length > 1)\n .forEach((columns) => {\n const { columnName } = columns[0];\n selects.push(`COALESCE(${columns.map((c) => `${c.stAlias}.${columnName}`).join(\", \")}) as ${columnName}`);\n });\n\n // If our meta has no subtypes, we're a left type and don't need a __class\n const cases = meta.subTypes.map((st, i) => `WHEN ${alias}_s${i}.id IS NOT NULL THEN '${st.type}'`);\n if (cases.length > 0) {\n selects.push(`CASE ${cases.join(\" \")} ELSE '_' END as __class`);\n }\n }\n}\n\n/** Rejects SQL predicates throughout a domain condition tree before optional-filter pruning. */\nfunction checkDomainCondition(condition: ConditionInput | undefined): void {\n if (!condition) return;\n if (isDeferredCondition(condition) || (predicateBrand in condition && condition[predicateBrand] === \"sql\")) {\n fail(\"SQL predicates are only supported by em.query/em.execute; use alias(...) predicates in em.find and scopes.\");\n }\n if (\"and\" in condition && condition.and) {\n for (const child of condition.and) checkDomainCondition(child);\n } else if (\"or\" in condition && condition.or) {\n for (const child of condition.or) checkDomainCondition(child);\n }\n}\n\n/** Resolves every `DeferredAliasCondition` in `query` against the parse's alias bindings. */\nfunction resolveAliasConditions(\n query: ParsedFindQuery,\n bindings: Map<AliasMgmt, { meta: EntityMetadata; alias: string }>,\n): void {\n function resolve(handle: AliasMgmt): { meta: EntityMetadata; alias: string } {\n return bindings.get(handle) ?? fail(`Alias for ${handle.tableName} is not bound to this query's join literal`);\n }\n function maybeResolve<C extends ColumnCondition | RawCondition>(c: C): C | undefined {\n return isDeferredAliasCondition(c) ? c[deferredAliasSym](resolve) : undefined;\n }\n visitConditions(query, { visitCond: maybeResolve, visitRaw: maybeResolve });\n}\n\nexport function getTables(query: ParsedFindQuery): [PrimaryTable, JoinTable[], LateralJoinTable[], CrossJoinTable[]] {\n let primary: PrimaryTable;\n const joins: JoinTable[] = [];\n const laterals: LateralJoinTable[] = [];\n const crosses: CrossJoinTable[] = [];\n for (const table of query.tables) {\n if (table.join === \"primary\") {\n primary = table;\n } else if (table.join === \"lateral\") {\n laterals.push(table);\n } else if (table.join === \"cross\") {\n crosses.push(table);\n } else {\n joins.push(table);\n }\n }\n return [primary!, joins, laterals, crosses];\n}\n\nfunction needsClassPerTableJoins(meta: EntityMetadata): boolean {\n return meta.inheritanceType === \"cti\" && (meta.subTypes.length > 0 || meta.baseTypes.length > 0);\n}\n\nfunction needsStiDiscriminator(meta: EntityMetadata): boolean {\n return meta.inheritanceType === \"sti\" && !meta.stiDiscriminatorField;\n}\n\nfunction addStiSubtypeFilter(cb: ConditionBuilder, subtypeMeta: EntityMetadata, alias: string): void {\n const cond = stiSubtypeFilter(subtypeMeta, alias);\n if (cond) cb.addSimpleCondition(cond);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"QueryParser.js","names":["newAlias","alias"],"sources":["../../../src/queries/find/QueryParser.ts"],"sourcesContent":["import { groupBy } from \"joist-utils\";\nimport { getConstructorFromTaggedId, getMetadataForTable } from \"src/configure.ts\";\nimport type { Entity } from \"src/Entity.ts\";\nimport { type EntityMetadata, type Field, getBaseMeta } from \"src/EntityMetadata.ts\";\nimport { keyToNumber, maybeResolveReferenceToId } from \"src/keys.ts\";\nimport { ConditionBuilder } from \"src/queries/ConditionBuilder.ts\";\nimport { type ConditionInput, predicateBrand } from \"src/queries/conditions.ts\";\nimport { filterSoftDeletes, lazyExcludedSelects, stiSubtypeFilter } from \"src/queries/entityQueryUtils.ts\";\nimport {\n type AliasMgmt,\n getAliasMgmt,\n getMaybeCtiAlias,\n isAlias,\n alias as newAlias,\n} from \"src/queries/find/Aliases.ts\";\nimport { deferredAliasSym, isDeferredAliasCondition } from \"src/queries/find/DeferredAlias.ts\";\nimport type { ExpressionFilter, OrderBy } from \"src/queries/find/EntityFilter.ts\";\nimport { pruneUnusedJoins } from \"src/queries/find/QueryParser.pruning.ts\";\nimport { visitConditions } from \"src/queries/find/QueryVisitor.ts\";\nimport { type Scope, isScope, isScopeJoinFilter, resolveScope } from \"src/queries/find/scopes.ts\";\nimport type { ColumnCondition, ParsedExpressionFilter, RawCondition } from \"src/queries/parsedConditions.ts\";\nimport { isDeferredCondition } from \"src/queries/sql/Expr.ts\";\nimport { kq, kqDot } from \"src/queries/sql/keywords.ts\";\nimport { type ParsedEntityFilter, mapToDb, parseEntityFilter, parseValueFilter } from \"src/queries/valueFilters.ts\";\nimport { abbreviation, fail } from \"src/utils.ts\";\n\n// `skipCondition` lives in its own leaf module, shared by domain aliases and SQL expressions\n// without a load-order cycle; `index.ts` re-exports it directly.\n\nexport interface PrimaryTable {\n join: \"primary\";\n alias: string;\n table: string;\n}\n\nexport interface JoinTable {\n join: \"inner\" | \"outer\";\n alias: string;\n table: string;\n col1: string;\n col2: string;\n distinct?: boolean;\n /**\n * Metadata used by `optimizeCollectionJoins` to rewrite collection joins into EXISTS.\n *\n * I.e. for `Author.books.reviews`:\n * ```sql\n * authors a\n * LEFT JOIN books b ON a.id = b.author_id\n * LEFT JOIN book_reviews br ON b.id = br.book_id\n * ```\n * `books b` has `parentAlias: \"a\"` and `rootAlias: \"b\"`, while `book_reviews br` has\n * `parentAlias: \"b\"` and `rootAlias: \"br\"`.\n *\n * I.e. for `Author.tags`, the m2m join table is the collection root:\n * ```sql\n * authors a\n * LEFT JOIN authors_to_tags att ON a.id = att.author_id\n * LEFT JOIN tags t ON att.tag_id = t.id\n * ```\n * `authors_to_tags att` has `alias: \"att\"` and `rootAlias: \"att\"`, while `tags t` has `alias: \"t\"`\n * but still has `rootAlias: \"att\"` because it belongs to the m2m subtree rooted at the join table.\n */\n collection?: {\n /** The collection relation type, i.e. `o2m` for `Author.books`, or `m2m` for `Author.tags`. */\n kind: \"o2m\" | \"m2m\";\n /** The alias that owns this collection path, i.e. `a` for `Author.books`, or `att` for `Author.tags -> tags`. */\n parentAlias: string;\n /** The top-level alias in this collection subtree, i.e. `b` for `Author.books.reviews`, or `att` for `Author.tags`. */\n rootAlias: string;\n };\n}\n\n/**\n * Creates a `CROSS JOIN`, currently used for our `em.find` batching.\n *\n * I.e. queries like:\n *\n * ```sql\n * WITH _find (tag, arg1, arg2) AS (VALUES\n * (0::int, 'a'::varchar, 'a'::varchar),\n * (1, 'b', 'b'),\n * (2, 'c', 'c')\n * )\n * SELECT a.*, array_agg(_find.tag) AS _tags\n * FROM authors a\n * CROSS JOIN _find AS _find\n * WHERE a.first_name = _find.arg0 OR a.last_name = _find.arg1\n * GROUP BY a.id\n * ```\n */\nexport interface CrossJoinTable {\n join: \"cross\";\n /** The new alias for the joined table. */\n alias: string;\n /** The table name to join into the query. */\n table: string;\n}\n\n/**\n * Adds `WITH` CTE clauses to the query.\n *\n * I.e. queries like:\n *\n * ```sql\n * WITH _find (tag, arg0, arg1) AS (\n * VALUES ($1::int, $2::character varying, $3::character varying), ($4, $5, $6)\n * )\n * ```\n */\nexport interface ParsedCteClause {\n /** The new alias for the CTE, i.e. `_find` in the above query. */\n alias: string;\n /** The columns, i.e. `tag, arg0, arg1` in the above query. */\n columns?: { columnName: string; dbType: string }[];\n /** The subquery for the AS of the CTE clause. */\n query: { kind: \"raw\"; sql: string; bindings: readonly any[] } | { kind: \"ast\"; query: ParsedFindQuery };\n /** Whether to include a `RECURSIVE` keyword after the `WITH`. */\n recursive?: boolean;\n}\n\n/**\n * Creates `LATERAL JOIN`s, currently used by `findCount` and JSON preloading.\n */\nexport interface LateralJoinTable {\n join: \"lateral\";\n alias: string;\n /** Used for join dependency tracking. */\n fromAlias: string;\n /** Used more for bookkeeping/consistency with other join tables than the query itself. */\n table: string;\n /** The subquery that will look for/roll-up N children. */\n query: ParsedFindQuery;\n /** Optional settings for the subquery, i.e. per-parent pagination. */\n settings?: { limit?: number; offset?: number };\n}\n\nexport type ParsedTable = PrimaryTable | JoinTable | CrossJoinTable | LateralJoinTable;\n\nexport interface ParsedOrderBy {\n alias: string;\n column: string;\n order: OrderBy;\n}\n\nexport type ParsedGroupBy = { alias: string; column: string } | { expression: string };\n\nexport type ParsedSelect = string | ParsedSelectWithBindings;\ntype ParsedSelectWithBindings = { sql: string; bindings: any[]; aliases: string[] };\n\n/** The result of parsing an `em.find` filter. */\nexport interface ParsedFindQuery {\n selects: ParsedSelect[];\n /** The primary table plus any joins. */\n tables: ParsedTable[];\n /** The query's conditions. */\n condition?: ParsedExpressionFilter;\n /** Extremely optional group bys; we generally don't support adhoc/aggregate queries, but the auto-batching infra uses these. */\n groupBys?: ParsedGroupBy[];\n /** Any optional orders to add before the default 'order by id'. */\n orderBys: ParsedOrderBy[];\n /** Optional CTE to prefix to the query, i.e. for recursive relations. */\n ctes?: ParsedCteClause[];\n}\n\n/**\n * Parses an `em.find` filter into a logical `ParsedFindQuery` AST, leaving optimization/pruning to callers.\n *\n * The main execution flow is:\n * parseFindQuery -> beforeFind plugins -> optimizeCollectionJoins -> pruneUnusedJoins -> execute SQL.\n */\nexport function parseFindQuery(\n meta: EntityMetadata,\n filter: any,\n opts: {\n conditions?: ExpressionFilter;\n orderBy?: any;\n pruneJoins?: boolean;\n keepAliases?: string[];\n softDeletes?: \"include\" | \"exclude\";\n allowMultipleLeftJoins?: boolean;\n optimizeJoinsToExists?: boolean;\n } = {},\n): ParsedFindQuery {\n const selects: string[] = [];\n const tables: ParsedTable[] = [];\n const orderBys: ParsedOrderBy[] = [];\n const query: ParsedFindQuery = { selects, tables, orderBys };\n const { orderBy, conditions: optsExpression, softDeletes = \"exclude\", pruneJoins = false, keepAliases = [] } = opts;\n const cb = new ConditionBuilder();\n // Where each user-created `alias(...)` is bound in this parse's join literal; alias-built conditions\n // (`a.firstName.eq(...)`) are resolved against it once the whole tree is walked\n const aliasBindings = new Map<AliasMgmt, { meta: EntityMetadata; alias: string }>();\n\n const aliases: Record<string, number> = {};\n function getAlias(tableName: string): string {\n const abbrev = abbreviation(tableName);\n const i = aliases[abbrev] || 0;\n aliases[abbrev] = i + 1;\n return i === 0 ? abbrev : `${abbrev}${i}`;\n }\n\n /** Adds a `deleted_at IS NULL` condition for `alias`, i.e. for the primary table or a collection join. */\n function addSoftDeleteCondition(meta: EntityMetadata, alias: string, targetCb: ConditionBuilder): void {\n if (filterSoftDeletes(meta, softDeletes)) {\n const column = meta.allFields[getBaseMeta(meta).timestampFields!.deletedAt!].serde?.columns[0]!;\n targetCb.addSimpleCondition({\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n cond: { kind: \"is-null\" },\n pruneable: true,\n });\n }\n }\n\n function addTable(\n meta: EntityMetadata,\n alias: string,\n join: ParsedTable[\"join\"],\n col1: string,\n col2: string,\n filter: any,\n fieldName?: string,\n targetCb: ConditionBuilder = cb,\n /** Whether this table is the \"other side\" of a collection, i.e. `books` in `em.find(Author, { books: ... })`. */\n isCollection: boolean = false,\n ): void {\n // look at filter, is it `{ book: \"b2\" }` or `{ book: { ... } }`\n const scopeFilter = isScope(filter);\n const ef = scopeFilter ? undefined : parseEntityFilter(meta, filter);\n if (!scopeFilter && !ef && join !== \"primary\" && !isAlias(filter)) {\n return;\n }\n\n if (join === \"primary\") {\n tables.push({ alias, table: meta.tableName, join });\n addTablePerClassJoinsAndClassTag({ selects, tables, orderBys }, meta, alias, true);\n } else if (meta.inheritanceType === \"cti\" && fieldName && !(fieldName in meta.fields)) {\n // For cti, our meta might be a subtype while the FK is actually on the base table. This should only be the case\n // when the fk is on another table (e.g. o2o/o2m). In these cases, we'll be passed a field name and can verify if\n // its directly in our meta, if not we should assume it's in the base type and join that in first.\n meta.baseTypes.forEach((bt, i) => {\n tables.push({\n alias: `${alias}_b${i}`,\n table: bt.tableName,\n join: \"outer\",\n col1,\n col2: `${kq(`${alias}_b${i}`)}.${col2.split(\".\")[1]}`,\n distinct: false,\n });\n // and we still need to join in our subtype as well in case its own fields are queried against\n tables.push({\n alias: `${alias}`,\n table: meta.tableName,\n join: \"outer\",\n col1: kqDot(alias, \"id\"),\n col2: kqDot(`${alias}_b${i}`, \"id\"),\n distinct: false,\n });\n });\n } else if (join === \"lateral\" || join === \"cross\") {\n fail(\"Unexpected lateral join\");\n } else {\n tables.push({ alias, table: meta.tableName, join, col1, col2 });\n // Maybe only do this if we're the primary, or have a field that needs it?\n addTablePerClassJoinsAndClassTag({ selects, tables, orderBys }, meta, alias, false);\n }\n\n if (needsStiDiscriminator(meta)) {\n addStiSubtypeFilter(targetCb, meta, alias);\n }\n\n // Only the primary table & collection joins filter soft-deletes, to match the in-memory relation\n // semantics of \"o2m/m2m collections filter out soft-deletes, but m2o/o2o references still return\n // them\". I.e. `book.author.get` returns a soft-deleted author, so `em.find(Book, { author: ... })`\n // should still match the book, as long as the book itself is not soft-deleted.\n if (join === \"primary\" || isCollection) {\n addSoftDeleteCondition(meta, alias, targetCb);\n }\n\n // The user's locally declared aliases, i.e. `const [a, b] = aliases(Author, Book)`,\n // aren't guaranteed to line up with the aliases we've assigned internally, like `a`\n // might actually be `a1` if there are two `authors` tables in the query, so push the\n // canonical alias value for the current clause into the Alias.\n if (filter && typeof filter === \"object\" && \"as\" in filter && isAlias(filter.as)) {\n aliasBindings.set(getAliasMgmt(filter.as), { meta, alias });\n } else if (isAlias(filter)) {\n aliasBindings.set(getAliasMgmt(filter), { meta, alias });\n }\n\n addFilterAt(meta, alias, filter, targetCb, ef, join);\n }\n\n function addFilterAt(\n meta: EntityMetadata,\n tableAlias: string,\n filter: any,\n targetCb: ConditionBuilder,\n parsed: ParsedEntityFilter | undefined = parseEntityFilter(meta, filter),\n parentJoin: ParsedTable[\"join\"] = \"primary\",\n ): void {\n if (isScope(filter)) {\n addScopeFilterAt(meta, tableAlias, filter, targetCb, parentJoin);\n } else if (parsed && parsed.kind === \"join\") {\n addSubFilter(meta, tableAlias, parsed.subFilter, targetCb, parentJoin);\n } else if (parsed) {\n const column = meta.fields[\"id\"].serde!.columns[0];\n targetCb.addValueFilter(tableAlias, column, parsed);\n }\n }\n\n function addScopeFilterAt<T extends Entity>(\n meta: EntityMetadata<T>,\n tableAlias: string,\n scope: Scope<T>,\n targetCb: ConditionBuilder,\n parentJoin: ParsedTable[\"join\"],\n ): void {\n for (const fragment of resolveScope(scope).fragments) {\n if (fragment.kind === \"filter\") {\n addFilterAt(meta, tableAlias, fragment.filter, targetCb, undefined, parentJoin);\n } else {\n const a = newAlias(meta.cstr);\n const result = fragment.fn(a);\n aliasBindings.set(getAliasMgmt(a), { meta, alias: tableAlias });\n if (isScopeJoinFilter(result)) {\n // Parse the join tree first so its `as:` bindings re-root the aliases that\n // `conditions` reference, then add the conditions against the now-bound aliases.\n addFilterAt(meta, tableAlias, result.where, targetCb, undefined, parentJoin);\n checkDomainCondition(result.conditions);\n targetCb.maybeAddExpression(result.conditions);\n } else {\n const conditions = Array.isArray(result) ? result : [result];\n for (const condition of conditions) checkDomainCondition(condition);\n if (conditions.length > 0) targetCb.maybeAddExpression({ and: conditions });\n }\n }\n }\n }\n\n function addSubFilter(\n meta: EntityMetadata,\n tableAlias: string,\n subFilter: object,\n targetCb: ConditionBuilder,\n parentJoin: ParsedTable[\"join\"],\n ): void {\n // subFilter really means we're matching against the entity columns/further joins\n Object.keys(subFilter).forEach((key) => {\n // Skip the `{ as: ... }` alias binding\n if (key === \"as\") return;\n if (key === \"and\" || key === \"or\") {\n addLogicalFilter(meta, tableAlias, key, (subFilter as any)[key], targetCb, parentJoin);\n return;\n }\n const field = findFilterField(meta, key) ?? fail(`Field '${key}' not found on ${meta.tableName}`);\n const fa = `${tableAlias}${field.aliasSuffix}`;\n if (field.kind === \"primitive\" || field.kind === \"primaryKey\" || field.kind === \"enum\") {\n const column = field.serde.columns[0];\n parseValueFilter((subFilter as any)[key]).forEach((filter) => {\n targetCb.addValueFilter(fa, column, filter);\n });\n } else if (field.kind === \"m2o\") {\n const column = field.serde.columns[0];\n const sub = (subFilter as any)[key];\n const joinKind = field.required && parentJoin !== \"outer\" ? \"inner\" : \"outer\";\n if (isAlias(sub)) {\n const a = getAlias(field.otherMetadata().tableName);\n addTable(\n field.otherMetadata(),\n a,\n joinKind,\n kqDot(fa, column.columnName),\n kqDot(a, \"id\"),\n sub,\n undefined,\n targetCb,\n );\n }\n const f = parseEntityFilter(field.otherMetadata(), sub);\n // Probe the filter and see if it's just an id, if so we can avoid the join; m2os don't need\n // a join for soft-delete filtering because references don't filter out soft-deletes.\n if (!f) {\n // skip\n } else if (f.kind === \"join\") {\n const a = getAlias(field.otherMetadata().tableName);\n addTable(\n field.otherMetadata(),\n a,\n joinKind,\n kqDot(fa, column.columnName),\n kqDot(a, \"id\"),\n sub,\n undefined,\n targetCb,\n );\n } else {\n targetCb.addValueFilter(fa, column, f);\n }\n } else if (field.kind === \"poly\") {\n const f = parseEntityFilter(meta, (subFilter as any)[key]);\n if (!f) {\n // skip\n } else if (f.kind === \"join\") {\n throw new Error(\"Joins through polys are not supported\");\n } else {\n // We're left with basically a ValueFilter against the ids\n // For now only support eq/ne/in/is-null\n if (f.kind === \"eq\" || f.kind === \"ne\") {\n const comp = field.components.find((p) => {\n const otherMeta = p.otherMetadata();\n const cstr = getConstructorFromTaggedId(f.value as string);\n // tagged ids from subclasses always map to the base class, so we should compare to the base class if we don't directly match\n return otherMeta.cstr === cstr || otherMeta.baseType === cstr.name;\n });\n if (!comp) fail(`Invalid tagged id passed to ${meta.type}.${key}: ${f.value}`);\n const column = field.serde.columns.find((c) => c.columnName === comp.columnName)!;\n targetCb.addValueFilter(fa, column, f);\n } else if (f.kind === \"is-null\") {\n // Add a condition for every component--these can be AND-d with the rest of the simple/inline conditions\n field.components.forEach((comp) => {\n const column = field.serde.columns.find((c) => c.columnName === comp.columnName)!;\n targetCb.addSimpleCondition({\n kind: \"column\",\n alias: fa,\n column: comp.columnName,\n dbType: column.dbType,\n cond: f,\n });\n });\n } else if (f.kind === \"not-null\") {\n const conditions = field.components.map((comp) => {\n const column = field.serde.columns.find((c) => c.columnName === comp.columnName)!;\n return {\n kind: \"column\",\n alias: fa,\n column: comp.columnName,\n dbType: column.dbType,\n cond: { kind: \"not-null\" },\n };\n }) satisfies ColumnCondition[];\n targetCb.addParsedExpression({ kind: \"exp\", op: \"or\", conditions });\n } else if (f.kind === \"in\") {\n // An empty `in` matches nothing, so emit a single always-false condition (consistent\n // with a non-poly m2o `{ relation: [] }`); otherwise grouping by constructor would yield\n // zero conditions and prune the filter entirely, incorrectly matching every row.\n if (f.value.length === 0) {\n targetCb.addValueFilter(fa, field.serde.columns[0], { kind: \"in\", value: [] });\n return;\n }\n // Split up the ids by constructor\n const idsByConstructor = groupBy(f.value, (id) => getConstructorFromTaggedId(id as string).name);\n // Or together `parent_book_id in (1,2,3) OR parent_author_id IN (4,5,6)`\n // ...if there is a `parent IN [b:1, b:2, a:1, null]` we'd need to pull the `null` out and do an `OR (all columns are null)`...\n const conditions = Object.entries(idsByConstructor).map(([cstrName, ids]) => {\n const column =\n field.serde.columns.find(\n // tagged ids from subclasses always map to the base class, so we should compare to the base class if we don't directly match\n (c) => c.otherMetadata().cstr.name === cstrName || c.otherMetadata().baseType === cstrName,\n ) ?? fail(`Invalid tagged ids passed to ${meta.type}.${key}: ${ids}`);\n return {\n kind: \"column\",\n alias: fa,\n column: column.columnName,\n dbType: column.dbType,\n cond: mapToDb(column, { kind: \"in\", value: ids }),\n } satisfies ColumnCondition;\n });\n targetCb.addParsedExpression({ kind: \"exp\", op: \"or\", conditions });\n } else {\n throw new Error(`Filters on polys for ${f.kind} are not supported`);\n }\n }\n } else if (field.kind === \"o2o\") {\n // We have to always join into o2os, i.e. we can't probe the filter like we do for m2os\n const otherMeta = field.otherMetadata();\n const a = getAlias(otherMeta.tableName);\n const otherField = otherMeta.allFields[field.otherFieldName];\n const otherColumn =\n // if our other is a poly, we need to find a matching column rather than just picking the first\n otherField.kind === \"poly\"\n ? otherField.components.find((c) => c.otherMetadata() === meta || c.otherMetadata() === getBaseMeta(meta))!\n .columnName\n : otherField.serde!.columns[0].columnName;\n addTable(\n field.otherMetadata(),\n a,\n \"outer\",\n kqDot(tableAlias, \"id\"),\n kqDot(a, otherColumn),\n (subFilter as any)[key],\n field.otherFieldName,\n targetCb,\n );\n } else if (field.kind === \"o2m\") {\n const otherMeta = field.otherMetadata();\n const otherField = otherMeta.allFields[field.otherFieldName];\n let otherColumn = otherField.serde!.columns[0].columnName;\n if (otherField.kind === \"poly\") {\n const otherComponent =\n otherField.components.find((c) => c.otherMetadata() === meta) ??\n fail(`No poly component found for ${otherField.fieldName}`);\n otherColumn = otherComponent.columnName;\n }\n const isCtiBaseFk =\n otherMeta.inheritanceType === \"cti\" && field.otherFieldName && !(field.otherFieldName in otherMeta.fields);\n const a = getAlias(otherMeta.tableName);\n addTable(\n otherMeta,\n a,\n \"outer\",\n kqDot(tableAlias, \"id\"),\n kqDot(a, otherColumn),\n (subFilter as any)[key],\n field.otherFieldName,\n targetCb,\n true,\n );\n if (!isCtiBaseFk) {\n const table = tables.find((t) => t.alias === a);\n if (table && (table.join === \"inner\" || table.join === \"outer\")) {\n table.collection = { parentAlias: tableAlias, rootAlias: a, kind: \"o2m\" };\n }\n }\n } else if (field.kind === \"m2m\") {\n const sub = (subFilter as any)[key];\n const f = parseEntityFilter(field.otherMetadata(), sub);\n if (!f && !isAlias(sub)) return;\n\n const ja = getAlias(field.joinTableName);\n tables.push({\n join: \"outer\",\n alias: ja,\n table: field.joinTableName,\n col1: kqDot(tableAlias, \"id\"),\n col2: kqDot(ja, field.columnNames[0]),\n collection: { parentAlias: tableAlias, rootAlias: ja, kind: \"m2m\" },\n });\n\n if (isAlias(sub) || f?.kind === \"join\" || filterSoftDeletes(field.otherMetadata(), softDeletes)) {\n const a = getAlias(field.otherMetadata().tableName);\n addTable(\n field.otherMetadata(),\n a,\n \"outer\",\n kqDot(ja, field.columnNames[1]),\n kqDot(a, \"id\"),\n sub,\n undefined,\n targetCb,\n true,\n );\n const table = tables.find((t) => t.alias === a);\n if (table && (table.join === \"inner\" || table.join === \"outer\")) {\n table.collection = { parentAlias: ja, rootAlias: ja, kind: \"m2m\" };\n }\n } else if (f) {\n const otherMeta = field.otherMetadata();\n const column: any = {\n columnName: field.columnNames[1],\n dbType: otherMeta.idDbType,\n mapToDb(value: any) {\n return value === null ? value : keyToNumber(otherMeta, maybeResolveReferenceToId(value));\n },\n };\n targetCb.addSimpleCondition({\n kind: \"column\",\n alias: ja,\n column: field.columnNames[1],\n dbType: otherMeta.idDbType,\n cond: mapToDb(column, f),\n });\n }\n } else if (field.kind === \"m2mEnum\") {\n // Membership filter, e.g. `{ logoColors: Color.Red }` / `{ logoColors: [Red, Green] }`: join the\n // join table and filter its enum-id column, mapping enum codes -> their numeric ids.\n const ja = getAlias(field.joinTableName);\n tables.push({\n join: \"outer\",\n alias: ja,\n table: field.joinTableName,\n col1: kqDot(tableAlias, \"id\"),\n col2: kqDot(ja, field.columnNames[0]),\n collection: { parentAlias: tableAlias, rootAlias: ja, kind: \"m2m\" },\n });\n const column: any = {\n columnName: field.columnNames[1],\n dbType: \"int\",\n mapToDb(value: any) {\n return value === null || value === undefined ? value : field.enumDetailType.getByCode(value).id;\n },\n };\n parseValueFilter((subFilter as any)[key]).forEach((filter) => {\n targetCb.addValueFilter(ja, column, filter);\n });\n } else {\n throw new Error(`Unsupported field ${key}`);\n }\n });\n }\n\n function addLogicalFilter(\n meta: EntityMetadata,\n tableAlias: string,\n op: \"and\" | \"or\",\n value: unknown,\n targetCb: ConditionBuilder,\n parentJoin: ParsedTable[\"join\"],\n ): void {\n const filters = Array.isArray(value) ? value : [value];\n const conditions = filters.flatMap((filter) => {\n const branchCb = new ConditionBuilder();\n addFilterAt(meta, tableAlias, filter, branchCb, undefined, parentJoin);\n const condition = branchCb.toExpressionFilter();\n return condition ? [condition] : [];\n });\n if (conditions.length > 0) targetCb.addParsedExpression({ kind: \"exp\", op, conditions });\n }\n\n function addOrderBy(meta: EntityMetadata, alias: string, orderBy: Record<string, any>): void {\n const entries = Object.entries(orderBy);\n if (entries.length === 0) return;\n for (const [key, value] of entries) {\n if (!value) continue; // prune undefined\n const field = meta.allFields[key] ?? fail(`${key} not found on ${meta.tableName}`);\n if (field.kind === \"primitive\" || field.kind === \"primaryKey\" || field.kind === \"enum\") {\n const column = field.serde.columns[0];\n orderBys.push({\n alias: `${alias}${field.aliasSuffix ?? \"\"}`,\n column: column.columnName,\n order: value as OrderBy,\n });\n } else if (field.kind === \"m2o\") {\n // Do we already this table joined in?\n let table = tables.find((t) => t.table === field.otherMetadata().tableName);\n if (table) {\n addTablePerClassJoinsAndClassTag(query, field.otherMetadata(), table.alias, false);\n addOrderBy(field.otherMetadata(), table.alias, value);\n } else {\n const table = field.otherMetadata().tableName;\n const a = getAlias(table);\n const column = field.serde.columns[0].columnName;\n const fa = getMaybeCtiAlias(meta, field, meta, alias);\n // If we don't have a join, don't force this to be an inner join\n tables.push({\n alias: a,\n table,\n join: \"outer\",\n col1: kqDot(fa, column),\n col2: kqDot(a, \"id\"),\n distinct: false,\n });\n addTablePerClassJoinsAndClassTag(query, field.otherMetadata(), a, false);\n addOrderBy(field.otherMetadata(), a, value);\n }\n } else {\n throw new Error(`Unsupported field ${key}`);\n }\n }\n }\n\n // always add the main table\n const alias = getAlias(meta.tableName);\n if (meta.hasLazyColumns) {\n selects.push(...lazyExcludedSelects(meta, alias));\n } else {\n selects.push(`${kq(alias)}.*`);\n }\n addTable(meta, alias, \"primary\", \"n/a\", \"n/a\", filter);\n\n // If they passed extra `conditions: ...`, parse that\n if (optsExpression) {\n checkDomainCondition(optsExpression);\n cb.maybeAddExpression(optsExpression);\n }\n\n Object.assign(query, {\n condition: cb.toExpressionFilter(),\n });\n\n // Resolve alias-built conditions against this parse's bindings, before anything reads their\n // aliases (the id-not-null injection just below, and join pruning)\n resolveAliasConditions(query, aliasBindings);\n\n if (query.tables.some((t) => t.join === \"outer\")) {\n maybeAddIdNotNulls(query);\n }\n\n if (orderBy) {\n if (Array.isArray(orderBy)) {\n for (const ob of orderBy) addOrderBy(meta, alias, ob);\n } else {\n addOrderBy(meta, alias, orderBy);\n }\n }\n maybeAddOrderBy(query, meta, alias);\n\n if (pruneJoins) {\n pruneUnusedJoins(query, keepAliases);\n }\n return query;\n}\n\n/**\n * Look for conditions doing `some_column IS NULL` in an outer join that\n * need an `id IS NOT NULL` to make sure they don't match inadvertently on\n * the child row simply not existing.\n *\n * Note: Instead of injecting an extra `id IS NOT NULL` condition, I had tried\n * using all INNER JOINs and flipping joins to OUTER only if the user explicit\n * had `id IS NULL` in their filter, but that didn't work for queries that wanted\n * to do an `OR` across two different children (which queries both children being\n * OUTER JOINs, and detecting that case seemed complicated).\n */\nexport function maybeAddIdNotNulls(query: ParsedFindQuery): void {\n visitConditions(query, {\n visitCond(c: ColumnCondition) {\n // Check `c.prunable` to make sure we don't catch our injected `deleted_at is null` conditions\n if (c.cond.kind !== \"is-null\" || c.column === \"id\" || c.pruneable) {\n return c;\n }\n // This is an `some_column IS NULL`, is it in an outer join?\n const table = query.tables.find((t) => t.alias === c.alias);\n if (table && table.join === \"outer\") {\n const meta = getMetadataForTable(table.table);\n return {\n kind: \"exp\",\n op: \"and\",\n conditions: [\n c,\n {\n kind: \"column\",\n alias: c.alias,\n column: \"id\",\n dbType: meta.idDbType,\n cond: { kind: \"not-null\" },\n },\n ],\n } satisfies ParsedExpressionFilter;\n }\n return c;\n },\n });\n}\n\n/** Returns the `a` from `\"a\".*`. */\nexport function parseAlias(alias: string): string {\n return alias.split(\".\")[0].replaceAll(`\"`, \"\");\n}\n\n/** Finds a filter field by fieldName or generated fieldIdName. */\nexport function findFilterField(meta: EntityMetadata, key: string): (Field & { aliasSuffix: string }) | undefined {\n return (\n meta.allFields[key] ??\n meta.polyComponentFields?.[key] ??\n Object.values(meta.allFields).find((field) => field.fieldIdName === key) ??\n Object.values(meta.polyComponentFields ?? {}).find((field) => field.fieldIdName === key)\n );\n}\n\n/** Adds any user-configured default order, plus an \"always order by id\" for determinism. */\nexport function maybeAddOrderBy(query: ParsedFindQuery, meta: EntityMetadata, alias: string): void {\n const { orderBys } = query;\n if (meta.orderBy) {\n const field = meta.allFields[meta.orderBy] ?? fail(`${meta.orderBy} not found on ${meta.tableName}`);\n const column = field.serde!.columns[0].columnName;\n const hasAlready = orderBys.find((o) => o.alias === alias && o.column === column);\n if (!hasAlready) {\n orderBys.push({ alias, column, order: \"ASC\" });\n }\n }\n // Even if they already added orders, add id as the last one to get deterministic output\n const hasIdOrder = orderBys.find((o) => o.alias === alias && o.column === \"id\");\n if (!hasIdOrder) {\n orderBys.push({ alias, column: \"id\", order: \"ASC\" });\n }\n}\n\nexport function addTablePerClassJoinsAndClassTag(\n query: ParsedFindQuery,\n meta: EntityMetadata,\n alias: string,\n isPrimary: boolean,\n): void {\n if (!needsClassPerTableJoins(meta)) return;\n const { selects, tables } = query;\n // When `.load(SmallPublisher)` is called, join in base tables like `Publisher`\n meta.baseTypes.forEach((bt, i) => {\n if (isPrimary) {\n selects.push(`${alias}_b${i}.*`);\n }\n tables.push({\n alias: `${alias}_b${i}`,\n table: bt.tableName,\n join: \"outer\",\n col1: kqDot(alias, \"id\"),\n col2: `${alias}_b${i}.id`,\n distinct: false,\n });\n });\n\n // We always join in the base table in case a query happens to use\n // it as a filter, but we only need to do the subtype joins + selects\n // if this is the primary table\n if (isPrimary) {\n // Watch for subTypes that share column names. It'd be great to do\n // this statically at codegen time, like a meta.sharedSubtypeColumns.\n const stColumns: { stAlias: string; columnName: string }[] = [];\n\n // When `.load(Publisher)` is called, join in sub tables like `SmallPublisher` and `LargePublisher`\n meta.subTypes.forEach((st, i) => {\n const stAlias = `${alias}_s${i}`;\n selects.push(`${stAlias}.*`);\n tables.push({\n alias: stAlias,\n table: st.tableName,\n join: \"outer\",\n col1: kqDot(alias, \"id\"),\n col2: `${alias}_s${i}.id`,\n distinct: false,\n });\n for (const field of Object.values(st.fields)) {\n if (field.fieldName !== \"id\" && field.serde) {\n for (const c of field.serde?.columns) {\n stColumns.push({ stAlias, columnName: c.columnName });\n }\n }\n }\n });\n\n // Nominate a specific `id` column to avoid ambiguity\n selects.push(`${kq(alias)}.id as id`);\n\n // Add an explicit coalesce for shared columns\n Object.values(groupBy(stColumns, (c) => c.columnName))\n .filter((columns) => columns.length > 1)\n .forEach((columns) => {\n const { columnName } = columns[0];\n selects.push(`COALESCE(${columns.map((c) => `${c.stAlias}.${columnName}`).join(\", \")}) as ${columnName}`);\n });\n\n // If our meta has no subtypes, we're a left type and don't need a __class\n const cases = meta.subTypes.map((st, i) => `WHEN ${alias}_s${i}.id IS NOT NULL THEN '${st.type}'`);\n if (cases.length > 0) {\n selects.push(`CASE ${cases.join(\" \")} ELSE '_' END as __class`);\n }\n }\n}\n\n/** Rejects SQL predicates throughout a domain condition tree before optional-filter pruning. */\nfunction checkDomainCondition(condition: ConditionInput | undefined): void {\n if (!condition) return;\n if (isDeferredCondition(condition) || (predicateBrand in condition && condition[predicateBrand] === \"sql\")) {\n fail(\"SQL predicates are only supported by em.query/em.execute; use alias(...) predicates in em.find and scopes.\");\n }\n if (\"and\" in condition && condition.and) {\n for (const child of condition.and) checkDomainCondition(child);\n } else if (\"or\" in condition && condition.or) {\n for (const child of condition.or) checkDomainCondition(child);\n }\n}\n\n/** Resolves every `DeferredAliasCondition` in `query` against the parse's alias bindings. */\nfunction resolveAliasConditions(\n query: ParsedFindQuery,\n bindings: Map<AliasMgmt, { meta: EntityMetadata; alias: string }>,\n): void {\n function resolve(handle: AliasMgmt): { meta: EntityMetadata; alias: string } {\n return bindings.get(handle) ?? fail(`Alias for ${handle.tableName} is not bound to this query's join literal`);\n }\n function maybeResolve<C extends ColumnCondition | RawCondition>(c: C): C | undefined {\n return isDeferredAliasCondition(c) ? c[deferredAliasSym](resolve) : undefined;\n }\n visitConditions(query, { visitCond: maybeResolve, visitRaw: maybeResolve });\n}\n\nexport function getTables(query: ParsedFindQuery): [PrimaryTable, JoinTable[], LateralJoinTable[], CrossJoinTable[]] {\n let primary: PrimaryTable;\n const joins: JoinTable[] = [];\n const laterals: LateralJoinTable[] = [];\n const crosses: CrossJoinTable[] = [];\n for (const table of query.tables) {\n if (table.join === \"primary\") {\n primary = table;\n } else if (table.join === \"lateral\") {\n laterals.push(table);\n } else if (table.join === \"cross\") {\n crosses.push(table);\n } else {\n joins.push(table);\n }\n }\n return [primary!, joins, laterals, crosses];\n}\n\nfunction needsClassPerTableJoins(meta: EntityMetadata): boolean {\n return meta.inheritanceType === \"cti\" && (meta.subTypes.length > 0 || meta.baseTypes.length > 0);\n}\n\nfunction needsStiDiscriminator(meta: EntityMetadata): boolean {\n return meta.inheritanceType === \"sti\" && !meta.stiDiscriminatorField;\n}\n\nfunction addStiSubtypeFilter(cb: ConditionBuilder, subtypeMeta: EntityMetadata, alias: string): void {\n const cond = stiSubtypeFilter(subtypeMeta, alias);\n if (cond) cb.addSimpleCondition(cond);\n}\n"],"mappings":"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"}
|
|
@@ -18,6 +18,10 @@ function visitConditions(query, visitor) {
|
|
|
18
18
|
if (query.condition) visitExistsSubqueries(query.condition, todo);
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
|
+
/** Returns whether a parsed query contains a condition tree that cannot match any database row. */
|
|
22
|
+
function isQueryProvablyEmpty(query) {
|
|
23
|
+
return query.condition ? isConditionProvablyFalse(query.condition) : false;
|
|
24
|
+
}
|
|
21
25
|
/** Finds ExistsCondition nodes in a condition tree and pushes their subqueries onto the todo list. */
|
|
22
26
|
function visitExistsSubqueries(condition, todo) {
|
|
23
27
|
if (condition.kind === "exp") for (const c of condition.conditions) visitExistsSubqueries(c, todo);
|
|
@@ -53,7 +57,20 @@ function visitFilter(pc, visitor) {
|
|
|
53
57
|
if (result || result === null) throw new Error("ParsedExpressionCondition overload not support mutating the condition");
|
|
54
58
|
} else if (pc.kind === "exists") {} else require_utils.assertNever(pc);
|
|
55
59
|
}
|
|
60
|
+
/** Evaluates only conditions whose false result can be proven without querying the database. */
|
|
61
|
+
function isConditionProvablyFalse(condition) {
|
|
62
|
+
switch (condition.kind) {
|
|
63
|
+
case "column": return condition.cond.kind === "in" && condition.cond.value.length === 0;
|
|
64
|
+
case "exp":
|
|
65
|
+
if (condition.conditions.length === 0) return false;
|
|
66
|
+
return condition.op === "and" ? condition.conditions.some(isConditionProvablyFalse) : condition.conditions.every(isConditionProvablyFalse);
|
|
67
|
+
case "exists": return !condition.negate && isQueryProvablyEmpty(condition.subquery);
|
|
68
|
+
case "raw": return false;
|
|
69
|
+
default: return require_utils.assertNever(condition);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
56
72
|
//#endregion
|
|
73
|
+
exports.isQueryProvablyEmpty = isQueryProvablyEmpty;
|
|
57
74
|
exports.visitConditions = visitConditions;
|
|
58
75
|
exports.visitFilter = visitFilter;
|
|
59
76
|
|