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

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.
@@ -1 +1 @@
1
- {"version":3,"file":"Tables.js","names":[],"sources":["../src/Tables.ts"],"sourcesContent":["import { groupBy } from \"joist-utils\";\n\n// Load-order only: without this, the built cjs/esm module graph evaluates relations/* before their\n// base classes exist (\"Class extends value undefined\"); keep it even though no symbol is imported.\nimport \"./configure.ts\";\nimport { getMaybeCtiAlias } from \"./Aliases.ts\";\nimport { buildValueCondition } from \"./drivers/buildUtils.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type IdOf, type MaybeAbstractEntityConstructor, type TaggedId } from \"./EntityManager.ts\";\nimport {\n type EntityMetadata,\n type Field,\n type LargeOneToManyField,\n type ManyToManyField,\n type OneToManyField,\n type OneToOneField,\n type PolymorphicField,\n type PolymorphicFieldComponent,\n getBaseAndSelfMetas,\n getMetadata,\n} from \"./EntityMetadata.ts\";\nimport {\n BaseExpr,\n type Expr,\n type ExprContext,\n type ExprLike,\n type ExprOutputType,\n type InnerJoin,\n type LeftJoin,\n type SqlFragment,\n asNode,\n canonicalDbType,\n deferredCondition,\n isExpr,\n} from \"./Expr.ts\";\nimport { type ExpressionCondition, getConstructorFromTaggedId, maybeResolveReferenceToId } from \"./index.ts\";\nimport { toIdOf } from \"./keys.ts\";\nimport { kqDot } from \"./keywords.ts\";\nimport { type ParsedValueFilter, makeLike, mapToDb } from \"./QueryParser.ts\";\nimport { type Column, KeySerde, PolymorphicKeySerde } from \"./serde.ts\";\nimport { skipCondition } from \"./skipCondition.ts\";\nimport { type ColumnsOf, type FieldsOf, type RootTypeNameOf } from \"./typeMap.ts\";\nimport { fail } from \"./utils.ts\";\n\n/** Creates physical column expressions and relationship joins for `T`. */\nexport function table<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): Table<T>;\n/**\n * Creates a table with an explicit type-level name, i.e. `table(Author, \"m\")` for a self-join.\n *\n * The name is the table's source key in `em.query`: two bare `table(Author)`s share the key `\"Author\"`,\n * so a left-joined mentor would also mark the mentee's columns nullable; a named alias has its own key.\n */\nexport function table<T extends Entity, Name extends string>(\n cstr: MaybeAbstractEntityConstructor<T>,\n name: Name,\n): Table<T, Name>;\nexport function table<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>, _name?: string): Table<T, any> {\n // The name only exists at the type level; the SQL alias is still assigned by the query parser\n return newTableProxy(cstr);\n}\n\n/** Creates multiple physical table handles. */\nexport function tables<T extends readonly MaybeAbstractEntityConstructor<any>[]>(\n ...type: T\n): { [P in keyof T]: T[P] extends MaybeAbstractEntityConstructor<infer E extends Entity> ? Table<E> : never } {\n return type.map((t) => newTableProxy(t)) as any;\n}\n\n/**\n * The runtime management interface plus phantom type information for `em.query`.\n *\n * `__entity` lets `QueryRow` recover `T` for entity mode (you cannot `infer T` back out of a mapped\n * type), and `__name` is the table's source key (see `Expr`).\n */\nexport interface TableBrand<T, Name extends string> extends TableMgmt {\n readonly __entity: T;\n readonly __name: Name;\n}\n\n/**\n * A physical table for `T`: one expression per SQL column, with relationship names as join factories.\n * Selecting the table itself retains entity hydration; selecting columns returns decoded SQL values.\n *\n * Unlike an Alias, a Table is an explicit SQL source, not a place to bind in an em.find relationship\n * tree. I.e. with `a = table(Author)`, `{ from: a }` registers that handle in the query's scope.\n * Its columns already know their physical column and codec, but their SQL name still depends on the\n * query: the same Author handle might be `a` in one query and `a1` in a nested query.\n *\n * Each predicate occurrence renders through ExprContext.aliasFor using the current scope (or an\n * enclosing scope for a correlation). Rendering returns SQL, ordered bindings, and source references\n * together. A comparison records both sides' references; templates and subqueries carry their\n * references too. Join pruning follows these references and join dependencies, rather than guessing\n * which tables a SQL string mentions. It also accounts for select/order/group expressions and keep.\n *\n * I.e. if a joined Author is used only by `a.first_name.eq(name)`, supplying undefined removes that\n * predicate and lets the unused join prune. Both APIs share this undefined-condition pruning rule;\n * they differ in how they get the references: Alias resolves domain conditions against a relationship\n * tree, while Table renders SQL expressions against explicit sources. Neither caches SQL names on\n * the reusable handle or predicate, so one parse cannot overwrite another parse's bindings.\n *\n * `Name` is the table's type-level source key, defaulting to the entity's root type name (see\n * `RootTypeNameOf`); `table(Author, \"m\")` gives a self-join table its own key.\n */\nexport type Table<T extends Entity, Name extends string = RootTypeNameOf<T>> = {\n readonly [tableMgmt]: TableBrand<T, Name>;\n} & {\n [P in keyof ColumnsOf<T>]: P extends \"id\"\n ? EntityColumn<T, never, Name>\n : ColumnsOf<T>[P] extends { kind: \"primitive\" | \"enum\"; type: infer V; nullable: infer N }\n ? PrimitiveColumn<V, N extends true ? null : never, Name>\n : ColumnsOf<T>[P] extends { kind: \"m2o\"; type: infer U extends Entity; nullable: infer N }\n ? ReferenceColumn<U, N extends true ? null : never, Name>\n : never;\n} & {\n [\n P in keyof FieldsOf<T> as P extends keyof ColumnsOf<T>\n ? never\n : FieldsOf<T>[P] extends { kind: \"m2o\" | \"poly\" | \"o2m\" | \"lo2m\" | \"m2m\" | \"o2o\" }\n ? P\n : never\n ]: FieldsOf<T>[P] extends { kind: \"m2o\"; type: infer U extends Entity; nullable: infer N }\n ? ReferenceJoin<U, N extends undefined ? null : never>\n : FieldsOf<T>[P] extends { kind: \"poly\"; type: infer U extends Entity; nullable: infer N }\n ? PolyReference<U, N extends undefined ? null : never>\n : FieldsOf<T>[P] extends { kind: \"o2m\" | \"lo2m\" | \"m2m\" | \"o2o\"; type: infer U extends Entity }\n ? CollectionJoin<U>\n : never;\n};\n\n/** A relationship join factory, without a selectable FK expression. */\nexport interface ReferenceJoin<U extends Entity, N extends null | never> {\n as<A extends TableFor<U>>(other: A): [N] extends [never] ? InnerJoin<A> : LeftJoin<A>;\n inner<A extends TableFor<U>>(other: A): InnerJoin<A>;\n left<A extends TableFor<U>>(other: A): LeftJoin<A>;\n}\n\n/** Any table whose entity is (a subtype of) `U`, i.e. what a relation join factory accepts. */\nexport type TableFor<U> = { readonly [tableMgmt]: TableBrand<U, string> };\n\n/**\n * A collection relation (o2m/o2o/m2m) as a join factory: `a.books.as(b)` returns the same\n * `{ left: b, on: ... }` entry the expanded form writes, with the FK condition built from metadata, so\n * join-list inference, nullability, scope checking, and pruning are unchanged and both forms mix freely.\n *\n * `as` binds the joined alias, the same way em.find's `{ books: { as: b } }` does. The default is LEFT\n * (a collection may be empty, and a LEFT join never filters rows, so pruning it is always safe);\n * `.inner(b)` opts into filtering. An m2m entry carries a hidden second join through the join table,\n * which the parser expands; the pair prunes together.\n */\nexport interface CollectionJoin<U extends Entity> {\n as<A extends TableFor<U>>(other: A): LeftJoin<A>;\n inner<A extends TableFor<U>>(other: A): InnerJoin<A>;\n left<A extends TableFor<U>>(other: A): LeftJoin<A>;\n}\n\n/**\n * A physical FK column expression (`b.author_id` selects/compares the FK) plus a join factory\n * (`b.author_id.as(a)` joins). The default join kind follows physical column nullability:\n * a NOT NULL FK is INNER, a nullable one is LEFT, and the row type reflects it.\n */\nexport interface ReferenceColumn<U extends Entity, N extends null | never, Src extends string>\n extends EntityColumn<U, N, Src>, ReferenceJoin<U, N> {}\n\n/**\n * A polymorphic reference: condition methods (each resolving the component column from the value), plus\n * a join factory that picks the component from the argument's entity, i.e. `c.parent.as(a)` joins\n * through `parent_author_id`, like an explicit join with `on: c.parent.eq(a.id)`.\n */\nexport interface PolyReference<U extends Entity, N extends null | never> extends ReferenceJoin<U, N> {\n eq(value: U | TaggedId | ExprLike<IdOf<U> | null> | null | undefined): ExpressionCondition;\n ne(value: U | TaggedId | ExprLike<IdOf<U> | null> | null | undefined): ExpressionCondition;\n in(values: Array<U | TaggedId> | ExprLike<IdOf<U> | null> | undefined): ExpressionCondition;\n}\n\nexport interface PrimitiveColumn<V, N extends null | never, Src extends string = string> extends Expr<V | N, Src> {\n eq(value: V | ExprLike<V | N> | N | undefined): ExpressionCondition;\n ne(value: V | ExprLike<V | N> | N | undefined): ExpressionCondition;\n in(values: readonly (V | null)[] | ExprLike<V | null> | undefined): ExpressionCondition;\n nin(values: readonly (V | null)[] | ExprLike<V | null> | undefined): ExpressionCondition;\n gt(value: V | ExprLike<V | N> | undefined): ExpressionCondition;\n gte(value: V | ExprLike<V | N> | undefined): ExpressionCondition;\n lt(value: V | ExprLike<V | N> | undefined): ExpressionCondition;\n lte(value: V | ExprLike<V | N> | 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 // need to move to ArrayColumn\n // ...added the `string` to support jsonb contains like `WHERE profile @> '{\"age\": 25}'`\n // Ideally this would go in a JsonbColumn\n contains(value: string | V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition;\n ncontains(value: string | V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition;\n overlaps(value: V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition;\n noverlaps(value: V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition;\n\n /**\n * Adds a JSON path existence condition, using the `@?` operator.\n *\n * Any values should be embedded directly within the `jsonPath`, because postgres does not\n * support parameterized JSON path expressions. The entire `jsonPath` is treated as a parameter,\n * so this is safe from SQL injection.\n */\n pathExists(jsonPath: string | undefined): ExpressionCondition;\n\n /**\n * Adds a JSON path predicate condition, using the `@@` operator.\n *\n * Any values should be embedded directly within the `jsonPath`, because postgres does not\n * support parameterized JSON path expressions. The entire `jsonPath` is treated as a parameter,\n * so this is safe from SQL injection.\n */\n pathIsTrue(jsonPath: string | undefined): ExpressionCondition;\n\n /**\n * Add `exp` to the query, which should include the operator & expression and any\n * bound parameters (but not include the column name).\n *\n * We use knex-style placeholders, i.e. `?` and `\\\\?` to escape question marks, i.e.\n *\n * ```ts\n * a.address.raw(\"@\\\\? ?\", ['$.street ? (@ == \"rr2\")'])`\n * ```\n */\n raw(exp: string, bindings: readonly any[] | undefined): ExpressionCondition;\n}\n\nexport interface EntityColumn<T, N extends null | never = never, Src extends string = string> extends Expr<\n IdOf<T> | N,\n Src\n> {\n eq(value: T | IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n ne(value: T | IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n // Adding `| null` for GraphQL support\n in(value: readonly (T | IdOf<T> | null)[] | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n nin(value: readonly (T | IdOf<T> | null)[] | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n gt(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n gte(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n lt(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n lte(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n raw(exp: string, bindings: readonly any[] | undefined): ExpressionCondition;\n}\n\nexport const tableMgmt = Symbol(\"tableMgmt\");\n\nexport function getTableMgmt(table: TableFor<unknown>): TableMgmt {\n return table[tableMgmt];\n}\n\n/** The identity SQL queries bind a table by, plus its original entity metadata. */\nexport interface TableMgmt {\n tableName: string;\n /**\n * The metadata this table was created with, i.e. `table(TaskNew)` keeps `taskNewMeta`.\n *\n * It cannot be re-derived from `tableName`: STI subtypes share their base's table (`Task`, `TaskNew`,\n * and `TaskOld` are all `tasks`), so a `getMetadataForTable(\"tasks\")` lookup can only return the base\n * `Task`, and the alias would lose its subtype identity (its discriminator filter and its constructor\n * for entity-mode hydration).\n */\n meta: EntityMetadata;\n}\n\n/** Returns the metadata for the entity that `table` is bound to. */\nexport function getTableMetadata<T extends Entity>(table: TableFor<T>): EntityMetadata<T> {\n const mgmt = table[tableMgmt];\n return mgmt.meta as EntityMetadata<T>;\n}\n\nexport function newTableProxy<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): Table<T> {\n const meta = getMetadata(cstr);\n // The identity SQL queries bind to a source, retaining STI subtype metadata.\n const mgmt: TableMgmt = { tableName: meta.tableName, meta };\n const proxy: any = new Proxy(cstr, {\n /** Create a physical column expression or a relation join factory. */\n get(_, key: PropertyKey): any {\n if (key === tableMgmt) {\n return mgmt;\n }\n if (typeof key !== \"string\") return undefined;\n const descriptor = Object.hasOwn(meta.columns, key) ? meta.columns[key] : undefined;\n if (descriptor) {\n const field = meta.allFields[descriptor.fieldName] ?? fail(`No field ${descriptor.fieldName} on ${cstr.name}`);\n const column =\n field.serde?.columns.find((c) => c.columnName === key) ?? fail(`No column ${key} on ${cstr.name}`);\n return field.kind === \"m2o\" || field.kind === \"poly\"\n ? new EntityColumnImpl(meta, field, column, mgmt)\n : new PrimitiveColumnImpl(meta, field, column, mgmt);\n }\n const field = meta.allFields[key as string] ?? fail(`No field ${String(key)} on ${cstr.name}`);\n switch (field.kind) {\n case \"m2o\":\n return new ReferenceJoinImpl(new EntityColumnImpl(meta, field, field.serde!.columns[0], mgmt));\n case \"poly\":\n return new PolyReferenceImpl(meta, mgmt, field);\n case \"o2m\":\n case \"o2o\":\n case \"lo2m\":\n return new OneToManyJoinImpl(proxy, field);\n case \"m2m\":\n return new ManyToManyJoinImpl(proxy, field);\n default:\n throw new Error(`Unsupported table field kind ${field.kind}`);\n }\n },\n\n has(_, key) {\n return (\n key === tableMgmt ||\n (typeof key === \"string\" && (Object.hasOwn(meta.columns, key) || isRelation(meta.allFields[key])))\n );\n },\n });\n return proxy;\n}\n\nexport function isTable(obj: unknown): obj is Table<any, any> {\n // Oddly enough `typeof` will be a function b/c we are proxying the constructors\n return typeof obj === \"function\" && tableMgmt in obj;\n}\n\n/**\n * A physical table column implements `Expr`: it renders as `alias.\"column\"`, decodes result\n * values through the field's serde, and inherits aggregate methods from `BaseExpr`.\n */\nclass TableColumn extends BaseExpr {\n public constructor(\n readonly meta: EntityMetadata,\n readonly field: Field & { aliasSuffix: string },\n readonly column: Column,\n readonly mgmt: TableMgmt,\n ) {\n super();\n }\n\n /** Author.id, Book.author_id, and Comment.parent_author_id use the same Author ID domain. */\n get outputType(): ExprOutputType | undefined {\n const idMeta = this.idMetadata;\n // Built-in poly components are plain columns, not KeySerde instances, but share its ID codec.\n if (idMeta && this.field.serde?.constructor === PolymorphicKeySerde) {\n return {\n dbType: canonicalDbType(this.column.dbType),\n domain: `key:${idMeta.tagName}`,\n idMeta,\n arrayElementSafe: true,\n };\n }\n const outputType = this.column.outputType;\n if (!outputType || !(this.column instanceof KeySerde)) return outputType;\n return idMeta ? { ...outputType, idMeta } : undefined;\n }\n\n get sqlNullable(): boolean | undefined {\n // Entity requiredness differs from physical NOT NULL for derived and STI fields.\n // A required poly still has nullable component FKs: only one target is set on each row.\n return this.field.kind === \"poly\" ? true : this.column.sqlNullable;\n }\n\n get sqlSource(): object {\n return this.mgmt;\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const alias = ctx.aliasFor(this.mgmt);\n const ctiAlias = getMaybeCtiAlias(this.meta, this.field, this.meta, alias);\n return { sql: kqDot(ctiAlias, this.column.columnName), bindings: [], refs: [alias] };\n }\n\n /** Decodes result-set values with public PK/FK ids, while hydration keeps internal tagged ids. */\n decode(value: unknown): unknown {\n if (value === null || value === undefined) return value;\n if (this.column instanceof KeySerde || this.field.serde instanceof PolymorphicKeySerde) {\n const idMeta = this.idMetadata;\n if (idMeta) return toIdOf(idMeta, this.column.mapFromDb(value) as TaggedId | undefined);\n }\n return this.column.mapFromDb(value);\n }\n\n encode(value: unknown): unknown {\n return this.column.mapToDb(value);\n }\n\n /** Identifies the ID domain of a primary key, FK, or physical polymorphic component. */\n get idMetadata(): EntityMetadata | undefined {\n return this.field.kind === \"primaryKey\"\n ? this.meta\n : this.field.kind === \"m2o\"\n ? this.field.otherMetadata()\n : this.field.kind === \"poly\"\n ? this.field.components.find((c) => c.columnName === this.column.columnName)?.otherMetadata()\n : undefined;\n }\n\n /** Encodes literals when the condition is created and renders with each query's aliases. */\n addCondition(value: ParsedValueFilter<unknown>): ExpressionCondition {\n const encoded = mapToDb(this.column, value);\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n const [sql, bindings] = buildValueCondition(left.sql, encoded);\n return { sql, bindings: [...left.bindings, ...bindings], refs: left.refs };\n });\n }\n\n /** Renders raw operators against the same quoted column SQL as other expressions. */\n protected addRawCondition(exp: string, bindings: readonly any[]): ExpressionCondition {\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return { sql: `${left.sql} ${exp}`, bindings: [...left.bindings, ...bindings], refs: left.refs };\n });\n }\n\n /** Uses column filter conversions for literals and shared comparisons for expressions and null equality. */\n protected compare(op: string, value: unknown): ExpressionCondition {\n if (value === undefined || isExpr(value) || (value === null && (op === \"=\" || op === \"!=\"))) {\n return super.compare(op, value);\n }\n // Primitive relational comparisons historically bind null through mapToDb.\n const kind = ({ \"=\": \"eq\", \"!=\": \"ne\", \">\": \"gt\", \">=\": \"gte\", \"<\": \"lt\", \"<=\": \"lte\" } as const)[op];\n if (!kind) return fail(`Invalid operator ${op}`);\n return this.addCondition({ kind, value });\n }\n\n /**\n * Compares this column to another expression.\n *\n * Table columns, aggregates, subquery columns, and `sql` templates use the expression context\n * to render their complete SQL.\n * Negated array operators wrap the complete comparison in NOT.\n */\n protected compareToExpr(op: string, value: ExprLike<any>, negate = false): ExpressionCondition {\n if (negate) {\n return deferredCondition((ctx) => {\n const comparison = ctx.conditionToSql(this.compareToExpr(op, value))!;\n return { ...comparison, sql: `NOT (${comparison.sql})` };\n });\n }\n return super.compare(op, value);\n }\n}\n\nclass PrimitiveColumnImpl<V, N extends null | never> extends TableColumn implements PrimitiveColumn<V, N> {\n between(v1: V | undefined, v2: V | undefined): ExpressionCondition {\n if (v1 === undefined || v2 === undefined) return skipCondition;\n return this.addCondition({ kind: \"between\", value: [v1, v2] });\n }\n\n like(value: V | undefined): ExpressionCondition {\n if (value === undefined) return skipCondition;\n return this.addCondition({ kind: \"like\", value });\n }\n\n ilike(value: V | undefined): ExpressionCondition {\n if (value === undefined) return skipCondition;\n return this.addCondition({ kind: \"ilike\", value });\n }\n\n search(value: V | undefined): ExpressionCondition {\n // Check !value so that empty strings are pruned\n if (!value) return skipCondition;\n return this.addCondition({ kind: \"ilike\", value: makeLike(value) });\n }\n\n in(values: readonly (V | null)[] | ExprLike<V | null> | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (isExpr(values)) return this.inList(\"IN\", values);\n if (values.includes(null)) {\n const isNull = this.addCondition({ kind: \"is-null\" });\n const hasValue = this.addCondition({ kind: \"in\", value: values.filter((v) => v !== null) });\n return { or: [isNull, hasValue] };\n } else {\n return this.addCondition({ kind: \"in\", value: values as V[] });\n }\n }\n\n nin(values: readonly (V | null)[] | ExprLike<V | null> | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (isExpr(values)) return this.inList(\"NOT IN\", values);\n return this.addCondition({ kind: \"nin\", value: values.filter((v) => v !== null) as V[] });\n }\n\n // V will already be an array\n contains(v1: string | V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition {\n if (v1 === undefined) return skipCondition;\n if (isExpr(v1)) return this.compareToExpr(\"@>\", v1);\n return this.addCondition({ kind: \"contains\", value: v1 as any });\n }\n\n // V will already be an array\n ncontains(v1: string | V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition {\n if (v1 === undefined) return skipCondition;\n if (isExpr(v1)) return this.compareToExpr(\"@>\", v1, true);\n return this.addCondition({ kind: \"ncontains\", value: v1 as any });\n }\n\n // V will already be an array\n overlaps(v1: V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition {\n if (v1 === undefined) return skipCondition;\n if (isExpr(v1)) return this.compareToExpr(\"&&\", v1);\n return this.addCondition({ kind: \"overlaps\", value: v1 as any });\n }\n\n noverlaps(v1: V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition {\n if (v1 === undefined) return skipCondition;\n if (isExpr(v1)) return this.compareToExpr(\"&&\", v1, true);\n return this.addCondition({ kind: \"noverlaps\", value: v1 as any });\n }\n\n pathExists(jsonPath: string | undefined): ExpressionCondition {\n if (jsonPath === undefined) return skipCondition;\n return this.addCondition({ kind: \"jsonPathExists\", value: jsonPath });\n }\n\n pathIsTrue(jsonPath: string | undefined): ExpressionCondition {\n if (jsonPath === undefined) return skipCondition;\n return this.addCondition({ kind: \"jsonPathPredicate\", value: jsonPath });\n }\n\n raw(exp: string, bindings: readonly any[] | undefined): ExpressionCondition {\n if (bindings === undefined) return skipCondition;\n return this.addRawCondition(exp, bindings);\n }\n}\n\nclass EntityColumnImpl<T> extends TableColumn implements EntityColumn<T> {\n in(values: readonly (T | IdOf<T> | null)[] | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n if (values === undefined) {\n return skipCondition;\n } else if (values === null) {\n throw new Error(\"Unsupported\");\n } else if (isExpr(values)) {\n return this.inList(\"IN\", values);\n } else if (values.includes(null)) {\n // Like `PrimitiveColumn.in`, split `[a1, null]` into `IS NULL OR IN (...)`\n const isNull = this.addCondition({ kind: \"is-null\" });\n const hasValue = this.addCondition({ kind: \"in\", value: values.filter((v) => v !== null) as any });\n return { or: [isNull, hasValue] };\n } else {\n return this.addCondition({ kind: \"in\", value: values as any });\n }\n }\n\n nin(values: readonly (T | IdOf<T> | null)[] | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n if (values === undefined) {\n return skipCondition;\n } else if (values === null) {\n throw new Error(\"Unsupported\");\n } else if (isExpr(values)) {\n return this.inList(\"NOT IN\", values);\n } else {\n return this.addCondition({ kind: \"nin\", value: values.filter((v) => v !== null) as any });\n }\n }\n\n gt(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n return this.compareId(\">\", \"gt\", value);\n }\n\n gte(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n return this.compareId(\">=\", \"gte\", value);\n }\n\n lt(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n return this.compareId(\"<\", \"lt\", value);\n }\n\n lte(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n return this.compareId(\"<=\", \"lte\", value);\n }\n\n raw(exp: string, bindings: readonly any[] | undefined): ExpressionCondition {\n if (bindings === undefined) return skipCondition;\n return this.addRawCondition(exp, bindings);\n }\n\n /** Joins `other` via this FK, INNER for a required reference and LEFT for a nullable one. */\n as(other: object): object {\n return this.joinEntry(this.sqlNullable === false ? \"inner\" : \"left\", other);\n }\n\n inner(other: object): object {\n return this.joinEntry(\"inner\", other);\n }\n\n left(other: object): object {\n return this.joinEntry(\"left\", other);\n }\n\n private joinEntry(kind: JoinKind, other: object): object {\n return { [kind]: requireTable(other), on: this.eq(idColumnOf(other)) };\n }\n\n private compareId(op: string, kind: \"gt\" | \"gte\" | \"lt\" | \"lte\", value: unknown): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value === null) throw new Error(\"Unsupported\");\n if (isExpr(value)) return this.compareToExpr(op, value);\n return this.addCondition({ kind, value: value as any });\n }\n}\n\nclass PolyReferenceImpl<T extends Entity> {\n public constructor(\n private meta: EntityMetadata,\n private mgmt: TableMgmt,\n private field: PolymorphicField & { aliasSuffix: string },\n ) {}\n\n /** Compares to a tagged id, an entity, or another table's id column, which picks the component (`c.parent.eq(a.id)`). */\n eq(value: T | TaggedId | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n return this.addEqOrNe(\"eq\", value);\n }\n\n ne(value: T | TaggedId | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n return this.addEqOrNe(\"ne\", value);\n }\n\n // We required tagged ids for polys\n in(values: Array<T | TaggedId> | ExprLike<IdOf<T> | null> | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (isExpr(values)) return this.inSubquery(values);\n // Split up the ids by constructor\n const idsByConstructor = 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(idsByConstructor).map(([cstrName, ids]) => {\n const comp =\n this.field.components.find((p) => p.otherMetadata().cstr.name === cstrName) ??\n fail(`No component for ${cstrName}`);\n return this.componentColumn(comp).addCondition({ kind: \"in\", value: ids });\n }),\n };\n }\n\n /** Joins `other` via this poly's component for its entity, INNER when the poly is required. */\n as(other: object): object {\n return this.joinEntry(this.field.required ? \"inner\" : \"left\", other);\n }\n\n inner(other: object): object {\n return this.joinEntry(\"inner\", other);\n }\n\n left(other: object): object {\n return this.joinEntry(\"left\", other);\n }\n\n private joinEntry(kind: JoinKind, other: object): object {\n return { [kind]: requireTable(other), on: this.eq(idColumnOf(other) as any) };\n }\n\n /**\n * i.e. `c.parent.in(query({ from: a, ..., select: a.id }))`: like `eq` against a table column, the\n * subquery's agreed ID domain picks the component, i.e. authors pick `parent_author_id`.\n */\n private inSubquery(values: ExprLike<any>): ExpressionCondition {\n // Only actual subqueries expose this getter; importing query.ts would create a load-order cycle.\n const selected = asNode(values).subquerySelect;\n const outputType = selected?.outputType;\n let otherMeta = outputType?.idMeta;\n if (!otherMeta) {\n // Ordinary reads can select an unknown key serde. Compounds validate codecs before exposing a select.\n if (!outputType && selected instanceof TableColumn) {\n otherMeta = selected.idMetadata;\n }\n if (!otherMeta) {\n return fail(\n selected instanceof TableColumn\n ? `${this.field.fieldName} \\`in\\` needs an id or FK column, got ${selected.field.fieldName}`\n : `${this.field.fieldName} is polymorphic, so \\`in\\` needs a subquery selecting an id or FK column`,\n );\n }\n }\n const comp =\n this.field.components.find((p) => getBaseAndSelfMetas(otherMeta).includes(p.otherMetadata())) ??\n fail(`${this.field.fieldName} has no component for ${otherMeta.type}`);\n return this.componentColumn(comp).in(values);\n }\n\n private addEqOrNe(\n kind: \"eq\" | \"ne\",\n value: T | TaggedId | ExprLike<IdOf<T> | null> | null | undefined,\n ): ExpressionCondition {\n if (value === undefined) {\n return skipCondition;\n } else if (value instanceof TableColumn) {\n // Joining through the poly, i.e. `c.parent.eq(a.id)`: the other table column's ID domain picks the component\n const otherMeta = value.idMetadata ?? fail(`${this.field.fieldName} needs an id or FK column`);\n const comp =\n this.field.components.find((p) => getBaseAndSelfMetas(otherMeta).includes(p.otherMetadata())) ??\n fail(`${this.field.fieldName} has no component for ${otherMeta.type}`);\n return this.componentColumn(comp)[kind](value);\n } else if (isExpr(value)) {\n return fail(\n `${this.field.fieldName} is polymorphic, so it can only be compared to tagged ids or entity table columns`,\n );\n } else if (value === null) {\n // We can AND each of the components as many conditions\n const value = kind === \"eq\" ? ({ kind: \"is-null\" } as const) : ({ kind: \"not-null\" } as const);\n return {\n and: this.field.components.map((p) => this.componentColumn(p).addCondition(value)),\n };\n } else {\n // If we have a value, we can find the component\n const comp =\n this.field.components.find(\n (p) => p.otherMetadata().cstr === getConstructorFromTaggedId(maybeResolveReferenceToId(value) as string),\n ) || fail(`Could not find component for ${value}`);\n return this.componentColumn(comp)[kind](value);\n }\n }\n\n /** Returns the physical FK expression for one polymorphic target. */\n private componentColumn(comp: PolymorphicFieldComponent): EntityColumnImpl<T> {\n const column = this.field.serde.columns.find((c) => c.columnName === comp.columnName) ?? fail(\"Missing column\");\n return new EntityColumnImpl<T>(this.meta, this.field, column, this.mgmt);\n }\n}\n\n/**\n * Marks a sugar join entry whose target is a *collection* (o2m/m2m), which filter soft-deletes like\n * em.find's \"collections filter out soft-deletes, but m2o/o2o references still return them\"; see\n * `QueryParser.addSoftDeleteCondition`'s call site. Reference joins and explicit joins are unmarked.\n */\nexport const collectionJoin: unique symbol = Symbol(\"joist.collectionJoin\");\n\n/** Marks a sugar m2m join entry (`a.tags.as(t)`) with its hidden join-table join; `parseQuery` expands it. */\nexport const m2mJoinTable: unique symbol = Symbol(\"joist.m2mJoinTable\");\n\nexport interface M2mJoinTable {\n handle: JoinTableHandle;\n on: ExpressionCondition;\n}\n\n/** The runtime identity of an m2m join table in a query, i.e. `authors_to_tags`; it has no entity. */\nexport class JoinTableHandle {\n constructor(readonly joinTableName: string) {}\n}\n\ntype JoinKind = \"inner\" | \"left\";\n\n/**\n * The `as`/`inner`/`left` join factory for collection relations, i.e. `a.books.as(b)` joins with the\n * relation's default kind (LEFT: a collection may be empty) and `.inner`/`.left` override. m2o/poly\n * relations implement the same three methods on their join factories. Physical FKs such as\n * `b.author_id` are expressions that also expose a join factory.\n */\nabstract class CollectionJoinImpl {\n as(other: object): object {\n return this.joinEntry(\"left\", requireTable(other));\n }\n\n inner(other: object): object {\n return this.joinEntry(\"inner\", requireTable(other));\n }\n\n left(other: object): object {\n return this.joinEntry(\"left\", requireTable(other));\n }\n\n protected abstract joinEntry(kind: JoinKind, other: TableFor<Entity>): object;\n}\n\n/** An o2m/lo2m/o2o relation: the ON is the other side's FK (an m2o or a poly component) back to our id. */\nclass OneToManyJoinImpl extends CollectionJoinImpl {\n constructor(\n private proxy: any,\n private field: OneToManyField | LargeOneToManyField | OneToOneField,\n ) {\n super();\n }\n\n protected joinEntry(kind: JoinKind, other: TableFor<Entity>): object {\n const { field } = this;\n const otherMeta = getTableMetadata(other);\n const inverse = otherMeta.allFields[field.otherFieldName];\n const column =\n inverse.kind === \"poly\"\n ? (other as any)[field.otherFieldName]\n : (other as any)[inverse.serde!.columns[0].columnName];\n const on = column.eq(this.proxy.id);\n // Collections (o2m/lo2m) filter soft-deletes like em.find; o2o references resolve them\n const filtered = field.kind === \"o2m\" ? field.softDeletes !== \"include\" : field.kind === \"lo2m\";\n return { [kind]: other, on, [collectionJoin]: filtered };\n }\n}\n\n/**\n * An m2m relation, i.e. `a.tags.as(t)`.\n *\n * The entry's own ON is `t.id = att.tag_id`, and the hidden `[m2mJoinTable]` half is\n * `att.author_id = a.id`; only the target's ON references the join table, so reference pruning keeps\n * or drops the pair together. Both are deferred conditions: the join table has no entity metadata, so\n * its alias only exists once the parser registers it.\n */\nclass ManyToManyJoinImpl extends CollectionJoinImpl {\n constructor(\n private proxy: any,\n private field: ManyToManyField,\n ) {\n super();\n }\n\n protected joinEntry(kind: JoinKind, other: TableFor<Entity>): object {\n const { joinTableName, columnNames } = this.field;\n const [ourColumn, otherColumn] = columnNames;\n const jt = new JoinTableHandle(joinTableName);\n const ourId = idColumnOf(this.proxy);\n const otherId = idColumnOf(other);\n const jtOn = deferredCondition((ctx) => {\n const jtAlias = ctx.aliasFor(jt);\n const id = ourId.toSql(ctx);\n return { sql: `${kqDot(jtAlias, ourColumn)} = ${id.sql}`, bindings: id.bindings, refs: id.refs };\n });\n const on = deferredCondition((ctx) => {\n const jtAlias = ctx.aliasFor(jt);\n const id = otherId.toSql(ctx);\n return { sql: `${id.sql} = ${kqDot(jtAlias, otherColumn)}`, bindings: id.bindings, refs: [...id.refs, jtAlias] };\n });\n const filtered = this.field.softDeletes !== \"include\";\n return {\n [kind]: other,\n on,\n [collectionJoin]: filtered,\n [m2mJoinTable]: { handle: jt, on: jtOn } satisfies M2mJoinTable,\n };\n }\n}\n\n/** Fails fast when a join factory is passed something other than a table. */\nfunction requireTable(other: object): TableFor<Entity> {\n if (!isTable(other)) return fail(`Expected a table to join, got ${other}`);\n return other;\n}\n\n/** The id column of a joined table, for building sugar ON conditions. */\nfunction idColumnOf(other: object): TableColumn {\n return (other as any).id;\n}\n\n/** Keeps relation names join-only; physical FK columns retain expression methods. */\nclass ReferenceJoinImpl {\n constructor(private column: EntityColumnImpl<unknown>) {}\n\n as(other: object): object {\n return this.column.field.required ? this.column.inner(other) : this.column.left(other);\n }\n\n inner(other: object): object {\n return this.column.inner(other);\n }\n\n left(other: object): object {\n return this.column.left(other);\n }\n}\n\n/** Identifies domain relationship keys exposed alongside physical columns. */\nfunction isRelation(field: Field | undefined): boolean {\n return field !== undefined && [\"m2o\", \"poly\", \"o2m\", \"lo2m\", \"m2m\", \"o2o\"].includes(field.kind);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Tables.js","names":[],"sources":["../src/Tables.ts"],"sourcesContent":["import { groupBy } from \"joist-utils\";\n\n// Load-order only: without this, the built cjs/esm module graph evaluates relations/* before their\n// base classes exist (\"Class extends value undefined\"); keep it even though no symbol is imported.\nimport \"./configure.ts\";\nimport { buildValueCondition } from \"./drivers/buildUtils.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type IdOf, type MaybeAbstractEntityConstructor, type TaggedId } from \"./EntityManager.ts\";\nimport {\n type EntityMetadata,\n type Field,\n type LargeOneToManyField,\n type ManyToManyField,\n type OneToManyField,\n type OneToOneField,\n type PolymorphicField,\n type PolymorphicFieldComponent,\n getBaseAndSelfMetas,\n getBaseMeta,\n getBaseSelfAndSubMetas,\n getMetadata,\n} from \"./EntityMetadata.ts\";\nimport {\n BaseExpr,\n type Expr,\n type ExprContext,\n type ExprLike,\n type ExprOutputType,\n type InnerJoin,\n type LeftJoin,\n type SqlFragment,\n asNode,\n canonicalDbType,\n deferredCondition,\n isExpr,\n} from \"./Expr.ts\";\nimport { type ExpressionCondition, getConstructorFromTaggedId, maybeResolveReferenceToId } from \"./index.ts\";\nimport { toIdOf } from \"./keys.ts\";\nimport { kqDot } from \"./keywords.ts\";\nimport { type ParsedValueFilter, makeLike, mapToDb } from \"./QueryParser.ts\";\nimport { type Column, KeySerde, PolymorphicKeySerde } from \"./serde.ts\";\nimport { skipCondition } from \"./skipCondition.ts\";\nimport { type ColumnsOf, type FieldsOf, type TypeMap, type TypeNameOf } from \"./typeMap.ts\";\nimport { fail } from \"./utils.ts\";\n\n/** Creates physical column expressions and relationship joins for `T`. */\nexport function table<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): Table<T>;\n/**\n * Creates a table with an explicit type-level name, i.e. `table(Author, \"m\")` for a self-join.\n *\n * The name is the table's source key in `em.query`: two bare `table(Author)`s share the key `\"Author\"`,\n * so a left-joined mentor would also mark the mentee's columns nullable; a named alias has its own key.\n */\nexport function table<T extends Entity, Name extends string>(\n cstr: MaybeAbstractEntityConstructor<T>,\n name: Name,\n): Table<T, Name>;\nexport function table<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>, _name?: string): Table<T, any> {\n // The name only exists at the type level; the SQL alias is still assigned by the query parser\n return newTableProxy(cstr);\n}\n\n/** Creates multiple physical table handles. */\nexport function tables<T extends readonly MaybeAbstractEntityConstructor<any>[]>(\n ...type: T\n): { [P in keyof T]: T[P] extends MaybeAbstractEntityConstructor<infer E extends Entity> ? Table<E> : never } {\n return type.map((t) => newTableProxy(t)) as any;\n}\n\n/**\n * The runtime management interface plus phantom type information for `em.query`.\n *\n * `__entity` lets `QueryRow` recover `T` for entity mode (you cannot `infer T` back out of a mapped\n * type), and `__name` is the table's source key (see `Expr`).\n */\nexport interface TableBrand<T, Name extends string> extends TableMgmt {\n readonly __entity: T;\n readonly __name: Name;\n}\n\n/**\n * A physical table for `T`: one expression per SQL column, with relationship names as join factories.\n * Selecting the table itself retains entity hydration; selecting columns returns decoded SQL values.\n *\n * Unlike an Alias, a Table is an explicit SQL source, not a place to bind in an em.find relationship\n * tree. I.e. with `a = table(Author)`, `{ from: a }` registers that handle in the query's scope.\n * Its columns already know their physical column and codec, but their SQL name still depends on the\n * query: the same Author handle might be `a` in one query and `a1` in a nested query.\n *\n * Each predicate occurrence renders through ExprContext.aliasFor using the current scope (or an\n * enclosing scope for a correlation). Rendering returns SQL, ordered bindings, and source references\n * together. A comparison records both sides' references; templates and subqueries carry their\n * references too. Join pruning follows these references and join dependencies, rather than guessing\n * which tables a SQL string mentions. It also accounts for select/order/group expressions and keep.\n *\n * I.e. if a joined Author is used only by `a.first_name.eq(name)`, supplying undefined removes that\n * predicate and lets the unused join prune. Both APIs share this undefined-condition pruning rule;\n * they differ in how they get the references: Alias resolves domain conditions against a relationship\n * tree, while Table renders SQL expressions against explicit sources. Neither caches SQL names on\n * the reusable handle or predicate, so one parse cannot overwrite another parse's bindings.\n *\n * `Name` is the table's type-level source key, defaulting to the entity's own type name, so a\n * LEFT-joined SmallPublisher does not make Publisher columns nullable. `table(Author, \"m\")`\n * gives a self-join table its own key.\n */\nexport type Table<T extends Entity, Name extends string = TableNameOf<T>> = {\n readonly [tableMgmt]: TableBrand<T, Name>;\n} & {\n [P in keyof ColumnsOf<T>]: P extends \"id\"\n ? EntityColumn<T, never, Name>\n : ColumnsOf<T>[P] extends { kind: \"primitive\" | \"enum\"; type: infer V; nullable: infer N }\n ? PrimitiveColumn<V, N extends true ? null : never, Name>\n : ColumnsOf<T>[P] extends { kind: \"m2o\"; type: infer U extends Entity; nullable: infer N }\n ? ReferenceColumn<U, N extends true ? null : never, Name>\n : never;\n} & {\n [\n P in keyof FieldsOf<T> as P extends keyof ColumnsOf<T>\n ? never\n : FieldsOf<T>[P] extends { kind: \"m2o\" | \"poly\" | \"o2m\" | \"lo2m\" | \"m2m\" | \"o2o\" }\n ? P\n : never\n ]: FieldsOf<T>[P] extends { kind: \"m2o\"; type: infer U extends Entity; nullable: infer N }\n ? ReferenceJoin<U, N extends undefined ? null : never>\n : FieldsOf<T>[P] extends { kind: \"poly\"; type: infer U extends Entity; nullable: infer N }\n ? PolyReference<U, N extends undefined ? null : never>\n : FieldsOf<T>[P] extends { kind: \"o2m\" | \"lo2m\" | \"m2m\" | \"o2o\"; type: infer U extends Entity }\n ? CollectionJoin<U>\n : never;\n} & {\n [\n K in keyof TypeMap as TypeMap[K] extends {\n entityType: infer U extends Entity & { __type: { 0: TypeNameOf<T>; 1: string } };\n }\n ? Uncapitalize<TypeNameOf<U> & string>\n : never\n ]: TypeMap[K] extends { entityType: infer U extends Entity } ? SubtypeJoin<U> : never;\n};\n\n/** Keeps explicit base and subtype sources independent, with generic entities untracked. */\ntype TableNameOf<T> = T extends { __type: { 0: string } } ? TypeNameOf<T> & string : string;\n\n/** A relationship join factory, without a selectable FK expression. */\nexport interface ReferenceJoin<U extends Entity, N extends null | never> {\n as<A extends TableFor<U>>(other: A): [N] extends [never] ? InnerJoin<A> : LeftJoin<A>;\n inner<A extends TableFor<U>>(other: A): InnerJoin<A>;\n left<A extends TableFor<U>>(other: A): LeftJoin<A>;\n}\n\n/** Any table whose entity is (a subtype of) `U`, i.e. what a relation join factory accepts. */\nexport type TableFor<U> = { readonly [tableMgmt]: TableBrand<U, string> };\n\n/**\n * A collection relation (o2m/o2o/m2m) as a join factory: `a.books.as(b)` returns the same\n * `{ left: b, on: ... }` entry the expanded form writes, with the FK condition built from metadata, so\n * join-list inference, nullability, scope checking, and pruning are unchanged and both forms mix freely.\n *\n * `as` binds the joined alias, the same way em.find's `{ books: { as: b } }` does. The default is LEFT\n * (a collection may be empty, and a LEFT join never filters rows, so pruning it is always safe);\n * `.inner(b)` opts into filtering. An m2m entry carries a hidden second join through the join table,\n * which the parser expands; the pair prunes together.\n */\nexport interface CollectionJoin<U extends Entity> {\n as<A extends TableFor<U>>(other: A): LeftJoin<A>;\n inner<A extends TableFor<U>>(other: A): InnerJoin<A>;\n left<A extends TableFor<U>>(other: A): LeftJoin<A>;\n}\n\n/** A named subtype join, defaulting to LEFT because a root row may belong to another subtype. */\ninterface SubtypeJoin<U extends Entity> extends CollectionJoin<U> {\n <A extends TableFor<U>>(other: A): LeftJoin<A>;\n}\n\n/**\n * A physical FK column expression (`b.author_id` selects/compares the FK) plus a join factory\n * (`b.author_id.as(a)` joins). The default join kind follows physical column nullability:\n * a NOT NULL FK is INNER, a nullable one is LEFT, and the row type reflects it.\n */\nexport interface ReferenceColumn<U extends Entity, N extends null | never, Src extends string>\n extends EntityColumn<U, N, Src>, ReferenceJoin<U, N> {}\n\n/**\n * A polymorphic reference: condition methods (each resolving the component column from the value), plus\n * a join factory that picks the component from the argument's entity, i.e. `c.parent.as(a)` joins\n * through `parent_author_id`, like an explicit join with `on: c.parent.eq(a.id)`.\n */\nexport interface PolyReference<U extends Entity, N extends null | never> extends ReferenceJoin<U, N> {\n eq(value: U | TaggedId | ExprLike<IdOf<U> | null> | null | undefined): ExpressionCondition;\n ne(value: U | TaggedId | ExprLike<IdOf<U> | null> | null | undefined): ExpressionCondition;\n in(values: Array<U | TaggedId> | ExprLike<IdOf<U> | null> | undefined): ExpressionCondition;\n}\n\nexport interface PrimitiveColumn<V, N extends null | never, Src extends string = string> extends Expr<V | N, Src> {\n eq(value: V | ExprLike<V | N> | N | undefined): ExpressionCondition;\n ne(value: V | ExprLike<V | N> | N | undefined): ExpressionCondition;\n in(values: readonly (V | null)[] | ExprLike<V | null> | undefined): ExpressionCondition;\n nin(values: readonly (V | null)[] | ExprLike<V | null> | undefined): ExpressionCondition;\n gt(value: V | ExprLike<V | N> | undefined): ExpressionCondition;\n gte(value: V | ExprLike<V | N> | undefined): ExpressionCondition;\n lt(value: V | ExprLike<V | N> | undefined): ExpressionCondition;\n lte(value: V | ExprLike<V | N> | 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 // need to move to ArrayColumn\n // ...added the `string` to support jsonb contains like `WHERE profile @> '{\"age\": 25}'`\n // Ideally this would go in a JsonbColumn\n contains(value: string | V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition;\n ncontains(value: string | V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition;\n overlaps(value: V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition;\n noverlaps(value: V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition;\n\n /**\n * Adds a JSON path existence condition, using the `@?` operator.\n *\n * Any values should be embedded directly within the `jsonPath`, because postgres does not\n * support parameterized JSON path expressions. The entire `jsonPath` is treated as a parameter,\n * so this is safe from SQL injection.\n */\n pathExists(jsonPath: string | undefined): ExpressionCondition;\n\n /**\n * Adds a JSON path predicate condition, using the `@@` operator.\n *\n * Any values should be embedded directly within the `jsonPath`, because postgres does not\n * support parameterized JSON path expressions. The entire `jsonPath` is treated as a parameter,\n * so this is safe from SQL injection.\n */\n pathIsTrue(jsonPath: string | undefined): ExpressionCondition;\n\n /**\n * Add `exp` to the query, which should include the operator & expression and any\n * bound parameters (but not include the column name).\n *\n * We use knex-style placeholders, i.e. `?` and `\\\\?` to escape question marks, i.e.\n *\n * ```ts\n * a.address.raw(\"@\\\\? ?\", ['$.street ? (@ == \"rr2\")'])`\n * ```\n */\n raw(exp: string, bindings: readonly any[] | undefined): ExpressionCondition;\n}\n\nexport interface EntityColumn<T, N extends null | never = never, Src extends string = string> extends Expr<\n IdOf<T> | N,\n Src\n> {\n eq(value: T | IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n ne(value: T | IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n // Adding `| null` for GraphQL support\n in(value: readonly (T | IdOf<T> | null)[] | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n nin(value: readonly (T | IdOf<T> | null)[] | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n gt(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n gte(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n lt(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n lte(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition;\n raw(exp: string, bindings: readonly any[] | undefined): ExpressionCondition;\n}\n\nexport const tableMgmt = Symbol(\"tableMgmt\");\n\nexport function getTableMgmt(table: TableFor<unknown>): TableMgmt {\n return table[tableMgmt];\n}\n\n/** The identity SQL queries bind a table by, plus its original entity metadata. */\nexport interface TableMgmt {\n tableName: string;\n /**\n * The metadata this table was created with, i.e. `table(TaskNew)` keeps `taskNewMeta`.\n *\n * It cannot be re-derived from `tableName`: STI subtypes share their base's table (`Task`, `TaskNew`,\n * and `TaskOld` are all `tasks`), so a `getMetadataForTable(\"tasks\")` lookup can only return the base\n * `Task`, and the alias would lose its subtype identity for explicit subtype joins and entity hydration.\n */\n meta: EntityMetadata;\n}\n\n/** Returns the metadata for the entity that `table` is bound to. */\nexport function getTableMetadata<T extends Entity>(table: TableFor<T>): EntityMetadata<T> {\n const mgmt = table[tableMgmt];\n return mgmt.meta as EntityMetadata<T>;\n}\n\nexport function newTableProxy<T extends Entity>(cstr: MaybeAbstractEntityConstructor<T>): Table<T> {\n const meta = getMetadata(cstr);\n // The identity SQL queries bind to a source, retaining STI subtype metadata.\n const mgmt: TableMgmt = { tableName: meta.tableName, meta };\n const subtypes = new Map(meta.subTypes.map((m) => [m.type[0].toLowerCase() + m.type.slice(1), m]));\n const proxy: any = new Proxy(cstr, {\n /** Create a physical column expression or a relation join factory. */\n get(_, key: PropertyKey): any {\n if (key === tableMgmt) {\n return mgmt;\n }\n if (typeof key !== \"string\") return undefined;\n const descriptor = Object.hasOwn(meta.columns, key) ? meta.columns[key] : undefined;\n if (descriptor) {\n const { field } = descriptor;\n const column =\n field.serde?.columns.find((c) => c.columnName === key) ?? fail(`No column ${key} on ${cstr.name}`);\n return field.kind === \"m2o\" || field.kind === \"poly\"\n ? new EntityColumnImpl(meta, field, column, mgmt)\n : new PrimitiveColumnImpl(meta, field, column, mgmt);\n }\n const subtype = subtypes.get(key);\n if (subtype) {\n const join = new SubtypeJoinImpl(proxy, subtype);\n return Object.assign(join.as.bind(join), {\n as: join.as.bind(join),\n inner: join.inner.bind(join),\n left: join.left.bind(join),\n });\n }\n const field =\n physicalRelation(meta, key) ?? fail(`No physical field ${key} on ${cstr.name}; join its base table explicitly`);\n switch (field.kind) {\n case \"m2o\":\n return new ReferenceJoinImpl(new EntityColumnImpl(meta, field, field.serde!.columns[0], mgmt));\n case \"poly\":\n return new PolyReferenceImpl(meta, mgmt, field);\n case \"o2m\":\n case \"o2o\":\n case \"lo2m\":\n return new OneToManyJoinImpl(proxy, field);\n case \"m2m\":\n return new ManyToManyJoinImpl(proxy, field);\n default:\n throw new Error(`Unsupported table field kind ${field.kind}`);\n }\n },\n\n has(_, key) {\n return (\n key === tableMgmt ||\n (typeof key === \"string\" &&\n (Object.hasOwn(meta.columns, key) || !!physicalRelation(meta, key) || subtypes.has(key)))\n );\n },\n });\n return proxy;\n}\n\nexport function isTable(obj: unknown): obj is Table<any, any> {\n // Oddly enough `typeof` will be a function b/c we are proxying the constructors\n return typeof obj === \"function\" && tableMgmt in obj;\n}\n\n/**\n * A physical table column implements `Expr`: it renders as `alias.\"column\"`, decodes result\n * values through the field's serde, and inherits aggregate methods from `BaseExpr`.\n */\nclass TableColumn extends BaseExpr {\n public constructor(\n readonly meta: EntityMetadata,\n readonly field: Field,\n readonly column: Column,\n readonly mgmt: TableMgmt,\n ) {\n super();\n }\n\n /** Author.id, Book.author_id, and Comment.parent_author_id use the same Author ID domain. */\n get outputType(): ExprOutputType | undefined {\n const idMeta = this.idMetadata;\n // Built-in poly components are plain columns, not KeySerde instances, but share its ID codec.\n if (idMeta && this.field.serde?.constructor === PolymorphicKeySerde) {\n return {\n dbType: canonicalDbType(this.column.dbType),\n domain: `key:${idMeta.tagName}`,\n idMeta,\n arrayElementSafe: true,\n };\n }\n const outputType = this.column.outputType;\n if (!outputType || !(this.column instanceof KeySerde)) return outputType;\n return idMeta ? { ...outputType, idMeta } : undefined;\n }\n\n get sqlNullable(): boolean | undefined {\n // Entity requiredness differs from physical NOT NULL for derived and STI fields.\n // A required poly still has nullable component FKs: only one target is set on each row.\n return this.field.kind === \"poly\" ? true : this.column.sqlNullable;\n }\n\n get sqlSource(): object {\n return this.mgmt;\n }\n\n toSql(ctx: ExprContext): SqlFragment {\n const alias = ctx.aliasFor(this.mgmt);\n return { sql: kqDot(alias, this.column.columnName), bindings: [], refs: [alias] };\n }\n\n /** Decodes result-set values with public PK/FK ids, while hydration keeps internal tagged ids. */\n decode(value: unknown): unknown {\n if (value === null || value === undefined) return value;\n if (this.column instanceof KeySerde || this.field.serde instanceof PolymorphicKeySerde) {\n const idMeta = this.idMetadata;\n if (idMeta) return toIdOf(idMeta, this.column.mapFromDb(value) as TaggedId | undefined);\n }\n return this.column.mapFromDb(value);\n }\n\n encode(value: unknown): unknown {\n return this.column.mapToDb(value);\n }\n\n /** Identifies the ID domain of a primary key, FK, or physical polymorphic component. */\n get idMetadata(): EntityMetadata | undefined {\n return this.field.kind === \"primaryKey\"\n ? this.meta\n : this.field.kind === \"m2o\"\n ? this.field.otherMetadata()\n : this.field.kind === \"poly\"\n ? this.field.components.find((c) => c.columnName === this.column.columnName)?.otherMetadata()\n : undefined;\n }\n\n /** Encodes literals when the condition is created and renders with each query's aliases. */\n addCondition(value: ParsedValueFilter<unknown>): ExpressionCondition {\n const encoded = mapToDb(this.column, value);\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n const [sql, bindings] = buildValueCondition(left.sql, encoded);\n return { sql, bindings: [...left.bindings, ...bindings], refs: left.refs };\n });\n }\n\n /** Renders raw operators against the same quoted column SQL as other expressions. */\n protected addRawCondition(exp: string, bindings: readonly any[]): ExpressionCondition {\n return deferredCondition((ctx) => {\n const left = this.toSql(ctx);\n return { sql: `${left.sql} ${exp}`, bindings: [...left.bindings, ...bindings], refs: left.refs };\n });\n }\n\n /** Uses column filter conversions for literals and shared comparisons for expressions and null equality. */\n protected compare(op: string, value: unknown): ExpressionCondition {\n if (value === undefined || isExpr(value) || (value === null && (op === \"=\" || op === \"!=\"))) {\n return super.compare(op, value);\n }\n // Primitive relational comparisons historically bind null through mapToDb.\n const kind = ({ \"=\": \"eq\", \"!=\": \"ne\", \">\": \"gt\", \">=\": \"gte\", \"<\": \"lt\", \"<=\": \"lte\" } as const)[op];\n if (!kind) return fail(`Invalid operator ${op}`);\n return this.addCondition({ kind, value });\n }\n\n /**\n * Compares this column to another expression.\n *\n * Table columns, aggregates, subquery columns, and `sql` templates use the expression context\n * to render their complete SQL.\n * Negated array operators wrap the complete comparison in NOT.\n */\n protected compareToExpr(op: string, value: ExprLike<any>, negate = false): ExpressionCondition {\n if (negate) {\n return deferredCondition((ctx) => {\n const comparison = ctx.conditionToSql(this.compareToExpr(op, value))!;\n return { ...comparison, sql: `NOT (${comparison.sql})` };\n });\n }\n return super.compare(op, value);\n }\n}\n\nclass PrimitiveColumnImpl<V, N extends null | never> extends TableColumn implements PrimitiveColumn<V, N> {\n between(v1: V | undefined, v2: V | undefined): ExpressionCondition {\n if (v1 === undefined || v2 === undefined) return skipCondition;\n return this.addCondition({ kind: \"between\", value: [v1, v2] });\n }\n\n like(value: V | undefined): ExpressionCondition {\n if (value === undefined) return skipCondition;\n return this.addCondition({ kind: \"like\", value });\n }\n\n ilike(value: V | undefined): ExpressionCondition {\n if (value === undefined) return skipCondition;\n return this.addCondition({ kind: \"ilike\", value });\n }\n\n search(value: V | undefined): ExpressionCondition {\n // Check !value so that empty strings are pruned\n if (!value) return skipCondition;\n return this.addCondition({ kind: \"ilike\", value: makeLike(value) });\n }\n\n in(values: readonly (V | null)[] | ExprLike<V | null> | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (isExpr(values)) return this.inList(\"IN\", values);\n if (values.includes(null)) {\n const isNull = this.addCondition({ kind: \"is-null\" });\n const hasValue = this.addCondition({ kind: \"in\", value: values.filter((v) => v !== null) });\n return { or: [isNull, hasValue] };\n } else {\n return this.addCondition({ kind: \"in\", value: values as V[] });\n }\n }\n\n nin(values: readonly (V | null)[] | ExprLike<V | null> | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (isExpr(values)) return this.inList(\"NOT IN\", values);\n return this.addCondition({ kind: \"nin\", value: values.filter((v) => v !== null) as V[] });\n }\n\n // V will already be an array\n contains(v1: string | V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition {\n if (v1 === undefined) return skipCondition;\n if (isExpr(v1)) return this.compareToExpr(\"@>\", v1);\n return this.addCondition({ kind: \"contains\", value: v1 as any });\n }\n\n // V will already be an array\n ncontains(v1: string | V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition {\n if (v1 === undefined) return skipCondition;\n if (isExpr(v1)) return this.compareToExpr(\"@>\", v1, true);\n return this.addCondition({ kind: \"ncontains\", value: v1 as any });\n }\n\n // V will already be an array\n overlaps(v1: V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition {\n if (v1 === undefined) return skipCondition;\n if (isExpr(v1)) return this.compareToExpr(\"&&\", v1);\n return this.addCondition({ kind: \"overlaps\", value: v1 as any });\n }\n\n noverlaps(v1: V | PrimitiveColumn<V, any> | N | undefined): ExpressionCondition {\n if (v1 === undefined) return skipCondition;\n if (isExpr(v1)) return this.compareToExpr(\"&&\", v1, true);\n return this.addCondition({ kind: \"noverlaps\", value: v1 as any });\n }\n\n pathExists(jsonPath: string | undefined): ExpressionCondition {\n if (jsonPath === undefined) return skipCondition;\n return this.addCondition({ kind: \"jsonPathExists\", value: jsonPath });\n }\n\n pathIsTrue(jsonPath: string | undefined): ExpressionCondition {\n if (jsonPath === undefined) return skipCondition;\n return this.addCondition({ kind: \"jsonPathPredicate\", value: jsonPath });\n }\n\n raw(exp: string, bindings: readonly any[] | undefined): ExpressionCondition {\n if (bindings === undefined) return skipCondition;\n return this.addRawCondition(exp, bindings);\n }\n}\n\nclass EntityColumnImpl<T> extends TableColumn implements EntityColumn<T> {\n in(values: readonly (T | IdOf<T> | null)[] | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n if (values === undefined) {\n return skipCondition;\n } else if (values === null) {\n throw new Error(\"Unsupported\");\n } else if (isExpr(values)) {\n return this.inList(\"IN\", values);\n } else if (values.includes(null)) {\n // Like `PrimitiveColumn.in`, split `[a1, null]` into `IS NULL OR IN (...)`\n const isNull = this.addCondition({ kind: \"is-null\" });\n const hasValue = this.addCondition({ kind: \"in\", value: values.filter((v) => v !== null) as any });\n return { or: [isNull, hasValue] };\n } else {\n return this.addCondition({ kind: \"in\", value: values as any });\n }\n }\n\n nin(values: readonly (T | IdOf<T> | null)[] | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n if (values === undefined) {\n return skipCondition;\n } else if (values === null) {\n throw new Error(\"Unsupported\");\n } else if (isExpr(values)) {\n return this.inList(\"NOT IN\", values);\n } else {\n return this.addCondition({ kind: \"nin\", value: values.filter((v) => v !== null) as any });\n }\n }\n\n gt(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n return this.compareId(\">\", \"gt\", value);\n }\n\n gte(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n return this.compareId(\">=\", \"gte\", value);\n }\n\n lt(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n return this.compareId(\"<\", \"lt\", value);\n }\n\n lte(value: IdOf<T> | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n return this.compareId(\"<=\", \"lte\", value);\n }\n\n raw(exp: string, bindings: readonly any[] | undefined): ExpressionCondition {\n if (bindings === undefined) return skipCondition;\n return this.addRawCondition(exp, bindings);\n }\n\n /** Joins `other` via this FK, INNER for a required reference and LEFT for a nullable one. */\n as(other: object): object {\n return this.joinEntry(this.sqlNullable === false ? \"inner\" : \"left\", other);\n }\n\n inner(other: object): object {\n return this.joinEntry(\"inner\", other);\n }\n\n left(other: object): object {\n return this.joinEntry(\"left\", other);\n }\n\n private joinEntry(kind: JoinKind, other: object): object {\n return { [kind]: requireTable(other), on: this.eq(idColumnOf(other)) };\n }\n\n private compareId(op: string, kind: \"gt\" | \"gte\" | \"lt\" | \"lte\", value: unknown): ExpressionCondition {\n if (value === undefined) return skipCondition;\n if (value === null) throw new Error(\"Unsupported\");\n if (isExpr(value)) return this.compareToExpr(op, value);\n return this.addCondition({ kind, value: value as any });\n }\n}\n\nclass PolyReferenceImpl<T extends Entity> {\n public constructor(\n private meta: EntityMetadata,\n private mgmt: TableMgmt,\n private field: PolymorphicField,\n ) {}\n\n /** Compares to a tagged id, an entity, or another table's id column, which picks the component (`c.parent.eq(a.id)`). */\n eq(value: T | TaggedId | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n return this.addEqOrNe(\"eq\", value);\n }\n\n ne(value: T | TaggedId | ExprLike<IdOf<T> | null> | null | undefined): ExpressionCondition {\n return this.addEqOrNe(\"ne\", value);\n }\n\n // We required tagged ids for polys\n in(values: Array<T | TaggedId> | ExprLike<IdOf<T> | null> | undefined): ExpressionCondition {\n if (values === undefined) return skipCondition;\n if (isExpr(values)) return this.inSubquery(values);\n // Split up the ids by constructor\n const idsByConstructor = 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(idsByConstructor).map(([cstrName, ids]) => {\n const comp =\n this.field.components.find((p) => p.otherMetadata().cstr.name === cstrName) ??\n fail(`No component for ${cstrName}`);\n return this.componentColumn(comp).addCondition({ kind: \"in\", value: ids });\n }),\n };\n }\n\n /** Joins `other` via this poly's component for its entity, INNER when the poly is required. */\n as(other: object): object {\n return this.joinEntry(this.field.required ? \"inner\" : \"left\", other);\n }\n\n inner(other: object): object {\n return this.joinEntry(\"inner\", other);\n }\n\n left(other: object): object {\n return this.joinEntry(\"left\", other);\n }\n\n private joinEntry(kind: JoinKind, other: object): object {\n return { [kind]: requireTable(other), on: this.eq(idColumnOf(other) as any) };\n }\n\n /**\n * i.e. `c.parent.in(query({ from: a, ..., select: a.id }))`: like `eq` against a table column, the\n * subquery's agreed ID domain picks the component, i.e. authors pick `parent_author_id`.\n */\n private inSubquery(values: ExprLike<any>): ExpressionCondition {\n // Only actual subqueries expose this getter; importing query.ts would create a load-order cycle.\n const selected = asNode(values).subquerySelect;\n const outputType = selected?.outputType;\n let otherMeta = outputType?.idMeta;\n if (!otherMeta) {\n // Ordinary reads can select an unknown key serde. Compounds validate codecs before exposing a select.\n if (!outputType && selected instanceof TableColumn) {\n otherMeta = selected.idMetadata;\n }\n if (!otherMeta) {\n return fail(\n selected instanceof TableColumn\n ? `${this.field.fieldName} \\`in\\` needs an id or FK column, got ${selected.field.fieldName}`\n : `${this.field.fieldName} is polymorphic, so \\`in\\` needs a subquery selecting an id or FK column`,\n );\n }\n }\n const comp =\n this.field.components.find((p) => getBaseAndSelfMetas(otherMeta).includes(p.otherMetadata())) ??\n fail(`${this.field.fieldName} has no component for ${otherMeta.type}`);\n return this.componentColumn(comp).in(values);\n }\n\n private addEqOrNe(\n kind: \"eq\" | \"ne\",\n value: T | TaggedId | ExprLike<IdOf<T> | null> | null | undefined,\n ): ExpressionCondition {\n if (value === undefined) {\n return skipCondition;\n } else if (value instanceof TableColumn) {\n // Joining through the poly, i.e. `c.parent.eq(a.id)`: the other table column's ID domain picks the component\n const otherMeta = value.idMetadata ?? fail(`${this.field.fieldName} needs an id or FK column`);\n const comp =\n this.field.components.find((p) => getBaseAndSelfMetas(otherMeta).includes(p.otherMetadata())) ??\n fail(`${this.field.fieldName} has no component for ${otherMeta.type}`);\n return this.componentColumn(comp)[kind](value);\n } else if (isExpr(value)) {\n return fail(\n `${this.field.fieldName} is polymorphic, so it can only be compared to tagged ids or entity table columns`,\n );\n } else if (value === null) {\n // We can AND each of the components as many conditions\n const value = kind === \"eq\" ? ({ kind: \"is-null\" } as const) : ({ kind: \"not-null\" } as const);\n return {\n and: this.field.components.map((p) => this.componentColumn(p).addCondition(value)),\n };\n } else {\n // If we have a value, we can find the component\n const comp =\n this.field.components.find(\n (p) => p.otherMetadata().cstr === getConstructorFromTaggedId(maybeResolveReferenceToId(value) as string),\n ) || fail(`Could not find component for ${value}`);\n return this.componentColumn(comp)[kind](value);\n }\n }\n\n /** Returns the physical FK expression for one polymorphic target. */\n private componentColumn(comp: PolymorphicFieldComponent): EntityColumnImpl<T> {\n const descriptor =\n this.meta.columns[comp.columnName] ?? fail(`No physical column ${comp.columnName} on ${this.meta.type}`);\n const column =\n descriptor.field.serde?.columns.find((c) => c.columnName === comp.columnName) ?? fail(\"Missing column\");\n return new EntityColumnImpl<T>(this.meta, descriptor.field, column, this.mgmt);\n }\n}\n\n/**\n * Marks a sugar join entry whose target is a *collection* (o2m/m2m), which filter soft-deletes like\n * em.find's \"collections filter out soft-deletes, but m2o/o2o references still return them\"; see\n * `QueryParser.addSoftDeleteCondition`'s call site. Reference joins and explicit joins are unmarked.\n */\nexport const collectionJoin: unique symbol = Symbol(\"joist.collectionJoin\");\n\n/** Marks a sugar m2m join entry (`a.tags.as(t)`) with its hidden join-table join; `parseQuery` expands it. */\nexport const m2mJoinTable: unique symbol = Symbol(\"joist.m2mJoinTable\");\n\nexport interface M2mJoinTable {\n handle: JoinTableHandle;\n on: ExpressionCondition;\n}\n\n/** The runtime identity of an m2m join table in a query, i.e. `authors_to_tags`; it has no entity. */\nexport class JoinTableHandle {\n constructor(readonly joinTableName: string) {}\n}\n\ntype JoinKind = \"inner\" | \"left\";\n\n/**\n * The `as`/`inner`/`left` join factory for collection relations, i.e. `a.books.as(b)` joins with the\n * relation's default kind (LEFT: a collection may be empty) and `.inner`/`.left` override. m2o/poly\n * relations implement the same three methods on their join factories. Physical FKs such as\n * `b.author_id` are expressions that also expose a join factory.\n */\nabstract class CollectionJoinImpl {\n as(other: object): object {\n return this.joinEntry(\"left\", requireTable(other));\n }\n\n inner(other: object): object {\n return this.joinEntry(\"inner\", requireTable(other));\n }\n\n left(other: object): object {\n return this.joinEntry(\"left\", requireTable(other));\n }\n\n protected abstract joinEntry(kind: JoinKind, other: TableFor<Entity>): object;\n}\n\n/** Joins a named subtype explicitly; only STI subtype sugar adds a discriminator to its ON. */\nclass SubtypeJoinImpl extends CollectionJoinImpl {\n constructor(\n private proxy: TableFor<Entity>,\n private subtype: EntityMetadata,\n ) {\n super();\n }\n\n protected joinEntry(kind: JoinKind, other: TableFor<Entity>): object {\n if (getTableMetadata(other) !== this.subtype) {\n return fail(`Expected table(${this.subtype.type}) for the explicit subtype join`);\n }\n const on = idColumnOf(this.proxy).eq(idColumnOf(other));\n if (this.subtype.inheritanceType !== \"sti\" || this.subtype.stiDiscriminatorValue === undefined) {\n return { [kind]: other, on };\n }\n const base = this.subtype.baseTypes.find((m) => m.stiDiscriminatorField !== undefined)!;\n const columnName = base.fields[base.stiDiscriminatorField!].serde!.columns[0].columnName;\n // Discriminator values are database enum ids, not domain enum values to pass through the field codec.\n const discriminator = deferredCondition((ctx) => {\n const alias = ctx.aliasFor(other[tableMgmt]);\n return {\n sql: `${kqDot(alias, columnName)} = ?`,\n bindings: [this.subtype.stiDiscriminatorValue],\n refs: [alias],\n };\n });\n return { [kind]: other, on: { and: [on, discriminator] } };\n }\n}\n\n/** An o2m/lo2m/o2o relation: the ON is the other side's FK (an m2o or a poly component) back to our id. */\nclass OneToManyJoinImpl extends CollectionJoinImpl {\n constructor(\n private proxy: any,\n private field: OneToManyField | LargeOneToManyField | OneToOneField,\n ) {\n super();\n }\n\n protected joinEntry(kind: JoinKind, other: TableFor<Entity>): object {\n const { field } = this;\n const otherMeta = getTableMetadata(other);\n const descriptor = otherMeta.columns[field.otherColumnName];\n if (!descriptor) {\n return fail(\n `Cannot join ${getTableMetadata(this.proxy).type}.${field.fieldName} to ${otherMeta.type}: ` +\n `${field.otherColumnName} is not physically present on ${otherMeta.tableName}; join the base table explicitly`,\n );\n }\n const physicalColumn =\n descriptor.field.serde?.columns.find((c) => c.columnName === field.otherColumnName) ?? fail(\"Missing column\");\n const column = new EntityColumnImpl(otherMeta, descriptor.field, physicalColumn, other[tableMgmt]);\n const on = column.eq(this.proxy.id);\n // Collections (o2m/lo2m) filter soft-deletes like em.find; o2o references resolve them\n const filtered = field.kind === \"o2m\" ? field.softDeletes !== \"include\" : field.kind === \"lo2m\";\n return { [kind]: other, on, [collectionJoin]: filtered };\n }\n}\n\n/**\n * An m2m relation, i.e. `a.tags.as(t)`.\n *\n * The entry's own ON is `t.id = att.tag_id`, and the hidden `[m2mJoinTable]` half is\n * `att.author_id = a.id`; only the target's ON references the join table, so reference pruning keeps\n * or drops the pair together. Both are deferred conditions: the join table has no entity metadata, so\n * its alias only exists once the parser registers it.\n */\nclass ManyToManyJoinImpl extends CollectionJoinImpl {\n constructor(\n private proxy: any,\n private field: ManyToManyField,\n ) {\n super();\n }\n\n protected joinEntry(kind: JoinKind, other: TableFor<Entity>): object {\n const { joinTableName, columnNames } = this.field;\n const [ourColumn, otherColumn] = columnNames;\n const jt = new JoinTableHandle(joinTableName);\n const ourId = idColumnOf(this.proxy);\n const otherId = idColumnOf(other);\n const jtOn = deferredCondition((ctx) => {\n const jtAlias = ctx.aliasFor(jt);\n const id = ourId.toSql(ctx);\n return { sql: `${kqDot(jtAlias, ourColumn)} = ${id.sql}`, bindings: id.bindings, refs: id.refs };\n });\n const on = deferredCondition((ctx) => {\n const jtAlias = ctx.aliasFor(jt);\n const id = otherId.toSql(ctx);\n return { sql: `${id.sql} = ${kqDot(jtAlias, otherColumn)}`, bindings: id.bindings, refs: [...id.refs, jtAlias] };\n });\n const filtered = this.field.softDeletes !== \"include\";\n return {\n [kind]: other,\n on,\n [collectionJoin]: filtered,\n [m2mJoinTable]: { handle: jt, on: jtOn } satisfies M2mJoinTable,\n };\n }\n}\n\n/** Fails fast when a join factory is passed something other than a table. */\nfunction requireTable(other: object): TableFor<Entity> {\n if (!isTable(other)) return fail(`Expected a table to join, got ${other}`);\n return other;\n}\n\n/** The id column of a joined table, for building sugar ON conditions. */\nfunction idColumnOf(other: object): TableColumn {\n return (other as any).id;\n}\n\n/** Keeps relation names join-only; physical FK columns retain expression methods. */\nclass ReferenceJoinImpl {\n constructor(private column: EntityColumnImpl<unknown>) {}\n\n as(other: object): object {\n return this.column.field.required ? this.column.inner(other) : this.column.left(other);\n }\n\n inner(other: object): object {\n return this.column.inner(other);\n }\n\n left(other: object): object {\n return this.column.left(other);\n }\n}\n\n/** Identifies domain relationship keys exposed alongside physical columns. */\nfunction isRelation(field: Field | undefined): boolean {\n return field !== undefined && [\"m2o\", \"poly\", \"o2m\", \"lo2m\", \"m2m\", \"o2o\"].includes(field.kind);\n}\n\n/** Resolves relationship sugar only from domain fields owned by this physical table. */\nfunction physicalRelation(meta: EntityMetadata, key: string): Field | undefined {\n const owners = [meta, ...getBaseSelfAndSubMetas(getBaseMeta(meta))];\n const owner = owners.find((owner) => owner.tableName === meta.tableName && Object.hasOwn(owner.fields, key));\n const field = owner?.fields[key];\n if (!isRelation(field)) return undefined;\n // I.e. TaskNew.copiedFrom uses Task's original FK domain, not its specialized TaskNew target.\n if (field?.kind === \"m2o\" || field?.kind === \"poly\") {\n const columnName = field.serde.columns[0].columnName;\n const storage = meta.columns[columnName]?.field;\n if (\n !storage ||\n storage.kind !== field.kind ||\n !storage.serde!.columns.every((column) => Object.hasOwn(meta.columns, column.columnName))\n )\n return undefined;\n return storage;\n }\n return field;\n}\n"],"mappings":"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"}
@@ -165,10 +165,7 @@ function hookUpBaseTypeAndSubTypes(metas) {
165
165
  }]));
166
166
  if (m.baseType) {
167
167
  const b = metaByName[m.baseType];
168
- m.columns = {
169
- ...b.columns,
170
- ...m.columns
171
- };
168
+ if (m.inheritanceType === "sti") m.columns = b.columns;
172
169
  m.baseTypes.push(b);
173
170
  b.subTypes.push(m);
174
171
  Object.entries(b.fields).forEach(([name, field]) => {
@@ -1 +1 @@
1
- {"version":3,"file":"configure.cjs","names":["getBaseAndSelfMetas","getBaseSelfAndSubMetas","fail","tagFromId","maybeResolveReferenceToId","maybeGetRuntimeConfig","isCannotBeUpdatedRule","AsyncDefault","reverseReactiveHint","getProperties","AsyncReactiveFieldImpl","KeySerde"],"sources":["../src/configure.ts"],"sourcesContent":["import { type Reactable, setAfterMetadataLocked, setBooted } from \"./config.ts\";\nimport { AsyncDefault } from \"./defaults.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type MaybeAbstractEntityConstructor, type TaggedId } from \"./EntityManager.ts\";\nimport {\n type EntityMetadata,\n type EnumField,\n type ManyToOneField,\n type OneToManyField,\n getBaseAndSelfMetas,\n getBaseSelfAndSubMetas,\n getMetadata,\n} from \"./EntityMetadata.ts\";\nimport { getProperties } from \"./getProperties.ts\";\nimport { maybeResolveReferenceToId, setTaggedIdDelimiter, tagFromId } from \"./keys.ts\";\nimport { reverseReactiveHint } from \"./reactiveHints.ts\";\nimport { AsyncReactiveFieldImpl } from \"./relations/AsyncReactiveField.ts\";\nimport { type ReactiveManyToManyImpl, type ReactiveReferenceImpl, type Reference } from \"./relations/index.ts\";\nimport { type ReactiveFieldImpl } from \"./relations/ReactiveField.ts\";\nimport { isCannotBeUpdatedRule } from \"./rules.ts\";\nimport { maybeGetRuntimeConfig } from \"./runtimeConfig.ts\";\nimport { KeySerde } from \"./serde.ts\";\nimport { defineLazyGetter, fail } from \"./utils.ts\";\n\nconst tagToConstructorMap = new Map<string, MaybeAbstractEntityConstructor<any>>();\nconst tableToMetaMap = new Map<string, EntityMetadata>();\nconst typeToMetaMap = new Map<string, EntityMetadata>();\n\nlet previousBootError: any;\n\n/** Performs our boot-time initialization, i.e. hooking up reactivity. */\nexport function configureMetadata(metas: EntityMetadata[]): void {\n // Add explicit \"did we already fail\" check b/c if a transformer like tsx gets a runtime error from\n // here, it can potentially suppress it, move on to another file, which will naively re-invoke\n // `configureMetadata` again, and fail with a very confusing \"Duplicate tag\" error\n if (previousBootError) {\n throw previousBootError;\n }\n try {\n populateConstructorMaps(metas);\n hookUpBaseTypeAndSubTypes(metas);\n installMetadataGetters(metas);\n sortMetasByBaseType(metas);\n setImmutableFields(metas);\n populatePolyComponentFields(metas);\n fireAfterMetadatas(metas);\n // Callers can make `config` calls during `afterMetadata` callbacks, but after that\n // we don't allow any more config changes.\n setBooted();\n // Do these after `fireAfterMetadatas`, in case afterMetadata callbacks added more defaults/rules\n copyAsyncDefaults(metas);\n reverseIndexReactivity(metas);\n installReactiveMetadataGetters(metas);\n copyRunBeforeBooksToBaseType(metas);\n } catch (e) {\n previousBootError = e;\n throw e;\n }\n}\n\n/** Installs lazy lookup getters for metadata-derived caches. */\nfunction installMetadataGetters(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n defineLazyGetter(meta, \"subTypesByType\", function buildSubTypesByType() {\n return new Map(meta.subTypes.map((st) => [st.type, st]));\n });\n defineLazyGetter(meta, \"subTypesByStiValue\", function buildSubTypesByStiValue() {\n return new Map(meta.subTypes.map((st) => [st.stiDiscriminatorValue, st]));\n });\n defineLazyGetter(meta, \"stiDiscriminatorColumnName\", function buildStiDiscriminatorColumnName() {\n const field = meta.fields[meta.stiDiscriminatorField!];\n if (field === undefined) throw new Error(`${meta.type} does not have an STI discriminator field`);\n if (field.kind !== \"enum\") throw new Error(\"Discriminator field must be an enum\");\n return (field as EnumField).serde.columns[0].columnName;\n });\n defineLazyGetter(meta, \"lazyFieldNames\", function buildLazyFieldNames() {\n return new Set(\n Object.values(meta.fields)\n .filter((f) => f.kind === \"primitive\" && f.lazy)\n .map((f) => f.fieldName),\n );\n });\n defineLazyGetter(meta, \"hasLazyColumns\", function buildHasLazyColumns() {\n return meta.lazyFieldNames!.size > 0;\n });\n defineLazyGetter(meta, \"syncDerivedFields\", function buildSyncDerivedFields() {\n return Object.values(meta.allFields)\n .filter((f) => (f.kind === \"primitive\" || f.kind === \"enum\") && f.derived === \"sync\")\n .map((f) => f.fieldName);\n });\n }\n}\n\n/** Installs lazy getters for reactivity caches after reactivity has been reverse-indexed. */\nfunction installReactiveMetadataGetters(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n defineLazyGetter(meta, \"reactables\", function buildReactables() {\n return getBaseAndSelfMetas(meta)\n .flatMap((m) => m.config.__data.reactables)\n .filter((r) => !r.isReadOnly);\n });\n defineLazyGetter(meta, \"reactablesByField\", function buildReactablesByField() {\n return indexReactablesByField(meta.reactables!);\n });\n defineLazyGetter(meta, \"reactablesIncludingReadOnly\", function buildReactablesIncludingReadOnly() {\n return getBaseAndSelfMetas(meta).flatMap((m) => m.config.__data.reactables);\n });\n defineLazyGetter(meta, \"reactablesIncludingReadOnlyByField\", function buildReactablesIncludingReadOnlyByField() {\n return indexReactablesByField(meta.reactablesIncludingReadOnly!);\n });\n defineLazyGetter(meta, \"reactiveRules\", function buildReactiveRules() {\n // We use \"AndSub\" because `reactiveRules` is called with `todo.metadata`, which is always\n // the root type, but ofc we don't want to skip subtype rules.\n //\n // I had considered filtering this list with `rr.fields.length > 0`, but even rules with 100%\n // immutable fields (so all read-only, and so not \"reactive\") need to run on initial entity creation.\n return getBaseSelfAndSubMetas(meta).flatMap((m) => m.config.__data.reactiveRules);\n });\n defineLazyGetter(meta, \"reactiveCommitRules\", function buildReactiveCommitRules() {\n // Same \"AndSub\" reasoning as `reactiveRules`, just for the post-flush/pre-commit commit rules.\n return getBaseSelfAndSubMetas(meta).flatMap((m) => m.config.__data.reactiveCommitRules);\n });\n defineLazyGetter(meta, \"hasCommitRules\", function buildHasCommitRules() {\n // True if flushing an entity of this type could trigger commit-rule work, so `em.flush` can\n // skip the whole commit-rule pass otherwise. We need *both* checks because hinted and\n // non-hinted commit rules are stored in different places:\n //\n // 1. Hinted commit rules are reverse-indexed onto their *trigger* entity's `reactiveCommitRules`,\n // which is often a *different* entity than the one the rule is declared on. I.e. a rule\n // `config.addCommitRule({ books: \"title\" }, fn)` declared on `Author` lands on\n // `Book.reactiveCommitRules`, so flushing a Book must run it even though `Book`'s own\n // `config.__data.commitRules` is empty — hence checking `reactiveCommitRules`, not `commitRules`.\n //\n // 2. Non-hinted commit rules are *not* reverse-indexed at all; they run on every insert/update of\n // the entity they're declared on (via `validateSimpleRules`). I.e. `config.addCommitRule(fn)` on\n // `Author` only ever shows up in `Author.config.__data.commitRules` with `hint === undefined`,\n // so `reactiveCommitRules` would miss it. (We filter to `hint === undefined` because hinted\n // rules are already covered by check #1.)\n return (\n meta.reactiveCommitRules!.length > 0 ||\n getBaseSelfAndSubMetas(meta).some((m) => m.config.__data.commitRules.some((r) => r.hint === undefined))\n );\n });\n }\n}\n\n// Sort metas in place by inheritance hierarchy so that the base type comes before subtypes\nfunction sortMetasByBaseType(metas: EntityMetadata[]): void {\n metas.sort(compareMetasByBaseType);\n}\n\n// Compare metas by inheritance hierarchy so that the base type sorts before subtypes\nfunction compareMetasByBaseType(a: EntityMetadata, b: EntityMetadata): number {\n if (a.baseTypes.length > 0 && b.baseTypes.length === 0) return 1;\n if (a.baseTypes.length === 0 && b.baseTypes.length > 0) return -1;\n if (a.baseTypes.some((baseType) => baseType === b)) return 1;\n if (b.baseTypes.some((baseType) => baseType === a)) return -1;\n return a.type.localeCompare(b.type);\n}\n\nfunction fireAfterMetadatas(metas: EntityMetadata[]): void {\n setAfterMetadataLocked();\n for (const meta of metas) {\n for (const fn of meta.config.__data.afterMetadataCallbacks) fn(meta);\n }\n}\n\nexport function resetConstructorMap(): void {\n tagToConstructorMap.clear();\n setTaggedIdDelimiter(\":\");\n}\n\nexport function getConstructorFromTag(tag: string): MaybeAbstractEntityConstructor<any> {\n return tagToConstructorMap.get(tag) ?? fail(`Unknown tag: \"${tag}\" `);\n}\n\nexport function getConstructorFromTaggedId(id: TaggedId): MaybeAbstractEntityConstructor<any> {\n return getConstructorFromTag(tagFromId(id));\n}\n\nexport function getMetadataForTable(tableName: string): EntityMetadata {\n return tableToMetaMap.get(tableName) ?? fail(`Unknown table ${tableName}`);\n}\n\nexport function getMetadataForType(typeName: string): EntityMetadata {\n return typeToMetaMap.get(typeName) ?? fail(`Unknown type ${typeName}`);\n}\n\n/** Returns metadata for `typeName`, if `configureMetadata` has populated the type map. */\nexport function maybeGetMetadataForType<T extends Entity = Entity>(typeName: string): EntityMetadata<T> | undefined {\n return typeToMetaMap.get(typeName) as EntityMetadata<T> | undefined;\n}\n\nexport function maybeGetConstructorFromReference(\n value: string | Entity | Reference<any, any, any> | undefined,\n): MaybeAbstractEntityConstructor<any> | undefined {\n const id = maybeResolveReferenceToId(value);\n return id ? getConstructorFromTaggedId(id) : undefined;\n}\n\nfunction populateConstructorMaps(metas: EntityMetadata[]): void {\n const runtimeConfig = maybeGetRuntimeConfig();\n const tagDelimiter = runtimeConfig && Object.hasOwn(runtimeConfig, \"tagDelimiter\") ? runtimeConfig.tagDelimiter : \":\";\n setTaggedIdDelimiter(tagDelimiter);\n\n for (const meta of metas) {\n // Add each (root) constructor into our tag -> constructor map for future lookups\n if (!meta.baseType) {\n const existing = tagToConstructorMap.get(meta.tagName);\n if (existing) throw new Error(`Duplicate tag '${meta.tagName}' for ${meta.type} and ${existing.name}`);\n tagToConstructorMap.set(meta.tagName, meta.cstr);\n }\n // Same for tables, but include subclass tables\n tableToMetaMap.set(meta.tableName, meta);\n typeToMetaMap.set(meta.type, meta);\n }\n}\n\n// Do a first pass to flag immutable fields (which we'll use in reverseReactiveHint)\nfunction setImmutableFields(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Scan rules for cannotBeUpdated so that we can set `field.immutable`\n for (const rule of meta.config.__data.rules) {\n if (isCannotBeUpdatedRule(rule.fn) && rule.fn.immutable) {\n // Usually the field will exist directly in meta.fields\n const selfField = meta.fields[rule.fn.field];\n // Or it might have come in from a base type in meta.allFields\n const baseField = meta.allFields[rule.fn.field];\n // Either way, at least one should exist\n if (!selfField && !baseField) {\n throw new Error(`Missing field '${meta.type}.${rule.fn.field}' for cannotBeUpdated at ${rule.name}`);\n }\n if (selfField) selfField.immutable = true;\n if (baseField) baseField.immutable = true;\n }\n }\n }\n}\n\n// Setup subTypes/baseTypes\nfunction hookUpBaseTypeAndSubTypes(metas: EntityMetadata[]): void {\n const metaByName = metas.reduce(\n (acc, m) => {\n acc[m.type] = m;\n return acc;\n },\n {} as Record<string, EntityMetadata>,\n );\n for (const m of metas) {\n // This is basically m.fields.mapValues to assign the primary alias\n m.allFields = Object.fromEntries(\n Object.entries(m.fields).map(([name, field]) => [name, { ...field, aliasSuffix: \"\" }]),\n );\n // Only supporting one level of inheritance for now, ideally would loop `while current !== null`\n if (m.baseType) {\n const b = metaByName[m.baseType];\n m.columns = { ...b.columns, ...m.columns };\n m.baseTypes.push(b);\n b.subTypes.push(m);\n // Add all the base's fields to our allFields, with the base's aliasSuffix, so that in\n // `WHERE` clauses for `small_publishers`, we'll have joined in `publishers` with an\n // alias + this alias suffix, so can `WHERE` on `${alias}_b0.name = 'foo'` and get\n // to the correct table.\n //\n // Note that we don't need to do this for subtypes, because `em.find` queries aren't\n // allowed to `WHERE` against columns in their subtypes. Maybe someday we can support\n // that like the GraphQL `...on SmallPublisher` syntax, like conditional/subtype-specific\n // clauses.\n Object.entries(b.fields).forEach(([name, field]) => {\n // We use `b0` because that is what addTablePerClassJoinsAndClassTag uses to join in the base table\n const aliasSuffix = b.inheritanceType === \"cti\" ? \"_b0\" : \"\";\n if (name in m.allFields && name !== \"id\") {\n // If the base field (i.e. group) is already in `m.allFields`, it's from a CTI subtype specializing\n // a base field (i.e. `SmallPublisher.group`), in which case we don't really want it inserted/updated\n // in the `small_publishers` table itself, so we'll delete it from `m.fields`, *but* leave it in\n // m.allFields, with appropriate/overridden `otherEntity: SmallPublisherGroup` config so that it\n // can be used to reverse validation rules/RFs.\n delete m.fields[name];\n m.allFields[name].aliasSuffix = aliasSuffix;\n m.allFields[name].specialized = true;\n } else {\n m.allFields[name] = { ...field, aliasSuffix };\n }\n });\n }\n }\n // Now that base/sub links are complete, cache the hot-path meta arrays that\n // `getBaseAndSelfMetas`/`getBaseSelfAndSubMetas` would otherwise re-allocate per call.\n for (const m of metas) {\n m.baseSelfMetas = [...m.baseTypes, m];\n m.baseSelfAndSubMetas = [...m.baseTypes, m, ...m.subTypes];\n }\n}\n\n/** Copy/pastes base AsyncDefaults onto subtypes, so that subtypes can have their own default dependencies. */\nfunction copyAsyncDefaults(metas: EntityMetadata[]): void {\n for (const m of metas) {\n for (const b of m.baseTypes) {\n // Clone in the base asyncDefaults, unless we override our own\n for (const [fieldName, df] of Object.entries(b.config.__data.asyncDefaults)) {\n if (!m.config.__data.asyncDefaults[fieldName]) {\n // Given our subtype its own instance, because we might have different default dependencies.\n // I.e. from a sample domain model, something like:\n // - The base `PlanVersion.type` default depends on `{ identity: \"type\" }`\n // - The base `Plan.type` has no default itself\n // - The sub `SpecialPlanVersion` inherits type, and specializes `SPV.identity: SP`\n // - The sub `SpecialPlan.type` does have a default\n //\n // So we need to eval `PlanVersion.type` separately from `SpecialPlanVersion.type`, even\n // though they come from the same `config.setDefault` call/lambda in `PlanVersion.ts`.\n m.config.__data.asyncDefaults[fieldName] = new AsyncDefault(df.fieldName, df.fieldHint, df.fn);\n }\n }\n }\n }\n}\n\n// Now hook up our reactivity\nfunction reverseIndexReactivity(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Look for reactive validation rules to reverse\n for (const { name, hint, fn } of meta.config.__data.rules) {\n if (hint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n // For each reversal, tell its config about the reverse hint to force-re-validate\n // the original rule's instance any time it changes.\n for (const { kind, entity, path, fields } of reversals) {\n if (kind === \"update\") {\n getMetadata(entity).config.__data.reactiveRules.push({\n source: entity,\n cstr: meta.cstr,\n name,\n fields,\n path,\n fn,\n });\n }\n }\n }\n }\n\n // Same reverse-indexing as `rules` above, but for `commitRules` -> `reactiveCommitRules`.\n for (const { name, hint, fn } of meta.config.__data.commitRules) {\n if (hint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n for (const { kind, entity, path, fields } of reversals) {\n if (kind === \"update\") {\n getMetadata(entity).config.__data.reactiveCommitRules.push({\n source: entity,\n cstr: meta.cstr,\n name,\n fields,\n path,\n fn,\n });\n }\n }\n }\n }\n\n // Look for reactions to reverse\n for (const { name, hint, fn, runOnce } of meta.config.__data.reactions) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n // For each reversal, tell its config about the reverse hint to force-rerun\n // the original reaction's instance any time it changes.\n for (const { kind, entity, path, fields } of reversals) {\n getMetadata(entity).config.__data.reactables.push({\n kind: \"reaction\",\n source: entity,\n cstr: meta.cstr,\n isReadOnly: kind === \"read-only\",\n name,\n fields,\n path,\n fn,\n runOnce,\n });\n }\n }\n\n // Look for ReactiveFields, ReactiveReferences, & ReactiveManyToManys to reverse\n const reactiveRelations = Object.values(meta.allFields).filter(\n (f) =>\n f.kind === \"primitive\" ||\n (f.kind === \"m2o\" && f.derived === \"async\") ||\n (f.kind === \"enum\" && f.derived === \"async\") ||\n (f.kind === \"m2m\" && f.derived === \"async\"),\n );\n for (const field of reactiveRelations) {\n const ap = (getProperties(meta) as any)[field.fieldName] as\n | ReactiveFieldImpl<any, any, any>\n | AsyncReactiveFieldImpl<any, any, any, any>\n | ReactiveReferenceImpl<any, any, any, any>\n | ReactiveManyToManyImpl<any, any, any>\n | undefined;\n // We might have an async property configured in joist-config.json that has not yet\n // been made a `hasReactiveField` in the entity file, so avoid continuing\n // if we don't actually have a property/loadHint available.\n if (ap?.reactiveHint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, ap.reactiveHint);\n for (const { kind, entity, path, fields } of reversals) {\n getMetadata(entity).config.__data.reactables.push({\n kind: ap instanceof AsyncReactiveFieldImpl ? \"query\" : \"populate\",\n cstr: meta.cstr,\n isReadOnly: kind === \"read-only\",\n name: field.fieldName,\n path,\n fields,\n runOnce: false,\n });\n }\n }\n }\n }\n}\n\n/**\n * In addition to the canonical `meta.allFields`, we populate a `meta.polyComponentFields` to\n * disaggregates the poly's components into individual fields so that `em.find` / `parseFindQuery`\n * can support component-specific find queries.\n */\nfunction populatePolyComponentFields(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n for (const [key, field] of Object.entries(meta.allFields)) {\n if (field.kind === \"poly\") {\n meta.polyComponentFields ??= {};\n for (const comp of field.components) {\n const fieldName = `${key}${comp.otherMetadata().type}`;\n // Synthesize a m2o component that won't be used for any actual read/write serde,\n // but just to help `parseFindQuery` build `WHERE` clauses.\n meta.polyComponentFields[fieldName] = {\n kind: \"m2o\",\n fieldName,\n fieldIdName: `${fieldName}Id`,\n required: false,\n immutable: false,\n derived: false,\n serde: new KeySerde(\n comp.otherMetadata().tagName,\n fieldName,\n comp.columnName,\n field.serde.columns[0].dbType as any,\n ),\n ...comp,\n aliasSuffix: field.aliasSuffix,\n } satisfies ManyToOneField & { aliasSuffix: string };\n }\n } else if (field.kind === \"m2o\") {\n field.otherMetadata().subTypes.forEach((st) => {\n const fieldName = `${key}${st.type}`;\n meta.polyComponentFields ??= {};\n meta.polyComponentFields[fieldName] = {\n ...field,\n // a subtype specific sub-field (i.e. `publisherLargePublishers`) cannot be required (which turns into\n // an `inner join`), even if its parent is, since it won't always be present (i.e. the pointed-at publisher\n // might be a small publisher).\n required: false,\n fieldName,\n fieldIdName: `${fieldName}Id`,\n otherMetadata: () => st,\n } satisfies ManyToOneField & { aliasSuffix: string };\n });\n } else if (field.kind === \"o2m\") {\n field.otherMetadata().subTypes.forEach((st) => {\n const fieldName = `${key}${st.type}`;\n meta.polyComponentFields ??= {};\n meta.polyComponentFields[fieldName] = {\n ...field,\n fieldName,\n fieldIdName: `${fieldName}Id`,\n otherMetadata: () => st,\n } satisfies OneToManyField & { aliasSuffix: string };\n });\n }\n }\n }\n}\n\nfunction copyRunBeforeBooksToBaseType(meta: EntityMetadata[]): void {\n for (const m of meta) {\n for (const b of m.baseTypes) {\n b.config.__data.runHooksBefore.push(...m.config.__data.runHooksBefore);\n }\n }\n}\n\n/** Indexes reactables once so field setters don't scan every reactable's fields. */\nfunction indexReactablesByField(reactables: readonly Reactable[]): Map<string, Reactable[]> {\n const byField = new Map<string, Reactable[]>();\n for (const reactable of reactables) {\n for (const field of reactable.fields) {\n let fields = byField.get(field);\n if (fields === undefined) {\n fields = [];\n byField.set(field, fields);\n }\n if (!fields.includes(reactable)) fields.push(reactable);\n }\n }\n return byField;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"configure.cjs","names":["getBaseAndSelfMetas","getBaseSelfAndSubMetas","fail","tagFromId","maybeResolveReferenceToId","maybeGetRuntimeConfig","isCannotBeUpdatedRule","AsyncDefault","reverseReactiveHint","getProperties","AsyncReactiveFieldImpl","KeySerde"],"sources":["../src/configure.ts"],"sourcesContent":["import { type Reactable, setAfterMetadataLocked, setBooted } from \"./config.ts\";\nimport { AsyncDefault } from \"./defaults.ts\";\nimport { type Entity } from \"./Entity.ts\";\nimport { type MaybeAbstractEntityConstructor, type TaggedId } from \"./EntityManager.ts\";\nimport {\n type EntityMetadata,\n type EnumField,\n type ManyToOneField,\n type OneToManyField,\n getBaseAndSelfMetas,\n getBaseSelfAndSubMetas,\n getMetadata,\n} from \"./EntityMetadata.ts\";\nimport { getProperties } from \"./getProperties.ts\";\nimport { maybeResolveReferenceToId, setTaggedIdDelimiter, tagFromId } from \"./keys.ts\";\nimport { reverseReactiveHint } from \"./reactiveHints.ts\";\nimport { AsyncReactiveFieldImpl } from \"./relations/AsyncReactiveField.ts\";\nimport { type ReactiveManyToManyImpl, type ReactiveReferenceImpl, type Reference } from \"./relations/index.ts\";\nimport { type ReactiveFieldImpl } from \"./relations/ReactiveField.ts\";\nimport { isCannotBeUpdatedRule } from \"./rules.ts\";\nimport { maybeGetRuntimeConfig } from \"./runtimeConfig.ts\";\nimport { KeySerde } from \"./serde.ts\";\nimport { defineLazyGetter, fail } from \"./utils.ts\";\n\nconst tagToConstructorMap = new Map<string, MaybeAbstractEntityConstructor<any>>();\nconst tableToMetaMap = new Map<string, EntityMetadata>();\nconst typeToMetaMap = new Map<string, EntityMetadata>();\n\nlet previousBootError: any;\n\n/** Performs our boot-time initialization, i.e. hooking up reactivity. */\nexport function configureMetadata(metas: EntityMetadata[]): void {\n // Add explicit \"did we already fail\" check b/c if a transformer like tsx gets a runtime error from\n // here, it can potentially suppress it, move on to another file, which will naively re-invoke\n // `configureMetadata` again, and fail with a very confusing \"Duplicate tag\" error\n if (previousBootError) {\n throw previousBootError;\n }\n try {\n populateConstructorMaps(metas);\n hookUpBaseTypeAndSubTypes(metas);\n installMetadataGetters(metas);\n sortMetasByBaseType(metas);\n setImmutableFields(metas);\n populatePolyComponentFields(metas);\n fireAfterMetadatas(metas);\n // Callers can make `config` calls during `afterMetadata` callbacks, but after that\n // we don't allow any more config changes.\n setBooted();\n // Do these after `fireAfterMetadatas`, in case afterMetadata callbacks added more defaults/rules\n copyAsyncDefaults(metas);\n reverseIndexReactivity(metas);\n installReactiveMetadataGetters(metas);\n copyRunBeforeBooksToBaseType(metas);\n } catch (e) {\n previousBootError = e;\n throw e;\n }\n}\n\n/** Installs lazy lookup getters for metadata-derived caches. */\nfunction installMetadataGetters(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n defineLazyGetter(meta, \"subTypesByType\", function buildSubTypesByType() {\n return new Map(meta.subTypes.map((st) => [st.type, st]));\n });\n defineLazyGetter(meta, \"subTypesByStiValue\", function buildSubTypesByStiValue() {\n return new Map(meta.subTypes.map((st) => [st.stiDiscriminatorValue, st]));\n });\n defineLazyGetter(meta, \"stiDiscriminatorColumnName\", function buildStiDiscriminatorColumnName() {\n const field = meta.fields[meta.stiDiscriminatorField!];\n if (field === undefined) throw new Error(`${meta.type} does not have an STI discriminator field`);\n if (field.kind !== \"enum\") throw new Error(\"Discriminator field must be an enum\");\n return (field as EnumField).serde.columns[0].columnName;\n });\n defineLazyGetter(meta, \"lazyFieldNames\", function buildLazyFieldNames() {\n return new Set(\n Object.values(meta.fields)\n .filter((f) => f.kind === \"primitive\" && f.lazy)\n .map((f) => f.fieldName),\n );\n });\n defineLazyGetter(meta, \"hasLazyColumns\", function buildHasLazyColumns() {\n return meta.lazyFieldNames!.size > 0;\n });\n defineLazyGetter(meta, \"syncDerivedFields\", function buildSyncDerivedFields() {\n return Object.values(meta.allFields)\n .filter((f) => (f.kind === \"primitive\" || f.kind === \"enum\") && f.derived === \"sync\")\n .map((f) => f.fieldName);\n });\n }\n}\n\n/** Installs lazy getters for reactivity caches after reactivity has been reverse-indexed. */\nfunction installReactiveMetadataGetters(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n defineLazyGetter(meta, \"reactables\", function buildReactables() {\n return getBaseAndSelfMetas(meta)\n .flatMap((m) => m.config.__data.reactables)\n .filter((r) => !r.isReadOnly);\n });\n defineLazyGetter(meta, \"reactablesByField\", function buildReactablesByField() {\n return indexReactablesByField(meta.reactables!);\n });\n defineLazyGetter(meta, \"reactablesIncludingReadOnly\", function buildReactablesIncludingReadOnly() {\n return getBaseAndSelfMetas(meta).flatMap((m) => m.config.__data.reactables);\n });\n defineLazyGetter(meta, \"reactablesIncludingReadOnlyByField\", function buildReactablesIncludingReadOnlyByField() {\n return indexReactablesByField(meta.reactablesIncludingReadOnly!);\n });\n defineLazyGetter(meta, \"reactiveRules\", function buildReactiveRules() {\n // We use \"AndSub\" because `reactiveRules` is called with `todo.metadata`, which is always\n // the root type, but ofc we don't want to skip subtype rules.\n //\n // I had considered filtering this list with `rr.fields.length > 0`, but even rules with 100%\n // immutable fields (so all read-only, and so not \"reactive\") need to run on initial entity creation.\n return getBaseSelfAndSubMetas(meta).flatMap((m) => m.config.__data.reactiveRules);\n });\n defineLazyGetter(meta, \"reactiveCommitRules\", function buildReactiveCommitRules() {\n // Same \"AndSub\" reasoning as `reactiveRules`, just for the post-flush/pre-commit commit rules.\n return getBaseSelfAndSubMetas(meta).flatMap((m) => m.config.__data.reactiveCommitRules);\n });\n defineLazyGetter(meta, \"hasCommitRules\", function buildHasCommitRules() {\n // True if flushing an entity of this type could trigger commit-rule work, so `em.flush` can\n // skip the whole commit-rule pass otherwise. We need *both* checks because hinted and\n // non-hinted commit rules are stored in different places:\n //\n // 1. Hinted commit rules are reverse-indexed onto their *trigger* entity's `reactiveCommitRules`,\n // which is often a *different* entity than the one the rule is declared on. I.e. a rule\n // `config.addCommitRule({ books: \"title\" }, fn)` declared on `Author` lands on\n // `Book.reactiveCommitRules`, so flushing a Book must run it even though `Book`'s own\n // `config.__data.commitRules` is empty — hence checking `reactiveCommitRules`, not `commitRules`.\n //\n // 2. Non-hinted commit rules are *not* reverse-indexed at all; they run on every insert/update of\n // the entity they're declared on (via `validateSimpleRules`). I.e. `config.addCommitRule(fn)` on\n // `Author` only ever shows up in `Author.config.__data.commitRules` with `hint === undefined`,\n // so `reactiveCommitRules` would miss it. (We filter to `hint === undefined` because hinted\n // rules are already covered by check #1.)\n return (\n meta.reactiveCommitRules!.length > 0 ||\n getBaseSelfAndSubMetas(meta).some((m) => m.config.__data.commitRules.some((r) => r.hint === undefined))\n );\n });\n }\n}\n\n// Sort metas in place by inheritance hierarchy so that the base type comes before subtypes\nfunction sortMetasByBaseType(metas: EntityMetadata[]): void {\n metas.sort(compareMetasByBaseType);\n}\n\n// Compare metas by inheritance hierarchy so that the base type sorts before subtypes\nfunction compareMetasByBaseType(a: EntityMetadata, b: EntityMetadata): number {\n if (a.baseTypes.length > 0 && b.baseTypes.length === 0) return 1;\n if (a.baseTypes.length === 0 && b.baseTypes.length > 0) return -1;\n if (a.baseTypes.some((baseType) => baseType === b)) return 1;\n if (b.baseTypes.some((baseType) => baseType === a)) return -1;\n return a.type.localeCompare(b.type);\n}\n\nfunction fireAfterMetadatas(metas: EntityMetadata[]): void {\n setAfterMetadataLocked();\n for (const meta of metas) {\n for (const fn of meta.config.__data.afterMetadataCallbacks) fn(meta);\n }\n}\n\nexport function resetConstructorMap(): void {\n tagToConstructorMap.clear();\n setTaggedIdDelimiter(\":\");\n}\n\nexport function getConstructorFromTag(tag: string): MaybeAbstractEntityConstructor<any> {\n return tagToConstructorMap.get(tag) ?? fail(`Unknown tag: \"${tag}\" `);\n}\n\nexport function getConstructorFromTaggedId(id: TaggedId): MaybeAbstractEntityConstructor<any> {\n return getConstructorFromTag(tagFromId(id));\n}\n\nexport function getMetadataForTable(tableName: string): EntityMetadata {\n return tableToMetaMap.get(tableName) ?? fail(`Unknown table ${tableName}`);\n}\n\nexport function getMetadataForType(typeName: string): EntityMetadata {\n return typeToMetaMap.get(typeName) ?? fail(`Unknown type ${typeName}`);\n}\n\n/** Returns metadata for `typeName`, if `configureMetadata` has populated the type map. */\nexport function maybeGetMetadataForType<T extends Entity = Entity>(typeName: string): EntityMetadata<T> | undefined {\n return typeToMetaMap.get(typeName) as EntityMetadata<T> | undefined;\n}\n\nexport function maybeGetConstructorFromReference(\n value: string | Entity | Reference<any, any, any> | undefined,\n): MaybeAbstractEntityConstructor<any> | undefined {\n const id = maybeResolveReferenceToId(value);\n return id ? getConstructorFromTaggedId(id) : undefined;\n}\n\nfunction populateConstructorMaps(metas: EntityMetadata[]): void {\n const runtimeConfig = maybeGetRuntimeConfig();\n const tagDelimiter = runtimeConfig && Object.hasOwn(runtimeConfig, \"tagDelimiter\") ? runtimeConfig.tagDelimiter : \":\";\n setTaggedIdDelimiter(tagDelimiter);\n\n for (const meta of metas) {\n // Add each (root) constructor into our tag -> constructor map for future lookups\n if (!meta.baseType) {\n const existing = tagToConstructorMap.get(meta.tagName);\n if (existing) throw new Error(`Duplicate tag '${meta.tagName}' for ${meta.type} and ${existing.name}`);\n tagToConstructorMap.set(meta.tagName, meta.cstr);\n }\n // Same for tables, but include subclass tables\n tableToMetaMap.set(meta.tableName, meta);\n typeToMetaMap.set(meta.type, meta);\n }\n}\n\n// Do a first pass to flag immutable fields (which we'll use in reverseReactiveHint)\nfunction setImmutableFields(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Scan rules for cannotBeUpdated so that we can set `field.immutable`\n for (const rule of meta.config.__data.rules) {\n if (isCannotBeUpdatedRule(rule.fn) && rule.fn.immutable) {\n // Usually the field will exist directly in meta.fields\n const selfField = meta.fields[rule.fn.field];\n // Or it might have come in from a base type in meta.allFields\n const baseField = meta.allFields[rule.fn.field];\n // Either way, at least one should exist\n if (!selfField && !baseField) {\n throw new Error(`Missing field '${meta.type}.${rule.fn.field}' for cannotBeUpdated at ${rule.name}`);\n }\n if (selfField) selfField.immutable = true;\n if (baseField) baseField.immutable = true;\n }\n }\n }\n}\n\n// Setup subTypes/baseTypes\nfunction hookUpBaseTypeAndSubTypes(metas: EntityMetadata[]): void {\n const metaByName = metas.reduce(\n (acc, m) => {\n acc[m.type] = m;\n return acc;\n },\n {} as Record<string, EntityMetadata>,\n );\n for (const m of metas) {\n // This is basically m.fields.mapValues to assign the primary alias\n m.allFields = Object.fromEntries(\n Object.entries(m.fields).map(([name, field]) => [name, { ...field, aliasSuffix: \"\" }]),\n );\n // Only supporting one level of inheritance for now, ideally would loop `while current !== null`\n if (m.baseType) {\n const b = metaByName[m.baseType];\n if (m.inheritanceType === \"sti\") {\n m.columns = b.columns;\n }\n m.baseTypes.push(b);\n b.subTypes.push(m);\n // Add all the base's fields to our allFields, with the base's aliasSuffix, so that in\n // `WHERE` clauses for `small_publishers`, we'll have joined in `publishers` with an\n // alias + this alias suffix, so can `WHERE` on `${alias}_b0.name = 'foo'` and get\n // to the correct table.\n //\n // Note that we don't need to do this for subtypes, because `em.find` queries aren't\n // allowed to `WHERE` against columns in their subtypes. Maybe someday we can support\n // that like the GraphQL `...on SmallPublisher` syntax, like conditional/subtype-specific\n // clauses.\n Object.entries(b.fields).forEach(([name, field]) => {\n // We use `b0` because that is what addTablePerClassJoinsAndClassTag uses to join in the base table\n const aliasSuffix = b.inheritanceType === \"cti\" ? \"_b0\" : \"\";\n if (name in m.allFields && name !== \"id\") {\n // If the base field (i.e. group) is already in `m.allFields`, it's from a CTI subtype specializing\n // a base field (i.e. `SmallPublisher.group`), in which case we don't really want it inserted/updated\n // in the `small_publishers` table itself, so we'll delete it from `m.fields`, *but* leave it in\n // m.allFields, with appropriate/overridden `otherEntity: SmallPublisherGroup` config so that it\n // can be used to reverse validation rules/RFs.\n delete m.fields[name];\n m.allFields[name].aliasSuffix = aliasSuffix;\n m.allFields[name].specialized = true;\n } else {\n m.allFields[name] = { ...field, aliasSuffix };\n }\n });\n }\n }\n // Now that base/sub links are complete, cache the hot-path meta arrays that\n // `getBaseAndSelfMetas`/`getBaseSelfAndSubMetas` would otherwise re-allocate per call.\n for (const m of metas) {\n m.baseSelfMetas = [...m.baseTypes, m];\n m.baseSelfAndSubMetas = [...m.baseTypes, m, ...m.subTypes];\n }\n}\n\n/** Copy/pastes base AsyncDefaults onto subtypes, so that subtypes can have their own default dependencies. */\nfunction copyAsyncDefaults(metas: EntityMetadata[]): void {\n for (const m of metas) {\n for (const b of m.baseTypes) {\n // Clone in the base asyncDefaults, unless we override our own\n for (const [fieldName, df] of Object.entries(b.config.__data.asyncDefaults)) {\n if (!m.config.__data.asyncDefaults[fieldName]) {\n // Given our subtype its own instance, because we might have different default dependencies.\n // I.e. from a sample domain model, something like:\n // - The base `PlanVersion.type` default depends on `{ identity: \"type\" }`\n // - The base `Plan.type` has no default itself\n // - The sub `SpecialPlanVersion` inherits type, and specializes `SPV.identity: SP`\n // - The sub `SpecialPlan.type` does have a default\n //\n // So we need to eval `PlanVersion.type` separately from `SpecialPlanVersion.type`, even\n // though they come from the same `config.setDefault` call/lambda in `PlanVersion.ts`.\n m.config.__data.asyncDefaults[fieldName] = new AsyncDefault(df.fieldName, df.fieldHint, df.fn);\n }\n }\n }\n }\n}\n\n// Now hook up our reactivity\nfunction reverseIndexReactivity(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Look for reactive validation rules to reverse\n for (const { name, hint, fn } of meta.config.__data.rules) {\n if (hint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n // For each reversal, tell its config about the reverse hint to force-re-validate\n // the original rule's instance any time it changes.\n for (const { kind, entity, path, fields } of reversals) {\n if (kind === \"update\") {\n getMetadata(entity).config.__data.reactiveRules.push({\n source: entity,\n cstr: meta.cstr,\n name,\n fields,\n path,\n fn,\n });\n }\n }\n }\n }\n\n // Same reverse-indexing as `rules` above, but for `commitRules` -> `reactiveCommitRules`.\n for (const { name, hint, fn } of meta.config.__data.commitRules) {\n if (hint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n for (const { kind, entity, path, fields } of reversals) {\n if (kind === \"update\") {\n getMetadata(entity).config.__data.reactiveCommitRules.push({\n source: entity,\n cstr: meta.cstr,\n name,\n fields,\n path,\n fn,\n });\n }\n }\n }\n }\n\n // Look for reactions to reverse\n for (const { name, hint, fn, runOnce } of meta.config.__data.reactions) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n // For each reversal, tell its config about the reverse hint to force-rerun\n // the original reaction's instance any time it changes.\n for (const { kind, entity, path, fields } of reversals) {\n getMetadata(entity).config.__data.reactables.push({\n kind: \"reaction\",\n source: entity,\n cstr: meta.cstr,\n isReadOnly: kind === \"read-only\",\n name,\n fields,\n path,\n fn,\n runOnce,\n });\n }\n }\n\n // Look for ReactiveFields, ReactiveReferences, & ReactiveManyToManys to reverse\n const reactiveRelations = Object.values(meta.allFields).filter(\n (f) =>\n f.kind === \"primitive\" ||\n (f.kind === \"m2o\" && f.derived === \"async\") ||\n (f.kind === \"enum\" && f.derived === \"async\") ||\n (f.kind === \"m2m\" && f.derived === \"async\"),\n );\n for (const field of reactiveRelations) {\n const ap = (getProperties(meta) as any)[field.fieldName] as\n | ReactiveFieldImpl<any, any, any>\n | AsyncReactiveFieldImpl<any, any, any, any>\n | ReactiveReferenceImpl<any, any, any, any>\n | ReactiveManyToManyImpl<any, any, any>\n | undefined;\n // We might have an async property configured in joist-config.json that has not yet\n // been made a `hasReactiveField` in the entity file, so avoid continuing\n // if we don't actually have a property/loadHint available.\n if (ap?.reactiveHint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, ap.reactiveHint);\n for (const { kind, entity, path, fields } of reversals) {\n getMetadata(entity).config.__data.reactables.push({\n kind: ap instanceof AsyncReactiveFieldImpl ? \"query\" : \"populate\",\n cstr: meta.cstr,\n isReadOnly: kind === \"read-only\",\n name: field.fieldName,\n path,\n fields,\n runOnce: false,\n });\n }\n }\n }\n }\n}\n\n/**\n * In addition to the canonical `meta.allFields`, we populate a `meta.polyComponentFields` to\n * disaggregates the poly's components into individual fields so that `em.find` / `parseFindQuery`\n * can support component-specific find queries.\n */\nfunction populatePolyComponentFields(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n for (const [key, field] of Object.entries(meta.allFields)) {\n if (field.kind === \"poly\") {\n meta.polyComponentFields ??= {};\n for (const comp of field.components) {\n const fieldName = `${key}${comp.otherMetadata().type}`;\n // Synthesize a m2o component that won't be used for any actual read/write serde,\n // but just to help `parseFindQuery` build `WHERE` clauses.\n meta.polyComponentFields[fieldName] = {\n kind: \"m2o\",\n fieldName,\n fieldIdName: `${fieldName}Id`,\n required: false,\n immutable: false,\n derived: false,\n serde: new KeySerde(\n comp.otherMetadata().tagName,\n fieldName,\n comp.columnName,\n field.serde.columns[0].dbType as any,\n ),\n ...comp,\n aliasSuffix: field.aliasSuffix,\n } satisfies ManyToOneField & { aliasSuffix: string };\n }\n } else if (field.kind === \"m2o\") {\n field.otherMetadata().subTypes.forEach((st) => {\n const fieldName = `${key}${st.type}`;\n meta.polyComponentFields ??= {};\n meta.polyComponentFields[fieldName] = {\n ...field,\n // a subtype specific sub-field (i.e. `publisherLargePublishers`) cannot be required (which turns into\n // an `inner join`), even if its parent is, since it won't always be present (i.e. the pointed-at publisher\n // might be a small publisher).\n required: false,\n fieldName,\n fieldIdName: `${fieldName}Id`,\n otherMetadata: () => st,\n } satisfies ManyToOneField & { aliasSuffix: string };\n });\n } else if (field.kind === \"o2m\") {\n field.otherMetadata().subTypes.forEach((st) => {\n const fieldName = `${key}${st.type}`;\n meta.polyComponentFields ??= {};\n meta.polyComponentFields[fieldName] = {\n ...field,\n fieldName,\n fieldIdName: `${fieldName}Id`,\n otherMetadata: () => st,\n } satisfies OneToManyField & { aliasSuffix: string };\n });\n }\n }\n }\n}\n\nfunction copyRunBeforeBooksToBaseType(meta: EntityMetadata[]): void {\n for (const m of meta) {\n for (const b of m.baseTypes) {\n b.config.__data.runHooksBefore.push(...m.config.__data.runHooksBefore);\n }\n }\n}\n\n/** Indexes reactables once so field setters don't scan every reactable's fields. */\nfunction indexReactablesByField(reactables: readonly Reactable[]): Map<string, Reactable[]> {\n const byField = new Map<string, Reactable[]>();\n for (const reactable of reactables) {\n for (const field of reactable.fields) {\n let fields = byField.get(field);\n if (fields === undefined) {\n fields = [];\n byField.set(field, fields);\n }\n if (!fields.includes(reactable)) fields.push(reactable);\n }\n }\n return byField;\n}\n"],"mappings":"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"}
@@ -164,10 +164,7 @@ function hookUpBaseTypeAndSubTypes(metas) {
164
164
  }]));
165
165
  if (m.baseType) {
166
166
  const b = metaByName[m.baseType];
167
- m.columns = {
168
- ...b.columns,
169
- ...m.columns
170
- };
167
+ if (m.inheritanceType === "sti") m.columns = b.columns;
171
168
  m.baseTypes.push(b);
172
169
  b.subTypes.push(m);
173
170
  Object.entries(b.fields).forEach(([name, field]) => {