joist-core 2.3.0-next.63 → 2.3.0-next.64

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.
Files changed (75) hide show
  1. package/build/Aliases.cjs +11 -10
  2. package/build/Aliases.cjs.map +1 -1
  3. package/build/Aliases.d.cts +19 -1
  4. package/build/Aliases.d.cts.map +1 -1
  5. package/build/Aliases.d.mts +19 -1
  6. package/build/Aliases.d.mts.map +1 -1
  7. package/build/Aliases.js +2 -1
  8. package/build/Aliases.js.map +1 -1
  9. package/build/ConditionBuilder.cjs +2 -3
  10. package/build/ConditionBuilder.cjs.map +1 -1
  11. package/build/ConditionBuilder.js +1 -2
  12. package/build/ConditionBuilder.js.map +1 -1
  13. package/build/DeferredAlias.cjs +2 -9
  14. package/build/DeferredAlias.cjs.map +1 -1
  15. package/build/DeferredAlias.d.cts +3 -5
  16. package/build/DeferredAlias.d.cts.map +1 -1
  17. package/build/DeferredAlias.d.mts +3 -5
  18. package/build/DeferredAlias.d.mts.map +1 -1
  19. package/build/DeferredAlias.js +3 -9
  20. package/build/DeferredAlias.js.map +1 -1
  21. package/build/Expr.cjs +6 -20
  22. package/build/Expr.cjs.map +1 -1
  23. package/build/Expr.d.cts +7 -9
  24. package/build/Expr.d.cts.map +1 -1
  25. package/build/Expr.d.mts +7 -9
  26. package/build/Expr.d.mts.map +1 -1
  27. package/build/Expr.js +5 -15
  28. package/build/Expr.js.map +1 -1
  29. package/build/QueryParser.cjs +1 -1
  30. package/build/QueryParser.cjs.map +1 -1
  31. package/build/QueryParser.js +1 -1
  32. package/build/QueryParser.js.map +1 -1
  33. package/build/Tables.cjs +68 -159
  34. package/build/Tables.cjs.map +1 -1
  35. package/build/Tables.d.cts +17 -0
  36. package/build/Tables.d.cts.map +1 -1
  37. package/build/Tables.d.mts +17 -0
  38. package/build/Tables.d.mts.map +1 -1
  39. package/build/Tables.js +49 -140
  40. package/build/Tables.js.map +1 -1
  41. package/build/drivers/buildUtils.cjs +5 -1
  42. package/build/drivers/buildUtils.cjs.map +1 -1
  43. package/build/drivers/buildUtils.d.cts +4 -2
  44. package/build/drivers/buildUtils.d.cts.map +1 -1
  45. package/build/drivers/buildUtils.d.mts +4 -2
  46. package/build/drivers/buildUtils.d.mts.map +1 -1
  47. package/build/drivers/buildUtils.js +5 -2
  48. package/build/drivers/buildUtils.js.map +1 -1
  49. package/build/drivers/index.cjs +1 -0
  50. package/build/drivers/index.d.cts +2 -2
  51. package/build/drivers/index.d.mts +2 -2
  52. package/build/drivers/index.js +2 -2
  53. package/build/index.cjs +3 -2
  54. package/build/index.cjs.map +1 -1
  55. package/build/index.d.cts +3 -3
  56. package/build/index.d.cts.map +1 -1
  57. package/build/index.d.mts +3 -3
  58. package/build/index.d.mts.map +1 -1
  59. package/build/index.js +3 -3
  60. package/build/index.js.map +1 -1
  61. package/build/query.cjs +7 -7
  62. package/build/query.cjs.map +1 -1
  63. package/build/query.d.cts +1 -1
  64. package/build/query.d.mts +1 -1
  65. package/build/query.js +6 -6
  66. package/build/query.js.map +1 -1
  67. package/build/skipCondition.cjs +15 -0
  68. package/build/skipCondition.cjs.map +1 -0
  69. package/build/skipCondition.d.cts +7 -0
  70. package/build/skipCondition.d.cts.map +1 -0
  71. package/build/skipCondition.d.mts +7 -0
  72. package/build/skipCondition.d.mts.map +1 -0
  73. package/build/skipCondition.js +14 -0
  74. package/build/skipCondition.js.map +1 -0
  75. package/package.json +2 -2
package/build/Aliases.cjs CHANGED
@@ -2,10 +2,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("./typeMap.cjs");
3
3
  require("./EntityFilter.cjs");
4
4
  const require_keys = require("./keys.cjs");
5
- const require_DeferredAlias = require("./DeferredAlias.cjs");
5
+ const require_skipCondition = require("./skipCondition.cjs");
6
6
  require("./serde.cjs");
7
7
  const require_EntityMetadata = require("./EntityMetadata.cjs");
8
8
  const require_utils = require("./utils.cjs");
9
+ const require_DeferredAlias = require("./DeferredAlias.cjs");
9
10
  require("./EntityManager.cjs");
10
11
  require("./Entity.cjs");
11
12
  const require_configure = require("./configure.cjs");
@@ -110,7 +111,7 @@ var AliasColumnImpl = class AliasColumnImpl {
110
111
  });
111
112
  }
112
113
  in(values) {
113
- if (values === void 0) return require_DeferredAlias.skipCondition;
114
+ if (values === void 0) return require_skipCondition.skipCondition;
114
115
  if (values === null) return require_utils.fail("Unsupported");
115
116
  if (values.includes(null)) return { or: [this.addCondition({ kind: "is-null" }), this.addCondition({
116
117
  kind: "in",
@@ -122,7 +123,7 @@ var AliasColumnImpl = class AliasColumnImpl {
122
123
  });
123
124
  }
124
125
  nin(values) {
125
- if (values === void 0) return require_DeferredAlias.skipCondition;
126
+ if (values === void 0) return require_skipCondition.skipCondition;
126
127
  if (values === null) return require_utils.fail("Unsupported");
127
128
  return this.addCondition({
128
129
  kind: "nin",
@@ -130,7 +131,7 @@ var AliasColumnImpl = class AliasColumnImpl {
130
131
  });
131
132
  }
132
133
  between(v1, v2) {
133
- if (v1 === void 0 || v2 === void 0) return require_DeferredAlias.skipCondition;
134
+ if (v1 === void 0 || v2 === void 0) return require_skipCondition.skipCondition;
134
135
  return this.addCondition({
135
136
  kind: "between",
136
137
  value: [v1, v2]
@@ -149,7 +150,7 @@ var AliasColumnImpl = class AliasColumnImpl {
149
150
  });
150
151
  }
151
152
  search(value) {
152
- return !value ? require_DeferredAlias.skipCondition : this.addCondition({
153
+ return !value ? require_skipCondition.skipCondition : this.addCondition({
153
154
  kind: "ilike",
154
155
  value: require_QueryParser.makeLike(value)
155
156
  });
@@ -167,7 +168,7 @@ var AliasColumnImpl = class AliasColumnImpl {
167
168
  });
168
169
  }
169
170
  raw(exp, bindings) {
170
- if (bindings === void 0) return require_DeferredAlias.skipCondition;
171
+ if (bindings === void 0) return require_skipCondition.skipCondition;
171
172
  return require_DeferredAlias.withDeferredAlias({
172
173
  kind: "raw",
173
174
  aliases: [],
@@ -183,7 +184,7 @@ var AliasColumnImpl = class AliasColumnImpl {
183
184
  }
184
185
  /** Maps literal values through the field serde and binds aliases only when parsing. */
185
186
  addCondition(value) {
186
- if ("value" in value && value.value === void 0) return require_DeferredAlias.skipCondition;
187
+ if ("value" in value && value.value === void 0) return require_skipCondition.skipCondition;
187
188
  const cond = {
188
189
  kind: "column",
189
190
  alias: "unset",
@@ -198,7 +199,7 @@ var AliasColumnImpl = class AliasColumnImpl {
198
199
  }
199
200
  /** Handles literal values, NULL, and domain cross-alias comparisons. */
200
201
  compare(kind, op, value) {
201
- if (value === void 0) return require_DeferredAlias.skipCondition;
202
+ if (value === void 0) return require_skipCondition.skipCondition;
202
203
  if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, op);
203
204
  if (value === null && (kind === "eq" || kind === "ne")) return this.addCondition({ kind: kind === "eq" ? "is-null" : "not-null" });
204
205
  if (value === null && [
@@ -230,7 +231,7 @@ var PolyReferenceAlias = class {
230
231
  return this.addEqOrNe("ne", value);
231
232
  }
232
233
  in(values) {
233
- if (values === void 0) return require_DeferredAlias.skipCondition;
234
+ if (values === void 0) return require_skipCondition.skipCondition;
234
235
  const groups = (0, joist_utils.groupBy)(values, (id) => require_configure.getConstructorFromTaggedId(require_keys.maybeResolveReferenceToId(id)).name);
235
236
  return { or: Object.entries(groups).map(([name, ids]) => {
236
237
  const comp = this.field.components.find((c) => c.otherMetadata().cstr.name === name) ?? require_utils.fail(`No component for ${name}`);
@@ -242,7 +243,7 @@ var PolyReferenceAlias = class {
242
243
  }
243
244
  /** Picks the component from an entity, tagged id, or another domain alias column. */
244
245
  addEqOrNe(kind, value) {
245
- if (value === void 0) return require_DeferredAlias.skipCondition;
246
+ if (value === void 0) return require_skipCondition.skipCondition;
246
247
  if (value === null) return { and: this.field.components.map((c) => this.component(c).addCondition({ kind: kind === "eq" ? "is-null" : "not-null" })) };
247
248
  const otherMeta = value instanceof AliasColumnImpl ? value.field.kind === "m2o" ? value.field.otherMetadata() : value.meta : require_EntityMetadata.getMetadata(require_configure.getConstructorFromTaggedId(require_keys.maybeResolveReferenceToId(value)));
248
249
  const comp = this.field.components.find((c) => require_EntityMetadata.getBaseAndSelfMetas(otherMeta).includes(c.otherMetadata())) ?? require_utils.fail(`${this.field.fieldName} has no component for ${otherMeta.type}`);
@@ -1 +1 @@
1
- {"version":3,"file":"Aliases.cjs","names":["getMetadata","fail","skipCondition","makeLike","withDeferredAlias","mapToDb","groupBy","getConstructorFromTaggedId","maybeResolveReferenceToId","getBaseAndSelfMetas"],"sources":["../src/Aliases.ts"],"sourcesContent":["import { groupBy } from \"joist-utils\";\n\n// Load configure first: relations must not evaluate before their base classes exist.\nimport { getConstructorFromTaggedId } from \"./configure.ts\";\nimport { skipCondition, withDeferredAlias } from \"./DeferredAlias.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type ExpressionCondition } from \"./EntityFilter.ts\";\nimport { type IdOf, type MaybeAbstractEntityConstructor, type TaggedId } from \"./EntityManager.ts\";\nimport {\n type EntityMetadata,\n type Field,\n type PolymorphicField,\n type PolymorphicFieldComponent,\n getBaseAndSelfMetas,\n getMetadata,\n} from \"./EntityMetadata.ts\";\nimport { maybeResolveReferenceToId } from \"./keys.ts\";\nimport { type ColumnCondition, type ParsedValueFilter, type RawCondition, makeLike, mapToDb } from \"./QueryParser.ts\";\nimport { type Column } from \"./serde.ts\";\nimport { type FieldsOf } from \"./typeMap.ts\";\nimport { fail } from \"./utils.ts\";\n\n/** Creates an alias for complex domain filtering in `em.find`. */\nexport function alias<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): Alias<T> {\n return newAliasProxy(cstr);\n}\n\n/** Creates multiple aliases for complex filtering. */\nexport function aliases<T extends readonly MaybeAbstractEntityConstructor<any>[]>(\n ...types: T\n): { [P in keyof T]: T[P] extends MaybeAbstractEntityConstructor<infer E extends Entity> ? Alias<E> : never } {\n return types.map((t) => newAliasProxy(t)) as any;\n}\n\nexport const aliasMgmt = Symbol(\"aliasMgmt\");\nconst aliasColumn = Symbol(\"aliasColumn\");\n\n/** The identity and original entity metadata of an `em.find` alias. */\nexport interface AliasMgmt {\n tableName: string;\n meta: EntityMetadata;\n}\n\n/** Keeps domain aliases covariant in their entity type. */\nexport interface AliasBrand<T> extends AliasMgmt {\n readonly __entity: T;\n}\n\n/** Domain field predicates, deliberately separate from SQL table expressions. */\nexport type Alias<T extends Entity> = { readonly [aliasMgmt]: AliasBrand<T> } & {\n [P in keyof FieldsOf<T>]: P extends \"id\"\n ? EntityAlias<T>\n : FieldsOf<T>[P] extends { kind: \"primitive\" | \"enum\"; type: infer V; nullable: infer N }\n ? PrimitiveAlias<V, N extends undefined ? null : never>\n : FieldsOf<T>[P] extends { kind: \"m2o\"; type: infer U extends Entity; nullable: infer N }\n ? EntityAlias<U, N extends undefined ? null : never>\n : FieldsOf<T>[P] extends { kind: \"poly\"; type: infer U extends Entity }\n ? PolyAlias<U>\n : never;\n};\n\n/** A domain column accepted on the other side of a cross-alias comparison. */\nexport interface AliasColumn<V> {\n readonly [aliasColumn]: V;\n}\n\nexport interface PrimitiveAlias<V, N extends null | never = never> extends AliasColumn<V | N> {\n eq(value: V | N | AliasColumn<V | null> | undefined): ExpressionCondition;\n ne(value: V | N | AliasColumn<V | null> | undefined): ExpressionCondition;\n in(values: readonly (V | null)[] | undefined): ExpressionCondition;\n nin(values: readonly (V | null)[] | undefined): ExpressionCondition;\n gt(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n gte(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n lt(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n lte(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n like(value: V | undefined): ExpressionCondition;\n ilike(value: V | undefined): ExpressionCondition;\n search(value: V | undefined): ExpressionCondition;\n between(v1: V | undefined, v2: V | undefined): ExpressionCondition;\n // V is already an array; strings also support jsonb contains.\n contains(value: string | V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n ncontains(value: string | V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n overlaps(value: V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n noverlaps(value: V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n /** Adds a parameterized JSON path existence condition using `@?`. */\n pathExists(jsonPath: string | undefined): ExpressionCondition;\n /** Adds a parameterized JSON path predicate condition using `@@`. */\n pathIsTrue(jsonPath: string | undefined): ExpressionCondition;\n /** Adds an operator and expression with knex-style placeholders, without the column name. */\n raw(exp: string, bindings: readonly unknown[] | undefined): ExpressionCondition;\n}\n\nexport interface EntityAlias<T, N extends null | never = never> extends AliasColumn<IdOf<T> | N> {\n eq(value: T | IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n ne(value: T | IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n // Adding `| null` for GraphQL support\n in(values: readonly (T | IdOf<T> | null)[] | null | undefined): ExpressionCondition;\n nin(values: readonly (T | IdOf<T> | null)[] | null | undefined): ExpressionCondition;\n gt(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n gte(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n lt(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n lte(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n raw(exp: string, bindings: readonly unknown[] | undefined): ExpressionCondition;\n}\n\nexport interface PolyAlias<T extends Entity> {\n eq(value: T | TaggedId | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n ne(value: T | TaggedId | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n in(values: readonly (T | TaggedId)[] | undefined): ExpressionCondition;\n}\n\n/** Returns the runtime identity bound by the find parser. */\nexport function getAliasMgmt(alias: { readonly [aliasMgmt]: AliasMgmt }): AliasMgmt {\n return alias[aliasMgmt];\n}\n\n/** Returns the original metadata, preserving STI subtype identity. */\nexport function getAliasMetadata<T extends Entity>(alias: Alias<T>): EntityMetadata<T> {\n return alias[aliasMgmt].meta as EntityMetadata<T>;\n}\n\n/** Creates domain predicates lazily from entity field metadata. */\nexport function newAliasProxy<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): Alias<T> {\n const meta = getMetadata(cstr);\n const mgmt: AliasMgmt = { tableName: meta.tableName, meta };\n return new Proxy(cstr, {\n get(_, key) {\n if (key === aliasMgmt) return mgmt;\n if (typeof key !== \"string\") return undefined;\n const field = meta.allFields[key] ?? fail(`No field ${key} on ${cstr.name}`);\n if (field.kind === \"poly\") return new PolyReferenceAlias(meta, mgmt, field);\n if ([\"primaryKey\", \"primitive\", \"enum\", \"m2o\"].includes(field.kind)) {\n return new AliasColumnImpl(meta, field, field.serde!.columns[0], mgmt);\n }\n return fail(`Unsupported alias field kind ${field.kind}`);\n },\n has(_, key) {\n return key === aliasMgmt || key in meta.allFields;\n },\n }) as unknown as Alias<T>;\n}\n\n/** Recognizes only domain aliases, not physical tables. */\nexport function isAlias(value: unknown): value is Alias<Entity> {\n return typeof value === \"function\" && aliasMgmt in value;\n}\n\n/** Builds field conditions without implementing the SQL expression protocol. */\nclass AliasColumnImpl {\n declare readonly [aliasColumn]: unknown;\n\n constructor(\n readonly meta: EntityMetadata,\n readonly field: Field & { aliasSuffix: string },\n readonly column: Column,\n readonly mgmt: AliasMgmt,\n ) {}\n\n eq(value: unknown): ExpressionCondition {\n return this.compare(\"eq\", \"=\", value);\n }\n ne(value: unknown): ExpressionCondition {\n return this.compare(\"ne\", \"!=\", value);\n }\n gt(value: unknown): ExpressionCondition {\n return this.compare(\"gt\", \">\", value);\n }\n gte(value: unknown): ExpressionCondition {\n return this.compare(\"gte\", \">=\", value);\n }\n lt(value: unknown): ExpressionCondition {\n return this.compare(\"lt\", \"<\", value);\n }\n lte(value: unknown): ExpressionCondition {\n return this.compare(\"lte\", \"<=\", value);\n }\n contains(value: unknown): ExpressionCondition {\n return this.compare(\"contains\", \"@>\", value);\n }\n ncontains(value: unknown): ExpressionCondition {\n if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, \"@>\", true);\n return this.addCondition({ kind: \"ncontains\", value: value as readonly unknown[] });\n }\n overlaps(value: unknown): ExpressionCondition {\n return this.compare(\"overlaps\", \"&&\", value);\n }\n noverlaps(value: unknown): ExpressionCondition {\n if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, \"&&\", true);\n return this.addCondition({ kind: \"noverlaps\", value: value as readonly unknown[] });\n }\n\n in(values: readonly unknown[] | null | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (values === null) return fail(\"Unsupported\");\n if (values.includes(null)) {\n return {\n or: [\n this.addCondition({ kind: \"is-null\" }),\n this.addCondition({ kind: \"in\", value: values.filter((v) => v !== null) }),\n ],\n };\n }\n return this.addCondition({ kind: \"in\", value: [...values] });\n }\n\n nin(values: readonly unknown[] | null | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (values === null) return fail(\"Unsupported\");\n return this.addCondition({ kind: \"nin\", value: values.filter((v) => v !== null) });\n }\n\n between(v1: unknown, v2: unknown): ExpressionCondition {\n if (v1 === undefined || v2 === undefined) return skipCondition;\n return this.addCondition({ kind: \"between\", value: [v1, v2] });\n }\n\n like(value: unknown): ExpressionCondition {\n return this.addCondition({ kind: \"like\", value });\n }\n ilike(value: unknown): ExpressionCondition {\n return this.addCondition({ kind: \"ilike\", value });\n }\n search(value: unknown): ExpressionCondition {\n // Check !value so that empty strings are pruned\n return !value ? skipCondition : this.addCondition({ kind: \"ilike\", value: makeLike(value) });\n }\n pathExists(value: string | undefined): ExpressionCondition {\n return this.addCondition({ kind: \"jsonPathExists\", value: value! });\n }\n pathIsTrue(value: string | undefined): ExpressionCondition {\n return this.addCondition({ kind: \"jsonPathPredicate\", value: value! });\n }\n\n raw(exp: string, bindings: readonly unknown[] | undefined): ExpressionCondition {\n if (bindings === undefined) return skipCondition;\n const cond: RawCondition = { kind: \"raw\", aliases: [], condition: \"unset\", pruneable: false, bindings };\n return withDeferredAlias(cond, (resolve, copy) => {\n const r = resolve(this.mgmt);\n const alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);\n copy.aliases = [alias];\n copy.condition = `${alias}.${this.column.columnName} ${exp}`;\n });\n }\n\n /** Maps literal values through the field serde and binds aliases only when parsing. */\n addCondition(value: ParsedValueFilter<unknown>): ColumnCondition {\n if (\"value\" in value && value.value === undefined) return skipCondition;\n const cond: ColumnCondition = {\n kind: \"column\",\n alias: \"unset\",\n column: this.column.columnName,\n dbType: this.column.dbType,\n cond: mapToDb(this.column, value),\n };\n return withDeferredAlias(cond, (resolve, copy) => {\n const r = resolve(this.mgmt);\n copy.alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);\n });\n }\n\n /** Handles literal values, NULL, and domain cross-alias comparisons. */\n private compare(\n kind: \"eq\" | \"ne\" | \"gt\" | \"gte\" | \"lt\" | \"lte\" | \"contains\" | \"ncontains\" | \"overlaps\",\n op: string,\n value: unknown,\n ): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, op);\n if (value === null && (kind === \"eq\" || kind === \"ne\"))\n return this.addCondition({ kind: kind === \"eq\" ? \"is-null\" : \"not-null\" });\n if (value === null && [\"gt\", \"gte\", \"lt\", \"lte\"].includes(kind)) return fail(\"Unsupported\");\n return this.addCondition({ kind, value } as ParsedValueFilter<unknown>);\n }\n}\n\n/** Resolves polymorphic predicates to their physical component columns. */\nclass PolyReferenceAlias {\n constructor(\n private meta: EntityMetadata,\n private mgmt: AliasMgmt,\n private field: PolymorphicField & { aliasSuffix: string },\n ) {}\n\n eq(value: unknown): ExpressionCondition {\n return this.addEqOrNe(\"eq\", value);\n }\n ne(value: unknown): ExpressionCondition {\n return this.addEqOrNe(\"ne\", value);\n }\n\n in(values: readonly (Entity | TaggedId)[] | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n // Split up the ids by constructor\n const groups = groupBy(values, (id) => getConstructorFromTaggedId(maybeResolveReferenceToId(id)!).name);\n // Or together `parent_book_id in (1,2,3) OR parent_author_id IN (4,5,6)`\n return {\n or: Object.entries(groups).map(([name, ids]) => {\n const comp =\n this.field.components.find((c) => c.otherMetadata().cstr.name === name) ?? fail(`No component for ${name}`);\n return this.component(comp).addCondition({ kind: \"in\", value: ids });\n }),\n };\n }\n\n /** Picks the component from an entity, tagged id, or another domain alias column. */\n private addEqOrNe(kind: \"eq\" | \"ne\", value: unknown): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value === null) {\n // We can AND each of the components as many conditions\n return {\n and: this.field.components.map((c) =>\n this.component(c).addCondition({ kind: kind === \"eq\" ? \"is-null\" : \"not-null\" }),\n ),\n };\n }\n const otherMeta =\n value instanceof AliasColumnImpl\n ? value.field.kind === \"m2o\"\n ? value.field.otherMetadata()\n : value.meta\n : getMetadata(getConstructorFromTaggedId(maybeResolveReferenceToId(value as Entity | TaggedId)!));\n const comp =\n this.field.components.find((c) => getBaseAndSelfMetas(otherMeta).includes(c.otherMetadata())) ??\n fail(`${this.field.fieldName} has no component for ${otherMeta.type}`);\n const column = this.component(comp);\n return kind === \"eq\" ? column.eq(value) : column.ne(value);\n }\n\n /** Uses the component serde, not the first component's codec. */\n private component(comp: PolymorphicFieldComponent): AliasColumnImpl {\n const column = this.field.serde.columns.find((c) => c.columnName === comp.columnName) ?? fail(\"Missing column\");\n return new AliasColumnImpl(this.meta, this.field, column, this.mgmt);\n }\n}\n\n/** Adjusts a field's SQL alias when a base alias is bound to a CTI subtype in the join tree. */\nexport function getMaybeCtiAlias(\n meta: EntityMetadata,\n field: Field & { aliasSuffix: string },\n newMeta: EntityMetadata,\n newAlias: string,\n): string {\n // Do we have mismatched `em.find(ChildMeta)` with a `alias(BaseMeta)`? If so, the\n // usual `${field.aliasSuffix}` won't know it should have a suffix, so we need to calc it.\n if (newMeta !== meta && newMeta.inheritanceType === \"cti\") {\n const bases = getBaseAndSelfMetas(newMeta);\n const fieldIsFromBase = bases.includes(newMeta);\n if (fieldIsFromBase) return `${newAlias}_b0`;\n }\n return `${newAlias}${field.aliasSuffix}`;\n}\n\n/** Compares domain columns with per-parse aliases, preserving condition reuse across find calls. */\nfunction crossColumnCondition(left: AliasColumnImpl, right: AliasColumnImpl, op: string, negate = false): RawCondition {\n const cond: RawCondition = { kind: \"raw\", aliases: [], condition: \"unset\", bindings: [], pruneable: false };\n return withDeferredAlias(cond, (resolve, copy) => {\n const l = resolve(left.mgmt);\n const r = resolve(right.mgmt);\n const a1 = getMaybeCtiAlias(left.meta, left.field, l.meta, l.alias);\n const a2 = getMaybeCtiAlias(right.meta, right.field, r.meta, r.alias);\n copy.aliases = [a1, a2];\n const sql = `${a1}.${left.column.columnName} ${op} ${a2}.${right.column.columnName}`;\n copy.condition = negate ? `NOT (${sql})` : sql;\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Aliases.cjs","names":["getMetadata","fail","skipCondition","makeLike","withDeferredAlias","mapToDb","groupBy","getConstructorFromTaggedId","maybeResolveReferenceToId","getBaseAndSelfMetas"],"sources":["../src/Aliases.ts"],"sourcesContent":["import { groupBy } from \"joist-utils\";\n\n// Load configure first: relations must not evaluate before their base classes exist.\nimport { getConstructorFromTaggedId } from \"./configure.ts\";\nimport { withDeferredAlias } from \"./DeferredAlias.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type ExpressionCondition } from \"./EntityFilter.ts\";\nimport { type IdOf, type MaybeAbstractEntityConstructor, type TaggedId } from \"./EntityManager.ts\";\nimport {\n type EntityMetadata,\n type Field,\n type PolymorphicField,\n type PolymorphicFieldComponent,\n getBaseAndSelfMetas,\n getMetadata,\n} from \"./EntityMetadata.ts\";\nimport { maybeResolveReferenceToId } from \"./keys.ts\";\nimport { type ColumnCondition, type ParsedValueFilter, type RawCondition, makeLike, mapToDb } from \"./QueryParser.ts\";\nimport { type Column } from \"./serde.ts\";\nimport { skipCondition } from \"./skipCondition.ts\";\nimport { type FieldsOf } from \"./typeMap.ts\";\nimport { fail } from \"./utils.ts\";\n\n/** Creates an alias for complex domain filtering in `em.find`. */\nexport function alias<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): Alias<T> {\n return newAliasProxy(cstr);\n}\n\n/** Creates multiple aliases for complex filtering. */\nexport function aliases<T extends readonly MaybeAbstractEntityConstructor<any>[]>(\n ...types: T\n): { [P in keyof T]: T[P] extends MaybeAbstractEntityConstructor<infer E extends Entity> ? Alias<E> : never } {\n return types.map((t) => newAliasProxy(t)) as any;\n}\n\nexport const aliasMgmt = Symbol(\"aliasMgmt\");\nconst aliasColumn = Symbol(\"aliasColumn\");\n\n/** The identity and original entity metadata of an `em.find` alias. */\nexport interface AliasMgmt {\n tableName: string;\n meta: EntityMetadata;\n}\n\n/** Keeps domain aliases covariant in their entity type. */\nexport interface AliasBrand<T> extends AliasMgmt {\n readonly __entity: T;\n}\n\n/**\n * Domain field predicates, deliberately separate from SQL table expressions.\n *\n * An Alias names a place in an em.find relationship tree, not a fixed SQL table occurrence.\n * I.e. with `a = alias(Author)`, `{ author: { as: a } }` binds `a` to the Book's Author;\n * binding it under `{ author: { mentor: { as: a } } }` instead makes it the Author's mentor.\n * The find parser builds those joins and knows which entity metadata and SQL name apply there,\n * including any inheritance joins. The Alias cannot know that when `a.firstName.eq(name)` is created.\n *\n * DeferredAlias therefore resolves each predicate to a fresh column/raw condition using that parse's\n * binding. The resolved condition records the SQL aliases it reads, including both sides of a\n * cross-alias comparison. Join pruning uses those references to retain the joins the filter needs.\n * An undefined predicate is skipped, so it does not keep an otherwise-unused join alive; explicit\n * keepAliases and other query dependencies can still retain that join.\n *\n * Table expressions solve a different problem: their sources are supplied directly in from/join,\n * so they render through ExprContext rather than asking the find parser to bind a relationship path.\n * Neither path stores a resolved SQL name on the reusable handle or predicate.\n */\nexport type Alias<T extends Entity> = { readonly [aliasMgmt]: AliasBrand<T> } & {\n [P in keyof FieldsOf<T>]: P extends \"id\"\n ? EntityAlias<T>\n : FieldsOf<T>[P] extends { kind: \"primitive\" | \"enum\"; type: infer V; nullable: infer N }\n ? PrimitiveAlias<V, N extends undefined ? null : never>\n : FieldsOf<T>[P] extends { kind: \"m2o\"; type: infer U extends Entity; nullable: infer N }\n ? EntityAlias<U, N extends undefined ? null : never>\n : FieldsOf<T>[P] extends { kind: \"poly\"; type: infer U extends Entity }\n ? PolyAlias<U>\n : never;\n};\n\n/** A domain column accepted on the other side of a cross-alias comparison. */\nexport interface AliasColumn<V> {\n readonly [aliasColumn]: V;\n}\n\nexport interface PrimitiveAlias<V, N extends null | never = never> extends AliasColumn<V | N> {\n eq(value: V | N | AliasColumn<V | null> | undefined): ExpressionCondition;\n ne(value: V | N | AliasColumn<V | null> | undefined): ExpressionCondition;\n in(values: readonly (V | null)[] | undefined): ExpressionCondition;\n nin(values: readonly (V | null)[] | undefined): ExpressionCondition;\n gt(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n gte(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n lt(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n lte(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n like(value: V | undefined): ExpressionCondition;\n ilike(value: V | undefined): ExpressionCondition;\n search(value: V | undefined): ExpressionCondition;\n between(v1: V | undefined, v2: V | undefined): ExpressionCondition;\n // V is already an array; strings also support jsonb contains.\n contains(value: string | V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n ncontains(value: string | V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n overlaps(value: V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n noverlaps(value: V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n /** Adds a parameterized JSON path existence condition using `@?`. */\n pathExists(jsonPath: string | undefined): ExpressionCondition;\n /** Adds a parameterized JSON path predicate condition using `@@`. */\n pathIsTrue(jsonPath: string | undefined): ExpressionCondition;\n /** Adds an operator and expression with knex-style placeholders, without the column name. */\n raw(exp: string, bindings: readonly unknown[] | undefined): ExpressionCondition;\n}\n\nexport interface EntityAlias<T, N extends null | never = never> extends AliasColumn<IdOf<T> | N> {\n eq(value: T | IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n ne(value: T | IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n // Adding `| null` for GraphQL support\n in(values: readonly (T | IdOf<T> | null)[] | null | undefined): ExpressionCondition;\n nin(values: readonly (T | IdOf<T> | null)[] | null | undefined): ExpressionCondition;\n gt(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n gte(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n lt(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n lte(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n raw(exp: string, bindings: readonly unknown[] | undefined): ExpressionCondition;\n}\n\nexport interface PolyAlias<T extends Entity> {\n eq(value: T | TaggedId | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n ne(value: T | TaggedId | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n in(values: readonly (T | TaggedId)[] | undefined): ExpressionCondition;\n}\n\n/** Returns the runtime identity bound by the find parser. */\nexport function getAliasMgmt(alias: { readonly [aliasMgmt]: AliasMgmt }): AliasMgmt {\n return alias[aliasMgmt];\n}\n\n/** Returns the original metadata, preserving STI subtype identity. */\nexport function getAliasMetadata<T extends Entity>(alias: Alias<T>): EntityMetadata<T> {\n return alias[aliasMgmt].meta as EntityMetadata<T>;\n}\n\n/** Creates domain predicates lazily from entity field metadata. */\nexport function newAliasProxy<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): Alias<T> {\n const meta = getMetadata(cstr);\n const mgmt: AliasMgmt = { tableName: meta.tableName, meta };\n return new Proxy(cstr, {\n get(_, key) {\n if (key === aliasMgmt) return mgmt;\n if (typeof key !== \"string\") return undefined;\n const field = meta.allFields[key] ?? fail(`No field ${key} on ${cstr.name}`);\n if (field.kind === \"poly\") return new PolyReferenceAlias(meta, mgmt, field);\n if ([\"primaryKey\", \"primitive\", \"enum\", \"m2o\"].includes(field.kind)) {\n return new AliasColumnImpl(meta, field, field.serde!.columns[0], mgmt);\n }\n return fail(`Unsupported alias field kind ${field.kind}`);\n },\n has(_, key) {\n return key === aliasMgmt || key in meta.allFields;\n },\n }) as unknown as Alias<T>;\n}\n\n/** Recognizes only domain aliases, not physical tables. */\nexport function isAlias(value: unknown): value is Alias<Entity> {\n return typeof value === \"function\" && aliasMgmt in value;\n}\n\n/** Builds field conditions without implementing the SQL expression protocol. */\nclass AliasColumnImpl {\n declare readonly [aliasColumn]: unknown;\n\n constructor(\n readonly meta: EntityMetadata,\n readonly field: Field & { aliasSuffix: string },\n readonly column: Column,\n readonly mgmt: AliasMgmt,\n ) {}\n\n eq(value: unknown): ExpressionCondition {\n return this.compare(\"eq\", \"=\", value);\n }\n ne(value: unknown): ExpressionCondition {\n return this.compare(\"ne\", \"!=\", value);\n }\n gt(value: unknown): ExpressionCondition {\n return this.compare(\"gt\", \">\", value);\n }\n gte(value: unknown): ExpressionCondition {\n return this.compare(\"gte\", \">=\", value);\n }\n lt(value: unknown): ExpressionCondition {\n return this.compare(\"lt\", \"<\", value);\n }\n lte(value: unknown): ExpressionCondition {\n return this.compare(\"lte\", \"<=\", value);\n }\n contains(value: unknown): ExpressionCondition {\n return this.compare(\"contains\", \"@>\", value);\n }\n ncontains(value: unknown): ExpressionCondition {\n if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, \"@>\", true);\n return this.addCondition({ kind: \"ncontains\", value: value as readonly unknown[] });\n }\n overlaps(value: unknown): ExpressionCondition {\n return this.compare(\"overlaps\", \"&&\", value);\n }\n noverlaps(value: unknown): ExpressionCondition {\n if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, \"&&\", true);\n return this.addCondition({ kind: \"noverlaps\", value: value as readonly unknown[] });\n }\n\n in(values: readonly unknown[] | null | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (values === null) return fail(\"Unsupported\");\n if (values.includes(null)) {\n return {\n or: [\n this.addCondition({ kind: \"is-null\" }),\n this.addCondition({ kind: \"in\", value: values.filter((v) => v !== null) }),\n ],\n };\n }\n return this.addCondition({ kind: \"in\", value: [...values] });\n }\n\n nin(values: readonly unknown[] | null | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (values === null) return fail(\"Unsupported\");\n return this.addCondition({ kind: \"nin\", value: values.filter((v) => v !== null) });\n }\n\n between(v1: unknown, v2: unknown): ExpressionCondition {\n if (v1 === undefined || v2 === undefined) return skipCondition;\n return this.addCondition({ kind: \"between\", value: [v1, v2] });\n }\n\n like(value: unknown): ExpressionCondition {\n return this.addCondition({ kind: \"like\", value });\n }\n ilike(value: unknown): ExpressionCondition {\n return this.addCondition({ kind: \"ilike\", value });\n }\n search(value: unknown): ExpressionCondition {\n // Check !value so that empty strings are pruned\n return !value ? skipCondition : this.addCondition({ kind: \"ilike\", value: makeLike(value) });\n }\n pathExists(value: string | undefined): ExpressionCondition {\n return this.addCondition({ kind: \"jsonPathExists\", value: value! });\n }\n pathIsTrue(value: string | undefined): ExpressionCondition {\n return this.addCondition({ kind: \"jsonPathPredicate\", value: value! });\n }\n\n raw(exp: string, bindings: readonly unknown[] | undefined): ExpressionCondition {\n if (bindings === undefined) return skipCondition;\n const cond: RawCondition = { kind: \"raw\", aliases: [], condition: \"unset\", pruneable: false, bindings };\n return withDeferredAlias(cond, (resolve, copy) => {\n const r = resolve(this.mgmt);\n const alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);\n copy.aliases = [alias];\n copy.condition = `${alias}.${this.column.columnName} ${exp}`;\n });\n }\n\n /** Maps literal values through the field serde and binds aliases only when parsing. */\n addCondition(value: ParsedValueFilter<unknown>): ColumnCondition {\n if (\"value\" in value && value.value === undefined) return skipCondition;\n const cond: ColumnCondition = {\n kind: \"column\",\n alias: \"unset\",\n column: this.column.columnName,\n dbType: this.column.dbType,\n cond: mapToDb(this.column, value),\n };\n return withDeferredAlias(cond, (resolve, copy) => {\n const r = resolve(this.mgmt);\n copy.alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);\n });\n }\n\n /** Handles literal values, NULL, and domain cross-alias comparisons. */\n private compare(\n kind: \"eq\" | \"ne\" | \"gt\" | \"gte\" | \"lt\" | \"lte\" | \"contains\" | \"ncontains\" | \"overlaps\",\n op: string,\n value: unknown,\n ): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, op);\n if (value === null && (kind === \"eq\" || kind === \"ne\"))\n return this.addCondition({ kind: kind === \"eq\" ? \"is-null\" : \"not-null\" });\n if (value === null && [\"gt\", \"gte\", \"lt\", \"lte\"].includes(kind)) return fail(\"Unsupported\");\n return this.addCondition({ kind, value } as ParsedValueFilter<unknown>);\n }\n}\n\n/** Resolves polymorphic predicates to their physical component columns. */\nclass PolyReferenceAlias {\n constructor(\n private meta: EntityMetadata,\n private mgmt: AliasMgmt,\n private field: PolymorphicField & { aliasSuffix: string },\n ) {}\n\n eq(value: unknown): ExpressionCondition {\n return this.addEqOrNe(\"eq\", value);\n }\n ne(value: unknown): ExpressionCondition {\n return this.addEqOrNe(\"ne\", value);\n }\n\n in(values: readonly (Entity | TaggedId)[] | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n // Split up the ids by constructor\n const groups = groupBy(values, (id) => getConstructorFromTaggedId(maybeResolveReferenceToId(id)!).name);\n // Or together `parent_book_id in (1,2,3) OR parent_author_id IN (4,5,6)`\n return {\n or: Object.entries(groups).map(([name, ids]) => {\n const comp =\n this.field.components.find((c) => c.otherMetadata().cstr.name === name) ?? fail(`No component for ${name}`);\n return this.component(comp).addCondition({ kind: \"in\", value: ids });\n }),\n };\n }\n\n /** Picks the component from an entity, tagged id, or another domain alias column. */\n private addEqOrNe(kind: \"eq\" | \"ne\", value: unknown): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value === null) {\n // We can AND each of the components as many conditions\n return {\n and: this.field.components.map((c) =>\n this.component(c).addCondition({ kind: kind === \"eq\" ? \"is-null\" : \"not-null\" }),\n ),\n };\n }\n const otherMeta =\n value instanceof AliasColumnImpl\n ? value.field.kind === \"m2o\"\n ? value.field.otherMetadata()\n : value.meta\n : getMetadata(getConstructorFromTaggedId(maybeResolveReferenceToId(value as Entity | TaggedId)!));\n const comp =\n this.field.components.find((c) => getBaseAndSelfMetas(otherMeta).includes(c.otherMetadata())) ??\n fail(`${this.field.fieldName} has no component for ${otherMeta.type}`);\n const column = this.component(comp);\n return kind === \"eq\" ? column.eq(value) : column.ne(value);\n }\n\n /** Uses the component serde, not the first component's codec. */\n private component(comp: PolymorphicFieldComponent): AliasColumnImpl {\n const column = this.field.serde.columns.find((c) => c.columnName === comp.columnName) ?? fail(\"Missing column\");\n return new AliasColumnImpl(this.meta, this.field, column, this.mgmt);\n }\n}\n\n/** Adjusts a field's SQL alias when a base alias is bound to a CTI subtype in the join tree. */\nexport function getMaybeCtiAlias(\n meta: EntityMetadata,\n field: Field & { aliasSuffix: string },\n newMeta: EntityMetadata,\n newAlias: string,\n): string {\n // Do we have mismatched `em.find(ChildMeta)` with a `alias(BaseMeta)`? If so, the\n // usual `${field.aliasSuffix}` won't know it should have a suffix, so we need to calc it.\n if (newMeta !== meta && newMeta.inheritanceType === \"cti\") {\n const bases = getBaseAndSelfMetas(newMeta);\n const fieldIsFromBase = bases.includes(newMeta);\n if (fieldIsFromBase) return `${newAlias}_b0`;\n }\n return `${newAlias}${field.aliasSuffix}`;\n}\n\n/** Compares domain columns with per-parse aliases, preserving condition reuse across find calls. */\nfunction crossColumnCondition(left: AliasColumnImpl, right: AliasColumnImpl, op: string, negate = false): RawCondition {\n const cond: RawCondition = { kind: \"raw\", aliases: [], condition: \"unset\", bindings: [], pruneable: false };\n return withDeferredAlias(cond, (resolve, copy) => {\n const l = resolve(left.mgmt);\n const r = resolve(right.mgmt);\n const a1 = getMaybeCtiAlias(left.meta, left.field, l.meta, l.alias);\n const a2 = getMaybeCtiAlias(right.meta, right.field, r.meta, r.alias);\n copy.aliases = [a1, a2];\n const sql = `${a1}.${left.column.columnName} ${op} ${a2}.${right.column.columnName}`;\n copy.condition = negate ? `NOT (${sql})` : sql;\n });\n}\n"],"mappings":"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"}
@@ -19,7 +19,25 @@ interface AliasMgmt {
19
19
  interface AliasBrand<T> extends AliasMgmt {
20
20
  readonly __entity: T;
21
21
  }
22
- /** Domain field predicates, deliberately separate from SQL table expressions. */
22
+ /**
23
+ * Domain field predicates, deliberately separate from SQL table expressions.
24
+ *
25
+ * An Alias names a place in an em.find relationship tree, not a fixed SQL table occurrence.
26
+ * I.e. with `a = alias(Author)`, `{ author: { as: a } }` binds `a` to the Book's Author;
27
+ * binding it under `{ author: { mentor: { as: a } } }` instead makes it the Author's mentor.
28
+ * The find parser builds those joins and knows which entity metadata and SQL name apply there,
29
+ * including any inheritance joins. The Alias cannot know that when `a.firstName.eq(name)` is created.
30
+ *
31
+ * DeferredAlias therefore resolves each predicate to a fresh column/raw condition using that parse's
32
+ * binding. The resolved condition records the SQL aliases it reads, including both sides of a
33
+ * cross-alias comparison. Join pruning uses those references to retain the joins the filter needs.
34
+ * An undefined predicate is skipped, so it does not keep an otherwise-unused join alive; explicit
35
+ * keepAliases and other query dependencies can still retain that join.
36
+ *
37
+ * Table expressions solve a different problem: their sources are supplied directly in from/join,
38
+ * so they render through ExprContext rather than asking the find parser to bind a relationship path.
39
+ * Neither path stores a resolved SQL name on the reusable handle or predicate.
40
+ */
23
41
  type Alias<T extends Entity> = {
24
42
  readonly [aliasMgmt]: AliasBrand<T>;
25
43
  } & { [P in keyof FieldsOf<T>]: P extends "id" ? EntityAlias<T> : FieldsOf<T>[P] extends {
@@ -1 +1 @@
1
- {"version":3,"file":"Aliases.d.cts","names":[],"sources":["../src/Aliases.ts"],"mappings":";;;;;;;iBAuBgB,MAAM,UAAU,QAAQ,MAAM,+BAA+B,KAAK,MAAM;;iBAKxE,QAAQ,mBAAmB,0CACtC,OAAO,OACN,WAAW,IAAI,EAAE,WAAW,qCAAqC,UAAU,UAAU,MAAM;cAIpF;cACP;;UAGW;EACf;EACA,MAAM;;;UAIS,WAAW,WAAW;WAC5B,UAAU;;;KAIT,MAAM,UAAU;YAAsB,YAAY,WAAW;OACtE,WAAW,SAAS,KAAK,iBACtB,YAAY,KACZ,SAAS,GAAG;EAAa;EAA4B,YAAY;EAAG,gBAAgB;IAClF,eAAe,GAAG,sCAClB,SAAS,GAAG;EAAa;EAAa,YAAY,UAAU;EAAQ,gBAAgB;IAClF,YAAY,GAAG,sCACf,SAAS,GAAG;EAAa;EAAc,YAAY,UAAU;IAC3D,UAAU;;UAKL,YAAY;YACjB,cAAc;;UAGT,eAAe,GAAG,wCAAwC,YAAY,IAAI;EACzF,GAAG,OAAO,IAAI,IAAI,YAAY,wBAAwB;EACtD,GAAG,OAAO,IAAI,IAAI,YAAY,wBAAwB;EACtD,GAAG,kBAAkB,0BAA0B;EAC/C,IAAI,kBAAkB,0BAA0B;EAChD,GAAG,OAAO,IAAI,YAAY,wBAAwB;EAClD,IAAI,OAAO,IAAI,YAAY,wBAAwB;EACnD,GAAG,OAAO,IAAI,YAAY,wBAAwB;EAClD,IAAI,OAAO,IAAI,YAAY,wBAAwB;EACnD,KAAK,OAAO,gBAAgB;EAC5B,MAAM,OAAO,gBAAgB;EAC7B,OAAO,OAAO,gBAAgB;EAC9B,QAAQ,IAAI,eAAe,IAAI,gBAAgB;EAE/C,SAAS,gBAAgB,IAAI,YAAY,YAAY,gBAAgB;EACrE,UAAU,gBAAgB,IAAI,YAAY,YAAY,gBAAgB;EACtE,SAAS,OAAO,IAAI,YAAY,YAAY,gBAAgB;EAC5D,UAAU,OAAO,IAAI,YAAY,YAAY,gBAAgB;;EAE7D,WAAW,+BAA+B;;EAE1C,WAAW,+BAA+B;;EAE1C,IAAI,aAAa,2CAA2C;;UAG7C,YAAY,GAAG,wCAAwC,YAAY,KAAK,KAAK;EAC5F,GAAG,OAAO,IAAI,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACzE,GAAG,OAAO,IAAI,KAAK,KAAK,YAAY,KAAK,gCAAgC;EAEzE,GAAG,kBAAkB,IAAI,KAAK,kCAAkC;EAChE,IAAI,kBAAkB,IAAI,KAAK,kCAAkC;EACjE,GAAG,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACrE,IAAI,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACtE,GAAG,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACrE,IAAI,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACtE,IAAI,aAAa,2CAA2C;;UAG7C,UAAU,UAAU;EACnC,GAAG,OAAO,IAAI,WAAW,YAAY,KAAK,gCAAgC;EAC1E,GAAG,OAAO,IAAI,WAAW,YAAY,KAAK,gCAAgC;EAC1E,GAAG,kBAAkB,IAAI,0BAA0B;;;iBAIrC,aAAa;YAAmB,YAAY;IAAc;;iBAK1D,iBAAiB,UAAU,QAAQ,OAAO,MAAM,KAAK,eAAe;;iBAKpE,cAAc,UAAU,QAAQ,MAAM,+BAA+B,KAAK,MAAM;;iBAqBhF,QAAQ,iBAAiB,SAAS,MAAM;;iBAiMxC,iBACd,MAAM,gBACN,OAAO;EAAU;GACjB,SAAS,gBACT"}
1
+ {"version":3,"file":"Aliases.d.cts","names":[],"sources":["../src/Aliases.ts"],"mappings":";;;;;;;iBAwBgB,MAAM,UAAU,QAAQ,MAAM,+BAA+B,KAAK,MAAM;;iBAKxE,QAAQ,mBAAmB,0CACtC,OAAO,OACN,WAAW,IAAI,EAAE,WAAW,qCAAqC,UAAU,UAAU,MAAM;cAIpF;cACP;;UAGW;EACf;EACA,MAAM;;;UAIS,WAAW,WAAW;WAC5B,UAAU;;;;;;;;;;;;;;;;;;;;;KAsBT,MAAM,UAAU;YAAsB,YAAY,WAAW;OACtE,WAAW,SAAS,KAAK,iBACtB,YAAY,KACZ,SAAS,GAAG;EAAa;EAA4B,YAAY;EAAG,gBAAgB;IAClF,eAAe,GAAG,sCAClB,SAAS,GAAG;EAAa;EAAa,YAAY,UAAU;EAAQ,gBAAgB;IAClF,YAAY,GAAG,sCACf,SAAS,GAAG;EAAa;EAAc,YAAY,UAAU;IAC3D,UAAU;;UAKL,YAAY;YACjB,cAAc;;UAGT,eAAe,GAAG,wCAAwC,YAAY,IAAI;EACzF,GAAG,OAAO,IAAI,IAAI,YAAY,wBAAwB;EACtD,GAAG,OAAO,IAAI,IAAI,YAAY,wBAAwB;EACtD,GAAG,kBAAkB,0BAA0B;EAC/C,IAAI,kBAAkB,0BAA0B;EAChD,GAAG,OAAO,IAAI,YAAY,wBAAwB;EAClD,IAAI,OAAO,IAAI,YAAY,wBAAwB;EACnD,GAAG,OAAO,IAAI,YAAY,wBAAwB;EAClD,IAAI,OAAO,IAAI,YAAY,wBAAwB;EACnD,KAAK,OAAO,gBAAgB;EAC5B,MAAM,OAAO,gBAAgB;EAC7B,OAAO,OAAO,gBAAgB;EAC9B,QAAQ,IAAI,eAAe,IAAI,gBAAgB;EAE/C,SAAS,gBAAgB,IAAI,YAAY,YAAY,gBAAgB;EACrE,UAAU,gBAAgB,IAAI,YAAY,YAAY,gBAAgB;EACtE,SAAS,OAAO,IAAI,YAAY,YAAY,gBAAgB;EAC5D,UAAU,OAAO,IAAI,YAAY,YAAY,gBAAgB;;EAE7D,WAAW,+BAA+B;;EAE1C,WAAW,+BAA+B;;EAE1C,IAAI,aAAa,2CAA2C;;UAG7C,YAAY,GAAG,wCAAwC,YAAY,KAAK,KAAK;EAC5F,GAAG,OAAO,IAAI,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACzE,GAAG,OAAO,IAAI,KAAK,KAAK,YAAY,KAAK,gCAAgC;EAEzE,GAAG,kBAAkB,IAAI,KAAK,kCAAkC;EAChE,IAAI,kBAAkB,IAAI,KAAK,kCAAkC;EACjE,GAAG,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACrE,IAAI,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACtE,GAAG,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACrE,IAAI,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACtE,IAAI,aAAa,2CAA2C;;UAG7C,UAAU,UAAU;EACnC,GAAG,OAAO,IAAI,WAAW,YAAY,KAAK,gCAAgC;EAC1E,GAAG,OAAO,IAAI,WAAW,YAAY,KAAK,gCAAgC;EAC1E,GAAG,kBAAkB,IAAI,0BAA0B;;;iBAIrC,aAAa;YAAmB,YAAY;IAAc;;iBAK1D,iBAAiB,UAAU,QAAQ,OAAO,MAAM,KAAK,eAAe;;iBAKpE,cAAc,UAAU,QAAQ,MAAM,+BAA+B,KAAK,MAAM;;iBAqBhF,QAAQ,iBAAiB,SAAS,MAAM;;iBAiMxC,iBACd,MAAM,gBACN,OAAO;EAAU;GACjB,SAAS,gBACT"}
@@ -19,7 +19,25 @@ interface AliasMgmt {
19
19
  interface AliasBrand<T> extends AliasMgmt {
20
20
  readonly __entity: T;
21
21
  }
22
- /** Domain field predicates, deliberately separate from SQL table expressions. */
22
+ /**
23
+ * Domain field predicates, deliberately separate from SQL table expressions.
24
+ *
25
+ * An Alias names a place in an em.find relationship tree, not a fixed SQL table occurrence.
26
+ * I.e. with `a = alias(Author)`, `{ author: { as: a } }` binds `a` to the Book's Author;
27
+ * binding it under `{ author: { mentor: { as: a } } }` instead makes it the Author's mentor.
28
+ * The find parser builds those joins and knows which entity metadata and SQL name apply there,
29
+ * including any inheritance joins. The Alias cannot know that when `a.firstName.eq(name)` is created.
30
+ *
31
+ * DeferredAlias therefore resolves each predicate to a fresh column/raw condition using that parse's
32
+ * binding. The resolved condition records the SQL aliases it reads, including both sides of a
33
+ * cross-alias comparison. Join pruning uses those references to retain the joins the filter needs.
34
+ * An undefined predicate is skipped, so it does not keep an otherwise-unused join alive; explicit
35
+ * keepAliases and other query dependencies can still retain that join.
36
+ *
37
+ * Table expressions solve a different problem: their sources are supplied directly in from/join,
38
+ * so they render through ExprContext rather than asking the find parser to bind a relationship path.
39
+ * Neither path stores a resolved SQL name on the reusable handle or predicate.
40
+ */
23
41
  type Alias<T extends Entity> = {
24
42
  readonly [aliasMgmt]: AliasBrand<T>;
25
43
  } & { [P in keyof FieldsOf<T>]: P extends "id" ? EntityAlias<T> : FieldsOf<T>[P] extends {
@@ -1 +1 @@
1
- {"version":3,"file":"Aliases.d.mts","names":[],"sources":["../src/Aliases.ts"],"mappings":";;;;;;;iBAuBgB,MAAM,UAAU,QAAQ,MAAM,+BAA+B,KAAK,MAAM;;iBAKxE,QAAQ,mBAAmB,0CACtC,OAAO,OACN,WAAW,IAAI,EAAE,WAAW,qCAAqC,UAAU,UAAU,MAAM;cAIpF;cACP;;UAGW;EACf;EACA,MAAM;;;UAIS,WAAW,WAAW;WAC5B,UAAU;;;KAIT,MAAM,UAAU;YAAsB,YAAY,WAAW;OACtE,WAAW,SAAS,KAAK,iBACtB,YAAY,KACZ,SAAS,GAAG;EAAa;EAA4B,YAAY;EAAG,gBAAgB;IAClF,eAAe,GAAG,sCAClB,SAAS,GAAG;EAAa;EAAa,YAAY,UAAU;EAAQ,gBAAgB;IAClF,YAAY,GAAG,sCACf,SAAS,GAAG;EAAa;EAAc,YAAY,UAAU;IAC3D,UAAU;;UAKL,YAAY;YACjB,cAAc;;UAGT,eAAe,GAAG,wCAAwC,YAAY,IAAI;EACzF,GAAG,OAAO,IAAI,IAAI,YAAY,wBAAwB;EACtD,GAAG,OAAO,IAAI,IAAI,YAAY,wBAAwB;EACtD,GAAG,kBAAkB,0BAA0B;EAC/C,IAAI,kBAAkB,0BAA0B;EAChD,GAAG,OAAO,IAAI,YAAY,wBAAwB;EAClD,IAAI,OAAO,IAAI,YAAY,wBAAwB;EACnD,GAAG,OAAO,IAAI,YAAY,wBAAwB;EAClD,IAAI,OAAO,IAAI,YAAY,wBAAwB;EACnD,KAAK,OAAO,gBAAgB;EAC5B,MAAM,OAAO,gBAAgB;EAC7B,OAAO,OAAO,gBAAgB;EAC9B,QAAQ,IAAI,eAAe,IAAI,gBAAgB;EAE/C,SAAS,gBAAgB,IAAI,YAAY,YAAY,gBAAgB;EACrE,UAAU,gBAAgB,IAAI,YAAY,YAAY,gBAAgB;EACtE,SAAS,OAAO,IAAI,YAAY,YAAY,gBAAgB;EAC5D,UAAU,OAAO,IAAI,YAAY,YAAY,gBAAgB;;EAE7D,WAAW,+BAA+B;;EAE1C,WAAW,+BAA+B;;EAE1C,IAAI,aAAa,2CAA2C;;UAG7C,YAAY,GAAG,wCAAwC,YAAY,KAAK,KAAK;EAC5F,GAAG,OAAO,IAAI,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACzE,GAAG,OAAO,IAAI,KAAK,KAAK,YAAY,KAAK,gCAAgC;EAEzE,GAAG,kBAAkB,IAAI,KAAK,kCAAkC;EAChE,IAAI,kBAAkB,IAAI,KAAK,kCAAkC;EACjE,GAAG,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACrE,IAAI,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACtE,GAAG,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACrE,IAAI,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACtE,IAAI,aAAa,2CAA2C;;UAG7C,UAAU,UAAU;EACnC,GAAG,OAAO,IAAI,WAAW,YAAY,KAAK,gCAAgC;EAC1E,GAAG,OAAO,IAAI,WAAW,YAAY,KAAK,gCAAgC;EAC1E,GAAG,kBAAkB,IAAI,0BAA0B;;;iBAIrC,aAAa;YAAmB,YAAY;IAAc;;iBAK1D,iBAAiB,UAAU,QAAQ,OAAO,MAAM,KAAK,eAAe;;iBAKpE,cAAc,UAAU,QAAQ,MAAM,+BAA+B,KAAK,MAAM;;iBAqBhF,QAAQ,iBAAiB,SAAS,MAAM;;iBAiMxC,iBACd,MAAM,gBACN,OAAO;EAAU;GACjB,SAAS,gBACT"}
1
+ {"version":3,"file":"Aliases.d.mts","names":[],"sources":["../src/Aliases.ts"],"mappings":";;;;;;;iBAwBgB,MAAM,UAAU,QAAQ,MAAM,+BAA+B,KAAK,MAAM;;iBAKxE,QAAQ,mBAAmB,0CACtC,OAAO,OACN,WAAW,IAAI,EAAE,WAAW,qCAAqC,UAAU,UAAU,MAAM;cAIpF;cACP;;UAGW;EACf;EACA,MAAM;;;UAIS,WAAW,WAAW;WAC5B,UAAU;;;;;;;;;;;;;;;;;;;;;KAsBT,MAAM,UAAU;YAAsB,YAAY,WAAW;OACtE,WAAW,SAAS,KAAK,iBACtB,YAAY,KACZ,SAAS,GAAG;EAAa;EAA4B,YAAY;EAAG,gBAAgB;IAClF,eAAe,GAAG,sCAClB,SAAS,GAAG;EAAa;EAAa,YAAY,UAAU;EAAQ,gBAAgB;IAClF,YAAY,GAAG,sCACf,SAAS,GAAG;EAAa;EAAc,YAAY,UAAU;IAC3D,UAAU;;UAKL,YAAY;YACjB,cAAc;;UAGT,eAAe,GAAG,wCAAwC,YAAY,IAAI;EACzF,GAAG,OAAO,IAAI,IAAI,YAAY,wBAAwB;EACtD,GAAG,OAAO,IAAI,IAAI,YAAY,wBAAwB;EACtD,GAAG,kBAAkB,0BAA0B;EAC/C,IAAI,kBAAkB,0BAA0B;EAChD,GAAG,OAAO,IAAI,YAAY,wBAAwB;EAClD,IAAI,OAAO,IAAI,YAAY,wBAAwB;EACnD,GAAG,OAAO,IAAI,YAAY,wBAAwB;EAClD,IAAI,OAAO,IAAI,YAAY,wBAAwB;EACnD,KAAK,OAAO,gBAAgB;EAC5B,MAAM,OAAO,gBAAgB;EAC7B,OAAO,OAAO,gBAAgB;EAC9B,QAAQ,IAAI,eAAe,IAAI,gBAAgB;EAE/C,SAAS,gBAAgB,IAAI,YAAY,YAAY,gBAAgB;EACrE,UAAU,gBAAgB,IAAI,YAAY,YAAY,gBAAgB;EACtE,SAAS,OAAO,IAAI,YAAY,YAAY,gBAAgB;EAC5D,UAAU,OAAO,IAAI,YAAY,YAAY,gBAAgB;;EAE7D,WAAW,+BAA+B;;EAE1C,WAAW,+BAA+B;;EAE1C,IAAI,aAAa,2CAA2C;;UAG7C,YAAY,GAAG,wCAAwC,YAAY,KAAK,KAAK;EAC5F,GAAG,OAAO,IAAI,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACzE,GAAG,OAAO,IAAI,KAAK,KAAK,YAAY,KAAK,gCAAgC;EAEzE,GAAG,kBAAkB,IAAI,KAAK,kCAAkC;EAChE,IAAI,kBAAkB,IAAI,KAAK,kCAAkC;EACjE,GAAG,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACrE,IAAI,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACtE,GAAG,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACrE,IAAI,OAAO,KAAK,KAAK,YAAY,KAAK,gCAAgC;EACtE,IAAI,aAAa,2CAA2C;;UAG7C,UAAU,UAAU;EACnC,GAAG,OAAO,IAAI,WAAW,YAAY,KAAK,gCAAgC;EAC1E,GAAG,OAAO,IAAI,WAAW,YAAY,KAAK,gCAAgC;EAC1E,GAAG,kBAAkB,IAAI,0BAA0B;;;iBAIrC,aAAa;YAAmB,YAAY;IAAc;;iBAK1D,iBAAiB,UAAU,QAAQ,OAAO,MAAM,KAAK,eAAe;;iBAKpE,cAAc,UAAU,QAAQ,MAAM,+BAA+B,KAAK,MAAM;;iBAqBhF,QAAQ,iBAAiB,SAAS,MAAM;;iBAiMxC,iBACd,MAAM,gBACN,OAAO;EAAU;GACjB,SAAS,gBACT"}
package/build/Aliases.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import "./typeMap.js";
2
2
  import "./EntityFilter.js";
3
3
  import { maybeResolveReferenceToId } from "./keys.js";
4
- import { skipCondition, withDeferredAlias } from "./DeferredAlias.js";
4
+ import { skipCondition } from "./skipCondition.js";
5
5
  import "./serde.js";
6
6
  import { getBaseAndSelfMetas, getMetadata } from "./EntityMetadata.js";
7
7
  import { fail } from "./utils.js";
8
+ import { withDeferredAlias } from "./DeferredAlias.js";
8
9
  import "./EntityManager.js";
9
10
  import "./Entity.js";
10
11
  import { getConstructorFromTaggedId } from "./configure.js";
@@ -1 +1 @@
1
- {"version":3,"file":"Aliases.js","names":[],"sources":["../src/Aliases.ts"],"sourcesContent":["import { groupBy } from \"joist-utils\";\n\n// Load configure first: relations must not evaluate before their base classes exist.\nimport { getConstructorFromTaggedId } from \"./configure.ts\";\nimport { skipCondition, withDeferredAlias } from \"./DeferredAlias.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type ExpressionCondition } from \"./EntityFilter.ts\";\nimport { type IdOf, type MaybeAbstractEntityConstructor, type TaggedId } from \"./EntityManager.ts\";\nimport {\n type EntityMetadata,\n type Field,\n type PolymorphicField,\n type PolymorphicFieldComponent,\n getBaseAndSelfMetas,\n getMetadata,\n} from \"./EntityMetadata.ts\";\nimport { maybeResolveReferenceToId } from \"./keys.ts\";\nimport { type ColumnCondition, type ParsedValueFilter, type RawCondition, makeLike, mapToDb } from \"./QueryParser.ts\";\nimport { type Column } from \"./serde.ts\";\nimport { type FieldsOf } from \"./typeMap.ts\";\nimport { fail } from \"./utils.ts\";\n\n/** Creates an alias for complex domain filtering in `em.find`. */\nexport function alias<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): Alias<T> {\n return newAliasProxy(cstr);\n}\n\n/** Creates multiple aliases for complex filtering. */\nexport function aliases<T extends readonly MaybeAbstractEntityConstructor<any>[]>(\n ...types: T\n): { [P in keyof T]: T[P] extends MaybeAbstractEntityConstructor<infer E extends Entity> ? Alias<E> : never } {\n return types.map((t) => newAliasProxy(t)) as any;\n}\n\nexport const aliasMgmt = Symbol(\"aliasMgmt\");\nconst aliasColumn = Symbol(\"aliasColumn\");\n\n/** The identity and original entity metadata of an `em.find` alias. */\nexport interface AliasMgmt {\n tableName: string;\n meta: EntityMetadata;\n}\n\n/** Keeps domain aliases covariant in their entity type. */\nexport interface AliasBrand<T> extends AliasMgmt {\n readonly __entity: T;\n}\n\n/** Domain field predicates, deliberately separate from SQL table expressions. */\nexport type Alias<T extends Entity> = { readonly [aliasMgmt]: AliasBrand<T> } & {\n [P in keyof FieldsOf<T>]: P extends \"id\"\n ? EntityAlias<T>\n : FieldsOf<T>[P] extends { kind: \"primitive\" | \"enum\"; type: infer V; nullable: infer N }\n ? PrimitiveAlias<V, N extends undefined ? null : never>\n : FieldsOf<T>[P] extends { kind: \"m2o\"; type: infer U extends Entity; nullable: infer N }\n ? EntityAlias<U, N extends undefined ? null : never>\n : FieldsOf<T>[P] extends { kind: \"poly\"; type: infer U extends Entity }\n ? PolyAlias<U>\n : never;\n};\n\n/** A domain column accepted on the other side of a cross-alias comparison. */\nexport interface AliasColumn<V> {\n readonly [aliasColumn]: V;\n}\n\nexport interface PrimitiveAlias<V, N extends null | never = never> extends AliasColumn<V | N> {\n eq(value: V | N | AliasColumn<V | null> | undefined): ExpressionCondition;\n ne(value: V | N | AliasColumn<V | null> | undefined): ExpressionCondition;\n in(values: readonly (V | null)[] | undefined): ExpressionCondition;\n nin(values: readonly (V | null)[] | undefined): ExpressionCondition;\n gt(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n gte(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n lt(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n lte(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n like(value: V | undefined): ExpressionCondition;\n ilike(value: V | undefined): ExpressionCondition;\n search(value: V | undefined): ExpressionCondition;\n between(v1: V | undefined, v2: V | undefined): ExpressionCondition;\n // V is already an array; strings also support jsonb contains.\n contains(value: string | V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n ncontains(value: string | V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n overlaps(value: V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n noverlaps(value: V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n /** Adds a parameterized JSON path existence condition using `@?`. */\n pathExists(jsonPath: string | undefined): ExpressionCondition;\n /** Adds a parameterized JSON path predicate condition using `@@`. */\n pathIsTrue(jsonPath: string | undefined): ExpressionCondition;\n /** Adds an operator and expression with knex-style placeholders, without the column name. */\n raw(exp: string, bindings: readonly unknown[] | undefined): ExpressionCondition;\n}\n\nexport interface EntityAlias<T, N extends null | never = never> extends AliasColumn<IdOf<T> | N> {\n eq(value: T | IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n ne(value: T | IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n // Adding `| null` for GraphQL support\n in(values: readonly (T | IdOf<T> | null)[] | null | undefined): ExpressionCondition;\n nin(values: readonly (T | IdOf<T> | null)[] | null | undefined): ExpressionCondition;\n gt(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n gte(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n lt(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n lte(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n raw(exp: string, bindings: readonly unknown[] | undefined): ExpressionCondition;\n}\n\nexport interface PolyAlias<T extends Entity> {\n eq(value: T | TaggedId | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n ne(value: T | TaggedId | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n in(values: readonly (T | TaggedId)[] | undefined): ExpressionCondition;\n}\n\n/** Returns the runtime identity bound by the find parser. */\nexport function getAliasMgmt(alias: { readonly [aliasMgmt]: AliasMgmt }): AliasMgmt {\n return alias[aliasMgmt];\n}\n\n/** Returns the original metadata, preserving STI subtype identity. */\nexport function getAliasMetadata<T extends Entity>(alias: Alias<T>): EntityMetadata<T> {\n return alias[aliasMgmt].meta as EntityMetadata<T>;\n}\n\n/** Creates domain predicates lazily from entity field metadata. */\nexport function newAliasProxy<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): Alias<T> {\n const meta = getMetadata(cstr);\n const mgmt: AliasMgmt = { tableName: meta.tableName, meta };\n return new Proxy(cstr, {\n get(_, key) {\n if (key === aliasMgmt) return mgmt;\n if (typeof key !== \"string\") return undefined;\n const field = meta.allFields[key] ?? fail(`No field ${key} on ${cstr.name}`);\n if (field.kind === \"poly\") return new PolyReferenceAlias(meta, mgmt, field);\n if ([\"primaryKey\", \"primitive\", \"enum\", \"m2o\"].includes(field.kind)) {\n return new AliasColumnImpl(meta, field, field.serde!.columns[0], mgmt);\n }\n return fail(`Unsupported alias field kind ${field.kind}`);\n },\n has(_, key) {\n return key === aliasMgmt || key in meta.allFields;\n },\n }) as unknown as Alias<T>;\n}\n\n/** Recognizes only domain aliases, not physical tables. */\nexport function isAlias(value: unknown): value is Alias<Entity> {\n return typeof value === \"function\" && aliasMgmt in value;\n}\n\n/** Builds field conditions without implementing the SQL expression protocol. */\nclass AliasColumnImpl {\n declare readonly [aliasColumn]: unknown;\n\n constructor(\n readonly meta: EntityMetadata,\n readonly field: Field & { aliasSuffix: string },\n readonly column: Column,\n readonly mgmt: AliasMgmt,\n ) {}\n\n eq(value: unknown): ExpressionCondition {\n return this.compare(\"eq\", \"=\", value);\n }\n ne(value: unknown): ExpressionCondition {\n return this.compare(\"ne\", \"!=\", value);\n }\n gt(value: unknown): ExpressionCondition {\n return this.compare(\"gt\", \">\", value);\n }\n gte(value: unknown): ExpressionCondition {\n return this.compare(\"gte\", \">=\", value);\n }\n lt(value: unknown): ExpressionCondition {\n return this.compare(\"lt\", \"<\", value);\n }\n lte(value: unknown): ExpressionCondition {\n return this.compare(\"lte\", \"<=\", value);\n }\n contains(value: unknown): ExpressionCondition {\n return this.compare(\"contains\", \"@>\", value);\n }\n ncontains(value: unknown): ExpressionCondition {\n if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, \"@>\", true);\n return this.addCondition({ kind: \"ncontains\", value: value as readonly unknown[] });\n }\n overlaps(value: unknown): ExpressionCondition {\n return this.compare(\"overlaps\", \"&&\", value);\n }\n noverlaps(value: unknown): ExpressionCondition {\n if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, \"&&\", true);\n return this.addCondition({ kind: \"noverlaps\", value: value as readonly unknown[] });\n }\n\n in(values: readonly unknown[] | null | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (values === null) return fail(\"Unsupported\");\n if (values.includes(null)) {\n return {\n or: [\n this.addCondition({ kind: \"is-null\" }),\n this.addCondition({ kind: \"in\", value: values.filter((v) => v !== null) }),\n ],\n };\n }\n return this.addCondition({ kind: \"in\", value: [...values] });\n }\n\n nin(values: readonly unknown[] | null | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (values === null) return fail(\"Unsupported\");\n return this.addCondition({ kind: \"nin\", value: values.filter((v) => v !== null) });\n }\n\n between(v1: unknown, v2: unknown): ExpressionCondition {\n if (v1 === undefined || v2 === undefined) return skipCondition;\n return this.addCondition({ kind: \"between\", value: [v1, v2] });\n }\n\n like(value: unknown): ExpressionCondition {\n return this.addCondition({ kind: \"like\", value });\n }\n ilike(value: unknown): ExpressionCondition {\n return this.addCondition({ kind: \"ilike\", value });\n }\n search(value: unknown): ExpressionCondition {\n // Check !value so that empty strings are pruned\n return !value ? skipCondition : this.addCondition({ kind: \"ilike\", value: makeLike(value) });\n }\n pathExists(value: string | undefined): ExpressionCondition {\n return this.addCondition({ kind: \"jsonPathExists\", value: value! });\n }\n pathIsTrue(value: string | undefined): ExpressionCondition {\n return this.addCondition({ kind: \"jsonPathPredicate\", value: value! });\n }\n\n raw(exp: string, bindings: readonly unknown[] | undefined): ExpressionCondition {\n if (bindings === undefined) return skipCondition;\n const cond: RawCondition = { kind: \"raw\", aliases: [], condition: \"unset\", pruneable: false, bindings };\n return withDeferredAlias(cond, (resolve, copy) => {\n const r = resolve(this.mgmt);\n const alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);\n copy.aliases = [alias];\n copy.condition = `${alias}.${this.column.columnName} ${exp}`;\n });\n }\n\n /** Maps literal values through the field serde and binds aliases only when parsing. */\n addCondition(value: ParsedValueFilter<unknown>): ColumnCondition {\n if (\"value\" in value && value.value === undefined) return skipCondition;\n const cond: ColumnCondition = {\n kind: \"column\",\n alias: \"unset\",\n column: this.column.columnName,\n dbType: this.column.dbType,\n cond: mapToDb(this.column, value),\n };\n return withDeferredAlias(cond, (resolve, copy) => {\n const r = resolve(this.mgmt);\n copy.alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);\n });\n }\n\n /** Handles literal values, NULL, and domain cross-alias comparisons. */\n private compare(\n kind: \"eq\" | \"ne\" | \"gt\" | \"gte\" | \"lt\" | \"lte\" | \"contains\" | \"ncontains\" | \"overlaps\",\n op: string,\n value: unknown,\n ): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, op);\n if (value === null && (kind === \"eq\" || kind === \"ne\"))\n return this.addCondition({ kind: kind === \"eq\" ? \"is-null\" : \"not-null\" });\n if (value === null && [\"gt\", \"gte\", \"lt\", \"lte\"].includes(kind)) return fail(\"Unsupported\");\n return this.addCondition({ kind, value } as ParsedValueFilter<unknown>);\n }\n}\n\n/** Resolves polymorphic predicates to their physical component columns. */\nclass PolyReferenceAlias {\n constructor(\n private meta: EntityMetadata,\n private mgmt: AliasMgmt,\n private field: PolymorphicField & { aliasSuffix: string },\n ) {}\n\n eq(value: unknown): ExpressionCondition {\n return this.addEqOrNe(\"eq\", value);\n }\n ne(value: unknown): ExpressionCondition {\n return this.addEqOrNe(\"ne\", value);\n }\n\n in(values: readonly (Entity | TaggedId)[] | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n // Split up the ids by constructor\n const groups = groupBy(values, (id) => getConstructorFromTaggedId(maybeResolveReferenceToId(id)!).name);\n // Or together `parent_book_id in (1,2,3) OR parent_author_id IN (4,5,6)`\n return {\n or: Object.entries(groups).map(([name, ids]) => {\n const comp =\n this.field.components.find((c) => c.otherMetadata().cstr.name === name) ?? fail(`No component for ${name}`);\n return this.component(comp).addCondition({ kind: \"in\", value: ids });\n }),\n };\n }\n\n /** Picks the component from an entity, tagged id, or another domain alias column. */\n private addEqOrNe(kind: \"eq\" | \"ne\", value: unknown): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value === null) {\n // We can AND each of the components as many conditions\n return {\n and: this.field.components.map((c) =>\n this.component(c).addCondition({ kind: kind === \"eq\" ? \"is-null\" : \"not-null\" }),\n ),\n };\n }\n const otherMeta =\n value instanceof AliasColumnImpl\n ? value.field.kind === \"m2o\"\n ? value.field.otherMetadata()\n : value.meta\n : getMetadata(getConstructorFromTaggedId(maybeResolveReferenceToId(value as Entity | TaggedId)!));\n const comp =\n this.field.components.find((c) => getBaseAndSelfMetas(otherMeta).includes(c.otherMetadata())) ??\n fail(`${this.field.fieldName} has no component for ${otherMeta.type}`);\n const column = this.component(comp);\n return kind === \"eq\" ? column.eq(value) : column.ne(value);\n }\n\n /** Uses the component serde, not the first component's codec. */\n private component(comp: PolymorphicFieldComponent): AliasColumnImpl {\n const column = this.field.serde.columns.find((c) => c.columnName === comp.columnName) ?? fail(\"Missing column\");\n return new AliasColumnImpl(this.meta, this.field, column, this.mgmt);\n }\n}\n\n/** Adjusts a field's SQL alias when a base alias is bound to a CTI subtype in the join tree. */\nexport function getMaybeCtiAlias(\n meta: EntityMetadata,\n field: Field & { aliasSuffix: string },\n newMeta: EntityMetadata,\n newAlias: string,\n): string {\n // Do we have mismatched `em.find(ChildMeta)` with a `alias(BaseMeta)`? If so, the\n // usual `${field.aliasSuffix}` won't know it should have a suffix, so we need to calc it.\n if (newMeta !== meta && newMeta.inheritanceType === \"cti\") {\n const bases = getBaseAndSelfMetas(newMeta);\n const fieldIsFromBase = bases.includes(newMeta);\n if (fieldIsFromBase) return `${newAlias}_b0`;\n }\n return `${newAlias}${field.aliasSuffix}`;\n}\n\n/** Compares domain columns with per-parse aliases, preserving condition reuse across find calls. */\nfunction crossColumnCondition(left: AliasColumnImpl, right: AliasColumnImpl, op: string, negate = false): RawCondition {\n const cond: RawCondition = { kind: \"raw\", aliases: [], condition: \"unset\", bindings: [], pruneable: false };\n return withDeferredAlias(cond, (resolve, copy) => {\n const l = resolve(left.mgmt);\n const r = resolve(right.mgmt);\n const a1 = getMaybeCtiAlias(left.meta, left.field, l.meta, l.alias);\n const a2 = getMaybeCtiAlias(right.meta, right.field, r.meta, r.alias);\n copy.aliases = [a1, a2];\n const sql = `${a1}.${left.column.columnName} ${op} ${a2}.${right.column.columnName}`;\n copy.condition = negate ? `NOT (${sql})` : sql;\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Aliases.js","names":[],"sources":["../src/Aliases.ts"],"sourcesContent":["import { groupBy } from \"joist-utils\";\n\n// Load configure first: relations must not evaluate before their base classes exist.\nimport { getConstructorFromTaggedId } from \"./configure.ts\";\nimport { withDeferredAlias } from \"./DeferredAlias.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type ExpressionCondition } from \"./EntityFilter.ts\";\nimport { type IdOf, type MaybeAbstractEntityConstructor, type TaggedId } from \"./EntityManager.ts\";\nimport {\n type EntityMetadata,\n type Field,\n type PolymorphicField,\n type PolymorphicFieldComponent,\n getBaseAndSelfMetas,\n getMetadata,\n} from \"./EntityMetadata.ts\";\nimport { maybeResolveReferenceToId } from \"./keys.ts\";\nimport { type ColumnCondition, type ParsedValueFilter, type RawCondition, makeLike, mapToDb } from \"./QueryParser.ts\";\nimport { type Column } from \"./serde.ts\";\nimport { skipCondition } from \"./skipCondition.ts\";\nimport { type FieldsOf } from \"./typeMap.ts\";\nimport { fail } from \"./utils.ts\";\n\n/** Creates an alias for complex domain filtering in `em.find`. */\nexport function alias<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): Alias<T> {\n return newAliasProxy(cstr);\n}\n\n/** Creates multiple aliases for complex filtering. */\nexport function aliases<T extends readonly MaybeAbstractEntityConstructor<any>[]>(\n ...types: T\n): { [P in keyof T]: T[P] extends MaybeAbstractEntityConstructor<infer E extends Entity> ? Alias<E> : never } {\n return types.map((t) => newAliasProxy(t)) as any;\n}\n\nexport const aliasMgmt = Symbol(\"aliasMgmt\");\nconst aliasColumn = Symbol(\"aliasColumn\");\n\n/** The identity and original entity metadata of an `em.find` alias. */\nexport interface AliasMgmt {\n tableName: string;\n meta: EntityMetadata;\n}\n\n/** Keeps domain aliases covariant in their entity type. */\nexport interface AliasBrand<T> extends AliasMgmt {\n readonly __entity: T;\n}\n\n/**\n * Domain field predicates, deliberately separate from SQL table expressions.\n *\n * An Alias names a place in an em.find relationship tree, not a fixed SQL table occurrence.\n * I.e. with `a = alias(Author)`, `{ author: { as: a } }` binds `a` to the Book's Author;\n * binding it under `{ author: { mentor: { as: a } } }` instead makes it the Author's mentor.\n * The find parser builds those joins and knows which entity metadata and SQL name apply there,\n * including any inheritance joins. The Alias cannot know that when `a.firstName.eq(name)` is created.\n *\n * DeferredAlias therefore resolves each predicate to a fresh column/raw condition using that parse's\n * binding. The resolved condition records the SQL aliases it reads, including both sides of a\n * cross-alias comparison. Join pruning uses those references to retain the joins the filter needs.\n * An undefined predicate is skipped, so it does not keep an otherwise-unused join alive; explicit\n * keepAliases and other query dependencies can still retain that join.\n *\n * Table expressions solve a different problem: their sources are supplied directly in from/join,\n * so they render through ExprContext rather than asking the find parser to bind a relationship path.\n * Neither path stores a resolved SQL name on the reusable handle or predicate.\n */\nexport type Alias<T extends Entity> = { readonly [aliasMgmt]: AliasBrand<T> } & {\n [P in keyof FieldsOf<T>]: P extends \"id\"\n ? EntityAlias<T>\n : FieldsOf<T>[P] extends { kind: \"primitive\" | \"enum\"; type: infer V; nullable: infer N }\n ? PrimitiveAlias<V, N extends undefined ? null : never>\n : FieldsOf<T>[P] extends { kind: \"m2o\"; type: infer U extends Entity; nullable: infer N }\n ? EntityAlias<U, N extends undefined ? null : never>\n : FieldsOf<T>[P] extends { kind: \"poly\"; type: infer U extends Entity }\n ? PolyAlias<U>\n : never;\n};\n\n/** A domain column accepted on the other side of a cross-alias comparison. */\nexport interface AliasColumn<V> {\n readonly [aliasColumn]: V;\n}\n\nexport interface PrimitiveAlias<V, N extends null | never = never> extends AliasColumn<V | N> {\n eq(value: V | N | AliasColumn<V | null> | undefined): ExpressionCondition;\n ne(value: V | N | AliasColumn<V | null> | undefined): ExpressionCondition;\n in(values: readonly (V | null)[] | undefined): ExpressionCondition;\n nin(values: readonly (V | null)[] | undefined): ExpressionCondition;\n gt(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n gte(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n lt(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n lte(value: V | AliasColumn<V | null> | undefined): ExpressionCondition;\n like(value: V | undefined): ExpressionCondition;\n ilike(value: V | undefined): ExpressionCondition;\n search(value: V | undefined): ExpressionCondition;\n between(v1: V | undefined, v2: V | undefined): ExpressionCondition;\n // V is already an array; strings also support jsonb contains.\n contains(value: string | V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n ncontains(value: string | V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n overlaps(value: V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n noverlaps(value: V | AliasColumn<V | null> | N | undefined): ExpressionCondition;\n /** Adds a parameterized JSON path existence condition using `@?`. */\n pathExists(jsonPath: string | undefined): ExpressionCondition;\n /** Adds a parameterized JSON path predicate condition using `@@`. */\n pathIsTrue(jsonPath: string | undefined): ExpressionCondition;\n /** Adds an operator and expression with knex-style placeholders, without the column name. */\n raw(exp: string, bindings: readonly unknown[] | undefined): ExpressionCondition;\n}\n\nexport interface EntityAlias<T, N extends null | never = never> extends AliasColumn<IdOf<T> | N> {\n eq(value: T | IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n ne(value: T | IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n // Adding `| null` for GraphQL support\n in(values: readonly (T | IdOf<T> | null)[] | null | undefined): ExpressionCondition;\n nin(values: readonly (T | IdOf<T> | null)[] | null | undefined): ExpressionCondition;\n gt(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n gte(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n lt(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n lte(value: IdOf<T> | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n raw(exp: string, bindings: readonly unknown[] | undefined): ExpressionCondition;\n}\n\nexport interface PolyAlias<T extends Entity> {\n eq(value: T | TaggedId | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n ne(value: T | TaggedId | AliasColumn<IdOf<T> | null> | null | undefined): ExpressionCondition;\n in(values: readonly (T | TaggedId)[] | undefined): ExpressionCondition;\n}\n\n/** Returns the runtime identity bound by the find parser. */\nexport function getAliasMgmt(alias: { readonly [aliasMgmt]: AliasMgmt }): AliasMgmt {\n return alias[aliasMgmt];\n}\n\n/** Returns the original metadata, preserving STI subtype identity. */\nexport function getAliasMetadata<T extends Entity>(alias: Alias<T>): EntityMetadata<T> {\n return alias[aliasMgmt].meta as EntityMetadata<T>;\n}\n\n/** Creates domain predicates lazily from entity field metadata. */\nexport function newAliasProxy<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): Alias<T> {\n const meta = getMetadata(cstr);\n const mgmt: AliasMgmt = { tableName: meta.tableName, meta };\n return new Proxy(cstr, {\n get(_, key) {\n if (key === aliasMgmt) return mgmt;\n if (typeof key !== \"string\") return undefined;\n const field = meta.allFields[key] ?? fail(`No field ${key} on ${cstr.name}`);\n if (field.kind === \"poly\") return new PolyReferenceAlias(meta, mgmt, field);\n if ([\"primaryKey\", \"primitive\", \"enum\", \"m2o\"].includes(field.kind)) {\n return new AliasColumnImpl(meta, field, field.serde!.columns[0], mgmt);\n }\n return fail(`Unsupported alias field kind ${field.kind}`);\n },\n has(_, key) {\n return key === aliasMgmt || key in meta.allFields;\n },\n }) as unknown as Alias<T>;\n}\n\n/** Recognizes only domain aliases, not physical tables. */\nexport function isAlias(value: unknown): value is Alias<Entity> {\n return typeof value === \"function\" && aliasMgmt in value;\n}\n\n/** Builds field conditions without implementing the SQL expression protocol. */\nclass AliasColumnImpl {\n declare readonly [aliasColumn]: unknown;\n\n constructor(\n readonly meta: EntityMetadata,\n readonly field: Field & { aliasSuffix: string },\n readonly column: Column,\n readonly mgmt: AliasMgmt,\n ) {}\n\n eq(value: unknown): ExpressionCondition {\n return this.compare(\"eq\", \"=\", value);\n }\n ne(value: unknown): ExpressionCondition {\n return this.compare(\"ne\", \"!=\", value);\n }\n gt(value: unknown): ExpressionCondition {\n return this.compare(\"gt\", \">\", value);\n }\n gte(value: unknown): ExpressionCondition {\n return this.compare(\"gte\", \">=\", value);\n }\n lt(value: unknown): ExpressionCondition {\n return this.compare(\"lt\", \"<\", value);\n }\n lte(value: unknown): ExpressionCondition {\n return this.compare(\"lte\", \"<=\", value);\n }\n contains(value: unknown): ExpressionCondition {\n return this.compare(\"contains\", \"@>\", value);\n }\n ncontains(value: unknown): ExpressionCondition {\n if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, \"@>\", true);\n return this.addCondition({ kind: \"ncontains\", value: value as readonly unknown[] });\n }\n overlaps(value: unknown): ExpressionCondition {\n return this.compare(\"overlaps\", \"&&\", value);\n }\n noverlaps(value: unknown): ExpressionCondition {\n if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, \"&&\", true);\n return this.addCondition({ kind: \"noverlaps\", value: value as readonly unknown[] });\n }\n\n in(values: readonly unknown[] | null | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (values === null) return fail(\"Unsupported\");\n if (values.includes(null)) {\n return {\n or: [\n this.addCondition({ kind: \"is-null\" }),\n this.addCondition({ kind: \"in\", value: values.filter((v) => v !== null) }),\n ],\n };\n }\n return this.addCondition({ kind: \"in\", value: [...values] });\n }\n\n nin(values: readonly unknown[] | null | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (values === null) return fail(\"Unsupported\");\n return this.addCondition({ kind: \"nin\", value: values.filter((v) => v !== null) });\n }\n\n between(v1: unknown, v2: unknown): ExpressionCondition {\n if (v1 === undefined || v2 === undefined) return skipCondition;\n return this.addCondition({ kind: \"between\", value: [v1, v2] });\n }\n\n like(value: unknown): ExpressionCondition {\n return this.addCondition({ kind: \"like\", value });\n }\n ilike(value: unknown): ExpressionCondition {\n return this.addCondition({ kind: \"ilike\", value });\n }\n search(value: unknown): ExpressionCondition {\n // Check !value so that empty strings are pruned\n return !value ? skipCondition : this.addCondition({ kind: \"ilike\", value: makeLike(value) });\n }\n pathExists(value: string | undefined): ExpressionCondition {\n return this.addCondition({ kind: \"jsonPathExists\", value: value! });\n }\n pathIsTrue(value: string | undefined): ExpressionCondition {\n return this.addCondition({ kind: \"jsonPathPredicate\", value: value! });\n }\n\n raw(exp: string, bindings: readonly unknown[] | undefined): ExpressionCondition {\n if (bindings === undefined) return skipCondition;\n const cond: RawCondition = { kind: \"raw\", aliases: [], condition: \"unset\", pruneable: false, bindings };\n return withDeferredAlias(cond, (resolve, copy) => {\n const r = resolve(this.mgmt);\n const alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);\n copy.aliases = [alias];\n copy.condition = `${alias}.${this.column.columnName} ${exp}`;\n });\n }\n\n /** Maps literal values through the field serde and binds aliases only when parsing. */\n addCondition(value: ParsedValueFilter<unknown>): ColumnCondition {\n if (\"value\" in value && value.value === undefined) return skipCondition;\n const cond: ColumnCondition = {\n kind: \"column\",\n alias: \"unset\",\n column: this.column.columnName,\n dbType: this.column.dbType,\n cond: mapToDb(this.column, value),\n };\n return withDeferredAlias(cond, (resolve, copy) => {\n const r = resolve(this.mgmt);\n copy.alias = getMaybeCtiAlias(this.meta, this.field, r.meta, r.alias);\n });\n }\n\n /** Handles literal values, NULL, and domain cross-alias comparisons. */\n private compare(\n kind: \"eq\" | \"ne\" | \"gt\" | \"gte\" | \"lt\" | \"lte\" | \"contains\" | \"ncontains\" | \"overlaps\",\n op: string,\n value: unknown,\n ): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value instanceof AliasColumnImpl) return crossColumnCondition(this, value, op);\n if (value === null && (kind === \"eq\" || kind === \"ne\"))\n return this.addCondition({ kind: kind === \"eq\" ? \"is-null\" : \"not-null\" });\n if (value === null && [\"gt\", \"gte\", \"lt\", \"lte\"].includes(kind)) return fail(\"Unsupported\");\n return this.addCondition({ kind, value } as ParsedValueFilter<unknown>);\n }\n}\n\n/** Resolves polymorphic predicates to their physical component columns. */\nclass PolyReferenceAlias {\n constructor(\n private meta: EntityMetadata,\n private mgmt: AliasMgmt,\n private field: PolymorphicField & { aliasSuffix: string },\n ) {}\n\n eq(value: unknown): ExpressionCondition {\n return this.addEqOrNe(\"eq\", value);\n }\n ne(value: unknown): ExpressionCondition {\n return this.addEqOrNe(\"ne\", value);\n }\n\n in(values: readonly (Entity | TaggedId)[] | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n // Split up the ids by constructor\n const groups = groupBy(values, (id) => getConstructorFromTaggedId(maybeResolveReferenceToId(id)!).name);\n // Or together `parent_book_id in (1,2,3) OR parent_author_id IN (4,5,6)`\n return {\n or: Object.entries(groups).map(([name, ids]) => {\n const comp =\n this.field.components.find((c) => c.otherMetadata().cstr.name === name) ?? fail(`No component for ${name}`);\n return this.component(comp).addCondition({ kind: \"in\", value: ids });\n }),\n };\n }\n\n /** Picks the component from an entity, tagged id, or another domain alias column. */\n private addEqOrNe(kind: \"eq\" | \"ne\", value: unknown): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value === null) {\n // We can AND each of the components as many conditions\n return {\n and: this.field.components.map((c) =>\n this.component(c).addCondition({ kind: kind === \"eq\" ? \"is-null\" : \"not-null\" }),\n ),\n };\n }\n const otherMeta =\n value instanceof AliasColumnImpl\n ? value.field.kind === \"m2o\"\n ? value.field.otherMetadata()\n : value.meta\n : getMetadata(getConstructorFromTaggedId(maybeResolveReferenceToId(value as Entity | TaggedId)!));\n const comp =\n this.field.components.find((c) => getBaseAndSelfMetas(otherMeta).includes(c.otherMetadata())) ??\n fail(`${this.field.fieldName} has no component for ${otherMeta.type}`);\n const column = this.component(comp);\n return kind === \"eq\" ? column.eq(value) : column.ne(value);\n }\n\n /** Uses the component serde, not the first component's codec. */\n private component(comp: PolymorphicFieldComponent): AliasColumnImpl {\n const column = this.field.serde.columns.find((c) => c.columnName === comp.columnName) ?? fail(\"Missing column\");\n return new AliasColumnImpl(this.meta, this.field, column, this.mgmt);\n }\n}\n\n/** Adjusts a field's SQL alias when a base alias is bound to a CTI subtype in the join tree. */\nexport function getMaybeCtiAlias(\n meta: EntityMetadata,\n field: Field & { aliasSuffix: string },\n newMeta: EntityMetadata,\n newAlias: string,\n): string {\n // Do we have mismatched `em.find(ChildMeta)` with a `alias(BaseMeta)`? If so, the\n // usual `${field.aliasSuffix}` won't know it should have a suffix, so we need to calc it.\n if (newMeta !== meta && newMeta.inheritanceType === \"cti\") {\n const bases = getBaseAndSelfMetas(newMeta);\n const fieldIsFromBase = bases.includes(newMeta);\n if (fieldIsFromBase) return `${newAlias}_b0`;\n }\n return `${newAlias}${field.aliasSuffix}`;\n}\n\n/** Compares domain columns with per-parse aliases, preserving condition reuse across find calls. */\nfunction crossColumnCondition(left: AliasColumnImpl, right: AliasColumnImpl, op: string, negate = false): RawCondition {\n const cond: RawCondition = { kind: \"raw\", aliases: [], condition: \"unset\", bindings: [], pruneable: false };\n return withDeferredAlias(cond, (resolve, copy) => {\n const l = resolve(left.mgmt);\n const r = resolve(right.mgmt);\n const a1 = getMaybeCtiAlias(left.meta, left.field, l.meta, l.alias);\n const a2 = getMaybeCtiAlias(right.meta, right.field, r.meta, r.alias);\n copy.aliases = [a1, a2];\n const sql = `${a1}.${left.column.columnName} ${op} ${a2}.${right.column.columnName}`;\n copy.condition = negate ? `NOT (${sql})` : sql;\n });\n}\n"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  require("./EntityFilter.cjs");
3
- const require_DeferredAlias = require("./DeferredAlias.cjs");
4
- require("./Expr.cjs");
3
+ const require_skipCondition = require("./skipCondition.cjs");
5
4
  require("./serde.cjs");
6
5
  const require_utils = require("./utils.cjs");
7
6
  const require_EntityManager = require("./EntityManager.cjs");
@@ -95,7 +94,7 @@ var ConditionBuilder = class {
95
94
  function parseExpression(expression) {
96
95
  const [op, expressions] = "and" in expression && expression.and ? ["and", expression.and] : "or" in expression && expression.or ? ["or", expression.or] : require_utils.fail(`Invalid expression ${expression}`);
97
96
  const conditions = expressions.map((exp) => exp && ("and" in exp || "or" in exp) ? parseExpression(exp) : exp);
98
- const [skip, valid] = require_utils.partition(conditions, (cond) => cond === void 0 || cond === require_DeferredAlias.skipCondition);
97
+ const [skip, valid] = require_utils.partition(conditions, (cond) => cond === void 0 || cond === require_skipCondition.skipCondition);
99
98
  if (skip.length > 0 && expression.pruneIfUndefined === "any" || valid.length === 0) return;
100
99
  return {
101
100
  kind: "exp",
@@ -1 +1 @@
1
- {"version":3,"file":"ConditionBuilder.cjs","names":["mapToDb","fail","partition","skipCondition","isDefined"],"sources":["../src/ConditionBuilder.ts"],"sourcesContent":["import { type ExpressionFilter } from \"./EntityFilter.ts\";\nimport { isDefined } from \"./EntityManager.ts\";\nimport { skipCondition } from \"./Expr.ts\";\nimport {\n type ColumnCondition,\n type ParsedExpressionCondition,\n type ParsedExpressionFilter,\n type ParsedValueFilter,\n type RawCondition,\n mapToDb,\n} from \"./QueryParser.ts\";\nimport { type Column } from \"./serde.ts\";\nimport { fail, partition } from \"./utils.ts\";\n\ntype PartialSome<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;\n\n/** Converts domain-level values like string ids/enums into their db equivalent. */\nexport class ConditionBuilder {\n /** Simple, single-column conditions, which will be AND-d together. */\n private conditions: (ColumnCondition | RawCondition)[] = [];\n /** Complex expressions, which will also be AND-d together with `conditions`. */\n private expressions: ParsedExpressionFilter[] = [];\n\n /** Accepts a raw user-facing DSL filter, and parses it into a `ParsedExpressionFilter`. */\n maybeAddExpression(expression: ExpressionFilter): void {\n const parsed = parseExpression(expression);\n if (parsed) this.expressions.push(parsed);\n }\n\n /** Adds an already-db-level condition to the simple conditions list. */\n addSimpleCondition(condition: ColumnCondition): void {\n this.conditions.push(condition);\n }\n\n /** Adds an already-db-level condition to the simple conditions list. */\n addRawCondition(condition: PartialSome<RawCondition, \"kind\" | \"bindings\">): void {\n this.conditions.push({\n kind: \"raw\",\n bindings: [],\n ...condition,\n });\n }\n\n /** Adds an already-db-level expression to the expressions list. */\n addParsedExpression(parsed: ParsedExpressionFilter): void {\n this.expressions.push(parsed);\n }\n\n /**\n * Adds a user-facing `ParsedValueFilter` to the inline conditions.\n *\n * Unless it's something like `in: [a1, null]`, in which case we split it into two `is-null` and `in` conditions.\n */\n addValueFilter(alias: string, column: Column, filter: ParsedValueFilter<any>): void {\n if (filter.kind === \"in\" && filter.value.includes(null)) {\n // If the filter contains a null, we need to split it into an `is-null` and `in` condition\n const isNull = {\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n cond: { kind: \"is-null\" },\n } satisfies ColumnCondition;\n const inValues = {\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n cond: {\n kind: \"in\",\n // Filter out the nulls from the in condition\n value: filter.value.filter((v) => v !== null).map((v) => column.mapToDb(v)),\n },\n } satisfies ColumnCondition;\n // Now OR them back together\n this.expressions.push({ kind: \"exp\", op: \"or\", conditions: [isNull, inValues] });\n } else {\n const cond = {\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n // Rewrite the user-facing domain values to db values\n cond: mapToDb(column, filter),\n } satisfies ColumnCondition;\n this.conditions.push(cond);\n }\n }\n\n /** Combines our collected `conditions` and `expressions` into a single `ParsedExpressionFilter`. */\n toExpressionFilter(): ParsedExpressionFilter | undefined {\n const { expressions, conditions } = this;\n const allSimple: ParsedExpressionCondition[] = [...conditions];\n if (allSimple.length === 0 && expressions.length === 1) {\n // If no inline conditions, and just 1 opt expression, just use that\n return expressions[0];\n } else if (expressions.length === 1 && expressions[0].op === \"and\") {\n // Merge the 1 `AND` expression with the other simple conditions\n return { kind: \"exp\", op: \"and\", conditions: [...allSimple, ...expressions[0].conditions] };\n } else if (allSimple.length > 0 || expressions.length > 0) {\n // Combine the conditions within the `em.find` join literal & the `conditions` as ANDs\n return { kind: \"exp\", op: \"and\", conditions: [...allSimple, ...expressions] };\n }\n return undefined;\n }\n}\n\n/** Parses user-facing `{ and: ... }` or `{ or: ... }` into a `ParsedExpressionFilter`. */\nfunction parseExpression(expression: ExpressionFilter): ParsedExpressionFilter | undefined {\n // Look for `{ and: [...] }` or `{ or: [...] }`\n const [op, expressions] =\n \"and\" in expression && expression.and\n ? [\"and\" as const, expression.and]\n : \"or\" in expression && expression.or\n ? [\"or\" as const, expression.or]\n : fail(`Invalid expression ${expression}`);\n // Potentially recurse into nested expressions\n const conditions = expressions.map((exp) => (exp && (\"and\" in exp || \"or\" in exp) ? parseExpression(exp) : exp));\n const [skip, valid] = partition(conditions, (cond) => cond === undefined || cond === skipCondition);\n if ((skip.length > 0 && expression.pruneIfUndefined === \"any\") || valid.length === 0) {\n return undefined;\n }\n return { kind: \"exp\", op, conditions: valid.filter(isDefined) };\n}\n"],"mappings":";;;;;;;;;;AAiBA,IAAa,mBAAb,MAA8B;;CAE5B,aAAyD,CAAC;;CAE1D,cAAgD,CAAC;;CAGjD,mBAAmB,YAAoC;EACrD,MAAM,SAAS,gBAAgB,UAAU;EACzC,IAAI,QAAQ,KAAK,YAAY,KAAK,MAAM;CAC1C;;CAGA,mBAAmB,WAAkC;EACnD,KAAK,WAAW,KAAK,SAAS;CAChC;;CAGA,gBAAgB,WAAiE;EAC/E,KAAK,WAAW,KAAK;GACnB,MAAM;GACN,UAAU,CAAC;GACX,GAAG;EACL,CAAC;CACH;;CAGA,oBAAoB,QAAsC;EACxD,KAAK,YAAY,KAAK,MAAM;CAC9B;;;;;;CAOA,eAAe,OAAe,QAAgB,QAAsC;EAClF,IAAI,OAAO,SAAS,QAAQ,OAAO,MAAM,SAAS,IAAI,GAAG;GAEvD,MAAM,SAAS;IACb,MAAM;IACN;IACA,QAAQ,OAAO;IACf,QAAQ,OAAO;IACf,MAAM,EAAE,MAAM,UAAU;GAC1B;GACA,MAAM,WAAW;IACf,MAAM;IACN;IACA,QAAQ,OAAO;IACf,QAAQ,OAAO;IACf,MAAM;KACJ,MAAM;KAEN,OAAO,OAAO,MAAM,QAAQ,MAAM,MAAM,IAAI,CAAC,CAAC,KAAK,MAAM,OAAO,QAAQ,CAAC,CAAC;IAC5E;GACF;GAEA,KAAK,YAAY,KAAK;IAAE,MAAM;IAAO,IAAI;IAAM,YAAY,CAAC,QAAQ,QAAQ;GAAE,CAAC;EACjF,OAAO;GACL,MAAM,OAAO;IACX,MAAM;IACN;IACA,QAAQ,OAAO;IACf,QAAQ,OAAO;IAEf,MAAMA,oBAAAA,QAAQ,QAAQ,MAAM;GAC9B;GACA,KAAK,WAAW,KAAK,IAAI;EAC3B;CACF;;CAGA,qBAAyD;EACvD,MAAM,EAAE,aAAa,eAAe;EACpC,MAAM,YAAyC,CAAC,GAAG,UAAU;EAC7D,IAAI,UAAU,WAAW,KAAK,YAAY,WAAW,GAEnD,OAAO,YAAY;OACd,IAAI,YAAY,WAAW,KAAK,YAAY,EAAE,CAAC,OAAO,OAE3D,OAAO;GAAE,MAAM;GAAO,IAAI;GAAO,YAAY,CAAC,GAAG,WAAW,GAAG,YAAY,EAAE,CAAC,UAAU;EAAE;OACrF,IAAI,UAAU,SAAS,KAAK,YAAY,SAAS,GAEtD,OAAO;GAAE,MAAM;GAAO,IAAI;GAAO,YAAY,CAAC,GAAG,WAAW,GAAG,WAAW;EAAE;CAGhF;AACF;;AAGA,SAAS,gBAAgB,YAAkE;CAEzF,MAAM,CAAC,IAAI,eACT,SAAS,cAAc,WAAW,MAC9B,CAAC,OAAgB,WAAW,GAAG,IAC/B,QAAQ,cAAc,WAAW,KAC/B,CAAC,MAAe,WAAW,EAAE,IAC7BC,cAAAA,KAAK,sBAAsB,YAAY;CAE/C,MAAM,aAAa,YAAY,KAAK,QAAS,QAAQ,SAAS,OAAO,QAAQ,OAAO,gBAAgB,GAAG,IAAI,GAAI;CAC/G,MAAM,CAAC,MAAM,SAASC,cAAAA,UAAU,aAAa,SAAS,SAAS,KAAA,KAAa,SAASC,sBAAAA,aAAa;CAClG,IAAK,KAAK,SAAS,KAAK,WAAW,qBAAqB,SAAU,MAAM,WAAW,GACjF;CAEF,OAAO;EAAE,MAAM;EAAO;EAAI,YAAY,MAAM,OAAOC,sBAAAA,SAAS;CAAE;AAChE"}
1
+ {"version":3,"file":"ConditionBuilder.cjs","names":["mapToDb","fail","partition","skipCondition","isDefined"],"sources":["../src/ConditionBuilder.ts"],"sourcesContent":["import { type ExpressionFilter } from \"./EntityFilter.ts\";\nimport { isDefined } from \"./EntityManager.ts\";\nimport {\n type ColumnCondition,\n type ParsedExpressionCondition,\n type ParsedExpressionFilter,\n type ParsedValueFilter,\n type RawCondition,\n mapToDb,\n} from \"./QueryParser.ts\";\nimport { type Column } from \"./serde.ts\";\nimport { skipCondition } from \"./skipCondition.ts\";\nimport { fail, partition } from \"./utils.ts\";\n\ntype PartialSome<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;\n\n/** Converts domain-level values like string ids/enums into their db equivalent. */\nexport class ConditionBuilder {\n /** Simple, single-column conditions, which will be AND-d together. */\n private conditions: (ColumnCondition | RawCondition)[] = [];\n /** Complex expressions, which will also be AND-d together with `conditions`. */\n private expressions: ParsedExpressionFilter[] = [];\n\n /** Accepts a raw user-facing DSL filter, and parses it into a `ParsedExpressionFilter`. */\n maybeAddExpression(expression: ExpressionFilter): void {\n const parsed = parseExpression(expression);\n if (parsed) this.expressions.push(parsed);\n }\n\n /** Adds an already-db-level condition to the simple conditions list. */\n addSimpleCondition(condition: ColumnCondition): void {\n this.conditions.push(condition);\n }\n\n /** Adds an already-db-level condition to the simple conditions list. */\n addRawCondition(condition: PartialSome<RawCondition, \"kind\" | \"bindings\">): void {\n this.conditions.push({\n kind: \"raw\",\n bindings: [],\n ...condition,\n });\n }\n\n /** Adds an already-db-level expression to the expressions list. */\n addParsedExpression(parsed: ParsedExpressionFilter): void {\n this.expressions.push(parsed);\n }\n\n /**\n * Adds a user-facing `ParsedValueFilter` to the inline conditions.\n *\n * Unless it's something like `in: [a1, null]`, in which case we split it into two `is-null` and `in` conditions.\n */\n addValueFilter(alias: string, column: Column, filter: ParsedValueFilter<any>): void {\n if (filter.kind === \"in\" && filter.value.includes(null)) {\n // If the filter contains a null, we need to split it into an `is-null` and `in` condition\n const isNull = {\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n cond: { kind: \"is-null\" },\n } satisfies ColumnCondition;\n const inValues = {\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n cond: {\n kind: \"in\",\n // Filter out the nulls from the in condition\n value: filter.value.filter((v) => v !== null).map((v) => column.mapToDb(v)),\n },\n } satisfies ColumnCondition;\n // Now OR them back together\n this.expressions.push({ kind: \"exp\", op: \"or\", conditions: [isNull, inValues] });\n } else {\n const cond = {\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n // Rewrite the user-facing domain values to db values\n cond: mapToDb(column, filter),\n } satisfies ColumnCondition;\n this.conditions.push(cond);\n }\n }\n\n /** Combines our collected `conditions` and `expressions` into a single `ParsedExpressionFilter`. */\n toExpressionFilter(): ParsedExpressionFilter | undefined {\n const { expressions, conditions } = this;\n const allSimple: ParsedExpressionCondition[] = [...conditions];\n if (allSimple.length === 0 && expressions.length === 1) {\n // If no inline conditions, and just 1 opt expression, just use that\n return expressions[0];\n } else if (expressions.length === 1 && expressions[0].op === \"and\") {\n // Merge the 1 `AND` expression with the other simple conditions\n return { kind: \"exp\", op: \"and\", conditions: [...allSimple, ...expressions[0].conditions] };\n } else if (allSimple.length > 0 || expressions.length > 0) {\n // Combine the conditions within the `em.find` join literal & the `conditions` as ANDs\n return { kind: \"exp\", op: \"and\", conditions: [...allSimple, ...expressions] };\n }\n return undefined;\n }\n}\n\n/** Parses user-facing `{ and: ... }` or `{ or: ... }` into a `ParsedExpressionFilter`. */\nfunction parseExpression(expression: ExpressionFilter): ParsedExpressionFilter | undefined {\n // Look for `{ and: [...] }` or `{ or: [...] }`\n const [op, expressions] =\n \"and\" in expression && expression.and\n ? [\"and\" as const, expression.and]\n : \"or\" in expression && expression.or\n ? [\"or\" as const, expression.or]\n : fail(`Invalid expression ${expression}`);\n // Potentially recurse into nested expressions\n const conditions = expressions.map((exp) => (exp && (\"and\" in exp || \"or\" in exp) ? parseExpression(exp) : exp));\n const [skip, valid] = partition(conditions, (cond) => cond === undefined || cond === skipCondition);\n if ((skip.length > 0 && expression.pruneIfUndefined === \"any\") || valid.length === 0) {\n return undefined;\n }\n return { kind: \"exp\", op, conditions: valid.filter(isDefined) };\n}\n"],"mappings":";;;;;;;;;AAiBA,IAAa,mBAAb,MAA8B;;CAE5B,aAAyD,CAAC;;CAE1D,cAAgD,CAAC;;CAGjD,mBAAmB,YAAoC;EACrD,MAAM,SAAS,gBAAgB,UAAU;EACzC,IAAI,QAAQ,KAAK,YAAY,KAAK,MAAM;CAC1C;;CAGA,mBAAmB,WAAkC;EACnD,KAAK,WAAW,KAAK,SAAS;CAChC;;CAGA,gBAAgB,WAAiE;EAC/E,KAAK,WAAW,KAAK;GACnB,MAAM;GACN,UAAU,CAAC;GACX,GAAG;EACL,CAAC;CACH;;CAGA,oBAAoB,QAAsC;EACxD,KAAK,YAAY,KAAK,MAAM;CAC9B;;;;;;CAOA,eAAe,OAAe,QAAgB,QAAsC;EAClF,IAAI,OAAO,SAAS,QAAQ,OAAO,MAAM,SAAS,IAAI,GAAG;GAEvD,MAAM,SAAS;IACb,MAAM;IACN;IACA,QAAQ,OAAO;IACf,QAAQ,OAAO;IACf,MAAM,EAAE,MAAM,UAAU;GAC1B;GACA,MAAM,WAAW;IACf,MAAM;IACN;IACA,QAAQ,OAAO;IACf,QAAQ,OAAO;IACf,MAAM;KACJ,MAAM;KAEN,OAAO,OAAO,MAAM,QAAQ,MAAM,MAAM,IAAI,CAAC,CAAC,KAAK,MAAM,OAAO,QAAQ,CAAC,CAAC;IAC5E;GACF;GAEA,KAAK,YAAY,KAAK;IAAE,MAAM;IAAO,IAAI;IAAM,YAAY,CAAC,QAAQ,QAAQ;GAAE,CAAC;EACjF,OAAO;GACL,MAAM,OAAO;IACX,MAAM;IACN;IACA,QAAQ,OAAO;IACf,QAAQ,OAAO;IAEf,MAAMA,oBAAAA,QAAQ,QAAQ,MAAM;GAC9B;GACA,KAAK,WAAW,KAAK,IAAI;EAC3B;CACF;;CAGA,qBAAyD;EACvD,MAAM,EAAE,aAAa,eAAe;EACpC,MAAM,YAAyC,CAAC,GAAG,UAAU;EAC7D,IAAI,UAAU,WAAW,KAAK,YAAY,WAAW,GAEnD,OAAO,YAAY;OACd,IAAI,YAAY,WAAW,KAAK,YAAY,EAAE,CAAC,OAAO,OAE3D,OAAO;GAAE,MAAM;GAAO,IAAI;GAAO,YAAY,CAAC,GAAG,WAAW,GAAG,YAAY,EAAE,CAAC,UAAU;EAAE;OACrF,IAAI,UAAU,SAAS,KAAK,YAAY,SAAS,GAEtD,OAAO;GAAE,MAAM;GAAO,IAAI;GAAO,YAAY,CAAC,GAAG,WAAW,GAAG,WAAW;EAAE;CAGhF;AACF;;AAGA,SAAS,gBAAgB,YAAkE;CAEzF,MAAM,CAAC,IAAI,eACT,SAAS,cAAc,WAAW,MAC9B,CAAC,OAAgB,WAAW,GAAG,IAC/B,QAAQ,cAAc,WAAW,KAC/B,CAAC,MAAe,WAAW,EAAE,IAC7BC,cAAAA,KAAK,sBAAsB,YAAY;CAE/C,MAAM,aAAa,YAAY,KAAK,QAAS,QAAQ,SAAS,OAAO,QAAQ,OAAO,gBAAgB,GAAG,IAAI,GAAI;CAC/G,MAAM,CAAC,MAAM,SAASC,cAAAA,UAAU,aAAa,SAAS,SAAS,KAAA,KAAa,SAASC,sBAAAA,aAAa;CAClG,IAAK,KAAK,SAAS,KAAK,WAAW,qBAAqB,SAAU,MAAM,WAAW,GACjF;CAEF,OAAO;EAAE,MAAM;EAAO;EAAI,YAAY,MAAM,OAAOC,sBAAAA,SAAS;CAAE;AAChE"}
@@ -1,6 +1,5 @@
1
1
  import "./EntityFilter.js";
2
- import { skipCondition } from "./DeferredAlias.js";
3
- import "./Expr.js";
2
+ import { skipCondition } from "./skipCondition.js";
4
3
  import "./serde.js";
5
4
  import { fail, partition } from "./utils.js";
6
5
  import { isDefined } from "./EntityManager.js";
@@ -1 +1 @@
1
- {"version":3,"file":"ConditionBuilder.js","names":[],"sources":["../src/ConditionBuilder.ts"],"sourcesContent":["import { type ExpressionFilter } from \"./EntityFilter.ts\";\nimport { isDefined } from \"./EntityManager.ts\";\nimport { skipCondition } from \"./Expr.ts\";\nimport {\n type ColumnCondition,\n type ParsedExpressionCondition,\n type ParsedExpressionFilter,\n type ParsedValueFilter,\n type RawCondition,\n mapToDb,\n} from \"./QueryParser.ts\";\nimport { type Column } from \"./serde.ts\";\nimport { fail, partition } from \"./utils.ts\";\n\ntype PartialSome<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;\n\n/** Converts domain-level values like string ids/enums into their db equivalent. */\nexport class ConditionBuilder {\n /** Simple, single-column conditions, which will be AND-d together. */\n private conditions: (ColumnCondition | RawCondition)[] = [];\n /** Complex expressions, which will also be AND-d together with `conditions`. */\n private expressions: ParsedExpressionFilter[] = [];\n\n /** Accepts a raw user-facing DSL filter, and parses it into a `ParsedExpressionFilter`. */\n maybeAddExpression(expression: ExpressionFilter): void {\n const parsed = parseExpression(expression);\n if (parsed) this.expressions.push(parsed);\n }\n\n /** Adds an already-db-level condition to the simple conditions list. */\n addSimpleCondition(condition: ColumnCondition): void {\n this.conditions.push(condition);\n }\n\n /** Adds an already-db-level condition to the simple conditions list. */\n addRawCondition(condition: PartialSome<RawCondition, \"kind\" | \"bindings\">): void {\n this.conditions.push({\n kind: \"raw\",\n bindings: [],\n ...condition,\n });\n }\n\n /** Adds an already-db-level expression to the expressions list. */\n addParsedExpression(parsed: ParsedExpressionFilter): void {\n this.expressions.push(parsed);\n }\n\n /**\n * Adds a user-facing `ParsedValueFilter` to the inline conditions.\n *\n * Unless it's something like `in: [a1, null]`, in which case we split it into two `is-null` and `in` conditions.\n */\n addValueFilter(alias: string, column: Column, filter: ParsedValueFilter<any>): void {\n if (filter.kind === \"in\" && filter.value.includes(null)) {\n // If the filter contains a null, we need to split it into an `is-null` and `in` condition\n const isNull = {\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n cond: { kind: \"is-null\" },\n } satisfies ColumnCondition;\n const inValues = {\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n cond: {\n kind: \"in\",\n // Filter out the nulls from the in condition\n value: filter.value.filter((v) => v !== null).map((v) => column.mapToDb(v)),\n },\n } satisfies ColumnCondition;\n // Now OR them back together\n this.expressions.push({ kind: \"exp\", op: \"or\", conditions: [isNull, inValues] });\n } else {\n const cond = {\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n // Rewrite the user-facing domain values to db values\n cond: mapToDb(column, filter),\n } satisfies ColumnCondition;\n this.conditions.push(cond);\n }\n }\n\n /** Combines our collected `conditions` and `expressions` into a single `ParsedExpressionFilter`. */\n toExpressionFilter(): ParsedExpressionFilter | undefined {\n const { expressions, conditions } = this;\n const allSimple: ParsedExpressionCondition[] = [...conditions];\n if (allSimple.length === 0 && expressions.length === 1) {\n // If no inline conditions, and just 1 opt expression, just use that\n return expressions[0];\n } else if (expressions.length === 1 && expressions[0].op === \"and\") {\n // Merge the 1 `AND` expression with the other simple conditions\n return { kind: \"exp\", op: \"and\", conditions: [...allSimple, ...expressions[0].conditions] };\n } else if (allSimple.length > 0 || expressions.length > 0) {\n // Combine the conditions within the `em.find` join literal & the `conditions` as ANDs\n return { kind: \"exp\", op: \"and\", conditions: [...allSimple, ...expressions] };\n }\n return undefined;\n }\n}\n\n/** Parses user-facing `{ and: ... }` or `{ or: ... }` into a `ParsedExpressionFilter`. */\nfunction parseExpression(expression: ExpressionFilter): ParsedExpressionFilter | undefined {\n // Look for `{ and: [...] }` or `{ or: [...] }`\n const [op, expressions] =\n \"and\" in expression && expression.and\n ? [\"and\" as const, expression.and]\n : \"or\" in expression && expression.or\n ? [\"or\" as const, expression.or]\n : fail(`Invalid expression ${expression}`);\n // Potentially recurse into nested expressions\n const conditions = expressions.map((exp) => (exp && (\"and\" in exp || \"or\" in exp) ? parseExpression(exp) : exp));\n const [skip, valid] = partition(conditions, (cond) => cond === undefined || cond === skipCondition);\n if ((skip.length > 0 && expression.pruneIfUndefined === \"any\") || valid.length === 0) {\n return undefined;\n }\n return { kind: \"exp\", op, conditions: valid.filter(isDefined) };\n}\n"],"mappings":";;;;;;;;;AAiBA,IAAa,mBAAb,MAA8B;;CAE5B,aAAyD,CAAC;;CAE1D,cAAgD,CAAC;;CAGjD,mBAAmB,YAAoC;EACrD,MAAM,SAAS,gBAAgB,UAAU;EACzC,IAAI,QAAQ,KAAK,YAAY,KAAK,MAAM;CAC1C;;CAGA,mBAAmB,WAAkC;EACnD,KAAK,WAAW,KAAK,SAAS;CAChC;;CAGA,gBAAgB,WAAiE;EAC/E,KAAK,WAAW,KAAK;GACnB,MAAM;GACN,UAAU,CAAC;GACX,GAAG;EACL,CAAC;CACH;;CAGA,oBAAoB,QAAsC;EACxD,KAAK,YAAY,KAAK,MAAM;CAC9B;;;;;;CAOA,eAAe,OAAe,QAAgB,QAAsC;EAClF,IAAI,OAAO,SAAS,QAAQ,OAAO,MAAM,SAAS,IAAI,GAAG;GAEvD,MAAM,SAAS;IACb,MAAM;IACN;IACA,QAAQ,OAAO;IACf,QAAQ,OAAO;IACf,MAAM,EAAE,MAAM,UAAU;GAC1B;GACA,MAAM,WAAW;IACf,MAAM;IACN;IACA,QAAQ,OAAO;IACf,QAAQ,OAAO;IACf,MAAM;KACJ,MAAM;KAEN,OAAO,OAAO,MAAM,QAAQ,MAAM,MAAM,IAAI,CAAC,CAAC,KAAK,MAAM,OAAO,QAAQ,CAAC,CAAC;IAC5E;GACF;GAEA,KAAK,YAAY,KAAK;IAAE,MAAM;IAAO,IAAI;IAAM,YAAY,CAAC,QAAQ,QAAQ;GAAE,CAAC;EACjF,OAAO;GACL,MAAM,OAAO;IACX,MAAM;IACN;IACA,QAAQ,OAAO;IACf,QAAQ,OAAO;IAEf,MAAM,QAAQ,QAAQ,MAAM;GAC9B;GACA,KAAK,WAAW,KAAK,IAAI;EAC3B;CACF;;CAGA,qBAAyD;EACvD,MAAM,EAAE,aAAa,eAAe;EACpC,MAAM,YAAyC,CAAC,GAAG,UAAU;EAC7D,IAAI,UAAU,WAAW,KAAK,YAAY,WAAW,GAEnD,OAAO,YAAY;OACd,IAAI,YAAY,WAAW,KAAK,YAAY,EAAE,CAAC,OAAO,OAE3D,OAAO;GAAE,MAAM;GAAO,IAAI;GAAO,YAAY,CAAC,GAAG,WAAW,GAAG,YAAY,EAAE,CAAC,UAAU;EAAE;OACrF,IAAI,UAAU,SAAS,KAAK,YAAY,SAAS,GAEtD,OAAO;GAAE,MAAM;GAAO,IAAI;GAAO,YAAY,CAAC,GAAG,WAAW,GAAG,WAAW;EAAE;CAGhF;AACF;;AAGA,SAAS,gBAAgB,YAAkE;CAEzF,MAAM,CAAC,IAAI,eACT,SAAS,cAAc,WAAW,MAC9B,CAAC,OAAgB,WAAW,GAAG,IAC/B,QAAQ,cAAc,WAAW,KAC/B,CAAC,MAAe,WAAW,EAAE,IAC7B,KAAK,sBAAsB,YAAY;CAE/C,MAAM,aAAa,YAAY,KAAK,QAAS,QAAQ,SAAS,OAAO,QAAQ,OAAO,gBAAgB,GAAG,IAAI,GAAI;CAC/G,MAAM,CAAC,MAAM,SAAS,UAAU,aAAa,SAAS,SAAS,KAAA,KAAa,SAAS,aAAa;CAClG,IAAK,KAAK,SAAS,KAAK,WAAW,qBAAqB,SAAU,MAAM,WAAW,GACjF;CAEF,OAAO;EAAE,MAAM;EAAO;EAAI,YAAY,MAAM,OAAO,SAAS;CAAE;AAChE"}
1
+ {"version":3,"file":"ConditionBuilder.js","names":[],"sources":["../src/ConditionBuilder.ts"],"sourcesContent":["import { type ExpressionFilter } from \"./EntityFilter.ts\";\nimport { isDefined } from \"./EntityManager.ts\";\nimport {\n type ColumnCondition,\n type ParsedExpressionCondition,\n type ParsedExpressionFilter,\n type ParsedValueFilter,\n type RawCondition,\n mapToDb,\n} from \"./QueryParser.ts\";\nimport { type Column } from \"./serde.ts\";\nimport { skipCondition } from \"./skipCondition.ts\";\nimport { fail, partition } from \"./utils.ts\";\n\ntype PartialSome<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;\n\n/** Converts domain-level values like string ids/enums into their db equivalent. */\nexport class ConditionBuilder {\n /** Simple, single-column conditions, which will be AND-d together. */\n private conditions: (ColumnCondition | RawCondition)[] = [];\n /** Complex expressions, which will also be AND-d together with `conditions`. */\n private expressions: ParsedExpressionFilter[] = [];\n\n /** Accepts a raw user-facing DSL filter, and parses it into a `ParsedExpressionFilter`. */\n maybeAddExpression(expression: ExpressionFilter): void {\n const parsed = parseExpression(expression);\n if (parsed) this.expressions.push(parsed);\n }\n\n /** Adds an already-db-level condition to the simple conditions list. */\n addSimpleCondition(condition: ColumnCondition): void {\n this.conditions.push(condition);\n }\n\n /** Adds an already-db-level condition to the simple conditions list. */\n addRawCondition(condition: PartialSome<RawCondition, \"kind\" | \"bindings\">): void {\n this.conditions.push({\n kind: \"raw\",\n bindings: [],\n ...condition,\n });\n }\n\n /** Adds an already-db-level expression to the expressions list. */\n addParsedExpression(parsed: ParsedExpressionFilter): void {\n this.expressions.push(parsed);\n }\n\n /**\n * Adds a user-facing `ParsedValueFilter` to the inline conditions.\n *\n * Unless it's something like `in: [a1, null]`, in which case we split it into two `is-null` and `in` conditions.\n */\n addValueFilter(alias: string, column: Column, filter: ParsedValueFilter<any>): void {\n if (filter.kind === \"in\" && filter.value.includes(null)) {\n // If the filter contains a null, we need to split it into an `is-null` and `in` condition\n const isNull = {\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n cond: { kind: \"is-null\" },\n } satisfies ColumnCondition;\n const inValues = {\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n cond: {\n kind: \"in\",\n // Filter out the nulls from the in condition\n value: filter.value.filter((v) => v !== null).map((v) => column.mapToDb(v)),\n },\n } satisfies ColumnCondition;\n // Now OR them back together\n this.expressions.push({ kind: \"exp\", op: \"or\", conditions: [isNull, inValues] });\n } else {\n const cond = {\n kind: \"column\",\n alias,\n column: column.columnName,\n dbType: column.dbType,\n // Rewrite the user-facing domain values to db values\n cond: mapToDb(column, filter),\n } satisfies ColumnCondition;\n this.conditions.push(cond);\n }\n }\n\n /** Combines our collected `conditions` and `expressions` into a single `ParsedExpressionFilter`. */\n toExpressionFilter(): ParsedExpressionFilter | undefined {\n const { expressions, conditions } = this;\n const allSimple: ParsedExpressionCondition[] = [...conditions];\n if (allSimple.length === 0 && expressions.length === 1) {\n // If no inline conditions, and just 1 opt expression, just use that\n return expressions[0];\n } else if (expressions.length === 1 && expressions[0].op === \"and\") {\n // Merge the 1 `AND` expression with the other simple conditions\n return { kind: \"exp\", op: \"and\", conditions: [...allSimple, ...expressions[0].conditions] };\n } else if (allSimple.length > 0 || expressions.length > 0) {\n // Combine the conditions within the `em.find` join literal & the `conditions` as ANDs\n return { kind: \"exp\", op: \"and\", conditions: [...allSimple, ...expressions] };\n }\n return undefined;\n }\n}\n\n/** Parses user-facing `{ and: ... }` or `{ or: ... }` into a `ParsedExpressionFilter`. */\nfunction parseExpression(expression: ExpressionFilter): ParsedExpressionFilter | undefined {\n // Look for `{ and: [...] }` or `{ or: [...] }`\n const [op, expressions] =\n \"and\" in expression && expression.and\n ? [\"and\" as const, expression.and]\n : \"or\" in expression && expression.or\n ? [\"or\" as const, expression.or]\n : fail(`Invalid expression ${expression}`);\n // Potentially recurse into nested expressions\n const conditions = expressions.map((exp) => (exp && (\"and\" in exp || \"or\" in exp) ? parseExpression(exp) : exp));\n const [skip, valid] = partition(conditions, (cond) => cond === undefined || cond === skipCondition);\n if ((skip.length > 0 && expression.pruneIfUndefined === \"any\") || valid.length === 0) {\n return undefined;\n }\n return { kind: \"exp\", op, conditions: valid.filter(isDefined) };\n}\n"],"mappings":";;;;;;;;AAiBA,IAAa,mBAAb,MAA8B;;CAE5B,aAAyD,CAAC;;CAE1D,cAAgD,CAAC;;CAGjD,mBAAmB,YAAoC;EACrD,MAAM,SAAS,gBAAgB,UAAU;EACzC,IAAI,QAAQ,KAAK,YAAY,KAAK,MAAM;CAC1C;;CAGA,mBAAmB,WAAkC;EACnD,KAAK,WAAW,KAAK,SAAS;CAChC;;CAGA,gBAAgB,WAAiE;EAC/E,KAAK,WAAW,KAAK;GACnB,MAAM;GACN,UAAU,CAAC;GACX,GAAG;EACL,CAAC;CACH;;CAGA,oBAAoB,QAAsC;EACxD,KAAK,YAAY,KAAK,MAAM;CAC9B;;;;;;CAOA,eAAe,OAAe,QAAgB,QAAsC;EAClF,IAAI,OAAO,SAAS,QAAQ,OAAO,MAAM,SAAS,IAAI,GAAG;GAEvD,MAAM,SAAS;IACb,MAAM;IACN;IACA,QAAQ,OAAO;IACf,QAAQ,OAAO;IACf,MAAM,EAAE,MAAM,UAAU;GAC1B;GACA,MAAM,WAAW;IACf,MAAM;IACN;IACA,QAAQ,OAAO;IACf,QAAQ,OAAO;IACf,MAAM;KACJ,MAAM;KAEN,OAAO,OAAO,MAAM,QAAQ,MAAM,MAAM,IAAI,CAAC,CAAC,KAAK,MAAM,OAAO,QAAQ,CAAC,CAAC;IAC5E;GACF;GAEA,KAAK,YAAY,KAAK;IAAE,MAAM;IAAO,IAAI;IAAM,YAAY,CAAC,QAAQ,QAAQ;GAAE,CAAC;EACjF,OAAO;GACL,MAAM,OAAO;IACX,MAAM;IACN;IACA,QAAQ,OAAO;IACf,QAAQ,OAAO;IAEf,MAAM,QAAQ,QAAQ,MAAM;GAC9B;GACA,KAAK,WAAW,KAAK,IAAI;EAC3B;CACF;;CAGA,qBAAyD;EACvD,MAAM,EAAE,aAAa,eAAe;EACpC,MAAM,YAAyC,CAAC,GAAG,UAAU;EAC7D,IAAI,UAAU,WAAW,KAAK,YAAY,WAAW,GAEnD,OAAO,YAAY;OACd,IAAI,YAAY,WAAW,KAAK,YAAY,EAAE,CAAC,OAAO,OAE3D,OAAO;GAAE,MAAM;GAAO,IAAI;GAAO,YAAY,CAAC,GAAG,WAAW,GAAG,YAAY,EAAE,CAAC,UAAU;EAAE;OACrF,IAAI,UAAU,SAAS,KAAK,YAAY,SAAS,GAEtD,OAAO;GAAE,MAAM;GAAO,IAAI;GAAO,YAAY,CAAC,GAAG,WAAW,GAAG,WAAW;EAAE;CAGhF;AACF;;AAGA,SAAS,gBAAgB,YAAkE;CAEzF,MAAM,CAAC,IAAI,eACT,SAAS,cAAc,WAAW,MAC9B,CAAC,OAAgB,WAAW,GAAG,IAC/B,QAAQ,cAAc,WAAW,KAC/B,CAAC,MAAe,WAAW,EAAE,IAC7B,KAAK,sBAAsB,YAAY;CAE/C,MAAM,aAAa,YAAY,KAAK,QAAS,QAAQ,SAAS,OAAO,QAAQ,OAAO,gBAAgB,GAAG,IAAI,GAAI;CAC/G,MAAM,CAAC,MAAM,SAAS,UAAU,aAAa,SAAS,SAAS,KAAA,KAAa,SAAS,aAAa;CAClG,IAAK,KAAK,SAAS,KAAK,WAAW,qBAAqB,SAAU,MAAM,WAAW,GACjF;CAEF,OAAO;EAAE,MAAM;EAAO;EAAI,YAAY,MAAM,OAAO,SAAS;CAAE;AAChE"}
@@ -1,13 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ require("./EntityMetadata.cjs");
3
+ require("./QueryParser.cjs");
2
4
  //#region src/DeferredAlias.ts
3
- /** An undefined predicate is pruned by either query parser. */
4
- const skipCondition = {
5
- kind: "column",
6
- alias: "skip",
7
- column: "skip",
8
- dbType: "skip",
9
- cond: void 0
10
- };
11
5
  const deferredAliasSym = Symbol("joist.deferredAliasCondition");
12
6
  /** Detects conditions that carry a per-parse alias resolver. */
13
7
  function isDeferredAliasCondition(cond) {
@@ -27,7 +21,6 @@ function withDeferredAlias(cond, resolve) {
27
21
  //#endregion
28
22
  exports.deferredAliasSym = deferredAliasSym;
29
23
  exports.isDeferredAliasCondition = isDeferredAliasCondition;
30
- exports.skipCondition = skipCondition;
31
24
  exports.withDeferredAlias = withDeferredAlias;
32
25
 
33
26
  //# sourceMappingURL=DeferredAlias.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"DeferredAlias.cjs","names":[],"sources":["../src/DeferredAlias.ts"],"sourcesContent":["// Erased imports keep domain predicates and SQL expressions independent at module load time.\nimport type { EntityMetadata } from \"./EntityMetadata.ts\";\nimport type { ColumnCondition, RawCondition } from \"./QueryParser.ts\";\n\n/** An undefined predicate is pruned by either query parser. */\nexport const skipCondition: ColumnCondition = {\n kind: \"column\",\n alias: \"skip\",\n column: \"skip\",\n dbType: \"skip\",\n cond: undefined as any,\n};\n\nexport const deferredAliasSym: unique symbol = Symbol(\"joist.deferredAliasCondition\");\n\n/** Resolves a domain alias or physical table handle to this parse's binding. */\nexport type AliasResolver = (handle: { meta: EntityMetadata; tableName: string }) => {\n meta: EntityMetadata;\n alias: string;\n};\n\n/** A condition whose SQL aliases are resolved afresh for each occurrence in a query. */\nexport interface DeferredAliasCondition<C = ColumnCondition | RawCondition> {\n [deferredAliasSym]: (resolve: AliasResolver) => C;\n}\n\n/** Detects conditions that carry a per-parse alias resolver. */\nexport function isDeferredAliasCondition<C>(cond: C): cond is C & DeferredAliasCondition<C> {\n return typeof cond === \"object\" && cond !== null && deferredAliasSym in cond;\n}\n\n/** Tags a condition without changing its enumerable shape; resolution only mutates a fresh copy. */\nexport function withDeferredAlias<C extends object>(\n cond: C,\n resolve: (r: AliasResolver, copy: C) => void,\n): C & DeferredAliasCondition<C> {\n return Object.defineProperty(cond, deferredAliasSym, {\n value: (r: AliasResolver) => {\n const copy = { ...cond };\n resolve(r, copy);\n return copy;\n },\n enumerable: false,\n }) as C & DeferredAliasCondition<C>;\n}\n"],"mappings":";;;AAKA,MAAa,gBAAiC;CAC5C,MAAM;CACN,OAAO;CACP,QAAQ;CACR,QAAQ;CACR,MAAM,KAAA;AACR;AAEA,MAAa,mBAAkC,OAAO,8BAA8B;;AAcpF,SAAgB,yBAA4B,MAAgD;CAC1F,OAAO,OAAO,SAAS,YAAY,SAAS,QAAQ,oBAAoB;AAC1E;;AAGA,SAAgB,kBACd,MACA,SAC+B;CAC/B,OAAO,OAAO,eAAe,MAAM,kBAAkB;EACnD,QAAQ,MAAqB;GAC3B,MAAM,OAAO,EAAE,GAAG,KAAK;GACvB,QAAQ,GAAG,IAAI;GACf,OAAO;EACT;EACA,YAAY;CACd,CAAC;AACH"}
1
+ {"version":3,"file":"DeferredAlias.cjs","names":[],"sources":["../src/DeferredAlias.ts"],"sourcesContent":["// Erased imports keep domain predicates independent of the query parser at module load time.\nimport { type EntityMetadata } from \"./EntityMetadata.ts\";\nimport { type ColumnCondition, type RawCondition } from \"./QueryParser.ts\";\n\nexport const deferredAliasSym: unique symbol = Symbol(\"joist.deferredAliasCondition\");\n\n/** Resolves a domain alias to this em.find parse's binding. */\nexport type AliasResolver = (handle: { meta: EntityMetadata; tableName: string }) => {\n meta: EntityMetadata;\n alias: string;\n};\n\n/** A domain condition whose SQL aliases are resolved afresh for each occurrence in em.find. */\nexport interface DeferredAliasCondition<C = ColumnCondition | RawCondition> {\n [deferredAliasSym]: (resolve: AliasResolver) => C;\n}\n\n/** Detects conditions that carry a per-parse alias resolver. */\nexport function isDeferredAliasCondition<C>(cond: C): cond is C & DeferredAliasCondition<C> {\n return typeof cond === \"object\" && cond !== null && deferredAliasSym in cond;\n}\n\n/** Tags a condition without changing its enumerable shape; resolution only mutates a fresh copy. */\nexport function withDeferredAlias<C extends object>(\n cond: C,\n resolve: (r: AliasResolver, copy: C) => void,\n): C & DeferredAliasCondition<C> {\n return Object.defineProperty(cond, deferredAliasSym, {\n value: (r: AliasResolver) => {\n const copy = { ...cond };\n resolve(r, copy);\n return copy;\n },\n enumerable: false,\n }) as C & DeferredAliasCondition<C>;\n}\n"],"mappings":";;;;AAIA,MAAa,mBAAkC,OAAO,8BAA8B;;AAcpF,SAAgB,yBAA4B,MAAgD;CAC1F,OAAO,OAAO,SAAS,YAAY,SAAS,QAAQ,oBAAoB;AAC1E;;AAGA,SAAgB,kBACd,MACA,SAC+B;CAC/B,OAAO,OAAO,eAAe,MAAM,kBAAkB;EACnD,QAAQ,MAAqB;GAC3B,MAAM,OAAO,EAAE,GAAG,KAAK;GACvB,QAAQ,GAAG,IAAI;GACf,OAAO;EACT;EACA,YAAY;CACd,CAAC;AACH"}
@@ -1,10 +1,8 @@
1
1
  import { EntityMetadata } from "./EntityMetadata.cjs";
2
2
  import { ColumnCondition, RawCondition } from "./QueryParser.cjs";
3
3
  //#region src/DeferredAlias.d.ts
4
- /** An undefined predicate is pruned by either query parser. */
5
- declare const skipCondition: ColumnCondition;
6
4
  declare const deferredAliasSym: unique symbol;
7
- /** Resolves a domain alias or physical table handle to this parse's binding. */
5
+ /** Resolves a domain alias to this em.find parse's binding. */
8
6
  type AliasResolver = (handle: {
9
7
  meta: EntityMetadata;
10
8
  tableName: string;
@@ -12,7 +10,7 @@ type AliasResolver = (handle: {
12
10
  meta: EntityMetadata;
13
11
  alias: string;
14
12
  };
15
- /** A condition whose SQL aliases are resolved afresh for each occurrence in a query. */
13
+ /** A domain condition whose SQL aliases are resolved afresh for each occurrence in em.find. */
16
14
  interface DeferredAliasCondition<C = ColumnCondition | RawCondition> {
17
15
  [deferredAliasSym]: (resolve: AliasResolver) => C;
18
16
  }
@@ -21,5 +19,5 @@ declare function isDeferredAliasCondition<C>(cond: C): cond is C & DeferredAlias
21
19
  /** Tags a condition without changing its enumerable shape; resolution only mutates a fresh copy. */
22
20
  declare function withDeferredAlias<C extends object>(cond: C, resolve: (r: AliasResolver, copy: C) => void): C & DeferredAliasCondition<C>;
23
21
  //#endregion
24
- export { AliasResolver, DeferredAliasCondition, deferredAliasSym, isDeferredAliasCondition, skipCondition, withDeferredAlias };
22
+ export { AliasResolver, DeferredAliasCondition, deferredAliasSym, isDeferredAliasCondition, withDeferredAlias };
25
23
  //# sourceMappingURL=DeferredAlias.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"DeferredAlias.d.cts","names":[],"sources":["../src/DeferredAlias.ts"],"mappings":";;;;cAKa,eAAe;cAQf;;KAGD,iBAAiB;EAAU,MAAM;EAAgB;;EAC3D,MAAM;EACN;;;UAIe,uBAAuB,IAAI,kBAAkB;GAC3D,oBAAoB,SAAS,kBAAkB;;;iBAIlC,yBAAyB,GAAG,MAAM,IAAI,QAAQ,IAAI,uBAAuB;;iBAKzE,kBAAkB,kBAChC,MAAM,GACN,UAAU,GAAG,eAAe,MAAM,aACjC,IAAI,uBAAuB"}
1
+ {"version":3,"file":"DeferredAlias.d.cts","names":[],"sources":["../src/DeferredAlias.ts"],"mappings":";;;cAIa;;KAGD,iBAAiB;EAAU,MAAM;EAAgB;;EAC3D,MAAM;EACN;;;UAIe,uBAAuB,IAAI,kBAAkB;GAC3D,oBAAoB,SAAS,kBAAkB;;;iBAIlC,yBAAyB,GAAG,MAAM,IAAI,QAAQ,IAAI,uBAAuB;;iBAKzE,kBAAkB,kBAChC,MAAM,GACN,UAAU,GAAG,eAAe,MAAM,aACjC,IAAI,uBAAuB"}