joist-core 2.3.0-next.61 → 2.3.0-next.62
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/Expr.cjs +7 -2
- package/build/Expr.cjs.map +1 -1
- package/build/Expr.d.cts +7 -2
- package/build/Expr.d.cts.map +1 -1
- package/build/Expr.d.mts +7 -2
- package/build/Expr.d.mts.map +1 -1
- package/build/Expr.js +7 -2
- package/build/Expr.js.map +1 -1
- package/build/query.cjs +14 -7
- package/build/query.cjs.map +1 -1
- package/build/query.d.cts +14 -7
- package/build/query.d.cts.map +1 -1
- package/build/query.d.mts +14 -7
- package/build/query.d.mts.map +1 -1
- package/build/query.js +14 -7
- package/build/query.js.map +1 -1
- package/package.json +2 -2
package/build/Expr.cjs
CHANGED
|
@@ -287,8 +287,13 @@ var RefExpr = class extends BaseExpr {
|
|
|
287
287
|
/**
|
|
288
288
|
* A `sql` tagged template.
|
|
289
289
|
*
|
|
290
|
-
*
|
|
291
|
-
*
|
|
290
|
+
* For an Author alias `a` assigned the SQL alias `a1`:
|
|
291
|
+
*
|
|
292
|
+
* ```ts
|
|
293
|
+
* sql`${a.age} * 2` // Expression: a1.age * 2
|
|
294
|
+
* sql`${a.age.gte(18)}` // Condition: (a1.age >= ?), bindings [18]
|
|
295
|
+
* sql`${"Alice"}` // Value: ?, bindings ["Alice"]
|
|
296
|
+
* ```
|
|
292
297
|
*/
|
|
293
298
|
var TemplateExpr = class extends BaseExpr {
|
|
294
299
|
strings;
|
package/build/Expr.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Expr.cjs","names":["safeKq"],"sources":["../src/Expr.ts"],"sourcesContent":["import type { AliasMgmt } from \"./Aliases.ts\";\nimport type { ExpressionCondition } from \"./EntityFilter.ts\";\nimport type { EntityMetadata } from \"./EntityMetadata.ts\";\nimport { safeKq } from \"./keywords.ts\";\nimport type { ColumnCondition, RawCondition } from \"./QueryParser.ts\";\n\n/**\n * The shared expression protocol for `em.query`.\n *\n * Alias columns (`a.firstName`), aggregates (`b.id.count()`), `sql` templates, subquery columns\n * (`bookStats.bookCount`), and scalar subqueries all implement it, so any of them can appear in\n * `select`, `where`, `groupBy`, `having`, `orderBy`, and inside other expressions.\n *\n * This module is a leaf on purpose: `Aliases.ts` extends `BaseExpr` at load time, so nothing here may\n * import (at runtime) a module that leads back to `Aliases.ts`. Anything that needs metadata, alias\n * binding, or SQL generation for conditions is reached through the `ExprContext` the query parser passes in.\n */\n\nexport const exprBrand: unique symbol = Symbol(\"joist.expr\");\n\n/**\n * Phantom type information carried by every `Expr`.\n *\n * `R` is the decoded result type.\n *\n * `Src` is the expression's *source key*: the type-level identity of the table it reads from. An entity\n * alias's key is its type name (`alias(Author)` gives `\"Author\"`) or the explicit name in\n * `alias(Author, \"m\")`; a subquery's key is its `as: \"book_stats\"`, or the shared sentinel `\"?\"` when it\n * has no `as`. Exactly two questions are asked of a source key, and nothing else:\n *\n * - `MaybeNull` asks \"is my source key among the LEFT-joined sources in this query's join list?\" If yes,\n * the value can be `null`.\n * - `CheckScope` asks \"is my source key among `from` + `join` at all?\" If no, the query reads from a\n * table it never joined.\n *\n * Two special keys opt out of both questions:\n *\n * - `Expr<number, never>` reads from nothing that can be left-joined away, i.e. `b.id.count()`\n * - `Expr<number, string>` (the default) is untracked, i.e. `sql.ref` on an unknown table\n */\nexport interface ExprBrand<R, Src extends string> {\n readonly __result: R;\n readonly __source: Src;\n}\n\n/**\n * \"Any expression whose result is `R`\", checked by brand alone.\n *\n * Method parameters use this instead of `Expr<R>` so that `Expr` stays covariant in `R`: checking\n * `Expr<AuthorId>` against `Expr<AuthorId | null>` then only compares the phantom `__result`, not every\n * method's parameter list (which would make `Expr` invariant, and break `select: b.author` dispatch and\n * polymorphic joins).\n */\nexport type ExprLike<R> = { readonly [exprBrand]: ExprBrand<R, any> };\n\n/**\n * A typed SQL expression: an alias column, an aggregate, a `sql` template, or a scalar subquery.\n *\n * Conditions and SQL functions are methods, so they need no import. Aggregates keep `Src` so scope\n * checking still sees through `bs.x.max()`; `count` is source-less because `count(x)` is 0, not null,\n * when `x`'s table is left-joined away; `coalesce` drops `Src` on purpose, since its whole job is to\n * remove the nullability a left join adds.\n */\nexport interface Expr<R, Src extends string = string> {\n readonly [exprBrand]: ExprBrand<R, Src>;\n eq(value: R | ExprLike<R> | undefined): ExpressionCondition;\n ne(value: R | ExprLike<R> | undefined): ExpressionCondition;\n gt(value: R | ExprLike<R> | undefined): ExpressionCondition;\n gte(value: R | ExprLike<R> | undefined): ExpressionCondition;\n lt(value: R | ExprLike<R> | undefined): ExpressionCondition;\n lte(value: R | ExprLike<R> | undefined): ExpressionCondition;\n // A list subquery may select a nullable column; NULLs in the set never match, so that is fine.\n in(values: readonly R[] | ExprLike<R | null> | undefined): ExpressionCondition;\n nin(values: readonly R[] | ExprLike<R | null> | undefined): ExpressionCondition;\n\n /** `count(x)::int`; `count(a.id)` is `count(*)` for the FROM table, and the matched-row count for a left-joined one. */\n count(): Expr<number, never>;\n countDistinct(): Expr<number, never>;\n sum(this: Expr<number | null, Src>): Expr<number | null, Src>;\n avg(this: Expr<number | null, Src>): Expr<number | null, Src>;\n min(): Expr<R | null, Src>;\n max(): Expr<R | null, Src>;\n /** PG keeps element NULLs (a left-joined empty group aggregates as `[null]`), and zero rows aggregate as NULL. */\n arrayAgg(): Expr<R[] | null, Src>;\n stringAgg(this: Expr<string | null, Src>, delimiter: string): Expr<string | null, Src>;\n coalesce(fallback: NonNullable<R>): Expr<NonNullable<R>, never>;\n}\n\n/**\n * A marker condition that `eq`/`in`/etc. return for an `undefined` value, so the condition prunes away.\n *\n * It lives here (not `QueryParser.ts`) so `Expr.ts` stays a runtime leaf: `Aliases.ts` extends `BaseExpr`\n * at load time, so this module must not (transitively) load `Aliases.ts` back. For the same reason its\n * `QueryParser.ts`/`EntityFilter.ts` imports use `import type`, which is fully erased - a `{ type X }`\n * import keeps a side-effect module load under `verbatimModuleSyntax`.\n */\nexport const skipCondition: ColumnCondition = {\n kind: \"column\",\n alias: \"skip\",\n column: \"skip\",\n dbType: \"skip\",\n cond: undefined as any,\n};\n\n/**\n * A join entry: the join kind is the key, the joined source is the value, plus `on`. `inner?: never` /\n * `left?: never` keep an entry to one kind (the `ExpressionFilter` `and`/`or` trick).\n *\n * `on` is required. A join is pruned when nothing references it anymore, not by an `undefined` ON;\n * `keep: true` pins a join that would otherwise prune, i.e. an inner join used as an existence filter,\n * the way em.find's `keepAliases` does. It is a boolean so callers can pass a flag.\n *\n * Declared here (not `query.ts`) so the relation join factories in `Aliases.ts` (i.e. `a.books.as(b)`) can\n * return them without importing `query.ts`; `query.ts` re-constrains `A` to its `QuerySource`.\n */\nexport interface InnerJoin<A> {\n readonly inner: A;\n readonly left?: never;\n readonly on: ExpressionCondition;\n readonly keep?: boolean;\n}\n\nexport interface LeftJoin<A> {\n readonly left: A;\n readonly inner?: never;\n readonly on: ExpressionCondition;\n readonly keep?: boolean;\n}\n\n/** SQL plus its `?` bindings plus the SQL aliases it references, i.e. for join pruning. */\nexport interface SqlFragment {\n sql: string;\n bindings: any[];\n refs: string[];\n}\n\n/**\n * What an expression needs from the query it is generating SQL for: the SQL alias assigned to each\n * source, and a way to turn nested conditions into SQL (which needs `ConditionBuilder`, so it lives in `query.ts`).\n */\nexport interface ExprContext {\n /** Returns the SQL alias for an alias's `AliasMgmt` or a subquery handle, searching enclosing queries. */\n aliasFor(handle: object): string;\n /** Turns a user-facing condition into SQL; `undefined` if it pruned away entirely. */\n conditionToSql(cond: ExpressionCondition): SqlFragment | undefined;\n}\n\nexport function isExpr(value: unknown): value is ExprLike<any> {\n return typeof value === \"object\" && value !== null && exprBrand in value;\n}\n\n/** Every `Expr` is a `BaseExpr` at runtime; this cast keeps `isExpr` a plain type guard so unions narrow. */\nexport function asNode(expr: ExprLike<any>): BaseExpr {\n return expr as any as BaseExpr;\n}\n\nexport const deferredAliasSym: unique symbol = Symbol(\"joist.deferredAliasCondition\");\n\n/** Resolves an alias handle (its `AliasMgmt`) to this parse's binding: the bound meta and SQL alias. */\nexport type AliasResolver = (handle: AliasMgmt) => { meta: EntityMetadata; alias: string };\n\n/**\n * A `ColumnCondition`/`RawCondition` whose alias(es) are re-resolved on every parse.\n *\n * Alias columns create conditions before any parser assigns SQL aliases, so the condition carries a\n * resolve function instead of a baked-in alias: `em.find` resolves with its join-literal bindings, and\n * `em.query` resolves through the `ExprContext`, whose `aliasFor` also records the ref for pruning and\n * correlation. Resolving recomputes from scratch, so one condition works across queries whose alias\n * assignments differ.\n */\nexport interface DeferredAliasCondition {\n [deferredAliasSym]: (resolve: AliasResolver) => void;\n}\n\nexport function isDeferredAliasCondition(cond: unknown): cond is DeferredAliasCondition {\n return typeof cond === \"object\" && cond !== null && deferredAliasSym in cond;\n}\n\n/** Tags `cond` with its per-parse resolve function, non-enumerable so the condition still deep-equals as data. */\nexport function withDeferredAlias<C extends object>(\n cond: C,\n resolve: (r: AliasResolver) => void,\n): C & DeferredAliasCondition {\n return Object.defineProperty(cond, deferredAliasSym, { value: resolve, enumerable: false }) as any;\n}\n\nexport const deferredSym: unique symbol = Symbol(\"joist.deferredCondition\");\n\n/**\n * A condition whose SQL depends on aliases that are only known once the query is parsed, i.e.\n * `bookStats.bookCount.gt(1)` or `bs.authorId.eq(a.id)`.\n *\n * It is shaped like a `RawCondition` so it can sit in any `ExpressionFilter`; `resolveDeferredConditions`\n * fills in `condition`, `bindings`, and `aliases` before the filter is parsed. Alias columns compared to\n * literals keep producing `ColumnCondition`s (the `em.find` path), so this is only for comparisons that\n * involve a non-alias expression.\n */\nexport interface DeferredCondition extends RawCondition {\n [deferredSym]: (ctx: ExprContext) => void;\n}\n\nexport function isDeferredCondition(cond: unknown): cond is DeferredCondition {\n return typeof cond === \"object\" && cond !== null && deferredSym in cond;\n}\n\n/** Creates a `DeferredCondition` that generates its SQL with `fn` once the query's aliases are known. */\nexport function deferredCondition(fn: (ctx: ExprContext) => SqlFragment): DeferredCondition {\n const cond: DeferredCondition = {\n kind: \"raw\",\n aliases: [],\n condition: \"<unresolved>\",\n bindings: [],\n pruneable: false,\n [deferredSym]: (ctx) => {\n const { sql, bindings, refs } = fn(ctx);\n cond.condition = sql;\n cond.bindings = bindings;\n cond.aliases = refs;\n },\n };\n return cond;\n}\n\n/** Walks an `ExpressionCondition` tree and resolves every deferred condition in place. */\nexport function resolveDeferredConditions(cond: ExpressionCondition | undefined, ctx: ExprContext): void {\n if (cond === undefined || cond === null) return;\n if (isDeferredCondition(cond)) {\n cond[deferredSym](ctx);\n } else if (isDeferredAliasCondition(cond)) {\n cond[deferredAliasSym](ctxResolver(ctx));\n } else if (\"and\" in cond && cond.and) {\n for (const c of cond.and) resolveDeferredConditions(c, ctx);\n } else if (\"or\" in cond && cond.or) {\n for (const c of cond.or) resolveDeferredConditions(c, ctx);\n }\n}\n\n/** Concatenates SQL fragments with `sep`, keeping bindings and refs in order. */\nexport function joinFragments(parts: SqlFragment[], sep: string): SqlFragment {\n return {\n sql: parts.map((p) => p.sql).join(sep),\n bindings: parts.flatMap((p) => p.bindings),\n refs: parts.flatMap((p) => p.refs),\n };\n}\n\n/**\n * The methods every expression shares. Subclasses provide `toSql`, and usually `decode`/`encode`.\n *\n * Alias columns override the comparison methods with the `em.find` `ColumnCondition` path when the\n * right-hand side is a literal, and fall back to these for expression-vs-expression comparisons.\n */\nexport abstract class BaseExpr {\n readonly [exprBrand]: any = this;\n\n /** Produces this expression's SQL so it can be embedded in a larger expression, i.e. a subquery gets parens. */\n abstract toSql(ctx: ExprContext): SqlFragment;\n\n /** The expression selected by a scalar subquery, used to resolve polymorphic IN conditions. */\n get subquerySelect(): BaseExpr | undefined {\n return undefined;\n }\n\n /** Produces the SQL without the outer parens a subquery normally gets; only differs for subqueries. */\n toSqlBare(ctx: ExprContext): SqlFragment {\n return this.toSql(ctx);\n }\n\n /** Converts a result-set value into the domain value, i.e. an int into a tagged id. */\n decode(value: unknown): unknown {\n return value;\n }\n\n /** Converts a domain value into the database value, i.e. a tagged id into an int, for bindings. */\n encode(value: unknown): unknown {\n return value;\n }\n\n eq(value: unknown): ExpressionCondition {\n return this.compare(\"=\", value);\n }\n\n ne(value: unknown): ExpressionCondition {\n return this.compare(\"!=\", value);\n }\n\n gt(value: unknown): ExpressionCondition {\n return this.compare(\">\", value);\n }\n\n gte(value: unknown): ExpressionCondition {\n return this.compare(\">=\", value);\n }\n\n lt(value: unknown): ExpressionCondition {\n return this.compare(\"<\", value);\n }\n\n lte(value: unknown): ExpressionCondition {\n return this.compare(\"<=\", value);\n }\n\n in(values: unknown): ExpressionCondition {\n return this.inList(\"IN\", values);\n }\n\n nin(values: unknown): ExpressionCondition {\n return this.inList(\"NOT IN\", values);\n }\n\n count(): Expr<number, never> {\n return new FnExpr(\"count\", [this], { suffix: \"::int\", decode: decodeNumber, encode: identity }) as any;\n }\n\n countDistinct(): Expr<number, never> {\n return new FnExpr(\"count\", [this], {\n prefix: \"DISTINCT \",\n suffix: \"::int\",\n decode: decodeNumber,\n encode: identity,\n }) as any;\n }\n\n sum(): Expr<number | null, any> {\n return new FnExpr(\"sum\", [this], { decode: decodeNumber, encode: identity }) as any;\n }\n\n avg(): Expr<number | null, any> {\n return new FnExpr(\"avg\", [this], { decode: decodeNumber, encode: identity }) as any;\n }\n\n min(): Expr<any, any> {\n return new FnExpr(\"min\", [this], { decode: (v) => this.decode(v) }) as any;\n }\n\n max(): Expr<any, any> {\n return new FnExpr(\"max\", [this], { decode: (v) => this.decode(v) }) as any;\n }\n\n arrayAgg(): Expr<any, any> {\n // Values are arrays while the argument encodes/decodes *elements*, i.e. a `.coalesce([\"b:1\"])`\n // fallback must encode each tagged id, not hand the whole array to the id column's encoder\n return new FnExpr(\"array_agg\", [this], {\n decode: (v) => (Array.isArray(v) ? v.map((e) => this.decode(e)) : v),\n encode: (v) => (Array.isArray(v) ? v.map((e) => this.encode(e)) : v),\n }) as any;\n }\n\n stringAgg(delimiter: string): Expr<string | null, any> {\n return new FnExpr(\"string_agg\", [this, new BindingExpr(delimiter)], {}) as any;\n }\n\n coalesce(fallback: unknown): Expr<any, never> {\n return new FnExpr(\"coalesce\", [this, new BindingExpr(this.encode(fallback))], {\n decode: (v) => this.decode(v),\n }) as any;\n }\n\n /** `this op value`, where `value` may be `undefined` (pruned), `null`, another expression, or a literal. */\n protected compare(op: string, value: unknown): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value === null) {\n const not = op === \"=\" ? \"\" : op === \"!=\" ? \"NOT \" : fail(`Cannot compare ${op} to null`);\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return { ...left, sql: `${left.sql} IS ${not}NULL` };\n });\n }\n if (isExpr(value)) {\n return deferredCondition((ctx) => joinFragments([this.toSql(ctx), asNode(value).toSql(ctx)], ` ${op} `));\n }\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return { sql: `${left.sql} ${op} ?`, bindings: [...left.bindings, this.encode(value)], refs: left.refs };\n });\n }\n\n /** `this IN (subquery)` or `this = ANY(?)` for a list; `NOT IN` / `!= ALL(?)` for `nin`. */\n protected inList(op: \"IN\" | \"NOT IN\", values: unknown): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (isExpr(values)) {\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n const right = asNode(values).toSqlBare(ctx);\n return joinFragments([left, { ...right, sql: `(${right.sql})` }], ` ${op} `);\n });\n }\n if (!Array.isArray(values)) fail(`Expected an array or subquery for ${op}, got ${values}`);\n const fn = op === \"IN\" ? \"= ANY(?)\" : \"!= ALL(?)\";\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return {\n sql: `${left.sql} ${fn}`,\n bindings: [...left.bindings, values.map((v) => this.encode(v))],\n refs: left.refs,\n };\n });\n }\n}\n\n/**\n * A SQL function applied to expressions, i.e. `count(a.\"id\")::int` or `coalesce(bs.\"n\", ?)`.\n *\n * By default the result decodes/encodes like the first argument (`max(a.id)` is still an id); numeric\n * aggregates pass their own `decode`/`encode`, since `count(a.id)` is a number, not an id.\n */\nexport class FnExpr extends BaseExpr {\n constructor(\n private name: string,\n private args: BaseExpr[],\n private opts: {\n prefix?: string;\n suffix?: string;\n decode?: (value: unknown) => unknown;\n encode?: (value: unknown) => unknown;\n },\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const args = joinFragments(\n this.args.map((a) => a.toSql(ctx)),\n \", \",\n );\n return { ...args, sql: `${this.name}(${this.opts.prefix ?? \"\"}${args.sql})${this.opts.suffix ?? \"\"}` };\n }\n\n decode(value: unknown): unknown {\n if (value === null || value === undefined) return value;\n return this.opts.decode ? this.opts.decode(value) : value;\n }\n\n encode(value: unknown): unknown {\n return this.opts.encode ? this.opts.encode(value) : this.args[0].encode(value);\n }\n}\n\n/** A bound literal, i.e. the `?` in `coalesce(x, ?)`. */\nexport class BindingExpr extends BaseExpr {\n constructor(private value: unknown) {\n super();\n }\n\n toSql(): SqlFragment {\n return { sql: \"?\", bindings: [this.value], refs: [] };\n }\n}\n\n/** An unmodeled column on a known source, i.e. `sql.ref(a, \"ts_search\")`; untracked at the type level. */\nexport class RefExpr extends BaseExpr {\n constructor(\n private handle: object,\n private column: string,\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const alias = ctx.aliasFor(this.handle);\n // safeKq for both halves: sql.ref takes user strings, and a subquery alias is its `as` name\n return { sql: `${safeKq(alias)}.${safeKq(this.column)}`, bindings: [], refs: [alias] };\n }\n}\n\n/**\n * A `sql` tagged template.\n *\n * Interpolated expressions use the alias Joist assigned, conditions become SQL, and every\n * other value becomes a `?` binding, so users never write `\"a.age * 2\"` and hope `a` is the SQL alias.\n */\nexport class TemplateExpr extends BaseExpr {\n constructor(\n private strings: TemplateStringsArray,\n private values: unknown[],\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const parts: SqlFragment[] = [];\n this.strings.forEach((s, i) => {\n parts.push({ sql: s, bindings: [], refs: [] });\n if (i < this.values.length) parts.push(interpolationToSql(this.values[i], ctx));\n });\n return joinFragments(parts, \"\");\n }\n}\n\n/** Turns one `${...}` of a `sql` template into SQL: an expression, a condition, or a bound value. */\nexport function interpolationToSql(value: unknown, ctx: ExprContext): SqlFragment {\n if (isExpr(value)) {\n return asNode(value).toSql(ctx);\n } else if (isConditionLike(value)) {\n return ctx.conditionToSql(value as ExpressionCondition) ?? { sql: \"true\", bindings: [], refs: [] };\n } else {\n return { sql: \"?\", bindings: [value], refs: [] };\n }\n}\n\n/** True for the user-facing condition shapes: `{ and }`, `{ or }`, `ColumnCondition`, `RawCondition`. */\nexport function isConditionLike(value: unknown): boolean {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as any;\n return \"and\" in v || \"or\" in v || v.kind === \"column\" || v.kind === \"raw\" || v.kind === \"exists\";\n}\n\n/** An `AliasResolver` backed by an `ExprContext`; a handle's bound meta is its own (`em.query` sources are their own tables). */\nfunction ctxResolver(ctx: ExprContext): AliasResolver {\n return function resolve(handle: AliasMgmt) {\n return { meta: handle.meta, alias: ctx.aliasFor(handle) };\n };\n}\n\n/** Decodes `count`/`sum`/`avg` results, which Postgres returns as strings for bigint/numeric. */\nfunction decodeNumber(value: unknown): unknown {\n return typeof value === \"string\" ? Number(value) : value;\n}\n\nfunction identity(value: unknown): unknown {\n return value;\n}\n\nfunction fail(message: string): never {\n throw new Error(message);\n}\n"],"mappings":";;;;;;;;;;;;;;AAkBA,MAAa,YAA2B,OAAO,YAAY;;;;;;;;;AA8E3D,MAAa,gBAAiC;CAC5C,MAAM;CACN,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,MAAM,KAAA;AACR;AA6CA,SAAgB,OAAO,OAAwC;CAC7D,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,aAAa;AACrE;;AAGA,SAAgB,OAAO,MAA+B;CACpD,OAAO;AACT;AAEA,MAAa,mBAAkC,OAAO,8BAA8B;AAkBpF,SAAgB,yBAAyB,MAA+C;CACtF,OAAO,OAAO,SAAS,YAAY,SAAS,QAAQ,oBAAoB;AAC1E;;AAGA,SAAgB,kBACd,MACA,SAC4B;CAC5B,OAAO,OAAO,eAAe,MAAM,kBAAkB;EAAE,OAAO;EAAS,YAAY;CAAM,CAAC;AAC5F;AAEA,MAAa,cAA6B,OAAO,yBAAyB;AAe1E,SAAgB,oBAAoB,MAA0C;CAC5E,OAAO,OAAO,SAAS,YAAY,SAAS,QAAQ,eAAe;AACrE;;AAGA,SAAgB,kBAAkB,IAA0D;CAC1F,MAAM,OAA0B;EAC9B,MAAM;EACN,SAAS,CAAC;EACV,WAAW;EACX,UAAU,CAAC;EACX,WAAW;GACV,eAAe,QAAQ;GACtB,MAAM,EAAE,KAAK,UAAU,SAAS,GAAG,GAAG;GACtC,KAAK,YAAY;GACjB,KAAK,WAAW;GAChB,KAAK,UAAU;EACjB;CACF;CACA,OAAO;AACT;;AAGA,SAAgB,0BAA0B,MAAuC,KAAwB;CACvG,IAAI,SAAS,KAAA,KAAa,SAAS,MAAM;CACzC,IAAI,oBAAoB,IAAI,GAC1B,KAAK,YAAY,CAAC,GAAG;MAChB,IAAI,yBAAyB,IAAI,GACtC,KAAK,iBAAiB,CAAC,YAAY,GAAG,CAAC;MAClC,IAAI,SAAS,QAAQ,KAAK,KAC/B,KAAK,MAAM,KAAK,KAAK,KAAK,0BAA0B,GAAG,GAAG;MACrD,IAAI,QAAQ,QAAQ,KAAK,IAC9B,KAAK,MAAM,KAAK,KAAK,IAAI,0BAA0B,GAAG,GAAG;AAE7D;;AAGA,SAAgB,cAAc,OAAsB,KAA0B;CAC5E,OAAO;EACL,KAAK,MAAM,KAAK,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG;EACrC,UAAU,MAAM,SAAS,MAAM,EAAE,QAAQ;EACzC,MAAM,MAAM,SAAS,MAAM,EAAE,IAAI;CACnC;AACF;;;;;;;AAQA,IAAsB,WAAtB,MAA+B;CAC7B,CAAU,aAAkB;;CAM5B,IAAI,iBAAuC,CAE3C;;CAGA,UAAU,KAA+B;EACvC,OAAO,KAAK,MAAM,GAAG;CACvB;;CAGA,OAAO,OAAyB;EAC9B,OAAO;CACT;;CAGA,OAAO,OAAyB;EAC9B,OAAO;CACT;CAEA,GAAG,OAAqC;EACtC,OAAO,KAAK,QAAQ,KAAK,KAAK;CAChC;CAEA,GAAG,OAAqC;EACtC,OAAO,KAAK,QAAQ,MAAM,KAAK;CACjC;CAEA,GAAG,OAAqC;EACtC,OAAO,KAAK,QAAQ,KAAK,KAAK;CAChC;CAEA,IAAI,OAAqC;EACvC,OAAO,KAAK,QAAQ,MAAM,KAAK;CACjC;CAEA,GAAG,OAAqC;EACtC,OAAO,KAAK,QAAQ,KAAK,KAAK;CAChC;CAEA,IAAI,OAAqC;EACvC,OAAO,KAAK,QAAQ,MAAM,KAAK;CACjC;CAEA,GAAG,QAAsC;EACvC,OAAO,KAAK,OAAO,MAAM,MAAM;CACjC;CAEA,IAAI,QAAsC;EACxC,OAAO,KAAK,OAAO,UAAU,MAAM;CACrC;CAEA,QAA6B;EAC3B,OAAO,IAAI,OAAO,SAAS,CAAC,IAAI,GAAG;GAAE,QAAQ;GAAS,QAAQ;GAAc,QAAQ;EAAS,CAAC;CAChG;CAEA,gBAAqC;EACnC,OAAO,IAAI,OAAO,SAAS,CAAC,IAAI,GAAG;GACjC,QAAQ;GACR,QAAQ;GACR,QAAQ;GACR,QAAQ;EACV,CAAC;CACH;CAEA,MAAgC;EAC9B,OAAO,IAAI,OAAO,OAAO,CAAC,IAAI,GAAG;GAAE,QAAQ;GAAc,QAAQ;EAAS,CAAC;CAC7E;CAEA,MAAgC;EAC9B,OAAO,IAAI,OAAO,OAAO,CAAC,IAAI,GAAG;GAAE,QAAQ;GAAc,QAAQ;EAAS,CAAC;CAC7E;CAEA,MAAsB;EACpB,OAAO,IAAI,OAAO,OAAO,CAAC,IAAI,GAAG,EAAE,SAAS,MAAM,KAAK,OAAO,CAAC,EAAE,CAAC;CACpE;CAEA,MAAsB;EACpB,OAAO,IAAI,OAAO,OAAO,CAAC,IAAI,GAAG,EAAE,SAAS,MAAM,KAAK,OAAO,CAAC,EAAE,CAAC;CACpE;CAEA,WAA2B;EAGzB,OAAO,IAAI,OAAO,aAAa,CAAC,IAAI,GAAG;GACrC,SAAS,MAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,KAAK,MAAM,KAAK,OAAO,CAAC,CAAC,IAAI;GAClE,SAAS,MAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,KAAK,MAAM,KAAK,OAAO,CAAC,CAAC,IAAI;EACpE,CAAC;CACH;CAEA,UAAU,WAA6C;EACrD,OAAO,IAAI,OAAO,cAAc,CAAC,MAAM,IAAI,YAAY,SAAS,CAAC,GAAG,CAAC,CAAC;CACxE;CAEA,SAAS,UAAqC;EAC5C,OAAO,IAAI,OAAO,YAAY,CAAC,MAAM,IAAI,YAAY,KAAK,OAAO,QAAQ,CAAC,CAAC,GAAG,EAC5E,SAAS,MAAM,KAAK,OAAO,CAAC,EAC9B,CAAC;CACH;;CAGA,QAAkB,IAAY,OAAqC;EACjE,IAAI,UAAU,KAAA,GAAW,OAAO;EAChC,IAAI,UAAU,MAAM;GAClB,MAAM,MAAM,OAAO,MAAM,KAAK,OAAO,OAAO,SAAS,KAAK,kBAAkB,GAAG,SAAS;GACxF,OAAO,mBAAmB,QAAQ;IAChC,MAAM,OAAO,KAAK,MAAM,GAAG;IAC3B,OAAO;KAAE,GAAG;KAAM,KAAK,GAAG,KAAK,IAAI,MAAM,IAAI;IAAM;GACrD,CAAC;EACH;EACA,IAAI,OAAO,KAAK,GACd,OAAO,mBAAmB,QAAQ,cAAc,CAAC,KAAK,MAAM,GAAG,GAAG,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC;EAEzG,OAAO,mBAAmB,QAAQ;GAChC,MAAM,OAAO,KAAK,MAAM,GAAG;GAC3B,OAAO;IAAE,KAAK,GAAG,KAAK,IAAI,GAAG,GAAG;IAAK,UAAU,CAAC,GAAG,KAAK,UAAU,KAAK,OAAO,KAAK,CAAC;IAAG,MAAM,KAAK;GAAK;EACzG,CAAC;CACH;;CAGA,OAAiB,IAAqB,QAAsC;EAC1E,IAAI,WAAW,KAAA,GAAW,OAAO;EACjC,IAAI,OAAO,MAAM,GACf,OAAO,mBAAmB,QAAQ;GAChC,MAAM,OAAO,KAAK,MAAM,GAAG;GAC3B,MAAM,QAAQ,OAAO,MAAM,CAAC,CAAC,UAAU,GAAG;GAC1C,OAAO,cAAc,CAAC,MAAM;IAAE,GAAG;IAAO,KAAK,IAAI,MAAM,IAAI;GAAG,CAAC,GAAG,IAAI,GAAG,EAAE;EAC7E,CAAC;EAEH,IAAI,CAAC,MAAM,QAAQ,MAAM,GAAG,KAAK,qCAAqC,GAAG,QAAQ,QAAQ;EACzF,MAAM,KAAK,OAAO,OAAO,aAAa;EACtC,OAAO,mBAAmB,QAAQ;GAChC,MAAM,OAAO,KAAK,MAAM,GAAG;GAC3B,OAAO;IACL,KAAK,GAAG,KAAK,IAAI,GAAG;IACpB,UAAU,CAAC,GAAG,KAAK,UAAU,OAAO,KAAK,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC;IAC9D,MAAM,KAAK;GACb;EACF,CAAC;CACH;AACF;;;;;;;AAQA,IAAa,SAAb,cAA4B,SAAS;CAEzB;CACA;CACA;CAHV,YACE,MACA,MACA,MAMA;EACA,MAAM;EATE,KAAA,OAAA;EACA,KAAA,OAAA;EACA,KAAA,OAAA;CAQV;CAEA,MAAM,KAA+B;EACnC,MAAM,OAAO,cACX,KAAK,KAAK,KAAK,MAAM,EAAE,MAAM,GAAG,CAAC,GACjC,IACF;EACA,OAAO;GAAE,GAAG;GAAM,KAAK,GAAG,KAAK,KAAK,GAAG,KAAK,KAAK,UAAU,KAAK,KAAK,IAAI,GAAG,KAAK,KAAK,UAAU;EAAK;CACvG;CAEA,OAAO,OAAyB;EAC9B,IAAI,UAAU,QAAQ,UAAU,KAAA,GAAW,OAAO;EAClD,OAAO,KAAK,KAAK,SAAS,KAAK,KAAK,OAAO,KAAK,IAAI;CACtD;CAEA,OAAO,OAAyB;EAC9B,OAAO,KAAK,KAAK,SAAS,KAAK,KAAK,OAAO,KAAK,IAAI,KAAK,KAAK,EAAE,CAAC,OAAO,KAAK;CAC/E;AACF;;AAGA,IAAa,cAAb,cAAiC,SAAS;CACpB;CAApB,YAAY,OAAwB;EAClC,MAAM;EADY,KAAA,QAAA;CAEpB;CAEA,QAAqB;EACnB,OAAO;GAAE,KAAK;GAAK,UAAU,CAAC,KAAK,KAAK;GAAG,MAAM,CAAC;EAAE;CACtD;AACF;;AAGA,IAAa,UAAb,cAA6B,SAAS;CAE1B;CACA;CAFV,YACE,QACA,QACA;EACA,MAAM;EAHE,KAAA,SAAA;EACA,KAAA,SAAA;CAGV;CAEA,MAAM,KAA+B;EACnC,MAAM,QAAQ,IAAI,SAAS,KAAK,MAAM;EAEtC,OAAO;GAAE,KAAK,GAAGA,iBAAAA,OAAO,KAAK,EAAE,GAAGA,iBAAAA,OAAO,KAAK,MAAM;GAAK,UAAU,CAAC;GAAG,MAAM,CAAC,KAAK;EAAE;CACvF;AACF;;;;;;;AAQA,IAAa,eAAb,cAAkC,SAAS;CAE/B;CACA;CAFV,YACE,SACA,QACA;EACA,MAAM;EAHE,KAAA,UAAA;EACA,KAAA,SAAA;CAGV;CAEA,MAAM,KAA+B;EACnC,MAAM,QAAuB,CAAC;EAC9B,KAAK,QAAQ,SAAS,GAAG,MAAM;GAC7B,MAAM,KAAK;IAAE,KAAK;IAAG,UAAU,CAAC;IAAG,MAAM,CAAC;GAAE,CAAC;GAC7C,IAAI,IAAI,KAAK,OAAO,QAAQ,MAAM,KAAK,mBAAmB,KAAK,OAAO,IAAI,GAAG,CAAC;EAChF,CAAC;EACD,OAAO,cAAc,OAAO,EAAE;CAChC;AACF;;AAGA,SAAgB,mBAAmB,OAAgB,KAA+B;CAChF,IAAI,OAAO,KAAK,GACd,OAAO,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG;MACzB,IAAI,gBAAgB,KAAK,GAC9B,OAAO,IAAI,eAAe,KAA4B,KAAK;EAAE,KAAK;EAAQ,UAAU,CAAC;EAAG,MAAM,CAAC;CAAE;MAEjG,OAAO;EAAE,KAAK;EAAK,UAAU,CAAC,KAAK;EAAG,MAAM,CAAC;CAAE;AAEnD;;AAGA,SAAgB,gBAAgB,OAAyB;CACvD,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,IAAI;CACV,OAAO,SAAS,KAAK,QAAQ,KAAK,EAAE,SAAS,YAAY,EAAE,SAAS,SAAS,EAAE,SAAS;AAC1F;;AAGA,SAAS,YAAY,KAAiC;CACpD,OAAO,SAAS,QAAQ,QAAmB;EACzC,OAAO;GAAE,MAAM,OAAO;GAAM,OAAO,IAAI,SAAS,MAAM;EAAE;CAC1D;AACF;;AAGA,SAAS,aAAa,OAAyB;CAC7C,OAAO,OAAO,UAAU,WAAW,OAAO,KAAK,IAAI;AACrD;AAEA,SAAS,SAAS,OAAyB;CACzC,OAAO;AACT;AAEA,SAAS,KAAK,SAAwB;CACpC,MAAM,IAAI,MAAM,OAAO;AACzB"}
|
|
1
|
+
{"version":3,"file":"Expr.cjs","names":["safeKq"],"sources":["../src/Expr.ts"],"sourcesContent":["import type { AliasMgmt } from \"./Aliases.ts\";\nimport type { ExpressionCondition } from \"./EntityFilter.ts\";\nimport type { EntityMetadata } from \"./EntityMetadata.ts\";\nimport { safeKq } from \"./keywords.ts\";\nimport type { ColumnCondition, RawCondition } from \"./QueryParser.ts\";\n\n/**\n * The shared expression protocol for `em.query`.\n *\n * Alias columns (`a.firstName`), aggregates (`b.id.count()`), `sql` templates, subquery columns\n * (`bookStats.bookCount`), and scalar subqueries all implement it, so any of them can appear in\n * `select`, `where`, `groupBy`, `having`, `orderBy`, and inside other expressions.\n *\n * This module is a leaf on purpose: `Aliases.ts` extends `BaseExpr` at load time, so nothing here may\n * import (at runtime) a module that leads back to `Aliases.ts`. Anything that needs metadata, alias\n * binding, or SQL generation for conditions is reached through the `ExprContext` the query parser passes in.\n */\n\nexport const exprBrand: unique symbol = Symbol(\"joist.expr\");\n\n/**\n * Phantom type information carried by every `Expr`.\n *\n * `R` is the decoded result type.\n *\n * `Src` is the expression's *source key*: the type-level identity of the table it reads from. An entity\n * alias's key is its type name (`alias(Author)` gives `\"Author\"`) or the explicit name in\n * `alias(Author, \"m\")`; a subquery's key is its `as: \"book_stats\"`, or the shared sentinel `\"?\"` when it\n * has no `as`. Exactly two questions are asked of a source key, and nothing else:\n *\n * - `MaybeNull` asks \"is my source key among the LEFT-joined sources in this query's join list?\" If yes,\n * the value can be `null`.\n * - `CheckScope` asks \"is my source key among `from` + `join` at all?\" If no, the query reads from a\n * table it never joined.\n *\n * Two special keys opt out of both questions:\n *\n * - `Expr<number, never>` reads from nothing that can be left-joined away, i.e. `b.id.count()`\n * - `Expr<number, string>` (the default) is untracked, i.e. `sql.ref` on an unknown table\n */\nexport interface ExprBrand<R, Src extends string> {\n readonly __result: R;\n readonly __source: Src;\n}\n\n/**\n * \"Any expression whose result is `R`\", checked by brand alone.\n *\n * Method parameters use this instead of `Expr<R>` so that `Expr` stays covariant in `R`: checking\n * `Expr<AuthorId>` against `Expr<AuthorId | null>` then only compares the phantom `__result`, not every\n * method's parameter list (which would make `Expr` invariant, and break `select: b.author` dispatch and\n * polymorphic joins).\n */\nexport type ExprLike<R> = { readonly [exprBrand]: ExprBrand<R, any> };\n\n/**\n * A typed SQL expression: an alias column, an aggregate, a `sql` template, or a scalar subquery.\n *\n * Conditions and SQL functions are methods, so they need no import. Aggregates keep `Src` so scope\n * checking still sees through `bs.x.max()`; `count` is source-less because `count(x)` is 0, not null,\n * when `x`'s table is left-joined away; `coalesce` drops `Src` on purpose, since its whole job is to\n * remove the nullability a left join adds.\n */\nexport interface Expr<R, Src extends string = string> {\n readonly [exprBrand]: ExprBrand<R, Src>;\n eq(value: R | ExprLike<R> | undefined): ExpressionCondition;\n ne(value: R | ExprLike<R> | undefined): ExpressionCondition;\n gt(value: R | ExprLike<R> | undefined): ExpressionCondition;\n gte(value: R | ExprLike<R> | undefined): ExpressionCondition;\n lt(value: R | ExprLike<R> | undefined): ExpressionCondition;\n lte(value: R | ExprLike<R> | undefined): ExpressionCondition;\n // A list subquery may select a nullable column; NULLs in the set never match, so that is fine.\n in(values: readonly R[] | ExprLike<R | null> | undefined): ExpressionCondition;\n nin(values: readonly R[] | ExprLike<R | null> | undefined): ExpressionCondition;\n\n /** `count(x)::int`; `count(a.id)` is `count(*)` for the FROM table, and the matched-row count for a left-joined one. */\n count(): Expr<number, never>;\n countDistinct(): Expr<number, never>;\n sum(this: Expr<number | null, Src>): Expr<number | null, Src>;\n avg(this: Expr<number | null, Src>): Expr<number | null, Src>;\n min(): Expr<R | null, Src>;\n max(): Expr<R | null, Src>;\n /** PG keeps element NULLs (a left-joined empty group aggregates as `[null]`), and zero rows aggregate as NULL. */\n arrayAgg(): Expr<R[] | null, Src>;\n stringAgg(this: Expr<string | null, Src>, delimiter: string): Expr<string | null, Src>;\n coalesce(fallback: NonNullable<R>): Expr<NonNullable<R>, never>;\n}\n\n/**\n * A marker condition that `eq`/`in`/etc. return for an `undefined` value, so the condition prunes away.\n *\n * It lives here (not `QueryParser.ts`) so `Expr.ts` stays a runtime leaf: `Aliases.ts` extends `BaseExpr`\n * at load time, so this module must not (transitively) load `Aliases.ts` back. For the same reason its\n * `QueryParser.ts`/`EntityFilter.ts` imports use `import type`, which is fully erased - a `{ type X }`\n * import keeps a side-effect module load under `verbatimModuleSyntax`.\n */\nexport const skipCondition: ColumnCondition = {\n kind: \"column\",\n alias: \"skip\",\n column: \"skip\",\n dbType: \"skip\",\n cond: undefined as any,\n};\n\n/**\n * A join entry: the join kind is the key, the joined source is the value, plus `on`. `inner?: never` /\n * `left?: never` keep an entry to one kind (the `ExpressionFilter` `and`/`or` trick).\n *\n * `on` is required. A join is pruned when nothing references it anymore, not by an `undefined` ON;\n * `keep: true` pins a join that would otherwise prune, i.e. an inner join used as an existence filter,\n * the way em.find's `keepAliases` does. It is a boolean so callers can pass a flag.\n *\n * Declared here (not `query.ts`) so the relation join factories in `Aliases.ts` (i.e. `a.books.as(b)`) can\n * return them without importing `query.ts`; `query.ts` re-constrains `A` to its `QuerySource`.\n */\nexport interface InnerJoin<A> {\n readonly inner: A;\n readonly left?: never;\n readonly on: ExpressionCondition;\n readonly keep?: boolean;\n}\n\nexport interface LeftJoin<A> {\n readonly left: A;\n readonly inner?: never;\n readonly on: ExpressionCondition;\n readonly keep?: boolean;\n}\n\n/** SQL plus its `?` bindings plus the SQL aliases it references, i.e. for join pruning. */\nexport interface SqlFragment {\n sql: string;\n bindings: any[];\n refs: string[];\n}\n\n/**\n * What an expression needs from the query it is generating SQL for: the SQL alias assigned to each\n * source, and a way to turn nested conditions into SQL (which needs `ConditionBuilder`, so it lives in `query.ts`).\n */\nexport interface ExprContext {\n /** Returns the SQL alias for an alias's `AliasMgmt` or a subquery handle, searching enclosing queries. */\n aliasFor(handle: object): string;\n /** Turns a user-facing condition into SQL; `undefined` if it pruned away entirely. */\n conditionToSql(cond: ExpressionCondition): SqlFragment | undefined;\n}\n\nexport function isExpr(value: unknown): value is ExprLike<any> {\n return typeof value === \"object\" && value !== null && exprBrand in value;\n}\n\n/** Every `Expr` is a `BaseExpr` at runtime; this cast keeps `isExpr` a plain type guard so unions narrow. */\nexport function asNode(expr: ExprLike<any>): BaseExpr {\n return expr as any as BaseExpr;\n}\n\nexport const deferredAliasSym: unique symbol = Symbol(\"joist.deferredAliasCondition\");\n\n/** Resolves an alias handle (its `AliasMgmt`) to this parse's binding: the bound meta and SQL alias. */\nexport type AliasResolver = (handle: AliasMgmt) => { meta: EntityMetadata; alias: string };\n\n/**\n * A `ColumnCondition`/`RawCondition` whose alias(es) are re-resolved on every parse.\n *\n * Alias columns create conditions before any parser assigns SQL aliases, so the condition carries a\n * resolve function instead of a baked-in alias: `em.find` resolves with its join-literal bindings, and\n * `em.query` resolves through the `ExprContext`, whose `aliasFor` also records the ref for pruning and\n * correlation. Resolving recomputes from scratch, so one condition works across queries whose alias\n * assignments differ.\n */\nexport interface DeferredAliasCondition {\n [deferredAliasSym]: (resolve: AliasResolver) => void;\n}\n\nexport function isDeferredAliasCondition(cond: unknown): cond is DeferredAliasCondition {\n return typeof cond === \"object\" && cond !== null && deferredAliasSym in cond;\n}\n\n/** Tags `cond` with its per-parse resolve function, non-enumerable so the condition still deep-equals as data. */\nexport function withDeferredAlias<C extends object>(\n cond: C,\n resolve: (r: AliasResolver) => void,\n): C & DeferredAliasCondition {\n return Object.defineProperty(cond, deferredAliasSym, { value: resolve, enumerable: false }) as any;\n}\n\nexport const deferredSym: unique symbol = Symbol(\"joist.deferredCondition\");\n\n/**\n * A condition whose SQL depends on aliases that are only known once the query is parsed, i.e.\n * `bookStats.bookCount.gt(1)` or `bs.authorId.eq(a.id)`.\n *\n * It is shaped like a `RawCondition` so it can sit in any `ExpressionFilter`; `resolveDeferredConditions`\n * fills in `condition`, `bindings`, and `aliases` before the filter is parsed. Alias columns compared to\n * literals keep producing `ColumnCondition`s (the `em.find` path), so this is only for comparisons that\n * involve a non-alias expression.\n */\nexport interface DeferredCondition extends RawCondition {\n [deferredSym]: (ctx: ExprContext) => void;\n}\n\nexport function isDeferredCondition(cond: unknown): cond is DeferredCondition {\n return typeof cond === \"object\" && cond !== null && deferredSym in cond;\n}\n\n/** Creates a `DeferredCondition` that generates its SQL with `fn` once the query's aliases are known. */\nexport function deferredCondition(fn: (ctx: ExprContext) => SqlFragment): DeferredCondition {\n const cond: DeferredCondition = {\n kind: \"raw\",\n aliases: [],\n condition: \"<unresolved>\",\n bindings: [],\n pruneable: false,\n [deferredSym]: (ctx) => {\n const { sql, bindings, refs } = fn(ctx);\n cond.condition = sql;\n cond.bindings = bindings;\n cond.aliases = refs;\n },\n };\n return cond;\n}\n\n/** Walks an `ExpressionCondition` tree and resolves every deferred condition in place. */\nexport function resolveDeferredConditions(cond: ExpressionCondition | undefined, ctx: ExprContext): void {\n if (cond === undefined || cond === null) return;\n if (isDeferredCondition(cond)) {\n cond[deferredSym](ctx);\n } else if (isDeferredAliasCondition(cond)) {\n cond[deferredAliasSym](ctxResolver(ctx));\n } else if (\"and\" in cond && cond.and) {\n for (const c of cond.and) resolveDeferredConditions(c, ctx);\n } else if (\"or\" in cond && cond.or) {\n for (const c of cond.or) resolveDeferredConditions(c, ctx);\n }\n}\n\n/** Concatenates SQL fragments with `sep`, keeping bindings and refs in order. */\nexport function joinFragments(parts: SqlFragment[], sep: string): SqlFragment {\n return {\n sql: parts.map((p) => p.sql).join(sep),\n bindings: parts.flatMap((p) => p.bindings),\n refs: parts.flatMap((p) => p.refs),\n };\n}\n\n/**\n * The methods every expression shares. Subclasses provide `toSql`, and usually `decode`/`encode`.\n *\n * Alias columns override the comparison methods with the `em.find` `ColumnCondition` path when the\n * right-hand side is a literal, and fall back to these for expression-vs-expression comparisons.\n */\nexport abstract class BaseExpr {\n readonly [exprBrand]: any = this;\n\n /** Produces this expression's SQL so it can be embedded in a larger expression, i.e. a subquery gets parens. */\n abstract toSql(ctx: ExprContext): SqlFragment;\n\n /** The expression selected by a scalar subquery, used to resolve polymorphic IN conditions. */\n get subquerySelect(): BaseExpr | undefined {\n return undefined;\n }\n\n /** Produces the SQL without the outer parens a subquery normally gets; only differs for subqueries. */\n toSqlBare(ctx: ExprContext): SqlFragment {\n return this.toSql(ctx);\n }\n\n /** Converts a result-set value into the domain value, i.e. an int into a tagged id. */\n decode(value: unknown): unknown {\n return value;\n }\n\n /** Converts a domain value into the database value, i.e. a tagged id into an int, for bindings. */\n encode(value: unknown): unknown {\n return value;\n }\n\n eq(value: unknown): ExpressionCondition {\n return this.compare(\"=\", value);\n }\n\n ne(value: unknown): ExpressionCondition {\n return this.compare(\"!=\", value);\n }\n\n gt(value: unknown): ExpressionCondition {\n return this.compare(\">\", value);\n }\n\n gte(value: unknown): ExpressionCondition {\n return this.compare(\">=\", value);\n }\n\n lt(value: unknown): ExpressionCondition {\n return this.compare(\"<\", value);\n }\n\n lte(value: unknown): ExpressionCondition {\n return this.compare(\"<=\", value);\n }\n\n in(values: unknown): ExpressionCondition {\n return this.inList(\"IN\", values);\n }\n\n nin(values: unknown): ExpressionCondition {\n return this.inList(\"NOT IN\", values);\n }\n\n count(): Expr<number, never> {\n return new FnExpr(\"count\", [this], { suffix: \"::int\", decode: decodeNumber, encode: identity }) as any;\n }\n\n countDistinct(): Expr<number, never> {\n return new FnExpr(\"count\", [this], {\n prefix: \"DISTINCT \",\n suffix: \"::int\",\n decode: decodeNumber,\n encode: identity,\n }) as any;\n }\n\n sum(): Expr<number | null, any> {\n return new FnExpr(\"sum\", [this], { decode: decodeNumber, encode: identity }) as any;\n }\n\n avg(): Expr<number | null, any> {\n return new FnExpr(\"avg\", [this], { decode: decodeNumber, encode: identity }) as any;\n }\n\n min(): Expr<any, any> {\n return new FnExpr(\"min\", [this], { decode: (v) => this.decode(v) }) as any;\n }\n\n max(): Expr<any, any> {\n return new FnExpr(\"max\", [this], { decode: (v) => this.decode(v) }) as any;\n }\n\n arrayAgg(): Expr<any, any> {\n // Values are arrays while the argument encodes/decodes *elements*, i.e. a `.coalesce([\"b:1\"])`\n // fallback must encode each tagged id, not hand the whole array to the id column's encoder\n return new FnExpr(\"array_agg\", [this], {\n decode: (v) => (Array.isArray(v) ? v.map((e) => this.decode(e)) : v),\n encode: (v) => (Array.isArray(v) ? v.map((e) => this.encode(e)) : v),\n }) as any;\n }\n\n stringAgg(delimiter: string): Expr<string | null, any> {\n return new FnExpr(\"string_agg\", [this, new BindingExpr(delimiter)], {}) as any;\n }\n\n coalesce(fallback: unknown): Expr<any, never> {\n return new FnExpr(\"coalesce\", [this, new BindingExpr(this.encode(fallback))], {\n decode: (v) => this.decode(v),\n }) as any;\n }\n\n /** `this op value`, where `value` may be `undefined` (pruned), `null`, another expression, or a literal. */\n protected compare(op: string, value: unknown): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value === null) {\n const not = op === \"=\" ? \"\" : op === \"!=\" ? \"NOT \" : fail(`Cannot compare ${op} to null`);\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return { ...left, sql: `${left.sql} IS ${not}NULL` };\n });\n }\n if (isExpr(value)) {\n return deferredCondition((ctx) => joinFragments([this.toSql(ctx), asNode(value).toSql(ctx)], ` ${op} `));\n }\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return { sql: `${left.sql} ${op} ?`, bindings: [...left.bindings, this.encode(value)], refs: left.refs };\n });\n }\n\n /** `this IN (subquery)` or `this = ANY(?)` for a list; `NOT IN` / `!= ALL(?)` for `nin`. */\n protected inList(op: \"IN\" | \"NOT IN\", values: unknown): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (isExpr(values)) {\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n const right = asNode(values).toSqlBare(ctx);\n return joinFragments([left, { ...right, sql: `(${right.sql})` }], ` ${op} `);\n });\n }\n if (!Array.isArray(values)) fail(`Expected an array or subquery for ${op}, got ${values}`);\n const fn = op === \"IN\" ? \"= ANY(?)\" : \"!= ALL(?)\";\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return {\n sql: `${left.sql} ${fn}`,\n bindings: [...left.bindings, values.map((v) => this.encode(v))],\n refs: left.refs,\n };\n });\n }\n}\n\n/**\n * A SQL function applied to expressions, i.e. `count(a.\"id\")::int` or `coalesce(bs.\"n\", ?)`.\n *\n * By default the result decodes/encodes like the first argument (`max(a.id)` is still an id); numeric\n * aggregates pass their own `decode`/`encode`, since `count(a.id)` is a number, not an id.\n */\nexport class FnExpr extends BaseExpr {\n constructor(\n private name: string,\n private args: BaseExpr[],\n private opts: {\n prefix?: string;\n suffix?: string;\n decode?: (value: unknown) => unknown;\n encode?: (value: unknown) => unknown;\n },\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const args = joinFragments(\n this.args.map((a) => a.toSql(ctx)),\n \", \",\n );\n return { ...args, sql: `${this.name}(${this.opts.prefix ?? \"\"}${args.sql})${this.opts.suffix ?? \"\"}` };\n }\n\n decode(value: unknown): unknown {\n if (value === null || value === undefined) return value;\n return this.opts.decode ? this.opts.decode(value) : value;\n }\n\n encode(value: unknown): unknown {\n return this.opts.encode ? this.opts.encode(value) : this.args[0].encode(value);\n }\n}\n\n/** A bound literal, i.e. the `?` in `coalesce(x, ?)`. */\nexport class BindingExpr extends BaseExpr {\n constructor(private value: unknown) {\n super();\n }\n\n toSql(): SqlFragment {\n return { sql: \"?\", bindings: [this.value], refs: [] };\n }\n}\n\n/** An unmodeled column on a known source, i.e. `sql.ref(a, \"ts_search\")`; untracked at the type level. */\nexport class RefExpr extends BaseExpr {\n constructor(\n private handle: object,\n private column: string,\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const alias = ctx.aliasFor(this.handle);\n // safeKq for both halves: sql.ref takes user strings, and a subquery alias is its `as` name\n return { sql: `${safeKq(alias)}.${safeKq(this.column)}`, bindings: [], refs: [alias] };\n }\n}\n\n/**\n * A `sql` tagged template.\n *\n * For an Author alias `a` assigned the SQL alias `a1`:\n *\n * ```ts\n * sql`${a.age} * 2` // Expression: a1.age * 2\n * sql`${a.age.gte(18)}` // Condition: (a1.age >= ?), bindings [18]\n * sql`${\"Alice\"}` // Value: ?, bindings [\"Alice\"]\n * ```\n */\nexport class TemplateExpr extends BaseExpr {\n constructor(\n private strings: TemplateStringsArray,\n private values: unknown[],\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const parts: SqlFragment[] = [];\n this.strings.forEach((s, i) => {\n parts.push({ sql: s, bindings: [], refs: [] });\n if (i < this.values.length) parts.push(interpolationToSql(this.values[i], ctx));\n });\n return joinFragments(parts, \"\");\n }\n}\n\n/** Turns one `${...}` of a `sql` template into SQL: an expression, a condition, or a bound value. */\nexport function interpolationToSql(value: unknown, ctx: ExprContext): SqlFragment {\n if (isExpr(value)) {\n return asNode(value).toSql(ctx);\n } else if (isConditionLike(value)) {\n return ctx.conditionToSql(value as ExpressionCondition) ?? { sql: \"true\", bindings: [], refs: [] };\n } else {\n return { sql: \"?\", bindings: [value], refs: [] };\n }\n}\n\n/** True for the user-facing condition shapes: `{ and }`, `{ or }`, `ColumnCondition`, `RawCondition`. */\nexport function isConditionLike(value: unknown): boolean {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as any;\n return \"and\" in v || \"or\" in v || v.kind === \"column\" || v.kind === \"raw\" || v.kind === \"exists\";\n}\n\n/** An `AliasResolver` backed by an `ExprContext`; a handle's bound meta is its own (`em.query` sources are their own tables). */\nfunction ctxResolver(ctx: ExprContext): AliasResolver {\n return function resolve(handle: AliasMgmt) {\n return { meta: handle.meta, alias: ctx.aliasFor(handle) };\n };\n}\n\n/** Decodes `count`/`sum`/`avg` results, which Postgres returns as strings for bigint/numeric. */\nfunction decodeNumber(value: unknown): unknown {\n return typeof value === \"string\" ? Number(value) : value;\n}\n\nfunction identity(value: unknown): unknown {\n return value;\n}\n\nfunction fail(message: string): never {\n throw new Error(message);\n}\n"],"mappings":"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"}
|
package/build/Expr.d.cts
CHANGED
|
@@ -248,8 +248,13 @@ declare class RefExpr extends BaseExpr {
|
|
|
248
248
|
/**
|
|
249
249
|
* A `sql` tagged template.
|
|
250
250
|
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
251
|
+
* For an Author alias `a` assigned the SQL alias `a1`:
|
|
252
|
+
*
|
|
253
|
+
* ```ts
|
|
254
|
+
* sql`${a.age} * 2` // Expression: a1.age * 2
|
|
255
|
+
* sql`${a.age.gte(18)}` // Condition: (a1.age >= ?), bindings [18]
|
|
256
|
+
* sql`${"Alice"}` // Value: ?, bindings ["Alice"]
|
|
257
|
+
* ```
|
|
253
258
|
*/
|
|
254
259
|
declare class TemplateExpr extends BaseExpr {
|
|
255
260
|
private strings;
|
package/build/Expr.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Expr.d.cts","names":[],"sources":["../src/Expr.ts"],"mappings":";;;;;;;;;;;;;;;;cAkBa;;;;;;;;;;;;;;;;;;;;;UAsBI,UAAU,GAAG;WACnB,UAAU;WACV,UAAU;;;;;;;;;;KAWT,SAAS;YAAiB,YAAY,UAAU;;;;;;;;;;UAU3C,KAAK,GAAG;YACb,YAAY,UAAU,GAAG;EACnC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,IAAI,OAAO,IAAI,SAAS,iBAAiB;EACzC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,IAAI,OAAO,IAAI,SAAS,iBAAiB;EAEzC,GAAG,iBAAiB,MAAM,SAAS,wBAAwB;EAC3D,IAAI,iBAAiB,MAAM,SAAS,wBAAwB;;EAG5D,SAAS;EACT,iBAAiB;EACjB,IAAI,MAAM,oBAAoB,OAAO,oBAAoB;EACzD,IAAI,MAAM,oBAAoB,OAAO,oBAAoB;EACzD,OAAO,KAAK,UAAU;EACtB,OAAO,KAAK,UAAU;;EAEtB,YAAY,KAAK,YAAY;EAC7B,UAAU,MAAM,oBAAoB,MAAM,oBAAoB,oBAAoB;EAClF,SAAS,UAAU,YAAY,KAAK,KAAK,YAAY;;;;;;;;;;cAW1C,eAAe;;;;;;;;;;;;UAmBX,UAAU;WAChB,OAAO;WACP;WACA,IAAI;WACJ;;UAGM,SAAS;WACf,MAAM;WACN;WACA,IAAI;WACJ;;;UAIM;EACf;EACA;EACA;;;;;;UAOe;;EAEf,SAAS;;EAET,eAAe,MAAM,sBAAsB;;iBAG7B,OAAO,iBAAiB,SAAS;;iBAKjC,OAAO,MAAM,gBAAgB;cAIhC;;KAGD,iBAAiB,QAAQ;EAAgB,MAAM;EAAgB;;;;;;;;;;;UAW1D;GACd,oBAAoB,SAAS;;iBAGhB,yBAAyB,gBAAgB,QAAQ;;iBAKjD,kBAAkB,kBAChC,MAAM,GACN,UAAU,GAAG,yBACZ,IAAI;cAIM;;;;;;;;;;UAWI,0BAA0B;GACxC,eAAe,KAAK;;iBAGP,oBAAoB,gBAAgB,QAAQ;;iBAK5C,kBAAkB,KAAK,KAAK,gBAAgB,cAAc;;iBAkB1D,0BAA0B,MAAM,iCAAiC,KAAK;;iBActE,cAAc,OAAO,eAAe,cAAc;;;;;;;uBAc5C;YACV;;WAGD,MAAM,KAAK,cAAc;;MAG9B,kBAAkB;;EAKtB,UAAU,KAAK,cAAc;;EAK7B,OAAO;;EAKP,OAAO;EAIP,GAAG,iBAAiB;EAIpB,GAAG,iBAAiB;EAIpB,GAAG,iBAAiB;EAIpB,IAAI,iBAAiB;EAIrB,GAAG,iBAAiB;EAIpB,IAAI,iBAAiB;EAIrB,GAAG,kBAAkB;EAIrB,IAAI,kBAAkB;EAItB,SAAS;EAIT,iBAAiB;EASjB,OAAO;EAIP,OAAO;EAIP,OAAO;EAIP,OAAO;EAIP,YAAY;EASZ,UAAU,oBAAoB;EAI9B,SAAS,oBAAoB;;YAOnB,QAAQ,YAAY,iBAAiB;;YAmBrC,OAAO,qBAAqB,kBAAkB;;;;;;;;cA4B7C,eAAe;UAEhB;UACA;UACA;EAHV,YACU,cACA,MAAM,YACN;IACN;IACA;IACA,UAAU;IACV,UAAU;;EAMd,MAAM,KAAK,cAAc;EAQzB,OAAO;EAKP,OAAO;;;cAMI,oBAAoB;UACX;EAApB,YAAoB;EAIpB,SAAS;;;cAME,gBAAgB;UAEjB;UACA;EAFV,YACU,gBACA;EAKV,MAAM,KAAK,cAAc
|
|
1
|
+
{"version":3,"file":"Expr.d.cts","names":[],"sources":["../src/Expr.ts"],"mappings":";;;;;;;;;;;;;;;;cAkBa;;;;;;;;;;;;;;;;;;;;;UAsBI,UAAU,GAAG;WACnB,UAAU;WACV,UAAU;;;;;;;;;;KAWT,SAAS;YAAiB,YAAY,UAAU;;;;;;;;;;UAU3C,KAAK,GAAG;YACb,YAAY,UAAU,GAAG;EACnC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,IAAI,OAAO,IAAI,SAAS,iBAAiB;EACzC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,IAAI,OAAO,IAAI,SAAS,iBAAiB;EAEzC,GAAG,iBAAiB,MAAM,SAAS,wBAAwB;EAC3D,IAAI,iBAAiB,MAAM,SAAS,wBAAwB;;EAG5D,SAAS;EACT,iBAAiB;EACjB,IAAI,MAAM,oBAAoB,OAAO,oBAAoB;EACzD,IAAI,MAAM,oBAAoB,OAAO,oBAAoB;EACzD,OAAO,KAAK,UAAU;EACtB,OAAO,KAAK,UAAU;;EAEtB,YAAY,KAAK,YAAY;EAC7B,UAAU,MAAM,oBAAoB,MAAM,oBAAoB,oBAAoB;EAClF,SAAS,UAAU,YAAY,KAAK,KAAK,YAAY;;;;;;;;;;cAW1C,eAAe;;;;;;;;;;;;UAmBX,UAAU;WAChB,OAAO;WACP;WACA,IAAI;WACJ;;UAGM,SAAS;WACf,MAAM;WACN;WACA,IAAI;WACJ;;;UAIM;EACf;EACA;EACA;;;;;;UAOe;;EAEf,SAAS;;EAET,eAAe,MAAM,sBAAsB;;iBAG7B,OAAO,iBAAiB,SAAS;;iBAKjC,OAAO,MAAM,gBAAgB;cAIhC;;KAGD,iBAAiB,QAAQ;EAAgB,MAAM;EAAgB;;;;;;;;;;;UAW1D;GACd,oBAAoB,SAAS;;iBAGhB,yBAAyB,gBAAgB,QAAQ;;iBAKjD,kBAAkB,kBAChC,MAAM,GACN,UAAU,GAAG,yBACZ,IAAI;cAIM;;;;;;;;;;UAWI,0BAA0B;GACxC,eAAe,KAAK;;iBAGP,oBAAoB,gBAAgB,QAAQ;;iBAK5C,kBAAkB,KAAK,KAAK,gBAAgB,cAAc;;iBAkB1D,0BAA0B,MAAM,iCAAiC,KAAK;;iBActE,cAAc,OAAO,eAAe,cAAc;;;;;;;uBAc5C;YACV;;WAGD,MAAM,KAAK,cAAc;;MAG9B,kBAAkB;;EAKtB,UAAU,KAAK,cAAc;;EAK7B,OAAO;;EAKP,OAAO;EAIP,GAAG,iBAAiB;EAIpB,GAAG,iBAAiB;EAIpB,GAAG,iBAAiB;EAIpB,IAAI,iBAAiB;EAIrB,GAAG,iBAAiB;EAIpB,IAAI,iBAAiB;EAIrB,GAAG,kBAAkB;EAIrB,IAAI,kBAAkB;EAItB,SAAS;EAIT,iBAAiB;EASjB,OAAO;EAIP,OAAO;EAIP,OAAO;EAIP,OAAO;EAIP,YAAY;EASZ,UAAU,oBAAoB;EAI9B,SAAS,oBAAoB;;YAOnB,QAAQ,YAAY,iBAAiB;;YAmBrC,OAAO,qBAAqB,kBAAkB;;;;;;;;cA4B7C,eAAe;UAEhB;UACA;UACA;EAHV,YACU,cACA,MAAM,YACN;IACN;IACA;IACA,UAAU;IACV,UAAU;;EAMd,MAAM,KAAK,cAAc;EAQzB,OAAO;EAKP,OAAO;;;cAMI,oBAAoB;UACX;EAApB,YAAoB;EAIpB,SAAS;;;cAME,gBAAgB;UAEjB;UACA;EAFV,YACU,gBACA;EAKV,MAAM,KAAK,cAAc;;;;;;;;;;;;;cAkBd,qBAAqB;UAEtB;UACA;EAFV,YACU,SAAS,sBACT;EAKV,MAAM,KAAK,cAAc;;;iBAWX,mBAAmB,gBAAgB,KAAK,cAAc;;iBAWtD,gBAAgB"}
|
package/build/Expr.d.mts
CHANGED
|
@@ -248,8 +248,13 @@ declare class RefExpr extends BaseExpr {
|
|
|
248
248
|
/**
|
|
249
249
|
* A `sql` tagged template.
|
|
250
250
|
*
|
|
251
|
-
*
|
|
252
|
-
*
|
|
251
|
+
* For an Author alias `a` assigned the SQL alias `a1`:
|
|
252
|
+
*
|
|
253
|
+
* ```ts
|
|
254
|
+
* sql`${a.age} * 2` // Expression: a1.age * 2
|
|
255
|
+
* sql`${a.age.gte(18)}` // Condition: (a1.age >= ?), bindings [18]
|
|
256
|
+
* sql`${"Alice"}` // Value: ?, bindings ["Alice"]
|
|
257
|
+
* ```
|
|
253
258
|
*/
|
|
254
259
|
declare class TemplateExpr extends BaseExpr {
|
|
255
260
|
private strings;
|
package/build/Expr.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Expr.d.mts","names":[],"sources":["../src/Expr.ts"],"mappings":";;;;;;;;;;;;;;;;cAkBa;;;;;;;;;;;;;;;;;;;;;UAsBI,UAAU,GAAG;WACnB,UAAU;WACV,UAAU;;;;;;;;;;KAWT,SAAS;YAAiB,YAAY,UAAU;;;;;;;;;;UAU3C,KAAK,GAAG;YACb,YAAY,UAAU,GAAG;EACnC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,IAAI,OAAO,IAAI,SAAS,iBAAiB;EACzC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,IAAI,OAAO,IAAI,SAAS,iBAAiB;EAEzC,GAAG,iBAAiB,MAAM,SAAS,wBAAwB;EAC3D,IAAI,iBAAiB,MAAM,SAAS,wBAAwB;;EAG5D,SAAS;EACT,iBAAiB;EACjB,IAAI,MAAM,oBAAoB,OAAO,oBAAoB;EACzD,IAAI,MAAM,oBAAoB,OAAO,oBAAoB;EACzD,OAAO,KAAK,UAAU;EACtB,OAAO,KAAK,UAAU;;EAEtB,YAAY,KAAK,YAAY;EAC7B,UAAU,MAAM,oBAAoB,MAAM,oBAAoB,oBAAoB;EAClF,SAAS,UAAU,YAAY,KAAK,KAAK,YAAY;;;;;;;;;;cAW1C,eAAe;;;;;;;;;;;;UAmBX,UAAU;WAChB,OAAO;WACP;WACA,IAAI;WACJ;;UAGM,SAAS;WACf,MAAM;WACN;WACA,IAAI;WACJ;;;UAIM;EACf;EACA;EACA;;;;;;UAOe;;EAEf,SAAS;;EAET,eAAe,MAAM,sBAAsB;;iBAG7B,OAAO,iBAAiB,SAAS;;iBAKjC,OAAO,MAAM,gBAAgB;cAIhC;;KAGD,iBAAiB,QAAQ;EAAgB,MAAM;EAAgB;;;;;;;;;;;UAW1D;GACd,oBAAoB,SAAS;;iBAGhB,yBAAyB,gBAAgB,QAAQ;;iBAKjD,kBAAkB,kBAChC,MAAM,GACN,UAAU,GAAG,yBACZ,IAAI;cAIM;;;;;;;;;;UAWI,0BAA0B;GACxC,eAAe,KAAK;;iBAGP,oBAAoB,gBAAgB,QAAQ;;iBAK5C,kBAAkB,KAAK,KAAK,gBAAgB,cAAc;;iBAkB1D,0BAA0B,MAAM,iCAAiC,KAAK;;iBActE,cAAc,OAAO,eAAe,cAAc;;;;;;;uBAc5C;YACV;;WAGD,MAAM,KAAK,cAAc;;MAG9B,kBAAkB;;EAKtB,UAAU,KAAK,cAAc;;EAK7B,OAAO;;EAKP,OAAO;EAIP,GAAG,iBAAiB;EAIpB,GAAG,iBAAiB;EAIpB,GAAG,iBAAiB;EAIpB,IAAI,iBAAiB;EAIrB,GAAG,iBAAiB;EAIpB,IAAI,iBAAiB;EAIrB,GAAG,kBAAkB;EAIrB,IAAI,kBAAkB;EAItB,SAAS;EAIT,iBAAiB;EASjB,OAAO;EAIP,OAAO;EAIP,OAAO;EAIP,OAAO;EAIP,YAAY;EASZ,UAAU,oBAAoB;EAI9B,SAAS,oBAAoB;;YAOnB,QAAQ,YAAY,iBAAiB;;YAmBrC,OAAO,qBAAqB,kBAAkB;;;;;;;;cA4B7C,eAAe;UAEhB;UACA;UACA;EAHV,YACU,cACA,MAAM,YACN;IACN;IACA;IACA,UAAU;IACV,UAAU;;EAMd,MAAM,KAAK,cAAc;EAQzB,OAAO;EAKP,OAAO;;;cAMI,oBAAoB;UACX;EAApB,YAAoB;EAIpB,SAAS;;;cAME,gBAAgB;UAEjB;UACA;EAFV,YACU,gBACA;EAKV,MAAM,KAAK,cAAc
|
|
1
|
+
{"version":3,"file":"Expr.d.mts","names":[],"sources":["../src/Expr.ts"],"mappings":";;;;;;;;;;;;;;;;cAkBa;;;;;;;;;;;;;;;;;;;;;UAsBI,UAAU,GAAG;WACnB,UAAU;WACV,UAAU;;;;;;;;;;KAWT,SAAS;YAAiB,YAAY,UAAU;;;;;;;;;;UAU3C,KAAK,GAAG;YACb,YAAY,UAAU,GAAG;EACnC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,IAAI,OAAO,IAAI,SAAS,iBAAiB;EACzC,GAAG,OAAO,IAAI,SAAS,iBAAiB;EACxC,IAAI,OAAO,IAAI,SAAS,iBAAiB;EAEzC,GAAG,iBAAiB,MAAM,SAAS,wBAAwB;EAC3D,IAAI,iBAAiB,MAAM,SAAS,wBAAwB;;EAG5D,SAAS;EACT,iBAAiB;EACjB,IAAI,MAAM,oBAAoB,OAAO,oBAAoB;EACzD,IAAI,MAAM,oBAAoB,OAAO,oBAAoB;EACzD,OAAO,KAAK,UAAU;EACtB,OAAO,KAAK,UAAU;;EAEtB,YAAY,KAAK,YAAY;EAC7B,UAAU,MAAM,oBAAoB,MAAM,oBAAoB,oBAAoB;EAClF,SAAS,UAAU,YAAY,KAAK,KAAK,YAAY;;;;;;;;;;cAW1C,eAAe;;;;;;;;;;;;UAmBX,UAAU;WAChB,OAAO;WACP;WACA,IAAI;WACJ;;UAGM,SAAS;WACf,MAAM;WACN;WACA,IAAI;WACJ;;;UAIM;EACf;EACA;EACA;;;;;;UAOe;;EAEf,SAAS;;EAET,eAAe,MAAM,sBAAsB;;iBAG7B,OAAO,iBAAiB,SAAS;;iBAKjC,OAAO,MAAM,gBAAgB;cAIhC;;KAGD,iBAAiB,QAAQ;EAAgB,MAAM;EAAgB;;;;;;;;;;;UAW1D;GACd,oBAAoB,SAAS;;iBAGhB,yBAAyB,gBAAgB,QAAQ;;iBAKjD,kBAAkB,kBAChC,MAAM,GACN,UAAU,GAAG,yBACZ,IAAI;cAIM;;;;;;;;;;UAWI,0BAA0B;GACxC,eAAe,KAAK;;iBAGP,oBAAoB,gBAAgB,QAAQ;;iBAK5C,kBAAkB,KAAK,KAAK,gBAAgB,cAAc;;iBAkB1D,0BAA0B,MAAM,iCAAiC,KAAK;;iBActE,cAAc,OAAO,eAAe,cAAc;;;;;;;uBAc5C;YACV;;WAGD,MAAM,KAAK,cAAc;;MAG9B,kBAAkB;;EAKtB,UAAU,KAAK,cAAc;;EAK7B,OAAO;;EAKP,OAAO;EAIP,GAAG,iBAAiB;EAIpB,GAAG,iBAAiB;EAIpB,GAAG,iBAAiB;EAIpB,IAAI,iBAAiB;EAIrB,GAAG,iBAAiB;EAIpB,IAAI,iBAAiB;EAIrB,GAAG,kBAAkB;EAIrB,IAAI,kBAAkB;EAItB,SAAS;EAIT,iBAAiB;EASjB,OAAO;EAIP,OAAO;EAIP,OAAO;EAIP,OAAO;EAIP,YAAY;EASZ,UAAU,oBAAoB;EAI9B,SAAS,oBAAoB;;YAOnB,QAAQ,YAAY,iBAAiB;;YAmBrC,OAAO,qBAAqB,kBAAkB;;;;;;;;cA4B7C,eAAe;UAEhB;UACA;UACA;EAHV,YACU,cACA,MAAM,YACN;IACN;IACA;IACA,UAAU;IACV,UAAU;;EAMd,MAAM,KAAK,cAAc;EAQzB,OAAO;EAKP,OAAO;;;cAMI,oBAAoB;UACX;EAApB,YAAoB;EAIpB,SAAS;;;cAME,gBAAgB;UAEjB;UACA;EAFV,YACU,gBACA;EAKV,MAAM,KAAK,cAAc;;;;;;;;;;;;;cAkBd,qBAAqB;UAEtB;UACA;EAFV,YACU,SAAS,sBACT;EAKV,MAAM,KAAK,cAAc;;;iBAWX,mBAAmB,gBAAgB,KAAK,cAAc;;iBAWtD,gBAAgB"}
|
package/build/Expr.js
CHANGED
|
@@ -286,8 +286,13 @@ var RefExpr = class extends BaseExpr {
|
|
|
286
286
|
/**
|
|
287
287
|
* A `sql` tagged template.
|
|
288
288
|
*
|
|
289
|
-
*
|
|
290
|
-
*
|
|
289
|
+
* For an Author alias `a` assigned the SQL alias `a1`:
|
|
290
|
+
*
|
|
291
|
+
* ```ts
|
|
292
|
+
* sql`${a.age} * 2` // Expression: a1.age * 2
|
|
293
|
+
* sql`${a.age.gte(18)}` // Condition: (a1.age >= ?), bindings [18]
|
|
294
|
+
* sql`${"Alice"}` // Value: ?, bindings ["Alice"]
|
|
295
|
+
* ```
|
|
291
296
|
*/
|
|
292
297
|
var TemplateExpr = class extends BaseExpr {
|
|
293
298
|
strings;
|
package/build/Expr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Expr.js","names":[],"sources":["../src/Expr.ts"],"sourcesContent":["import type { AliasMgmt } from \"./Aliases.ts\";\nimport type { ExpressionCondition } from \"./EntityFilter.ts\";\nimport type { EntityMetadata } from \"./EntityMetadata.ts\";\nimport { safeKq } from \"./keywords.ts\";\nimport type { ColumnCondition, RawCondition } from \"./QueryParser.ts\";\n\n/**\n * The shared expression protocol for `em.query`.\n *\n * Alias columns (`a.firstName`), aggregates (`b.id.count()`), `sql` templates, subquery columns\n * (`bookStats.bookCount`), and scalar subqueries all implement it, so any of them can appear in\n * `select`, `where`, `groupBy`, `having`, `orderBy`, and inside other expressions.\n *\n * This module is a leaf on purpose: `Aliases.ts` extends `BaseExpr` at load time, so nothing here may\n * import (at runtime) a module that leads back to `Aliases.ts`. Anything that needs metadata, alias\n * binding, or SQL generation for conditions is reached through the `ExprContext` the query parser passes in.\n */\n\nexport const exprBrand: unique symbol = Symbol(\"joist.expr\");\n\n/**\n * Phantom type information carried by every `Expr`.\n *\n * `R` is the decoded result type.\n *\n * `Src` is the expression's *source key*: the type-level identity of the table it reads from. An entity\n * alias's key is its type name (`alias(Author)` gives `\"Author\"`) or the explicit name in\n * `alias(Author, \"m\")`; a subquery's key is its `as: \"book_stats\"`, or the shared sentinel `\"?\"` when it\n * has no `as`. Exactly two questions are asked of a source key, and nothing else:\n *\n * - `MaybeNull` asks \"is my source key among the LEFT-joined sources in this query's join list?\" If yes,\n * the value can be `null`.\n * - `CheckScope` asks \"is my source key among `from` + `join` at all?\" If no, the query reads from a\n * table it never joined.\n *\n * Two special keys opt out of both questions:\n *\n * - `Expr<number, never>` reads from nothing that can be left-joined away, i.e. `b.id.count()`\n * - `Expr<number, string>` (the default) is untracked, i.e. `sql.ref` on an unknown table\n */\nexport interface ExprBrand<R, Src extends string> {\n readonly __result: R;\n readonly __source: Src;\n}\n\n/**\n * \"Any expression whose result is `R`\", checked by brand alone.\n *\n * Method parameters use this instead of `Expr<R>` so that `Expr` stays covariant in `R`: checking\n * `Expr<AuthorId>` against `Expr<AuthorId | null>` then only compares the phantom `__result`, not every\n * method's parameter list (which would make `Expr` invariant, and break `select: b.author` dispatch and\n * polymorphic joins).\n */\nexport type ExprLike<R> = { readonly [exprBrand]: ExprBrand<R, any> };\n\n/**\n * A typed SQL expression: an alias column, an aggregate, a `sql` template, or a scalar subquery.\n *\n * Conditions and SQL functions are methods, so they need no import. Aggregates keep `Src` so scope\n * checking still sees through `bs.x.max()`; `count` is source-less because `count(x)` is 0, not null,\n * when `x`'s table is left-joined away; `coalesce` drops `Src` on purpose, since its whole job is to\n * remove the nullability a left join adds.\n */\nexport interface Expr<R, Src extends string = string> {\n readonly [exprBrand]: ExprBrand<R, Src>;\n eq(value: R | ExprLike<R> | undefined): ExpressionCondition;\n ne(value: R | ExprLike<R> | undefined): ExpressionCondition;\n gt(value: R | ExprLike<R> | undefined): ExpressionCondition;\n gte(value: R | ExprLike<R> | undefined): ExpressionCondition;\n lt(value: R | ExprLike<R> | undefined): ExpressionCondition;\n lte(value: R | ExprLike<R> | undefined): ExpressionCondition;\n // A list subquery may select a nullable column; NULLs in the set never match, so that is fine.\n in(values: readonly R[] | ExprLike<R | null> | undefined): ExpressionCondition;\n nin(values: readonly R[] | ExprLike<R | null> | undefined): ExpressionCondition;\n\n /** `count(x)::int`; `count(a.id)` is `count(*)` for the FROM table, and the matched-row count for a left-joined one. */\n count(): Expr<number, never>;\n countDistinct(): Expr<number, never>;\n sum(this: Expr<number | null, Src>): Expr<number | null, Src>;\n avg(this: Expr<number | null, Src>): Expr<number | null, Src>;\n min(): Expr<R | null, Src>;\n max(): Expr<R | null, Src>;\n /** PG keeps element NULLs (a left-joined empty group aggregates as `[null]`), and zero rows aggregate as NULL. */\n arrayAgg(): Expr<R[] | null, Src>;\n stringAgg(this: Expr<string | null, Src>, delimiter: string): Expr<string | null, Src>;\n coalesce(fallback: NonNullable<R>): Expr<NonNullable<R>, never>;\n}\n\n/**\n * A marker condition that `eq`/`in`/etc. return for an `undefined` value, so the condition prunes away.\n *\n * It lives here (not `QueryParser.ts`) so `Expr.ts` stays a runtime leaf: `Aliases.ts` extends `BaseExpr`\n * at load time, so this module must not (transitively) load `Aliases.ts` back. For the same reason its\n * `QueryParser.ts`/`EntityFilter.ts` imports use `import type`, which is fully erased - a `{ type X }`\n * import keeps a side-effect module load under `verbatimModuleSyntax`.\n */\nexport const skipCondition: ColumnCondition = {\n kind: \"column\",\n alias: \"skip\",\n column: \"skip\",\n dbType: \"skip\",\n cond: undefined as any,\n};\n\n/**\n * A join entry: the join kind is the key, the joined source is the value, plus `on`. `inner?: never` /\n * `left?: never` keep an entry to one kind (the `ExpressionFilter` `and`/`or` trick).\n *\n * `on` is required. A join is pruned when nothing references it anymore, not by an `undefined` ON;\n * `keep: true` pins a join that would otherwise prune, i.e. an inner join used as an existence filter,\n * the way em.find's `keepAliases` does. It is a boolean so callers can pass a flag.\n *\n * Declared here (not `query.ts`) so the relation join factories in `Aliases.ts` (i.e. `a.books.as(b)`) can\n * return them without importing `query.ts`; `query.ts` re-constrains `A` to its `QuerySource`.\n */\nexport interface InnerJoin<A> {\n readonly inner: A;\n readonly left?: never;\n readonly on: ExpressionCondition;\n readonly keep?: boolean;\n}\n\nexport interface LeftJoin<A> {\n readonly left: A;\n readonly inner?: never;\n readonly on: ExpressionCondition;\n readonly keep?: boolean;\n}\n\n/** SQL plus its `?` bindings plus the SQL aliases it references, i.e. for join pruning. */\nexport interface SqlFragment {\n sql: string;\n bindings: any[];\n refs: string[];\n}\n\n/**\n * What an expression needs from the query it is generating SQL for: the SQL alias assigned to each\n * source, and a way to turn nested conditions into SQL (which needs `ConditionBuilder`, so it lives in `query.ts`).\n */\nexport interface ExprContext {\n /** Returns the SQL alias for an alias's `AliasMgmt` or a subquery handle, searching enclosing queries. */\n aliasFor(handle: object): string;\n /** Turns a user-facing condition into SQL; `undefined` if it pruned away entirely. */\n conditionToSql(cond: ExpressionCondition): SqlFragment | undefined;\n}\n\nexport function isExpr(value: unknown): value is ExprLike<any> {\n return typeof value === \"object\" && value !== null && exprBrand in value;\n}\n\n/** Every `Expr` is a `BaseExpr` at runtime; this cast keeps `isExpr` a plain type guard so unions narrow. */\nexport function asNode(expr: ExprLike<any>): BaseExpr {\n return expr as any as BaseExpr;\n}\n\nexport const deferredAliasSym: unique symbol = Symbol(\"joist.deferredAliasCondition\");\n\n/** Resolves an alias handle (its `AliasMgmt`) to this parse's binding: the bound meta and SQL alias. */\nexport type AliasResolver = (handle: AliasMgmt) => { meta: EntityMetadata; alias: string };\n\n/**\n * A `ColumnCondition`/`RawCondition` whose alias(es) are re-resolved on every parse.\n *\n * Alias columns create conditions before any parser assigns SQL aliases, so the condition carries a\n * resolve function instead of a baked-in alias: `em.find` resolves with its join-literal bindings, and\n * `em.query` resolves through the `ExprContext`, whose `aliasFor` also records the ref for pruning and\n * correlation. Resolving recomputes from scratch, so one condition works across queries whose alias\n * assignments differ.\n */\nexport interface DeferredAliasCondition {\n [deferredAliasSym]: (resolve: AliasResolver) => void;\n}\n\nexport function isDeferredAliasCondition(cond: unknown): cond is DeferredAliasCondition {\n return typeof cond === \"object\" && cond !== null && deferredAliasSym in cond;\n}\n\n/** Tags `cond` with its per-parse resolve function, non-enumerable so the condition still deep-equals as data. */\nexport function withDeferredAlias<C extends object>(\n cond: C,\n resolve: (r: AliasResolver) => void,\n): C & DeferredAliasCondition {\n return Object.defineProperty(cond, deferredAliasSym, { value: resolve, enumerable: false }) as any;\n}\n\nexport const deferredSym: unique symbol = Symbol(\"joist.deferredCondition\");\n\n/**\n * A condition whose SQL depends on aliases that are only known once the query is parsed, i.e.\n * `bookStats.bookCount.gt(1)` or `bs.authorId.eq(a.id)`.\n *\n * It is shaped like a `RawCondition` so it can sit in any `ExpressionFilter`; `resolveDeferredConditions`\n * fills in `condition`, `bindings`, and `aliases` before the filter is parsed. Alias columns compared to\n * literals keep producing `ColumnCondition`s (the `em.find` path), so this is only for comparisons that\n * involve a non-alias expression.\n */\nexport interface DeferredCondition extends RawCondition {\n [deferredSym]: (ctx: ExprContext) => void;\n}\n\nexport function isDeferredCondition(cond: unknown): cond is DeferredCondition {\n return typeof cond === \"object\" && cond !== null && deferredSym in cond;\n}\n\n/** Creates a `DeferredCondition` that generates its SQL with `fn` once the query's aliases are known. */\nexport function deferredCondition(fn: (ctx: ExprContext) => SqlFragment): DeferredCondition {\n const cond: DeferredCondition = {\n kind: \"raw\",\n aliases: [],\n condition: \"<unresolved>\",\n bindings: [],\n pruneable: false,\n [deferredSym]: (ctx) => {\n const { sql, bindings, refs } = fn(ctx);\n cond.condition = sql;\n cond.bindings = bindings;\n cond.aliases = refs;\n },\n };\n return cond;\n}\n\n/** Walks an `ExpressionCondition` tree and resolves every deferred condition in place. */\nexport function resolveDeferredConditions(cond: ExpressionCondition | undefined, ctx: ExprContext): void {\n if (cond === undefined || cond === null) return;\n if (isDeferredCondition(cond)) {\n cond[deferredSym](ctx);\n } else if (isDeferredAliasCondition(cond)) {\n cond[deferredAliasSym](ctxResolver(ctx));\n } else if (\"and\" in cond && cond.and) {\n for (const c of cond.and) resolveDeferredConditions(c, ctx);\n } else if (\"or\" in cond && cond.or) {\n for (const c of cond.or) resolveDeferredConditions(c, ctx);\n }\n}\n\n/** Concatenates SQL fragments with `sep`, keeping bindings and refs in order. */\nexport function joinFragments(parts: SqlFragment[], sep: string): SqlFragment {\n return {\n sql: parts.map((p) => p.sql).join(sep),\n bindings: parts.flatMap((p) => p.bindings),\n refs: parts.flatMap((p) => p.refs),\n };\n}\n\n/**\n * The methods every expression shares. Subclasses provide `toSql`, and usually `decode`/`encode`.\n *\n * Alias columns override the comparison methods with the `em.find` `ColumnCondition` path when the\n * right-hand side is a literal, and fall back to these for expression-vs-expression comparisons.\n */\nexport abstract class BaseExpr {\n readonly [exprBrand]: any = this;\n\n /** Produces this expression's SQL so it can be embedded in a larger expression, i.e. a subquery gets parens. */\n abstract toSql(ctx: ExprContext): SqlFragment;\n\n /** The expression selected by a scalar subquery, used to resolve polymorphic IN conditions. */\n get subquerySelect(): BaseExpr | undefined {\n return undefined;\n }\n\n /** Produces the SQL without the outer parens a subquery normally gets; only differs for subqueries. */\n toSqlBare(ctx: ExprContext): SqlFragment {\n return this.toSql(ctx);\n }\n\n /** Converts a result-set value into the domain value, i.e. an int into a tagged id. */\n decode(value: unknown): unknown {\n return value;\n }\n\n /** Converts a domain value into the database value, i.e. a tagged id into an int, for bindings. */\n encode(value: unknown): unknown {\n return value;\n }\n\n eq(value: unknown): ExpressionCondition {\n return this.compare(\"=\", value);\n }\n\n ne(value: unknown): ExpressionCondition {\n return this.compare(\"!=\", value);\n }\n\n gt(value: unknown): ExpressionCondition {\n return this.compare(\">\", value);\n }\n\n gte(value: unknown): ExpressionCondition {\n return this.compare(\">=\", value);\n }\n\n lt(value: unknown): ExpressionCondition {\n return this.compare(\"<\", value);\n }\n\n lte(value: unknown): ExpressionCondition {\n return this.compare(\"<=\", value);\n }\n\n in(values: unknown): ExpressionCondition {\n return this.inList(\"IN\", values);\n }\n\n nin(values: unknown): ExpressionCondition {\n return this.inList(\"NOT IN\", values);\n }\n\n count(): Expr<number, never> {\n return new FnExpr(\"count\", [this], { suffix: \"::int\", decode: decodeNumber, encode: identity }) as any;\n }\n\n countDistinct(): Expr<number, never> {\n return new FnExpr(\"count\", [this], {\n prefix: \"DISTINCT \",\n suffix: \"::int\",\n decode: decodeNumber,\n encode: identity,\n }) as any;\n }\n\n sum(): Expr<number | null, any> {\n return new FnExpr(\"sum\", [this], { decode: decodeNumber, encode: identity }) as any;\n }\n\n avg(): Expr<number | null, any> {\n return new FnExpr(\"avg\", [this], { decode: decodeNumber, encode: identity }) as any;\n }\n\n min(): Expr<any, any> {\n return new FnExpr(\"min\", [this], { decode: (v) => this.decode(v) }) as any;\n }\n\n max(): Expr<any, any> {\n return new FnExpr(\"max\", [this], { decode: (v) => this.decode(v) }) as any;\n }\n\n arrayAgg(): Expr<any, any> {\n // Values are arrays while the argument encodes/decodes *elements*, i.e. a `.coalesce([\"b:1\"])`\n // fallback must encode each tagged id, not hand the whole array to the id column's encoder\n return new FnExpr(\"array_agg\", [this], {\n decode: (v) => (Array.isArray(v) ? v.map((e) => this.decode(e)) : v),\n encode: (v) => (Array.isArray(v) ? v.map((e) => this.encode(e)) : v),\n }) as any;\n }\n\n stringAgg(delimiter: string): Expr<string | null, any> {\n return new FnExpr(\"string_agg\", [this, new BindingExpr(delimiter)], {}) as any;\n }\n\n coalesce(fallback: unknown): Expr<any, never> {\n return new FnExpr(\"coalesce\", [this, new BindingExpr(this.encode(fallback))], {\n decode: (v) => this.decode(v),\n }) as any;\n }\n\n /** `this op value`, where `value` may be `undefined` (pruned), `null`, another expression, or a literal. */\n protected compare(op: string, value: unknown): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value === null) {\n const not = op === \"=\" ? \"\" : op === \"!=\" ? \"NOT \" : fail(`Cannot compare ${op} to null`);\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return { ...left, sql: `${left.sql} IS ${not}NULL` };\n });\n }\n if (isExpr(value)) {\n return deferredCondition((ctx) => joinFragments([this.toSql(ctx), asNode(value).toSql(ctx)], ` ${op} `));\n }\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return { sql: `${left.sql} ${op} ?`, bindings: [...left.bindings, this.encode(value)], refs: left.refs };\n });\n }\n\n /** `this IN (subquery)` or `this = ANY(?)` for a list; `NOT IN` / `!= ALL(?)` for `nin`. */\n protected inList(op: \"IN\" | \"NOT IN\", values: unknown): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (isExpr(values)) {\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n const right = asNode(values).toSqlBare(ctx);\n return joinFragments([left, { ...right, sql: `(${right.sql})` }], ` ${op} `);\n });\n }\n if (!Array.isArray(values)) fail(`Expected an array or subquery for ${op}, got ${values}`);\n const fn = op === \"IN\" ? \"= ANY(?)\" : \"!= ALL(?)\";\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return {\n sql: `${left.sql} ${fn}`,\n bindings: [...left.bindings, values.map((v) => this.encode(v))],\n refs: left.refs,\n };\n });\n }\n}\n\n/**\n * A SQL function applied to expressions, i.e. `count(a.\"id\")::int` or `coalesce(bs.\"n\", ?)`.\n *\n * By default the result decodes/encodes like the first argument (`max(a.id)` is still an id); numeric\n * aggregates pass their own `decode`/`encode`, since `count(a.id)` is a number, not an id.\n */\nexport class FnExpr extends BaseExpr {\n constructor(\n private name: string,\n private args: BaseExpr[],\n private opts: {\n prefix?: string;\n suffix?: string;\n decode?: (value: unknown) => unknown;\n encode?: (value: unknown) => unknown;\n },\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const args = joinFragments(\n this.args.map((a) => a.toSql(ctx)),\n \", \",\n );\n return { ...args, sql: `${this.name}(${this.opts.prefix ?? \"\"}${args.sql})${this.opts.suffix ?? \"\"}` };\n }\n\n decode(value: unknown): unknown {\n if (value === null || value === undefined) return value;\n return this.opts.decode ? this.opts.decode(value) : value;\n }\n\n encode(value: unknown): unknown {\n return this.opts.encode ? this.opts.encode(value) : this.args[0].encode(value);\n }\n}\n\n/** A bound literal, i.e. the `?` in `coalesce(x, ?)`. */\nexport class BindingExpr extends BaseExpr {\n constructor(private value: unknown) {\n super();\n }\n\n toSql(): SqlFragment {\n return { sql: \"?\", bindings: [this.value], refs: [] };\n }\n}\n\n/** An unmodeled column on a known source, i.e. `sql.ref(a, \"ts_search\")`; untracked at the type level. */\nexport class RefExpr extends BaseExpr {\n constructor(\n private handle: object,\n private column: string,\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const alias = ctx.aliasFor(this.handle);\n // safeKq for both halves: sql.ref takes user strings, and a subquery alias is its `as` name\n return { sql: `${safeKq(alias)}.${safeKq(this.column)}`, bindings: [], refs: [alias] };\n }\n}\n\n/**\n * A `sql` tagged template.\n *\n * Interpolated expressions use the alias Joist assigned, conditions become SQL, and every\n * other value becomes a `?` binding, so users never write `\"a.age * 2\"` and hope `a` is the SQL alias.\n */\nexport class TemplateExpr extends BaseExpr {\n constructor(\n private strings: TemplateStringsArray,\n private values: unknown[],\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const parts: SqlFragment[] = [];\n this.strings.forEach((s, i) => {\n parts.push({ sql: s, bindings: [], refs: [] });\n if (i < this.values.length) parts.push(interpolationToSql(this.values[i], ctx));\n });\n return joinFragments(parts, \"\");\n }\n}\n\n/** Turns one `${...}` of a `sql` template into SQL: an expression, a condition, or a bound value. */\nexport function interpolationToSql(value: unknown, ctx: ExprContext): SqlFragment {\n if (isExpr(value)) {\n return asNode(value).toSql(ctx);\n } else if (isConditionLike(value)) {\n return ctx.conditionToSql(value as ExpressionCondition) ?? { sql: \"true\", bindings: [], refs: [] };\n } else {\n return { sql: \"?\", bindings: [value], refs: [] };\n }\n}\n\n/** True for the user-facing condition shapes: `{ and }`, `{ or }`, `ColumnCondition`, `RawCondition`. */\nexport function isConditionLike(value: unknown): boolean {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as any;\n return \"and\" in v || \"or\" in v || v.kind === \"column\" || v.kind === \"raw\" || v.kind === \"exists\";\n}\n\n/** An `AliasResolver` backed by an `ExprContext`; a handle's bound meta is its own (`em.query` sources are their own tables). */\nfunction ctxResolver(ctx: ExprContext): AliasResolver {\n return function resolve(handle: AliasMgmt) {\n return { meta: handle.meta, alias: ctx.aliasFor(handle) };\n };\n}\n\n/** Decodes `count`/`sum`/`avg` results, which Postgres returns as strings for bigint/numeric. */\nfunction decodeNumber(value: unknown): unknown {\n return typeof value === \"string\" ? Number(value) : value;\n}\n\nfunction identity(value: unknown): unknown {\n return value;\n}\n\nfunction fail(message: string): never {\n throw new Error(message);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Expr.js","names":[],"sources":["../src/Expr.ts"],"sourcesContent":["import type { AliasMgmt } from \"./Aliases.ts\";\nimport type { ExpressionCondition } from \"./EntityFilter.ts\";\nimport type { EntityMetadata } from \"./EntityMetadata.ts\";\nimport { safeKq } from \"./keywords.ts\";\nimport type { ColumnCondition, RawCondition } from \"./QueryParser.ts\";\n\n/**\n * The shared expression protocol for `em.query`.\n *\n * Alias columns (`a.firstName`), aggregates (`b.id.count()`), `sql` templates, subquery columns\n * (`bookStats.bookCount`), and scalar subqueries all implement it, so any of them can appear in\n * `select`, `where`, `groupBy`, `having`, `orderBy`, and inside other expressions.\n *\n * This module is a leaf on purpose: `Aliases.ts` extends `BaseExpr` at load time, so nothing here may\n * import (at runtime) a module that leads back to `Aliases.ts`. Anything that needs metadata, alias\n * binding, or SQL generation for conditions is reached through the `ExprContext` the query parser passes in.\n */\n\nexport const exprBrand: unique symbol = Symbol(\"joist.expr\");\n\n/**\n * Phantom type information carried by every `Expr`.\n *\n * `R` is the decoded result type.\n *\n * `Src` is the expression's *source key*: the type-level identity of the table it reads from. An entity\n * alias's key is its type name (`alias(Author)` gives `\"Author\"`) or the explicit name in\n * `alias(Author, \"m\")`; a subquery's key is its `as: \"book_stats\"`, or the shared sentinel `\"?\"` when it\n * has no `as`. Exactly two questions are asked of a source key, and nothing else:\n *\n * - `MaybeNull` asks \"is my source key among the LEFT-joined sources in this query's join list?\" If yes,\n * the value can be `null`.\n * - `CheckScope` asks \"is my source key among `from` + `join` at all?\" If no, the query reads from a\n * table it never joined.\n *\n * Two special keys opt out of both questions:\n *\n * - `Expr<number, never>` reads from nothing that can be left-joined away, i.e. `b.id.count()`\n * - `Expr<number, string>` (the default) is untracked, i.e. `sql.ref` on an unknown table\n */\nexport interface ExprBrand<R, Src extends string> {\n readonly __result: R;\n readonly __source: Src;\n}\n\n/**\n * \"Any expression whose result is `R`\", checked by brand alone.\n *\n * Method parameters use this instead of `Expr<R>` so that `Expr` stays covariant in `R`: checking\n * `Expr<AuthorId>` against `Expr<AuthorId | null>` then only compares the phantom `__result`, not every\n * method's parameter list (which would make `Expr` invariant, and break `select: b.author` dispatch and\n * polymorphic joins).\n */\nexport type ExprLike<R> = { readonly [exprBrand]: ExprBrand<R, any> };\n\n/**\n * A typed SQL expression: an alias column, an aggregate, a `sql` template, or a scalar subquery.\n *\n * Conditions and SQL functions are methods, so they need no import. Aggregates keep `Src` so scope\n * checking still sees through `bs.x.max()`; `count` is source-less because `count(x)` is 0, not null,\n * when `x`'s table is left-joined away; `coalesce` drops `Src` on purpose, since its whole job is to\n * remove the nullability a left join adds.\n */\nexport interface Expr<R, Src extends string = string> {\n readonly [exprBrand]: ExprBrand<R, Src>;\n eq(value: R | ExprLike<R> | undefined): ExpressionCondition;\n ne(value: R | ExprLike<R> | undefined): ExpressionCondition;\n gt(value: R | ExprLike<R> | undefined): ExpressionCondition;\n gte(value: R | ExprLike<R> | undefined): ExpressionCondition;\n lt(value: R | ExprLike<R> | undefined): ExpressionCondition;\n lte(value: R | ExprLike<R> | undefined): ExpressionCondition;\n // A list subquery may select a nullable column; NULLs in the set never match, so that is fine.\n in(values: readonly R[] | ExprLike<R | null> | undefined): ExpressionCondition;\n nin(values: readonly R[] | ExprLike<R | null> | undefined): ExpressionCondition;\n\n /** `count(x)::int`; `count(a.id)` is `count(*)` for the FROM table, and the matched-row count for a left-joined one. */\n count(): Expr<number, never>;\n countDistinct(): Expr<number, never>;\n sum(this: Expr<number | null, Src>): Expr<number | null, Src>;\n avg(this: Expr<number | null, Src>): Expr<number | null, Src>;\n min(): Expr<R | null, Src>;\n max(): Expr<R | null, Src>;\n /** PG keeps element NULLs (a left-joined empty group aggregates as `[null]`), and zero rows aggregate as NULL. */\n arrayAgg(): Expr<R[] | null, Src>;\n stringAgg(this: Expr<string | null, Src>, delimiter: string): Expr<string | null, Src>;\n coalesce(fallback: NonNullable<R>): Expr<NonNullable<R>, never>;\n}\n\n/**\n * A marker condition that `eq`/`in`/etc. return for an `undefined` value, so the condition prunes away.\n *\n * It lives here (not `QueryParser.ts`) so `Expr.ts` stays a runtime leaf: `Aliases.ts` extends `BaseExpr`\n * at load time, so this module must not (transitively) load `Aliases.ts` back. For the same reason its\n * `QueryParser.ts`/`EntityFilter.ts` imports use `import type`, which is fully erased - a `{ type X }`\n * import keeps a side-effect module load under `verbatimModuleSyntax`.\n */\nexport const skipCondition: ColumnCondition = {\n kind: \"column\",\n alias: \"skip\",\n column: \"skip\",\n dbType: \"skip\",\n cond: undefined as any,\n};\n\n/**\n * A join entry: the join kind is the key, the joined source is the value, plus `on`. `inner?: never` /\n * `left?: never` keep an entry to one kind (the `ExpressionFilter` `and`/`or` trick).\n *\n * `on` is required. A join is pruned when nothing references it anymore, not by an `undefined` ON;\n * `keep: true` pins a join that would otherwise prune, i.e. an inner join used as an existence filter,\n * the way em.find's `keepAliases` does. It is a boolean so callers can pass a flag.\n *\n * Declared here (not `query.ts`) so the relation join factories in `Aliases.ts` (i.e. `a.books.as(b)`) can\n * return them without importing `query.ts`; `query.ts` re-constrains `A` to its `QuerySource`.\n */\nexport interface InnerJoin<A> {\n readonly inner: A;\n readonly left?: never;\n readonly on: ExpressionCondition;\n readonly keep?: boolean;\n}\n\nexport interface LeftJoin<A> {\n readonly left: A;\n readonly inner?: never;\n readonly on: ExpressionCondition;\n readonly keep?: boolean;\n}\n\n/** SQL plus its `?` bindings plus the SQL aliases it references, i.e. for join pruning. */\nexport interface SqlFragment {\n sql: string;\n bindings: any[];\n refs: string[];\n}\n\n/**\n * What an expression needs from the query it is generating SQL for: the SQL alias assigned to each\n * source, and a way to turn nested conditions into SQL (which needs `ConditionBuilder`, so it lives in `query.ts`).\n */\nexport interface ExprContext {\n /** Returns the SQL alias for an alias's `AliasMgmt` or a subquery handle, searching enclosing queries. */\n aliasFor(handle: object): string;\n /** Turns a user-facing condition into SQL; `undefined` if it pruned away entirely. */\n conditionToSql(cond: ExpressionCondition): SqlFragment | undefined;\n}\n\nexport function isExpr(value: unknown): value is ExprLike<any> {\n return typeof value === \"object\" && value !== null && exprBrand in value;\n}\n\n/** Every `Expr` is a `BaseExpr` at runtime; this cast keeps `isExpr` a plain type guard so unions narrow. */\nexport function asNode(expr: ExprLike<any>): BaseExpr {\n return expr as any as BaseExpr;\n}\n\nexport const deferredAliasSym: unique symbol = Symbol(\"joist.deferredAliasCondition\");\n\n/** Resolves an alias handle (its `AliasMgmt`) to this parse's binding: the bound meta and SQL alias. */\nexport type AliasResolver = (handle: AliasMgmt) => { meta: EntityMetadata; alias: string };\n\n/**\n * A `ColumnCondition`/`RawCondition` whose alias(es) are re-resolved on every parse.\n *\n * Alias columns create conditions before any parser assigns SQL aliases, so the condition carries a\n * resolve function instead of a baked-in alias: `em.find` resolves with its join-literal bindings, and\n * `em.query` resolves through the `ExprContext`, whose `aliasFor` also records the ref for pruning and\n * correlation. Resolving recomputes from scratch, so one condition works across queries whose alias\n * assignments differ.\n */\nexport interface DeferredAliasCondition {\n [deferredAliasSym]: (resolve: AliasResolver) => void;\n}\n\nexport function isDeferredAliasCondition(cond: unknown): cond is DeferredAliasCondition {\n return typeof cond === \"object\" && cond !== null && deferredAliasSym in cond;\n}\n\n/** Tags `cond` with its per-parse resolve function, non-enumerable so the condition still deep-equals as data. */\nexport function withDeferredAlias<C extends object>(\n cond: C,\n resolve: (r: AliasResolver) => void,\n): C & DeferredAliasCondition {\n return Object.defineProperty(cond, deferredAliasSym, { value: resolve, enumerable: false }) as any;\n}\n\nexport const deferredSym: unique symbol = Symbol(\"joist.deferredCondition\");\n\n/**\n * A condition whose SQL depends on aliases that are only known once the query is parsed, i.e.\n * `bookStats.bookCount.gt(1)` or `bs.authorId.eq(a.id)`.\n *\n * It is shaped like a `RawCondition` so it can sit in any `ExpressionFilter`; `resolveDeferredConditions`\n * fills in `condition`, `bindings`, and `aliases` before the filter is parsed. Alias columns compared to\n * literals keep producing `ColumnCondition`s (the `em.find` path), so this is only for comparisons that\n * involve a non-alias expression.\n */\nexport interface DeferredCondition extends RawCondition {\n [deferredSym]: (ctx: ExprContext) => void;\n}\n\nexport function isDeferredCondition(cond: unknown): cond is DeferredCondition {\n return typeof cond === \"object\" && cond !== null && deferredSym in cond;\n}\n\n/** Creates a `DeferredCondition` that generates its SQL with `fn` once the query's aliases are known. */\nexport function deferredCondition(fn: (ctx: ExprContext) => SqlFragment): DeferredCondition {\n const cond: DeferredCondition = {\n kind: \"raw\",\n aliases: [],\n condition: \"<unresolved>\",\n bindings: [],\n pruneable: false,\n [deferredSym]: (ctx) => {\n const { sql, bindings, refs } = fn(ctx);\n cond.condition = sql;\n cond.bindings = bindings;\n cond.aliases = refs;\n },\n };\n return cond;\n}\n\n/** Walks an `ExpressionCondition` tree and resolves every deferred condition in place. */\nexport function resolveDeferredConditions(cond: ExpressionCondition | undefined, ctx: ExprContext): void {\n if (cond === undefined || cond === null) return;\n if (isDeferredCondition(cond)) {\n cond[deferredSym](ctx);\n } else if (isDeferredAliasCondition(cond)) {\n cond[deferredAliasSym](ctxResolver(ctx));\n } else if (\"and\" in cond && cond.and) {\n for (const c of cond.and) resolveDeferredConditions(c, ctx);\n } else if (\"or\" in cond && cond.or) {\n for (const c of cond.or) resolveDeferredConditions(c, ctx);\n }\n}\n\n/** Concatenates SQL fragments with `sep`, keeping bindings and refs in order. */\nexport function joinFragments(parts: SqlFragment[], sep: string): SqlFragment {\n return {\n sql: parts.map((p) => p.sql).join(sep),\n bindings: parts.flatMap((p) => p.bindings),\n refs: parts.flatMap((p) => p.refs),\n };\n}\n\n/**\n * The methods every expression shares. Subclasses provide `toSql`, and usually `decode`/`encode`.\n *\n * Alias columns override the comparison methods with the `em.find` `ColumnCondition` path when the\n * right-hand side is a literal, and fall back to these for expression-vs-expression comparisons.\n */\nexport abstract class BaseExpr {\n readonly [exprBrand]: any = this;\n\n /** Produces this expression's SQL so it can be embedded in a larger expression, i.e. a subquery gets parens. */\n abstract toSql(ctx: ExprContext): SqlFragment;\n\n /** The expression selected by a scalar subquery, used to resolve polymorphic IN conditions. */\n get subquerySelect(): BaseExpr | undefined {\n return undefined;\n }\n\n /** Produces the SQL without the outer parens a subquery normally gets; only differs for subqueries. */\n toSqlBare(ctx: ExprContext): SqlFragment {\n return this.toSql(ctx);\n }\n\n /** Converts a result-set value into the domain value, i.e. an int into a tagged id. */\n decode(value: unknown): unknown {\n return value;\n }\n\n /** Converts a domain value into the database value, i.e. a tagged id into an int, for bindings. */\n encode(value: unknown): unknown {\n return value;\n }\n\n eq(value: unknown): ExpressionCondition {\n return this.compare(\"=\", value);\n }\n\n ne(value: unknown): ExpressionCondition {\n return this.compare(\"!=\", value);\n }\n\n gt(value: unknown): ExpressionCondition {\n return this.compare(\">\", value);\n }\n\n gte(value: unknown): ExpressionCondition {\n return this.compare(\">=\", value);\n }\n\n lt(value: unknown): ExpressionCondition {\n return this.compare(\"<\", value);\n }\n\n lte(value: unknown): ExpressionCondition {\n return this.compare(\"<=\", value);\n }\n\n in(values: unknown): ExpressionCondition {\n return this.inList(\"IN\", values);\n }\n\n nin(values: unknown): ExpressionCondition {\n return this.inList(\"NOT IN\", values);\n }\n\n count(): Expr<number, never> {\n return new FnExpr(\"count\", [this], { suffix: \"::int\", decode: decodeNumber, encode: identity }) as any;\n }\n\n countDistinct(): Expr<number, never> {\n return new FnExpr(\"count\", [this], {\n prefix: \"DISTINCT \",\n suffix: \"::int\",\n decode: decodeNumber,\n encode: identity,\n }) as any;\n }\n\n sum(): Expr<number | null, any> {\n return new FnExpr(\"sum\", [this], { decode: decodeNumber, encode: identity }) as any;\n }\n\n avg(): Expr<number | null, any> {\n return new FnExpr(\"avg\", [this], { decode: decodeNumber, encode: identity }) as any;\n }\n\n min(): Expr<any, any> {\n return new FnExpr(\"min\", [this], { decode: (v) => this.decode(v) }) as any;\n }\n\n max(): Expr<any, any> {\n return new FnExpr(\"max\", [this], { decode: (v) => this.decode(v) }) as any;\n }\n\n arrayAgg(): Expr<any, any> {\n // Values are arrays while the argument encodes/decodes *elements*, i.e. a `.coalesce([\"b:1\"])`\n // fallback must encode each tagged id, not hand the whole array to the id column's encoder\n return new FnExpr(\"array_agg\", [this], {\n decode: (v) => (Array.isArray(v) ? v.map((e) => this.decode(e)) : v),\n encode: (v) => (Array.isArray(v) ? v.map((e) => this.encode(e)) : v),\n }) as any;\n }\n\n stringAgg(delimiter: string): Expr<string | null, any> {\n return new FnExpr(\"string_agg\", [this, new BindingExpr(delimiter)], {}) as any;\n }\n\n coalesce(fallback: unknown): Expr<any, never> {\n return new FnExpr(\"coalesce\", [this, new BindingExpr(this.encode(fallback))], {\n decode: (v) => this.decode(v),\n }) as any;\n }\n\n /** `this op value`, where `value` may be `undefined` (pruned), `null`, another expression, or a literal. */\n protected compare(op: string, value: unknown): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value === null) {\n const not = op === \"=\" ? \"\" : op === \"!=\" ? \"NOT \" : fail(`Cannot compare ${op} to null`);\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return { ...left, sql: `${left.sql} IS ${not}NULL` };\n });\n }\n if (isExpr(value)) {\n return deferredCondition((ctx) => joinFragments([this.toSql(ctx), asNode(value).toSql(ctx)], ` ${op} `));\n }\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return { sql: `${left.sql} ${op} ?`, bindings: [...left.bindings, this.encode(value)], refs: left.refs };\n });\n }\n\n /** `this IN (subquery)` or `this = ANY(?)` for a list; `NOT IN` / `!= ALL(?)` for `nin`. */\n protected inList(op: \"IN\" | \"NOT IN\", values: unknown): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (isExpr(values)) {\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n const right = asNode(values).toSqlBare(ctx);\n return joinFragments([left, { ...right, sql: `(${right.sql})` }], ` ${op} `);\n });\n }\n if (!Array.isArray(values)) fail(`Expected an array or subquery for ${op}, got ${values}`);\n const fn = op === \"IN\" ? \"= ANY(?)\" : \"!= ALL(?)\";\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return {\n sql: `${left.sql} ${fn}`,\n bindings: [...left.bindings, values.map((v) => this.encode(v))],\n refs: left.refs,\n };\n });\n }\n}\n\n/**\n * A SQL function applied to expressions, i.e. `count(a.\"id\")::int` or `coalesce(bs.\"n\", ?)`.\n *\n * By default the result decodes/encodes like the first argument (`max(a.id)` is still an id); numeric\n * aggregates pass their own `decode`/`encode`, since `count(a.id)` is a number, not an id.\n */\nexport class FnExpr extends BaseExpr {\n constructor(\n private name: string,\n private args: BaseExpr[],\n private opts: {\n prefix?: string;\n suffix?: string;\n decode?: (value: unknown) => unknown;\n encode?: (value: unknown) => unknown;\n },\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const args = joinFragments(\n this.args.map((a) => a.toSql(ctx)),\n \", \",\n );\n return { ...args, sql: `${this.name}(${this.opts.prefix ?? \"\"}${args.sql})${this.opts.suffix ?? \"\"}` };\n }\n\n decode(value: unknown): unknown {\n if (value === null || value === undefined) return value;\n return this.opts.decode ? this.opts.decode(value) : value;\n }\n\n encode(value: unknown): unknown {\n return this.opts.encode ? this.opts.encode(value) : this.args[0].encode(value);\n }\n}\n\n/** A bound literal, i.e. the `?` in `coalesce(x, ?)`. */\nexport class BindingExpr extends BaseExpr {\n constructor(private value: unknown) {\n super();\n }\n\n toSql(): SqlFragment {\n return { sql: \"?\", bindings: [this.value], refs: [] };\n }\n}\n\n/** An unmodeled column on a known source, i.e. `sql.ref(a, \"ts_search\")`; untracked at the type level. */\nexport class RefExpr extends BaseExpr {\n constructor(\n private handle: object,\n private column: string,\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const alias = ctx.aliasFor(this.handle);\n // safeKq for both halves: sql.ref takes user strings, and a subquery alias is its `as` name\n return { sql: `${safeKq(alias)}.${safeKq(this.column)}`, bindings: [], refs: [alias] };\n }\n}\n\n/**\n * A `sql` tagged template.\n *\n * For an Author alias `a` assigned the SQL alias `a1`:\n *\n * ```ts\n * sql`${a.age} * 2` // Expression: a1.age * 2\n * sql`${a.age.gte(18)}` // Condition: (a1.age >= ?), bindings [18]\n * sql`${\"Alice\"}` // Value: ?, bindings [\"Alice\"]\n * ```\n */\nexport class TemplateExpr extends BaseExpr {\n constructor(\n private strings: TemplateStringsArray,\n private values: unknown[],\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const parts: SqlFragment[] = [];\n this.strings.forEach((s, i) => {\n parts.push({ sql: s, bindings: [], refs: [] });\n if (i < this.values.length) parts.push(interpolationToSql(this.values[i], ctx));\n });\n return joinFragments(parts, \"\");\n }\n}\n\n/** Turns one `${...}` of a `sql` template into SQL: an expression, a condition, or a bound value. */\nexport function interpolationToSql(value: unknown, ctx: ExprContext): SqlFragment {\n if (isExpr(value)) {\n return asNode(value).toSql(ctx);\n } else if (isConditionLike(value)) {\n return ctx.conditionToSql(value as ExpressionCondition) ?? { sql: \"true\", bindings: [], refs: [] };\n } else {\n return { sql: \"?\", bindings: [value], refs: [] };\n }\n}\n\n/** True for the user-facing condition shapes: `{ and }`, `{ or }`, `ColumnCondition`, `RawCondition`. */\nexport function isConditionLike(value: unknown): boolean {\n if (typeof value !== \"object\" || value === null) return false;\n const v = value as any;\n return \"and\" in v || \"or\" in v || v.kind === \"column\" || v.kind === \"raw\" || v.kind === \"exists\";\n}\n\n/** An `AliasResolver` backed by an `ExprContext`; a handle's bound meta is its own (`em.query` sources are their own tables). */\nfunction ctxResolver(ctx: ExprContext): AliasResolver {\n return function resolve(handle: AliasMgmt) {\n return { meta: handle.meta, alias: ctx.aliasFor(handle) };\n };\n}\n\n/** Decodes `count`/`sum`/`avg` results, which Postgres returns as strings for bigint/numeric. */\nfunction decodeNumber(value: unknown): unknown {\n return typeof value === \"string\" ? Number(value) : value;\n}\n\nfunction identity(value: unknown): unknown {\n return value;\n}\n\nfunction fail(message: string): never {\n throw new Error(message);\n}\n"],"mappings":"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"}
|
package/build/query.cjs
CHANGED
|
@@ -73,15 +73,22 @@ function query(q) {
|
|
|
73
73
|
else return newSubqueryProxy(handle);
|
|
74
74
|
}
|
|
75
75
|
/**
|
|
76
|
-
*
|
|
76
|
+
* Builds a SQL expression from a tagged template.
|
|
77
77
|
*
|
|
78
|
-
*
|
|
79
|
-
* and every other value becomes a `?` binding, so users never write `"a.age * 2"` and hope `a` is the SQL
|
|
80
|
-
* alias, and referenced aliases still count for join pruning.
|
|
78
|
+
* For an Author alias `a` assigned the SQL alias `a1`:
|
|
81
79
|
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
80
|
+
* ```ts
|
|
81
|
+
* sql`${a.age} * 2` // Expression: a1.age * 2
|
|
82
|
+
* sql`${a.age.gte(18)}` // Condition: (a1.age >= ?), bindings [18]
|
|
83
|
+
* sql`${"Alice"}` // Value: ?, bindings ["Alice"]
|
|
84
|
+
*
|
|
85
|
+
* // Selecting this expression keeps the join to Book b.
|
|
86
|
+
* sql<number>`${b.order} * ${2}`
|
|
87
|
+
*
|
|
88
|
+
* // Reference an unmodeled column; it is untracked at the type level.
|
|
89
|
+
* sql.ref<string>(a, "ts_search")
|
|
90
|
+
* sql.condition`${sql.ref(a, "ts_search")} @@ plainto_tsquery(${term})`
|
|
91
|
+
* ```
|
|
85
92
|
*/
|
|
86
93
|
function sql(strings, ...values) {
|
|
87
94
|
return new require_Expr.TemplateExpr(strings, values);
|
package/build/query.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.cjs","names":["isAlias","isExpr","TemplateExpr","deferredCondition","RefExpr","AliasAssigner","fail","BaseExpr","safeKq","asNode","getAliasMgmt","JoinTableHandle","collectionJoin","m2mJoinTable","getAliasMetadata","kq","lazyExcludedSelects","kqStar","filterSoftDeletes","getBaseMeta","stiSubtypeFilter","ConditionBuilder","buildWhereClause","deepFindConditions"],"sources":["../src/query.ts"],"sourcesContent":["import { AliasAssigner } from \"./AliasAssigner.ts\";\nimport {\n type Alias,\n type AliasBrand,\n type AliasMgmt,\n JoinTableHandle,\n type M2mJoinTable,\n aliasMgmt,\n collectionJoin,\n getAliasMetadata,\n getAliasMgmt,\n isAlias,\n m2mJoinTable,\n} from \"./Aliases.ts\";\nimport { ConditionBuilder } from \"./ConditionBuilder.ts\";\nimport { buildWhereClause } from \"./drivers/buildUtils.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type ExpressionCondition, type ExpressionFilter } from \"./EntityFilter.ts\";\nimport { type EntityMetadata, getBaseMeta } from \"./EntityMetadata.ts\";\nimport {\n BaseExpr,\n type Expr,\n type ExprBrand,\n type ExprContext,\n type ExprLike,\n type InnerJoin,\n type LeftJoin,\n RefExpr,\n type SqlFragment,\n TemplateExpr,\n asNode,\n deferredCondition,\n exprBrand,\n isExpr,\n resolveDeferredConditions,\n} from \"./Expr.ts\";\nimport { kq, kqStar, safeKq } from \"./keywords.ts\";\nimport { deepFindConditions } from \"./QueryParser.pruning.ts\";\nimport {\n type ColumnCondition,\n type ParsedExpressionFilter,\n type ParsedFindQuery,\n addTablePerClassJoinsAndClassTag,\n filterSoftDeletes,\n lazyExcludedSelects,\n stiSubtypeFilter,\n} from \"./QueryParser.ts\";\nimport { fail } from \"./utils.ts\";\n\n/**\n * `em.query`: SQL-shaped queries as plain object literals.\n *\n * A query is data, a `Query<S, J>` POJO, `{ from, join, where, groupBy, having, select, orderBy, ... }`\n * in SQL evaluation order:\n *\n * const [a, b] = aliases(Author, Book);\n * const bookStats = query({ from: b, groupBy: [b.author], select: { authorId: b.author, n: b.id.count() } });\n * const rows = await em.query({\n * from: a,\n * join: [{ left: bookStats, on: bookStats.authorId.eq(a.id) }],\n * select: { name: a.firstName, n: bookStats.n },\n * orderBy: { n: \"DESC\" },\n * });\n * // rows: { name: string; n: number | null }[] (null because of the LEFT join)\n *\n * `em.query(pojo)` runs it. `select` decides the row type: a bare alias returns entities, a\n * `{ key: expr }` object returns typed POJOs, a bare subquery returns that subquery's rows.\n *\n * `query(pojo)` turns the *same* POJO into a value: a derived table with typed columns, a scalar\n * expression, or an entity list. It is the one non-POJO step, and the subquery analog of `alias(Author)`:\n * to reference a query's columns, the outer query needs *values* for them, and no POJO can manufacture\n * values keyed off its own `select` keys.\n *\n * `alias()`/`aliases()` and `query()` are the only free functions a query needs, plus the `sql` tagged\n * template as the escape hatch for SQL with no modeled shape. Everything else is in-DSL: join kinds and\n * sort directions are keyword keys (`{ left: b, on }`, `{ desc: x }`), SQL functions are methods on\n * expressions (`b.id.count()`, `b.title.max()`, `x.coalesce(0)`), conditions are methods\n * (`a.age.gte(18)`), and pruning is `undefined`: an `undefined` condition drops out, and a join nothing\n * references anymore drops with it (see \"Pruning\" below).\n *\n * User documentation: `docs/src/content/docs/features/queries-raw.md`.\n */\n\n// =====================================================================================================\n// Sources, joins, clauses\n// =====================================================================================================\n\nexport const subqueryBrand: unique symbol = Symbol(\"joist.subquery\");\nexport const entityQueryBrand: unique symbol = Symbol(\"joist.entityQuery\");\n\n/** Phantom type information carried by a table-shaped subquery. */\nexport interface SubqueryBrand<R, Name extends string> {\n readonly __row: R;\n readonly __name: Name;\n}\n\n/** Anything that can be a source or be joined: an entity alias or a table-shaped subquery. */\nexport type QuerySource =\n | { readonly [aliasMgmt]: AliasBrand<any, string> }\n | { readonly [subqueryBrand]: SubqueryBrand<any, string> };\n\n/**\n * A join entry (see `InnerJoin`/`LeftJoin` in `Expr.ts`): the expanded `{ inner: b, on }` form, or the\n * entry a relation join factory returns (`a.books.as(b)`); joins to a subquery are always the expanded\n * form, since a subquery has no FK metadata.\n */\nexport type QueryJoin = InnerJoin<QuerySource> | LeftJoin<QuerySource>;\nexport type QueryJoins = readonly (QueryJoin | undefined)[];\n\n/**\n * An expression order-by entry: the direction is the key and the expression is the value, unlike\n * the keyed form's field name and `\"ASC\" | \"DESC\"` value. `never` on the other key keeps an\n * entry to one direction, the same trick `ExpressionFilter` uses for `and`/`or`. `nulls` is\n * `NULLS FIRST/LAST`.\n *\n * When select keys are known, exclude them so a keyed sort cannot be silently ignored inside an\n * expression entry. An untyped `Query` has no known keys to exclude.\n */\nexport type QueryOrderBy<S = never> = (\n | { readonly asc: ExprLike<any>; readonly desc?: never }\n | { readonly desc: ExprLike<any>; readonly asc?: never }\n) & { readonly nulls?: \"first\" | \"last\" } & (string extends OrderByKey<S>\n ? unknown\n : { readonly [K in Exclude<OrderByKey<S>, \"asc\" | \"desc\" | \"nulls\">]?: never });\n\nexport type OrderByDirection =\n | \"ASC\"\n | \"DESC\"\n | \"ASC NULLS FIRST\"\n | \"ASC NULLS LAST\"\n | \"DESC NULLS FIRST\"\n | \"DESC NULLS LAST\";\n\n/**\n * A keyed `orderBy` entry, used alone or in an array, like `em.find`'s `orderBy: [{ firstName: \"ASC\" }]`.\n *\n * The keys are the keys of a POJO/subquery `select` (rendered as SQL output-column names, so ordering\n * by an aggregate does not repeat its expression), or the entity's sortable fields in entity mode.\n * An `undefined` direction prunes the entry, like any other condition. For expressions that are not\n * in `select`, mix in `{ asc: expr }` / `{ desc: expr }` entries in the array form.\n */\nexport type OrderByKeys<S> = S extends { readonly [aliasMgmt]: { readonly __entity: infer T } }\n ? T extends Entity\n ? { readonly [K in keyof Alias<T> as Alias<T>[K] extends ExprLike<any> ? K : never]?: OrderByDirection | undefined }\n : never\n : S extends { readonly [exprBrand]: any }\n ? never\n : { readonly [K in keyof S & string]?: OrderByDirection | undefined };\n\n/** All sortable keys across select variants, not just the keys shared by every variant. */\ntype OrderByKey<S> = S extends unknown ? keyof OrderByKeys<S> : never;\n\n/** The three select shapes: entity mode, single-expression mode (scalar/list subqueries), and POJO mode. */\nexport type QuerySelect = QuerySource | ExprLike<any> | Record<string, ExprLike<any>>;\n\n/**\n * Everything but the source, in SQL evaluation order: FROM/JOIN, WHERE, GROUP BY, HAVING, SELECT,\n * ORDER BY, LIMIT.\n *\n * `S` and `J` are generic so callers keep the literal shape of `select` and `join`; the defaults let\n * a standalone object use `satisfies Query` (or `satisfies Clauses` for a source-less fragment).\n */\nexport interface Clauses<S extends QuerySelect = QuerySelect, J extends QueryJoins = QueryJoins> {\n join?: J;\n /** An `{ and: [...] }` / `{ or: [...] }` filter, or a single bare condition, i.e. `where: a.age.gte(18)`. */\n where?: ExpressionCondition;\n groupBy?: readonly ExprLike<any>[];\n having?: ExpressionCondition;\n select: S;\n orderBy?: readonly (QueryOrderBy<S> | OrderByKeys<S> | undefined)[] | OrderByKeys<S>;\n limit?: number;\n offset?: number;\n distinct?: boolean;\n /** Defaults to true. `false` keeps every join, em.find's opt-out. */\n pruneJoins?: boolean;\n /**\n * Defaults to `\"exclude\"`, em.find's rule: a soft-deletable entity in `from` gains a\n * `deleted_at IS NULL` condition in WHERE, and a joined one gains it in its join's ON (so a LEFT\n * join nulls its columns out instead of dropping rows). `\"include\"` turns the injection off for\n * this query; subqueries read their own key.\n */\n softDeletes?: \"include\" | \"exclude\";\n}\n\n/** A whole query: `Clauses` plus its source. `query(q)` turns it into a value; `em.query(q)` runs it. */\nexport interface Query<S extends QuerySelect = QuerySelect, J extends QueryJoins = QueryJoins> extends Clauses<S, J> {\n from: QuerySource;\n}\n\n// =====================================================================================================\n// Result-row types\n// =====================================================================================================\n\n/** The type-level name of an alias or subquery, i.e. `\"Author\"` or `\"book_stats\"`. */\nexport type NameOf<A> = A extends { readonly [aliasMgmt]: { readonly __name: infer N } }\n ? N\n : A extends { readonly [subqueryBrand]: { readonly __name: infer N } }\n ? N\n : never;\n\n/** The names of every alias that was LEFT JOINed; `X` is a naked type parameter so this distributes. */\ntype LeftJoined<X> = X extends LeftJoin<infer A> ? NameOf<A> : never;\n\n/**\n * Asks: is this expression's source key among the LEFT-joined sources in this query's join list? If\n * yes, the value can be `null`, so `R` becomes `R | null`; if no, `R` is unchanged.\n *\n * I.e. `MaybeNull<number, \"book_stats\", [LeftJoin<typeof bookStats>]>` is `number | null`,\n * because `book_stats` is in `LeftJoined<J[number]>`; with an inner join it stays `number`.\n *\n * Source-less expressions (`Src` is `never`, i.e. `b.id.count()`) are never nullified. Untracked ones\n * (`Src` is `string`, i.e. a `sql.ref` on an unknown table) might come from any left-joined table,\n * so they are conservatively nullified whenever the query has a left join at all.\n *\n * `string` must never be a *table's* name: `Extract<\"Author\", string>` matches, so one left-joined\n * table named `string` would nullify every column in the query. That is why anonymous subqueries\n * share the literal sentinel `\"?\"` instead.\n */\nexport type MaybeNull<R, Src extends string, J extends QueryJoins> = string extends Src\n ? [LeftJoined<J[number]>] extends [never]\n ? R\n : R | null\n : [Extract<Src, LeftJoined<J[number]>>] extends [never]\n ? R\n : R | null;\n\n/**\n * The result row for a query with select `S` and joins `J`.\n *\n * - entity mode (`select: a`) is the entity\n * - subquery mode (`select: bookStats`) is the subquery's row, i.e. `select *`\n * - single expression (`select: b.id.count()`) is that expression's value, used by scalar subqueries\n * - POJO mode is a mapped type over the select keys, with left-join nullability applied\n */\nexport type QueryRow<S, J extends QueryJoins = []> = S extends { readonly [aliasMgmt]: { readonly __entity: infer T } }\n ? T\n : S extends { readonly [subqueryBrand]: { readonly __row: infer R } }\n ? R\n : S extends { readonly [exprBrand]: ExprBrand<infer R, infer Src> }\n ? MaybeNull<R, Src, J>\n : {\n [K in keyof S]: S[K] extends { readonly [exprBrand]: ExprBrand<infer R, infer Src> }\n ? MaybeNull<R, Src, J>\n : never;\n };\n\n// =====================================================================================================\n// `query()`: a query POJO becomes a typed table, scalar, or entity list\n// =====================================================================================================\n\n/**\n * A table-shaped query: one `Expr` per select key, each tagged with the table's name as its `Src`,\n * plus a brand carrying the row type. This is the direct analog of `Alias<T>`: `Alias<T>` maps entity\n * fields to expressions, `Subquery<Row, Name>` maps the inner query's select keys to expressions.\n */\nexport type Subquery<R, Name extends string> = {\n readonly [subqueryBrand]: SubqueryBrand<R, Name>;\n} & { readonly [K in keyof R]: Expr<R[K], Name> };\n\n/** An entity-mode query (`select: a`): runnable, but it has no columns to reference. */\nexport type EntityQuery<T extends Entity> = { readonly [entityQueryBrand]: { readonly __row: T } };\n\n/**\n * Rejects a `select` that a `: Query` annotation widened to the whole `QuerySelect` union.\n *\n * `satisfies Query` checks the shape but keeps the literal type of `select`, so `S` infers as\n * `{ name: Expr<string, \"Author\"> }`. A `: Query` annotation replaces that type with the annotation, so\n * `S` infers as `QuerySelect` itself, and without this guard `query(q)` returned a useless union with no\n * error at all.\n *\n * A widened `S` is the only kind of `S` the whole `QuerySelect` union is assignable to (a POJO, an\n * `Expr`, or an `Alias` never is), so `QuerySelect extends S` detects it, and intersecting the parameter\n * with `{ select: \"<message>\" }` fails the call on `select` with that message, for `query()` and\n * `em.query()` alike:\n *\n * const narrow = { from: a, select: { name: a.firstName } } satisfies Query;\n * query(narrow); // Subquery<{ name: string }, \"?\">\n *\n * const widened: Query = { from: a, select: { name: a.firstName } };\n * query(widened);\n * // error: Type 'QuerySelect' is not assignable to type\n * // '\"select was typed too generically; use `satisfies Query` instead of `: Query`\"'\n *\n * `S` also defaults to `never`, so a *missing* `select` is reported as \"Property 'select' is missing\"\n * against `Query<never, []>` instead of tripping this guard.\n */\nexport type NotWidened<S> = QuerySelect extends S\n ? { select: \"select was typed too generically; use `satisfies Query` instead of `: Query`\" }\n : unknown;\n\n/** What `query()` returns, by select shape: an entity list, a scalar/list subquery, or a derived table. */\nexport type QueryValue<S, J extends QueryJoins, Name extends string> = S extends {\n readonly [aliasMgmt]: { readonly __entity: infer T extends Entity };\n}\n ? EntityQuery<T>\n : S extends { readonly [exprBrand]: ExprBrand<infer R, any> }\n ? Expr<R | null, never>\n : Subquery<QueryRow<S, J>, Name>;\n\n/** The names of every alias in scope for a query: the source alias plus every joined alias. */\ntype JoinedName<X> = X extends { readonly inner: infer A }\n ? NameOf<A>\n : X extends { readonly left: infer A }\n ? NameOf<A>\n : never;\ntype InScope<F, J extends QueryJoins> = NameOf<F> | JoinedName<J[number]>;\n\n/**\n * Asks, for every column of a POJO select: is its source key among `from` + `join` at all? If no, the\n * query reads from a table it never joined, and that select key's type becomes an error message.\n *\n * Because `Expr` already carries `Src`, this is nearly free: for each select key, if `Src` is tracked\n * and any of its names is outside `InScope`, intersect that key's type with an error string, so the\n * caller sees `Type 'Expr<number, \"book_stats\">' is not assignable to type '... is not in from/join'`.\n * Untracked (`string`) and source-less (`never`) expressions always pass. Aliases with the same\n * type-level name (two bare `alias(Author)`, or two anonymous tables) cannot be told apart, so a miss\n * there goes unreported; the check never gives a false positive, only false negatives on collisions.\n *\n * `[S] extends [...]` keeps this non-distributive, and `never` is skipped outright: `query()` defaults\n * `S` to `never` when `select` is missing, and a distributive conditional over `never` would swallow the\n * whole parameter type.\n */\nexport type CheckScope<S, F, J extends QueryJoins> = [S] extends [never]\n ? unknown\n : // A source-shaped select (`select: a`, `select: bookStats`) must be the `from`: a joined source's\n // rows would need left-join nullability (and entity hydration) that source-shaped selects don't\n // model. Two same-named sources (unnamed aliases of one entity, anonymous subqueries) pass this\n // check and are caught at runtime instead.\n [S] extends [QuerySource]\n ? NameOf<S> extends NameOf<F>\n ? unknown\n : { select: `'${NameOf<S> & string}' is a joined source, not the from; select its columns individually` }\n : [S] extends [Record<string, ExprLike<any>>]\n ? {\n select: {\n [K in keyof S]: S[K] extends { readonly [exprBrand]: ExprBrand<any, infer Src> }\n ? string extends Src\n ? unknown\n : [Exclude<Src, InScope<F, J>>] extends [never]\n ? unknown\n : `alias '${Exclude<Src, InScope<F, J>> & string}' is not in from/join`\n : unknown;\n };\n }\n : unknown;\n\n/** The one argument type `query()` and `em.query()` share: a `Query` POJO plus its source, name, and checks. */\nexport type QueryArg<F extends QuerySource, S extends QuerySelect, J extends QueryJoins, Name extends string> = Query<\n S,\n J\n> & {\n from: F;\n as?: Name;\n} & CheckScope<S, F, J> &\n NotWidened<S>;\n\n/**\n * Turns a `Query` POJO into a value. The select shape decides which (`QueryValue`):\n *\n * - a single expression is a scalar subquery or an IN list (`Expr<R | null>`; a scalar subquery can\n * return no row, so use `.coalesce(0)` when the SQL guarantees a value, i.e. an ungrouped `count`)\n * - an entity alias is an entity list, runnable via `em.query`\n * - a POJO is a derived table whose columns are `Expr`s; it can be a source, be joined, or be run\n *\n * `as` is the SQL alias and the type-level identity, the same role the second argument of\n * `alias(Author, \"m\")` plays. Without it the SQL alias is generated, like `alias(Author)`, and all\n * anonymous tables share the type-level identity `\"?\"`: precise against every named alias, and\n * conservative (a left-joined anonymous table nullifies every anonymous table's columns) only among\n * themselves. This is the same collision two bare `alias(Author)` have.\n *\n * One signature, not three overloads: overloads wrapped every clauses-object mistake in \"No overload\n * matches this call\", hid `as` from completions, and cost 15-28% check time; the one thing they did\n * better, rejecting a `select` widened by a `: Query` annotation, `NotWidened` does with a clearer message.\n */\nexport function query<\n F extends QuerySource,\n S extends QuerySelect = never,\n J extends QueryJoins = [],\n Name extends string = \"?\",\n>(q: QueryArg<F, S, J, Name>): QueryValue<S, J, Name> {\n const handle = new SubqueryHandle(q as AnyQuery);\n const select = (q as AnyQuery).select;\n if (isAlias(select)) {\n return { [entityQueryBrand]: handle } as any;\n } else if (isExpr(select)) {\n return new SubqueryExpr(handle) as any;\n } else {\n return newSubqueryProxy(handle) as any;\n }\n}\n\n/**\n * The escape hatch for SQL with no modeled shape.\n *\n * Interpolated expressions use the alias Joist assigned, interpolated conditions become SQL,\n * and every other value becomes a `?` binding, so users never write `\"a.age * 2\"` and hope `a` is the SQL\n * alias, and referenced aliases still count for join pruning.\n *\n * sql<number>`${b.order} * ${2}`\n * sql.condition`${sql.ref(a, \"ts_search\")} @@ plainto_tsquery(${term})`\n * sql.ref<string>(a, \"ts_search\") // an unmodeled column; untracked at the type level\n */\nexport function sql<R = unknown>(strings: TemplateStringsArray, ...values: unknown[]): Expr<R, never> {\n return new TemplateExpr(strings, values) as any;\n}\n\n/** A raw condition for `where`, `having`, or `on`. */\nsql.condition = function condition(strings: TemplateStringsArray, ...values: unknown[]): ExpressionCondition {\n return deferredCondition((ctx) => new TemplateExpr(strings, values).toSql(ctx));\n};\n\n/** A column Joist does not model, on a source that is in the query. */\nsql.ref = function ref<R = unknown>(source: QuerySource, column: string): Expr<R, string> {\n return new RefExpr(handleOf(source), column) as any;\n};\n\n/**\n * Parses `arg` (a `Query` POJO or `query(...)` value) into a runnable `Plan`.\n *\n * `EntityManager.query` runs the plan; this module deliberately does not import `EntityManager` (see\n * `EntityHydrator`), so it parses and hands back `{ sql, bindings, decodeRows }` instead of executing.\n */\nexport function parseUserQuery(arg: unknown): Plan {\n return parseQuery(toQuery(arg), undefined, new AliasAssigner());\n}\n\n/**\n * The one `EntityManager` capability that row decoding needs, typed structurally.\n *\n * Importing `EntityManager.ts` here would complete an `EntityManager.ts` <-> `query.ts` declaration\n * cycle (`EntityManager.query` imports this module's types), which correlated with a tsc 7.0.2\n * incremental-build bug: after tsdown rewrites `build/`, `tsc --build` sporadically reports thousands\n * of phantom \"Module 'joist-orm' has no exported member ...\" errors and caches them in `.tsbuildinfo`.\n */\nexport interface EntityHydrator {\n hydrate(cstr: any, rows: readonly any[]): any[];\n}\n\nexport interface Plan {\n sql: string;\n bindings: any[];\n /** Aliases of enclosing queries this (sub)query referenced. */\n outerRefs: string[];\n decodeRows(em: EntityHydrator, rows: any[]): any[];\n}\n\n// =====================================================================================================\n// Runtime: handles, subquery expressions, the proxy\n// =====================================================================================================\n\ntype AnyQuery = Query<any, any> & { as?: string };\n\n/** The runtime identity of a `query(...)` value; `Ctx.aliasFor` keys on it, like an alias's `AliasMgmt`. */\nexport class SubqueryHandle {\n constructor(readonly q: AnyQuery) {}\n\n get name(): string | undefined {\n return this.q.as;\n }\n\n /** The select keys, for `select: <subquery>` and for reporting unknown columns. */\n columnKeys(): string[] {\n const { select } = this.q;\n if (isPlainSelect(select)) return Object.keys(select);\n if (isSubqueryValue(select)) return select[subqueryBrand].columnKeys();\n return fail(`A subquery with an entity or scalar select has no columns`);\n }\n\n /** The inner expression behind `key`, for its decoder/encoder. */\n columnExpr(key: string): BaseExpr {\n const { select } = this.q;\n if (isPlainSelect(select)) {\n return (select[key] as any as BaseExpr) ?? fail(`Subquery ${this.describe()} has no column ${key}`);\n } else if (isSubqueryValue(select)) {\n return select[subqueryBrand].columnExpr(key);\n }\n return fail(`Subquery ${this.describe()} has no columns`);\n }\n\n column(key: string): SubqueryColumnExpr {\n return new SubqueryColumnExpr(this, key, this.columnExpr(key));\n }\n\n describe(): string {\n return this.q.as ? `'${this.q.as}'` : \"(anonymous)\";\n }\n}\n\n/** A column of a joined/from'd subquery, i.e. `bookStats.bookCount`, which becomes `book_stats.\"bookCount\"`. */\nclass SubqueryColumnExpr extends BaseExpr {\n constructor(\n private handle: SubqueryHandle,\n private key: string,\n private inner: BaseExpr,\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const alias = ctx.aliasFor(this.handle);\n // safeKq for the alias too: a subquery's canonical alias is its user-provided `as` name\n return { sql: `${safeKq(alias)}.${safeKq(this.key)}`, bindings: [], refs: [alias] };\n }\n\n decode(value: unknown): unknown {\n return this.inner.decode(value);\n }\n\n encode(value: unknown): unknown {\n return this.inner.encode(value);\n }\n}\n\n/**\n * A scalar (or IN-list) subquery, i.e. `query({ from: b, where: [...], select: b.id.count() })`.\n *\n * It closes over the outer aliases it references, so correlation is free; those references are the\n * subquery's \"free\" aliases and count toward the outer query's join pruning.\n */\nclass SubqueryExpr extends BaseExpr {\n constructor(readonly handle: SubqueryHandle) {\n super();\n }\n\n get subquerySelect(): BaseExpr {\n return asNode(this.handle.q.select);\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const bare = this.toSqlBare(ctx);\n return { ...bare, sql: `(${bare.sql})` };\n }\n\n toSqlBare(ctx: ExprContext): SqlFragment {\n const parent = ctx instanceof Ctx ? ctx : fail(\"Subqueries need the query parser's context\");\n const plan = parseQuery(this.handle.q, parent, parent.assigner);\n return { sql: plan.sql, bindings: plan.bindings, refs: plan.outerRefs };\n }\n\n decode(value: unknown): unknown {\n return this.subquerySelect.decode(value);\n }\n\n encode(value: unknown): unknown {\n return this.subquerySelect.encode(value);\n }\n}\n\nfunction newSubqueryProxy(handle: SubqueryHandle): object {\n return new Proxy(\n {},\n {\n get(_, key) {\n if (key === subqueryBrand) return handle;\n if (typeof key === \"string\") return handle.column(key);\n return undefined;\n },\n has(_, key) {\n return key === subqueryBrand || (typeof key === \"string\" && handle.columnKeys().includes(key));\n },\n },\n );\n}\n\nfunction isSubqueryValue(value: unknown): value is { [subqueryBrand]: SubqueryHandle } {\n return typeof value === \"object\" && value !== null && subqueryBrand in value;\n}\n\nfunction isEntityQueryValue(value: unknown): value is { [entityQueryBrand]: SubqueryHandle } {\n return typeof value === \"object\" && value !== null && entityQueryBrand in value;\n}\n\nfunction isPlainSelect(select: unknown): select is Record<string, ExprLike<any>> {\n return (\n typeof select === \"object\" && select !== null && !isAlias(select) && !isExpr(select) && !isSubqueryValue(select)\n );\n}\n\n/** Returns the runtime identity of a source: an alias's `AliasMgmt` or a subquery's handle. */\nfunction handleOf(source: unknown): AliasMgmt | SubqueryHandle {\n if (isAlias(source)) return getAliasMgmt(source);\n if (isSubqueryValue(source)) return source[subqueryBrand];\n return fail(`Expected an alias or a query(...) value, got ${source}`);\n}\n\n// =====================================================================================================\n// Runtime: parse -> prune -> SQL -> decode\n// =====================================================================================================\n\nfunction toQuery(arg: unknown): AnyQuery {\n if (isSubqueryValue(arg)) return arg[subqueryBrand].q;\n if (isEntityQueryValue(arg)) return arg[entityQueryBrand].q;\n if (arg instanceof SubqueryExpr) return arg.handle.q;\n if (typeof arg === \"object\" && arg !== null && \"from\" in arg && \"select\" in arg) return arg as AnyQuery;\n return fail(`em.query expects a { from, select, ... } object or a query(...) value`);\n}\n\n/**\n * What an expression needs from the query it is generating SQL for.\n *\n * Each (sub)query gets its own `Ctx`; a lookup that misses locally walks up to the enclosing query and\n * records the hit in `outerRefs`, which is how a correlated subquery reports the outer aliases it\n * depends on (the way `ExistsCondition.outerAliases` does), so join pruning keeps them.\n */\nclass Ctx implements ExprContext {\n private aliases = new Map<object, string>();\n readonly outerRefs = new Set<string>();\n /** Physical CTI table aliases (`sp_b0`) to their source alias (`sp`), shared across the whole parse. */\n readonly ctiAliases: Map<string, string>;\n\n constructor(\n readonly assigner: AliasAssigner,\n private parent: Ctx | undefined,\n ) {\n this.ctiAliases = parent?.ctiAliases ?? new Map();\n }\n\n register(handle: object, alias: string): void {\n this.aliases.set(handle, alias);\n }\n\n aliasFor(handle: object): string {\n const local = this.aliases.get(handle);\n if (local) return local;\n if (this.parent) {\n const outer = this.parent.aliasFor(handle);\n this.outerRefs.add(outer);\n return outer;\n }\n return fail(`${describeHandle(handle)} is not in this query's from/join`);\n }\n\n conditionToSql(cond: ExpressionCondition): SqlFragment | undefined {\n // Inside another expression (i.e. a `sql` template), keep `a OR b` grouped\n return conditionToSql(cond, this, false);\n }\n}\n\nfunction describeHandle(handle: object): string {\n if (handle instanceof SubqueryHandle) return `Subquery ${handle.describe()}`;\n if (handle instanceof JoinTableHandle) return `Join table ${handle.joinTableName}`;\n if (\"tableName\" in handle) return `Alias for ${(handle as AliasMgmt).tableName}`;\n return \"Alias\";\n}\n\ninterface ParsedSource {\n handle: AliasMgmt | SubqueryHandle | JoinTableHandle;\n alias: string;\n /** `table AS alias` or `(SELECT ...) AS alias`. */\n sql: string;\n bindings: any[];\n /** Outer aliases a derived table references; PG rejects those without LATERAL, but pruning should still see them. */\n refs: string[];\n /** CTI base/sub-table joins that travel with an entity alias. */\n extraJoins: string[];\n /** Entity-mode selects, i.e. `a.*` plus CTI columns and the `__class` tag. */\n entitySelects: string[];\n meta: EntityMetadata | undefined;\n}\n\ninterface ParsedJoin {\n kind: \"inner\" | \"left\";\n source: ParsedSource;\n /** The user's ON alone; `undefined` means it pruned away entirely, an error if the join is kept. */\n userOn: SqlFragment | undefined;\n /** The ON to emit: the user's ON plus any injected soft-delete/STI-discriminator conditions. */\n fullOn: SqlFragment | undefined;\n keep: boolean;\n}\n\n/**\n * Parses one `Query` POJO into SQL, recursively for subqueries.\n *\n * 1. Register every source's runtime identity with its SQL alias in this parse's context.\n * 2. Generate SQL for sources, selects, conditions, group-bys, and order-bys against the context; every fragment\n * reports the aliases it references.\n * 3. Prune: drop joins nothing references (see below), then reject a kept join whose ON collapsed.\n * 4. Assemble the SQL from the kept fragments, so pruned bindings disappear with their SQL.\n */\nfunction parseQuery(q: AnyQuery, parent: Ctx | undefined, assigner: AliasAssigner): Plan {\n const ctx = new Ctx(assigner, parent);\n const selectedAlias = isAlias(q.select) ? getAliasMgmt(q.select) : undefined;\n const joinEntries = [...(q.join ?? [])].filter(isDefined);\n\n // 1. Register every source before generating SQL, so conditions can resolve their aliases.\n const parseFrom = registerSource(q.from, ctx, assigner, handleOf(q.from) === selectedAlias);\n const pendingJoins = joinEntries.flatMap((j) => {\n const kind = \"inner\" in j && j.inner ? (\"inner\" as const) : (\"left\" as const);\n const alias = kind === \"inner\" ? j.inner : j.left;\n const keep = j.keep ?? false;\n // Only collection sugar joins (o2m/m2m) filter soft-deletes, em.find's relation semantics:\n // references (m2o/o2o/poly) resolve soft-deleted entities, and explicit joins are the user's own\n const softDeletes = (j as any)[collectionJoin] === true;\n const target = { kind, keep, on: j.on, softDeletes, parseSource: registerSource(alias, ctx, assigner, false) };\n // A sugar m2m join (`a.tags.as(t)`) carries a hidden join-table join; emit it first, with the same kind\n const m2m: M2mJoinTable | undefined = (j as any)[m2mJoinTable];\n if (!m2m) return [target];\n return [\n { kind, keep, on: m2m.on, softDeletes: false, parseSource: registerJoinTable(m2m.handle, ctx, assigner) },\n target,\n ];\n });\n\n // 2. Generate SQL.\n const softDeletes = q.softDeletes ?? \"exclude\";\n const from = parseFrom();\n const joins: ParsedJoin[] = pendingJoins.map((j) => {\n const source = j.parseSource();\n // `userOn` is the user's ON alone, so the collapsed-ON check below is not fooled by injections\n const userOn = conditionToSql(j.on, ctx, true);\n const injected = injectedConditions(source, j.softDeletes ? softDeletes : \"include\");\n const fullOn = userOn && injected.length > 0 ? conditionToSql({ and: [j.on, ...injected] }, ctx, true) : userOn;\n return { kind: j.kind, keep: j.keep, source, userOn, fullOn };\n });\n const { selects, decodeRows } = selectsToSql(q, ctx, from);\n const fromInjected = injectedConditions(from, softDeletes);\n const where = conditionToSql(fromInjected.length > 0 ? { and: [q.where, ...fromInjected] } : q.where, ctx, true);\n const having = conditionToSql(q.having, ctx, true);\n const groupBys = (q.groupBy ?? []).map((g) => asExpr(g, \"groupBy\").toSql(ctx));\n const orderBys = orderBysToSql(q, ctx);\n\n // 3. Prune.\n const kept = pruneJoins(q, from, joins, [...selects, ...groupBys, ...orderBys, where, having].filter(isDefined));\n // Joins emit in declaration order, so an ON may only reference sources declared before it; a forward\n // reference would reach PG as invalid SQL (\"missing FROM-clause entry\"). Reordering is not offered:\n // it is not semantics-preserving once INNER and LEFT joins mix, and the caller's fix is trivial.\n const laterAliases = new Set(kept.map((j) => j.source.alias));\n for (const j of kept) {\n if (!j.userOn) {\n fail(\n `Join ${describeHandle(j.source.handle)} has no ON condition left (they all pruned), but the query still references it`,\n );\n }\n laterAliases.delete(j.source.alias);\n const forward = j.fullOn!.refs.find((r) => laterAliases.has(r));\n if (forward) {\n fail(\n `Join ${describeHandle(j.source.handle)} references '${forward}', which is joined later; move that join earlier in the join array`,\n );\n }\n }\n\n // 4. Assemble.\n const out: SqlFragment[] = [];\n out.push({ sql: `SELECT ${q.distinct ? \"DISTINCT \" : \"\"}`, bindings: [], refs: [] });\n out.push(joinFragmentParts(selects, \", \"));\n out.push({ sql: ` FROM ${from.sql}`, bindings: from.bindings, refs: [] });\n for (const extra of from.extraJoins) out.push({ sql: ` ${extra}`, bindings: [], refs: [] });\n for (const j of kept) {\n const keyword = j.kind === \"inner\" ? \"JOIN\" : \"LEFT OUTER JOIN\";\n // A CTI subtype's physical base-table joins go *inside* a parenthesized join item: the ON can\n // reference the base alias (i.e. `sp.id` renders as `sp_b0.id`), so the subtree must join first\n const source = j.source.extraJoins.length > 0 ? `(${j.source.sql} ${j.source.extraJoins.join(\" \")})` : j.source.sql;\n out.push({\n sql: ` ${keyword} ${source} ON ${j.fullOn!.sql}`,\n bindings: [...j.source.bindings, ...j.fullOn!.bindings],\n refs: [],\n });\n }\n if (where) out.push({ sql: ` WHERE ${where.sql}`, bindings: where.bindings, refs: [] });\n if (groupBys.length > 0)\n out.push({ ...joinFragmentParts(groupBys, \", \"), sql: ` GROUP BY ${groupBys.map((g) => g.sql).join(\", \")}` });\n if (having) out.push({ sql: ` HAVING ${having.sql}`, bindings: having.bindings, refs: [] });\n if (orderBys.length > 0)\n out.push({ ...joinFragmentParts(orderBys, \", \"), sql: ` ORDER BY ${orderBys.map((o) => o.sql).join(\", \")}` });\n if (q.limit !== undefined) out.push({ sql: ` LIMIT ?`, bindings: [q.limit], refs: [] });\n if (q.offset !== undefined) out.push({ sql: ` OFFSET ?`, bindings: [q.offset], refs: [] });\n\n return {\n sql: out.map((o) => o.sql).join(\"\"),\n bindings: out.flatMap((o) => o.bindings),\n outerRefs: [...ctx.outerRefs],\n decodeRows,\n };\n}\n\n/**\n * Assigns a SQL alias to a source and returns a function that parses it after all sources are registered.\n *\n * Conditions resolve source identities through the context when their SQL is generated. CTI entities\n * get their base/sub-table joins from `addTablePerClassJoinsAndClassTag`, and the entity-mode `select`\n * gets that helper's selects too.\n */\nfunction registerSource(source: unknown, ctx: Ctx, assigner: AliasAssigner, isPrimary: boolean): () => ParsedSource {\n const handle = handleOf(source);\n if (handle instanceof SubqueryHandle) {\n const alias = handle.name ? assigner.getLiteralAlias(handle.name) : assigner.getLiteralAlias(\"sq\");\n ctx.register(handle, alias);\n return () => {\n const inner = parseQuery(handle.q, ctx, assigner);\n return {\n handle,\n alias,\n sql: `(${inner.sql}) AS ${safeKq(alias)}`,\n bindings: inner.bindings,\n refs: inner.outerRefs,\n extraJoins: [],\n entitySelects: [],\n meta: undefined,\n };\n };\n } else {\n const meta = getAliasMetadata(source as any);\n const alias = assigner.getAlias(meta.tableName);\n ctx.register(handle, alias);\n // Record the physical CTI table aliases this source emits (i.e. `sp_b0`), so `refsOf` can credit\n // their refs to this alias exactly; a user subquery named `book_b0` must not be mistaken for one\n if (meta.inheritanceType === \"cti\") {\n meta.baseTypes.forEach((_, i) => ctx.ctiAliases.set(`${alias}_b${i}`, alias));\n if (isPrimary) meta.subTypes.forEach((_, i) => ctx.ctiAliases.set(`${alias}_s${i}`, alias));\n }\n return () => {\n const cti: ParsedFindQuery = { selects: [], tables: [], orderBys: [] };\n addTablePerClassJoinsAndClassTag(cti, meta, alias, isPrimary);\n const extraJoins = cti.tables.map((t) => {\n if (t.join !== \"outer\") return fail(`Unexpected ${t.join} join for CTI`);\n return `LEFT OUTER JOIN ${kq(t.table)} AS ${kq(t.alias)} ON ${t.col1} = ${t.col2}`;\n });\n // Entity mode starts with the primary table's own columns (excluding lazy ones, like em.find)\n // and *appends* the CTI base/sub-table columns and the __class tag; the CTI selects alone would\n // drop the selected table's own fields, i.e. a Publisher would hydrate with an undefined name\n const primarySelects = meta.hasLazyColumns ? lazyExcludedSelects(meta, alias) : [kqStar(alias)];\n const entitySelects = [...primarySelects, ...(cti.selects as string[])];\n return {\n handle,\n alias,\n sql: `${kq(meta.tableName)} AS ${kq(alias)}`,\n bindings: [],\n refs: [],\n extraJoins,\n entitySelects,\n meta,\n };\n };\n }\n}\n\n/**\n * em.find's per-source injections: `alias.deleted_at IS NULL` for a soft-deletable entity (CTI\n * subtypes are skipped, like em.find; see `filterSoftDeletes`), and the `type_id = X` discriminator\n * for an STI subtype, so `from: alias(TaskNew)` only sees (and a joined subtype only matches)\n * TaskNew rows.\n *\n * The conditions go into the from's WHERE or the join's ON, and never keep an otherwise unreferenced\n * join alive, which is what `pruneable: true` means on em.find's side.\n */\nfunction injectedConditions(source: ParsedSource, softDeletes: \"include\" | \"exclude\"): ColumnCondition[] {\n const { meta } = source;\n if (!meta) return [];\n const conditions: ColumnCondition[] = [];\n if (filterSoftDeletes(meta, softDeletes)) {\n const field = meta.allFields[getBaseMeta(meta).timestampFields!.deletedAt!];\n const column = field.serde!.columns[0];\n conditions.push({\n kind: \"column\",\n alias: `${source.alias}${field.aliasSuffix}`,\n column: column.columnName,\n dbType: column.dbType,\n cond: { kind: \"is-null\" },\n pruneable: true,\n });\n }\n const sti = stiSubtypeFilter(meta, source.alias);\n if (sti) conditions.push(sti);\n return conditions;\n}\n\n/** Registers a sugar m2m join table, i.e. `authors_to_tags`: a raw table with no entity metadata. */\nfunction registerJoinTable(handle: JoinTableHandle, ctx: Ctx, assigner: AliasAssigner): () => ParsedSource {\n const alias = assigner.getAlias(handle.joinTableName);\n ctx.register(handle, alias);\n return () => ({\n handle,\n alias,\n sql: `${kq(handle.joinTableName)} AS ${kq(alias)}`,\n bindings: [],\n refs: [],\n extraJoins: [],\n entitySelects: [],\n meta: undefined,\n });\n}\n\n/** Generates the `select` clause SQL and returns how to decode the resulting rows. */\nfunction selectsToSql(\n q: AnyQuery,\n ctx: Ctx,\n from: ParsedSource,\n): { selects: SqlFragment[]; decodeRows: Plan[\"decodeRows\"] } {\n const { select } = q;\n if (isAlias(select)) {\n // Entity mode: `a.*` (plus CTI columns), hydrated through the identity map. Only the from is\n // hydratable: a joined alias would need null-row skipping and left-join nullability (see TODO.md)\n if (from.handle !== getAliasMgmt(select)) {\n fail(\"Selecting a joined alias is not supported yet; select the from alias, or select its columns individually\");\n }\n const alias = ctx.aliasFor(getAliasMgmt(select));\n const meta = getAliasMetadata(select);\n const selects = from.entitySelects.map((s) => ({ sql: s, bindings: [], refs: [alias] }));\n return { selects, decodeRows: (em, rows) => em.hydrate(meta.cstr as any, rows) };\n } else if (isSubqueryValue(select)) {\n // `select: <subquery>` is `select *` for that table; like entity mode, only for the from, since a\n // left-joined subquery's unmatched rows would decode null fields the row type calls non-null\n const handle = select[subqueryBrand];\n if (from.handle !== handle) {\n fail(\n \"Selecting a joined subquery is not supported; select the from subquery, or select its columns individually\",\n );\n }\n const alias = ctx.aliasFor(handle);\n const keys = handle.columnKeys();\n const selects = keys.map((k) => ({\n sql: `${safeKq(alias)}.${safeKq(k)} AS ${safeKq(k)}`,\n bindings: [],\n refs: [alias],\n }));\n const decoders = keys.map((k) => [k, handle.columnExpr(k)] as const);\n return { selects, decodeRows: (_, rows) => rows.map((row) => decodeRow(row, decoders)) };\n } else if (isExpr(select)) {\n // Scalar mode: one value per row, used by scalar/IN-list subqueries\n const fragment = asNode(select).toSql(ctx);\n const selects = [{ ...fragment, sql: `${fragment.sql} AS value` }];\n return { selects, decodeRows: (_, rows) => rows.map((row) => asNode(select).decode(row.value)) };\n } else if (isPlainSelect(select)) {\n // POJO mode\n const entries = Object.entries(select).map(([key, expr]) => [key, asExpr(expr, `select.${key}`)] as const);\n const selects = entries.map(([key, expr]) => {\n const fragment = expr.toSql(ctx);\n return { ...fragment, sql: `${fragment.sql} AS ${safeKq(key)}` };\n });\n return { selects, decodeRows: (_, rows) => rows.map((row) => decodeRow(row, entries)) };\n }\n return fail(`Unsupported select ${select}`);\n}\n\nfunction decodeRow(row: any, decoders: readonly (readonly [string, BaseExpr])[]): any {\n const result: any = {};\n for (const [key, expr] of decoders) {\n const value = row[key];\n result[key] = value === null || value === undefined ? null : expr.decode(value);\n }\n return result;\n}\n\nconst ORDER_BY_DIRECTIONS: string[] = [\n \"ASC\",\n \"DESC\",\n \"ASC NULLS FIRST\",\n \"ASC NULLS LAST\",\n \"DESC NULLS FIRST\",\n \"DESC NULLS LAST\",\n];\n\n/**\n * Generates ORDER BY SQL in entry order for keyed/expression arrays or a single keyed object.\n *\n * Expression entries retain bindings and alias references for join pruning. Undefined entries and\n * directions are omitted.\n */\nfunction orderBysToSql(q: AnyQuery, ctx: Ctx): SqlFragment[] {\n const { orderBy, select } = q;\n if (!orderBy) return [];\n const result: SqlFragment[] = [];\n for (const entry of Array.isArray(orderBy) ? orderBy : [orderBy]) {\n if (entry === undefined) continue;\n // A select key can also be named asc or desc, so distinguish entries by their values, not their keys.\n if (isExpr(entry.asc) || isExpr(entry.desc)) {\n result.push(orderByToSql(entry, ctx));\n continue;\n }\n for (const [key, dir] of Object.entries(entry)) {\n if (dir === undefined) continue;\n // The direction is interpolated into the SQL, so never trust it, i.e. it might be a request param\n if (!ORDER_BY_DIRECTIONS.includes(dir as string)) return fail(`Invalid orderBy direction '${dir}'`);\n // Entity mode orders by the alias's column; POJO/subquery selects order by the output column name\n if (isAlias(select)) {\n const column = (select as any)[key];\n if (!isExpr(column)) return fail(`orderBy key '${key}' is not a sortable field of the entity`);\n const fragment = asNode(column).toSql(ctx);\n result.push({ ...fragment, sql: `${fragment.sql} ${dir}` });\n } else {\n if (isExpr(select)) return fail(`the keyed orderBy form needs a POJO or entity select`);\n const keys = isSubqueryValue(select) ? select[subqueryBrand].columnKeys() : Object.keys(select as object);\n if (!keys.includes(key)) return fail(`orderBy key '${key}' is not a key of select`);\n result.push({ sql: `${safeKq(key)} ${dir}`, bindings: [], refs: [] });\n }\n }\n }\n return result;\n}\n\nfunction orderByToSql(o: QueryOrderBy, ctx: Ctx): SqlFragment {\n const [expr, direction] = \"asc\" in o && o.asc ? [o.asc, \"ASC\"] : [o.desc, \"DESC\"];\n const fragment = asExpr(expr, \"orderBy\").toSql(ctx);\n // `nulls` is interpolated into the SQL, so never trust it, i.e. it might cross an `any` boundary\n if (o.nulls !== undefined && o.nulls !== \"first\" && o.nulls !== \"last\") {\n return fail(`Invalid orderBy nulls '${o.nulls}'`);\n }\n const nulls = o.nulls ? ` NULLS ${o.nulls.toUpperCase()}` : \"\";\n return { ...fragment, sql: `${fragment.sql} ${direction}${nulls}` };\n}\n\n/**\n * Parses a user-facing condition (a single condition or an `{ and }`/`{ or }` filter) with the same\n * `ConditionBuilder` `em.find` uses, so `undefined` members drop out, empty groups drop, and\n * `pruneIfUndefined` applies unchanged. Deferred (expression-vs-expression) conditions are resolved\n * against the context first.\n */\nfunction conditionToSql(cond: ExpressionCondition | undefined, ctx: Ctx, topLevel: boolean): SqlFragment | undefined {\n if (cond === undefined || cond === null) return undefined;\n resolveDeferredConditions(cond, ctx);\n const filter: ExpressionFilter = isFilter(cond) ? cond : { and: [cond] };\n const cb = new ConditionBuilder();\n cb.maybeAddExpression(filter);\n const parsed = cb.toExpressionFilter();\n if (!parsed) return undefined;\n const where = buildWhereClause(parsed, topLevel);\n if (!where) return undefined;\n return { sql: where[0], bindings: where[1], refs: refsOf(parsed, ctx) };\n}\n\nfunction isFilter(cond: ExpressionCondition): cond is ExpressionFilter {\n return (\"and\" in cond && cond.and !== undefined) || (\"or\" in cond && cond.or !== undefined);\n}\n\n/** The aliases a parsed condition tree references, with physical CTI aliases credited to their source. */\nfunction refsOf(parsed: ParsedExpressionFilter, ctx: Ctx): string[] {\n return deepFindConditions(parsed, false)\n .flatMap((c) => (c.kind === \"column\" ? [c.alias] : c.kind === \"raw\" ? c.aliases : c.outerAliases))\n .map((a) => ctx.ctiAliases.get(a) ?? a);\n}\n\n/**\n * Pruning: em.find's paradigm, on a flat join list.\n *\n * A condition given `undefined` was already dropped by `ConditionBuilder`. Now a join that nothing\n * references anymore drops with it: a join is required if the source, a select, a surviving condition,\n * a group-by, an order-by, or another required join's ON references it, or if it is pinned with\n * `keep: true`. Marking follows ON dependencies transitively, exactly like `pruneUnusedJoins`'s\n * `DependencyTracker`.\n *\n * em.find's joins almost never filter rows by themselves, so pruning them is semantics-preserving. An\n * explicit `{ inner: b, on }` here does filter rows, so pruning it when unreferenced drops that filter;\n * that matches `{ books: { title: undefined } }` in em.find and is deliberate. `keep: true` pins it, and\n * a pure existence filter is better written as `a.id.in(query({ ... }))`, which is never `undefined`.\n */\nfunction pruneJoins(q: AnyQuery, from: ParsedSource, joins: ParsedJoin[], used: SqlFragment[]): ParsedJoin[] {\n if (q.pruneJoins === false) return joins;\n const deps = new Map<string, string[]>();\n for (const j of joins) {\n const refs = [...(j.userOn?.refs ?? []), ...j.source.refs].filter((r) => r !== j.source.alias);\n deps.set(j.source.alias, refs);\n }\n const required = new Set<string>();\n function markRequired(alias: string): void {\n if (required.has(alias)) return;\n required.add(alias);\n for (const dep of deps.get(alias) ?? []) markRequired(dep);\n }\n markRequired(from.alias);\n for (const r of used.flatMap((u) => u.refs)) markRequired(r);\n for (const j of joins) if (j.keep) markRequired(j.source.alias);\n return joins.filter((j) => required.has(j.source.alias));\n}\n\nfunction asExpr(value: unknown, where: string): BaseExpr {\n if (isExpr(value)) return value as any as BaseExpr;\n return fail(\n `${where} must be an expression, i.e. an alias column, aggregate, sql\\`...\\`, or query(...); got ${value}`,\n );\n}\n\nfunction joinFragmentParts(parts: SqlFragment[], sep: string): SqlFragment {\n return { sql: parts.map((p) => p.sql).join(sep), bindings: parts.flatMap((p) => p.bindings), refs: [] };\n}\n\nfunction isDefined<T>(value: T | undefined): value is T {\n return value !== undefined;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"query.cjs","names":["isAlias","isExpr","TemplateExpr","deferredCondition","RefExpr","AliasAssigner","fail","BaseExpr","safeKq","asNode","getAliasMgmt","JoinTableHandle","collectionJoin","m2mJoinTable","getAliasMetadata","kq","lazyExcludedSelects","kqStar","filterSoftDeletes","getBaseMeta","stiSubtypeFilter","ConditionBuilder","buildWhereClause","deepFindConditions"],"sources":["../src/query.ts"],"sourcesContent":["import { AliasAssigner } from \"./AliasAssigner.ts\";\nimport {\n type Alias,\n type AliasBrand,\n type AliasMgmt,\n JoinTableHandle,\n type M2mJoinTable,\n aliasMgmt,\n collectionJoin,\n getAliasMetadata,\n getAliasMgmt,\n isAlias,\n m2mJoinTable,\n} from \"./Aliases.ts\";\nimport { ConditionBuilder } from \"./ConditionBuilder.ts\";\nimport { buildWhereClause } from \"./drivers/buildUtils.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type ExpressionCondition, type ExpressionFilter } from \"./EntityFilter.ts\";\nimport { type EntityMetadata, getBaseMeta } from \"./EntityMetadata.ts\";\nimport {\n BaseExpr,\n type Expr,\n type ExprBrand,\n type ExprContext,\n type ExprLike,\n type InnerJoin,\n type LeftJoin,\n RefExpr,\n type SqlFragment,\n TemplateExpr,\n asNode,\n deferredCondition,\n exprBrand,\n isExpr,\n resolveDeferredConditions,\n} from \"./Expr.ts\";\nimport { kq, kqStar, safeKq } from \"./keywords.ts\";\nimport { deepFindConditions } from \"./QueryParser.pruning.ts\";\nimport {\n type ColumnCondition,\n type ParsedExpressionFilter,\n type ParsedFindQuery,\n addTablePerClassJoinsAndClassTag,\n filterSoftDeletes,\n lazyExcludedSelects,\n stiSubtypeFilter,\n} from \"./QueryParser.ts\";\nimport { fail } from \"./utils.ts\";\n\n/**\n * `em.query`: SQL-shaped queries as plain object literals.\n *\n * A query is data, a `Query<S, J>` POJO, `{ from, join, where, groupBy, having, select, orderBy, ... }`\n * in SQL evaluation order:\n *\n * const [a, b] = aliases(Author, Book);\n * const bookStats = query({ from: b, groupBy: [b.author], select: { authorId: b.author, n: b.id.count() } });\n * const rows = await em.query({\n * from: a,\n * join: [{ left: bookStats, on: bookStats.authorId.eq(a.id) }],\n * select: { name: a.firstName, n: bookStats.n },\n * orderBy: { n: \"DESC\" },\n * });\n * // rows: { name: string; n: number | null }[] (null because of the LEFT join)\n *\n * `em.query(pojo)` runs it. `select` decides the row type: a bare alias returns entities, a\n * `{ key: expr }` object returns typed POJOs, a bare subquery returns that subquery's rows.\n *\n * `query(pojo)` turns the *same* POJO into a value: a derived table with typed columns, a scalar\n * expression, or an entity list. It is the one non-POJO step, and the subquery analog of `alias(Author)`:\n * to reference a query's columns, the outer query needs *values* for them, and no POJO can manufacture\n * values keyed off its own `select` keys.\n *\n * `alias()`/`aliases()` and `query()` are the only free functions a query needs, plus the `sql` tagged\n * template as the escape hatch for SQL with no modeled shape. Everything else is in-DSL: join kinds and\n * sort directions are keyword keys (`{ left: b, on }`, `{ desc: x }`), SQL functions are methods on\n * expressions (`b.id.count()`, `b.title.max()`, `x.coalesce(0)`), conditions are methods\n * (`a.age.gte(18)`), and pruning is `undefined`: an `undefined` condition drops out, and a join nothing\n * references anymore drops with it (see \"Pruning\" below).\n *\n * User documentation: `docs/src/content/docs/features/queries-raw.md`.\n */\n\n// =====================================================================================================\n// Sources, joins, clauses\n// =====================================================================================================\n\nexport const subqueryBrand: unique symbol = Symbol(\"joist.subquery\");\nexport const entityQueryBrand: unique symbol = Symbol(\"joist.entityQuery\");\n\n/** Phantom type information carried by a table-shaped subquery. */\nexport interface SubqueryBrand<R, Name extends string> {\n readonly __row: R;\n readonly __name: Name;\n}\n\n/** Anything that can be a source or be joined: an entity alias or a table-shaped subquery. */\nexport type QuerySource =\n | { readonly [aliasMgmt]: AliasBrand<any, string> }\n | { readonly [subqueryBrand]: SubqueryBrand<any, string> };\n\n/**\n * A join entry (see `InnerJoin`/`LeftJoin` in `Expr.ts`): the expanded `{ inner: b, on }` form, or the\n * entry a relation join factory returns (`a.books.as(b)`); joins to a subquery are always the expanded\n * form, since a subquery has no FK metadata.\n */\nexport type QueryJoin = InnerJoin<QuerySource> | LeftJoin<QuerySource>;\nexport type QueryJoins = readonly (QueryJoin | undefined)[];\n\n/**\n * An expression order-by entry: the direction is the key and the expression is the value, unlike\n * the keyed form's field name and `\"ASC\" | \"DESC\"` value. `never` on the other key keeps an\n * entry to one direction, the same trick `ExpressionFilter` uses for `and`/`or`. `nulls` is\n * `NULLS FIRST/LAST`.\n *\n * When select keys are known, exclude them so a keyed sort cannot be silently ignored inside an\n * expression entry. An untyped `Query` has no known keys to exclude.\n */\nexport type QueryOrderBy<S = never> = (\n | { readonly asc: ExprLike<any>; readonly desc?: never }\n | { readonly desc: ExprLike<any>; readonly asc?: never }\n) & { readonly nulls?: \"first\" | \"last\" } & (string extends OrderByKey<S>\n ? unknown\n : { readonly [K in Exclude<OrderByKey<S>, \"asc\" | \"desc\" | \"nulls\">]?: never });\n\nexport type OrderByDirection =\n | \"ASC\"\n | \"DESC\"\n | \"ASC NULLS FIRST\"\n | \"ASC NULLS LAST\"\n | \"DESC NULLS FIRST\"\n | \"DESC NULLS LAST\";\n\n/**\n * A keyed `orderBy` entry, used alone or in an array, like `em.find`'s `orderBy: [{ firstName: \"ASC\" }]`.\n *\n * The keys are the keys of a POJO/subquery `select` (rendered as SQL output-column names, so ordering\n * by an aggregate does not repeat its expression), or the entity's sortable fields in entity mode.\n * An `undefined` direction prunes the entry, like any other condition. For expressions that are not\n * in `select`, mix in `{ asc: expr }` / `{ desc: expr }` entries in the array form.\n */\nexport type OrderByKeys<S> = S extends { readonly [aliasMgmt]: { readonly __entity: infer T } }\n ? T extends Entity\n ? { readonly [K in keyof Alias<T> as Alias<T>[K] extends ExprLike<any> ? K : never]?: OrderByDirection | undefined }\n : never\n : S extends { readonly [exprBrand]: any }\n ? never\n : { readonly [K in keyof S & string]?: OrderByDirection | undefined };\n\n/** All sortable keys across select variants, not just the keys shared by every variant. */\ntype OrderByKey<S> = S extends unknown ? keyof OrderByKeys<S> : never;\n\n/** The three select shapes: entity mode, single-expression mode (scalar/list subqueries), and POJO mode. */\nexport type QuerySelect = QuerySource | ExprLike<any> | Record<string, ExprLike<any>>;\n\n/**\n * Everything but the source, in SQL evaluation order: FROM/JOIN, WHERE, GROUP BY, HAVING, SELECT,\n * ORDER BY, LIMIT.\n *\n * `S` and `J` are generic so callers keep the literal shape of `select` and `join`; the defaults let\n * a standalone object use `satisfies Query` (or `satisfies Clauses` for a source-less fragment).\n */\nexport interface Clauses<S extends QuerySelect = QuerySelect, J extends QueryJoins = QueryJoins> {\n join?: J;\n /** An `{ and: [...] }` / `{ or: [...] }` filter, or a single bare condition, i.e. `where: a.age.gte(18)`. */\n where?: ExpressionCondition;\n groupBy?: readonly ExprLike<any>[];\n having?: ExpressionCondition;\n select: S;\n orderBy?: readonly (QueryOrderBy<S> | OrderByKeys<S> | undefined)[] | OrderByKeys<S>;\n limit?: number;\n offset?: number;\n distinct?: boolean;\n /** Defaults to true. `false` keeps every join, em.find's opt-out. */\n pruneJoins?: boolean;\n /**\n * Defaults to `\"exclude\"`, em.find's rule: a soft-deletable entity in `from` gains a\n * `deleted_at IS NULL` condition in WHERE, and a joined one gains it in its join's ON (so a LEFT\n * join nulls its columns out instead of dropping rows). `\"include\"` turns the injection off for\n * this query; subqueries read their own key.\n */\n softDeletes?: \"include\" | \"exclude\";\n}\n\n/** A whole query: `Clauses` plus its source. `query(q)` turns it into a value; `em.query(q)` runs it. */\nexport interface Query<S extends QuerySelect = QuerySelect, J extends QueryJoins = QueryJoins> extends Clauses<S, J> {\n from: QuerySource;\n}\n\n// =====================================================================================================\n// Result-row types\n// =====================================================================================================\n\n/** The type-level name of an alias or subquery, i.e. `\"Author\"` or `\"book_stats\"`. */\nexport type NameOf<A> = A extends { readonly [aliasMgmt]: { readonly __name: infer N } }\n ? N\n : A extends { readonly [subqueryBrand]: { readonly __name: infer N } }\n ? N\n : never;\n\n/** The names of every alias that was LEFT JOINed; `X` is a naked type parameter so this distributes. */\ntype LeftJoined<X> = X extends LeftJoin<infer A> ? NameOf<A> : never;\n\n/**\n * Asks: is this expression's source key among the LEFT-joined sources in this query's join list? If\n * yes, the value can be `null`, so `R` becomes `R | null`; if no, `R` is unchanged.\n *\n * I.e. `MaybeNull<number, \"book_stats\", [LeftJoin<typeof bookStats>]>` is `number | null`,\n * because `book_stats` is in `LeftJoined<J[number]>`; with an inner join it stays `number`.\n *\n * Source-less expressions (`Src` is `never`, i.e. `b.id.count()`) are never nullified. Untracked ones\n * (`Src` is `string`, i.e. a `sql.ref` on an unknown table) might come from any left-joined table,\n * so they are conservatively nullified whenever the query has a left join at all.\n *\n * `string` must never be a *table's* name: `Extract<\"Author\", string>` matches, so one left-joined\n * table named `string` would nullify every column in the query. That is why anonymous subqueries\n * share the literal sentinel `\"?\"` instead.\n */\nexport type MaybeNull<R, Src extends string, J extends QueryJoins> = string extends Src\n ? [LeftJoined<J[number]>] extends [never]\n ? R\n : R | null\n : [Extract<Src, LeftJoined<J[number]>>] extends [never]\n ? R\n : R | null;\n\n/**\n * The result row for a query with select `S` and joins `J`.\n *\n * - entity mode (`select: a`) is the entity\n * - subquery mode (`select: bookStats`) is the subquery's row, i.e. `select *`\n * - single expression (`select: b.id.count()`) is that expression's value, used by scalar subqueries\n * - POJO mode is a mapped type over the select keys, with left-join nullability applied\n */\nexport type QueryRow<S, J extends QueryJoins = []> = S extends { readonly [aliasMgmt]: { readonly __entity: infer T } }\n ? T\n : S extends { readonly [subqueryBrand]: { readonly __row: infer R } }\n ? R\n : S extends { readonly [exprBrand]: ExprBrand<infer R, infer Src> }\n ? MaybeNull<R, Src, J>\n : {\n [K in keyof S]: S[K] extends { readonly [exprBrand]: ExprBrand<infer R, infer Src> }\n ? MaybeNull<R, Src, J>\n : never;\n };\n\n// =====================================================================================================\n// `query()`: a query POJO becomes a typed table, scalar, or entity list\n// =====================================================================================================\n\n/**\n * A table-shaped query: one `Expr` per select key, each tagged with the table's name as its `Src`,\n * plus a brand carrying the row type. This is the direct analog of `Alias<T>`: `Alias<T>` maps entity\n * fields to expressions, `Subquery<Row, Name>` maps the inner query's select keys to expressions.\n */\nexport type Subquery<R, Name extends string> = {\n readonly [subqueryBrand]: SubqueryBrand<R, Name>;\n} & { readonly [K in keyof R]: Expr<R[K], Name> };\n\n/** An entity-mode query (`select: a`): runnable, but it has no columns to reference. */\nexport type EntityQuery<T extends Entity> = { readonly [entityQueryBrand]: { readonly __row: T } };\n\n/**\n * Rejects a `select` that a `: Query` annotation widened to the whole `QuerySelect` union.\n *\n * `satisfies Query` checks the shape but keeps the literal type of `select`, so `S` infers as\n * `{ name: Expr<string, \"Author\"> }`. A `: Query` annotation replaces that type with the annotation, so\n * `S` infers as `QuerySelect` itself, and without this guard `query(q)` returned a useless union with no\n * error at all.\n *\n * A widened `S` is the only kind of `S` the whole `QuerySelect` union is assignable to (a POJO, an\n * `Expr`, or an `Alias` never is), so `QuerySelect extends S` detects it, and intersecting the parameter\n * with `{ select: \"<message>\" }` fails the call on `select` with that message, for `query()` and\n * `em.query()` alike:\n *\n * const narrow = { from: a, select: { name: a.firstName } } satisfies Query;\n * query(narrow); // Subquery<{ name: string }, \"?\">\n *\n * const widened: Query = { from: a, select: { name: a.firstName } };\n * query(widened);\n * // error: Type 'QuerySelect' is not assignable to type\n * // '\"select was typed too generically; use `satisfies Query` instead of `: Query`\"'\n *\n * `S` also defaults to `never`, so a *missing* `select` is reported as \"Property 'select' is missing\"\n * against `Query<never, []>` instead of tripping this guard.\n */\nexport type NotWidened<S> = QuerySelect extends S\n ? { select: \"select was typed too generically; use `satisfies Query` instead of `: Query`\" }\n : unknown;\n\n/** What `query()` returns, by select shape: an entity list, a scalar/list subquery, or a derived table. */\nexport type QueryValue<S, J extends QueryJoins, Name extends string> = S extends {\n readonly [aliasMgmt]: { readonly __entity: infer T extends Entity };\n}\n ? EntityQuery<T>\n : S extends { readonly [exprBrand]: ExprBrand<infer R, any> }\n ? Expr<R | null, never>\n : Subquery<QueryRow<S, J>, Name>;\n\n/** The names of every alias in scope for a query: the source alias plus every joined alias. */\ntype JoinedName<X> = X extends { readonly inner: infer A }\n ? NameOf<A>\n : X extends { readonly left: infer A }\n ? NameOf<A>\n : never;\ntype InScope<F, J extends QueryJoins> = NameOf<F> | JoinedName<J[number]>;\n\n/**\n * Asks, for every column of a POJO select: is its source key among `from` + `join` at all? If no, the\n * query reads from a table it never joined, and that select key's type becomes an error message.\n *\n * Because `Expr` already carries `Src`, this is nearly free: for each select key, if `Src` is tracked\n * and any of its names is outside `InScope`, intersect that key's type with an error string, so the\n * caller sees `Type 'Expr<number, \"book_stats\">' is not assignable to type '... is not in from/join'`.\n * Untracked (`string`) and source-less (`never`) expressions always pass. Aliases with the same\n * type-level name (two bare `alias(Author)`, or two anonymous tables) cannot be told apart, so a miss\n * there goes unreported; the check never gives a false positive, only false negatives on collisions.\n *\n * `[S] extends [...]` keeps this non-distributive, and `never` is skipped outright: `query()` defaults\n * `S` to `never` when `select` is missing, and a distributive conditional over `never` would swallow the\n * whole parameter type.\n */\nexport type CheckScope<S, F, J extends QueryJoins> = [S] extends [never]\n ? unknown\n : // A source-shaped select (`select: a`, `select: bookStats`) must be the `from`: a joined source's\n // rows would need left-join nullability (and entity hydration) that source-shaped selects don't\n // model. Two same-named sources (unnamed aliases of one entity, anonymous subqueries) pass this\n // check and are caught at runtime instead.\n [S] extends [QuerySource]\n ? NameOf<S> extends NameOf<F>\n ? unknown\n : { select: `'${NameOf<S> & string}' is a joined source, not the from; select its columns individually` }\n : [S] extends [Record<string, ExprLike<any>>]\n ? {\n select: {\n [K in keyof S]: S[K] extends { readonly [exprBrand]: ExprBrand<any, infer Src> }\n ? string extends Src\n ? unknown\n : [Exclude<Src, InScope<F, J>>] extends [never]\n ? unknown\n : `alias '${Exclude<Src, InScope<F, J>> & string}' is not in from/join`\n : unknown;\n };\n }\n : unknown;\n\n/** The one argument type `query()` and `em.query()` share: a `Query` POJO plus its source, name, and checks. */\nexport type QueryArg<F extends QuerySource, S extends QuerySelect, J extends QueryJoins, Name extends string> = Query<\n S,\n J\n> & {\n from: F;\n as?: Name;\n} & CheckScope<S, F, J> &\n NotWidened<S>;\n\n/**\n * Turns a `Query` POJO into a value. The select shape decides which (`QueryValue`):\n *\n * - a single expression is a scalar subquery or an IN list (`Expr<R | null>`; a scalar subquery can\n * return no row, so use `.coalesce(0)` when the SQL guarantees a value, i.e. an ungrouped `count`)\n * - an entity alias is an entity list, runnable via `em.query`\n * - a POJO is a derived table whose columns are `Expr`s; it can be a source, be joined, or be run\n *\n * `as` is the SQL alias and the type-level identity, the same role the second argument of\n * `alias(Author, \"m\")` plays. Without it the SQL alias is generated, like `alias(Author)`, and all\n * anonymous tables share the type-level identity `\"?\"`: precise against every named alias, and\n * conservative (a left-joined anonymous table nullifies every anonymous table's columns) only among\n * themselves. This is the same collision two bare `alias(Author)` have.\n *\n * One signature, not three overloads: overloads wrapped every clauses-object mistake in \"No overload\n * matches this call\", hid `as` from completions, and cost 15-28% check time; the one thing they did\n * better, rejecting a `select` widened by a `: Query` annotation, `NotWidened` does with a clearer message.\n */\nexport function query<\n F extends QuerySource,\n S extends QuerySelect = never,\n J extends QueryJoins = [],\n Name extends string = \"?\",\n>(q: QueryArg<F, S, J, Name>): QueryValue<S, J, Name> {\n const handle = new SubqueryHandle(q as AnyQuery);\n const select = (q as AnyQuery).select;\n if (isAlias(select)) {\n return { [entityQueryBrand]: handle } as any;\n } else if (isExpr(select)) {\n return new SubqueryExpr(handle) as any;\n } else {\n return newSubqueryProxy(handle) as any;\n }\n}\n\n/**\n * Builds a SQL expression from a tagged template.\n *\n * For an Author alias `a` assigned the SQL alias `a1`:\n *\n * ```ts\n * sql`${a.age} * 2` // Expression: a1.age * 2\n * sql`${a.age.gte(18)}` // Condition: (a1.age >= ?), bindings [18]\n * sql`${\"Alice\"}` // Value: ?, bindings [\"Alice\"]\n *\n * // Selecting this expression keeps the join to Book b.\n * sql<number>`${b.order} * ${2}`\n *\n * // Reference an unmodeled column; it is untracked at the type level.\n * sql.ref<string>(a, \"ts_search\")\n * sql.condition`${sql.ref(a, \"ts_search\")} @@ plainto_tsquery(${term})`\n * ```\n */\nexport function sql<R = unknown>(strings: TemplateStringsArray, ...values: unknown[]): Expr<R, never> {\n return new TemplateExpr(strings, values) as any;\n}\n\n/** A raw condition for `where`, `having`, or `on`. */\nsql.condition = function condition(strings: TemplateStringsArray, ...values: unknown[]): ExpressionCondition {\n return deferredCondition((ctx) => new TemplateExpr(strings, values).toSql(ctx));\n};\n\n/** A column Joist does not model, on a source that is in the query. */\nsql.ref = function ref<R = unknown>(source: QuerySource, column: string): Expr<R, string> {\n return new RefExpr(handleOf(source), column) as any;\n};\n\n/**\n * Parses `arg` (a `Query` POJO or `query(...)` value) into a runnable `Plan`.\n *\n * `EntityManager.query` runs the plan; this module deliberately does not import `EntityManager` (see\n * `EntityHydrator`), so it parses and hands back `{ sql, bindings, decodeRows }` instead of executing.\n */\nexport function parseUserQuery(arg: unknown): Plan {\n return parseQuery(toQuery(arg), undefined, new AliasAssigner());\n}\n\n/**\n * The one `EntityManager` capability that row decoding needs, typed structurally.\n *\n * Importing `EntityManager.ts` here would complete an `EntityManager.ts` <-> `query.ts` declaration\n * cycle (`EntityManager.query` imports this module's types), which correlated with a tsc 7.0.2\n * incremental-build bug: after tsdown rewrites `build/`, `tsc --build` sporadically reports thousands\n * of phantom \"Module 'joist-orm' has no exported member ...\" errors and caches them in `.tsbuildinfo`.\n */\nexport interface EntityHydrator {\n hydrate(cstr: any, rows: readonly any[]): any[];\n}\n\nexport interface Plan {\n sql: string;\n bindings: any[];\n /** Aliases of enclosing queries this (sub)query referenced. */\n outerRefs: string[];\n decodeRows(em: EntityHydrator, rows: any[]): any[];\n}\n\n// =====================================================================================================\n// Runtime: handles, subquery expressions, the proxy\n// =====================================================================================================\n\ntype AnyQuery = Query<any, any> & { as?: string };\n\n/** The runtime identity of a `query(...)` value; `Ctx.aliasFor` keys on it, like an alias's `AliasMgmt`. */\nexport class SubqueryHandle {\n constructor(readonly q: AnyQuery) {}\n\n get name(): string | undefined {\n return this.q.as;\n }\n\n /** The select keys, for `select: <subquery>` and for reporting unknown columns. */\n columnKeys(): string[] {\n const { select } = this.q;\n if (isPlainSelect(select)) return Object.keys(select);\n if (isSubqueryValue(select)) return select[subqueryBrand].columnKeys();\n return fail(`A subquery with an entity or scalar select has no columns`);\n }\n\n /** The inner expression behind `key`, for its decoder/encoder. */\n columnExpr(key: string): BaseExpr {\n const { select } = this.q;\n if (isPlainSelect(select)) {\n return (select[key] as any as BaseExpr) ?? fail(`Subquery ${this.describe()} has no column ${key}`);\n } else if (isSubqueryValue(select)) {\n return select[subqueryBrand].columnExpr(key);\n }\n return fail(`Subquery ${this.describe()} has no columns`);\n }\n\n column(key: string): SubqueryColumnExpr {\n return new SubqueryColumnExpr(this, key, this.columnExpr(key));\n }\n\n describe(): string {\n return this.q.as ? `'${this.q.as}'` : \"(anonymous)\";\n }\n}\n\n/** A column of a joined/from'd subquery, i.e. `bookStats.bookCount`, which becomes `book_stats.\"bookCount\"`. */\nclass SubqueryColumnExpr extends BaseExpr {\n constructor(\n private handle: SubqueryHandle,\n private key: string,\n private inner: BaseExpr,\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const alias = ctx.aliasFor(this.handle);\n // safeKq for the alias too: a subquery's canonical alias is its user-provided `as` name\n return { sql: `${safeKq(alias)}.${safeKq(this.key)}`, bindings: [], refs: [alias] };\n }\n\n decode(value: unknown): unknown {\n return this.inner.decode(value);\n }\n\n encode(value: unknown): unknown {\n return this.inner.encode(value);\n }\n}\n\n/**\n * A scalar (or IN-list) subquery, i.e. `query({ from: b, where: [...], select: b.id.count() })`.\n *\n * It closes over the outer aliases it references, so correlation is free; those references are the\n * subquery's \"free\" aliases and count toward the outer query's join pruning.\n */\nclass SubqueryExpr extends BaseExpr {\n constructor(readonly handle: SubqueryHandle) {\n super();\n }\n\n get subquerySelect(): BaseExpr {\n return asNode(this.handle.q.select);\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const bare = this.toSqlBare(ctx);\n return { ...bare, sql: `(${bare.sql})` };\n }\n\n toSqlBare(ctx: ExprContext): SqlFragment {\n const parent = ctx instanceof Ctx ? ctx : fail(\"Subqueries need the query parser's context\");\n const plan = parseQuery(this.handle.q, parent, parent.assigner);\n return { sql: plan.sql, bindings: plan.bindings, refs: plan.outerRefs };\n }\n\n decode(value: unknown): unknown {\n return this.subquerySelect.decode(value);\n }\n\n encode(value: unknown): unknown {\n return this.subquerySelect.encode(value);\n }\n}\n\nfunction newSubqueryProxy(handle: SubqueryHandle): object {\n return new Proxy(\n {},\n {\n get(_, key) {\n if (key === subqueryBrand) return handle;\n if (typeof key === \"string\") return handle.column(key);\n return undefined;\n },\n has(_, key) {\n return key === subqueryBrand || (typeof key === \"string\" && handle.columnKeys().includes(key));\n },\n },\n );\n}\n\nfunction isSubqueryValue(value: unknown): value is { [subqueryBrand]: SubqueryHandle } {\n return typeof value === \"object\" && value !== null && subqueryBrand in value;\n}\n\nfunction isEntityQueryValue(value: unknown): value is { [entityQueryBrand]: SubqueryHandle } {\n return typeof value === \"object\" && value !== null && entityQueryBrand in value;\n}\n\nfunction isPlainSelect(select: unknown): select is Record<string, ExprLike<any>> {\n return (\n typeof select === \"object\" && select !== null && !isAlias(select) && !isExpr(select) && !isSubqueryValue(select)\n );\n}\n\n/** Returns the runtime identity of a source: an alias's `AliasMgmt` or a subquery's handle. */\nfunction handleOf(source: unknown): AliasMgmt | SubqueryHandle {\n if (isAlias(source)) return getAliasMgmt(source);\n if (isSubqueryValue(source)) return source[subqueryBrand];\n return fail(`Expected an alias or a query(...) value, got ${source}`);\n}\n\n// =====================================================================================================\n// Runtime: parse -> prune -> SQL -> decode\n// =====================================================================================================\n\nfunction toQuery(arg: unknown): AnyQuery {\n if (isSubqueryValue(arg)) return arg[subqueryBrand].q;\n if (isEntityQueryValue(arg)) return arg[entityQueryBrand].q;\n if (arg instanceof SubqueryExpr) return arg.handle.q;\n if (typeof arg === \"object\" && arg !== null && \"from\" in arg && \"select\" in arg) return arg as AnyQuery;\n return fail(`em.query expects a { from, select, ... } object or a query(...) value`);\n}\n\n/**\n * What an expression needs from the query it is generating SQL for.\n *\n * Each (sub)query gets its own `Ctx`; a lookup that misses locally walks up to the enclosing query and\n * records the hit in `outerRefs`, which is how a correlated subquery reports the outer aliases it\n * depends on (the way `ExistsCondition.outerAliases` does), so join pruning keeps them.\n */\nclass Ctx implements ExprContext {\n private aliases = new Map<object, string>();\n readonly outerRefs = new Set<string>();\n /** Physical CTI table aliases (`sp_b0`) to their source alias (`sp`), shared across the whole parse. */\n readonly ctiAliases: Map<string, string>;\n\n constructor(\n readonly assigner: AliasAssigner,\n private parent: Ctx | undefined,\n ) {\n this.ctiAliases = parent?.ctiAliases ?? new Map();\n }\n\n register(handle: object, alias: string): void {\n this.aliases.set(handle, alias);\n }\n\n aliasFor(handle: object): string {\n const local = this.aliases.get(handle);\n if (local) return local;\n if (this.parent) {\n const outer = this.parent.aliasFor(handle);\n this.outerRefs.add(outer);\n return outer;\n }\n return fail(`${describeHandle(handle)} is not in this query's from/join`);\n }\n\n conditionToSql(cond: ExpressionCondition): SqlFragment | undefined {\n // Inside another expression (i.e. a `sql` template), keep `a OR b` grouped\n return conditionToSql(cond, this, false);\n }\n}\n\nfunction describeHandle(handle: object): string {\n if (handle instanceof SubqueryHandle) return `Subquery ${handle.describe()}`;\n if (handle instanceof JoinTableHandle) return `Join table ${handle.joinTableName}`;\n if (\"tableName\" in handle) return `Alias for ${(handle as AliasMgmt).tableName}`;\n return \"Alias\";\n}\n\ninterface ParsedSource {\n handle: AliasMgmt | SubqueryHandle | JoinTableHandle;\n alias: string;\n /** `table AS alias` or `(SELECT ...) AS alias`. */\n sql: string;\n bindings: any[];\n /** Outer aliases a derived table references; PG rejects those without LATERAL, but pruning should still see them. */\n refs: string[];\n /** CTI base/sub-table joins that travel with an entity alias. */\n extraJoins: string[];\n /** Entity-mode selects, i.e. `a.*` plus CTI columns and the `__class` tag. */\n entitySelects: string[];\n meta: EntityMetadata | undefined;\n}\n\ninterface ParsedJoin {\n kind: \"inner\" | \"left\";\n source: ParsedSource;\n /** The user's ON alone; `undefined` means it pruned away entirely, an error if the join is kept. */\n userOn: SqlFragment | undefined;\n /** The ON to emit: the user's ON plus any injected soft-delete/STI-discriminator conditions. */\n fullOn: SqlFragment | undefined;\n keep: boolean;\n}\n\n/**\n * Parses one `Query` POJO into SQL, recursively for subqueries.\n *\n * 1. Register every source's runtime identity with its SQL alias in this parse's context.\n * 2. Generate SQL for sources, selects, conditions, group-bys, and order-bys against the context; every fragment\n * reports the aliases it references.\n * 3. Prune: drop joins nothing references (see below), then reject a kept join whose ON collapsed.\n * 4. Assemble the SQL from the kept fragments, so pruned bindings disappear with their SQL.\n */\nfunction parseQuery(q: AnyQuery, parent: Ctx | undefined, assigner: AliasAssigner): Plan {\n const ctx = new Ctx(assigner, parent);\n const selectedAlias = isAlias(q.select) ? getAliasMgmt(q.select) : undefined;\n const joinEntries = [...(q.join ?? [])].filter(isDefined);\n\n // 1. Register every source before generating SQL, so conditions can resolve their aliases.\n const parseFrom = registerSource(q.from, ctx, assigner, handleOf(q.from) === selectedAlias);\n const pendingJoins = joinEntries.flatMap((j) => {\n const kind = \"inner\" in j && j.inner ? (\"inner\" as const) : (\"left\" as const);\n const alias = kind === \"inner\" ? j.inner : j.left;\n const keep = j.keep ?? false;\n // Only collection sugar joins (o2m/m2m) filter soft-deletes, em.find's relation semantics:\n // references (m2o/o2o/poly) resolve soft-deleted entities, and explicit joins are the user's own\n const softDeletes = (j as any)[collectionJoin] === true;\n const target = { kind, keep, on: j.on, softDeletes, parseSource: registerSource(alias, ctx, assigner, false) };\n // A sugar m2m join (`a.tags.as(t)`) carries a hidden join-table join; emit it first, with the same kind\n const m2m: M2mJoinTable | undefined = (j as any)[m2mJoinTable];\n if (!m2m) return [target];\n return [\n { kind, keep, on: m2m.on, softDeletes: false, parseSource: registerJoinTable(m2m.handle, ctx, assigner) },\n target,\n ];\n });\n\n // 2. Generate SQL.\n const softDeletes = q.softDeletes ?? \"exclude\";\n const from = parseFrom();\n const joins: ParsedJoin[] = pendingJoins.map((j) => {\n const source = j.parseSource();\n // `userOn` is the user's ON alone, so the collapsed-ON check below is not fooled by injections\n const userOn = conditionToSql(j.on, ctx, true);\n const injected = injectedConditions(source, j.softDeletes ? softDeletes : \"include\");\n const fullOn = userOn && injected.length > 0 ? conditionToSql({ and: [j.on, ...injected] }, ctx, true) : userOn;\n return { kind: j.kind, keep: j.keep, source, userOn, fullOn };\n });\n const { selects, decodeRows } = selectsToSql(q, ctx, from);\n const fromInjected = injectedConditions(from, softDeletes);\n const where = conditionToSql(fromInjected.length > 0 ? { and: [q.where, ...fromInjected] } : q.where, ctx, true);\n const having = conditionToSql(q.having, ctx, true);\n const groupBys = (q.groupBy ?? []).map((g) => asExpr(g, \"groupBy\").toSql(ctx));\n const orderBys = orderBysToSql(q, ctx);\n\n // 3. Prune.\n const kept = pruneJoins(q, from, joins, [...selects, ...groupBys, ...orderBys, where, having].filter(isDefined));\n // Joins emit in declaration order, so an ON may only reference sources declared before it; a forward\n // reference would reach PG as invalid SQL (\"missing FROM-clause entry\"). Reordering is not offered:\n // it is not semantics-preserving once INNER and LEFT joins mix, and the caller's fix is trivial.\n const laterAliases = new Set(kept.map((j) => j.source.alias));\n for (const j of kept) {\n if (!j.userOn) {\n fail(\n `Join ${describeHandle(j.source.handle)} has no ON condition left (they all pruned), but the query still references it`,\n );\n }\n laterAliases.delete(j.source.alias);\n const forward = j.fullOn!.refs.find((r) => laterAliases.has(r));\n if (forward) {\n fail(\n `Join ${describeHandle(j.source.handle)} references '${forward}', which is joined later; move that join earlier in the join array`,\n );\n }\n }\n\n // 4. Assemble.\n const out: SqlFragment[] = [];\n out.push({ sql: `SELECT ${q.distinct ? \"DISTINCT \" : \"\"}`, bindings: [], refs: [] });\n out.push(joinFragmentParts(selects, \", \"));\n out.push({ sql: ` FROM ${from.sql}`, bindings: from.bindings, refs: [] });\n for (const extra of from.extraJoins) out.push({ sql: ` ${extra}`, bindings: [], refs: [] });\n for (const j of kept) {\n const keyword = j.kind === \"inner\" ? \"JOIN\" : \"LEFT OUTER JOIN\";\n // A CTI subtype's physical base-table joins go *inside* a parenthesized join item: the ON can\n // reference the base alias (i.e. `sp.id` renders as `sp_b0.id`), so the subtree must join first\n const source = j.source.extraJoins.length > 0 ? `(${j.source.sql} ${j.source.extraJoins.join(\" \")})` : j.source.sql;\n out.push({\n sql: ` ${keyword} ${source} ON ${j.fullOn!.sql}`,\n bindings: [...j.source.bindings, ...j.fullOn!.bindings],\n refs: [],\n });\n }\n if (where) out.push({ sql: ` WHERE ${where.sql}`, bindings: where.bindings, refs: [] });\n if (groupBys.length > 0)\n out.push({ ...joinFragmentParts(groupBys, \", \"), sql: ` GROUP BY ${groupBys.map((g) => g.sql).join(\", \")}` });\n if (having) out.push({ sql: ` HAVING ${having.sql}`, bindings: having.bindings, refs: [] });\n if (orderBys.length > 0)\n out.push({ ...joinFragmentParts(orderBys, \", \"), sql: ` ORDER BY ${orderBys.map((o) => o.sql).join(\", \")}` });\n if (q.limit !== undefined) out.push({ sql: ` LIMIT ?`, bindings: [q.limit], refs: [] });\n if (q.offset !== undefined) out.push({ sql: ` OFFSET ?`, bindings: [q.offset], refs: [] });\n\n return {\n sql: out.map((o) => o.sql).join(\"\"),\n bindings: out.flatMap((o) => o.bindings),\n outerRefs: [...ctx.outerRefs],\n decodeRows,\n };\n}\n\n/**\n * Assigns a SQL alias to a source and returns a function that parses it after all sources are registered.\n *\n * Conditions resolve source identities through the context when their SQL is generated. CTI entities\n * get their base/sub-table joins from `addTablePerClassJoinsAndClassTag`, and the entity-mode `select`\n * gets that helper's selects too.\n */\nfunction registerSource(source: unknown, ctx: Ctx, assigner: AliasAssigner, isPrimary: boolean): () => ParsedSource {\n const handle = handleOf(source);\n if (handle instanceof SubqueryHandle) {\n const alias = handle.name ? assigner.getLiteralAlias(handle.name) : assigner.getLiteralAlias(\"sq\");\n ctx.register(handle, alias);\n return () => {\n const inner = parseQuery(handle.q, ctx, assigner);\n return {\n handle,\n alias,\n sql: `(${inner.sql}) AS ${safeKq(alias)}`,\n bindings: inner.bindings,\n refs: inner.outerRefs,\n extraJoins: [],\n entitySelects: [],\n meta: undefined,\n };\n };\n } else {\n const meta = getAliasMetadata(source as any);\n const alias = assigner.getAlias(meta.tableName);\n ctx.register(handle, alias);\n // Record the physical CTI table aliases this source emits (i.e. `sp_b0`), so `refsOf` can credit\n // their refs to this alias exactly; a user subquery named `book_b0` must not be mistaken for one\n if (meta.inheritanceType === \"cti\") {\n meta.baseTypes.forEach((_, i) => ctx.ctiAliases.set(`${alias}_b${i}`, alias));\n if (isPrimary) meta.subTypes.forEach((_, i) => ctx.ctiAliases.set(`${alias}_s${i}`, alias));\n }\n return () => {\n const cti: ParsedFindQuery = { selects: [], tables: [], orderBys: [] };\n addTablePerClassJoinsAndClassTag(cti, meta, alias, isPrimary);\n const extraJoins = cti.tables.map((t) => {\n if (t.join !== \"outer\") return fail(`Unexpected ${t.join} join for CTI`);\n return `LEFT OUTER JOIN ${kq(t.table)} AS ${kq(t.alias)} ON ${t.col1} = ${t.col2}`;\n });\n // Entity mode starts with the primary table's own columns (excluding lazy ones, like em.find)\n // and *appends* the CTI base/sub-table columns and the __class tag; the CTI selects alone would\n // drop the selected table's own fields, i.e. a Publisher would hydrate with an undefined name\n const primarySelects = meta.hasLazyColumns ? lazyExcludedSelects(meta, alias) : [kqStar(alias)];\n const entitySelects = [...primarySelects, ...(cti.selects as string[])];\n return {\n handle,\n alias,\n sql: `${kq(meta.tableName)} AS ${kq(alias)}`,\n bindings: [],\n refs: [],\n extraJoins,\n entitySelects,\n meta,\n };\n };\n }\n}\n\n/**\n * em.find's per-source injections: `alias.deleted_at IS NULL` for a soft-deletable entity (CTI\n * subtypes are skipped, like em.find; see `filterSoftDeletes`), and the `type_id = X` discriminator\n * for an STI subtype, so `from: alias(TaskNew)` only sees (and a joined subtype only matches)\n * TaskNew rows.\n *\n * The conditions go into the from's WHERE or the join's ON, and never keep an otherwise unreferenced\n * join alive, which is what `pruneable: true` means on em.find's side.\n */\nfunction injectedConditions(source: ParsedSource, softDeletes: \"include\" | \"exclude\"): ColumnCondition[] {\n const { meta } = source;\n if (!meta) return [];\n const conditions: ColumnCondition[] = [];\n if (filterSoftDeletes(meta, softDeletes)) {\n const field = meta.allFields[getBaseMeta(meta).timestampFields!.deletedAt!];\n const column = field.serde!.columns[0];\n conditions.push({\n kind: \"column\",\n alias: `${source.alias}${field.aliasSuffix}`,\n column: column.columnName,\n dbType: column.dbType,\n cond: { kind: \"is-null\" },\n pruneable: true,\n });\n }\n const sti = stiSubtypeFilter(meta, source.alias);\n if (sti) conditions.push(sti);\n return conditions;\n}\n\n/** Registers a sugar m2m join table, i.e. `authors_to_tags`: a raw table with no entity metadata. */\nfunction registerJoinTable(handle: JoinTableHandle, ctx: Ctx, assigner: AliasAssigner): () => ParsedSource {\n const alias = assigner.getAlias(handle.joinTableName);\n ctx.register(handle, alias);\n return () => ({\n handle,\n alias,\n sql: `${kq(handle.joinTableName)} AS ${kq(alias)}`,\n bindings: [],\n refs: [],\n extraJoins: [],\n entitySelects: [],\n meta: undefined,\n });\n}\n\n/** Generates the `select` clause SQL and returns how to decode the resulting rows. */\nfunction selectsToSql(\n q: AnyQuery,\n ctx: Ctx,\n from: ParsedSource,\n): { selects: SqlFragment[]; decodeRows: Plan[\"decodeRows\"] } {\n const { select } = q;\n if (isAlias(select)) {\n // Entity mode: `a.*` (plus CTI columns), hydrated through the identity map. Only the from is\n // hydratable: a joined alias would need null-row skipping and left-join nullability (see TODO.md)\n if (from.handle !== getAliasMgmt(select)) {\n fail(\"Selecting a joined alias is not supported yet; select the from alias, or select its columns individually\");\n }\n const alias = ctx.aliasFor(getAliasMgmt(select));\n const meta = getAliasMetadata(select);\n const selects = from.entitySelects.map((s) => ({ sql: s, bindings: [], refs: [alias] }));\n return { selects, decodeRows: (em, rows) => em.hydrate(meta.cstr as any, rows) };\n } else if (isSubqueryValue(select)) {\n // `select: <subquery>` is `select *` for that table; like entity mode, only for the from, since a\n // left-joined subquery's unmatched rows would decode null fields the row type calls non-null\n const handle = select[subqueryBrand];\n if (from.handle !== handle) {\n fail(\n \"Selecting a joined subquery is not supported; select the from subquery, or select its columns individually\",\n );\n }\n const alias = ctx.aliasFor(handle);\n const keys = handle.columnKeys();\n const selects = keys.map((k) => ({\n sql: `${safeKq(alias)}.${safeKq(k)} AS ${safeKq(k)}`,\n bindings: [],\n refs: [alias],\n }));\n const decoders = keys.map((k) => [k, handle.columnExpr(k)] as const);\n return { selects, decodeRows: (_, rows) => rows.map((row) => decodeRow(row, decoders)) };\n } else if (isExpr(select)) {\n // Scalar mode: one value per row, used by scalar/IN-list subqueries\n const fragment = asNode(select).toSql(ctx);\n const selects = [{ ...fragment, sql: `${fragment.sql} AS value` }];\n return { selects, decodeRows: (_, rows) => rows.map((row) => asNode(select).decode(row.value)) };\n } else if (isPlainSelect(select)) {\n // POJO mode\n const entries = Object.entries(select).map(([key, expr]) => [key, asExpr(expr, `select.${key}`)] as const);\n const selects = entries.map(([key, expr]) => {\n const fragment = expr.toSql(ctx);\n return { ...fragment, sql: `${fragment.sql} AS ${safeKq(key)}` };\n });\n return { selects, decodeRows: (_, rows) => rows.map((row) => decodeRow(row, entries)) };\n }\n return fail(`Unsupported select ${select}`);\n}\n\nfunction decodeRow(row: any, decoders: readonly (readonly [string, BaseExpr])[]): any {\n const result: any = {};\n for (const [key, expr] of decoders) {\n const value = row[key];\n result[key] = value === null || value === undefined ? null : expr.decode(value);\n }\n return result;\n}\n\nconst ORDER_BY_DIRECTIONS: string[] = [\n \"ASC\",\n \"DESC\",\n \"ASC NULLS FIRST\",\n \"ASC NULLS LAST\",\n \"DESC NULLS FIRST\",\n \"DESC NULLS LAST\",\n];\n\n/**\n * Generates ORDER BY SQL in entry order for keyed/expression arrays or a single keyed object.\n *\n * Expression entries retain bindings and alias references for join pruning. Undefined entries and\n * directions are omitted.\n */\nfunction orderBysToSql(q: AnyQuery, ctx: Ctx): SqlFragment[] {\n const { orderBy, select } = q;\n if (!orderBy) return [];\n const result: SqlFragment[] = [];\n for (const entry of Array.isArray(orderBy) ? orderBy : [orderBy]) {\n if (entry === undefined) continue;\n // A select key can also be named asc or desc, so distinguish entries by their values, not their keys.\n if (isExpr(entry.asc) || isExpr(entry.desc)) {\n result.push(orderByToSql(entry, ctx));\n continue;\n }\n for (const [key, dir] of Object.entries(entry)) {\n if (dir === undefined) continue;\n // The direction is interpolated into the SQL, so never trust it, i.e. it might be a request param\n if (!ORDER_BY_DIRECTIONS.includes(dir as string)) return fail(`Invalid orderBy direction '${dir}'`);\n // Entity mode orders by the alias's column; POJO/subquery selects order by the output column name\n if (isAlias(select)) {\n const column = (select as any)[key];\n if (!isExpr(column)) return fail(`orderBy key '${key}' is not a sortable field of the entity`);\n const fragment = asNode(column).toSql(ctx);\n result.push({ ...fragment, sql: `${fragment.sql} ${dir}` });\n } else {\n if (isExpr(select)) return fail(`the keyed orderBy form needs a POJO or entity select`);\n const keys = isSubqueryValue(select) ? select[subqueryBrand].columnKeys() : Object.keys(select as object);\n if (!keys.includes(key)) return fail(`orderBy key '${key}' is not a key of select`);\n result.push({ sql: `${safeKq(key)} ${dir}`, bindings: [], refs: [] });\n }\n }\n }\n return result;\n}\n\nfunction orderByToSql(o: QueryOrderBy, ctx: Ctx): SqlFragment {\n const [expr, direction] = \"asc\" in o && o.asc ? [o.asc, \"ASC\"] : [o.desc, \"DESC\"];\n const fragment = asExpr(expr, \"orderBy\").toSql(ctx);\n // `nulls` is interpolated into the SQL, so never trust it, i.e. it might cross an `any` boundary\n if (o.nulls !== undefined && o.nulls !== \"first\" && o.nulls !== \"last\") {\n return fail(`Invalid orderBy nulls '${o.nulls}'`);\n }\n const nulls = o.nulls ? ` NULLS ${o.nulls.toUpperCase()}` : \"\";\n return { ...fragment, sql: `${fragment.sql} ${direction}${nulls}` };\n}\n\n/**\n * Parses a user-facing condition (a single condition or an `{ and }`/`{ or }` filter) with the same\n * `ConditionBuilder` `em.find` uses, so `undefined` members drop out, empty groups drop, and\n * `pruneIfUndefined` applies unchanged. Deferred (expression-vs-expression) conditions are resolved\n * against the context first.\n */\nfunction conditionToSql(cond: ExpressionCondition | undefined, ctx: Ctx, topLevel: boolean): SqlFragment | undefined {\n if (cond === undefined || cond === null) return undefined;\n resolveDeferredConditions(cond, ctx);\n const filter: ExpressionFilter = isFilter(cond) ? cond : { and: [cond] };\n const cb = new ConditionBuilder();\n cb.maybeAddExpression(filter);\n const parsed = cb.toExpressionFilter();\n if (!parsed) return undefined;\n const where = buildWhereClause(parsed, topLevel);\n if (!where) return undefined;\n return { sql: where[0], bindings: where[1], refs: refsOf(parsed, ctx) };\n}\n\nfunction isFilter(cond: ExpressionCondition): cond is ExpressionFilter {\n return (\"and\" in cond && cond.and !== undefined) || (\"or\" in cond && cond.or !== undefined);\n}\n\n/** The aliases a parsed condition tree references, with physical CTI aliases credited to their source. */\nfunction refsOf(parsed: ParsedExpressionFilter, ctx: Ctx): string[] {\n return deepFindConditions(parsed, false)\n .flatMap((c) => (c.kind === \"column\" ? [c.alias] : c.kind === \"raw\" ? c.aliases : c.outerAliases))\n .map((a) => ctx.ctiAliases.get(a) ?? a);\n}\n\n/**\n * Pruning: em.find's paradigm, on a flat join list.\n *\n * A condition given `undefined` was already dropped by `ConditionBuilder`. Now a join that nothing\n * references anymore drops with it: a join is required if the source, a select, a surviving condition,\n * a group-by, an order-by, or another required join's ON references it, or if it is pinned with\n * `keep: true`. Marking follows ON dependencies transitively, exactly like `pruneUnusedJoins`'s\n * `DependencyTracker`.\n *\n * em.find's joins almost never filter rows by themselves, so pruning them is semantics-preserving. An\n * explicit `{ inner: b, on }` here does filter rows, so pruning it when unreferenced drops that filter;\n * that matches `{ books: { title: undefined } }` in em.find and is deliberate. `keep: true` pins it, and\n * a pure existence filter is better written as `a.id.in(query({ ... }))`, which is never `undefined`.\n */\nfunction pruneJoins(q: AnyQuery, from: ParsedSource, joins: ParsedJoin[], used: SqlFragment[]): ParsedJoin[] {\n if (q.pruneJoins === false) return joins;\n const deps = new Map<string, string[]>();\n for (const j of joins) {\n const refs = [...(j.userOn?.refs ?? []), ...j.source.refs].filter((r) => r !== j.source.alias);\n deps.set(j.source.alias, refs);\n }\n const required = new Set<string>();\n function markRequired(alias: string): void {\n if (required.has(alias)) return;\n required.add(alias);\n for (const dep of deps.get(alias) ?? []) markRequired(dep);\n }\n markRequired(from.alias);\n for (const r of used.flatMap((u) => u.refs)) markRequired(r);\n for (const j of joins) if (j.keep) markRequired(j.source.alias);\n return joins.filter((j) => required.has(j.source.alias));\n}\n\nfunction asExpr(value: unknown, where: string): BaseExpr {\n if (isExpr(value)) return value as any as BaseExpr;\n return fail(\n `${where} must be an expression, i.e. an alias column, aggregate, sql\\`...\\`, or query(...); got ${value}`,\n );\n}\n\nfunction joinFragmentParts(parts: SqlFragment[], sep: string): SqlFragment {\n return { sql: parts.map((p) => p.sql).join(sep), bindings: parts.flatMap((p) => p.bindings), refs: [] };\n}\n\nfunction isDefined<T>(value: T | undefined): value is T {\n return value !== undefined;\n}\n"],"mappings":"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"}
|
package/build/query.d.cts
CHANGED
|
@@ -278,15 +278,22 @@ type QueryArg<F extends QuerySource, S extends QuerySelect, J extends QueryJoins
|
|
|
278
278
|
*/
|
|
279
279
|
declare function query<F extends QuerySource, S extends QuerySelect = never, J extends QueryJoins = [], Name extends string = "?">(q: QueryArg<F, S, J, Name>): QueryValue<S, J, Name>;
|
|
280
280
|
/**
|
|
281
|
-
*
|
|
281
|
+
* Builds a SQL expression from a tagged template.
|
|
282
282
|
*
|
|
283
|
-
*
|
|
284
|
-
* and every other value becomes a `?` binding, so users never write `"a.age * 2"` and hope `a` is the SQL
|
|
285
|
-
* alias, and referenced aliases still count for join pruning.
|
|
283
|
+
* For an Author alias `a` assigned the SQL alias `a1`:
|
|
286
284
|
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
285
|
+
* ```ts
|
|
286
|
+
* sql`${a.age} * 2` // Expression: a1.age * 2
|
|
287
|
+
* sql`${a.age.gte(18)}` // Condition: (a1.age >= ?), bindings [18]
|
|
288
|
+
* sql`${"Alice"}` // Value: ?, bindings ["Alice"]
|
|
289
|
+
*
|
|
290
|
+
* // Selecting this expression keeps the join to Book b.
|
|
291
|
+
* sql<number>`${b.order} * ${2}`
|
|
292
|
+
*
|
|
293
|
+
* // Reference an unmodeled column; it is untracked at the type level.
|
|
294
|
+
* sql.ref<string>(a, "ts_search")
|
|
295
|
+
* sql.condition`${sql.ref(a, "ts_search")} @@ plainto_tsquery(${term})`
|
|
296
|
+
* ```
|
|
290
297
|
*/
|
|
291
298
|
declare function sql<R = unknown>(strings: TemplateStringsArray, ...values: unknown[]): Expr<R, never>;
|
|
292
299
|
declare namespace sql {
|
package/build/query.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.cts","names":[],"sources":["../src/query.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAuFa;cACA;;UAGI,cAAc,GAAG;WACvB,OAAO;WACP,QAAQ;;;KAIP;YACI,YAAY;;YACZ,gBAAgB;;;;;;;KAOpB,YAAY,UAAU,eAAe,SAAS;KAC9C,uBAAuB;;;;;;;;;;KAWvB,aAAa;WACV,KAAK;WAAwB;;WAC7B,MAAM;WAAwB;;WAC9B;oBAA6C,WAAW,2BAErD,KAAK,QAAQ,WAAW;KAE9B;;;;;;;;;KAgBA,YAAY,KAAK;YAAsB;aAAuB,gBAAgB;;IACtF,UAAU,qBACI,WAAW,MAAM,MAAM,MAAM,GAAG,WAAW,gBAAgB,aAAa,0CAEtF;YAAsB;wBAER,WAAW,cAAc;;KAGtC,WAAW,KAAK,0BAA0B,YAAY;;KAG/C,cAAc,cAAc,gBAAgB,eAAe;;;;;;;;UAStD,QAAQ,UAAU,cAAc,aAAa,UAAU,aAAa;EACnF,OAAO;;EAEP,QAAQ;EACR,mBAAmB;EACnB,SAAS;EACT,QAAQ;EACR,oBAAoB,aAAa,KAAK,YAAY,oBAAoB,YAAY;EAClF;EACA;EACA;;EAEA;;;;;;;EAOA;;;UAIe,MAAM,UAAU,cAAc,aAAa,UAAU,aAAa,oBAAoB,QAAQ,GAAG;EAChH,MAAM;;;KAQI,OAAO,KAAK;YAAsB;aAAuB,cAAc;;IAC/E,IACA;YAAsB;aAA2B,cAAc;;IAC7D;;KAID,WAAW,KAAK,UAAU,eAAe,KAAK,OAAO;;;;;;;;;;;;;;;;KAiB9C,UAAU,GAAG,oBAAoB,UAAU,6BAA6B,OAC/E,WAAW,8BACV,IACA,YACD,QAAQ,KAAK,WAAW,+BACvB,IACA;;;;;;;;;KAUM,SAAS,GAAG,UAAU,mBAAmB;YAAsB;aAAuB,gBAAgB;;IAC9G,IACA;YAAsB;aAA2B,aAAa;;IAC5D,IACA;YAAsB,YAAY,gBAAgB,SAAS;IACzD,UAAU,GAAG,KAAK,QAEf,WAAW,IAAI,EAAE;YAAuB,YAAY,gBAAgB,SAAS;IAC1E,UAAU,GAAG,KAAK;;;;;;KAapB,SAAS,GAAG;YACZ,gBAAgB,cAAc,GAAG;gBAC7B,WAAW,IAAI,KAAK,EAAE,IAAI;;KAG9B,YAAY,UAAU;YAAsB;aAA8B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0BjF,WAAW,KAAK,oBAAoB;EAC1C;;;KAIM,WAAW,GAAG,UAAU,YAAY,uBAAuB;YAC3D;aAAuB,gBAAgB,UAAU;;IAEzD,YAAY,KACZ;YAAsB,YAAY,gBAAgB;IAChD,KAAK,mBACL,SAAS,SAAS,GAAG,IAAI;;KAG1B,WAAW,KAAK;WAAqB,aAAa;IACnD,OAAO,KACP;WAAqB,YAAY;IAC/B,OAAO;KAER,QAAQ,GAAG,UAAU,cAAc,OAAO,KAAK,WAAW;;;;;;;;;;;;;;;;KAiBnD,WAAW,GAAG,GAAG,UAAU,eAAe,gCAMjD,YAAY,eACX,OAAO,WAAW,OAAO;EAErB,YAAY,OAAO;KACtB,YAAY,eAAe;EAExB,WACG,WAAW,IAAI,EAAE;cAAuB,YAAY,qBAAqB;qBACvD,iBAEZ,QAAQ,KAAK,QAAQ,GAAG,2CAEb,QAAQ,KAAK,QAAQ,GAAG;;;KAO1C,SAAS,UAAU,aAAa,UAAU,aAAa,UAAU,YAAY,uBAAuB,MAC9G,GACA;EAEA,MAAM;EACN,KAAK;IACH,WAAW,GAAG,GAAG,KACnB,WAAW;;;;;;;;;;;;;;;;;;;iBAoBG,MACd,UAAU,aACV,UAAU,qBACV,UAAU,iBACV,2BACA,GAAG,SAAS,GAAG,GAAG,GAAG,QAAQ,WAAW,GAAG,GAAG
|
|
1
|
+
{"version":3,"file":"query.d.cts","names":[],"sources":["../src/query.ts"],"mappings":"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"}
|
package/build/query.d.mts
CHANGED
|
@@ -278,15 +278,22 @@ type QueryArg<F extends QuerySource, S extends QuerySelect, J extends QueryJoins
|
|
|
278
278
|
*/
|
|
279
279
|
declare function query<F extends QuerySource, S extends QuerySelect = never, J extends QueryJoins = [], Name extends string = "?">(q: QueryArg<F, S, J, Name>): QueryValue<S, J, Name>;
|
|
280
280
|
/**
|
|
281
|
-
*
|
|
281
|
+
* Builds a SQL expression from a tagged template.
|
|
282
282
|
*
|
|
283
|
-
*
|
|
284
|
-
* and every other value becomes a `?` binding, so users never write `"a.age * 2"` and hope `a` is the SQL
|
|
285
|
-
* alias, and referenced aliases still count for join pruning.
|
|
283
|
+
* For an Author alias `a` assigned the SQL alias `a1`:
|
|
286
284
|
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
285
|
+
* ```ts
|
|
286
|
+
* sql`${a.age} * 2` // Expression: a1.age * 2
|
|
287
|
+
* sql`${a.age.gte(18)}` // Condition: (a1.age >= ?), bindings [18]
|
|
288
|
+
* sql`${"Alice"}` // Value: ?, bindings ["Alice"]
|
|
289
|
+
*
|
|
290
|
+
* // Selecting this expression keeps the join to Book b.
|
|
291
|
+
* sql<number>`${b.order} * ${2}`
|
|
292
|
+
*
|
|
293
|
+
* // Reference an unmodeled column; it is untracked at the type level.
|
|
294
|
+
* sql.ref<string>(a, "ts_search")
|
|
295
|
+
* sql.condition`${sql.ref(a, "ts_search")} @@ plainto_tsquery(${term})`
|
|
296
|
+
* ```
|
|
290
297
|
*/
|
|
291
298
|
declare function sql<R = unknown>(strings: TemplateStringsArray, ...values: unknown[]): Expr<R, never>;
|
|
292
299
|
declare namespace sql {
|
package/build/query.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.mts","names":[],"sources":["../src/query.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAuFa;cACA;;UAGI,cAAc,GAAG;WACvB,OAAO;WACP,QAAQ;;;KAIP;YACI,YAAY;;YACZ,gBAAgB;;;;;;;KAOpB,YAAY,UAAU,eAAe,SAAS;KAC9C,uBAAuB;;;;;;;;;;KAWvB,aAAa;WACV,KAAK;WAAwB;;WAC7B,MAAM;WAAwB;;WAC9B;oBAA6C,WAAW,2BAErD,KAAK,QAAQ,WAAW;KAE9B;;;;;;;;;KAgBA,YAAY,KAAK;YAAsB;aAAuB,gBAAgB;;IACtF,UAAU,qBACI,WAAW,MAAM,MAAM,MAAM,GAAG,WAAW,gBAAgB,aAAa,0CAEtF;YAAsB;wBAER,WAAW,cAAc;;KAGtC,WAAW,KAAK,0BAA0B,YAAY;;KAG/C,cAAc,cAAc,gBAAgB,eAAe;;;;;;;;UAStD,QAAQ,UAAU,cAAc,aAAa,UAAU,aAAa;EACnF,OAAO;;EAEP,QAAQ;EACR,mBAAmB;EACnB,SAAS;EACT,QAAQ;EACR,oBAAoB,aAAa,KAAK,YAAY,oBAAoB,YAAY;EAClF;EACA;EACA;;EAEA;;;;;;;EAOA;;;UAIe,MAAM,UAAU,cAAc,aAAa,UAAU,aAAa,oBAAoB,QAAQ,GAAG;EAChH,MAAM;;;KAQI,OAAO,KAAK;YAAsB;aAAuB,cAAc;;IAC/E,IACA;YAAsB;aAA2B,cAAc;;IAC7D;;KAID,WAAW,KAAK,UAAU,eAAe,KAAK,OAAO;;;;;;;;;;;;;;;;KAiB9C,UAAU,GAAG,oBAAoB,UAAU,6BAA6B,OAC/E,WAAW,8BACV,IACA,YACD,QAAQ,KAAK,WAAW,+BACvB,IACA;;;;;;;;;KAUM,SAAS,GAAG,UAAU,mBAAmB;YAAsB;aAAuB,gBAAgB;;IAC9G,IACA;YAAsB;aAA2B,aAAa;;IAC5D,IACA;YAAsB,YAAY,gBAAgB,SAAS;IACzD,UAAU,GAAG,KAAK,QAEf,WAAW,IAAI,EAAE;YAAuB,YAAY,gBAAgB,SAAS;IAC1E,UAAU,GAAG,KAAK;;;;;;KAapB,SAAS,GAAG;YACZ,gBAAgB,cAAc,GAAG;gBAC7B,WAAW,IAAI,KAAK,EAAE,IAAI;;KAG9B,YAAY,UAAU;YAAsB;aAA8B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0BjF,WAAW,KAAK,oBAAoB;EAC1C;;;KAIM,WAAW,GAAG,UAAU,YAAY,uBAAuB;YAC3D;aAAuB,gBAAgB,UAAU;;IAEzD,YAAY,KACZ;YAAsB,YAAY,gBAAgB;IAChD,KAAK,mBACL,SAAS,SAAS,GAAG,IAAI;;KAG1B,WAAW,KAAK;WAAqB,aAAa;IACnD,OAAO,KACP;WAAqB,YAAY;IAC/B,OAAO;KAER,QAAQ,GAAG,UAAU,cAAc,OAAO,KAAK,WAAW;;;;;;;;;;;;;;;;KAiBnD,WAAW,GAAG,GAAG,UAAU,eAAe,gCAMjD,YAAY,eACX,OAAO,WAAW,OAAO;EAErB,YAAY,OAAO;KACtB,YAAY,eAAe;EAExB,WACG,WAAW,IAAI,EAAE;cAAuB,YAAY,qBAAqB;qBACvD,iBAEZ,QAAQ,KAAK,QAAQ,GAAG,2CAEb,QAAQ,KAAK,QAAQ,GAAG;;;KAO1C,SAAS,UAAU,aAAa,UAAU,aAAa,UAAU,YAAY,uBAAuB,MAC9G,GACA;EAEA,MAAM;EACN,KAAK;IACH,WAAW,GAAG,GAAG,KACnB,WAAW;;;;;;;;;;;;;;;;;;;iBAoBG,MACd,UAAU,aACV,UAAU,qBACV,UAAU,iBACV,2BACA,GAAG,SAAS,GAAG,GAAG,GAAG,QAAQ,WAAW,GAAG,GAAG
|
|
1
|
+
{"version":3,"file":"query.d.mts","names":[],"sources":["../src/query.ts"],"mappings":"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"}
|
package/build/query.js
CHANGED
|
@@ -72,15 +72,22 @@ function query(q) {
|
|
|
72
72
|
else return newSubqueryProxy(handle);
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
75
|
-
*
|
|
75
|
+
* Builds a SQL expression from a tagged template.
|
|
76
76
|
*
|
|
77
|
-
*
|
|
78
|
-
* and every other value becomes a `?` binding, so users never write `"a.age * 2"` and hope `a` is the SQL
|
|
79
|
-
* alias, and referenced aliases still count for join pruning.
|
|
77
|
+
* For an Author alias `a` assigned the SQL alias `a1`:
|
|
80
78
|
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
79
|
+
* ```ts
|
|
80
|
+
* sql`${a.age} * 2` // Expression: a1.age * 2
|
|
81
|
+
* sql`${a.age.gte(18)}` // Condition: (a1.age >= ?), bindings [18]
|
|
82
|
+
* sql`${"Alice"}` // Value: ?, bindings ["Alice"]
|
|
83
|
+
*
|
|
84
|
+
* // Selecting this expression keeps the join to Book b.
|
|
85
|
+
* sql<number>`${b.order} * ${2}`
|
|
86
|
+
*
|
|
87
|
+
* // Reference an unmodeled column; it is untracked at the type level.
|
|
88
|
+
* sql.ref<string>(a, "ts_search")
|
|
89
|
+
* sql.condition`${sql.ref(a, "ts_search")} @@ plainto_tsquery(${term})`
|
|
90
|
+
* ```
|
|
84
91
|
*/
|
|
85
92
|
function sql(strings, ...values) {
|
|
86
93
|
return new TemplateExpr(strings, values);
|
package/build/query.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","names":[],"sources":["../src/query.ts"],"sourcesContent":["import { AliasAssigner } from \"./AliasAssigner.ts\";\nimport {\n type Alias,\n type AliasBrand,\n type AliasMgmt,\n JoinTableHandle,\n type M2mJoinTable,\n aliasMgmt,\n collectionJoin,\n getAliasMetadata,\n getAliasMgmt,\n isAlias,\n m2mJoinTable,\n} from \"./Aliases.ts\";\nimport { ConditionBuilder } from \"./ConditionBuilder.ts\";\nimport { buildWhereClause } from \"./drivers/buildUtils.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type ExpressionCondition, type ExpressionFilter } from \"./EntityFilter.ts\";\nimport { type EntityMetadata, getBaseMeta } from \"./EntityMetadata.ts\";\nimport {\n BaseExpr,\n type Expr,\n type ExprBrand,\n type ExprContext,\n type ExprLike,\n type InnerJoin,\n type LeftJoin,\n RefExpr,\n type SqlFragment,\n TemplateExpr,\n asNode,\n deferredCondition,\n exprBrand,\n isExpr,\n resolveDeferredConditions,\n} from \"./Expr.ts\";\nimport { kq, kqStar, safeKq } from \"./keywords.ts\";\nimport { deepFindConditions } from \"./QueryParser.pruning.ts\";\nimport {\n type ColumnCondition,\n type ParsedExpressionFilter,\n type ParsedFindQuery,\n addTablePerClassJoinsAndClassTag,\n filterSoftDeletes,\n lazyExcludedSelects,\n stiSubtypeFilter,\n} from \"./QueryParser.ts\";\nimport { fail } from \"./utils.ts\";\n\n/**\n * `em.query`: SQL-shaped queries as plain object literals.\n *\n * A query is data, a `Query<S, J>` POJO, `{ from, join, where, groupBy, having, select, orderBy, ... }`\n * in SQL evaluation order:\n *\n * const [a, b] = aliases(Author, Book);\n * const bookStats = query({ from: b, groupBy: [b.author], select: { authorId: b.author, n: b.id.count() } });\n * const rows = await em.query({\n * from: a,\n * join: [{ left: bookStats, on: bookStats.authorId.eq(a.id) }],\n * select: { name: a.firstName, n: bookStats.n },\n * orderBy: { n: \"DESC\" },\n * });\n * // rows: { name: string; n: number | null }[] (null because of the LEFT join)\n *\n * `em.query(pojo)` runs it. `select` decides the row type: a bare alias returns entities, a\n * `{ key: expr }` object returns typed POJOs, a bare subquery returns that subquery's rows.\n *\n * `query(pojo)` turns the *same* POJO into a value: a derived table with typed columns, a scalar\n * expression, or an entity list. It is the one non-POJO step, and the subquery analog of `alias(Author)`:\n * to reference a query's columns, the outer query needs *values* for them, and no POJO can manufacture\n * values keyed off its own `select` keys.\n *\n * `alias()`/`aliases()` and `query()` are the only free functions a query needs, plus the `sql` tagged\n * template as the escape hatch for SQL with no modeled shape. Everything else is in-DSL: join kinds and\n * sort directions are keyword keys (`{ left: b, on }`, `{ desc: x }`), SQL functions are methods on\n * expressions (`b.id.count()`, `b.title.max()`, `x.coalesce(0)`), conditions are methods\n * (`a.age.gte(18)`), and pruning is `undefined`: an `undefined` condition drops out, and a join nothing\n * references anymore drops with it (see \"Pruning\" below).\n *\n * User documentation: `docs/src/content/docs/features/queries-raw.md`.\n */\n\n// =====================================================================================================\n// Sources, joins, clauses\n// =====================================================================================================\n\nexport const subqueryBrand: unique symbol = Symbol(\"joist.subquery\");\nexport const entityQueryBrand: unique symbol = Symbol(\"joist.entityQuery\");\n\n/** Phantom type information carried by a table-shaped subquery. */\nexport interface SubqueryBrand<R, Name extends string> {\n readonly __row: R;\n readonly __name: Name;\n}\n\n/** Anything that can be a source or be joined: an entity alias or a table-shaped subquery. */\nexport type QuerySource =\n | { readonly [aliasMgmt]: AliasBrand<any, string> }\n | { readonly [subqueryBrand]: SubqueryBrand<any, string> };\n\n/**\n * A join entry (see `InnerJoin`/`LeftJoin` in `Expr.ts`): the expanded `{ inner: b, on }` form, or the\n * entry a relation join factory returns (`a.books.as(b)`); joins to a subquery are always the expanded\n * form, since a subquery has no FK metadata.\n */\nexport type QueryJoin = InnerJoin<QuerySource> | LeftJoin<QuerySource>;\nexport type QueryJoins = readonly (QueryJoin | undefined)[];\n\n/**\n * An expression order-by entry: the direction is the key and the expression is the value, unlike\n * the keyed form's field name and `\"ASC\" | \"DESC\"` value. `never` on the other key keeps an\n * entry to one direction, the same trick `ExpressionFilter` uses for `and`/`or`. `nulls` is\n * `NULLS FIRST/LAST`.\n *\n * When select keys are known, exclude them so a keyed sort cannot be silently ignored inside an\n * expression entry. An untyped `Query` has no known keys to exclude.\n */\nexport type QueryOrderBy<S = never> = (\n | { readonly asc: ExprLike<any>; readonly desc?: never }\n | { readonly desc: ExprLike<any>; readonly asc?: never }\n) & { readonly nulls?: \"first\" | \"last\" } & (string extends OrderByKey<S>\n ? unknown\n : { readonly [K in Exclude<OrderByKey<S>, \"asc\" | \"desc\" | \"nulls\">]?: never });\n\nexport type OrderByDirection =\n | \"ASC\"\n | \"DESC\"\n | \"ASC NULLS FIRST\"\n | \"ASC NULLS LAST\"\n | \"DESC NULLS FIRST\"\n | \"DESC NULLS LAST\";\n\n/**\n * A keyed `orderBy` entry, used alone or in an array, like `em.find`'s `orderBy: [{ firstName: \"ASC\" }]`.\n *\n * The keys are the keys of a POJO/subquery `select` (rendered as SQL output-column names, so ordering\n * by an aggregate does not repeat its expression), or the entity's sortable fields in entity mode.\n * An `undefined` direction prunes the entry, like any other condition. For expressions that are not\n * in `select`, mix in `{ asc: expr }` / `{ desc: expr }` entries in the array form.\n */\nexport type OrderByKeys<S> = S extends { readonly [aliasMgmt]: { readonly __entity: infer T } }\n ? T extends Entity\n ? { readonly [K in keyof Alias<T> as Alias<T>[K] extends ExprLike<any> ? K : never]?: OrderByDirection | undefined }\n : never\n : S extends { readonly [exprBrand]: any }\n ? never\n : { readonly [K in keyof S & string]?: OrderByDirection | undefined };\n\n/** All sortable keys across select variants, not just the keys shared by every variant. */\ntype OrderByKey<S> = S extends unknown ? keyof OrderByKeys<S> : never;\n\n/** The three select shapes: entity mode, single-expression mode (scalar/list subqueries), and POJO mode. */\nexport type QuerySelect = QuerySource | ExprLike<any> | Record<string, ExprLike<any>>;\n\n/**\n * Everything but the source, in SQL evaluation order: FROM/JOIN, WHERE, GROUP BY, HAVING, SELECT,\n * ORDER BY, LIMIT.\n *\n * `S` and `J` are generic so callers keep the literal shape of `select` and `join`; the defaults let\n * a standalone object use `satisfies Query` (or `satisfies Clauses` for a source-less fragment).\n */\nexport interface Clauses<S extends QuerySelect = QuerySelect, J extends QueryJoins = QueryJoins> {\n join?: J;\n /** An `{ and: [...] }` / `{ or: [...] }` filter, or a single bare condition, i.e. `where: a.age.gte(18)`. */\n where?: ExpressionCondition;\n groupBy?: readonly ExprLike<any>[];\n having?: ExpressionCondition;\n select: S;\n orderBy?: readonly (QueryOrderBy<S> | OrderByKeys<S> | undefined)[] | OrderByKeys<S>;\n limit?: number;\n offset?: number;\n distinct?: boolean;\n /** Defaults to true. `false` keeps every join, em.find's opt-out. */\n pruneJoins?: boolean;\n /**\n * Defaults to `\"exclude\"`, em.find's rule: a soft-deletable entity in `from` gains a\n * `deleted_at IS NULL` condition in WHERE, and a joined one gains it in its join's ON (so a LEFT\n * join nulls its columns out instead of dropping rows). `\"include\"` turns the injection off for\n * this query; subqueries read their own key.\n */\n softDeletes?: \"include\" | \"exclude\";\n}\n\n/** A whole query: `Clauses` plus its source. `query(q)` turns it into a value; `em.query(q)` runs it. */\nexport interface Query<S extends QuerySelect = QuerySelect, J extends QueryJoins = QueryJoins> extends Clauses<S, J> {\n from: QuerySource;\n}\n\n// =====================================================================================================\n// Result-row types\n// =====================================================================================================\n\n/** The type-level name of an alias or subquery, i.e. `\"Author\"` or `\"book_stats\"`. */\nexport type NameOf<A> = A extends { readonly [aliasMgmt]: { readonly __name: infer N } }\n ? N\n : A extends { readonly [subqueryBrand]: { readonly __name: infer N } }\n ? N\n : never;\n\n/** The names of every alias that was LEFT JOINed; `X` is a naked type parameter so this distributes. */\ntype LeftJoined<X> = X extends LeftJoin<infer A> ? NameOf<A> : never;\n\n/**\n * Asks: is this expression's source key among the LEFT-joined sources in this query's join list? If\n * yes, the value can be `null`, so `R` becomes `R | null`; if no, `R` is unchanged.\n *\n * I.e. `MaybeNull<number, \"book_stats\", [LeftJoin<typeof bookStats>]>` is `number | null`,\n * because `book_stats` is in `LeftJoined<J[number]>`; with an inner join it stays `number`.\n *\n * Source-less expressions (`Src` is `never`, i.e. `b.id.count()`) are never nullified. Untracked ones\n * (`Src` is `string`, i.e. a `sql.ref` on an unknown table) might come from any left-joined table,\n * so they are conservatively nullified whenever the query has a left join at all.\n *\n * `string` must never be a *table's* name: `Extract<\"Author\", string>` matches, so one left-joined\n * table named `string` would nullify every column in the query. That is why anonymous subqueries\n * share the literal sentinel `\"?\"` instead.\n */\nexport type MaybeNull<R, Src extends string, J extends QueryJoins> = string extends Src\n ? [LeftJoined<J[number]>] extends [never]\n ? R\n : R | null\n : [Extract<Src, LeftJoined<J[number]>>] extends [never]\n ? R\n : R | null;\n\n/**\n * The result row for a query with select `S` and joins `J`.\n *\n * - entity mode (`select: a`) is the entity\n * - subquery mode (`select: bookStats`) is the subquery's row, i.e. `select *`\n * - single expression (`select: b.id.count()`) is that expression's value, used by scalar subqueries\n * - POJO mode is a mapped type over the select keys, with left-join nullability applied\n */\nexport type QueryRow<S, J extends QueryJoins = []> = S extends { readonly [aliasMgmt]: { readonly __entity: infer T } }\n ? T\n : S extends { readonly [subqueryBrand]: { readonly __row: infer R } }\n ? R\n : S extends { readonly [exprBrand]: ExprBrand<infer R, infer Src> }\n ? MaybeNull<R, Src, J>\n : {\n [K in keyof S]: S[K] extends { readonly [exprBrand]: ExprBrand<infer R, infer Src> }\n ? MaybeNull<R, Src, J>\n : never;\n };\n\n// =====================================================================================================\n// `query()`: a query POJO becomes a typed table, scalar, or entity list\n// =====================================================================================================\n\n/**\n * A table-shaped query: one `Expr` per select key, each tagged with the table's name as its `Src`,\n * plus a brand carrying the row type. This is the direct analog of `Alias<T>`: `Alias<T>` maps entity\n * fields to expressions, `Subquery<Row, Name>` maps the inner query's select keys to expressions.\n */\nexport type Subquery<R, Name extends string> = {\n readonly [subqueryBrand]: SubqueryBrand<R, Name>;\n} & { readonly [K in keyof R]: Expr<R[K], Name> };\n\n/** An entity-mode query (`select: a`): runnable, but it has no columns to reference. */\nexport type EntityQuery<T extends Entity> = { readonly [entityQueryBrand]: { readonly __row: T } };\n\n/**\n * Rejects a `select` that a `: Query` annotation widened to the whole `QuerySelect` union.\n *\n * `satisfies Query` checks the shape but keeps the literal type of `select`, so `S` infers as\n * `{ name: Expr<string, \"Author\"> }`. A `: Query` annotation replaces that type with the annotation, so\n * `S` infers as `QuerySelect` itself, and without this guard `query(q)` returned a useless union with no\n * error at all.\n *\n * A widened `S` is the only kind of `S` the whole `QuerySelect` union is assignable to (a POJO, an\n * `Expr`, or an `Alias` never is), so `QuerySelect extends S` detects it, and intersecting the parameter\n * with `{ select: \"<message>\" }` fails the call on `select` with that message, for `query()` and\n * `em.query()` alike:\n *\n * const narrow = { from: a, select: { name: a.firstName } } satisfies Query;\n * query(narrow); // Subquery<{ name: string }, \"?\">\n *\n * const widened: Query = { from: a, select: { name: a.firstName } };\n * query(widened);\n * // error: Type 'QuerySelect' is not assignable to type\n * // '\"select was typed too generically; use `satisfies Query` instead of `: Query`\"'\n *\n * `S` also defaults to `never`, so a *missing* `select` is reported as \"Property 'select' is missing\"\n * against `Query<never, []>` instead of tripping this guard.\n */\nexport type NotWidened<S> = QuerySelect extends S\n ? { select: \"select was typed too generically; use `satisfies Query` instead of `: Query`\" }\n : unknown;\n\n/** What `query()` returns, by select shape: an entity list, a scalar/list subquery, or a derived table. */\nexport type QueryValue<S, J extends QueryJoins, Name extends string> = S extends {\n readonly [aliasMgmt]: { readonly __entity: infer T extends Entity };\n}\n ? EntityQuery<T>\n : S extends { readonly [exprBrand]: ExprBrand<infer R, any> }\n ? Expr<R | null, never>\n : Subquery<QueryRow<S, J>, Name>;\n\n/** The names of every alias in scope for a query: the source alias plus every joined alias. */\ntype JoinedName<X> = X extends { readonly inner: infer A }\n ? NameOf<A>\n : X extends { readonly left: infer A }\n ? NameOf<A>\n : never;\ntype InScope<F, J extends QueryJoins> = NameOf<F> | JoinedName<J[number]>;\n\n/**\n * Asks, for every column of a POJO select: is its source key among `from` + `join` at all? If no, the\n * query reads from a table it never joined, and that select key's type becomes an error message.\n *\n * Because `Expr` already carries `Src`, this is nearly free: for each select key, if `Src` is tracked\n * and any of its names is outside `InScope`, intersect that key's type with an error string, so the\n * caller sees `Type 'Expr<number, \"book_stats\">' is not assignable to type '... is not in from/join'`.\n * Untracked (`string`) and source-less (`never`) expressions always pass. Aliases with the same\n * type-level name (two bare `alias(Author)`, or two anonymous tables) cannot be told apart, so a miss\n * there goes unreported; the check never gives a false positive, only false negatives on collisions.\n *\n * `[S] extends [...]` keeps this non-distributive, and `never` is skipped outright: `query()` defaults\n * `S` to `never` when `select` is missing, and a distributive conditional over `never` would swallow the\n * whole parameter type.\n */\nexport type CheckScope<S, F, J extends QueryJoins> = [S] extends [never]\n ? unknown\n : // A source-shaped select (`select: a`, `select: bookStats`) must be the `from`: a joined source's\n // rows would need left-join nullability (and entity hydration) that source-shaped selects don't\n // model. Two same-named sources (unnamed aliases of one entity, anonymous subqueries) pass this\n // check and are caught at runtime instead.\n [S] extends [QuerySource]\n ? NameOf<S> extends NameOf<F>\n ? unknown\n : { select: `'${NameOf<S> & string}' is a joined source, not the from; select its columns individually` }\n : [S] extends [Record<string, ExprLike<any>>]\n ? {\n select: {\n [K in keyof S]: S[K] extends { readonly [exprBrand]: ExprBrand<any, infer Src> }\n ? string extends Src\n ? unknown\n : [Exclude<Src, InScope<F, J>>] extends [never]\n ? unknown\n : `alias '${Exclude<Src, InScope<F, J>> & string}' is not in from/join`\n : unknown;\n };\n }\n : unknown;\n\n/** The one argument type `query()` and `em.query()` share: a `Query` POJO plus its source, name, and checks. */\nexport type QueryArg<F extends QuerySource, S extends QuerySelect, J extends QueryJoins, Name extends string> = Query<\n S,\n J\n> & {\n from: F;\n as?: Name;\n} & CheckScope<S, F, J> &\n NotWidened<S>;\n\n/**\n * Turns a `Query` POJO into a value. The select shape decides which (`QueryValue`):\n *\n * - a single expression is a scalar subquery or an IN list (`Expr<R | null>`; a scalar subquery can\n * return no row, so use `.coalesce(0)` when the SQL guarantees a value, i.e. an ungrouped `count`)\n * - an entity alias is an entity list, runnable via `em.query`\n * - a POJO is a derived table whose columns are `Expr`s; it can be a source, be joined, or be run\n *\n * `as` is the SQL alias and the type-level identity, the same role the second argument of\n * `alias(Author, \"m\")` plays. Without it the SQL alias is generated, like `alias(Author)`, and all\n * anonymous tables share the type-level identity `\"?\"`: precise against every named alias, and\n * conservative (a left-joined anonymous table nullifies every anonymous table's columns) only among\n * themselves. This is the same collision two bare `alias(Author)` have.\n *\n * One signature, not three overloads: overloads wrapped every clauses-object mistake in \"No overload\n * matches this call\", hid `as` from completions, and cost 15-28% check time; the one thing they did\n * better, rejecting a `select` widened by a `: Query` annotation, `NotWidened` does with a clearer message.\n */\nexport function query<\n F extends QuerySource,\n S extends QuerySelect = never,\n J extends QueryJoins = [],\n Name extends string = \"?\",\n>(q: QueryArg<F, S, J, Name>): QueryValue<S, J, Name> {\n const handle = new SubqueryHandle(q as AnyQuery);\n const select = (q as AnyQuery).select;\n if (isAlias(select)) {\n return { [entityQueryBrand]: handle } as any;\n } else if (isExpr(select)) {\n return new SubqueryExpr(handle) as any;\n } else {\n return newSubqueryProxy(handle) as any;\n }\n}\n\n/**\n * The escape hatch for SQL with no modeled shape.\n *\n * Interpolated expressions use the alias Joist assigned, interpolated conditions become SQL,\n * and every other value becomes a `?` binding, so users never write `\"a.age * 2\"` and hope `a` is the SQL\n * alias, and referenced aliases still count for join pruning.\n *\n * sql<number>`${b.order} * ${2}`\n * sql.condition`${sql.ref(a, \"ts_search\")} @@ plainto_tsquery(${term})`\n * sql.ref<string>(a, \"ts_search\") // an unmodeled column; untracked at the type level\n */\nexport function sql<R = unknown>(strings: TemplateStringsArray, ...values: unknown[]): Expr<R, never> {\n return new TemplateExpr(strings, values) as any;\n}\n\n/** A raw condition for `where`, `having`, or `on`. */\nsql.condition = function condition(strings: TemplateStringsArray, ...values: unknown[]): ExpressionCondition {\n return deferredCondition((ctx) => new TemplateExpr(strings, values).toSql(ctx));\n};\n\n/** A column Joist does not model, on a source that is in the query. */\nsql.ref = function ref<R = unknown>(source: QuerySource, column: string): Expr<R, string> {\n return new RefExpr(handleOf(source), column) as any;\n};\n\n/**\n * Parses `arg` (a `Query` POJO or `query(...)` value) into a runnable `Plan`.\n *\n * `EntityManager.query` runs the plan; this module deliberately does not import `EntityManager` (see\n * `EntityHydrator`), so it parses and hands back `{ sql, bindings, decodeRows }` instead of executing.\n */\nexport function parseUserQuery(arg: unknown): Plan {\n return parseQuery(toQuery(arg), undefined, new AliasAssigner());\n}\n\n/**\n * The one `EntityManager` capability that row decoding needs, typed structurally.\n *\n * Importing `EntityManager.ts` here would complete an `EntityManager.ts` <-> `query.ts` declaration\n * cycle (`EntityManager.query` imports this module's types), which correlated with a tsc 7.0.2\n * incremental-build bug: after tsdown rewrites `build/`, `tsc --build` sporadically reports thousands\n * of phantom \"Module 'joist-orm' has no exported member ...\" errors and caches them in `.tsbuildinfo`.\n */\nexport interface EntityHydrator {\n hydrate(cstr: any, rows: readonly any[]): any[];\n}\n\nexport interface Plan {\n sql: string;\n bindings: any[];\n /** Aliases of enclosing queries this (sub)query referenced. */\n outerRefs: string[];\n decodeRows(em: EntityHydrator, rows: any[]): any[];\n}\n\n// =====================================================================================================\n// Runtime: handles, subquery expressions, the proxy\n// =====================================================================================================\n\ntype AnyQuery = Query<any, any> & { as?: string };\n\n/** The runtime identity of a `query(...)` value; `Ctx.aliasFor` keys on it, like an alias's `AliasMgmt`. */\nexport class SubqueryHandle {\n constructor(readonly q: AnyQuery) {}\n\n get name(): string | undefined {\n return this.q.as;\n }\n\n /** The select keys, for `select: <subquery>` and for reporting unknown columns. */\n columnKeys(): string[] {\n const { select } = this.q;\n if (isPlainSelect(select)) return Object.keys(select);\n if (isSubqueryValue(select)) return select[subqueryBrand].columnKeys();\n return fail(`A subquery with an entity or scalar select has no columns`);\n }\n\n /** The inner expression behind `key`, for its decoder/encoder. */\n columnExpr(key: string): BaseExpr {\n const { select } = this.q;\n if (isPlainSelect(select)) {\n return (select[key] as any as BaseExpr) ?? fail(`Subquery ${this.describe()} has no column ${key}`);\n } else if (isSubqueryValue(select)) {\n return select[subqueryBrand].columnExpr(key);\n }\n return fail(`Subquery ${this.describe()} has no columns`);\n }\n\n column(key: string): SubqueryColumnExpr {\n return new SubqueryColumnExpr(this, key, this.columnExpr(key));\n }\n\n describe(): string {\n return this.q.as ? `'${this.q.as}'` : \"(anonymous)\";\n }\n}\n\n/** A column of a joined/from'd subquery, i.e. `bookStats.bookCount`, which becomes `book_stats.\"bookCount\"`. */\nclass SubqueryColumnExpr extends BaseExpr {\n constructor(\n private handle: SubqueryHandle,\n private key: string,\n private inner: BaseExpr,\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const alias = ctx.aliasFor(this.handle);\n // safeKq for the alias too: a subquery's canonical alias is its user-provided `as` name\n return { sql: `${safeKq(alias)}.${safeKq(this.key)}`, bindings: [], refs: [alias] };\n }\n\n decode(value: unknown): unknown {\n return this.inner.decode(value);\n }\n\n encode(value: unknown): unknown {\n return this.inner.encode(value);\n }\n}\n\n/**\n * A scalar (or IN-list) subquery, i.e. `query({ from: b, where: [...], select: b.id.count() })`.\n *\n * It closes over the outer aliases it references, so correlation is free; those references are the\n * subquery's \"free\" aliases and count toward the outer query's join pruning.\n */\nclass SubqueryExpr extends BaseExpr {\n constructor(readonly handle: SubqueryHandle) {\n super();\n }\n\n get subquerySelect(): BaseExpr {\n return asNode(this.handle.q.select);\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const bare = this.toSqlBare(ctx);\n return { ...bare, sql: `(${bare.sql})` };\n }\n\n toSqlBare(ctx: ExprContext): SqlFragment {\n const parent = ctx instanceof Ctx ? ctx : fail(\"Subqueries need the query parser's context\");\n const plan = parseQuery(this.handle.q, parent, parent.assigner);\n return { sql: plan.sql, bindings: plan.bindings, refs: plan.outerRefs };\n }\n\n decode(value: unknown): unknown {\n return this.subquerySelect.decode(value);\n }\n\n encode(value: unknown): unknown {\n return this.subquerySelect.encode(value);\n }\n}\n\nfunction newSubqueryProxy(handle: SubqueryHandle): object {\n return new Proxy(\n {},\n {\n get(_, key) {\n if (key === subqueryBrand) return handle;\n if (typeof key === \"string\") return handle.column(key);\n return undefined;\n },\n has(_, key) {\n return key === subqueryBrand || (typeof key === \"string\" && handle.columnKeys().includes(key));\n },\n },\n );\n}\n\nfunction isSubqueryValue(value: unknown): value is { [subqueryBrand]: SubqueryHandle } {\n return typeof value === \"object\" && value !== null && subqueryBrand in value;\n}\n\nfunction isEntityQueryValue(value: unknown): value is { [entityQueryBrand]: SubqueryHandle } {\n return typeof value === \"object\" && value !== null && entityQueryBrand in value;\n}\n\nfunction isPlainSelect(select: unknown): select is Record<string, ExprLike<any>> {\n return (\n typeof select === \"object\" && select !== null && !isAlias(select) && !isExpr(select) && !isSubqueryValue(select)\n );\n}\n\n/** Returns the runtime identity of a source: an alias's `AliasMgmt` or a subquery's handle. */\nfunction handleOf(source: unknown): AliasMgmt | SubqueryHandle {\n if (isAlias(source)) return getAliasMgmt(source);\n if (isSubqueryValue(source)) return source[subqueryBrand];\n return fail(`Expected an alias or a query(...) value, got ${source}`);\n}\n\n// =====================================================================================================\n// Runtime: parse -> prune -> SQL -> decode\n// =====================================================================================================\n\nfunction toQuery(arg: unknown): AnyQuery {\n if (isSubqueryValue(arg)) return arg[subqueryBrand].q;\n if (isEntityQueryValue(arg)) return arg[entityQueryBrand].q;\n if (arg instanceof SubqueryExpr) return arg.handle.q;\n if (typeof arg === \"object\" && arg !== null && \"from\" in arg && \"select\" in arg) return arg as AnyQuery;\n return fail(`em.query expects a { from, select, ... } object or a query(...) value`);\n}\n\n/**\n * What an expression needs from the query it is generating SQL for.\n *\n * Each (sub)query gets its own `Ctx`; a lookup that misses locally walks up to the enclosing query and\n * records the hit in `outerRefs`, which is how a correlated subquery reports the outer aliases it\n * depends on (the way `ExistsCondition.outerAliases` does), so join pruning keeps them.\n */\nclass Ctx implements ExprContext {\n private aliases = new Map<object, string>();\n readonly outerRefs = new Set<string>();\n /** Physical CTI table aliases (`sp_b0`) to their source alias (`sp`), shared across the whole parse. */\n readonly ctiAliases: Map<string, string>;\n\n constructor(\n readonly assigner: AliasAssigner,\n private parent: Ctx | undefined,\n ) {\n this.ctiAliases = parent?.ctiAliases ?? new Map();\n }\n\n register(handle: object, alias: string): void {\n this.aliases.set(handle, alias);\n }\n\n aliasFor(handle: object): string {\n const local = this.aliases.get(handle);\n if (local) return local;\n if (this.parent) {\n const outer = this.parent.aliasFor(handle);\n this.outerRefs.add(outer);\n return outer;\n }\n return fail(`${describeHandle(handle)} is not in this query's from/join`);\n }\n\n conditionToSql(cond: ExpressionCondition): SqlFragment | undefined {\n // Inside another expression (i.e. a `sql` template), keep `a OR b` grouped\n return conditionToSql(cond, this, false);\n }\n}\n\nfunction describeHandle(handle: object): string {\n if (handle instanceof SubqueryHandle) return `Subquery ${handle.describe()}`;\n if (handle instanceof JoinTableHandle) return `Join table ${handle.joinTableName}`;\n if (\"tableName\" in handle) return `Alias for ${(handle as AliasMgmt).tableName}`;\n return \"Alias\";\n}\n\ninterface ParsedSource {\n handle: AliasMgmt | SubqueryHandle | JoinTableHandle;\n alias: string;\n /** `table AS alias` or `(SELECT ...) AS alias`. */\n sql: string;\n bindings: any[];\n /** Outer aliases a derived table references; PG rejects those without LATERAL, but pruning should still see them. */\n refs: string[];\n /** CTI base/sub-table joins that travel with an entity alias. */\n extraJoins: string[];\n /** Entity-mode selects, i.e. `a.*` plus CTI columns and the `__class` tag. */\n entitySelects: string[];\n meta: EntityMetadata | undefined;\n}\n\ninterface ParsedJoin {\n kind: \"inner\" | \"left\";\n source: ParsedSource;\n /** The user's ON alone; `undefined` means it pruned away entirely, an error if the join is kept. */\n userOn: SqlFragment | undefined;\n /** The ON to emit: the user's ON plus any injected soft-delete/STI-discriminator conditions. */\n fullOn: SqlFragment | undefined;\n keep: boolean;\n}\n\n/**\n * Parses one `Query` POJO into SQL, recursively for subqueries.\n *\n * 1. Register every source's runtime identity with its SQL alias in this parse's context.\n * 2. Generate SQL for sources, selects, conditions, group-bys, and order-bys against the context; every fragment\n * reports the aliases it references.\n * 3. Prune: drop joins nothing references (see below), then reject a kept join whose ON collapsed.\n * 4. Assemble the SQL from the kept fragments, so pruned bindings disappear with their SQL.\n */\nfunction parseQuery(q: AnyQuery, parent: Ctx | undefined, assigner: AliasAssigner): Plan {\n const ctx = new Ctx(assigner, parent);\n const selectedAlias = isAlias(q.select) ? getAliasMgmt(q.select) : undefined;\n const joinEntries = [...(q.join ?? [])].filter(isDefined);\n\n // 1. Register every source before generating SQL, so conditions can resolve their aliases.\n const parseFrom = registerSource(q.from, ctx, assigner, handleOf(q.from) === selectedAlias);\n const pendingJoins = joinEntries.flatMap((j) => {\n const kind = \"inner\" in j && j.inner ? (\"inner\" as const) : (\"left\" as const);\n const alias = kind === \"inner\" ? j.inner : j.left;\n const keep = j.keep ?? false;\n // Only collection sugar joins (o2m/m2m) filter soft-deletes, em.find's relation semantics:\n // references (m2o/o2o/poly) resolve soft-deleted entities, and explicit joins are the user's own\n const softDeletes = (j as any)[collectionJoin] === true;\n const target = { kind, keep, on: j.on, softDeletes, parseSource: registerSource(alias, ctx, assigner, false) };\n // A sugar m2m join (`a.tags.as(t)`) carries a hidden join-table join; emit it first, with the same kind\n const m2m: M2mJoinTable | undefined = (j as any)[m2mJoinTable];\n if (!m2m) return [target];\n return [\n { kind, keep, on: m2m.on, softDeletes: false, parseSource: registerJoinTable(m2m.handle, ctx, assigner) },\n target,\n ];\n });\n\n // 2. Generate SQL.\n const softDeletes = q.softDeletes ?? \"exclude\";\n const from = parseFrom();\n const joins: ParsedJoin[] = pendingJoins.map((j) => {\n const source = j.parseSource();\n // `userOn` is the user's ON alone, so the collapsed-ON check below is not fooled by injections\n const userOn = conditionToSql(j.on, ctx, true);\n const injected = injectedConditions(source, j.softDeletes ? softDeletes : \"include\");\n const fullOn = userOn && injected.length > 0 ? conditionToSql({ and: [j.on, ...injected] }, ctx, true) : userOn;\n return { kind: j.kind, keep: j.keep, source, userOn, fullOn };\n });\n const { selects, decodeRows } = selectsToSql(q, ctx, from);\n const fromInjected = injectedConditions(from, softDeletes);\n const where = conditionToSql(fromInjected.length > 0 ? { and: [q.where, ...fromInjected] } : q.where, ctx, true);\n const having = conditionToSql(q.having, ctx, true);\n const groupBys = (q.groupBy ?? []).map((g) => asExpr(g, \"groupBy\").toSql(ctx));\n const orderBys = orderBysToSql(q, ctx);\n\n // 3. Prune.\n const kept = pruneJoins(q, from, joins, [...selects, ...groupBys, ...orderBys, where, having].filter(isDefined));\n // Joins emit in declaration order, so an ON may only reference sources declared before it; a forward\n // reference would reach PG as invalid SQL (\"missing FROM-clause entry\"). Reordering is not offered:\n // it is not semantics-preserving once INNER and LEFT joins mix, and the caller's fix is trivial.\n const laterAliases = new Set(kept.map((j) => j.source.alias));\n for (const j of kept) {\n if (!j.userOn) {\n fail(\n `Join ${describeHandle(j.source.handle)} has no ON condition left (they all pruned), but the query still references it`,\n );\n }\n laterAliases.delete(j.source.alias);\n const forward = j.fullOn!.refs.find((r) => laterAliases.has(r));\n if (forward) {\n fail(\n `Join ${describeHandle(j.source.handle)} references '${forward}', which is joined later; move that join earlier in the join array`,\n );\n }\n }\n\n // 4. Assemble.\n const out: SqlFragment[] = [];\n out.push({ sql: `SELECT ${q.distinct ? \"DISTINCT \" : \"\"}`, bindings: [], refs: [] });\n out.push(joinFragmentParts(selects, \", \"));\n out.push({ sql: ` FROM ${from.sql}`, bindings: from.bindings, refs: [] });\n for (const extra of from.extraJoins) out.push({ sql: ` ${extra}`, bindings: [], refs: [] });\n for (const j of kept) {\n const keyword = j.kind === \"inner\" ? \"JOIN\" : \"LEFT OUTER JOIN\";\n // A CTI subtype's physical base-table joins go *inside* a parenthesized join item: the ON can\n // reference the base alias (i.e. `sp.id` renders as `sp_b0.id`), so the subtree must join first\n const source = j.source.extraJoins.length > 0 ? `(${j.source.sql} ${j.source.extraJoins.join(\" \")})` : j.source.sql;\n out.push({\n sql: ` ${keyword} ${source} ON ${j.fullOn!.sql}`,\n bindings: [...j.source.bindings, ...j.fullOn!.bindings],\n refs: [],\n });\n }\n if (where) out.push({ sql: ` WHERE ${where.sql}`, bindings: where.bindings, refs: [] });\n if (groupBys.length > 0)\n out.push({ ...joinFragmentParts(groupBys, \", \"), sql: ` GROUP BY ${groupBys.map((g) => g.sql).join(\", \")}` });\n if (having) out.push({ sql: ` HAVING ${having.sql}`, bindings: having.bindings, refs: [] });\n if (orderBys.length > 0)\n out.push({ ...joinFragmentParts(orderBys, \", \"), sql: ` ORDER BY ${orderBys.map((o) => o.sql).join(\", \")}` });\n if (q.limit !== undefined) out.push({ sql: ` LIMIT ?`, bindings: [q.limit], refs: [] });\n if (q.offset !== undefined) out.push({ sql: ` OFFSET ?`, bindings: [q.offset], refs: [] });\n\n return {\n sql: out.map((o) => o.sql).join(\"\"),\n bindings: out.flatMap((o) => o.bindings),\n outerRefs: [...ctx.outerRefs],\n decodeRows,\n };\n}\n\n/**\n * Assigns a SQL alias to a source and returns a function that parses it after all sources are registered.\n *\n * Conditions resolve source identities through the context when their SQL is generated. CTI entities\n * get their base/sub-table joins from `addTablePerClassJoinsAndClassTag`, and the entity-mode `select`\n * gets that helper's selects too.\n */\nfunction registerSource(source: unknown, ctx: Ctx, assigner: AliasAssigner, isPrimary: boolean): () => ParsedSource {\n const handle = handleOf(source);\n if (handle instanceof SubqueryHandle) {\n const alias = handle.name ? assigner.getLiteralAlias(handle.name) : assigner.getLiteralAlias(\"sq\");\n ctx.register(handle, alias);\n return () => {\n const inner = parseQuery(handle.q, ctx, assigner);\n return {\n handle,\n alias,\n sql: `(${inner.sql}) AS ${safeKq(alias)}`,\n bindings: inner.bindings,\n refs: inner.outerRefs,\n extraJoins: [],\n entitySelects: [],\n meta: undefined,\n };\n };\n } else {\n const meta = getAliasMetadata(source as any);\n const alias = assigner.getAlias(meta.tableName);\n ctx.register(handle, alias);\n // Record the physical CTI table aliases this source emits (i.e. `sp_b0`), so `refsOf` can credit\n // their refs to this alias exactly; a user subquery named `book_b0` must not be mistaken for one\n if (meta.inheritanceType === \"cti\") {\n meta.baseTypes.forEach((_, i) => ctx.ctiAliases.set(`${alias}_b${i}`, alias));\n if (isPrimary) meta.subTypes.forEach((_, i) => ctx.ctiAliases.set(`${alias}_s${i}`, alias));\n }\n return () => {\n const cti: ParsedFindQuery = { selects: [], tables: [], orderBys: [] };\n addTablePerClassJoinsAndClassTag(cti, meta, alias, isPrimary);\n const extraJoins = cti.tables.map((t) => {\n if (t.join !== \"outer\") return fail(`Unexpected ${t.join} join for CTI`);\n return `LEFT OUTER JOIN ${kq(t.table)} AS ${kq(t.alias)} ON ${t.col1} = ${t.col2}`;\n });\n // Entity mode starts with the primary table's own columns (excluding lazy ones, like em.find)\n // and *appends* the CTI base/sub-table columns and the __class tag; the CTI selects alone would\n // drop the selected table's own fields, i.e. a Publisher would hydrate with an undefined name\n const primarySelects = meta.hasLazyColumns ? lazyExcludedSelects(meta, alias) : [kqStar(alias)];\n const entitySelects = [...primarySelects, ...(cti.selects as string[])];\n return {\n handle,\n alias,\n sql: `${kq(meta.tableName)} AS ${kq(alias)}`,\n bindings: [],\n refs: [],\n extraJoins,\n entitySelects,\n meta,\n };\n };\n }\n}\n\n/**\n * em.find's per-source injections: `alias.deleted_at IS NULL` for a soft-deletable entity (CTI\n * subtypes are skipped, like em.find; see `filterSoftDeletes`), and the `type_id = X` discriminator\n * for an STI subtype, so `from: alias(TaskNew)` only sees (and a joined subtype only matches)\n * TaskNew rows.\n *\n * The conditions go into the from's WHERE or the join's ON, and never keep an otherwise unreferenced\n * join alive, which is what `pruneable: true` means on em.find's side.\n */\nfunction injectedConditions(source: ParsedSource, softDeletes: \"include\" | \"exclude\"): ColumnCondition[] {\n const { meta } = source;\n if (!meta) return [];\n const conditions: ColumnCondition[] = [];\n if (filterSoftDeletes(meta, softDeletes)) {\n const field = meta.allFields[getBaseMeta(meta).timestampFields!.deletedAt!];\n const column = field.serde!.columns[0];\n conditions.push({\n kind: \"column\",\n alias: `${source.alias}${field.aliasSuffix}`,\n column: column.columnName,\n dbType: column.dbType,\n cond: { kind: \"is-null\" },\n pruneable: true,\n });\n }\n const sti = stiSubtypeFilter(meta, source.alias);\n if (sti) conditions.push(sti);\n return conditions;\n}\n\n/** Registers a sugar m2m join table, i.e. `authors_to_tags`: a raw table with no entity metadata. */\nfunction registerJoinTable(handle: JoinTableHandle, ctx: Ctx, assigner: AliasAssigner): () => ParsedSource {\n const alias = assigner.getAlias(handle.joinTableName);\n ctx.register(handle, alias);\n return () => ({\n handle,\n alias,\n sql: `${kq(handle.joinTableName)} AS ${kq(alias)}`,\n bindings: [],\n refs: [],\n extraJoins: [],\n entitySelects: [],\n meta: undefined,\n });\n}\n\n/** Generates the `select` clause SQL and returns how to decode the resulting rows. */\nfunction selectsToSql(\n q: AnyQuery,\n ctx: Ctx,\n from: ParsedSource,\n): { selects: SqlFragment[]; decodeRows: Plan[\"decodeRows\"] } {\n const { select } = q;\n if (isAlias(select)) {\n // Entity mode: `a.*` (plus CTI columns), hydrated through the identity map. Only the from is\n // hydratable: a joined alias would need null-row skipping and left-join nullability (see TODO.md)\n if (from.handle !== getAliasMgmt(select)) {\n fail(\"Selecting a joined alias is not supported yet; select the from alias, or select its columns individually\");\n }\n const alias = ctx.aliasFor(getAliasMgmt(select));\n const meta = getAliasMetadata(select);\n const selects = from.entitySelects.map((s) => ({ sql: s, bindings: [], refs: [alias] }));\n return { selects, decodeRows: (em, rows) => em.hydrate(meta.cstr as any, rows) };\n } else if (isSubqueryValue(select)) {\n // `select: <subquery>` is `select *` for that table; like entity mode, only for the from, since a\n // left-joined subquery's unmatched rows would decode null fields the row type calls non-null\n const handle = select[subqueryBrand];\n if (from.handle !== handle) {\n fail(\n \"Selecting a joined subquery is not supported; select the from subquery, or select its columns individually\",\n );\n }\n const alias = ctx.aliasFor(handle);\n const keys = handle.columnKeys();\n const selects = keys.map((k) => ({\n sql: `${safeKq(alias)}.${safeKq(k)} AS ${safeKq(k)}`,\n bindings: [],\n refs: [alias],\n }));\n const decoders = keys.map((k) => [k, handle.columnExpr(k)] as const);\n return { selects, decodeRows: (_, rows) => rows.map((row) => decodeRow(row, decoders)) };\n } else if (isExpr(select)) {\n // Scalar mode: one value per row, used by scalar/IN-list subqueries\n const fragment = asNode(select).toSql(ctx);\n const selects = [{ ...fragment, sql: `${fragment.sql} AS value` }];\n return { selects, decodeRows: (_, rows) => rows.map((row) => asNode(select).decode(row.value)) };\n } else if (isPlainSelect(select)) {\n // POJO mode\n const entries = Object.entries(select).map(([key, expr]) => [key, asExpr(expr, `select.${key}`)] as const);\n const selects = entries.map(([key, expr]) => {\n const fragment = expr.toSql(ctx);\n return { ...fragment, sql: `${fragment.sql} AS ${safeKq(key)}` };\n });\n return { selects, decodeRows: (_, rows) => rows.map((row) => decodeRow(row, entries)) };\n }\n return fail(`Unsupported select ${select}`);\n}\n\nfunction decodeRow(row: any, decoders: readonly (readonly [string, BaseExpr])[]): any {\n const result: any = {};\n for (const [key, expr] of decoders) {\n const value = row[key];\n result[key] = value === null || value === undefined ? null : expr.decode(value);\n }\n return result;\n}\n\nconst ORDER_BY_DIRECTIONS: string[] = [\n \"ASC\",\n \"DESC\",\n \"ASC NULLS FIRST\",\n \"ASC NULLS LAST\",\n \"DESC NULLS FIRST\",\n \"DESC NULLS LAST\",\n];\n\n/**\n * Generates ORDER BY SQL in entry order for keyed/expression arrays or a single keyed object.\n *\n * Expression entries retain bindings and alias references for join pruning. Undefined entries and\n * directions are omitted.\n */\nfunction orderBysToSql(q: AnyQuery, ctx: Ctx): SqlFragment[] {\n const { orderBy, select } = q;\n if (!orderBy) return [];\n const result: SqlFragment[] = [];\n for (const entry of Array.isArray(orderBy) ? orderBy : [orderBy]) {\n if (entry === undefined) continue;\n // A select key can also be named asc or desc, so distinguish entries by their values, not their keys.\n if (isExpr(entry.asc) || isExpr(entry.desc)) {\n result.push(orderByToSql(entry, ctx));\n continue;\n }\n for (const [key, dir] of Object.entries(entry)) {\n if (dir === undefined) continue;\n // The direction is interpolated into the SQL, so never trust it, i.e. it might be a request param\n if (!ORDER_BY_DIRECTIONS.includes(dir as string)) return fail(`Invalid orderBy direction '${dir}'`);\n // Entity mode orders by the alias's column; POJO/subquery selects order by the output column name\n if (isAlias(select)) {\n const column = (select as any)[key];\n if (!isExpr(column)) return fail(`orderBy key '${key}' is not a sortable field of the entity`);\n const fragment = asNode(column).toSql(ctx);\n result.push({ ...fragment, sql: `${fragment.sql} ${dir}` });\n } else {\n if (isExpr(select)) return fail(`the keyed orderBy form needs a POJO or entity select`);\n const keys = isSubqueryValue(select) ? select[subqueryBrand].columnKeys() : Object.keys(select as object);\n if (!keys.includes(key)) return fail(`orderBy key '${key}' is not a key of select`);\n result.push({ sql: `${safeKq(key)} ${dir}`, bindings: [], refs: [] });\n }\n }\n }\n return result;\n}\n\nfunction orderByToSql(o: QueryOrderBy, ctx: Ctx): SqlFragment {\n const [expr, direction] = \"asc\" in o && o.asc ? [o.asc, \"ASC\"] : [o.desc, \"DESC\"];\n const fragment = asExpr(expr, \"orderBy\").toSql(ctx);\n // `nulls` is interpolated into the SQL, so never trust it, i.e. it might cross an `any` boundary\n if (o.nulls !== undefined && o.nulls !== \"first\" && o.nulls !== \"last\") {\n return fail(`Invalid orderBy nulls '${o.nulls}'`);\n }\n const nulls = o.nulls ? ` NULLS ${o.nulls.toUpperCase()}` : \"\";\n return { ...fragment, sql: `${fragment.sql} ${direction}${nulls}` };\n}\n\n/**\n * Parses a user-facing condition (a single condition or an `{ and }`/`{ or }` filter) with the same\n * `ConditionBuilder` `em.find` uses, so `undefined` members drop out, empty groups drop, and\n * `pruneIfUndefined` applies unchanged. Deferred (expression-vs-expression) conditions are resolved\n * against the context first.\n */\nfunction conditionToSql(cond: ExpressionCondition | undefined, ctx: Ctx, topLevel: boolean): SqlFragment | undefined {\n if (cond === undefined || cond === null) return undefined;\n resolveDeferredConditions(cond, ctx);\n const filter: ExpressionFilter = isFilter(cond) ? cond : { and: [cond] };\n const cb = new ConditionBuilder();\n cb.maybeAddExpression(filter);\n const parsed = cb.toExpressionFilter();\n if (!parsed) return undefined;\n const where = buildWhereClause(parsed, topLevel);\n if (!where) return undefined;\n return { sql: where[0], bindings: where[1], refs: refsOf(parsed, ctx) };\n}\n\nfunction isFilter(cond: ExpressionCondition): cond is ExpressionFilter {\n return (\"and\" in cond && cond.and !== undefined) || (\"or\" in cond && cond.or !== undefined);\n}\n\n/** The aliases a parsed condition tree references, with physical CTI aliases credited to their source. */\nfunction refsOf(parsed: ParsedExpressionFilter, ctx: Ctx): string[] {\n return deepFindConditions(parsed, false)\n .flatMap((c) => (c.kind === \"column\" ? [c.alias] : c.kind === \"raw\" ? c.aliases : c.outerAliases))\n .map((a) => ctx.ctiAliases.get(a) ?? a);\n}\n\n/**\n * Pruning: em.find's paradigm, on a flat join list.\n *\n * A condition given `undefined` was already dropped by `ConditionBuilder`. Now a join that nothing\n * references anymore drops with it: a join is required if the source, a select, a surviving condition,\n * a group-by, an order-by, or another required join's ON references it, or if it is pinned with\n * `keep: true`. Marking follows ON dependencies transitively, exactly like `pruneUnusedJoins`'s\n * `DependencyTracker`.\n *\n * em.find's joins almost never filter rows by themselves, so pruning them is semantics-preserving. An\n * explicit `{ inner: b, on }` here does filter rows, so pruning it when unreferenced drops that filter;\n * that matches `{ books: { title: undefined } }` in em.find and is deliberate. `keep: true` pins it, and\n * a pure existence filter is better written as `a.id.in(query({ ... }))`, which is never `undefined`.\n */\nfunction pruneJoins(q: AnyQuery, from: ParsedSource, joins: ParsedJoin[], used: SqlFragment[]): ParsedJoin[] {\n if (q.pruneJoins === false) return joins;\n const deps = new Map<string, string[]>();\n for (const j of joins) {\n const refs = [...(j.userOn?.refs ?? []), ...j.source.refs].filter((r) => r !== j.source.alias);\n deps.set(j.source.alias, refs);\n }\n const required = new Set<string>();\n function markRequired(alias: string): void {\n if (required.has(alias)) return;\n required.add(alias);\n for (const dep of deps.get(alias) ?? []) markRequired(dep);\n }\n markRequired(from.alias);\n for (const r of used.flatMap((u) => u.refs)) markRequired(r);\n for (const j of joins) if (j.keep) markRequired(j.source.alias);\n return joins.filter((j) => required.has(j.source.alias));\n}\n\nfunction asExpr(value: unknown, where: string): BaseExpr {\n if (isExpr(value)) return value as any as BaseExpr;\n return fail(\n `${where} must be an expression, i.e. an alias column, aggregate, sql\\`...\\`, or query(...); got ${value}`,\n );\n}\n\nfunction joinFragmentParts(parts: SqlFragment[], sep: string): SqlFragment {\n return { sql: parts.map((p) => p.sql).join(sep), bindings: parts.flatMap((p) => p.bindings), refs: [] };\n}\n\nfunction isDefined<T>(value: T | undefined): value is T {\n return value !== undefined;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"query.js","names":[],"sources":["../src/query.ts"],"sourcesContent":["import { AliasAssigner } from \"./AliasAssigner.ts\";\nimport {\n type Alias,\n type AliasBrand,\n type AliasMgmt,\n JoinTableHandle,\n type M2mJoinTable,\n aliasMgmt,\n collectionJoin,\n getAliasMetadata,\n getAliasMgmt,\n isAlias,\n m2mJoinTable,\n} from \"./Aliases.ts\";\nimport { ConditionBuilder } from \"./ConditionBuilder.ts\";\nimport { buildWhereClause } from \"./drivers/buildUtils.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type ExpressionCondition, type ExpressionFilter } from \"./EntityFilter.ts\";\nimport { type EntityMetadata, getBaseMeta } from \"./EntityMetadata.ts\";\nimport {\n BaseExpr,\n type Expr,\n type ExprBrand,\n type ExprContext,\n type ExprLike,\n type InnerJoin,\n type LeftJoin,\n RefExpr,\n type SqlFragment,\n TemplateExpr,\n asNode,\n deferredCondition,\n exprBrand,\n isExpr,\n resolveDeferredConditions,\n} from \"./Expr.ts\";\nimport { kq, kqStar, safeKq } from \"./keywords.ts\";\nimport { deepFindConditions } from \"./QueryParser.pruning.ts\";\nimport {\n type ColumnCondition,\n type ParsedExpressionFilter,\n type ParsedFindQuery,\n addTablePerClassJoinsAndClassTag,\n filterSoftDeletes,\n lazyExcludedSelects,\n stiSubtypeFilter,\n} from \"./QueryParser.ts\";\nimport { fail } from \"./utils.ts\";\n\n/**\n * `em.query`: SQL-shaped queries as plain object literals.\n *\n * A query is data, a `Query<S, J>` POJO, `{ from, join, where, groupBy, having, select, orderBy, ... }`\n * in SQL evaluation order:\n *\n * const [a, b] = aliases(Author, Book);\n * const bookStats = query({ from: b, groupBy: [b.author], select: { authorId: b.author, n: b.id.count() } });\n * const rows = await em.query({\n * from: a,\n * join: [{ left: bookStats, on: bookStats.authorId.eq(a.id) }],\n * select: { name: a.firstName, n: bookStats.n },\n * orderBy: { n: \"DESC\" },\n * });\n * // rows: { name: string; n: number | null }[] (null because of the LEFT join)\n *\n * `em.query(pojo)` runs it. `select` decides the row type: a bare alias returns entities, a\n * `{ key: expr }` object returns typed POJOs, a bare subquery returns that subquery's rows.\n *\n * `query(pojo)` turns the *same* POJO into a value: a derived table with typed columns, a scalar\n * expression, or an entity list. It is the one non-POJO step, and the subquery analog of `alias(Author)`:\n * to reference a query's columns, the outer query needs *values* for them, and no POJO can manufacture\n * values keyed off its own `select` keys.\n *\n * `alias()`/`aliases()` and `query()` are the only free functions a query needs, plus the `sql` tagged\n * template as the escape hatch for SQL with no modeled shape. Everything else is in-DSL: join kinds and\n * sort directions are keyword keys (`{ left: b, on }`, `{ desc: x }`), SQL functions are methods on\n * expressions (`b.id.count()`, `b.title.max()`, `x.coalesce(0)`), conditions are methods\n * (`a.age.gte(18)`), and pruning is `undefined`: an `undefined` condition drops out, and a join nothing\n * references anymore drops with it (see \"Pruning\" below).\n *\n * User documentation: `docs/src/content/docs/features/queries-raw.md`.\n */\n\n// =====================================================================================================\n// Sources, joins, clauses\n// =====================================================================================================\n\nexport const subqueryBrand: unique symbol = Symbol(\"joist.subquery\");\nexport const entityQueryBrand: unique symbol = Symbol(\"joist.entityQuery\");\n\n/** Phantom type information carried by a table-shaped subquery. */\nexport interface SubqueryBrand<R, Name extends string> {\n readonly __row: R;\n readonly __name: Name;\n}\n\n/** Anything that can be a source or be joined: an entity alias or a table-shaped subquery. */\nexport type QuerySource =\n | { readonly [aliasMgmt]: AliasBrand<any, string> }\n | { readonly [subqueryBrand]: SubqueryBrand<any, string> };\n\n/**\n * A join entry (see `InnerJoin`/`LeftJoin` in `Expr.ts`): the expanded `{ inner: b, on }` form, or the\n * entry a relation join factory returns (`a.books.as(b)`); joins to a subquery are always the expanded\n * form, since a subquery has no FK metadata.\n */\nexport type QueryJoin = InnerJoin<QuerySource> | LeftJoin<QuerySource>;\nexport type QueryJoins = readonly (QueryJoin | undefined)[];\n\n/**\n * An expression order-by entry: the direction is the key and the expression is the value, unlike\n * the keyed form's field name and `\"ASC\" | \"DESC\"` value. `never` on the other key keeps an\n * entry to one direction, the same trick `ExpressionFilter` uses for `and`/`or`. `nulls` is\n * `NULLS FIRST/LAST`.\n *\n * When select keys are known, exclude them so a keyed sort cannot be silently ignored inside an\n * expression entry. An untyped `Query` has no known keys to exclude.\n */\nexport type QueryOrderBy<S = never> = (\n | { readonly asc: ExprLike<any>; readonly desc?: never }\n | { readonly desc: ExprLike<any>; readonly asc?: never }\n) & { readonly nulls?: \"first\" | \"last\" } & (string extends OrderByKey<S>\n ? unknown\n : { readonly [K in Exclude<OrderByKey<S>, \"asc\" | \"desc\" | \"nulls\">]?: never });\n\nexport type OrderByDirection =\n | \"ASC\"\n | \"DESC\"\n | \"ASC NULLS FIRST\"\n | \"ASC NULLS LAST\"\n | \"DESC NULLS FIRST\"\n | \"DESC NULLS LAST\";\n\n/**\n * A keyed `orderBy` entry, used alone or in an array, like `em.find`'s `orderBy: [{ firstName: \"ASC\" }]`.\n *\n * The keys are the keys of a POJO/subquery `select` (rendered as SQL output-column names, so ordering\n * by an aggregate does not repeat its expression), or the entity's sortable fields in entity mode.\n * An `undefined` direction prunes the entry, like any other condition. For expressions that are not\n * in `select`, mix in `{ asc: expr }` / `{ desc: expr }` entries in the array form.\n */\nexport type OrderByKeys<S> = S extends { readonly [aliasMgmt]: { readonly __entity: infer T } }\n ? T extends Entity\n ? { readonly [K in keyof Alias<T> as Alias<T>[K] extends ExprLike<any> ? K : never]?: OrderByDirection | undefined }\n : never\n : S extends { readonly [exprBrand]: any }\n ? never\n : { readonly [K in keyof S & string]?: OrderByDirection | undefined };\n\n/** All sortable keys across select variants, not just the keys shared by every variant. */\ntype OrderByKey<S> = S extends unknown ? keyof OrderByKeys<S> : never;\n\n/** The three select shapes: entity mode, single-expression mode (scalar/list subqueries), and POJO mode. */\nexport type QuerySelect = QuerySource | ExprLike<any> | Record<string, ExprLike<any>>;\n\n/**\n * Everything but the source, in SQL evaluation order: FROM/JOIN, WHERE, GROUP BY, HAVING, SELECT,\n * ORDER BY, LIMIT.\n *\n * `S` and `J` are generic so callers keep the literal shape of `select` and `join`; the defaults let\n * a standalone object use `satisfies Query` (or `satisfies Clauses` for a source-less fragment).\n */\nexport interface Clauses<S extends QuerySelect = QuerySelect, J extends QueryJoins = QueryJoins> {\n join?: J;\n /** An `{ and: [...] }` / `{ or: [...] }` filter, or a single bare condition, i.e. `where: a.age.gte(18)`. */\n where?: ExpressionCondition;\n groupBy?: readonly ExprLike<any>[];\n having?: ExpressionCondition;\n select: S;\n orderBy?: readonly (QueryOrderBy<S> | OrderByKeys<S> | undefined)[] | OrderByKeys<S>;\n limit?: number;\n offset?: number;\n distinct?: boolean;\n /** Defaults to true. `false` keeps every join, em.find's opt-out. */\n pruneJoins?: boolean;\n /**\n * Defaults to `\"exclude\"`, em.find's rule: a soft-deletable entity in `from` gains a\n * `deleted_at IS NULL` condition in WHERE, and a joined one gains it in its join's ON (so a LEFT\n * join nulls its columns out instead of dropping rows). `\"include\"` turns the injection off for\n * this query; subqueries read their own key.\n */\n softDeletes?: \"include\" | \"exclude\";\n}\n\n/** A whole query: `Clauses` plus its source. `query(q)` turns it into a value; `em.query(q)` runs it. */\nexport interface Query<S extends QuerySelect = QuerySelect, J extends QueryJoins = QueryJoins> extends Clauses<S, J> {\n from: QuerySource;\n}\n\n// =====================================================================================================\n// Result-row types\n// =====================================================================================================\n\n/** The type-level name of an alias or subquery, i.e. `\"Author\"` or `\"book_stats\"`. */\nexport type NameOf<A> = A extends { readonly [aliasMgmt]: { readonly __name: infer N } }\n ? N\n : A extends { readonly [subqueryBrand]: { readonly __name: infer N } }\n ? N\n : never;\n\n/** The names of every alias that was LEFT JOINed; `X` is a naked type parameter so this distributes. */\ntype LeftJoined<X> = X extends LeftJoin<infer A> ? NameOf<A> : never;\n\n/**\n * Asks: is this expression's source key among the LEFT-joined sources in this query's join list? If\n * yes, the value can be `null`, so `R` becomes `R | null`; if no, `R` is unchanged.\n *\n * I.e. `MaybeNull<number, \"book_stats\", [LeftJoin<typeof bookStats>]>` is `number | null`,\n * because `book_stats` is in `LeftJoined<J[number]>`; with an inner join it stays `number`.\n *\n * Source-less expressions (`Src` is `never`, i.e. `b.id.count()`) are never nullified. Untracked ones\n * (`Src` is `string`, i.e. a `sql.ref` on an unknown table) might come from any left-joined table,\n * so they are conservatively nullified whenever the query has a left join at all.\n *\n * `string` must never be a *table's* name: `Extract<\"Author\", string>` matches, so one left-joined\n * table named `string` would nullify every column in the query. That is why anonymous subqueries\n * share the literal sentinel `\"?\"` instead.\n */\nexport type MaybeNull<R, Src extends string, J extends QueryJoins> = string extends Src\n ? [LeftJoined<J[number]>] extends [never]\n ? R\n : R | null\n : [Extract<Src, LeftJoined<J[number]>>] extends [never]\n ? R\n : R | null;\n\n/**\n * The result row for a query with select `S` and joins `J`.\n *\n * - entity mode (`select: a`) is the entity\n * - subquery mode (`select: bookStats`) is the subquery's row, i.e. `select *`\n * - single expression (`select: b.id.count()`) is that expression's value, used by scalar subqueries\n * - POJO mode is a mapped type over the select keys, with left-join nullability applied\n */\nexport type QueryRow<S, J extends QueryJoins = []> = S extends { readonly [aliasMgmt]: { readonly __entity: infer T } }\n ? T\n : S extends { readonly [subqueryBrand]: { readonly __row: infer R } }\n ? R\n : S extends { readonly [exprBrand]: ExprBrand<infer R, infer Src> }\n ? MaybeNull<R, Src, J>\n : {\n [K in keyof S]: S[K] extends { readonly [exprBrand]: ExprBrand<infer R, infer Src> }\n ? MaybeNull<R, Src, J>\n : never;\n };\n\n// =====================================================================================================\n// `query()`: a query POJO becomes a typed table, scalar, or entity list\n// =====================================================================================================\n\n/**\n * A table-shaped query: one `Expr` per select key, each tagged with the table's name as its `Src`,\n * plus a brand carrying the row type. This is the direct analog of `Alias<T>`: `Alias<T>` maps entity\n * fields to expressions, `Subquery<Row, Name>` maps the inner query's select keys to expressions.\n */\nexport type Subquery<R, Name extends string> = {\n readonly [subqueryBrand]: SubqueryBrand<R, Name>;\n} & { readonly [K in keyof R]: Expr<R[K], Name> };\n\n/** An entity-mode query (`select: a`): runnable, but it has no columns to reference. */\nexport type EntityQuery<T extends Entity> = { readonly [entityQueryBrand]: { readonly __row: T } };\n\n/**\n * Rejects a `select` that a `: Query` annotation widened to the whole `QuerySelect` union.\n *\n * `satisfies Query` checks the shape but keeps the literal type of `select`, so `S` infers as\n * `{ name: Expr<string, \"Author\"> }`. A `: Query` annotation replaces that type with the annotation, so\n * `S` infers as `QuerySelect` itself, and without this guard `query(q)` returned a useless union with no\n * error at all.\n *\n * A widened `S` is the only kind of `S` the whole `QuerySelect` union is assignable to (a POJO, an\n * `Expr`, or an `Alias` never is), so `QuerySelect extends S` detects it, and intersecting the parameter\n * with `{ select: \"<message>\" }` fails the call on `select` with that message, for `query()` and\n * `em.query()` alike:\n *\n * const narrow = { from: a, select: { name: a.firstName } } satisfies Query;\n * query(narrow); // Subquery<{ name: string }, \"?\">\n *\n * const widened: Query = { from: a, select: { name: a.firstName } };\n * query(widened);\n * // error: Type 'QuerySelect' is not assignable to type\n * // '\"select was typed too generically; use `satisfies Query` instead of `: Query`\"'\n *\n * `S` also defaults to `never`, so a *missing* `select` is reported as \"Property 'select' is missing\"\n * against `Query<never, []>` instead of tripping this guard.\n */\nexport type NotWidened<S> = QuerySelect extends S\n ? { select: \"select was typed too generically; use `satisfies Query` instead of `: Query`\" }\n : unknown;\n\n/** What `query()` returns, by select shape: an entity list, a scalar/list subquery, or a derived table. */\nexport type QueryValue<S, J extends QueryJoins, Name extends string> = S extends {\n readonly [aliasMgmt]: { readonly __entity: infer T extends Entity };\n}\n ? EntityQuery<T>\n : S extends { readonly [exprBrand]: ExprBrand<infer R, any> }\n ? Expr<R | null, never>\n : Subquery<QueryRow<S, J>, Name>;\n\n/** The names of every alias in scope for a query: the source alias plus every joined alias. */\ntype JoinedName<X> = X extends { readonly inner: infer A }\n ? NameOf<A>\n : X extends { readonly left: infer A }\n ? NameOf<A>\n : never;\ntype InScope<F, J extends QueryJoins> = NameOf<F> | JoinedName<J[number]>;\n\n/**\n * Asks, for every column of a POJO select: is its source key among `from` + `join` at all? If no, the\n * query reads from a table it never joined, and that select key's type becomes an error message.\n *\n * Because `Expr` already carries `Src`, this is nearly free: for each select key, if `Src` is tracked\n * and any of its names is outside `InScope`, intersect that key's type with an error string, so the\n * caller sees `Type 'Expr<number, \"book_stats\">' is not assignable to type '... is not in from/join'`.\n * Untracked (`string`) and source-less (`never`) expressions always pass. Aliases with the same\n * type-level name (two bare `alias(Author)`, or two anonymous tables) cannot be told apart, so a miss\n * there goes unreported; the check never gives a false positive, only false negatives on collisions.\n *\n * `[S] extends [...]` keeps this non-distributive, and `never` is skipped outright: `query()` defaults\n * `S` to `never` when `select` is missing, and a distributive conditional over `never` would swallow the\n * whole parameter type.\n */\nexport type CheckScope<S, F, J extends QueryJoins> = [S] extends [never]\n ? unknown\n : // A source-shaped select (`select: a`, `select: bookStats`) must be the `from`: a joined source's\n // rows would need left-join nullability (and entity hydration) that source-shaped selects don't\n // model. Two same-named sources (unnamed aliases of one entity, anonymous subqueries) pass this\n // check and are caught at runtime instead.\n [S] extends [QuerySource]\n ? NameOf<S> extends NameOf<F>\n ? unknown\n : { select: `'${NameOf<S> & string}' is a joined source, not the from; select its columns individually` }\n : [S] extends [Record<string, ExprLike<any>>]\n ? {\n select: {\n [K in keyof S]: S[K] extends { readonly [exprBrand]: ExprBrand<any, infer Src> }\n ? string extends Src\n ? unknown\n : [Exclude<Src, InScope<F, J>>] extends [never]\n ? unknown\n : `alias '${Exclude<Src, InScope<F, J>> & string}' is not in from/join`\n : unknown;\n };\n }\n : unknown;\n\n/** The one argument type `query()` and `em.query()` share: a `Query` POJO plus its source, name, and checks. */\nexport type QueryArg<F extends QuerySource, S extends QuerySelect, J extends QueryJoins, Name extends string> = Query<\n S,\n J\n> & {\n from: F;\n as?: Name;\n} & CheckScope<S, F, J> &\n NotWidened<S>;\n\n/**\n * Turns a `Query` POJO into a value. The select shape decides which (`QueryValue`):\n *\n * - a single expression is a scalar subquery or an IN list (`Expr<R | null>`; a scalar subquery can\n * return no row, so use `.coalesce(0)` when the SQL guarantees a value, i.e. an ungrouped `count`)\n * - an entity alias is an entity list, runnable via `em.query`\n * - a POJO is a derived table whose columns are `Expr`s; it can be a source, be joined, or be run\n *\n * `as` is the SQL alias and the type-level identity, the same role the second argument of\n * `alias(Author, \"m\")` plays. Without it the SQL alias is generated, like `alias(Author)`, and all\n * anonymous tables share the type-level identity `\"?\"`: precise against every named alias, and\n * conservative (a left-joined anonymous table nullifies every anonymous table's columns) only among\n * themselves. This is the same collision two bare `alias(Author)` have.\n *\n * One signature, not three overloads: overloads wrapped every clauses-object mistake in \"No overload\n * matches this call\", hid `as` from completions, and cost 15-28% check time; the one thing they did\n * better, rejecting a `select` widened by a `: Query` annotation, `NotWidened` does with a clearer message.\n */\nexport function query<\n F extends QuerySource,\n S extends QuerySelect = never,\n J extends QueryJoins = [],\n Name extends string = \"?\",\n>(q: QueryArg<F, S, J, Name>): QueryValue<S, J, Name> {\n const handle = new SubqueryHandle(q as AnyQuery);\n const select = (q as AnyQuery).select;\n if (isAlias(select)) {\n return { [entityQueryBrand]: handle } as any;\n } else if (isExpr(select)) {\n return new SubqueryExpr(handle) as any;\n } else {\n return newSubqueryProxy(handle) as any;\n }\n}\n\n/**\n * Builds a SQL expression from a tagged template.\n *\n * For an Author alias `a` assigned the SQL alias `a1`:\n *\n * ```ts\n * sql`${a.age} * 2` // Expression: a1.age * 2\n * sql`${a.age.gte(18)}` // Condition: (a1.age >= ?), bindings [18]\n * sql`${\"Alice\"}` // Value: ?, bindings [\"Alice\"]\n *\n * // Selecting this expression keeps the join to Book b.\n * sql<number>`${b.order} * ${2}`\n *\n * // Reference an unmodeled column; it is untracked at the type level.\n * sql.ref<string>(a, \"ts_search\")\n * sql.condition`${sql.ref(a, \"ts_search\")} @@ plainto_tsquery(${term})`\n * ```\n */\nexport function sql<R = unknown>(strings: TemplateStringsArray, ...values: unknown[]): Expr<R, never> {\n return new TemplateExpr(strings, values) as any;\n}\n\n/** A raw condition for `where`, `having`, or `on`. */\nsql.condition = function condition(strings: TemplateStringsArray, ...values: unknown[]): ExpressionCondition {\n return deferredCondition((ctx) => new TemplateExpr(strings, values).toSql(ctx));\n};\n\n/** A column Joist does not model, on a source that is in the query. */\nsql.ref = function ref<R = unknown>(source: QuerySource, column: string): Expr<R, string> {\n return new RefExpr(handleOf(source), column) as any;\n};\n\n/**\n * Parses `arg` (a `Query` POJO or `query(...)` value) into a runnable `Plan`.\n *\n * `EntityManager.query` runs the plan; this module deliberately does not import `EntityManager` (see\n * `EntityHydrator`), so it parses and hands back `{ sql, bindings, decodeRows }` instead of executing.\n */\nexport function parseUserQuery(arg: unknown): Plan {\n return parseQuery(toQuery(arg), undefined, new AliasAssigner());\n}\n\n/**\n * The one `EntityManager` capability that row decoding needs, typed structurally.\n *\n * Importing `EntityManager.ts` here would complete an `EntityManager.ts` <-> `query.ts` declaration\n * cycle (`EntityManager.query` imports this module's types), which correlated with a tsc 7.0.2\n * incremental-build bug: after tsdown rewrites `build/`, `tsc --build` sporadically reports thousands\n * of phantom \"Module 'joist-orm' has no exported member ...\" errors and caches them in `.tsbuildinfo`.\n */\nexport interface EntityHydrator {\n hydrate(cstr: any, rows: readonly any[]): any[];\n}\n\nexport interface Plan {\n sql: string;\n bindings: any[];\n /** Aliases of enclosing queries this (sub)query referenced. */\n outerRefs: string[];\n decodeRows(em: EntityHydrator, rows: any[]): any[];\n}\n\n// =====================================================================================================\n// Runtime: handles, subquery expressions, the proxy\n// =====================================================================================================\n\ntype AnyQuery = Query<any, any> & { as?: string };\n\n/** The runtime identity of a `query(...)` value; `Ctx.aliasFor` keys on it, like an alias's `AliasMgmt`. */\nexport class SubqueryHandle {\n constructor(readonly q: AnyQuery) {}\n\n get name(): string | undefined {\n return this.q.as;\n }\n\n /** The select keys, for `select: <subquery>` and for reporting unknown columns. */\n columnKeys(): string[] {\n const { select } = this.q;\n if (isPlainSelect(select)) return Object.keys(select);\n if (isSubqueryValue(select)) return select[subqueryBrand].columnKeys();\n return fail(`A subquery with an entity or scalar select has no columns`);\n }\n\n /** The inner expression behind `key`, for its decoder/encoder. */\n columnExpr(key: string): BaseExpr {\n const { select } = this.q;\n if (isPlainSelect(select)) {\n return (select[key] as any as BaseExpr) ?? fail(`Subquery ${this.describe()} has no column ${key}`);\n } else if (isSubqueryValue(select)) {\n return select[subqueryBrand].columnExpr(key);\n }\n return fail(`Subquery ${this.describe()} has no columns`);\n }\n\n column(key: string): SubqueryColumnExpr {\n return new SubqueryColumnExpr(this, key, this.columnExpr(key));\n }\n\n describe(): string {\n return this.q.as ? `'${this.q.as}'` : \"(anonymous)\";\n }\n}\n\n/** A column of a joined/from'd subquery, i.e. `bookStats.bookCount`, which becomes `book_stats.\"bookCount\"`. */\nclass SubqueryColumnExpr extends BaseExpr {\n constructor(\n private handle: SubqueryHandle,\n private key: string,\n private inner: BaseExpr,\n ) {\n super();\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const alias = ctx.aliasFor(this.handle);\n // safeKq for the alias too: a subquery's canonical alias is its user-provided `as` name\n return { sql: `${safeKq(alias)}.${safeKq(this.key)}`, bindings: [], refs: [alias] };\n }\n\n decode(value: unknown): unknown {\n return this.inner.decode(value);\n }\n\n encode(value: unknown): unknown {\n return this.inner.encode(value);\n }\n}\n\n/**\n * A scalar (or IN-list) subquery, i.e. `query({ from: b, where: [...], select: b.id.count() })`.\n *\n * It closes over the outer aliases it references, so correlation is free; those references are the\n * subquery's \"free\" aliases and count toward the outer query's join pruning.\n */\nclass SubqueryExpr extends BaseExpr {\n constructor(readonly handle: SubqueryHandle) {\n super();\n }\n\n get subquerySelect(): BaseExpr {\n return asNode(this.handle.q.select);\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const bare = this.toSqlBare(ctx);\n return { ...bare, sql: `(${bare.sql})` };\n }\n\n toSqlBare(ctx: ExprContext): SqlFragment {\n const parent = ctx instanceof Ctx ? ctx : fail(\"Subqueries need the query parser's context\");\n const plan = parseQuery(this.handle.q, parent, parent.assigner);\n return { sql: plan.sql, bindings: plan.bindings, refs: plan.outerRefs };\n }\n\n decode(value: unknown): unknown {\n return this.subquerySelect.decode(value);\n }\n\n encode(value: unknown): unknown {\n return this.subquerySelect.encode(value);\n }\n}\n\nfunction newSubqueryProxy(handle: SubqueryHandle): object {\n return new Proxy(\n {},\n {\n get(_, key) {\n if (key === subqueryBrand) return handle;\n if (typeof key === \"string\") return handle.column(key);\n return undefined;\n },\n has(_, key) {\n return key === subqueryBrand || (typeof key === \"string\" && handle.columnKeys().includes(key));\n },\n },\n );\n}\n\nfunction isSubqueryValue(value: unknown): value is { [subqueryBrand]: SubqueryHandle } {\n return typeof value === \"object\" && value !== null && subqueryBrand in value;\n}\n\nfunction isEntityQueryValue(value: unknown): value is { [entityQueryBrand]: SubqueryHandle } {\n return typeof value === \"object\" && value !== null && entityQueryBrand in value;\n}\n\nfunction isPlainSelect(select: unknown): select is Record<string, ExprLike<any>> {\n return (\n typeof select === \"object\" && select !== null && !isAlias(select) && !isExpr(select) && !isSubqueryValue(select)\n );\n}\n\n/** Returns the runtime identity of a source: an alias's `AliasMgmt` or a subquery's handle. */\nfunction handleOf(source: unknown): AliasMgmt | SubqueryHandle {\n if (isAlias(source)) return getAliasMgmt(source);\n if (isSubqueryValue(source)) return source[subqueryBrand];\n return fail(`Expected an alias or a query(...) value, got ${source}`);\n}\n\n// =====================================================================================================\n// Runtime: parse -> prune -> SQL -> decode\n// =====================================================================================================\n\nfunction toQuery(arg: unknown): AnyQuery {\n if (isSubqueryValue(arg)) return arg[subqueryBrand].q;\n if (isEntityQueryValue(arg)) return arg[entityQueryBrand].q;\n if (arg instanceof SubqueryExpr) return arg.handle.q;\n if (typeof arg === \"object\" && arg !== null && \"from\" in arg && \"select\" in arg) return arg as AnyQuery;\n return fail(`em.query expects a { from, select, ... } object or a query(...) value`);\n}\n\n/**\n * What an expression needs from the query it is generating SQL for.\n *\n * Each (sub)query gets its own `Ctx`; a lookup that misses locally walks up to the enclosing query and\n * records the hit in `outerRefs`, which is how a correlated subquery reports the outer aliases it\n * depends on (the way `ExistsCondition.outerAliases` does), so join pruning keeps them.\n */\nclass Ctx implements ExprContext {\n private aliases = new Map<object, string>();\n readonly outerRefs = new Set<string>();\n /** Physical CTI table aliases (`sp_b0`) to their source alias (`sp`), shared across the whole parse. */\n readonly ctiAliases: Map<string, string>;\n\n constructor(\n readonly assigner: AliasAssigner,\n private parent: Ctx | undefined,\n ) {\n this.ctiAliases = parent?.ctiAliases ?? new Map();\n }\n\n register(handle: object, alias: string): void {\n this.aliases.set(handle, alias);\n }\n\n aliasFor(handle: object): string {\n const local = this.aliases.get(handle);\n if (local) return local;\n if (this.parent) {\n const outer = this.parent.aliasFor(handle);\n this.outerRefs.add(outer);\n return outer;\n }\n return fail(`${describeHandle(handle)} is not in this query's from/join`);\n }\n\n conditionToSql(cond: ExpressionCondition): SqlFragment | undefined {\n // Inside another expression (i.e. a `sql` template), keep `a OR b` grouped\n return conditionToSql(cond, this, false);\n }\n}\n\nfunction describeHandle(handle: object): string {\n if (handle instanceof SubqueryHandle) return `Subquery ${handle.describe()}`;\n if (handle instanceof JoinTableHandle) return `Join table ${handle.joinTableName}`;\n if (\"tableName\" in handle) return `Alias for ${(handle as AliasMgmt).tableName}`;\n return \"Alias\";\n}\n\ninterface ParsedSource {\n handle: AliasMgmt | SubqueryHandle | JoinTableHandle;\n alias: string;\n /** `table AS alias` or `(SELECT ...) AS alias`. */\n sql: string;\n bindings: any[];\n /** Outer aliases a derived table references; PG rejects those without LATERAL, but pruning should still see them. */\n refs: string[];\n /** CTI base/sub-table joins that travel with an entity alias. */\n extraJoins: string[];\n /** Entity-mode selects, i.e. `a.*` plus CTI columns and the `__class` tag. */\n entitySelects: string[];\n meta: EntityMetadata | undefined;\n}\n\ninterface ParsedJoin {\n kind: \"inner\" | \"left\";\n source: ParsedSource;\n /** The user's ON alone; `undefined` means it pruned away entirely, an error if the join is kept. */\n userOn: SqlFragment | undefined;\n /** The ON to emit: the user's ON plus any injected soft-delete/STI-discriminator conditions. */\n fullOn: SqlFragment | undefined;\n keep: boolean;\n}\n\n/**\n * Parses one `Query` POJO into SQL, recursively for subqueries.\n *\n * 1. Register every source's runtime identity with its SQL alias in this parse's context.\n * 2. Generate SQL for sources, selects, conditions, group-bys, and order-bys against the context; every fragment\n * reports the aliases it references.\n * 3. Prune: drop joins nothing references (see below), then reject a kept join whose ON collapsed.\n * 4. Assemble the SQL from the kept fragments, so pruned bindings disappear with their SQL.\n */\nfunction parseQuery(q: AnyQuery, parent: Ctx | undefined, assigner: AliasAssigner): Plan {\n const ctx = new Ctx(assigner, parent);\n const selectedAlias = isAlias(q.select) ? getAliasMgmt(q.select) : undefined;\n const joinEntries = [...(q.join ?? [])].filter(isDefined);\n\n // 1. Register every source before generating SQL, so conditions can resolve their aliases.\n const parseFrom = registerSource(q.from, ctx, assigner, handleOf(q.from) === selectedAlias);\n const pendingJoins = joinEntries.flatMap((j) => {\n const kind = \"inner\" in j && j.inner ? (\"inner\" as const) : (\"left\" as const);\n const alias = kind === \"inner\" ? j.inner : j.left;\n const keep = j.keep ?? false;\n // Only collection sugar joins (o2m/m2m) filter soft-deletes, em.find's relation semantics:\n // references (m2o/o2o/poly) resolve soft-deleted entities, and explicit joins are the user's own\n const softDeletes = (j as any)[collectionJoin] === true;\n const target = { kind, keep, on: j.on, softDeletes, parseSource: registerSource(alias, ctx, assigner, false) };\n // A sugar m2m join (`a.tags.as(t)`) carries a hidden join-table join; emit it first, with the same kind\n const m2m: M2mJoinTable | undefined = (j as any)[m2mJoinTable];\n if (!m2m) return [target];\n return [\n { kind, keep, on: m2m.on, softDeletes: false, parseSource: registerJoinTable(m2m.handle, ctx, assigner) },\n target,\n ];\n });\n\n // 2. Generate SQL.\n const softDeletes = q.softDeletes ?? \"exclude\";\n const from = parseFrom();\n const joins: ParsedJoin[] = pendingJoins.map((j) => {\n const source = j.parseSource();\n // `userOn` is the user's ON alone, so the collapsed-ON check below is not fooled by injections\n const userOn = conditionToSql(j.on, ctx, true);\n const injected = injectedConditions(source, j.softDeletes ? softDeletes : \"include\");\n const fullOn = userOn && injected.length > 0 ? conditionToSql({ and: [j.on, ...injected] }, ctx, true) : userOn;\n return { kind: j.kind, keep: j.keep, source, userOn, fullOn };\n });\n const { selects, decodeRows } = selectsToSql(q, ctx, from);\n const fromInjected = injectedConditions(from, softDeletes);\n const where = conditionToSql(fromInjected.length > 0 ? { and: [q.where, ...fromInjected] } : q.where, ctx, true);\n const having = conditionToSql(q.having, ctx, true);\n const groupBys = (q.groupBy ?? []).map((g) => asExpr(g, \"groupBy\").toSql(ctx));\n const orderBys = orderBysToSql(q, ctx);\n\n // 3. Prune.\n const kept = pruneJoins(q, from, joins, [...selects, ...groupBys, ...orderBys, where, having].filter(isDefined));\n // Joins emit in declaration order, so an ON may only reference sources declared before it; a forward\n // reference would reach PG as invalid SQL (\"missing FROM-clause entry\"). Reordering is not offered:\n // it is not semantics-preserving once INNER and LEFT joins mix, and the caller's fix is trivial.\n const laterAliases = new Set(kept.map((j) => j.source.alias));\n for (const j of kept) {\n if (!j.userOn) {\n fail(\n `Join ${describeHandle(j.source.handle)} has no ON condition left (they all pruned), but the query still references it`,\n );\n }\n laterAliases.delete(j.source.alias);\n const forward = j.fullOn!.refs.find((r) => laterAliases.has(r));\n if (forward) {\n fail(\n `Join ${describeHandle(j.source.handle)} references '${forward}', which is joined later; move that join earlier in the join array`,\n );\n }\n }\n\n // 4. Assemble.\n const out: SqlFragment[] = [];\n out.push({ sql: `SELECT ${q.distinct ? \"DISTINCT \" : \"\"}`, bindings: [], refs: [] });\n out.push(joinFragmentParts(selects, \", \"));\n out.push({ sql: ` FROM ${from.sql}`, bindings: from.bindings, refs: [] });\n for (const extra of from.extraJoins) out.push({ sql: ` ${extra}`, bindings: [], refs: [] });\n for (const j of kept) {\n const keyword = j.kind === \"inner\" ? \"JOIN\" : \"LEFT OUTER JOIN\";\n // A CTI subtype's physical base-table joins go *inside* a parenthesized join item: the ON can\n // reference the base alias (i.e. `sp.id` renders as `sp_b0.id`), so the subtree must join first\n const source = j.source.extraJoins.length > 0 ? `(${j.source.sql} ${j.source.extraJoins.join(\" \")})` : j.source.sql;\n out.push({\n sql: ` ${keyword} ${source} ON ${j.fullOn!.sql}`,\n bindings: [...j.source.bindings, ...j.fullOn!.bindings],\n refs: [],\n });\n }\n if (where) out.push({ sql: ` WHERE ${where.sql}`, bindings: where.bindings, refs: [] });\n if (groupBys.length > 0)\n out.push({ ...joinFragmentParts(groupBys, \", \"), sql: ` GROUP BY ${groupBys.map((g) => g.sql).join(\", \")}` });\n if (having) out.push({ sql: ` HAVING ${having.sql}`, bindings: having.bindings, refs: [] });\n if (orderBys.length > 0)\n out.push({ ...joinFragmentParts(orderBys, \", \"), sql: ` ORDER BY ${orderBys.map((o) => o.sql).join(\", \")}` });\n if (q.limit !== undefined) out.push({ sql: ` LIMIT ?`, bindings: [q.limit], refs: [] });\n if (q.offset !== undefined) out.push({ sql: ` OFFSET ?`, bindings: [q.offset], refs: [] });\n\n return {\n sql: out.map((o) => o.sql).join(\"\"),\n bindings: out.flatMap((o) => o.bindings),\n outerRefs: [...ctx.outerRefs],\n decodeRows,\n };\n}\n\n/**\n * Assigns a SQL alias to a source and returns a function that parses it after all sources are registered.\n *\n * Conditions resolve source identities through the context when their SQL is generated. CTI entities\n * get their base/sub-table joins from `addTablePerClassJoinsAndClassTag`, and the entity-mode `select`\n * gets that helper's selects too.\n */\nfunction registerSource(source: unknown, ctx: Ctx, assigner: AliasAssigner, isPrimary: boolean): () => ParsedSource {\n const handle = handleOf(source);\n if (handle instanceof SubqueryHandle) {\n const alias = handle.name ? assigner.getLiteralAlias(handle.name) : assigner.getLiteralAlias(\"sq\");\n ctx.register(handle, alias);\n return () => {\n const inner = parseQuery(handle.q, ctx, assigner);\n return {\n handle,\n alias,\n sql: `(${inner.sql}) AS ${safeKq(alias)}`,\n bindings: inner.bindings,\n refs: inner.outerRefs,\n extraJoins: [],\n entitySelects: [],\n meta: undefined,\n };\n };\n } else {\n const meta = getAliasMetadata(source as any);\n const alias = assigner.getAlias(meta.tableName);\n ctx.register(handle, alias);\n // Record the physical CTI table aliases this source emits (i.e. `sp_b0`), so `refsOf` can credit\n // their refs to this alias exactly; a user subquery named `book_b0` must not be mistaken for one\n if (meta.inheritanceType === \"cti\") {\n meta.baseTypes.forEach((_, i) => ctx.ctiAliases.set(`${alias}_b${i}`, alias));\n if (isPrimary) meta.subTypes.forEach((_, i) => ctx.ctiAliases.set(`${alias}_s${i}`, alias));\n }\n return () => {\n const cti: ParsedFindQuery = { selects: [], tables: [], orderBys: [] };\n addTablePerClassJoinsAndClassTag(cti, meta, alias, isPrimary);\n const extraJoins = cti.tables.map((t) => {\n if (t.join !== \"outer\") return fail(`Unexpected ${t.join} join for CTI`);\n return `LEFT OUTER JOIN ${kq(t.table)} AS ${kq(t.alias)} ON ${t.col1} = ${t.col2}`;\n });\n // Entity mode starts with the primary table's own columns (excluding lazy ones, like em.find)\n // and *appends* the CTI base/sub-table columns and the __class tag; the CTI selects alone would\n // drop the selected table's own fields, i.e. a Publisher would hydrate with an undefined name\n const primarySelects = meta.hasLazyColumns ? lazyExcludedSelects(meta, alias) : [kqStar(alias)];\n const entitySelects = [...primarySelects, ...(cti.selects as string[])];\n return {\n handle,\n alias,\n sql: `${kq(meta.tableName)} AS ${kq(alias)}`,\n bindings: [],\n refs: [],\n extraJoins,\n entitySelects,\n meta,\n };\n };\n }\n}\n\n/**\n * em.find's per-source injections: `alias.deleted_at IS NULL` for a soft-deletable entity (CTI\n * subtypes are skipped, like em.find; see `filterSoftDeletes`), and the `type_id = X` discriminator\n * for an STI subtype, so `from: alias(TaskNew)` only sees (and a joined subtype only matches)\n * TaskNew rows.\n *\n * The conditions go into the from's WHERE or the join's ON, and never keep an otherwise unreferenced\n * join alive, which is what `pruneable: true` means on em.find's side.\n */\nfunction injectedConditions(source: ParsedSource, softDeletes: \"include\" | \"exclude\"): ColumnCondition[] {\n const { meta } = source;\n if (!meta) return [];\n const conditions: ColumnCondition[] = [];\n if (filterSoftDeletes(meta, softDeletes)) {\n const field = meta.allFields[getBaseMeta(meta).timestampFields!.deletedAt!];\n const column = field.serde!.columns[0];\n conditions.push({\n kind: \"column\",\n alias: `${source.alias}${field.aliasSuffix}`,\n column: column.columnName,\n dbType: column.dbType,\n cond: { kind: \"is-null\" },\n pruneable: true,\n });\n }\n const sti = stiSubtypeFilter(meta, source.alias);\n if (sti) conditions.push(sti);\n return conditions;\n}\n\n/** Registers a sugar m2m join table, i.e. `authors_to_tags`: a raw table with no entity metadata. */\nfunction registerJoinTable(handle: JoinTableHandle, ctx: Ctx, assigner: AliasAssigner): () => ParsedSource {\n const alias = assigner.getAlias(handle.joinTableName);\n ctx.register(handle, alias);\n return () => ({\n handle,\n alias,\n sql: `${kq(handle.joinTableName)} AS ${kq(alias)}`,\n bindings: [],\n refs: [],\n extraJoins: [],\n entitySelects: [],\n meta: undefined,\n });\n}\n\n/** Generates the `select` clause SQL and returns how to decode the resulting rows. */\nfunction selectsToSql(\n q: AnyQuery,\n ctx: Ctx,\n from: ParsedSource,\n): { selects: SqlFragment[]; decodeRows: Plan[\"decodeRows\"] } {\n const { select } = q;\n if (isAlias(select)) {\n // Entity mode: `a.*` (plus CTI columns), hydrated through the identity map. Only the from is\n // hydratable: a joined alias would need null-row skipping and left-join nullability (see TODO.md)\n if (from.handle !== getAliasMgmt(select)) {\n fail(\"Selecting a joined alias is not supported yet; select the from alias, or select its columns individually\");\n }\n const alias = ctx.aliasFor(getAliasMgmt(select));\n const meta = getAliasMetadata(select);\n const selects = from.entitySelects.map((s) => ({ sql: s, bindings: [], refs: [alias] }));\n return { selects, decodeRows: (em, rows) => em.hydrate(meta.cstr as any, rows) };\n } else if (isSubqueryValue(select)) {\n // `select: <subquery>` is `select *` for that table; like entity mode, only for the from, since a\n // left-joined subquery's unmatched rows would decode null fields the row type calls non-null\n const handle = select[subqueryBrand];\n if (from.handle !== handle) {\n fail(\n \"Selecting a joined subquery is not supported; select the from subquery, or select its columns individually\",\n );\n }\n const alias = ctx.aliasFor(handle);\n const keys = handle.columnKeys();\n const selects = keys.map((k) => ({\n sql: `${safeKq(alias)}.${safeKq(k)} AS ${safeKq(k)}`,\n bindings: [],\n refs: [alias],\n }));\n const decoders = keys.map((k) => [k, handle.columnExpr(k)] as const);\n return { selects, decodeRows: (_, rows) => rows.map((row) => decodeRow(row, decoders)) };\n } else if (isExpr(select)) {\n // Scalar mode: one value per row, used by scalar/IN-list subqueries\n const fragment = asNode(select).toSql(ctx);\n const selects = [{ ...fragment, sql: `${fragment.sql} AS value` }];\n return { selects, decodeRows: (_, rows) => rows.map((row) => asNode(select).decode(row.value)) };\n } else if (isPlainSelect(select)) {\n // POJO mode\n const entries = Object.entries(select).map(([key, expr]) => [key, asExpr(expr, `select.${key}`)] as const);\n const selects = entries.map(([key, expr]) => {\n const fragment = expr.toSql(ctx);\n return { ...fragment, sql: `${fragment.sql} AS ${safeKq(key)}` };\n });\n return { selects, decodeRows: (_, rows) => rows.map((row) => decodeRow(row, entries)) };\n }\n return fail(`Unsupported select ${select}`);\n}\n\nfunction decodeRow(row: any, decoders: readonly (readonly [string, BaseExpr])[]): any {\n const result: any = {};\n for (const [key, expr] of decoders) {\n const value = row[key];\n result[key] = value === null || value === undefined ? null : expr.decode(value);\n }\n return result;\n}\n\nconst ORDER_BY_DIRECTIONS: string[] = [\n \"ASC\",\n \"DESC\",\n \"ASC NULLS FIRST\",\n \"ASC NULLS LAST\",\n \"DESC NULLS FIRST\",\n \"DESC NULLS LAST\",\n];\n\n/**\n * Generates ORDER BY SQL in entry order for keyed/expression arrays or a single keyed object.\n *\n * Expression entries retain bindings and alias references for join pruning. Undefined entries and\n * directions are omitted.\n */\nfunction orderBysToSql(q: AnyQuery, ctx: Ctx): SqlFragment[] {\n const { orderBy, select } = q;\n if (!orderBy) return [];\n const result: SqlFragment[] = [];\n for (const entry of Array.isArray(orderBy) ? orderBy : [orderBy]) {\n if (entry === undefined) continue;\n // A select key can also be named asc or desc, so distinguish entries by their values, not their keys.\n if (isExpr(entry.asc) || isExpr(entry.desc)) {\n result.push(orderByToSql(entry, ctx));\n continue;\n }\n for (const [key, dir] of Object.entries(entry)) {\n if (dir === undefined) continue;\n // The direction is interpolated into the SQL, so never trust it, i.e. it might be a request param\n if (!ORDER_BY_DIRECTIONS.includes(dir as string)) return fail(`Invalid orderBy direction '${dir}'`);\n // Entity mode orders by the alias's column; POJO/subquery selects order by the output column name\n if (isAlias(select)) {\n const column = (select as any)[key];\n if (!isExpr(column)) return fail(`orderBy key '${key}' is not a sortable field of the entity`);\n const fragment = asNode(column).toSql(ctx);\n result.push({ ...fragment, sql: `${fragment.sql} ${dir}` });\n } else {\n if (isExpr(select)) return fail(`the keyed orderBy form needs a POJO or entity select`);\n const keys = isSubqueryValue(select) ? select[subqueryBrand].columnKeys() : Object.keys(select as object);\n if (!keys.includes(key)) return fail(`orderBy key '${key}' is not a key of select`);\n result.push({ sql: `${safeKq(key)} ${dir}`, bindings: [], refs: [] });\n }\n }\n }\n return result;\n}\n\nfunction orderByToSql(o: QueryOrderBy, ctx: Ctx): SqlFragment {\n const [expr, direction] = \"asc\" in o && o.asc ? [o.asc, \"ASC\"] : [o.desc, \"DESC\"];\n const fragment = asExpr(expr, \"orderBy\").toSql(ctx);\n // `nulls` is interpolated into the SQL, so never trust it, i.e. it might cross an `any` boundary\n if (o.nulls !== undefined && o.nulls !== \"first\" && o.nulls !== \"last\") {\n return fail(`Invalid orderBy nulls '${o.nulls}'`);\n }\n const nulls = o.nulls ? ` NULLS ${o.nulls.toUpperCase()}` : \"\";\n return { ...fragment, sql: `${fragment.sql} ${direction}${nulls}` };\n}\n\n/**\n * Parses a user-facing condition (a single condition or an `{ and }`/`{ or }` filter) with the same\n * `ConditionBuilder` `em.find` uses, so `undefined` members drop out, empty groups drop, and\n * `pruneIfUndefined` applies unchanged. Deferred (expression-vs-expression) conditions are resolved\n * against the context first.\n */\nfunction conditionToSql(cond: ExpressionCondition | undefined, ctx: Ctx, topLevel: boolean): SqlFragment | undefined {\n if (cond === undefined || cond === null) return undefined;\n resolveDeferredConditions(cond, ctx);\n const filter: ExpressionFilter = isFilter(cond) ? cond : { and: [cond] };\n const cb = new ConditionBuilder();\n cb.maybeAddExpression(filter);\n const parsed = cb.toExpressionFilter();\n if (!parsed) return undefined;\n const where = buildWhereClause(parsed, topLevel);\n if (!where) return undefined;\n return { sql: where[0], bindings: where[1], refs: refsOf(parsed, ctx) };\n}\n\nfunction isFilter(cond: ExpressionCondition): cond is ExpressionFilter {\n return (\"and\" in cond && cond.and !== undefined) || (\"or\" in cond && cond.or !== undefined);\n}\n\n/** The aliases a parsed condition tree references, with physical CTI aliases credited to their source. */\nfunction refsOf(parsed: ParsedExpressionFilter, ctx: Ctx): string[] {\n return deepFindConditions(parsed, false)\n .flatMap((c) => (c.kind === \"column\" ? [c.alias] : c.kind === \"raw\" ? c.aliases : c.outerAliases))\n .map((a) => ctx.ctiAliases.get(a) ?? a);\n}\n\n/**\n * Pruning: em.find's paradigm, on a flat join list.\n *\n * A condition given `undefined` was already dropped by `ConditionBuilder`. Now a join that nothing\n * references anymore drops with it: a join is required if the source, a select, a surviving condition,\n * a group-by, an order-by, or another required join's ON references it, or if it is pinned with\n * `keep: true`. Marking follows ON dependencies transitively, exactly like `pruneUnusedJoins`'s\n * `DependencyTracker`.\n *\n * em.find's joins almost never filter rows by themselves, so pruning them is semantics-preserving. An\n * explicit `{ inner: b, on }` here does filter rows, so pruning it when unreferenced drops that filter;\n * that matches `{ books: { title: undefined } }` in em.find and is deliberate. `keep: true` pins it, and\n * a pure existence filter is better written as `a.id.in(query({ ... }))`, which is never `undefined`.\n */\nfunction pruneJoins(q: AnyQuery, from: ParsedSource, joins: ParsedJoin[], used: SqlFragment[]): ParsedJoin[] {\n if (q.pruneJoins === false) return joins;\n const deps = new Map<string, string[]>();\n for (const j of joins) {\n const refs = [...(j.userOn?.refs ?? []), ...j.source.refs].filter((r) => r !== j.source.alias);\n deps.set(j.source.alias, refs);\n }\n const required = new Set<string>();\n function markRequired(alias: string): void {\n if (required.has(alias)) return;\n required.add(alias);\n for (const dep of deps.get(alias) ?? []) markRequired(dep);\n }\n markRequired(from.alias);\n for (const r of used.flatMap((u) => u.refs)) markRequired(r);\n for (const j of joins) if (j.keep) markRequired(j.source.alias);\n return joins.filter((j) => required.has(j.source.alias));\n}\n\nfunction asExpr(value: unknown, where: string): BaseExpr {\n if (isExpr(value)) return value as any as BaseExpr;\n return fail(\n `${where} must be an expression, i.e. an alias column, aggregate, sql\\`...\\`, or query(...); got ${value}`,\n );\n}\n\nfunction joinFragmentParts(parts: SqlFragment[], sep: string): SqlFragment {\n return { sql: parts.map((p) => p.sql).join(sep), bindings: parts.flatMap((p) => p.bindings), refs: [] };\n}\n\nfunction isDefined<T>(value: T | undefined): value is T {\n return value !== undefined;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "joist-core",
|
|
3
|
-
"version": "2.3.0-next.
|
|
3
|
+
"version": "2.3.0-next.62",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"build"
|
|
43
43
|
],
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"joist-utils": "2.3.0-next.
|
|
45
|
+
"joist-utils": "2.3.0-next.62"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"ansis": "^4.3.1",
|