joist-core 2.3.0-next.88 → 2.3.0-next.89

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 CHANGED
@@ -287,7 +287,11 @@ var FnExpr = class extends BaseExpr {
287
287
  */
288
288
  toSql(ctx) {
289
289
  const args = joinFragments(this.args.map((a) => a.toSql(ctx)), ", ");
290
- const ordering = joinFragments((this.opts.aggregate?.orderBy ?? []).filter((entry) => entry !== void 0).map((entry) => orderByToSql(entry, ctx)), ", ");
290
+ const ordering = joinFragments((this.opts.aggregate?.orderBy ?? []).flatMap((entry) => {
291
+ if (entry === void 0) return [];
292
+ const fragment = orderByToSql(entry, ctx);
293
+ return fragment ? [fragment] : [];
294
+ }), ", ");
291
295
  const filter = this.opts.aggregate?.filter;
292
296
  const condition = filter === void 0 ? void 0 : ctx.conditionToSql(filter);
293
297
  return {
@@ -467,16 +471,18 @@ function minMaxOutputType(outputType) {
467
471
  function decodeNumber(value) {
468
472
  return typeof value === "string" ? Number(value) : value;
469
473
  }
470
- /** Renders an expression order for either a query or an aggregate. */
474
+ /** Renders an expression order for either a query or an aggregate, or prunes an undefined order. */
471
475
  function orderByToSql(o, ctx) {
472
- const [expr, direction] = "asc" in o && o.asc ? [o.asc, "ASC"] : [o.desc, "DESC"];
473
- if (!(expr instanceof BaseExpr)) return fail("orderBy must be an expression, i.e. a table column, aggregate, sql`...`, or scalar query(...)");
474
- const fragment = expr.toSql(ctx);
476
+ if (!(o.sort instanceof BaseExpr)) return fail("orderBy must be an expression, i.e. a table column, aggregate, sql`...`, or scalar query(...)");
477
+ if (Object.keys(o).some((key) => key !== "sort" && key !== "order" && key !== "nulls")) return fail("Expression orderBy entries only accept sort, order, and nulls");
478
+ if (o.order === void 0) return void 0;
479
+ if (o.order !== "ASC" && o.order !== "DESC") return fail(`Invalid orderBy direction '${o.order}'`);
475
480
  if (o.nulls !== void 0 && o.nulls !== "first" && o.nulls !== "last") return fail(`Invalid orderBy nulls '${o.nulls}'`);
481
+ const fragment = o.sort.toSql(ctx);
476
482
  const nulls = o.nulls ? ` NULLS ${o.nulls.toUpperCase()}` : "";
477
483
  return {
478
484
  ...fragment,
479
- sql: `${fragment.sql} ${direction}${nulls}`
485
+ sql: `${fragment.sql} ${o.order}${nulls}`
480
486
  };
481
487
  }
482
488
  function identity(value) {
@@ -1 +1 @@
1
- {"version":3,"file":"Expr.cjs","names":["brandPredicate","arrayOutputType","skipCondition","safeKq"],"sources":["../src/Expr.ts"],"sourcesContent":["import { type ConditionInput, type PredicateBrand, type SqlCondition, brandPredicate } from \"./conditions.ts\";\nimport type { EntityMetadata } from \"./EntityMetadata.ts\";\nimport { safeKq } from \"./keywords.ts\";\nimport type { QueryCondition, QueryOrderBy } from \"./query.ts\";\nimport type { RawCondition } from \"./QueryParser.ts\";\nimport { skipCondition } from \"./skipCondition.ts\";\nimport { type TypeInfo, arrayOutputType } from \"./TypeInfo.ts\";\n\n/**\n * The shared expression protocol for `em.query`.\n *\n * Table columns (`a.first_name`), 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: `Tables.ts` extends `BaseExpr` at load time, so nothing here may\n * import (at runtime) a module that leads back to `Tables.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 * table's key is its type name (`table(Author)` gives `\"Author\"`) or the explicit name in\n * `table(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_id` dispatch and\n * polymorphic joins).\n */\nexport type ExprLike<R> = { readonly [exprBrand]: ExprBrand<R, any> };\n\n/** Controls which values enter an array aggregate and their order within the array. */\nexport interface ArrayAggOptions {\n distinct?: boolean;\n /** With DISTINCT, PostgreSQL requires ordering expressions to match the aggregate argument. */\n orderBy?: readonly (QueryOrderBy | undefined)[];\n /** Undefined conditions are pruned, as in a query's where clause. */\n filter?: QueryCondition;\n}\n\n/**\n * A typed SQL expression: a table 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): SqlCondition;\n ne(value: R | ExprLike<R> | undefined): SqlCondition;\n gt(value: R | ExprLike<R> | undefined): SqlCondition;\n gte(value: R | ExprLike<R> | undefined): SqlCondition;\n lt(value: R | ExprLike<R> | undefined): SqlCondition;\n lte(value: R | ExprLike<R> | undefined): SqlCondition;\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): SqlCondition;\n nin(values: readonly R[] | ExprLike<R | null> | undefined): SqlCondition;\n\n /** Prefixes this expression and a space to a raw predicate; write .is`IS NULL`, not .is`NULL`. */\n is(strings: TemplateStringsArray, ...values: unknown[]): SqlCondition;\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(options?: ArrayAggOptions): 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 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 `SqlCondition` `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 `Tables.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, C = SqlCondition> {\n readonly inner: A;\n readonly left?: never;\n readonly on: C;\n readonly keep?: boolean;\n}\n\nexport interface LeftJoin<A, C = SqlCondition> {\n readonly left: A;\n readonly inner?: never;\n readonly on: C;\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 a table's `TableMgmt` 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: QueryCondition): 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 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` with a SQL brand so it can sit in any `SqlCondition`; `resolveDeferredConditions`\n * snapshots `condition`, `bindings`, and `aliases` before the filter is parsed. Domain alias conditions\n * use a separate protocol in the `em.find` parser.\n */\nexport interface DeferredCondition extends RawCondition, PredicateBrand<\"sql\"> {\n [deferredSym]: (ctx: ExprContext) => RawCondition;\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 = brandPredicate(\n {\n kind: \"raw\",\n aliases: [],\n condition: \"<unresolved>\",\n bindings: [],\n pruneable: false,\n [deferredSym]: (ctx: ExprContext): RawCondition => {\n const { sql, bindings, refs } = fn(ctx);\n return { ...cond, condition: sql, bindings, aliases: refs };\n },\n },\n \"sql\",\n );\n return cond;\n}\n\n/**\n * Resolve each condition occurrence and snapshot it before resolving the next one. A nested subquery\n * may reuse the same condition under another alias; it must not overwrite this occurrence's SQL.\n */\nexport function resolveDeferredConditions(\n cond: ConditionInput | undefined,\n ctx: ExprContext,\n): ConditionInput | undefined {\n if (cond === undefined || cond === null) return cond;\n if (isDeferredCondition(cond)) {\n return cond[deferredSym](ctx);\n } else if (\"and\" in cond && cond.and) {\n return { ...cond, and: cond.and.map((c) => resolveDeferredConditions(c, ctx)) };\n } else if (\"or\" in cond && cond.or) {\n return { ...cond, or: cond.or.map((c) => resolveDeferredConditions(c, ctx)) };\n }\n return cond;\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 * Table columns can override comparisons to apply column-specific conversions. Domain aliases do not\n * implement this protocol.\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 /** Only an actual scalar/IN subquery exposes its selected expression, not an ordinary ID expression. */\n get subquerySelect(): BaseExpr | undefined {\n return undefined;\n }\n\n /** Known SQL representation and logical domain; raw SQL and unmodeled refs remain unknown. */\n get outputType(): TypeInfo | undefined {\n return undefined;\n }\n\n /** Physical SQL nullability; undefined means unknown, not a NOT NULL guarantee. */\n get sqlNullable(): boolean | undefined {\n return undefined;\n }\n\n /** The source of a direct column reference, whose value becomes NULL under an unmatched LEFT join. */\n get sqlSource(): object | 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): SqlCondition {\n return this.compare(\"=\", value);\n }\n\n ne(value: unknown): SqlCondition {\n return this.compare(\"!=\", value);\n }\n\n gt(value: unknown): SqlCondition {\n return this.compare(\">\", value);\n }\n\n gte(value: unknown): SqlCondition {\n return this.compare(\">=\", value);\n }\n\n lt(value: unknown): SqlCondition {\n return this.compare(\"<\", value);\n }\n\n lte(value: unknown): SqlCondition {\n return this.compare(\"<=\", value);\n }\n\n in(values: unknown): SqlCondition {\n return this.inList(\"IN\", values);\n }\n\n nin(values: unknown): SqlCondition {\n return this.inList(\"NOT IN\", values);\n }\n\n /** Prefixes this expression to a SQL template, retaining bindings and referenced aliases. */\n is(strings: TemplateStringsArray, ...values: unknown[]): SqlCondition {\n const suffix = new TemplateExpr(strings, values);\n return deferredCondition((ctx) => joinFragments([this.toSql(ctx), suffix.toSql(ctx)], \" \"));\n }\n\n count(): Expr<number, never> {\n return new FnExpr(\"count\", [this], {\n suffix: \"::int\",\n decode: decodeNumber,\n encode: identity,\n outputType: { dbType: \"int4\", domain: Number, arrayElementSafe: true },\n }) 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 outputType: { dbType: \"int4\", domain: Number, arrayElementSafe: true },\n }) as any;\n }\n\n sum(): Expr<number | null, any> {\n return new FnExpr(\"sum\", [this], {\n decode: decodeNumber,\n encode: identity,\n outputType: numericAggregateOutputType(\"sum\", this.outputType),\n }) as any;\n }\n\n avg(): Expr<number | null, any> {\n return new FnExpr(\"avg\", [this], {\n decode: decodeNumber,\n encode: identity,\n outputType: numericAggregateOutputType(\"avg\", this.outputType),\n }) as any;\n }\n\n min(): Expr<any, any> {\n return new FnExpr(\"min\", [this], {\n decode: (v) => this.decode(v),\n outputType: minMaxOutputType(this.outputType),\n }) as any;\n }\n\n max(): Expr<any, any> {\n return new FnExpr(\"max\", [this], {\n decode: (v) => this.decode(v),\n outputType: minMaxOutputType(this.outputType),\n }) as any;\n }\n\n arrayAgg(options?: ArrayAggOptions): 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 prefix: options?.distinct ? \"DISTINCT \" : undefined,\n aggregate: options,\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 outputType: arrayOutputType(this.outputType),\n }) as any;\n }\n\n stringAgg(delimiter: string): Expr<string | null, any> {\n return new FnExpr(\"string_agg\", [this, new BindingExpr(delimiter)], {\n outputType:\n this.outputType?.domain === String ? { dbType: \"text\", domain: String, arrayElementSafe: true } : undefined,\n }) 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 outputType: this.outputType,\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): SqlCondition {\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): SqlCondition {\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 decoding is identity and encoding follows the first argument. Callers explicitly supply\n * a decoder and output type when needed (`max(a.id)` is still an id); numeric aggregates supply their\n * own decoder/encoder, since `count(a.id)` is a number, not an id. Unknown functions have no output type.\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 outputType?: TypeInfo;\n aggregate?: ArrayAggOptions;\n },\n ) {\n super();\n }\n\n get outputType(): TypeInfo | undefined {\n return this.opts.outputType;\n }\n\n get sqlNullable(): boolean | undefined {\n switch (this.name) {\n case \"count\":\n return false;\n case \"sum\":\n case \"avg\":\n case \"min\":\n case \"max\":\n case \"array_agg\":\n case \"string_agg\":\n return true;\n case \"coalesce\":\n // Only the fallback is independent of an outer query's LEFT joins.\n return this.args[1]?.sqlNullable === false ? false : undefined;\n default:\n return undefined;\n }\n }\n\n /**\n * Renders function arguments, aggregate ordering, and the filter in SQL binding order.\n * Keep references from all three so aggregate-only joins are retained.\n */\n toSql(ctx: ExprContext): SqlFragment {\n const args = joinFragments(\n this.args.map((a) => a.toSql(ctx)),\n \", \",\n );\n const ordering = joinFragments(\n (this.opts.aggregate?.orderBy ?? [])\n .filter((entry) => entry !== undefined)\n .map((entry) => orderByToSql(entry, ctx)),\n \", \",\n );\n const filter = this.opts.aggregate?.filter;\n const condition = filter === undefined ? undefined : ctx.conditionToSql(filter);\n return {\n sql: `${this.name}(${this.opts.prefix ?? \"\"}${args.sql}${ordering.sql ? ` ORDER BY ${ordering.sql}` : \"\"})${condition ? ` FILTER (WHERE ${condition.sql})` : \"\"}${this.opts.suffix ?? \"\"}`,\n bindings: [...args.bindings, ...ordering.bindings, ...(condition?.bindings ?? [])],\n refs: [...args.refs, ...ordering.refs, ...(condition?.refs ?? [])],\n };\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 get sqlNullable(): boolean {\n return this.value === null || this.value === undefined;\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 get sqlSource(): object {\n return this.handle;\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 table `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 SqlCondition) ?? { 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/**\n * Resolves the SQL result type of supported numeric aggregates; other overloads remain unknown.\n *\n * I.e. `a.age.sum()` has `dbType: \"int8\"` and Number conversion, while `a.age` has `dbType: \"int4\"`\n * and identity conversion. Their number domains agree, but SQL types reject a union in either order.\n */\nfunction numericAggregateOutputType(name: \"sum\" | \"avg\", outputType: TypeInfo | undefined): TypeInfo | undefined {\n switch (outputType?.dbType) {\n case \"int2\":\n case \"int4\":\n return { dbType: name === \"sum\" ? \"int8\" : \"numeric\", domain: Number, arrayElementSafe: true };\n case \"int8\":\n case \"numeric\":\n return { dbType: \"numeric\", domain: Number, arrayElementSafe: true };\n case \"float4\":\n return { dbType: name === \"sum\" ? \"float4\" : \"float8\", domain: Number, arrayElementSafe: true };\n case \"float8\":\n return { dbType: \"float8\", domain: Number, arrayElementSafe: true };\n default:\n return undefined;\n }\n}\n\n/** Only known MIN/MAX overloads have predictable output types; varchar/name use the text overload. */\nfunction minMaxOutputType(outputType: TypeInfo | undefined): TypeInfo | undefined {\n switch (outputType?.dbType) {\n case \"varchar\":\n case \"name\":\n return { ...outputType, dbType: \"text\" };\n case \"int2\":\n case \"int4\":\n case \"int8\":\n case \"numeric\":\n case \"float4\":\n case \"float8\":\n case \"text\":\n case \"bpchar\":\n case \"date\":\n case \"time\":\n case \"timetz\":\n case \"timestamp\":\n case \"timestamptz\":\n case \"interval\":\n case \"money\":\n case \"inet\":\n return outputType;\n default:\n return undefined;\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\n/** Renders an expression order for either a query or an aggregate. */\nexport function orderByToSql(o: QueryOrderBy, ctx: ExprContext): SqlFragment {\n const [expr, direction] = \"asc\" in o && o.asc ? [o.asc, \"ASC\"] : [o.desc, \"DESC\"];\n if (!(expr instanceof BaseExpr)) {\n return fail(\"orderBy must be an expression, i.e. a table column, aggregate, sql`...`, or scalar query(...)\");\n }\n const fragment = expr.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\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.cjs","names":["brandPredicate","arrayOutputType","skipCondition","safeKq"],"sources":["../src/Expr.ts"],"sourcesContent":["import { type ConditionInput, type PredicateBrand, type SqlCondition, brandPredicate } from \"./conditions.ts\";\nimport type { EntityMetadata } from \"./EntityMetadata.ts\";\nimport { safeKq } from \"./keywords.ts\";\nimport type { ExpressionOrderBy, QueryCondition } from \"./query.ts\";\nimport type { RawCondition } from \"./QueryParser.ts\";\nimport { skipCondition } from \"./skipCondition.ts\";\nimport { type TypeInfo, arrayOutputType } from \"./TypeInfo.ts\";\n\n/**\n * The shared expression protocol for `em.query`.\n *\n * Table columns (`a.first_name`), 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: `Tables.ts` extends `BaseExpr` at load time, so nothing here may\n * import (at runtime) a module that leads back to `Tables.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 * table's key is its type name (`table(Author)` gives `\"Author\"`) or the explicit name in\n * `table(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_id` dispatch and\n * polymorphic joins).\n */\nexport type ExprLike<R> = { readonly [exprBrand]: ExprBrand<R, any> };\n\n/** Controls which values enter an array aggregate and their order within the array. */\nexport interface ArrayAggOptions {\n distinct?: boolean;\n /** With DISTINCT, PostgreSQL requires ordering expressions to match the aggregate argument. */\n orderBy?: readonly (ExpressionOrderBy | undefined)[];\n /** Undefined conditions are pruned, as in a query's where clause. */\n filter?: QueryCondition;\n}\n\n/**\n * A typed SQL expression: a table 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): SqlCondition;\n ne(value: R | ExprLike<R> | undefined): SqlCondition;\n gt(value: R | ExprLike<R> | undefined): SqlCondition;\n gte(value: R | ExprLike<R> | undefined): SqlCondition;\n lt(value: R | ExprLike<R> | undefined): SqlCondition;\n lte(value: R | ExprLike<R> | undefined): SqlCondition;\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): SqlCondition;\n nin(values: readonly R[] | ExprLike<R | null> | undefined): SqlCondition;\n\n /** Prefixes this expression and a space to a raw predicate; write .is`IS NULL`, not .is`NULL`. */\n is(strings: TemplateStringsArray, ...values: unknown[]): SqlCondition;\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(options?: ArrayAggOptions): 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 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 `SqlCondition` `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 `Tables.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, C = SqlCondition> {\n readonly inner: A;\n readonly left?: never;\n readonly on: C;\n readonly keep?: boolean;\n}\n\nexport interface LeftJoin<A, C = SqlCondition> {\n readonly left: A;\n readonly inner?: never;\n readonly on: C;\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 a table's `TableMgmt` 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: QueryCondition): 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 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` with a SQL brand so it can sit in any `SqlCondition`; `resolveDeferredConditions`\n * snapshots `condition`, `bindings`, and `aliases` before the filter is parsed. Domain alias conditions\n * use a separate protocol in the `em.find` parser.\n */\nexport interface DeferredCondition extends RawCondition, PredicateBrand<\"sql\"> {\n [deferredSym]: (ctx: ExprContext) => RawCondition;\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 = brandPredicate(\n {\n kind: \"raw\",\n aliases: [],\n condition: \"<unresolved>\",\n bindings: [],\n pruneable: false,\n [deferredSym]: (ctx: ExprContext): RawCondition => {\n const { sql, bindings, refs } = fn(ctx);\n return { ...cond, condition: sql, bindings, aliases: refs };\n },\n },\n \"sql\",\n );\n return cond;\n}\n\n/**\n * Resolve each condition occurrence and snapshot it before resolving the next one. A nested subquery\n * may reuse the same condition under another alias; it must not overwrite this occurrence's SQL.\n */\nexport function resolveDeferredConditions(\n cond: ConditionInput | undefined,\n ctx: ExprContext,\n): ConditionInput | undefined {\n if (cond === undefined || cond === null) return cond;\n if (isDeferredCondition(cond)) {\n return cond[deferredSym](ctx);\n } else if (\"and\" in cond && cond.and) {\n return { ...cond, and: cond.and.map((c) => resolveDeferredConditions(c, ctx)) };\n } else if (\"or\" in cond && cond.or) {\n return { ...cond, or: cond.or.map((c) => resolveDeferredConditions(c, ctx)) };\n }\n return cond;\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 * Table columns can override comparisons to apply column-specific conversions. Domain aliases do not\n * implement this protocol.\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 /** Only an actual scalar/IN subquery exposes its selected expression, not an ordinary ID expression. */\n get subquerySelect(): BaseExpr | undefined {\n return undefined;\n }\n\n /** Known SQL representation and logical domain; raw SQL and unmodeled refs remain unknown. */\n get outputType(): TypeInfo | undefined {\n return undefined;\n }\n\n /** Physical SQL nullability; undefined means unknown, not a NOT NULL guarantee. */\n get sqlNullable(): boolean | undefined {\n return undefined;\n }\n\n /** The source of a direct column reference, whose value becomes NULL under an unmatched LEFT join. */\n get sqlSource(): object | 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): SqlCondition {\n return this.compare(\"=\", value);\n }\n\n ne(value: unknown): SqlCondition {\n return this.compare(\"!=\", value);\n }\n\n gt(value: unknown): SqlCondition {\n return this.compare(\">\", value);\n }\n\n gte(value: unknown): SqlCondition {\n return this.compare(\">=\", value);\n }\n\n lt(value: unknown): SqlCondition {\n return this.compare(\"<\", value);\n }\n\n lte(value: unknown): SqlCondition {\n return this.compare(\"<=\", value);\n }\n\n in(values: unknown): SqlCondition {\n return this.inList(\"IN\", values);\n }\n\n nin(values: unknown): SqlCondition {\n return this.inList(\"NOT IN\", values);\n }\n\n /** Prefixes this expression to a SQL template, retaining bindings and referenced aliases. */\n is(strings: TemplateStringsArray, ...values: unknown[]): SqlCondition {\n const suffix = new TemplateExpr(strings, values);\n return deferredCondition((ctx) => joinFragments([this.toSql(ctx), suffix.toSql(ctx)], \" \"));\n }\n\n count(): Expr<number, never> {\n return new FnExpr(\"count\", [this], {\n suffix: \"::int\",\n decode: decodeNumber,\n encode: identity,\n outputType: { dbType: \"int4\", domain: Number, arrayElementSafe: true },\n }) 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 outputType: { dbType: \"int4\", domain: Number, arrayElementSafe: true },\n }) as any;\n }\n\n sum(): Expr<number | null, any> {\n return new FnExpr(\"sum\", [this], {\n decode: decodeNumber,\n encode: identity,\n outputType: numericAggregateOutputType(\"sum\", this.outputType),\n }) as any;\n }\n\n avg(): Expr<number | null, any> {\n return new FnExpr(\"avg\", [this], {\n decode: decodeNumber,\n encode: identity,\n outputType: numericAggregateOutputType(\"avg\", this.outputType),\n }) as any;\n }\n\n min(): Expr<any, any> {\n return new FnExpr(\"min\", [this], {\n decode: (v) => this.decode(v),\n outputType: minMaxOutputType(this.outputType),\n }) as any;\n }\n\n max(): Expr<any, any> {\n return new FnExpr(\"max\", [this], {\n decode: (v) => this.decode(v),\n outputType: minMaxOutputType(this.outputType),\n }) as any;\n }\n\n arrayAgg(options?: ArrayAggOptions): 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 prefix: options?.distinct ? \"DISTINCT \" : undefined,\n aggregate: options,\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 outputType: arrayOutputType(this.outputType),\n }) as any;\n }\n\n stringAgg(delimiter: string): Expr<string | null, any> {\n return new FnExpr(\"string_agg\", [this, new BindingExpr(delimiter)], {\n outputType:\n this.outputType?.domain === String ? { dbType: \"text\", domain: String, arrayElementSafe: true } : undefined,\n }) 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 outputType: this.outputType,\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): SqlCondition {\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): SqlCondition {\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 decoding is identity and encoding follows the first argument. Callers explicitly supply\n * a decoder and output type when needed (`max(a.id)` is still an id); numeric aggregates supply their\n * own decoder/encoder, since `count(a.id)` is a number, not an id. Unknown functions have no output type.\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 outputType?: TypeInfo;\n aggregate?: ArrayAggOptions;\n },\n ) {\n super();\n }\n\n get outputType(): TypeInfo | undefined {\n return this.opts.outputType;\n }\n\n get sqlNullable(): boolean | undefined {\n switch (this.name) {\n case \"count\":\n return false;\n case \"sum\":\n case \"avg\":\n case \"min\":\n case \"max\":\n case \"array_agg\":\n case \"string_agg\":\n return true;\n case \"coalesce\":\n // Only the fallback is independent of an outer query's LEFT joins.\n return this.args[1]?.sqlNullable === false ? false : undefined;\n default:\n return undefined;\n }\n }\n\n /**\n * Renders function arguments, aggregate ordering, and the filter in SQL binding order.\n * Keep references from all three so aggregate-only joins are retained.\n */\n toSql(ctx: ExprContext): SqlFragment {\n const args = joinFragments(\n this.args.map((a) => a.toSql(ctx)),\n \", \",\n );\n const ordering = joinFragments(\n (this.opts.aggregate?.orderBy ?? []).flatMap((entry) => {\n if (entry === undefined) return [];\n const fragment = orderByToSql(entry, ctx);\n return fragment ? [fragment] : [];\n }),\n \", \",\n );\n const filter = this.opts.aggregate?.filter;\n const condition = filter === undefined ? undefined : ctx.conditionToSql(filter);\n return {\n sql: `${this.name}(${this.opts.prefix ?? \"\"}${args.sql}${ordering.sql ? ` ORDER BY ${ordering.sql}` : \"\"})${condition ? ` FILTER (WHERE ${condition.sql})` : \"\"}${this.opts.suffix ?? \"\"}`,\n bindings: [...args.bindings, ...ordering.bindings, ...(condition?.bindings ?? [])],\n refs: [...args.refs, ...ordering.refs, ...(condition?.refs ?? [])],\n };\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 get sqlNullable(): boolean {\n return this.value === null || this.value === undefined;\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 get sqlSource(): object {\n return this.handle;\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 table `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 SqlCondition) ?? { 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/**\n * Resolves the SQL result type of supported numeric aggregates; other overloads remain unknown.\n *\n * I.e. `a.age.sum()` has `dbType: \"int8\"` and Number conversion, while `a.age` has `dbType: \"int4\"`\n * and identity conversion. Their number domains agree, but SQL types reject a union in either order.\n */\nfunction numericAggregateOutputType(name: \"sum\" | \"avg\", outputType: TypeInfo | undefined): TypeInfo | undefined {\n switch (outputType?.dbType) {\n case \"int2\":\n case \"int4\":\n return { dbType: name === \"sum\" ? \"int8\" : \"numeric\", domain: Number, arrayElementSafe: true };\n case \"int8\":\n case \"numeric\":\n return { dbType: \"numeric\", domain: Number, arrayElementSafe: true };\n case \"float4\":\n return { dbType: name === \"sum\" ? \"float4\" : \"float8\", domain: Number, arrayElementSafe: true };\n case \"float8\":\n return { dbType: \"float8\", domain: Number, arrayElementSafe: true };\n default:\n return undefined;\n }\n}\n\n/** Only known MIN/MAX overloads have predictable output types; varchar/name use the text overload. */\nfunction minMaxOutputType(outputType: TypeInfo | undefined): TypeInfo | undefined {\n switch (outputType?.dbType) {\n case \"varchar\":\n case \"name\":\n return { ...outputType, dbType: \"text\" };\n case \"int2\":\n case \"int4\":\n case \"int8\":\n case \"numeric\":\n case \"float4\":\n case \"float8\":\n case \"text\":\n case \"bpchar\":\n case \"date\":\n case \"time\":\n case \"timetz\":\n case \"timestamp\":\n case \"timestamptz\":\n case \"interval\":\n case \"money\":\n case \"inet\":\n return outputType;\n default:\n return undefined;\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\n/** Renders an expression order for either a query or an aggregate, or prunes an undefined order. */\nexport function orderByToSql(o: ExpressionOrderBy, ctx: ExprContext): SqlFragment | undefined {\n if (!(o.sort instanceof BaseExpr)) {\n return fail(\"orderBy must be an expression, i.e. a table column, aggregate, sql`...`, or scalar query(...)\");\n }\n if (Object.keys(o).some((key) => key !== \"sort\" && key !== \"order\" && key !== \"nulls\")) {\n return fail(\"Expression orderBy entries only accept sort, order, and nulls\");\n }\n if (o.order === undefined) return undefined;\n if (o.order !== \"ASC\" && o.order !== \"DESC\") {\n return fail(`Invalid orderBy direction '${o.order}'`);\n }\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 fragment = o.sort.toSql(ctx);\n const nulls = o.nulls ? ` NULLS ${o.nulls.toUpperCase()}` : \"\";\n return { ...fragment, sql: `${fragment.sql} ${o.order}${nulls}` };\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
@@ -1,6 +1,6 @@
1
1
  import { ConditionInput, PredicateBrand, SqlCondition } from "./conditions.cjs";
2
2
  import { TypeInfo } from "./TypeInfo.cjs";
3
- import { QueryCondition, QueryOrderBy } from "./query.cjs";
3
+ import { ExpressionOrderBy, QueryCondition } from "./query.cjs";
4
4
  import { RawCondition } from "./QueryParser.cjs";
5
5
  //#region src/Expr.d.ts
6
6
  /**
@@ -54,7 +54,7 @@ type ExprLike<R> = {
54
54
  interface ArrayAggOptions {
55
55
  distinct?: boolean;
56
56
  /** With DISTINCT, PostgreSQL requires ordering expressions to match the aggregate argument. */
57
- orderBy?: readonly (QueryOrderBy | undefined)[];
57
+ orderBy?: readonly (ExpressionOrderBy | undefined)[];
58
58
  /** Undefined conditions are pruned, as in a query's where clause. */
59
59
  filter?: QueryCondition;
60
60
  }
@@ -267,8 +267,8 @@ declare class TemplateExpr extends BaseExpr {
267
267
  declare function interpolationToSql(value: unknown, ctx: ExprContext): SqlFragment;
268
268
  /** True for the user-facing condition shapes: `{ and }`, `{ or }`, `ColumnCondition`, `RawCondition`. */
269
269
  declare function isConditionLike(value: unknown): boolean;
270
- /** Renders an expression order for either a query or an aggregate. */
271
- declare function orderByToSql(o: QueryOrderBy, ctx: ExprContext): SqlFragment;
270
+ /** Renders an expression order for either a query or an aggregate, or prunes an undefined order. */
271
+ declare function orderByToSql(o: ExpressionOrderBy, ctx: ExprContext): SqlFragment | undefined;
272
272
  //#endregion
273
273
  export { ArrayAggOptions, BaseExpr, BindingExpr, DeferredCondition, Expr, ExprBrand, ExprContext, ExprLike, FnExpr, InnerJoin, LeftJoin, RefExpr, SqlFragment, TemplateExpr, asNode, deferredCondition, deferredSym, exprBrand, interpolationToSql, isConditionLike, isDeferredCondition, isExpr, joinFragments, orderByToSql, resolveDeferredConditions };
274
274
  //# sourceMappingURL=Expr.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Expr.d.cts","names":[],"sources":["../src/Expr.ts"],"mappings":"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"}
1
+ {"version":3,"file":"Expr.d.cts","names":[],"sources":["../src/Expr.ts"],"mappings":"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"}
package/build/Expr.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ConditionInput, PredicateBrand, SqlCondition } from "./conditions.mjs";
2
2
  import { TypeInfo } from "./TypeInfo.mjs";
3
- import { QueryCondition, QueryOrderBy } from "./query.mjs";
3
+ import { ExpressionOrderBy, QueryCondition } from "./query.mjs";
4
4
  import { RawCondition } from "./QueryParser.mjs";
5
5
  //#region src/Expr.d.ts
6
6
  /**
@@ -54,7 +54,7 @@ type ExprLike<R> = {
54
54
  interface ArrayAggOptions {
55
55
  distinct?: boolean;
56
56
  /** With DISTINCT, PostgreSQL requires ordering expressions to match the aggregate argument. */
57
- orderBy?: readonly (QueryOrderBy | undefined)[];
57
+ orderBy?: readonly (ExpressionOrderBy | undefined)[];
58
58
  /** Undefined conditions are pruned, as in a query's where clause. */
59
59
  filter?: QueryCondition;
60
60
  }
@@ -267,8 +267,8 @@ declare class TemplateExpr extends BaseExpr {
267
267
  declare function interpolationToSql(value: unknown, ctx: ExprContext): SqlFragment;
268
268
  /** True for the user-facing condition shapes: `{ and }`, `{ or }`, `ColumnCondition`, `RawCondition`. */
269
269
  declare function isConditionLike(value: unknown): boolean;
270
- /** Renders an expression order for either a query or an aggregate. */
271
- declare function orderByToSql(o: QueryOrderBy, ctx: ExprContext): SqlFragment;
270
+ /** Renders an expression order for either a query or an aggregate, or prunes an undefined order. */
271
+ declare function orderByToSql(o: ExpressionOrderBy, ctx: ExprContext): SqlFragment | undefined;
272
272
  //#endregion
273
273
  export { ArrayAggOptions, BaseExpr, BindingExpr, DeferredCondition, Expr, ExprBrand, ExprContext, ExprLike, FnExpr, InnerJoin, LeftJoin, RefExpr, SqlFragment, TemplateExpr, asNode, deferredCondition, deferredSym, exprBrand, interpolationToSql, isConditionLike, isDeferredCondition, isExpr, joinFragments, orderByToSql, resolveDeferredConditions };
274
274
  //# sourceMappingURL=Expr.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Expr.d.mts","names":[],"sources":["../src/Expr.ts"],"mappings":"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"}
1
+ {"version":3,"file":"Expr.d.mts","names":[],"sources":["../src/Expr.ts"],"mappings":"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"}
package/build/Expr.js CHANGED
@@ -286,7 +286,11 @@ var FnExpr = class extends BaseExpr {
286
286
  */
287
287
  toSql(ctx) {
288
288
  const args = joinFragments(this.args.map((a) => a.toSql(ctx)), ", ");
289
- const ordering = joinFragments((this.opts.aggregate?.orderBy ?? []).filter((entry) => entry !== void 0).map((entry) => orderByToSql(entry, ctx)), ", ");
289
+ const ordering = joinFragments((this.opts.aggregate?.orderBy ?? []).flatMap((entry) => {
290
+ if (entry === void 0) return [];
291
+ const fragment = orderByToSql(entry, ctx);
292
+ return fragment ? [fragment] : [];
293
+ }), ", ");
290
294
  const filter = this.opts.aggregate?.filter;
291
295
  const condition = filter === void 0 ? void 0 : ctx.conditionToSql(filter);
292
296
  return {
@@ -466,16 +470,18 @@ function minMaxOutputType(outputType) {
466
470
  function decodeNumber(value) {
467
471
  return typeof value === "string" ? Number(value) : value;
468
472
  }
469
- /** Renders an expression order for either a query or an aggregate. */
473
+ /** Renders an expression order for either a query or an aggregate, or prunes an undefined order. */
470
474
  function orderByToSql(o, ctx) {
471
- const [expr, direction] = "asc" in o && o.asc ? [o.asc, "ASC"] : [o.desc, "DESC"];
472
- if (!(expr instanceof BaseExpr)) return fail("orderBy must be an expression, i.e. a table column, aggregate, sql`...`, or scalar query(...)");
473
- const fragment = expr.toSql(ctx);
475
+ if (!(o.sort instanceof BaseExpr)) return fail("orderBy must be an expression, i.e. a table column, aggregate, sql`...`, or scalar query(...)");
476
+ if (Object.keys(o).some((key) => key !== "sort" && key !== "order" && key !== "nulls")) return fail("Expression orderBy entries only accept sort, order, and nulls");
477
+ if (o.order === void 0) return void 0;
478
+ if (o.order !== "ASC" && o.order !== "DESC") return fail(`Invalid orderBy direction '${o.order}'`);
474
479
  if (o.nulls !== void 0 && o.nulls !== "first" && o.nulls !== "last") return fail(`Invalid orderBy nulls '${o.nulls}'`);
480
+ const fragment = o.sort.toSql(ctx);
475
481
  const nulls = o.nulls ? ` NULLS ${o.nulls.toUpperCase()}` : "";
476
482
  return {
477
483
  ...fragment,
478
- sql: `${fragment.sql} ${direction}${nulls}`
484
+ sql: `${fragment.sql} ${o.order}${nulls}`
479
485
  };
480
486
  }
481
487
  function identity(value) {
package/build/Expr.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"Expr.js","names":[],"sources":["../src/Expr.ts"],"sourcesContent":["import { type ConditionInput, type PredicateBrand, type SqlCondition, brandPredicate } from \"./conditions.ts\";\nimport type { EntityMetadata } from \"./EntityMetadata.ts\";\nimport { safeKq } from \"./keywords.ts\";\nimport type { QueryCondition, QueryOrderBy } from \"./query.ts\";\nimport type { RawCondition } from \"./QueryParser.ts\";\nimport { skipCondition } from \"./skipCondition.ts\";\nimport { type TypeInfo, arrayOutputType } from \"./TypeInfo.ts\";\n\n/**\n * The shared expression protocol for `em.query`.\n *\n * Table columns (`a.first_name`), 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: `Tables.ts` extends `BaseExpr` at load time, so nothing here may\n * import (at runtime) a module that leads back to `Tables.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 * table's key is its type name (`table(Author)` gives `\"Author\"`) or the explicit name in\n * `table(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_id` dispatch and\n * polymorphic joins).\n */\nexport type ExprLike<R> = { readonly [exprBrand]: ExprBrand<R, any> };\n\n/** Controls which values enter an array aggregate and their order within the array. */\nexport interface ArrayAggOptions {\n distinct?: boolean;\n /** With DISTINCT, PostgreSQL requires ordering expressions to match the aggregate argument. */\n orderBy?: readonly (QueryOrderBy | undefined)[];\n /** Undefined conditions are pruned, as in a query's where clause. */\n filter?: QueryCondition;\n}\n\n/**\n * A typed SQL expression: a table 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): SqlCondition;\n ne(value: R | ExprLike<R> | undefined): SqlCondition;\n gt(value: R | ExprLike<R> | undefined): SqlCondition;\n gte(value: R | ExprLike<R> | undefined): SqlCondition;\n lt(value: R | ExprLike<R> | undefined): SqlCondition;\n lte(value: R | ExprLike<R> | undefined): SqlCondition;\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): SqlCondition;\n nin(values: readonly R[] | ExprLike<R | null> | undefined): SqlCondition;\n\n /** Prefixes this expression and a space to a raw predicate; write .is`IS NULL`, not .is`NULL`. */\n is(strings: TemplateStringsArray, ...values: unknown[]): SqlCondition;\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(options?: ArrayAggOptions): 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 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 `SqlCondition` `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 `Tables.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, C = SqlCondition> {\n readonly inner: A;\n readonly left?: never;\n readonly on: C;\n readonly keep?: boolean;\n}\n\nexport interface LeftJoin<A, C = SqlCondition> {\n readonly left: A;\n readonly inner?: never;\n readonly on: C;\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 a table's `TableMgmt` 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: QueryCondition): 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 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` with a SQL brand so it can sit in any `SqlCondition`; `resolveDeferredConditions`\n * snapshots `condition`, `bindings`, and `aliases` before the filter is parsed. Domain alias conditions\n * use a separate protocol in the `em.find` parser.\n */\nexport interface DeferredCondition extends RawCondition, PredicateBrand<\"sql\"> {\n [deferredSym]: (ctx: ExprContext) => RawCondition;\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 = brandPredicate(\n {\n kind: \"raw\",\n aliases: [],\n condition: \"<unresolved>\",\n bindings: [],\n pruneable: false,\n [deferredSym]: (ctx: ExprContext): RawCondition => {\n const { sql, bindings, refs } = fn(ctx);\n return { ...cond, condition: sql, bindings, aliases: refs };\n },\n },\n \"sql\",\n );\n return cond;\n}\n\n/**\n * Resolve each condition occurrence and snapshot it before resolving the next one. A nested subquery\n * may reuse the same condition under another alias; it must not overwrite this occurrence's SQL.\n */\nexport function resolveDeferredConditions(\n cond: ConditionInput | undefined,\n ctx: ExprContext,\n): ConditionInput | undefined {\n if (cond === undefined || cond === null) return cond;\n if (isDeferredCondition(cond)) {\n return cond[deferredSym](ctx);\n } else if (\"and\" in cond && cond.and) {\n return { ...cond, and: cond.and.map((c) => resolveDeferredConditions(c, ctx)) };\n } else if (\"or\" in cond && cond.or) {\n return { ...cond, or: cond.or.map((c) => resolveDeferredConditions(c, ctx)) };\n }\n return cond;\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 * Table columns can override comparisons to apply column-specific conversions. Domain aliases do not\n * implement this protocol.\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 /** Only an actual scalar/IN subquery exposes its selected expression, not an ordinary ID expression. */\n get subquerySelect(): BaseExpr | undefined {\n return undefined;\n }\n\n /** Known SQL representation and logical domain; raw SQL and unmodeled refs remain unknown. */\n get outputType(): TypeInfo | undefined {\n return undefined;\n }\n\n /** Physical SQL nullability; undefined means unknown, not a NOT NULL guarantee. */\n get sqlNullable(): boolean | undefined {\n return undefined;\n }\n\n /** The source of a direct column reference, whose value becomes NULL under an unmatched LEFT join. */\n get sqlSource(): object | 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): SqlCondition {\n return this.compare(\"=\", value);\n }\n\n ne(value: unknown): SqlCondition {\n return this.compare(\"!=\", value);\n }\n\n gt(value: unknown): SqlCondition {\n return this.compare(\">\", value);\n }\n\n gte(value: unknown): SqlCondition {\n return this.compare(\">=\", value);\n }\n\n lt(value: unknown): SqlCondition {\n return this.compare(\"<\", value);\n }\n\n lte(value: unknown): SqlCondition {\n return this.compare(\"<=\", value);\n }\n\n in(values: unknown): SqlCondition {\n return this.inList(\"IN\", values);\n }\n\n nin(values: unknown): SqlCondition {\n return this.inList(\"NOT IN\", values);\n }\n\n /** Prefixes this expression to a SQL template, retaining bindings and referenced aliases. */\n is(strings: TemplateStringsArray, ...values: unknown[]): SqlCondition {\n const suffix = new TemplateExpr(strings, values);\n return deferredCondition((ctx) => joinFragments([this.toSql(ctx), suffix.toSql(ctx)], \" \"));\n }\n\n count(): Expr<number, never> {\n return new FnExpr(\"count\", [this], {\n suffix: \"::int\",\n decode: decodeNumber,\n encode: identity,\n outputType: { dbType: \"int4\", domain: Number, arrayElementSafe: true },\n }) 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 outputType: { dbType: \"int4\", domain: Number, arrayElementSafe: true },\n }) as any;\n }\n\n sum(): Expr<number | null, any> {\n return new FnExpr(\"sum\", [this], {\n decode: decodeNumber,\n encode: identity,\n outputType: numericAggregateOutputType(\"sum\", this.outputType),\n }) as any;\n }\n\n avg(): Expr<number | null, any> {\n return new FnExpr(\"avg\", [this], {\n decode: decodeNumber,\n encode: identity,\n outputType: numericAggregateOutputType(\"avg\", this.outputType),\n }) as any;\n }\n\n min(): Expr<any, any> {\n return new FnExpr(\"min\", [this], {\n decode: (v) => this.decode(v),\n outputType: minMaxOutputType(this.outputType),\n }) as any;\n }\n\n max(): Expr<any, any> {\n return new FnExpr(\"max\", [this], {\n decode: (v) => this.decode(v),\n outputType: minMaxOutputType(this.outputType),\n }) as any;\n }\n\n arrayAgg(options?: ArrayAggOptions): 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 prefix: options?.distinct ? \"DISTINCT \" : undefined,\n aggregate: options,\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 outputType: arrayOutputType(this.outputType),\n }) as any;\n }\n\n stringAgg(delimiter: string): Expr<string | null, any> {\n return new FnExpr(\"string_agg\", [this, new BindingExpr(delimiter)], {\n outputType:\n this.outputType?.domain === String ? { dbType: \"text\", domain: String, arrayElementSafe: true } : undefined,\n }) 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 outputType: this.outputType,\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): SqlCondition {\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): SqlCondition {\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 decoding is identity and encoding follows the first argument. Callers explicitly supply\n * a decoder and output type when needed (`max(a.id)` is still an id); numeric aggregates supply their\n * own decoder/encoder, since `count(a.id)` is a number, not an id. Unknown functions have no output type.\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 outputType?: TypeInfo;\n aggregate?: ArrayAggOptions;\n },\n ) {\n super();\n }\n\n get outputType(): TypeInfo | undefined {\n return this.opts.outputType;\n }\n\n get sqlNullable(): boolean | undefined {\n switch (this.name) {\n case \"count\":\n return false;\n case \"sum\":\n case \"avg\":\n case \"min\":\n case \"max\":\n case \"array_agg\":\n case \"string_agg\":\n return true;\n case \"coalesce\":\n // Only the fallback is independent of an outer query's LEFT joins.\n return this.args[1]?.sqlNullable === false ? false : undefined;\n default:\n return undefined;\n }\n }\n\n /**\n * Renders function arguments, aggregate ordering, and the filter in SQL binding order.\n * Keep references from all three so aggregate-only joins are retained.\n */\n toSql(ctx: ExprContext): SqlFragment {\n const args = joinFragments(\n this.args.map((a) => a.toSql(ctx)),\n \", \",\n );\n const ordering = joinFragments(\n (this.opts.aggregate?.orderBy ?? [])\n .filter((entry) => entry !== undefined)\n .map((entry) => orderByToSql(entry, ctx)),\n \", \",\n );\n const filter = this.opts.aggregate?.filter;\n const condition = filter === undefined ? undefined : ctx.conditionToSql(filter);\n return {\n sql: `${this.name}(${this.opts.prefix ?? \"\"}${args.sql}${ordering.sql ? ` ORDER BY ${ordering.sql}` : \"\"})${condition ? ` FILTER (WHERE ${condition.sql})` : \"\"}${this.opts.suffix ?? \"\"}`,\n bindings: [...args.bindings, ...ordering.bindings, ...(condition?.bindings ?? [])],\n refs: [...args.refs, ...ordering.refs, ...(condition?.refs ?? [])],\n };\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 get sqlNullable(): boolean {\n return this.value === null || this.value === undefined;\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 get sqlSource(): object {\n return this.handle;\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 table `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 SqlCondition) ?? { 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/**\n * Resolves the SQL result type of supported numeric aggregates; other overloads remain unknown.\n *\n * I.e. `a.age.sum()` has `dbType: \"int8\"` and Number conversion, while `a.age` has `dbType: \"int4\"`\n * and identity conversion. Their number domains agree, but SQL types reject a union in either order.\n */\nfunction numericAggregateOutputType(name: \"sum\" | \"avg\", outputType: TypeInfo | undefined): TypeInfo | undefined {\n switch (outputType?.dbType) {\n case \"int2\":\n case \"int4\":\n return { dbType: name === \"sum\" ? \"int8\" : \"numeric\", domain: Number, arrayElementSafe: true };\n case \"int8\":\n case \"numeric\":\n return { dbType: \"numeric\", domain: Number, arrayElementSafe: true };\n case \"float4\":\n return { dbType: name === \"sum\" ? \"float4\" : \"float8\", domain: Number, arrayElementSafe: true };\n case \"float8\":\n return { dbType: \"float8\", domain: Number, arrayElementSafe: true };\n default:\n return undefined;\n }\n}\n\n/** Only known MIN/MAX overloads have predictable output types; varchar/name use the text overload. */\nfunction minMaxOutputType(outputType: TypeInfo | undefined): TypeInfo | undefined {\n switch (outputType?.dbType) {\n case \"varchar\":\n case \"name\":\n return { ...outputType, dbType: \"text\" };\n case \"int2\":\n case \"int4\":\n case \"int8\":\n case \"numeric\":\n case \"float4\":\n case \"float8\":\n case \"text\":\n case \"bpchar\":\n case \"date\":\n case \"time\":\n case \"timetz\":\n case \"timestamp\":\n case \"timestamptz\":\n case \"interval\":\n case \"money\":\n case \"inet\":\n return outputType;\n default:\n return undefined;\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\n/** Renders an expression order for either a query or an aggregate. */\nexport function orderByToSql(o: QueryOrderBy, ctx: ExprContext): SqlFragment {\n const [expr, direction] = \"asc\" in o && o.asc ? [o.asc, \"ASC\"] : [o.desc, \"DESC\"];\n if (!(expr instanceof BaseExpr)) {\n return fail(\"orderBy must be an expression, i.e. a table column, aggregate, sql`...`, or scalar query(...)\");\n }\n const fragment = expr.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\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 ConditionInput, type PredicateBrand, type SqlCondition, brandPredicate } from \"./conditions.ts\";\nimport type { EntityMetadata } from \"./EntityMetadata.ts\";\nimport { safeKq } from \"./keywords.ts\";\nimport type { ExpressionOrderBy, QueryCondition } from \"./query.ts\";\nimport type { RawCondition } from \"./QueryParser.ts\";\nimport { skipCondition } from \"./skipCondition.ts\";\nimport { type TypeInfo, arrayOutputType } from \"./TypeInfo.ts\";\n\n/**\n * The shared expression protocol for `em.query`.\n *\n * Table columns (`a.first_name`), 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: `Tables.ts` extends `BaseExpr` at load time, so nothing here may\n * import (at runtime) a module that leads back to `Tables.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 * table's key is its type name (`table(Author)` gives `\"Author\"`) or the explicit name in\n * `table(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_id` dispatch and\n * polymorphic joins).\n */\nexport type ExprLike<R> = { readonly [exprBrand]: ExprBrand<R, any> };\n\n/** Controls which values enter an array aggregate and their order within the array. */\nexport interface ArrayAggOptions {\n distinct?: boolean;\n /** With DISTINCT, PostgreSQL requires ordering expressions to match the aggregate argument. */\n orderBy?: readonly (ExpressionOrderBy | undefined)[];\n /** Undefined conditions are pruned, as in a query's where clause. */\n filter?: QueryCondition;\n}\n\n/**\n * A typed SQL expression: a table 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): SqlCondition;\n ne(value: R | ExprLike<R> | undefined): SqlCondition;\n gt(value: R | ExprLike<R> | undefined): SqlCondition;\n gte(value: R | ExprLike<R> | undefined): SqlCondition;\n lt(value: R | ExprLike<R> | undefined): SqlCondition;\n lte(value: R | ExprLike<R> | undefined): SqlCondition;\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): SqlCondition;\n nin(values: readonly R[] | ExprLike<R | null> | undefined): SqlCondition;\n\n /** Prefixes this expression and a space to a raw predicate; write .is`IS NULL`, not .is`NULL`. */\n is(strings: TemplateStringsArray, ...values: unknown[]): SqlCondition;\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(options?: ArrayAggOptions): 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 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 `SqlCondition` `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 `Tables.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, C = SqlCondition> {\n readonly inner: A;\n readonly left?: never;\n readonly on: C;\n readonly keep?: boolean;\n}\n\nexport interface LeftJoin<A, C = SqlCondition> {\n readonly left: A;\n readonly inner?: never;\n readonly on: C;\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 a table's `TableMgmt` 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: QueryCondition): 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 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` with a SQL brand so it can sit in any `SqlCondition`; `resolveDeferredConditions`\n * snapshots `condition`, `bindings`, and `aliases` before the filter is parsed. Domain alias conditions\n * use a separate protocol in the `em.find` parser.\n */\nexport interface DeferredCondition extends RawCondition, PredicateBrand<\"sql\"> {\n [deferredSym]: (ctx: ExprContext) => RawCondition;\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 = brandPredicate(\n {\n kind: \"raw\",\n aliases: [],\n condition: \"<unresolved>\",\n bindings: [],\n pruneable: false,\n [deferredSym]: (ctx: ExprContext): RawCondition => {\n const { sql, bindings, refs } = fn(ctx);\n return { ...cond, condition: sql, bindings, aliases: refs };\n },\n },\n \"sql\",\n );\n return cond;\n}\n\n/**\n * Resolve each condition occurrence and snapshot it before resolving the next one. A nested subquery\n * may reuse the same condition under another alias; it must not overwrite this occurrence's SQL.\n */\nexport function resolveDeferredConditions(\n cond: ConditionInput | undefined,\n ctx: ExprContext,\n): ConditionInput | undefined {\n if (cond === undefined || cond === null) return cond;\n if (isDeferredCondition(cond)) {\n return cond[deferredSym](ctx);\n } else if (\"and\" in cond && cond.and) {\n return { ...cond, and: cond.and.map((c) => resolveDeferredConditions(c, ctx)) };\n } else if (\"or\" in cond && cond.or) {\n return { ...cond, or: cond.or.map((c) => resolveDeferredConditions(c, ctx)) };\n }\n return cond;\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 * Table columns can override comparisons to apply column-specific conversions. Domain aliases do not\n * implement this protocol.\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 /** Only an actual scalar/IN subquery exposes its selected expression, not an ordinary ID expression. */\n get subquerySelect(): BaseExpr | undefined {\n return undefined;\n }\n\n /** Known SQL representation and logical domain; raw SQL and unmodeled refs remain unknown. */\n get outputType(): TypeInfo | undefined {\n return undefined;\n }\n\n /** Physical SQL nullability; undefined means unknown, not a NOT NULL guarantee. */\n get sqlNullable(): boolean | undefined {\n return undefined;\n }\n\n /** The source of a direct column reference, whose value becomes NULL under an unmatched LEFT join. */\n get sqlSource(): object | 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): SqlCondition {\n return this.compare(\"=\", value);\n }\n\n ne(value: unknown): SqlCondition {\n return this.compare(\"!=\", value);\n }\n\n gt(value: unknown): SqlCondition {\n return this.compare(\">\", value);\n }\n\n gte(value: unknown): SqlCondition {\n return this.compare(\">=\", value);\n }\n\n lt(value: unknown): SqlCondition {\n return this.compare(\"<\", value);\n }\n\n lte(value: unknown): SqlCondition {\n return this.compare(\"<=\", value);\n }\n\n in(values: unknown): SqlCondition {\n return this.inList(\"IN\", values);\n }\n\n nin(values: unknown): SqlCondition {\n return this.inList(\"NOT IN\", values);\n }\n\n /** Prefixes this expression to a SQL template, retaining bindings and referenced aliases. */\n is(strings: TemplateStringsArray, ...values: unknown[]): SqlCondition {\n const suffix = new TemplateExpr(strings, values);\n return deferredCondition((ctx) => joinFragments([this.toSql(ctx), suffix.toSql(ctx)], \" \"));\n }\n\n count(): Expr<number, never> {\n return new FnExpr(\"count\", [this], {\n suffix: \"::int\",\n decode: decodeNumber,\n encode: identity,\n outputType: { dbType: \"int4\", domain: Number, arrayElementSafe: true },\n }) 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 outputType: { dbType: \"int4\", domain: Number, arrayElementSafe: true },\n }) as any;\n }\n\n sum(): Expr<number | null, any> {\n return new FnExpr(\"sum\", [this], {\n decode: decodeNumber,\n encode: identity,\n outputType: numericAggregateOutputType(\"sum\", this.outputType),\n }) as any;\n }\n\n avg(): Expr<number | null, any> {\n return new FnExpr(\"avg\", [this], {\n decode: decodeNumber,\n encode: identity,\n outputType: numericAggregateOutputType(\"avg\", this.outputType),\n }) as any;\n }\n\n min(): Expr<any, any> {\n return new FnExpr(\"min\", [this], {\n decode: (v) => this.decode(v),\n outputType: minMaxOutputType(this.outputType),\n }) as any;\n }\n\n max(): Expr<any, any> {\n return new FnExpr(\"max\", [this], {\n decode: (v) => this.decode(v),\n outputType: minMaxOutputType(this.outputType),\n }) as any;\n }\n\n arrayAgg(options?: ArrayAggOptions): 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 prefix: options?.distinct ? \"DISTINCT \" : undefined,\n aggregate: options,\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 outputType: arrayOutputType(this.outputType),\n }) as any;\n }\n\n stringAgg(delimiter: string): Expr<string | null, any> {\n return new FnExpr(\"string_agg\", [this, new BindingExpr(delimiter)], {\n outputType:\n this.outputType?.domain === String ? { dbType: \"text\", domain: String, arrayElementSafe: true } : undefined,\n }) 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 outputType: this.outputType,\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): SqlCondition {\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): SqlCondition {\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 decoding is identity and encoding follows the first argument. Callers explicitly supply\n * a decoder and output type when needed (`max(a.id)` is still an id); numeric aggregates supply their\n * own decoder/encoder, since `count(a.id)` is a number, not an id. Unknown functions have no output type.\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 outputType?: TypeInfo;\n aggregate?: ArrayAggOptions;\n },\n ) {\n super();\n }\n\n get outputType(): TypeInfo | undefined {\n return this.opts.outputType;\n }\n\n get sqlNullable(): boolean | undefined {\n switch (this.name) {\n case \"count\":\n return false;\n case \"sum\":\n case \"avg\":\n case \"min\":\n case \"max\":\n case \"array_agg\":\n case \"string_agg\":\n return true;\n case \"coalesce\":\n // Only the fallback is independent of an outer query's LEFT joins.\n return this.args[1]?.sqlNullable === false ? false : undefined;\n default:\n return undefined;\n }\n }\n\n /**\n * Renders function arguments, aggregate ordering, and the filter in SQL binding order.\n * Keep references from all three so aggregate-only joins are retained.\n */\n toSql(ctx: ExprContext): SqlFragment {\n const args = joinFragments(\n this.args.map((a) => a.toSql(ctx)),\n \", \",\n );\n const ordering = joinFragments(\n (this.opts.aggregate?.orderBy ?? []).flatMap((entry) => {\n if (entry === undefined) return [];\n const fragment = orderByToSql(entry, ctx);\n return fragment ? [fragment] : [];\n }),\n \", \",\n );\n const filter = this.opts.aggregate?.filter;\n const condition = filter === undefined ? undefined : ctx.conditionToSql(filter);\n return {\n sql: `${this.name}(${this.opts.prefix ?? \"\"}${args.sql}${ordering.sql ? ` ORDER BY ${ordering.sql}` : \"\"})${condition ? ` FILTER (WHERE ${condition.sql})` : \"\"}${this.opts.suffix ?? \"\"}`,\n bindings: [...args.bindings, ...ordering.bindings, ...(condition?.bindings ?? [])],\n refs: [...args.refs, ...ordering.refs, ...(condition?.refs ?? [])],\n };\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 get sqlNullable(): boolean {\n return this.value === null || this.value === undefined;\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 get sqlSource(): object {\n return this.handle;\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 table `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 SqlCondition) ?? { 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/**\n * Resolves the SQL result type of supported numeric aggregates; other overloads remain unknown.\n *\n * I.e. `a.age.sum()` has `dbType: \"int8\"` and Number conversion, while `a.age` has `dbType: \"int4\"`\n * and identity conversion. Their number domains agree, but SQL types reject a union in either order.\n */\nfunction numericAggregateOutputType(name: \"sum\" | \"avg\", outputType: TypeInfo | undefined): TypeInfo | undefined {\n switch (outputType?.dbType) {\n case \"int2\":\n case \"int4\":\n return { dbType: name === \"sum\" ? \"int8\" : \"numeric\", domain: Number, arrayElementSafe: true };\n case \"int8\":\n case \"numeric\":\n return { dbType: \"numeric\", domain: Number, arrayElementSafe: true };\n case \"float4\":\n return { dbType: name === \"sum\" ? \"float4\" : \"float8\", domain: Number, arrayElementSafe: true };\n case \"float8\":\n return { dbType: \"float8\", domain: Number, arrayElementSafe: true };\n default:\n return undefined;\n }\n}\n\n/** Only known MIN/MAX overloads have predictable output types; varchar/name use the text overload. */\nfunction minMaxOutputType(outputType: TypeInfo | undefined): TypeInfo | undefined {\n switch (outputType?.dbType) {\n case \"varchar\":\n case \"name\":\n return { ...outputType, dbType: \"text\" };\n case \"int2\":\n case \"int4\":\n case \"int8\":\n case \"numeric\":\n case \"float4\":\n case \"float8\":\n case \"text\":\n case \"bpchar\":\n case \"date\":\n case \"time\":\n case \"timetz\":\n case \"timestamp\":\n case \"timestamptz\":\n case \"interval\":\n case \"money\":\n case \"inet\":\n return outputType;\n default:\n return undefined;\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\n/** Renders an expression order for either a query or an aggregate, or prunes an undefined order. */\nexport function orderByToSql(o: ExpressionOrderBy, ctx: ExprContext): SqlFragment | undefined {\n if (!(o.sort instanceof BaseExpr)) {\n return fail(\"orderBy must be an expression, i.e. a table column, aggregate, sql`...`, or scalar query(...)\");\n }\n if (Object.keys(o).some((key) => key !== \"sort\" && key !== \"order\" && key !== \"nulls\")) {\n return fail(\"Expression orderBy entries only accept sort, order, and nulls\");\n }\n if (o.order === undefined) return undefined;\n if (o.order !== \"ASC\" && o.order !== \"DESC\") {\n return fail(`Invalid orderBy direction '${o.order}'`);\n }\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 fragment = o.sort.toSql(ctx);\n const nulls = o.nulls ? ` NULLS ${o.nulls.toUpperCase()}` : \"\";\n return { ...fragment, sql: `${fragment.sql} ${o.order}${nulls}` };\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":";;;;;;;;;;;;;;;;AAoBA,MAAa,YAA2B,OAAO,YAAY;AA6H3D,SAAgB,OAAO,OAAwC;CAC7D,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,aAAa;AACrE;;AAGA,SAAgB,OAAO,MAA+B;CACpD,OAAO;AACT;AAEA,MAAa,cAA6B,OAAO,yBAAyB;AAc1E,SAAgB,oBAAoB,MAA0C;CAC5E,OAAO,OAAO,SAAS,YAAY,SAAS,QAAQ,eAAe;AACrE;;AAGA,SAAgB,kBAAkB,IAA0D;CAC1F,MAAM,OAA0B,eAC9B;EACE,MAAM;EACN,SAAS,CAAC;EACV,WAAW;EACX,UAAU,CAAC;EACX,WAAW;GACV,eAAe,QAAmC;GACjD,MAAM,EAAE,KAAK,UAAU,SAAS,GAAG,GAAG;GACtC,OAAO;IAAE,GAAG;IAAM,WAAW;IAAK;IAAU,SAAS;GAAK;EAC5D;CACF,GACA,KACF;CACA,OAAO;AACT;;;;;AAMA,SAAgB,0BACd,MACA,KAC4B;CAC5B,IAAI,SAAS,KAAA,KAAa,SAAS,MAAM,OAAO;CAChD,IAAI,oBAAoB,IAAI,GAC1B,OAAO,KAAK,YAAY,CAAC,GAAG;MACvB,IAAI,SAAS,QAAQ,KAAK,KAC/B,OAAO;EAAE,GAAG;EAAM,KAAK,KAAK,IAAI,KAAK,MAAM,0BAA0B,GAAG,GAAG,CAAC;CAAE;MACzE,IAAI,QAAQ,QAAQ,KAAK,IAC9B,OAAO;EAAE,GAAG;EAAM,IAAI,KAAK,GAAG,KAAK,MAAM,0BAA0B,GAAG,GAAG,CAAC;CAAE;CAE9E,OAAO;AACT;;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,IAAI,aAAmC,CAEvC;;CAGA,IAAI,cAAmC,CAEvC;;CAGA,IAAI,YAAgC,CAEpC;;CAGA,UAAU,KAA+B;EACvC,OAAO,KAAK,MAAM,GAAG;CACvB;;CAGA,OAAO,OAAyB;EAC9B,OAAO;CACT;;CAGA,OAAO,OAAyB;EAC9B,OAAO;CACT;CAEA,GAAG,OAA8B;EAC/B,OAAO,KAAK,QAAQ,KAAK,KAAK;CAChC;CAEA,GAAG,OAA8B;EAC/B,OAAO,KAAK,QAAQ,MAAM,KAAK;CACjC;CAEA,GAAG,OAA8B;EAC/B,OAAO,KAAK,QAAQ,KAAK,KAAK;CAChC;CAEA,IAAI,OAA8B;EAChC,OAAO,KAAK,QAAQ,MAAM,KAAK;CACjC;CAEA,GAAG,OAA8B;EAC/B,OAAO,KAAK,QAAQ,KAAK,KAAK;CAChC;CAEA,IAAI,OAA8B;EAChC,OAAO,KAAK,QAAQ,MAAM,KAAK;CACjC;CAEA,GAAG,QAA+B;EAChC,OAAO,KAAK,OAAO,MAAM,MAAM;CACjC;CAEA,IAAI,QAA+B;EACjC,OAAO,KAAK,OAAO,UAAU,MAAM;CACrC;;CAGA,GAAG,SAA+B,GAAG,QAAiC;EACpE,MAAM,SAAS,IAAI,aAAa,SAAS,MAAM;EAC/C,OAAO,mBAAmB,QAAQ,cAAc,CAAC,KAAK,MAAM,GAAG,GAAG,OAAO,MAAM,GAAG,CAAC,GAAG,GAAG,CAAC;CAC5F;CAEA,QAA6B;EAC3B,OAAO,IAAI,OAAO,SAAS,CAAC,IAAI,GAAG;GACjC,QAAQ;GACR,QAAQ;GACR,QAAQ;GACR,YAAY;IAAE,QAAQ;IAAQ,QAAQ;IAAQ,kBAAkB;GAAK;EACvE,CAAC;CACH;CAEA,gBAAqC;EACnC,OAAO,IAAI,OAAO,SAAS,CAAC,IAAI,GAAG;GACjC,QAAQ;GACR,QAAQ;GACR,QAAQ;GACR,QAAQ;GACR,YAAY;IAAE,QAAQ;IAAQ,QAAQ;IAAQ,kBAAkB;GAAK;EACvE,CAAC;CACH;CAEA,MAAgC;EAC9B,OAAO,IAAI,OAAO,OAAO,CAAC,IAAI,GAAG;GAC/B,QAAQ;GACR,QAAQ;GACR,YAAY,2BAA2B,OAAO,KAAK,UAAU;EAC/D,CAAC;CACH;CAEA,MAAgC;EAC9B,OAAO,IAAI,OAAO,OAAO,CAAC,IAAI,GAAG;GAC/B,QAAQ;GACR,QAAQ;GACR,YAAY,2BAA2B,OAAO,KAAK,UAAU;EAC/D,CAAC;CACH;CAEA,MAAsB;EACpB,OAAO,IAAI,OAAO,OAAO,CAAC,IAAI,GAAG;GAC/B,SAAS,MAAM,KAAK,OAAO,CAAC;GAC5B,YAAY,iBAAiB,KAAK,UAAU;EAC9C,CAAC;CACH;CAEA,MAAsB;EACpB,OAAO,IAAI,OAAO,OAAO,CAAC,IAAI,GAAG;GAC/B,SAAS,MAAM,KAAK,OAAO,CAAC;GAC5B,YAAY,iBAAiB,KAAK,UAAU;EAC9C,CAAC;CACH;CAEA,SAAS,SAA2C;EAGlD,OAAO,IAAI,OAAO,aAAa,CAAC,IAAI,GAAG;GACrC,QAAQ,SAAS,WAAW,cAAc,KAAA;GAC1C,WAAW;GACX,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;GAClE,YAAY,gBAAgB,KAAK,UAAU;EAC7C,CAAC;CACH;CAEA,UAAU,WAA6C;EACrD,OAAO,IAAI,OAAO,cAAc,CAAC,MAAM,IAAI,YAAY,SAAS,CAAC,GAAG,EAClE,YACE,KAAK,YAAY,WAAW,SAAS;GAAE,QAAQ;GAAQ,QAAQ;GAAQ,kBAAkB;EAAK,IAAI,KAAA,EACtG,CAAC;CACH;CAEA,SAAS,UAAqC;EAC5C,OAAO,IAAI,OAAO,YAAY,CAAC,MAAM,IAAI,YAAY,KAAK,OAAO,QAAQ,CAAC,CAAC,GAAG;GAC5E,SAAS,MAAM,KAAK,OAAO,CAAC;GAC5B,YAAY,KAAK;EACnB,CAAC;CACH;;CAGA,QAAkB,IAAY,OAA8B;EAC1D,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,QAA+B;EACnE,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;;;;;;;;AASA,IAAa,SAAb,cAA4B,SAAS;CAEzB;CACA;CACA;CAHV,YACE,MACA,MACA,MAQA;EACA,MAAM;EAXE,KAAA,OAAA;EACA,KAAA,OAAA;EACA,KAAA,OAAA;CAUV;CAEA,IAAI,aAAmC;EACrC,OAAO,KAAK,KAAK;CACnB;CAEA,IAAI,cAAmC;EACrC,QAAQ,KAAK,MAAb;GACE,KAAK,SACH,OAAO;GACT,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK,cACH,OAAO;GACT,KAAK,YAEH,OAAO,KAAK,KAAK,EAAE,EAAE,gBAAgB,QAAQ,QAAQ,KAAA;GACvD,SACE;EACJ;CACF;;;;;CAMA,MAAM,KAA+B;EACnC,MAAM,OAAO,cACX,KAAK,KAAK,KAAK,MAAM,EAAE,MAAM,GAAG,CAAC,GACjC,IACF;EACA,MAAM,WAAW,eACd,KAAK,KAAK,WAAW,WAAW,CAAC,EAAA,CAAG,SAAS,UAAU;GACtD,IAAI,UAAU,KAAA,GAAW,OAAO,CAAC;GACjC,MAAM,WAAW,aAAa,OAAO,GAAG;GACxC,OAAO,WAAW,CAAC,QAAQ,IAAI,CAAC;EAClC,CAAC,GACD,IACF;EACA,MAAM,SAAS,KAAK,KAAK,WAAW;EACpC,MAAM,YAAY,WAAW,KAAA,IAAY,KAAA,IAAY,IAAI,eAAe,MAAM;EAC9E,OAAO;GACL,KAAK,GAAG,KAAK,KAAK,GAAG,KAAK,KAAK,UAAU,KAAK,KAAK,MAAM,SAAS,MAAM,aAAa,SAAS,QAAQ,GAAG,GAAG,YAAY,kBAAkB,UAAU,IAAI,KAAK,KAAK,KAAK,KAAK,UAAU;GACtL,UAAU;IAAC,GAAG,KAAK;IAAU,GAAG,SAAS;IAAU,GAAI,WAAW,YAAY,CAAC;GAAE;GACjF,MAAM;IAAC,GAAG,KAAK;IAAM,GAAG,SAAS;IAAM,GAAI,WAAW,QAAQ,CAAC;GAAE;EACnE;CACF;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,IAAI,cAAuB;EACzB,OAAO,KAAK,UAAU,QAAQ,KAAK,UAAU,KAAA;CAC/C;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,IAAI,YAAoB;EACtB,OAAO,KAAK;CACd;CAEA,MAAM,KAA+B;EACnC,MAAM,QAAQ,IAAI,SAAS,KAAK,MAAM;EAEtC,OAAO;GAAE,KAAK,GAAG,OAAO,KAAK,EAAE,GAAG,OAAO,KAAK,MAAM;GAAK,UAAU,CAAC;GAAG,MAAM,CAAC,KAAK;EAAE;CACvF;AACF;;;;;;;;;;;;AAaA,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,KAAqB,KAAK;EAAE,KAAK;EAAQ,UAAU,CAAC;EAAG,MAAM,CAAC;CAAE;MAE1F,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;;;;;;;AAQA,SAAS,2BAA2B,MAAqB,YAAwD;CAC/G,QAAQ,YAAY,QAApB;EACE,KAAK;EACL,KAAK,QACH,OAAO;GAAE,QAAQ,SAAS,QAAQ,SAAS;GAAW,QAAQ;GAAQ,kBAAkB;EAAK;EAC/F,KAAK;EACL,KAAK,WACH,OAAO;GAAE,QAAQ;GAAW,QAAQ;GAAQ,kBAAkB;EAAK;EACrE,KAAK,UACH,OAAO;GAAE,QAAQ,SAAS,QAAQ,WAAW;GAAU,QAAQ;GAAQ,kBAAkB;EAAK;EAChG,KAAK,UACH,OAAO;GAAE,QAAQ;GAAU,QAAQ;GAAQ,kBAAkB;EAAK;EACpE,SACE;CACJ;AACF;;AAGA,SAAS,iBAAiB,YAAwD;CAChF,QAAQ,YAAY,QAApB;EACE,KAAK;EACL,KAAK,QACH,OAAO;GAAE,GAAG;GAAY,QAAQ;EAAO;EACzC,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,QACH,OAAO;EACT,SACE;CACJ;AACF;;AAGA,SAAS,aAAa,OAAyB;CAC7C,OAAO,OAAO,UAAU,WAAW,OAAO,KAAK,IAAI;AACrD;;AAGA,SAAgB,aAAa,GAAsB,KAA2C;CAC5F,IAAI,EAAE,EAAE,gBAAgB,WACtB,OAAO,KAAK,+FAA+F;CAE7G,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,QAAQ,QAAQ,UAAU,QAAQ,WAAW,QAAQ,OAAO,GACnF,OAAO,KAAK,+DAA+D;CAE7E,IAAI,EAAE,UAAU,KAAA,GAAW,OAAO,KAAA;CAClC,IAAI,EAAE,UAAU,SAAS,EAAE,UAAU,QACnC,OAAO,KAAK,8BAA8B,EAAE,MAAM,EAAE;CAGtD,IAAI,EAAE,UAAU,KAAA,KAAa,EAAE,UAAU,WAAW,EAAE,UAAU,QAC9D,OAAO,KAAK,0BAA0B,EAAE,MAAM,EAAE;CAElD,MAAM,WAAW,EAAE,KAAK,MAAM,GAAG;CACjC,MAAM,QAAQ,EAAE,QAAQ,UAAU,EAAE,MAAM,YAAY,MAAM;CAC5D,OAAO;EAAE,GAAG;EAAU,KAAK,GAAG,SAAS,IAAI,GAAG,EAAE,QAAQ;CAAQ;AAClE;AAEA,SAAS,SAAS,OAAyB;CACzC,OAAO;AACT;AAEA,SAAS,KAAK,SAAwB;CACpC,MAAM,IAAI,MAAM,OAAO;AACzB"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["getMetadata","getProperties","getBaseMeta","getField","AbstractRelationImpl","isLazyField","isProperty","isAsyncProperty","isReactiveGetter","isReactiveField","isAsyncReactiveField","FactoryInitialValue","ReactiveFieldImpl","AsyncReactiveFieldImpl","getInstanceData"],"sources":["../src/index.ts"],"sourcesContent":["import { getInstanceData } from \"./BaseEntity.ts\";\nimport { getDefaultDependencies } from \"./defaults.ts\";\nimport { buildWhereClause } from \"./drivers/buildUtils.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type EntityConstructor, type MaybeAbstractEntityConstructor } from \"./EntityManager.ts\";\nimport { type EntityMetadata, getBaseMeta, getMetadata } from \"./EntityMetadata.ts\";\nimport { getField, setField } from \"./fields.ts\";\nimport { getProperties } from \"./getProperties.ts\";\nimport { type New } from \"./loadHints.ts\";\nimport { isAllSqlPaths } from \"./loadLens.ts\";\nimport { FactoryInitialValue } from \"./newTestInstance.ts\";\nimport { partitionHint } from \"./preloading/partitionHint.ts\";\nimport { AbstractRelationImpl } from \"./relations/AbstractRelationImpl.ts\";\nimport { AsyncReactiveFieldImpl } from \"./relations/AsyncReactiveField.ts\";\nimport {\n isAsyncProperty,\n isAsyncReactiveField,\n isLazyField,\n isProperty,\n isReactiveField,\n isReactiveGetter,\n} from \"./relations/index.ts\";\nimport { ReactiveFieldImpl } from \"./relations/ReactiveField.ts\";\nimport { type OptsOf } from \"./typeMap.ts\";\nimport { fail } from \"./utils.ts\";\n\nexport const testing = { isAllSqlPaths, getDefaultDependencies, partitionHint };\nexport const internals = { buildWhereClause };\nexport { newPgConnectionConfig } from \"joist-utils\";\nexport { AliasAssigner } from \"./AliasAssigner.ts\";\nexport {\n type AndCondition,\n type ConditionGroup,\n type DomainPredicate,\n type OrCondition,\n type PredicateBrand,\n type SqlCondition,\n type SqlPredicate,\n} from \"./conditions.ts\";\n// Domain aliases belong to em.find; physical table expressions belong to em.query/em.execute.\nexport {\n alias,\n aliases,\n getAliasMetadata,\n getAliasMgmt,\n getMaybeCtiAlias,\n isAlias,\n newAliasProxy,\n type Alias,\n type AliasBrand,\n type AliasMgmt,\n type AliasColumn,\n type EntityAlias,\n type PolyAlias,\n type PrimitiveAlias,\n} from \"./Aliases.ts\";\nexport {\n table,\n tables,\n tableMgmt,\n getTableMetadata,\n getTableMgmt,\n isTable,\n newTableProxy,\n type Table,\n type TableFilter,\n type TableBrand,\n type TableFor,\n type TableMgmt,\n type ReferenceJoin,\n type PrimitiveColumn,\n type EntityColumn,\n type ReferenceColumn,\n type CollectionJoin,\n type PolyReference,\n} from \"./Tables.ts\";\nexport { BaseEntity, getInstanceData } from \"./BaseEntity.ts\";\nexport { ConditionBuilder } from \"./ConditionBuilder.ts\";\nexport { type Entity, type IdType, isEntity } from \"./Entity.ts\";\nexport type * from \"./EntityFields.ts\";\nexport * from \"./EntityFilter.ts\";\nexport * from \"./EntityGraphQLFilter.ts\";\nexport * from \"./EntityManager.ts\";\nexport * from \"./EntityMetadata.ts\";\nexport type {\n DeleteStatement,\n ExecuteResult,\n InsertStatement,\n InsertValues,\n MutationReturning,\n MutationStatement,\n UpdateStatement,\n UpdateValues,\n} from \"./execute.ts\";\nexport type { EnumMetadata } from \"./EnumMetadata.ts\";\n// `em.query`'s expression surface. Only the user-facing types are re-exported: the runtime half\n// (BaseExpr, asNode, deferredCondition, the FnExpr/TemplateExpr node classes) stays internal to\n// joist-core, so `toSql`/`decode`/`encode` never show up as something a user could call.\nexport {\n type ArrayAggOptions,\n type Expr,\n type ExprBrand,\n exprBrand,\n type ExprLike,\n type InnerJoin,\n type LeftJoin,\n} from \"./Expr.ts\";\nexport { expr, type CaseElse, type CaseWhen, type ExprFromInput, type ExprInput } from \"./expressions/expression.ts\";\nexport { skipCondition } from \"./skipCondition.ts\";\nexport type { EntityOrId, HintNode } from \"./HintTree.ts\";\nexport { InstanceData } from \"./InstanceData.ts\";\nexport { type JoinColumnValue, type JoinRow, JoinRowOperation, type ManyToManyLike } from \"./JoinRows.ts\";\nexport type * from \"./PendingChanges.ts\";\nexport { Plugin } from \"./PluginManager.ts\";\nexport * from \"./QueryParser.ts\";\nexport * from \"./QueryParser.collectionJoins.ts\";\nexport { visitConditions } from \"./QueryVisitor.ts\";\nexport * from \"./RowData.ts\";\nexport { type JoinRowTodo, Todo } from \"./Todo.ts\";\nexport * from \"./changes.ts\";\nexport { ConfigApi, type EntityHook, resetBootFlag } from \"./config.ts\";\nexport {\n configureMetadata,\n getConstructorFromTaggedId,\n getMetadataForTable,\n getMetadataForType,\n maybeGetConstructorFromReference,\n} from \"./configure.ts\";\nexport { driverApi } from \"./driverApi.ts\";\nexport * from \"./drivers/index.ts\";\nexport { getField, isChangeableField, isFieldSet, setField } from \"./fields.ts\";\nexport * from \"./getProperties.ts\";\nexport * from \"./json.ts\";\nexport * from \"./keys.ts\";\nexport { kq, kqDot, kqStar } from \"./keywords.ts\";\nexport {\n assertLoaded,\n type DeepNew,\n ensureLoaded,\n isLoaded,\n isNew,\n type Loadable,\n type Loaded,\n type LoadHint,\n type MarkLoaded,\n maybePopulateThen,\n type NestedLoadHint,\n type New,\n type RelationsIn,\n unsafeLoaded,\n} from \"./loadHints.ts\";\nexport * from \"./loadLens.ts\";\nexport { setFactoryWriter } from \"./logging/FactoryLogger.ts\";\nexport * from \"./logging/FieldLogger.ts\";\nexport { ReactionLogger, setReactionLogging } from \"./logging/ReactionLogger.ts\";\nexport { lazyField } from \"./newEntity.ts\";\nexport {\n defaultValue,\n factories,\n type FactoryEntityOpt,\n type FactoryOpts,\n getTestIndex,\n isFactoryCreation,\n maybeBranchValue,\n maybeNew,\n maybeNewPoly,\n newTestInstance,\n noValue,\n setFactoryLogging,\n testIndex,\n} from \"./newTestInstance.ts\";\nexport { deepNormalizeHint, normalizeHint } from \"./normalizeHints.ts\";\nexport { ImmutableEntitiesPlugin } from \"./plugins/ImmutableEntitiesPlugin.ts\";\nexport type { JoinResult, PreloadHydrator, PreloadPlugin } from \"./plugins/PreloadPlugin.ts\";\nexport { JsonAggregatePreloader } from \"./preloading/JsonAggregatePreloader.ts\";\n// `em.query`'s query surface; the parse pipeline (SubqueryHandle, parseUserQuery, Plan) stays internal\nexport {\n type CheckScope,\n type Clauses,\n type EntityQuery,\n type ExistsQuery,\n entityQueryBrand,\n type MaybeNull,\n type NameOf,\n type NotWidened,\n type OrderByDirection,\n type OrderByKeys,\n type Query,\n type QueryArg,\n type QueryCondition,\n type QueryJoin,\n type QueryJoins,\n type QueryOrderBy,\n type QueryRow,\n type QuerySelect,\n type QuerySource,\n type QueryValue,\n recursiveQuery,\n type RecursiveOptions,\n type ScalarQuery,\n type SetQuery,\n query,\n sql,\n type Subquery,\n type SubqueryBrand,\n subqueryBrand,\n type WithInput,\n type WithSource,\n} from \"./query.ts\";\nexport {\n convertToLoadHint,\n isTypeOrSubType,\n type Reactable,\n type Reacted,\n type ReactiveHint,\n type ReactiveTarget,\n reverseReactiveHint,\n} from \"./reactiveHints.ts\";\nexport * from \"./relations/index.ts\";\nexport {\n cannotBeChanged,\n cannotBeUpdated,\n type GenericError,\n maxValueRule,\n minValueRule,\n mustBeSubType,\n newRequiredLazyFieldRule,\n newRequiredRule,\n rangeValueRule,\n ValidationCode,\n type ValidationError,\n ValidationErrors,\n type ValidationRule,\n type ValidationRuleInternal,\n type ValidationRuleResult,\n} from \"./rules.ts\";\nexport { getRuntimeConfig, setRuntimeConfig, type RuntimeConfig } from \"./runtimeConfig.ts\";\nexport { nowUTC } from \"./nowUTC.ts\";\nexport * from \"./serde.ts\";\nexport * from \"./columns.ts\";\nexport * from \"./fieldSerde.ts\";\nexport * from \"./scopes.ts\";\nexport { maybeRequireTemporal, requireTemporal, Temporal } from \"./temporal.ts\";\nexport * from \"./temporalMappers.ts\";\nexport { isInTrustedContext, runInTrustedContext } from \"./trusted.ts\";\nexport type * from \"./typeMap.ts\";\nexport { buildUnnestCte, ensureRectangularArraySizes } from \"./unnest.ts\";\nexport { type DeepPartialOrNull, updatePartial, upsert } from \"./upsert.ts\";\nexport {\n abbreviation,\n asNew,\n assertNever,\n cleanSql,\n cleanStringValue,\n fail,\n failIfAnyRejected,\n indexBy,\n partition,\n zeroTo,\n} from \"./utils.ts\";\nexport { ensureWithLoaded, StubbedRelation, type WithLoaded, withLoaded } from \"./withLoaded.ts\";\n\n// https://spin.atomicobject.com/2018/01/15/typescript-flexible-nominal-typing/\ninterface Flavoring<FlavorT> {\n _type?: FlavorT;\n}\n\nexport type Flavor<T, FlavorT> = T & Flavoring<FlavorT>;\n\n/**\n * Sets each value in `values` on the current entity.\n *\n * The default behavior is that passing a value as either `null` or `undefined` will set\n * the field as `undefined`, i.e. automatic `null` to `undefined` conversion.\n *\n * However, if you pass `ignoreUndefined: true`, then any opt that is `undefined` will be treated\n * as \"do not set\", and `null` will still mean \"set to `undefined`\". This is useful for implementing\n * APIs were an input of `undefined` means \"do not set / noop\" and `null` means \"unset\".\n *\n * Note that constructors _always_ call this method, but if the call is coming from `em.hydrate`, we\n * use `values` being a primary key to short-circuit and let hydration callers assign the values\n * returned by the serde `fromRow` methods.\n */\nexport function setOpts<T extends Entity>(\n entity: T,\n values: Partial<OptsOf<T>> | undefined,\n opts?: { partial?: boolean; calledFromConstructor?: boolean },\n): void {\n const { calledFromConstructor = false, partial } = opts || {};\n // If `values` is undefined, we're being called by `createPartial` that will do its\n // own opt handling, but we still want the sync defaults applied after this opts handling.\n if (values !== undefined) {\n const meta = getMetadata(entity);\n for (const [key, _value] of Object.entries(values as {})) {\n setOpt(meta, entity, key, _value, partial, calledFromConstructor);\n }\n }\n}\n\n/**\n * Applies some standard behavior & protections to `entity[key] = value`. I.e.\n *\n * - We don't set over AsyncProperties/relations/etc., and instead call current.set(value)\n * - We catch missing/invalid field names\n * - We handle FactoryInitialValues\n */\nexport function setOpt<T extends Entity>(\n meta: EntityMetadata<T>,\n entity: T,\n key: string,\n _value: any,\n partial = false,\n calledFromConstructor = false,\n): void {\n const field = meta.allFields[key];\n if (!field) {\n // Allow setting non-field properties like fullName setters\n const prop = getProperties(meta)[key];\n if (!prop) {\n throw new Error(`Unknown field ${key}`);\n }\n }\n\n // If partial is set, we treat undefined as a noop\n if (partial && _value === undefined) return;\n // Ignore the STI discriminator, em.register will set this accordingly\n if (meta.inheritanceType === \"sti\" && getBaseMeta(meta).stiDiscriminatorField === key) return;\n\n // We let optional opts fields be `| null` for convenience, and convert to undefined.\n const value = _value === null ? undefined : _value;\n\n // Use `getField` to side-step `id` blowing up on new entities that are setting an\n // explicit id; otherwise use `entity[key]` to get back the relation.\n const current = key === \"id\" ? getField(entity, key) : (entity as any)[key];\n\n if (current instanceof AbstractRelationImpl) {\n if (calledFromConstructor) {\n current.setFromOpts(value);\n } else {\n current.set(value);\n }\n } else if (isLazyField(current)) {\n current.set(value);\n } else if (isProperty(current) || isAsyncProperty(current) || isReactiveGetter(current)) {\n throw new Error(`Invalid argument, cannot set over ${key} ${current.constructor.name}`);\n } else if (isReactiveField(current) || isAsyncReactiveField(current)) {\n if (value instanceof FactoryInitialValue) {\n if (current instanceof ReactiveFieldImpl) {\n current.setFactoryValue(value.value);\n } else if (current instanceof AsyncReactiveFieldImpl) {\n current.setFactoryValue(value.value);\n } else {\n throw new Error(`Unhandled case ${current.constructor.name}`);\n }\n } else {\n throw new Error(`Invalid argument, cannot set over ${key} ${current.constructor.name}`);\n }\n } else {\n // If setting an explicit id, go through setField, otherwise use\n // `entity[key]` to set the value directly to that we go through setters.\n if (key === \"id\" && entity.isNewEntity) {\n setField(entity, key, value);\n } else {\n (entity as any)[key] = value;\n }\n }\n}\n\nexport function ensureNotDeleted(entity: Entity, ignore?: \"pending\"): void {\n if (entity.isDeletedEntity && (ignore === undefined || getInstanceData(entity).isDeletedAndFlushed)) {\n fail(`${entity} is marked as deleted`);\n }\n}\n\n/** Adds `null` to every key in `T` to accept partial-update-style input. */\nexport type PartialOrNull<T> = {\n [P in keyof T]?: T[P] | null;\n};\n\nexport function getRequiredKeys<T extends Entity>(entity: T): string[];\nexport function getRequiredKeys<T extends Entity>(type: EntityConstructor<T>): string[];\nexport function getRequiredKeys<T extends Entity>(entityOrType: T | EntityConstructor<T>): string[] {\n return Object.values(getMetadata(entityOrType as any).fields)\n .filter((f) => f.required)\n .map((f) => f.fieldName);\n}\n\nexport function getRelations(entity: Entity): AbstractRelationImpl<any, any>[] {\n return Object.entries(getProperties(getMetadata(entity)))\n .filter(([, v]) => v instanceof AbstractRelationImpl)\n .map(([name]) => (entity as any)[name]);\n}\n\nexport function getRelationEntries(entity: Entity): [string, AbstractRelationImpl<any, any>][] {\n return Object.entries(getProperties(getMetadata(entity)))\n .filter(([, v]) => v instanceof AbstractRelationImpl)\n .map(([name]) => [name, (entity as any)[name]]);\n}\n\n/** Casts a \"maybe abstract\" cstr to a concrete cstr when the calling code knows it's safe. */\nexport function asConcreteCstr<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): EntityConstructor<T> {\n return cstr as any;\n}\n\n/**\n * Thrown when `.id` is accessed on an entity that does not have an id yet.\n *\n * For Postgres, entities are actually allowed to have ids pre-INSERT, if you call\n * `em.assignNewIds()`. Other databases typically require INSERTs to trigger the auto\n * id assignment.\n */\nexport class NoIdError extends Error {}\n\n/** Throws a `NoIdError` for `entity`, i.e. because `id` was called before being saved. */\nexport function failNoIdYet(entity: string): never {\n throw new NoIdError(`${entity} has no id yet`);\n}\n\n/**\n * Add a static function since getters can't have type guards.\n *\n * See https://github.com/microsoft/TypeScript/issues/43368\n */\nexport function isNewEntity<T extends Entity>(entity: T): entity is New<T> {\n return entity.isNewEntity;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["getMetadata","getProperties","getBaseMeta","getField","AbstractRelationImpl","isLazyField","isProperty","isAsyncProperty","isReactiveGetter","isReactiveField","isAsyncReactiveField","FactoryInitialValue","ReactiveFieldImpl","AsyncReactiveFieldImpl","getInstanceData"],"sources":["../src/index.ts"],"sourcesContent":["import { getInstanceData } from \"./BaseEntity.ts\";\nimport { getDefaultDependencies } from \"./defaults.ts\";\nimport { buildWhereClause } from \"./drivers/buildUtils.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type EntityConstructor, type MaybeAbstractEntityConstructor } from \"./EntityManager.ts\";\nimport { type EntityMetadata, getBaseMeta, getMetadata } from \"./EntityMetadata.ts\";\nimport { getField, setField } from \"./fields.ts\";\nimport { getProperties } from \"./getProperties.ts\";\nimport { type New } from \"./loadHints.ts\";\nimport { isAllSqlPaths } from \"./loadLens.ts\";\nimport { FactoryInitialValue } from \"./newTestInstance.ts\";\nimport { partitionHint } from \"./preloading/partitionHint.ts\";\nimport { AbstractRelationImpl } from \"./relations/AbstractRelationImpl.ts\";\nimport { AsyncReactiveFieldImpl } from \"./relations/AsyncReactiveField.ts\";\nimport {\n isAsyncProperty,\n isAsyncReactiveField,\n isLazyField,\n isProperty,\n isReactiveField,\n isReactiveGetter,\n} from \"./relations/index.ts\";\nimport { ReactiveFieldImpl } from \"./relations/ReactiveField.ts\";\nimport { type OptsOf } from \"./typeMap.ts\";\nimport { fail } from \"./utils.ts\";\n\nexport const testing = { isAllSqlPaths, getDefaultDependencies, partitionHint };\nexport const internals = { buildWhereClause };\nexport { newPgConnectionConfig } from \"joist-utils\";\nexport { AliasAssigner } from \"./AliasAssigner.ts\";\nexport {\n type AndCondition,\n type ConditionGroup,\n type DomainPredicate,\n type OrCondition,\n type PredicateBrand,\n type SqlCondition,\n type SqlPredicate,\n} from \"./conditions.ts\";\n// Domain aliases belong to em.find; physical table expressions belong to em.query/em.execute.\nexport {\n alias,\n aliases,\n getAliasMetadata,\n getAliasMgmt,\n getMaybeCtiAlias,\n isAlias,\n newAliasProxy,\n type Alias,\n type AliasBrand,\n type AliasMgmt,\n type AliasColumn,\n type EntityAlias,\n type PolyAlias,\n type PrimitiveAlias,\n} from \"./Aliases.ts\";\nexport {\n table,\n tables,\n tableMgmt,\n getTableMetadata,\n getTableMgmt,\n isTable,\n newTableProxy,\n type Table,\n type TableFilter,\n type TableBrand,\n type TableFor,\n type TableMgmt,\n type ReferenceJoin,\n type PrimitiveColumn,\n type EntityColumn,\n type ReferenceColumn,\n type CollectionJoin,\n type PolyReference,\n} from \"./Tables.ts\";\nexport { BaseEntity, getInstanceData } from \"./BaseEntity.ts\";\nexport { ConditionBuilder } from \"./ConditionBuilder.ts\";\nexport { type Entity, type IdType, isEntity } from \"./Entity.ts\";\nexport type * from \"./EntityFields.ts\";\nexport * from \"./EntityFilter.ts\";\nexport * from \"./EntityGraphQLFilter.ts\";\nexport * from \"./EntityManager.ts\";\nexport * from \"./EntityMetadata.ts\";\nexport type {\n DeleteStatement,\n ExecuteResult,\n InsertStatement,\n InsertValues,\n MutationReturning,\n MutationStatement,\n UpdateStatement,\n UpdateValues,\n} from \"./execute.ts\";\nexport type { EnumMetadata } from \"./EnumMetadata.ts\";\n// `em.query`'s expression surface. Only the user-facing types are re-exported: the runtime half\n// (BaseExpr, asNode, deferredCondition, the FnExpr/TemplateExpr node classes) stays internal to\n// joist-core, so `toSql`/`decode`/`encode` never show up as something a user could call.\nexport {\n type ArrayAggOptions,\n type Expr,\n type ExprBrand,\n exprBrand,\n type ExprLike,\n type InnerJoin,\n type LeftJoin,\n} from \"./Expr.ts\";\nexport { expr, type CaseElse, type CaseWhen, type ExprFromInput, type ExprInput } from \"./expressions/expression.ts\";\nexport { skipCondition } from \"./skipCondition.ts\";\nexport type { EntityOrId, HintNode } from \"./HintTree.ts\";\nexport { InstanceData } from \"./InstanceData.ts\";\nexport { type JoinColumnValue, type JoinRow, JoinRowOperation, type ManyToManyLike } from \"./JoinRows.ts\";\nexport type * from \"./PendingChanges.ts\";\nexport { Plugin } from \"./PluginManager.ts\";\nexport * from \"./QueryParser.ts\";\nexport * from \"./QueryParser.collectionJoins.ts\";\nexport { visitConditions } from \"./QueryVisitor.ts\";\nexport * from \"./RowData.ts\";\nexport { type JoinRowTodo, Todo } from \"./Todo.ts\";\nexport * from \"./changes.ts\";\nexport { ConfigApi, type EntityHook, resetBootFlag } from \"./config.ts\";\nexport {\n configureMetadata,\n getConstructorFromTaggedId,\n getMetadataForTable,\n getMetadataForType,\n maybeGetConstructorFromReference,\n} from \"./configure.ts\";\nexport { driverApi } from \"./driverApi.ts\";\nexport * from \"./drivers/index.ts\";\nexport { getField, isChangeableField, isFieldSet, setField } from \"./fields.ts\";\nexport * from \"./getProperties.ts\";\nexport * from \"./json.ts\";\nexport * from \"./keys.ts\";\nexport { kq, kqDot, kqStar } from \"./keywords.ts\";\nexport {\n assertLoaded,\n type DeepNew,\n ensureLoaded,\n isLoaded,\n isNew,\n type Loadable,\n type Loaded,\n type LoadHint,\n type MarkLoaded,\n maybePopulateThen,\n type NestedLoadHint,\n type New,\n type RelationsIn,\n unsafeLoaded,\n} from \"./loadHints.ts\";\nexport * from \"./loadLens.ts\";\nexport { setFactoryWriter } from \"./logging/FactoryLogger.ts\";\nexport * from \"./logging/FieldLogger.ts\";\nexport { ReactionLogger, setReactionLogging } from \"./logging/ReactionLogger.ts\";\nexport { lazyField } from \"./newEntity.ts\";\nexport {\n defaultValue,\n factories,\n type FactoryEntityOpt,\n type FactoryOpts,\n getTestIndex,\n isFactoryCreation,\n maybeBranchValue,\n maybeNew,\n maybeNewPoly,\n newTestInstance,\n noValue,\n setFactoryLogging,\n testIndex,\n} from \"./newTestInstance.ts\";\nexport { deepNormalizeHint, normalizeHint } from \"./normalizeHints.ts\";\nexport { ImmutableEntitiesPlugin } from \"./plugins/ImmutableEntitiesPlugin.ts\";\nexport type { JoinResult, PreloadHydrator, PreloadPlugin } from \"./plugins/PreloadPlugin.ts\";\nexport { JsonAggregatePreloader } from \"./preloading/JsonAggregatePreloader.ts\";\n// `em.query`'s query surface; the parse pipeline (SubqueryHandle, parseUserQuery, Plan) stays internal\nexport {\n type CheckScope,\n type Clauses,\n type EntityQuery,\n type ExpressionOrderBy,\n type ExistsQuery,\n entityQueryBrand,\n type MaybeNull,\n type NameOf,\n type NotWidened,\n type OrderByDirection,\n type OrderByKeys,\n type Query,\n type QueryArg,\n type QueryCondition,\n type QueryJoin,\n type QueryJoins,\n type QueryRow,\n type QuerySelect,\n type QuerySource,\n type QueryValue,\n recursiveQuery,\n type RecursiveOptions,\n type ScalarQuery,\n type SetQuery,\n query,\n sql,\n type Subquery,\n type SubqueryBrand,\n subqueryBrand,\n type WithInput,\n type WithSource,\n} from \"./query.ts\";\nexport {\n convertToLoadHint,\n isTypeOrSubType,\n type Reactable,\n type Reacted,\n type ReactiveHint,\n type ReactiveTarget,\n reverseReactiveHint,\n} from \"./reactiveHints.ts\";\nexport * from \"./relations/index.ts\";\nexport {\n cannotBeChanged,\n cannotBeUpdated,\n type GenericError,\n maxValueRule,\n minValueRule,\n mustBeSubType,\n newRequiredLazyFieldRule,\n newRequiredRule,\n rangeValueRule,\n ValidationCode,\n type ValidationError,\n ValidationErrors,\n type ValidationRule,\n type ValidationRuleInternal,\n type ValidationRuleResult,\n} from \"./rules.ts\";\nexport { getRuntimeConfig, setRuntimeConfig, type RuntimeConfig } from \"./runtimeConfig.ts\";\nexport { nowUTC } from \"./nowUTC.ts\";\nexport * from \"./serde.ts\";\nexport * from \"./columns.ts\";\nexport * from \"./fieldSerde.ts\";\nexport * from \"./scopes.ts\";\nexport { maybeRequireTemporal, requireTemporal, Temporal } from \"./temporal.ts\";\nexport * from \"./temporalMappers.ts\";\nexport { isInTrustedContext, runInTrustedContext } from \"./trusted.ts\";\nexport type * from \"./typeMap.ts\";\nexport { buildUnnestCte, ensureRectangularArraySizes } from \"./unnest.ts\";\nexport { type DeepPartialOrNull, updatePartial, upsert } from \"./upsert.ts\";\nexport {\n abbreviation,\n asNew,\n assertNever,\n cleanSql,\n cleanStringValue,\n fail,\n failIfAnyRejected,\n indexBy,\n partition,\n zeroTo,\n} from \"./utils.ts\";\nexport { ensureWithLoaded, StubbedRelation, type WithLoaded, withLoaded } from \"./withLoaded.ts\";\n\n// https://spin.atomicobject.com/2018/01/15/typescript-flexible-nominal-typing/\ninterface Flavoring<FlavorT> {\n _type?: FlavorT;\n}\n\nexport type Flavor<T, FlavorT> = T & Flavoring<FlavorT>;\n\n/**\n * Sets each value in `values` on the current entity.\n *\n * The default behavior is that passing a value as either `null` or `undefined` will set\n * the field as `undefined`, i.e. automatic `null` to `undefined` conversion.\n *\n * However, if you pass `ignoreUndefined: true`, then any opt that is `undefined` will be treated\n * as \"do not set\", and `null` will still mean \"set to `undefined`\". This is useful for implementing\n * APIs were an input of `undefined` means \"do not set / noop\" and `null` means \"unset\".\n *\n * Note that constructors _always_ call this method, but if the call is coming from `em.hydrate`, we\n * use `values` being a primary key to short-circuit and let hydration callers assign the values\n * returned by the serde `fromRow` methods.\n */\nexport function setOpts<T extends Entity>(\n entity: T,\n values: Partial<OptsOf<T>> | undefined,\n opts?: { partial?: boolean; calledFromConstructor?: boolean },\n): void {\n const { calledFromConstructor = false, partial } = opts || {};\n // If `values` is undefined, we're being called by `createPartial` that will do its\n // own opt handling, but we still want the sync defaults applied after this opts handling.\n if (values !== undefined) {\n const meta = getMetadata(entity);\n for (const [key, _value] of Object.entries(values as {})) {\n setOpt(meta, entity, key, _value, partial, calledFromConstructor);\n }\n }\n}\n\n/**\n * Applies some standard behavior & protections to `entity[key] = value`. I.e.\n *\n * - We don't set over AsyncProperties/relations/etc., and instead call current.set(value)\n * - We catch missing/invalid field names\n * - We handle FactoryInitialValues\n */\nexport function setOpt<T extends Entity>(\n meta: EntityMetadata<T>,\n entity: T,\n key: string,\n _value: any,\n partial = false,\n calledFromConstructor = false,\n): void {\n const field = meta.allFields[key];\n if (!field) {\n // Allow setting non-field properties like fullName setters\n const prop = getProperties(meta)[key];\n if (!prop) {\n throw new Error(`Unknown field ${key}`);\n }\n }\n\n // If partial is set, we treat undefined as a noop\n if (partial && _value === undefined) return;\n // Ignore the STI discriminator, em.register will set this accordingly\n if (meta.inheritanceType === \"sti\" && getBaseMeta(meta).stiDiscriminatorField === key) return;\n\n // We let optional opts fields be `| null` for convenience, and convert to undefined.\n const value = _value === null ? undefined : _value;\n\n // Use `getField` to side-step `id` blowing up on new entities that are setting an\n // explicit id; otherwise use `entity[key]` to get back the relation.\n const current = key === \"id\" ? getField(entity, key) : (entity as any)[key];\n\n if (current instanceof AbstractRelationImpl) {\n if (calledFromConstructor) {\n current.setFromOpts(value);\n } else {\n current.set(value);\n }\n } else if (isLazyField(current)) {\n current.set(value);\n } else if (isProperty(current) || isAsyncProperty(current) || isReactiveGetter(current)) {\n throw new Error(`Invalid argument, cannot set over ${key} ${current.constructor.name}`);\n } else if (isReactiveField(current) || isAsyncReactiveField(current)) {\n if (value instanceof FactoryInitialValue) {\n if (current instanceof ReactiveFieldImpl) {\n current.setFactoryValue(value.value);\n } else if (current instanceof AsyncReactiveFieldImpl) {\n current.setFactoryValue(value.value);\n } else {\n throw new Error(`Unhandled case ${current.constructor.name}`);\n }\n } else {\n throw new Error(`Invalid argument, cannot set over ${key} ${current.constructor.name}`);\n }\n } else {\n // If setting an explicit id, go through setField, otherwise use\n // `entity[key]` to set the value directly to that we go through setters.\n if (key === \"id\" && entity.isNewEntity) {\n setField(entity, key, value);\n } else {\n (entity as any)[key] = value;\n }\n }\n}\n\nexport function ensureNotDeleted(entity: Entity, ignore?: \"pending\"): void {\n if (entity.isDeletedEntity && (ignore === undefined || getInstanceData(entity).isDeletedAndFlushed)) {\n fail(`${entity} is marked as deleted`);\n }\n}\n\n/** Adds `null` to every key in `T` to accept partial-update-style input. */\nexport type PartialOrNull<T> = {\n [P in keyof T]?: T[P] | null;\n};\n\nexport function getRequiredKeys<T extends Entity>(entity: T): string[];\nexport function getRequiredKeys<T extends Entity>(type: EntityConstructor<T>): string[];\nexport function getRequiredKeys<T extends Entity>(entityOrType: T | EntityConstructor<T>): string[] {\n return Object.values(getMetadata(entityOrType as any).fields)\n .filter((f) => f.required)\n .map((f) => f.fieldName);\n}\n\nexport function getRelations(entity: Entity): AbstractRelationImpl<any, any>[] {\n return Object.entries(getProperties(getMetadata(entity)))\n .filter(([, v]) => v instanceof AbstractRelationImpl)\n .map(([name]) => (entity as any)[name]);\n}\n\nexport function getRelationEntries(entity: Entity): [string, AbstractRelationImpl<any, any>][] {\n return Object.entries(getProperties(getMetadata(entity)))\n .filter(([, v]) => v instanceof AbstractRelationImpl)\n .map(([name]) => [name, (entity as any)[name]]);\n}\n\n/** Casts a \"maybe abstract\" cstr to a concrete cstr when the calling code knows it's safe. */\nexport function asConcreteCstr<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): EntityConstructor<T> {\n return cstr as any;\n}\n\n/**\n * Thrown when `.id` is accessed on an entity that does not have an id yet.\n *\n * For Postgres, entities are actually allowed to have ids pre-INSERT, if you call\n * `em.assignNewIds()`. Other databases typically require INSERTs to trigger the auto\n * id assignment.\n */\nexport class NoIdError extends Error {}\n\n/** Throws a `NoIdError` for `entity`, i.e. because `id` was called before being saved. */\nexport function failNoIdYet(entity: string): never {\n throw new NoIdError(`${entity} has no id yet`);\n}\n\n/**\n * Add a static function since getters can't have type guards.\n *\n * See https://github.com/microsoft/TypeScript/issues/43368\n */\nexport function isNewEntity<T extends Entity>(entity: T): entity is New<T> {\n return entity.isNewEntity;\n}\n"],"mappings":"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"}