uql-orm 0.65.1 → 0.67.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/dist/browser/querier/httpQuerier.js +1 -8
  2. package/dist/browser/uql-browser.min.js.map +5 -5
  3. package/dist/bunSql/bunSql.util.d.ts +2 -6
  4. package/dist/bunSql/bunSql.util.js +2 -6
  5. package/dist/bunSql/bunSqlQuerier.d.ts +2 -5
  6. package/dist/bunSql/bunSqlQuerier.js +2 -5
  7. package/dist/cockroachdb/cockroachDialect.d.ts +4 -13
  8. package/dist/cockroachdb/cockroachDialect.js +4 -13
  9. package/dist/context/context.browser.js +2 -10
  10. package/dist/context/context.d.ts +4 -17
  11. package/dist/context/context.js +4 -17
  12. package/dist/dialect/abstractDialect.d.ts +4 -19
  13. package/dist/dialect/abstractDialect.js +2 -20
  14. package/dist/dialect/abstractSqlDialect.d.ts +47 -212
  15. package/dist/dialect/abstractSqlDialect.js +68 -222
  16. package/dist/dialect/aliases.d.ts +2 -12
  17. package/dist/dialect/aliases.js +4 -12
  18. package/dist/dialect/hydrateColumn.d.ts +2 -6
  19. package/dist/dialect/hydrateColumn.js +3 -13
  20. package/dist/dialect/jsonArrayElemMatchUtils.d.ts +1 -7
  21. package/dist/dialect/jsonArrayElemMatchUtils.js +1 -7
  22. package/dist/dialect/jsonSql.d.ts +6 -27
  23. package/dist/dialect/jsonSql.js +6 -27
  24. package/dist/dialect/mergeSqlDialect.d.ts +4 -22
  25. package/dist/dialect/mergeSqlDialect.js +4 -22
  26. package/dist/dialect/mysqlLikeSqlDialect.d.ts +11 -37
  27. package/dist/dialect/mysqlLikeSqlDialect.js +35 -51
  28. package/dist/dialect/pgLikeSqlDialect.d.ts +8 -22
  29. package/dist/dialect/pgLikeSqlDialect.js +36 -39
  30. package/dist/dialect/queryContext.d.ts +4 -22
  31. package/dist/dialect/queryContext.js +4 -22
  32. package/dist/dialect/queryJoins.d.ts +3 -12
  33. package/dist/dialect/queryJoins.js +3 -12
  34. package/dist/dialect/vectorCast.d.ts +2 -12
  35. package/dist/dialect/vectorCast.js +3 -19
  36. package/dist/dialect/vectorSqlDialect.d.ts +8 -38
  37. package/dist/dialect/vectorSqlDialect.js +7 -38
  38. package/dist/entity/decorator/bag.d.ts +6 -19
  39. package/dist/entity/decorator/bag.js +6 -22
  40. package/dist/entity/decorator/entity.d.ts +5 -10
  41. package/dist/entity/decorator/entity.js +2 -7
  42. package/dist/entity/decorator/members.d.ts +10 -31
  43. package/dist/entity/decorator/members.js +3 -12
  44. package/dist/entity/metadata/definition.d.ts +5 -21
  45. package/dist/entity/metadata/definition.js +69 -91
  46. package/dist/http/handler.d.ts +2 -14
  47. package/dist/index.d.ts +3 -1
  48. package/dist/index.js +3 -1
  49. package/dist/libsql/libsqlDialect.d.ts +1 -8
  50. package/dist/libsql/libsqlDialect.js +1 -8
  51. package/dist/maria/mariaDialect.d.ts +3 -5
  52. package/dist/maria/mariaDialect.js +5 -5
  53. package/dist/maria/mariadbQuerier.js +2 -2
  54. package/dist/maria/mariadbQuerierPool.js +1 -6
  55. package/dist/migrate/builder/migrationBuilder.js +3 -19
  56. package/dist/migrate/builder/splitSqlStatements.d.ts +1 -14
  57. package/dist/migrate/builder/splitSqlStatements.js +2 -22
  58. package/dist/migrate/builder/types.d.ts +2 -15
  59. package/dist/migrate/cli-config.js +2 -11
  60. package/dist/migrate/cli.js +2 -7
  61. package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -15
  62. package/dist/migrate/codegen/entityCodeGenerator.js +15 -44
  63. package/dist/migrate/codegen/fieldOptionsSource.d.ts +1 -8
  64. package/dist/migrate/codegen/fieldOptionsSource.js +3 -22
  65. package/dist/migrate/ddl/indexDdl.d.ts +2 -5
  66. package/dist/migrate/ddl/indexDdl.js +2 -5
  67. package/dist/migrate/ddl/pgIndexDdl.d.ts +3 -13
  68. package/dist/migrate/ddl/pgIndexDdl.js +3 -13
  69. package/dist/migrate/generator/definitionToNode.d.ts +2 -9
  70. package/dist/migrate/generator/definitionToNode.js +3 -17
  71. package/dist/migrate/generator/indexNodeToSchema.d.ts +2 -3
  72. package/dist/migrate/generator/indexNodeToSchema.js +2 -3
  73. package/dist/migrate/generator/mongoCommand.d.ts +1 -8
  74. package/dist/migrate/generator/mongoSchemaGenerator.d.ts +1 -8
  75. package/dist/migrate/generator/mongoSchemaGenerator.js +1 -8
  76. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +6 -26
  77. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +9 -41
  78. package/dist/migrate/introspection/baseSqlIntrospector.js +0 -1
  79. package/dist/migrate/introspection/mongoIntrospector.d.ts +3 -1
  80. package/dist/migrate/introspection/mongoIntrospector.js +48 -46
  81. package/dist/migrate/introspection/mssqlIntrospector.d.ts +4 -4
  82. package/dist/migrate/introspection/mssqlIntrospector.js +18 -27
  83. package/dist/migrate/introspection/mysqlIntrospector.d.ts +7 -2
  84. package/dist/migrate/introspection/mysqlIntrospector.js +16 -14
  85. package/dist/migrate/introspection/postgresIntrospector.d.ts +24 -9
  86. package/dist/migrate/introspection/postgresIntrospector.js +68 -59
  87. package/dist/migrate/introspection/sqliteIntrospector.d.ts +1 -1
  88. package/dist/migrate/introspection/sqliteIntrospector.js +8 -10
  89. package/dist/migrate/migrator.d.ts +9 -53
  90. package/dist/migrate/migrator.js +32 -65
  91. package/dist/migrate/schemaGenerator.d.ts +20 -66
  92. package/dist/migrate/schemaGenerator.js +32 -93
  93. package/dist/mongo/mongoDialect.d.ts +21 -53
  94. package/dist/mongo/mongoDialect.js +25 -70
  95. package/dist/mongo/mongodbQuerier.d.ts +5 -8
  96. package/dist/mongo/mongodbQuerier.js +31 -65
  97. package/dist/mssql/mssqlDialect.d.ts +8 -34
  98. package/dist/mssql/mssqlDialect.js +37 -51
  99. package/dist/mssql/mssqlQuerier.d.ts +37 -4
  100. package/dist/mssql/mssqlQuerier.js +2 -2
  101. package/dist/mssql/mssqlWireTypes.d.ts +2 -14
  102. package/dist/mssql/mssqlWireTypes.js +2 -14
  103. package/dist/nestjs/uqlModule.js +2 -7
  104. package/dist/pglite/pgliteQuerier.d.ts +1 -9
  105. package/dist/pglite/pgliteQuerierPool.d.ts +4 -26
  106. package/dist/pglite/pgliteQuerierPool.js +3 -18
  107. package/dist/postgres/abstractPgQuerierPool.d.ts +1 -8
  108. package/dist/postgres/abstractPgQuerierPool.js +1 -8
  109. package/dist/postgres/pgNumericTypes.d.ts +3 -26
  110. package/dist/postgres/pgNumericTypes.js +3 -26
  111. package/dist/postgres/postgresDialect.d.ts +4 -10
  112. package/dist/postgres/postgresDialect.js +4 -10
  113. package/dist/querier/abstractQuerier.d.ts +35 -103
  114. package/dist/querier/abstractQuerier.js +105 -201
  115. package/dist/querier/abstractSharedHandleQuerierPool.d.ts +3 -17
  116. package/dist/querier/abstractSharedHandleQuerierPool.js +3 -17
  117. package/dist/querier/abstractSqlQuerier.d.ts +15 -36
  118. package/dist/querier/abstractSqlQuerier.js +49 -131
  119. package/dist/schema/canonicalType.d.ts +3 -21
  120. package/dist/schema/canonicalType.js +22 -67
  121. package/dist/schema/dependencyGraph.d.ts +2 -8
  122. package/dist/schema/dependencyGraph.js +2 -32
  123. package/dist/schema/index.d.ts +1 -25
  124. package/dist/schema/index.js +0 -26
  125. package/dist/schema/indexColumns.d.ts +1 -8
  126. package/dist/schema/indexColumns.js +1 -8
  127. package/dist/schema/indexDifferences.d.ts +7 -40
  128. package/dist/schema/indexDifferences.js +6 -31
  129. package/dist/schema/schemaAST.d.ts +8 -175
  130. package/dist/schema/schemaAST.js +13 -365
  131. package/dist/schema/schemaASTBuilder.d.ts +2 -24
  132. package/dist/schema/schemaASTBuilder.js +6 -41
  133. package/dist/schema/schemaASTDiffer.d.ts +6 -46
  134. package/dist/schema/schemaASTDiffer.js +8 -56
  135. package/dist/schema/types.d.ts +5 -61
  136. package/dist/schema/types.js +3 -6
  137. package/dist/sqlite/abstractSqliteQuerier.d.ts +1 -8
  138. package/dist/sqlite/localSqliteQuerierPool.d.ts +1 -7
  139. package/dist/sqlite/localSqliteQuerierPool.js +1 -7
  140. package/dist/sqlite/nodeSqliteQuerierPool.d.ts +2 -7
  141. package/dist/sqlite/nodeSqliteQuerierPool.js +2 -7
  142. package/dist/sqlite/sqliteDialect.d.ts +5 -20
  143. package/dist/sqlite/sqliteDialect.js +29 -35
  144. package/dist/turso/tursoDialect.d.ts +4 -6
  145. package/dist/turso/tursoDialect.js +4 -6
  146. package/dist/turso/tursoLocalQuerierPool.d.ts +1 -7
  147. package/dist/turso/tursoLocalQuerierPool.js +1 -7
  148. package/dist/turso/tursoQuerierPool.d.ts +2 -6
  149. package/dist/turso/tursoQuerierPool.js +2 -6
  150. package/dist/turso/tursoSessionQuerier.d.ts +1 -7
  151. package/dist/turso/tursoSessionQuerier.js +1 -7
  152. package/dist/type/dialect.d.ts +42 -94
  153. package/dist/type/dialect.js +3 -13
  154. package/dist/type/entity.d.ts +189 -551
  155. package/dist/type/entity.js +26 -9
  156. package/dist/type/logger.d.ts +2 -14
  157. package/dist/type/migration.d.ts +9 -38
  158. package/dist/type/querier.d.ts +9 -28
  159. package/dist/type/querierPool.d.ts +4 -26
  160. package/dist/type/query.d.ts +28 -78
  161. package/dist/type/query.js +2 -7
  162. package/dist/type/queryAggregate.d.ts +18 -98
  163. package/dist/type/queryRaw.d.ts +1 -8
  164. package/dist/type/queryRaw.js +1 -8
  165. package/dist/type/queryWhere.d.ts +13 -61
  166. package/dist/type/universalQuerier.d.ts +18 -105
  167. package/dist/type/utility.d.ts +12 -24
  168. package/dist/type/vector.d.ts +8 -38
  169. package/dist/type/vector.js +1 -1
  170. package/dist/type/wire.d.ts +2 -5
  171. package/dist/util/dialect.util.d.ts +9 -27
  172. package/dist/util/dialect.util.js +10 -27
  173. package/dist/util/field.util.d.ts +5 -37
  174. package/dist/util/field.util.js +7 -50
  175. package/dist/util/fieldOption.util.d.ts +7 -15
  176. package/dist/util/fieldOption.util.js +1 -1
  177. package/dist/util/filters.util.d.ts +2 -5
  178. package/dist/util/filters.util.js +2 -5
  179. package/dist/util/logger.d.ts +2 -6
  180. package/dist/util/logger.js +2 -6
  181. package/dist/util/object.util.d.ts +2 -6
  182. package/dist/util/object.util.js +1 -5
  183. package/dist/util/raw.d.ts +3 -23
  184. package/dist/util/relationQuery.util.d.ts +3 -14
  185. package/dist/util/relationQuery.util.js +3 -14
  186. package/dist/util/rowKey.util.d.ts +2 -10
  187. package/dist/util/rowKey.util.js +2 -10
  188. package/dist/util/sql.util.d.ts +6 -37
  189. package/dist/util/sql.util.js +13 -73
  190. package/dist/util/sqlLiteral.d.ts +2 -13
  191. package/dist/util/sqlLiteral.js +8 -13
  192. package/dist/util/string.util.js +0 -2
  193. package/package.json +4 -4
@@ -46,13 +46,7 @@ export declare class Migrator {
46
46
  to?: string;
47
47
  step?: number;
48
48
  }): Promise<MigrationResult[]>;
49
- /**
50
- * Narrow a run list by `to`/`step` and execute it, stopping at the first failure.
51
- *
52
- * Both directions do exactly this and differ only in the list they start from: `up` takes the
53
- * pending migrations, `down` the executed ones reversed. Keeping the selection in one place is what
54
- * makes `--to` and `--step` mean the same thing whichever way you are going.
55
- */
49
+ /** Runs the list narrowed by `to`/`step`, stopping at the first failure: `up` over the pending, `down` over the executed reversed. */
56
50
  private runInOrder;
57
51
  /**
58
52
  * Run a single migration, within a transaction where the dialect has one for it
@@ -73,29 +67,13 @@ export declare class Migrator {
73
67
  */
74
68
  getDiffs(): Promise<SchemaDiff[]>;
75
69
  /**
76
- * One AST spanning every schema the entities claim, each table stamped with the schema it was read
77
- * from. Read per schema rather than all at once, so a table comes back keyed exactly as the entity
78
- * that wants it spells the key: `undefined` on both sides for the connection's default, a name on
79
- * both sides otherwise. Ordinarily that is one schema and one pass, as before, and that pass keeps
80
- * {@link schemaIntrospector} so a caller that replaced it still wins.
81
- */
82
- private introspectClaimedSchemas;
83
- /**
84
- * Applies the entity schema to the database: every registered entity, or the one `entity` names.
85
- *
86
- * The whole surface is this and {@link planSync}, which answers the same question without running
87
- * it - `force` and a single entity included, so `--dry-run` means the same thing whatever else was
88
- * asked for.
70
+ * The tables `entities` name, read a schema at a time so each is keyed as its entity spells it. Those
71
+ * alone: nothing else is diffed, and another table can be dropped mid-scan by whatever else is running.
89
72
  */
73
+ private introspectEntities;
74
+ /** Applies the entity schema: every entity, or the one `entity` names. {@link planSync} answers the same without running it. */
90
75
  sync(options?: SyncOptions): Promise<void>;
91
- /**
92
- * Every table dropped and recreated.
93
- *
94
- * Both directions span the whole entity set rather than looping an entity at a time. A per-entity
95
- * AST cannot resolve a cross-entity foreign key, so the old create loop silently produced a schema
96
- * with no referential integrity; and the old drop loop went in reverse *declaration* order, which
97
- * says nothing about the relation graph and is rejected as soon as the constraints are really there.
98
- */
76
+ /** Every table dropped and recreated, the whole entity set at once, so foreign keys resolve and drop in graph order. */
99
77
  private forceStatements;
100
78
  /**
101
79
  * The DDL for one entity: {@link planSync} narrowed to the table it names. A new table costs one
@@ -114,14 +92,7 @@ export declare class Migrator {
114
92
  * statements rather than a summary of a second, differently-computed diff.
115
93
  */
116
94
  planSync(options?: SyncOptions): Promise<string[]>;
117
- /**
118
- * New tables are emitted together, never one at a time: a single-entity AST has no other table for a
119
- * relation to resolve against, so every cross-entity foreign key was dropped and generated schemas
120
- * carried none. Spanning the graph is also what lets a cyclic relation (any `createdBy`
121
- * back-reference) be created at all.
122
- *
123
- * Empty in, empty out, so a diff with no new tables does not build an AST for the whole graph.
124
- */
95
+ /** The new tables, created together so a foreign key between them, cyclic included, resolves. Empty in, empty out. */
125
96
  private createSchema;
126
97
  /**
127
98
  * The pending diffs a sync or a generated migration acts on: the tables to create and the tables to
@@ -184,22 +155,7 @@ export interface BuilderMigrationDefinition<Q extends Querier = SqlQuerier> {
184
155
  down(builder: IMigrationBuilder, querier: Q): Promise<void>;
185
156
  }
186
157
  /**
187
- * Define a migration using the type-safe builder API.
188
- *
189
- * @example
190
- * ```ts
191
- * export default defineBuilderMigration({
192
- * async up(m) {
193
- * await m.createTable('users', (t) => {
194
- * t.id();
195
- * t.string('email', { length: 255 }).unique();
196
- * t.timestamps();
197
- * });
198
- * },
199
- * async down(m) {
200
- * await m.dropTable('users');
201
- * }
202
- * });
203
- * ```
158
+ * Defines a migration with the builder:
159
+ * `defineBuilderMigration({ up: (m) => m.createTable('users', (t) => t.id()), down: (m) => m.dropTable('users') })`.
204
160
  */
205
161
  export declare function defineBuilderMigration<Q extends Querier = SqlQuerier>(migration: BuilderMigrationDefinition<Q>): MigrationDefinition<Q>;
@@ -2,7 +2,7 @@ import { mkdir, readdir, writeFile } from 'node:fs/promises';
2
2
  import { basename, extname, join } from 'node:path';
3
3
  import { pathToFileURL } from 'node:url';
4
4
  import { getEntities, getMeta } from '../entity/index.js';
5
- import { introspectSchema, SchemaAST } from '../schema/index.js';
5
+ import { SchemaAST } from '../schema/index.js';
6
6
  import { LoggerWrapper } from '../util/index.js';
7
7
  import { buildMigrationModule } from './codegen/migrationFile.js';
8
8
  import { introspectorFor } from './introspection/registry.js';
@@ -88,13 +88,7 @@ export class Migrator {
88
88
  const executedMigrations = migrations.filter((m) => executedSet.has(m.name)).reverse(); // Rollback in reverse order
89
89
  return this.runInOrder(executedMigrations, 'down', options);
90
90
  }
91
- /**
92
- * Narrow a run list by `to`/`step` and execute it, stopping at the first failure.
93
- *
94
- * Both directions do exactly this and differ only in the list they start from: `up` takes the
95
- * pending migrations, `down` the executed ones reversed. Keeping the selection in one place is what
96
- * makes `--to` and `--step` mean the same thing whichever way you are going.
97
- */
91
+ /** Runs the list narrowed by `to`/`step`, stopping at the first failure: `up` over the pending, `down` over the executed reversed. */
98
92
  async runInOrder(migrations, direction, options) {
99
93
  let selected = migrations;
100
94
  if (options.to) {
@@ -211,7 +205,7 @@ export class Migrator {
211
205
  */
212
206
  async getDiffs() {
213
207
  const generator = await this.getSchemaGenerator();
214
- const ast = await this.introspectClaimedSchemas();
208
+ const ast = await this.introspectEntities(this.entities);
215
209
  // Both sides built once: the database's above, the entities' here. Left to `diffSchema`, each
216
210
  // entity would rebuild the whole AST, which is quadratic in the number of entities. Absent on a
217
211
  // generator that compares no schema of its own - MongoDB, which reads only indexes.
@@ -223,29 +217,22 @@ export class Migrator {
223
217
  });
224
218
  }
225
219
  /**
226
- * One AST spanning every schema the entities claim, each table stamped with the schema it was read
227
- * from. Read per schema rather than all at once, so a table comes back keyed exactly as the entity
228
- * that wants it spells the key: `undefined` on both sides for the connection's default, a name on
229
- * both sides otherwise. Ordinarily that is one schema and one pass, as before, and that pass keeps
230
- * {@link schemaIntrospector} so a caller that replaced it still wins.
220
+ * The tables `entities` name, read a schema at a time so each is keyed as its entity spells it. Those
221
+ * alone: nothing else is diffed, and another table can be dropped mid-scan by whatever else is running.
231
222
  */
232
- async introspectClaimedSchemas() {
233
- const claimed = new Set(this.entities.map((entity) => this.pool.dialect.resolveSchema(getMeta(entity))));
223
+ async introspectEntities(entities) {
224
+ const { dialect } = this.pool;
225
+ const bySchema = Map.groupBy(new Set(entities), (entity) => dialect.resolveSchema(getMeta(entity)));
234
226
  const merged = new SchemaAST();
235
- for (const schema of claimed) {
236
- for (const table of (await introspectSchema(this.schemaIntrospectorFor(schema))).getTables()) {
227
+ for (const [schema, members] of bySchema) {
228
+ const tables = members.map((entity) => dialect.resolveTableAlias(getMeta(entity)));
229
+ for (const table of (await this.schemaIntrospectorFor(schema).introspect(tables)).getTables()) {
237
230
  merged.addTable(table);
238
231
  }
239
232
  }
240
233
  return merged;
241
234
  }
242
- /**
243
- * Applies the entity schema to the database: every registered entity, or the one `entity` names.
244
- *
245
- * The whole surface is this and {@link planSync}, which answers the same question without running
246
- * it - `force` and a single entity included, so `--dry-run` means the same thing whatever else was
247
- * asked for.
248
- */
235
+ /** Applies the entity schema: every entity, or the one `entity` names. {@link planSync} answers the same without running it. */
249
236
  async sync(options = {}) {
250
237
  const statements = await this.planSync(options);
251
238
  if (statements.length) {
@@ -255,14 +242,7 @@ export class Migrator {
255
242
  this.logger.logSchema('Schema is already in sync.');
256
243
  }
257
244
  }
258
- /**
259
- * Every table dropped and recreated.
260
- *
261
- * Both directions span the whole entity set rather than looping an entity at a time. A per-entity
262
- * AST cannot resolve a cross-entity foreign key, so the old create loop silently produced a schema
263
- * with no referential integrity; and the old drop loop went in reverse *declaration* order, which
264
- * says nothing about the relation graph and is rejected as soon as the constraints are really there.
265
- */
245
+ /** Every table dropped and recreated, the whole entity set at once, so foreign keys resolve and drop in graph order. */
266
246
  forceStatements(generator) {
267
247
  return [
268
248
  ...generator.generateDropSchema(this.entities, { ifExists: true, cascade: true }),
@@ -276,14 +256,17 @@ export class Migrator {
276
256
  */
277
257
  async planEntity(generator, entity, options) {
278
258
  const meta = getMeta(entity);
279
- const introspector = this.schemaIntrospectorFor(this.pool.dialect.resolveSchema(meta));
259
+ const { dialect } = this.pool;
260
+ const introspector = this.schemaIntrospectorFor(dialect.resolveSchema(meta));
280
261
  const tableName = generator.resolveTableName(meta);
281
- return (await introspector.tableExists(tableName))
282
- ? this.alterFromEntity(generator, entity, (await introspectSchema(introspector)).getTable(tableName), options)
283
- : // Spanning the whole set, so a foreign key resolves against the tables it points at, and
284
- // always including this entity: pinned to an explicit `entities` list, a sync of one outside
285
- // it emitted nothing at all. `only` is what keeps the statements to this table.
286
- generator.generateCreateSchema(this.entitiesWith(entity), { only: [tableName], ifNotExists: true });
262
+ if (!(await introspector.tableExists(dialect.resolveTableAlias(meta)))) {
263
+ // Spanning the whole set, so a foreign key resolves against the tables it points at, and always
264
+ // including this entity: `only` is what keeps the statements to this table.
265
+ return generator.generateCreateSchema(this.entitiesWith(entity), { only: [tableName], ifNotExists: true });
266
+ }
267
+ // With the tables it references, which its foreign keys resolve against.
268
+ const ast = await this.introspectEntities([entity, ...referencedEntities(meta)]);
269
+ return this.alterFromEntity(generator, entity, ast.getTable(tableName), options);
287
270
  }
288
271
  /** The same for one entity against the table it already has, and nothing where the two agree. */
289
272
  alterFromEntity(generator, entity, table, options) {
@@ -319,14 +302,7 @@ export class Migrator {
319
302
  ...altered.flatMap((diff) => generator.generateAlterTable(this.filterDiff(diff, options))),
320
303
  ];
321
304
  }
322
- /**
323
- * New tables are emitted together, never one at a time: a single-entity AST has no other table for a
324
- * relation to resolve against, so every cross-entity foreign key was dropped and generated schemas
325
- * carried none. Spanning the graph is also what lets a cyclic relation (any `createdBy`
326
- * back-reference) be created at all.
327
- *
328
- * Empty in, empty out, so a diff with no new tables does not build an AST for the whole graph.
329
- */
305
+ /** The new tables, created together so a foreign key between them, cyclic included, resolves. Empty in, empty out. */
330
306
  createSchema(generator, tableNames) {
331
307
  return tableNames.length ? generator.generateCreateSchema(this.entities, { only: tableNames }) : [];
332
308
  }
@@ -484,23 +460,8 @@ export function defineMigration(migration) {
484
460
  return migration;
485
461
  }
486
462
  /**
487
- * Define a migration using the type-safe builder API.
488
- *
489
- * @example
490
- * ```ts
491
- * export default defineBuilderMigration({
492
- * async up(m) {
493
- * await m.createTable('users', (t) => {
494
- * t.id();
495
- * t.string('email', { length: 255 }).unique();
496
- * t.timestamps();
497
- * });
498
- * },
499
- * async down(m) {
500
- * await m.dropTable('users');
501
- * }
502
- * });
503
- * ```
463
+ * Defines a migration with the builder:
464
+ * `defineBuilderMigration({ up: (m) => m.createTable('users', (t) => t.id()), down: (m) => m.dropTable('users') })`.
504
465
  */
505
466
  export function defineBuilderMigration(migration) {
506
467
  return {
@@ -509,3 +470,9 @@ export function defineBuilderMigration(migration) {
509
470
  down: async (querier) => migration.down(await migrationBuilderFor(querier), querier),
510
471
  };
511
472
  }
473
+ /** The entities `meta` points at, through a relation or a foreign key field. */
474
+ function referencedEntities(meta) {
475
+ const fields = Object.values(meta.fields).flatMap((field) => field?.references?.() ?? []);
476
+ const relations = Object.values(meta.relations).flatMap((relation) => relation?.entity?.() ?? []);
477
+ return [...fields, ...relations];
478
+ }
@@ -28,35 +28,18 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
28
28
  /** Escape an identifier (table name, column name, etc.) */
29
29
  protected escapeId(identifier: string): string;
30
30
  /**
31
- * How an auto-increment key of `type` is spelled: the type as any other column renders it, plus what
32
- * the engine appends to make it generated.
33
- *
34
- * Derived rather than a fixed string per dialect, because a foreign key column takes its type from
35
- * the key it points at, resolved through the same canonical type. A key whose spelling ignored that
36
- * type could never be referenced: `@Id({ columnType: 'int' })` emitted `BIGINT` while the column
37
- * pointing at it emitted `INT`, and every engine refuses that constraint.
31
+ * An auto-increment key's type: its canonical type rendered like any column's, plus the engine's generated
32
+ * suffix, so a foreign key taking its type from this key gets the same one.
38
33
  */
39
34
  protected serialType(type: CanonicalType): string;
40
- /**
41
- * The SQL type a column is spelled with: the engine's generated-key form for an auto-increment key,
42
- * the canonical type otherwise.
43
- *
44
- * One method because both paths that spell a column need the same answer - written twice, with a
45
- * comment asking the two to stay in sync, is how the generated key and the column referencing it
46
- * came to disagree in the first place.
47
- */
35
+ /** The SQL type a column is spelled with: the generated-key form for an auto-increment key, the canonical type otherwise. */
48
36
  protected columnSqlType(col: ColumnNode): string;
49
37
  protected canonicalTypeToSql(type: CanonicalType): string;
50
38
  /** The entity side as an AST, carrying this generator's default referential action. */
51
39
  buildAST(entities: readonly Type<object>[]): SchemaAST;
52
40
  /**
53
- * Every `CREATE TABLE` for `entities`, then their foreign keys.
54
- *
55
- * Two phases rather than inline constraints, because a relation graph is routinely cyclic: any
56
- * `createdBy`-style back-reference makes `A` reference `B` while `B` references `A`, and no create
57
- * order satisfies that. TypeORM's schema builder splits for the same reason (`createNewTables()`
58
- * then `createForeignKeys()`). SQLite is the exception and keeps them inline: it cannot `ALTER` a
59
- * foreign key in, but it resolves targets lazily, so a forward reference is fine there.
41
+ * Every `CREATE TABLE` for `entities`, then their foreign keys, since a relation graph is routinely
42
+ * cyclic. SQLite keeps them inline: it cannot add one later, and resolves a forward reference lazily.
60
43
  */
61
44
  generateCreateSchema(entities: readonly Type<object>[], options?: CreateSchemaOptions): string[];
62
45
  /**
@@ -88,13 +71,8 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
88
71
  */
89
72
  generateDropIndex(tableName: string, indexName: string, schema?: string): string;
90
73
  /**
91
- * A column definition from a {@link ColumnSchema}, whose type is already the engine's own spelling
92
- * and may carry its own size.
93
- *
94
- * Kept apart from {@link generateColumnFromNode} rather than folded into it: a `ColumnSchema` has no
95
- * `enum`, because introspection reads one back as a `CHECK` constraint and not as a property of the
96
- * column, so only the node knows enough to emit that clause. Both spell the definition through
97
- * {@link renderColumn}, which is the part that must not be written twice.
74
+ * A column definition from a {@link ColumnSchema}, whose type is already the engine's spelling. Apart from
75
+ * {@link generateColumnFromNode}, which alone knows an `enum`; both render through {@link renderColumn}.
98
76
  */
99
77
  generateColumnDefinitionFromSchema(column: ColumnSchema): string;
100
78
  /**
@@ -104,35 +82,25 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
104
82
  * enum's `CHECK` comes last, the only place MariaDB takes it.
105
83
  */
106
84
  private renderColumn;
85
+ /**
86
+ * The column type a field gets, resolved as its table resolves it. A field alone cannot tell that it is
87
+ * one column of a composite key, which its table never makes serial.
88
+ */
107
89
  getSqlType(field: FieldMeta): string;
108
90
  /** The statements that alter `column` in place, as this dialect spells them. */
109
91
  generateAlterColumnStatements(tableName: string, column: ColumnSchema, newDefinition: string): string[];
110
92
  /** The inline ` COMMENT '...'` a column declaration carries, where the engine takes one there. */
111
93
  generateColumnComment(comment: string): string;
112
- /**
113
- * The `COMMENT ON` statements a table and its columns need, on an engine that carries a comment
114
- * that way. Empty on the others: MySQL writes them inline, SQLite has no comments at all.
115
- *
116
- * Emitted after the `CREATE TABLE` rather than folded into it, which is what `COMMENT ON` requires -
117
- * and what makes a comment reach Postgres, where it was previously read as unsupported and dropped.
118
- */
94
+ /** The `COMMENT ON` statements a table and its columns need, after the `CREATE TABLE`, where the engine uses them. */
119
95
  protected generateCommentStatements(table: TableNode): string[];
120
- /**
121
- * The `COMMENT ON COLUMN` one column needs, on an engine that carries a comment that way.
122
- *
123
- * Shared by `CREATE TABLE` and every path that adds a column: written only for the former, a column
124
- * added later reached the database undocumented, the way its enum `CHECK` used to.
125
- */
96
+ /** The `COMMENT ON COLUMN` a column needs where the engine uses one, for `CREATE TABLE` and every path adding a column. */
126
97
  protected generateColumnCommentStatement(tableName: string, column: {
127
98
  name: string;
128
99
  comment?: string;
129
100
  }, schema?: string): string[];
130
101
  /**
131
- * How this entity differs from the table the database reported, as the migrator's `SchemaDiff`.
132
- *
133
- * The comparison itself is {@link diffTable}, the same one drift detection runs, so the two can no
134
- * longer disagree about what has changed. Only two things are this side's own: the entity becomes a
135
- * table node first, and types are compared as the *engine* would store them - see `normalizeType`.
102
+ * How the entity differs from the table the database reported, compared by {@link diffTable}, the one
103
+ * drift detection runs, with types normalized as the engine stores them.
136
104
  */
137
105
  diffSchema(entity: Type<object>, currentTable: TableNode | undefined, desiredAst?: SchemaAST): SchemaDiff | undefined;
138
106
  /**
@@ -171,13 +139,7 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
171
139
  generateRenameTableSql(oldName: string, newName: string): string;
172
140
  /** `raw` is split, being the one SQL no generator wrote. */
173
141
  generateOperation(operation: AnyMigrationOperation): string[];
174
- /**
175
- * `ADD COLUMN`, plus the constraint and index the column declares.
176
- *
177
- * `CREATE TABLE` lifts a column's `references` and `index` onto the table it is building; this had
178
- * no lift, so a hand-written `addColumn(...).references(...).index()` emitted the column alone and
179
- * dropped both without a word.
180
- */
142
+ /** `ADD COLUMN`, plus the foreign key and index the column declares, as `CREATE TABLE` lifts them. */
181
143
  generateAddColumnSql(tableName: string, column: FullColumnDefinition): string[];
182
144
  generateAlterColumnSql(tableName: string, columnName: string, column: FullColumnDefinition): string[];
183
145
  generateDropColumnSql(tableName: string, columnName: string): string[];
@@ -198,12 +160,8 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
198
160
  */
199
161
  generateAddPrimaryKeySql(tableName: string, columns: readonly string[], name?: string): string;
200
162
  /**
201
- * Drops whatever key the table has.
202
- *
203
- * `constraintName` has to be what the constraint is *actually* called: the name introspection
204
- * reported for a key the database already had, or the derived one for a key this generator itself
205
- * added, which is what reversing a migration drops. Guessing either way names nothing. MySQL takes
206
- * no name at all - a table's key is always `PRIMARY` there.
163
+ * Drops the table's key, by the name the constraint really has: introspected, or derived where this
164
+ * generator added it. MySQL takes no name.
207
165
  */
208
166
  generateDropPrimaryKeySql(tableName: string, constraintName?: string): string;
209
167
  /**
@@ -214,11 +172,7 @@ export declare class SqlSchemaGenerator implements SchemaGenerator {
214
172
  private assertPrimaryKeyAlterable;
215
173
  }
216
174
  /**
217
- * The entities as an AST, named the way `generator` names things.
218
- *
219
- * Its resolvers rather than a naming strategy, because the two disagree: a strategy renames whatever
220
- * it is handed, while a generator leaves an explicit `@Entity({ name })` alone. Build the AST the
221
- * other way and the table is created under one name and compared under another, which reports every
222
- * table of a project using a naming strategy as both missing and unexpected.
175
+ * The entities as an AST, named by `generator`'s resolvers rather than a naming strategy, which would
176
+ * also rename an explicit `@Entity({ name })` and so compare each table under another name.
223
177
  */
224
178
  export declare function buildEntityAST(generator: Pick<SchemaGenerator, 'resolveTableAlias' | 'resolveSchema' | 'resolveColumnName' | 'compileDdl' | 'compileIndexPredicate'>, entities: readonly Type<object>[], defaultForeignKeyAction?: ForeignKeyAction): SchemaAST;
@@ -1,7 +1,7 @@
1
- import { getMeta, soleIdOf } from '../entity/index.js';
2
- import { canonicalToSql, engineType, fieldOptionsToCanonical, isVectorCategory } from '../schema/canonicalType.js';
1
+ import { getMeta } from '../entity/index.js';
2
+ import { canonicalToSql, engineType, isVectorCategory } from '../schema/canonicalType.js';
3
3
  import { indexSignature } from '../schema/indexDifferences.js';
4
- import { buildSchemaAST } from '../schema/schemaASTBuilder.js';
4
+ import { buildSchemaAST, resolveColumnCanonicalType } from '../schema/schemaASTBuilder.js';
5
5
  import { diffRelationshipNodes, diffTable } from '../schema/schemaASTDiffer.js';
6
6
  import { isAutoIncrement, qualifyName } from '../util/index.js';
7
7
  import { derivedCheckName, derivedForeignKeyName, derivedPrimaryKeyName } from '../util/sql.util.js';
@@ -59,25 +59,13 @@ export class SqlSchemaGenerator {
59
59
  return this.dialect.escapeId(identifier);
60
60
  }
61
61
  /**
62
- * How an auto-increment key of `type` is spelled: the type as any other column renders it, plus what
63
- * the engine appends to make it generated.
64
- *
65
- * Derived rather than a fixed string per dialect, because a foreign key column takes its type from
66
- * the key it points at, resolved through the same canonical type. A key whose spelling ignored that
67
- * type could never be referenced: `@Id({ columnType: 'int' })` emitted `BIGINT` while the column
68
- * pointing at it emitted `INT`, and every engine refuses that constraint.
62
+ * An auto-increment key's type: its canonical type rendered like any column's, plus the engine's generated
63
+ * suffix, so a foreign key taking its type from this key gets the same one.
69
64
  */
70
65
  serialType(type) {
71
66
  return `${this.canonicalTypeToSql(type)} ${this.dialect.autoIncrementSuffix}`;
72
67
  }
73
- /**
74
- * The SQL type a column is spelled with: the engine's generated-key form for an auto-increment key,
75
- * the canonical type otherwise.
76
- *
77
- * One method because both paths that spell a column need the same answer - written twice, with a
78
- * comment asking the two to stay in sync, is how the generated key and the column referencing it
79
- * came to disagree in the first place.
80
- */
68
+ /** The SQL type a column is spelled with: the generated-key form for an auto-increment key, the canonical type otherwise. */
81
69
  columnSqlType(col) {
82
70
  return col.isPrimaryKey && col.isAutoIncrement ? this.serialType(col.type) : this.canonicalTypeToSql(col.type);
83
71
  }
@@ -89,13 +77,8 @@ export class SqlSchemaGenerator {
89
77
  return buildEntityAST(this, entities, this.defaultForeignKeyAction);
90
78
  }
91
79
  /**
92
- * Every `CREATE TABLE` for `entities`, then their foreign keys.
93
- *
94
- * Two phases rather than inline constraints, because a relation graph is routinely cyclic: any
95
- * `createdBy`-style back-reference makes `A` reference `B` while `B` references `A`, and no create
96
- * order satisfies that. TypeORM's schema builder splits for the same reason (`createNewTables()`
97
- * then `createForeignKeys()`). SQLite is the exception and keeps them inline: it cannot `ALTER` a
98
- * foreign key in, but it resolves targets lazily, so a forward reference is fine there.
80
+ * Every `CREATE TABLE` for `entities`, then their foreign keys, since a relation graph is routinely
81
+ * cyclic. SQLite keeps them inline: it cannot add one later, and resolves a forward reference lazily.
99
82
  */
100
83
  generateCreateSchema(entities, options = {}) {
101
84
  const tables = this.orderedTables(entities, 'create', options.only);
@@ -271,13 +254,8 @@ export class SqlSchemaGenerator {
271
254
  return `DROP INDEX IF EXISTS ${this.dialect.escapeQualifiedId(indexName, schema)};`;
272
255
  }
273
256
  /**
274
- * A column definition from a {@link ColumnSchema}, whose type is already the engine's own spelling
275
- * and may carry its own size.
276
- *
277
- * Kept apart from {@link generateColumnFromNode} rather than folded into it: a `ColumnSchema` has no
278
- * `enum`, because introspection reads one back as a `CHECK` constraint and not as a property of the
279
- * column, so only the node knows enough to emit that clause. Both spell the definition through
280
- * {@link renderColumn}, which is the part that must not be written twice.
257
+ * A column definition from a {@link ColumnSchema}, whose type is already the engine's spelling. Apart from
258
+ * {@link generateColumnFromNode}, which alone knows an `enum`; both render through {@link renderColumn}.
281
259
  */
282
260
  generateColumnDefinitionFromSchema(column) {
283
261
  return this.renderColumn({ ...column, type: sizedType(column) });
@@ -309,23 +287,15 @@ export class SqlSchemaGenerator {
309
287
  }
310
288
  return def;
311
289
  }
290
+ /**
291
+ * The column type a field gets, resolved as its table resolves it. A field alone cannot tell that it is
292
+ * one column of a composite key, which its table never makes serial.
293
+ */
312
294
  getSqlType(field) {
313
- // A foreign key takes the type of the key it points at. A `referencedKey` the target does not
314
- // have falls through to this column's own options, as the AST builder does with the same case.
315
- if (field.references) {
316
- const refMeta = getMeta(field.references());
317
- const refIdField = refMeta.fields[field.referencedKey ?? soleIdOf(refMeta, 'a foreign key')];
318
- if (refIdField) {
319
- return this.getSqlType({ ...refIdField, references: undefined, isId: undefined, autoIncrement: false });
320
- }
321
- }
322
- // Get canonical type and convert to SQL
323
- const canonical = fieldOptionsToCanonical(field);
324
- // Special case for serial primary keys
325
- if (isAutoIncrement(field, field.isId === true)) {
326
- return this.serialType(canonical);
327
- }
328
- return this.canonicalTypeToSql(canonical);
295
+ const canonical = resolveColumnCanonicalType(field);
296
+ return isAutoIncrement(field, field.isId === true)
297
+ ? this.serialType(canonical)
298
+ : this.canonicalTypeToSql(canonical);
329
299
  }
330
300
  /** The statements that alter `column` in place, as this dialect spells them. */
331
301
  generateAlterColumnStatements(tableName, column, newDefinition) {
@@ -335,13 +305,7 @@ export class SqlSchemaGenerator {
335
305
  generateColumnComment(comment) {
336
306
  return this.features.commentSyntax === 'inline' ? ` COMMENT ${this.dialect.escape(comment)}` : '';
337
307
  }
338
- /**
339
- * The `COMMENT ON` statements a table and its columns need, on an engine that carries a comment
340
- * that way. Empty on the others: MySQL writes them inline, SQLite has no comments at all.
341
- *
342
- * Emitted after the `CREATE TABLE` rather than folded into it, which is what `COMMENT ON` requires -
343
- * and what makes a comment reach Postgres, where it was previously read as unsupported and dropped.
344
- */
308
+ /** The `COMMENT ON` statements a table and its columns need, after the `CREATE TABLE`, where the engine uses them. */
345
309
  generateCommentStatements(table) {
346
310
  if (this.features.commentSyntax !== 'statement') {
347
311
  return [];
@@ -353,12 +317,7 @@ export class SqlSchemaGenerator {
353
317
  }
354
318
  return statements;
355
319
  }
356
- /**
357
- * The `COMMENT ON COLUMN` one column needs, on an engine that carries a comment that way.
358
- *
359
- * Shared by `CREATE TABLE` and every path that adds a column: written only for the former, a column
360
- * added later reached the database undocumented, the way its enum `CHECK` used to.
361
- */
320
+ /** The `COMMENT ON COLUMN` a column needs where the engine uses one, for `CREATE TABLE` and every path adding a column. */
362
321
  generateColumnCommentStatement(tableName, column, schema) {
363
322
  if (!column.comment || this.features.commentSyntax !== 'statement') {
364
323
  return [];
@@ -367,11 +326,8 @@ export class SqlSchemaGenerator {
367
326
  return [`COMMENT ON COLUMN ${tableRef}.${this.escapeId(column.name)} IS ${this.dialect.escape(column.comment)};`];
368
327
  }
369
328
  /**
370
- * How this entity differs from the table the database reported, as the migrator's `SchemaDiff`.
371
- *
372
- * The comparison itself is {@link diffTable}, the same one drift detection runs, so the two can no
373
- * longer disagree about what has changed. Only two things are this side's own: the entity becomes a
374
- * table node first, and types are compared as the *engine* would store them - see `normalizeType`.
329
+ * How the entity differs from the table the database reported, compared by {@link diffTable}, the one
330
+ * drift detection runs, with types normalized as the engine stores them.
375
331
  */
376
332
  diffSchema(entity, currentTable, desiredAst) {
377
333
  const meta = getMeta(entity);
@@ -412,13 +368,8 @@ export class SqlSchemaGenerator {
412
368
  to: tableDiff.primaryKeyDiff.expected,
413
369
  fromName: tableDiff.primaryKeyDiff.actualName,
414
370
  };
415
- // This table's own constraints, which is what `outgoingRelations` holds on both sides: the
416
- // entity's as the AST derived them, the database's as the introspector read them back.
417
- //
418
- // None at all where the engine cannot alter one: SQLite resolves foreign keys lazily and keeps
419
- // them inline at CREATE time, and its only way to change one afterwards is the twelve-step table
420
- // rebuild, which a sync does not do. Reporting a difference nothing can apply would throw on
421
- // every sync of an entity that has a relation. `drift:check` still names it.
371
+ // This table's own foreign keys. None where the engine cannot alter one (SQLite, short of rebuilding
372
+ // the table), since a difference nothing can apply would throw on every sync; `drift:check` names it.
422
373
  const relationDiffs = this.features.foreignKeyAlter
423
374
  ? diffRelationshipNodes(desired.outgoingRelations, currentTable.outgoingRelations, this.diffOptions())
424
375
  : [];
@@ -512,7 +463,9 @@ export class SqlSchemaGenerator {
512
463
  // later `DROP` has something to name. The exception is a dialect whose serial type states the key
513
464
  // itself (SQLite's `INTEGER PRIMARY KEY AUTOINCREMENT`, which cannot be split): there the column
514
465
  // has already declared it, and saying it again is a second primary key.
515
- const declaredByColumn = this.dialect.serialDeclaresPrimaryKey && table.primaryKey.length === 1 && table.primaryKey[0].isAutoIncrement;
466
+ const declaredByColumn = this.dialect.features.serialDeclaresPrimaryKey &&
467
+ table.primaryKey.length === 1 &&
468
+ table.primaryKey[0].isAutoIncrement;
516
469
  if (table.primaryKey.length && !declaredByColumn) {
517
470
  const pkColumns = table.primaryKey.map((c) => c.name);
518
471
  const pkName = table.primaryKeyName ?? derivedPrimaryKeyName(table.name, pkColumns);
@@ -614,13 +567,7 @@ export class SqlSchemaGenerator {
614
567
  return splitSqlStatements(operation.sql);
615
568
  }
616
569
  }
617
- /**
618
- * `ADD COLUMN`, plus the constraint and index the column declares.
619
- *
620
- * `CREATE TABLE` lifts a column's `references` and `index` onto the table it is building; this had
621
- * no lift, so a hand-written `addColumn(...).references(...).index()` emitted the column alone and
622
- * dropped both without a word.
623
- */
570
+ /** `ADD COLUMN`, plus the foreign key and index the column declares, as `CREATE TABLE` lifts them. */
624
571
  generateAddColumnSql(tableName, column) {
625
572
  this.assertColumnAddable(tableName, column);
626
573
  const colSql = this.generateColumnFromNode(fullColumnDefinitionToNode(column, tableName));
@@ -682,12 +629,8 @@ export class SqlSchemaGenerator {
682
629
  return `ALTER TABLE ${this.escapeId(tableName)} ADD CONSTRAINT ${constraintName} PRIMARY KEY (${pkCols});`;
683
630
  }
684
631
  /**
685
- * Drops whatever key the table has.
686
- *
687
- * `constraintName` has to be what the constraint is *actually* called: the name introspection
688
- * reported for a key the database already had, or the derived one for a key this generator itself
689
- * added, which is what reversing a migration drops. Guessing either way names nothing. MySQL takes
690
- * no name at all - a table's key is always `PRIMARY` there.
632
+ * Drops the table's key, by the name the constraint really has: introspected, or derived where this
633
+ * generator added it. MySQL takes no name.
691
634
  */
692
635
  generateDropPrimaryKeySql(tableName, constraintName) {
693
636
  this.assertPrimaryKeyAlterable(tableName);
@@ -747,12 +690,8 @@ function foreignKeyOf(relation) {
747
690
  };
748
691
  }
749
692
  /**
750
- * The entities as an AST, named the way `generator` names things.
751
- *
752
- * Its resolvers rather than a naming strategy, because the two disagree: a strategy renames whatever
753
- * it is handed, while a generator leaves an explicit `@Entity({ name })` alone. Build the AST the
754
- * other way and the table is created under one name and compared under another, which reports every
755
- * table of a project using a naming strategy as both missing and unexpected.
693
+ * The entities as an AST, named by `generator`'s resolvers rather than a naming strategy, which would
694
+ * also rename an explicit `@Entity({ name })` and so compare each table under another name.
756
695
  */
757
696
  export function buildEntityAST(generator, entities, defaultForeignKeyAction) {
758
697
  return buildSchemaAST(entities, {