uql-orm 0.66.0 → 0.67.1

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 +2 -7
  41. package/dist/entity/decorator/entity.js +2 -7
  42. package/dist/entity/decorator/members.d.ts +7 -30
  43. package/dist/entity/decorator/members.js +3 -12
  44. package/dist/entity/metadata/definition.d.ts +2 -18
  45. package/dist/entity/metadata/definition.js +6 -28
  46. package/dist/http/handler.d.ts +2 -14
  47. package/dist/index.d.ts +4 -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 +16 -66
  92. package/dist/migrate/schemaGenerator.js +21 -74
  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 +2 -30
  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 +163 -534
  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 +19 -73
  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 +2 -31
  174. package/dist/util/field.util.js +3 -43
  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
@@ -175,11 +175,8 @@ export function defineEntity(entity, opts = {}) {
175
175
  if (!hasKeys(meta.fields)) {
176
176
  throw TypeError(`'${entity.name}' must have fields`);
177
177
  }
178
- // A later call composes onto the entity, so saying nothing about the table retracts nothing - which
179
- // is why `derivedName` is only ever *set*, never recomputed from what a previous call left.
180
- // It records that the class name stood in, telling a naming strategy there is something to derive;
181
- // comparing the two cannot, since an entity may name its table exactly what its class is called and
182
- // a spec's minted class is named after its table.
178
+ // A later call composes onto the entity, so a name is only ever set, and `derivedName` records that
179
+ // the class name stood in, which is what a naming strategy derives from.
183
180
  if (opts.name !== undefined) {
184
181
  meta.name = opts.name;
185
182
  meta.derivedName = false;
@@ -251,27 +248,11 @@ export function relationOf(meta, key) {
251
248
  }
252
249
  return relation;
253
250
  }
254
- /**
255
- * Whether the caller named every column of the row's primary key, so {@link idOf} can name the row.
256
- *
257
- * `!= null` rather than falsiness: `0` and an empty string are ids a row can legitimately carry, and
258
- * reading them as "no id" is how a write of that row turned into a second insert. Distinct from
259
- * "does the row carry this column", which an insert asks of `undefined` alone because that is what
260
- * decides whether the column appears in its `VALUES` list at all.
261
- */
251
+ /** Whether the row names every column of its primary key, `0` and `''` included. */
262
252
  export function namesKey(meta, row) {
263
253
  return meta.ids.every((key) => row[key] != null);
264
254
  }
265
- /**
266
- * A row's primary key: the value itself for a single key, an object carrying every key for a
267
- * composite - which is {@link WrittenId}, and reads as the {@link EntityId} a `$where` takes.
268
- *
269
- * What a settled write names its rows by, and what a write hands back. Naming a composite row by one
270
- * of its columns would address every row agreeing on that one.
271
- *
272
- * `WrittenId` does not reduce for an unresolved `E`, so which branch this entity is in cannot be
273
- * proven here, only checked - which is what `ids.length` does.
274
- */
255
+ /** A row's primary key: its value, or a map of every column on a composite, checked at run time. */
275
256
  export function idOf(meta, row) {
276
257
  const { ids } = meta;
277
258
  const id = ids.length === 1 ? row[ids[0]] : Object.fromEntries(ids.map((key) => [key, row[key]]));
@@ -503,11 +484,8 @@ function getIdKeys(meta) {
503
484
  return getKeys(meta.fields).filter((key) => meta.fields[key]?.isId);
504
485
  }
505
486
  /**
506
- * Merges `ancestor` and its own ancestors into `meta`, nearest first, so a further one never overwrites
507
- * a nearer. An `abstract class BaseEntity` carrying `@Field`s but no `@Entity()` has nobody to drain
508
- * its registrations, so do it here. Walking the *class* prototype chain rather than the metadata
509
- * object's is what makes this work on every transformer: tsc and esbuild chain metadata across
510
- * `extends`, SWC does not.
487
+ * Merges `ancestor` and its ancestors into `meta`, nearest first, draining an undecorated base's
488
+ * registrations. Walks the class chain, since not every compiler chains decorator metadata.
511
489
  */
512
490
  function inheritFrom(meta, ancestor) {
513
491
  for (let parent = ancestor; parent && parent !== Object; parent = parentOf(parent)) {
@@ -29,13 +29,7 @@ export type HookContext<E extends object, Ctx = unknown> = {
29
29
  readonly meta: EntityMeta<E>;
30
30
  readonly op: CrudOperation;
31
31
  readonly method: HttpMethod;
32
- /**
33
- * parsed query - mutate in place or reassign to shape it (e.g. force a `$select`, inject a
34
- * `$sort`). For actual tenant/row-level scoping, prefer `@Filter(..., { security: true })` on
35
- * the entity instead: unlike a hook mutation, it is AND-merged (a client `$where` on the same
36
- * key cannot silently win), fails closed when its context is missing, and applies uniformly
37
- * across every query path including joined relations.
38
- */
32
+ /** The parsed query, to reshape in place. Scope rows with a `security` filter instead, which a client cannot override. */
39
33
  query: Query<E>;
40
34
  /**
41
35
  * request payload - reassignable for sanitization or field injection.
@@ -51,13 +45,7 @@ export type ResponseHook<Ctx = unknown> = <E extends object>(ctx: HookContext<E,
51
45
  export type RequestHandlerOptions<Ctx = unknown> = {
52
46
  include?: Type<object>[];
53
47
  exclude?: Type<object>[];
54
- /**
55
- * The URL segment an entity is addressed by, defaulting to its kebab-cased class name.
56
- *
57
- * State it where the default cannot serve: a build that minifies class names renames every route,
58
- * and two entities mapping one table in different schemas collide on one. The browser client takes
59
- * the same option, so both ends can read one map.
60
- */
48
+ /** The URL segment an entity is addressed by, its kebab-cased class name by default; the browser client takes the same option. */
61
49
  entityPath?: (entity: Type<unknown>) => string;
62
50
  /**
63
51
  * Allow augment any kind of request before it runs. Hooks may be async
package/dist/index.d.ts CHANGED
@@ -4,4 +4,7 @@ export * from './entity/index.js';
4
4
  export * from './namingStrategy/index.js';
5
5
  export * from './querier/index.js';
6
6
  export * from './type/index.js';
7
- export * from './util/index.js';
7
+ export { withDeleted } from './util/filters.util.js';
8
+ export type { HookContext } from './util/hook.util.js';
9
+ export { DefaultLogger } from './util/logger.js';
10
+ export { raw, refs } from './util/raw.js';
package/dist/index.js CHANGED
@@ -4,4 +4,6 @@ export * from './entity/index.js';
4
4
  export * from './namingStrategy/index.js';
5
5
  export * from './querier/index.js';
6
6
  export * from './type/index.js';
7
- export * from './util/index.js';
7
+ export { withDeleted } from './util/filters.util.js';
8
+ export { DefaultLogger } from './util/logger.js';
9
+ export { raw, refs } from './util/raw.js';
@@ -7,13 +7,6 @@ import type { VectorDistance, VectorMetric } from '../type/index.js';
7
7
  * functions, which `TursoDialect` inherits.
8
8
  */
9
9
  export declare class LibsqlDialect extends SqliteDialect {
10
- /**
11
- * libSQL has vector search built in, under its own names, so the sqlite-vec `vec_distance_*`
12
- * functions this dialect would otherwise inherit are never present.
13
- *
14
- * @remarks `inner` and `l1` are left out: `vector_distance_dot` only exists in the newer Rust
15
- * engine (see `TursoLocalDialect`) and no libSQL build has an L1 metric. Both raise the same
16
- * "does not support vector distance metric" error as any other unsupported metric.
17
- */
10
+ /** libSQL's built-in vector functions; no `inner` (only the Rust engine has it) and no `l1`. */
18
11
  readonly vectorMetrics: ReadonlyMap<VectorDistance, VectorMetric>;
19
12
  }
@@ -6,14 +6,7 @@ import { SqliteDialect } from '../sqlite/sqliteDialect.js';
6
6
  * functions, which `TursoDialect` inherits.
7
7
  */
8
8
  export class LibsqlDialect extends SqliteDialect {
9
- /**
10
- * libSQL has vector search built in, under its own names, so the sqlite-vec `vec_distance_*`
11
- * functions this dialect would otherwise inherit are never present.
12
- *
13
- * @remarks `inner` and `l1` are left out: `vector_distance_dot` only exists in the newer Rust
14
- * engine (see `TursoLocalDialect`) and no libSQL build has an L1 metric. Both raise the same
15
- * "does not support vector distance metric" error as any other unsupported metric.
16
- */
9
+ /** libSQL's built-in vector functions; no `inner` (only the Rust engine has it) and no `l1`. */
17
10
  vectorMetrics = new Map([
18
11
  ['cosine', { fn: 'vector_distance_cos' }],
19
12
  ['l2', { fn: 'vector_distance_l2' }],
@@ -1,16 +1,14 @@
1
1
  import { type RelationRows } from '../dialect/abstractSqlDialect.js';
2
2
  import { MysqlLikeSqlDialect } from '../dialect/mysqlLikeSqlDialect.js';
3
- import type { DialectFeatures, EntityMeta, FieldOptions, Query, QueryContext, Type, VectorDistance, VectorMetric } from '../type/index.js';
3
+ import type { EntityMeta, FieldOptions, Query, QueryContext, SqlDialectFeatures, Type, VectorDistance, VectorMetric } from '../type/index.js';
4
4
  export declare class MariaDialect extends MysqlLikeSqlDialect {
5
5
  readonly dialectName = "mariadb";
6
6
  readonly insertIdSource = "returning";
7
- /** MariaDB has no `FOR ... OF`, so a lock cannot be narrowed to one table of a join. */
8
- readonly supportsLockOf = false;
9
7
  /**
10
8
  * Unlike MySQL: `VECTOR(n)` takes its dimension, every column of a vector index has to be NOT NULL,
11
- * and `CREATE INDEX` takes `IF NOT EXISTS` - which MySQL's grammar has no place for.
9
+ * `CREATE INDEX` takes `IF NOT EXISTS`, and a lock cannot be narrowed to one table of a join.
12
10
  */
13
- protected readonly featureOverrides: Partial<DialectFeatures>;
11
+ readonly features: SqlDialectFeatures;
14
12
  /**
15
13
  * A derived table here reads no column of the statement around it, so the aggregate reads the
16
14
  * related table itself, and orders and pages inside `JSON_ARRAYAGG`, which takes both.
@@ -1,6 +1,6 @@
1
1
  import { relationTermKey } from '../dialect/abstractSqlDialect.js';
2
2
  import { jsonPath } from '../dialect/jsonSql.js';
3
- import { MysqlLikeSqlDialect } from '../dialect/mysqlLikeSqlDialect.js';
3
+ import { MYSQL_FEATURES, MysqlLikeSqlDialect } from '../dialect/mysqlLikeSqlDialect.js';
4
4
  import { getMeta } from '../entity/index.js';
5
5
  import { columnFamily } from '../util/field.util.js';
6
6
  import { MARIA_VECTOR_METRICS } from './mariaVectorMetrics.js';
@@ -8,16 +8,16 @@ export class MariaDialect extends MysqlLikeSqlDialect {
8
8
  dialectName = 'mariadb';
9
9
  // MariaDB 10.5+ has `INSERT ... RETURNING`, so ids come back exact per row - the upsert's too.
10
10
  insertIdSource = 'returning';
11
- /** MariaDB has no `FOR ... OF`, so a lock cannot be narrowed to one table of a join. */
12
- supportsLockOf = false;
13
11
  /**
14
12
  * Unlike MySQL: `VECTOR(n)` takes its dimension, every column of a vector index has to be NOT NULL,
15
- * and `CREATE INDEX` takes `IF NOT EXISTS` - which MySQL's grammar has no place for.
13
+ * `CREATE INDEX` takes `IF NOT EXISTS`, and a lock cannot be narrowed to one table of a join.
16
14
  */
17
- featureOverrides = {
15
+ features = {
16
+ ...MYSQL_FEATURES,
18
17
  vectorSupportsLength: true,
19
18
  vectorIndexRequiresNotNull: true,
20
19
  indexIfNotExists: true,
20
+ rowLockOf: false,
21
21
  };
22
22
  /**
23
23
  * A derived table here reads no column of the statement around it, so the aggregate reads the
@@ -7,8 +7,8 @@ export class MariadbQuerier extends AbstractPoolQuerier {
7
7
  }
8
8
  async internalRun(query, values) {
9
9
  const res = await this.getConn().query(query, values);
10
- // MariaDB may not set `affectedRows` when RETURNING is used; fall back to row count.
11
- const changes = res.affectedRows ?? res.length ?? 0;
10
+ // An OK packet reports `affectedRows`; a `RETURNING` statement answers rows instead, and counts by them.
11
+ const changes = res.affectedRows ?? res.length;
12
12
  const rows = res.length ? Array.from(res, decodeBigInts) : [];
13
13
  return this.buildUpdateResult({ rows, changes, upsertStatus: res.affectedRows });
14
14
  }
@@ -11,12 +11,7 @@ export class MariadbQuerierPool extends AbstractSqlQuerierPool {
11
11
  // BIGINT stays the driver's `bigint`, which `MariadbQuerier` decodes by the rule every driver here
12
12
  // shares (`decodeWideNumber`) - not `bigIntAsNumber`, which rounds past 2^53 without a word.
13
13
  this.pool = createPool(opts);
14
- // `mariadb`'s own `createPool` already attaches a silent no-op 'error'
15
- // listener (so a dropped connection can't crash the process), but its
16
- // `Pool` type only declares `on` for 'acquire' | 'connection' | 'enqueue'
17
- // | 'release' - 'error' genuinely fires at runtime (see `lib/pool.js`)
18
- // but isn't in the declaration, hence the cast. Re-attaching our own
19
- // listener here just makes the error visible instead of a silent no-op.
14
+ // `mariadb` fires 'error' at runtime without declaring it, hence the cast; this makes it visible.
20
15
  attachPoolErrorHandler(this.pool, 'Idle MariaDB pool connection encountered an error', extra?.logger);
21
16
  }
22
17
  async getQuerier() {
@@ -20,13 +20,7 @@ function createIndexOperation(tableName, columns, options = {}) {
20
20
  },
21
21
  };
22
22
  }
23
- /**
24
- * The one shape of an `addForeignKey` operation, `NO ACTION` defaults included.
25
- *
26
- * Three callers build it and differ only in what they do with the result: the table builder records
27
- * it through its parent, the recorder records it directly, and the executing builder also runs it.
28
- * Spelled out three times, a changed default would have had to be found in all three.
29
- */
23
+ /** An `addForeignKey` operation, `NO ACTION` defaults included, for the three builders that record one. */
30
24
  function addForeignKeyOperation(tableName, columns, target, options = {}) {
31
25
  return {
32
26
  type: 'addForeignKey',
@@ -40,21 +34,11 @@ function addForeignKeyOperation(tableName, columns, target, options = {}) {
40
34
  },
41
35
  };
42
36
  }
43
- /**
44
- * Declare one column through the same vocabulary `createTable` uses. A throwaway {@link TableBuilder}
45
- * is that vocabulary: `addColumn`/`alterColumn` used to take a bare {@link IColumnBuilder}, which
46
- * cannot express a type, so every column they recorded was hard-coded `VARCHAR`.
47
- */
37
+ /** One column declared through `createTable`'s vocabulary, a throwaway {@link TableBuilder}, so its type is stated. */
48
38
  function buildOneColumn(callback) {
49
39
  return callback(new TableBuilder('')).build();
50
40
  }
51
- /**
52
- * Collects the operations one `alterTable` callback declares, in the order it declared them.
53
- *
54
- * Collected rather than dispatched to the parent as they are made: the chaining methods are
55
- * synchronous by contract, so a builder that executes could only fire and forget, which returned from
56
- * `alterTable` with the statements still in flight and turned a failure into an unhandled rejection.
57
- */
41
+ /** The operations one `alterTable` callback declares, collected in order, since its methods are synchronous. */
58
42
  class AlterTableBuilder {
59
43
  tableName;
60
44
  operations = [];
@@ -1,15 +1,2 @@
1
- /**
2
- * Splits a SQL blob on semicolons into separate statements.
3
- *
4
- * Uses a declarative Master-Regex scanner to rapidly
5
- * identify and skip "non-splittable" blocks (strings, comments, dollar-quotes) in a single pass.
6
- * This approach is $O(n)$, leverages native regex speed, and is trivially easy to audit.
7
- *
8
- * Handles:
9
- * - Single quotes: '...' (standard SQL, respects '' and \')
10
- * - Double quotes: "..." (identifiers or MySQL strings)
11
- * - Backticks: `...` (MySQL identifiers)
12
- * - Postgres Dollar quotes: $tag$...$tag$ or $$...$$
13
- * - Comments: -- and /* ... *\/
14
- */
1
+ /** Splits SQL on semicolons, skipping strings, quoted identifiers, dollar-quoted blocks and comments in one regex pass. */
15
2
  export declare function splitSqlStatements(sql: string): string[];
@@ -1,28 +1,8 @@
1
- /**
2
- * Splits a SQL blob on semicolons into separate statements.
3
- *
4
- * Uses a declarative Master-Regex scanner to rapidly
5
- * identify and skip "non-splittable" blocks (strings, comments, dollar-quotes) in a single pass.
6
- * This approach is $O(n)$, leverages native regex speed, and is trivially easy to audit.
7
- *
8
- * Handles:
9
- * - Single quotes: '...' (standard SQL, respects '' and \')
10
- * - Double quotes: "..." (identifiers or MySQL strings)
11
- * - Backticks: `...` (MySQL identifiers)
12
- * - Postgres Dollar quotes: $tag$...$tag$ or $$...$$
13
- * - Comments: -- and /* ... *\/
14
- */
1
+ /** Splits SQL on semicolons, skipping strings, quoted identifiers, dollar-quoted blocks and comments in one regex pass. */
15
2
  export function splitSqlStatements(sql) {
16
3
  const statements = [];
17
4
  let lastIndex = 0;
18
- // This regex matches:
19
- // 1. Single quoted strings: '(?:''|\\['\\]|[^'])*(?:'|(?=$))
20
- // 2. Double quoted identifiers: "(?:""|\\["\\]|[^"])*(?:"|(?=$))
21
- // 3. Backticked identifiers: `(?:``|\\[`\\]|[^`])*(?:`|(?=$))
22
- // 4. Postgres Dollar quoted blocks: \$(?<tag>[a-zA-Z0-9_]*)\$[\s\S]*?(?:\$\k<tag>|(?=$))
23
- // 5. Single-line comments: --.*
24
- // 6. Multi-line comments: \/\*[\s\S]*?(?:\*\/|(?=$))
25
- // 7. Statement terminator: ;
5
+ // Quoted strings and identifiers, dollar quotes, comments, or a `;`: the one regex scanning them all.
26
6
  const masterRegex = /'(?:''|\\['\\]|[^'])*(?:'|(?=$))|"(?:""|\\["\\]|[^"])*(?:"|(?=$))|`(?:``|\\[`\\]|[^`])*(?:`|(?=$))|\$(?<tag>[a-zA-Z0-9_]*)\$[\s\S]*?(?:\$\k<tag>|(?=$))|--.*|\/\*[\s\S]*?(?:\*\/|(?=$))|;/g;
27
7
  for (const match of sql.matchAll(masterRegex)) {
28
8
  if (match[0] === ';') {
@@ -67,14 +67,7 @@ export interface VectorColumnOptions extends BaseColumnOptions {
67
67
  /** Number of dimensions */
68
68
  dimensions?: number;
69
69
  }
70
- /**
71
- * A column as the builder describes one: {@link ColumnNode} without the graph links a DTO cannot carry.
72
- *
73
- * Derived rather than restated, so the two cannot drift. A column gained `enum` and this shape was
74
- * simply missing it, which is why a hand-written `createTable` could never constrain one. A field
75
- * added to the node now reaches here, and failing to render it is a compile error rather than a
76
- * column that quietly loses half its declaration.
77
- */
70
+ /** A column as the builder describes one: a {@link ColumnNode} without its graph links. */
78
71
  export type ColumnDefinition = Omit<ColumnNode, 'table' | 'referencedBy' | 'references'>;
79
72
  /**
80
73
  * The foreign key a single column declares: {@link ForeignKeySchema} without the local columns, which
@@ -260,13 +253,7 @@ export interface IForeignKeyBuilder extends IColumnBuilder {
260
253
  /** Set ON UPDATE action */
261
254
  onUpdate(action: ForeignKeyAction): this;
262
255
  }
263
- /**
264
- * The column vocabulary: every column type the builder can declare, name first.
265
- *
266
- * Split out of {@link ITableBuilder} so `addColumn`/`alterColumn` can hand it to their callback. They
267
- * used to take an {@link IColumnBuilder}, which has no way to say what type a column is - so the
268
- * builder hard-coded `VARCHAR`, and every column a generated migration added or altered was a string.
269
- */
256
+ /** Every column type the builder can declare, name first, handed to `addColumn`/`alterColumn` callbacks too. */
270
257
  export interface IColumnFactory {
271
258
  /** Add an auto-incrementing primary key */
272
259
  id(name?: string, options?: BaseColumnOptions): IColumnBuilder;
@@ -2,17 +2,8 @@ import { stat } from 'node:fs/promises';
2
2
  import { resolve } from 'node:path';
3
3
  import { pathToFileURL } from 'node:url';
4
4
  /**
5
- * Loads the config with a plain `import()`, leaving TypeScript to whatever runs the CLI.
6
- *
7
- * @remarks uql deliberately bundles no transpiler. The config imports the entity classes, so whoever
8
- * loads it decides which decorator spec their decorators are invoked with, and only the runtime knows
9
- * the project's `tsconfig.json`. Bun and `node --import tsx` both get it right; a bundled loader would
10
- * be guessing, and `jiti` guessed wrong (it hardcodes the legacy transform, so standard decorators were
11
- * called as `(prototype, key)` and every field was silently dropped).
12
- *
13
- * Node's own type stripping covers a config that is only types plus a plain object, which is why the
14
- * error below distinguishes the two cases: decorators are not erasable syntax, so a config that reaches
15
- * decorated entity classes needs a runtime that actually transforms them.
5
+ * Loads the config with a plain `import()`, leaving TypeScript to the runtime: uql bundles no transpiler,
6
+ * since only the project knows its decorator spec. Node's type stripping handles no decorators.
16
7
  */
17
8
  async function importConfig(path) {
18
9
  const mod = (await import(pathToFileURL(path).href).catch((cause) => {
@@ -76,11 +76,7 @@ export async function main(args = process.argv.slice(2)) {
76
76
  printHelp();
77
77
  process.exit(1);
78
78
  }
79
- // Close the connection pool
80
- const pool = config.pool;
81
- if (pool.end) {
82
- await pool.end();
83
- }
79
+ await config.pool.end();
84
80
  }
85
81
  catch (error) {
86
82
  console.error('Error:', error.message);
@@ -202,8 +198,7 @@ export async function runSync(migrator, args, config) {
202
198
  const force = args.includes('--force');
203
199
  const safe = !args.includes('--unsafe');
204
200
  const options = { force, safe, drop: !safe };
205
- // Ahead of the warning as well as of the run: `--dry-run` means the same thing whatever else was
206
- // asked for, and it used to be ignored beside `--force`.
201
+ // Ahead of the warning and the run: `--dry-run` means the same whatever else was asked for, `--force` included.
207
202
  if (args.includes('--dry-run')) {
208
203
  const statements = await migrator.planSync(options);
209
204
  console.log(statements.length ? `\n${statements.join('\n')}` : '\nSchema is already in sync.');
@@ -1,14 +1,3 @@
1
- /**
2
- * Entity Code Generator
3
- *
4
- * Generates TypeScript entity files from SchemaAST.
5
- * Supports:
6
- * - ES Module syntax
7
- * - TypeScript types
8
- * - Relations with proper decorators
9
- * - Indexes
10
- * - JSDoc comments for sync-added fields
11
- */
12
1
  import type { SchemaAST } from '../../schema/schemaAST.js';
13
2
  /**
14
3
  * Options for entity code generation.
@@ -107,10 +96,6 @@ export declare class EntityCodeGenerator {
107
96
  * Build incoming relation (OneToMany where other tables have FK to this).
108
97
  */
109
98
  private buildIncomingRelation;
110
- /**
111
- * Get decorator name for relation type.
112
- */
113
- private getRelationDecoratorName;
114
99
  /**
115
100
  * Format type for description.
116
101
  */
@@ -1,20 +1,16 @@
1
- /**
2
- * Entity Code Generator
3
- *
4
- * Generates TypeScript entity files from SchemaAST.
5
- * Supports:
6
- * - ES Module syntax
7
- * - TypeScript types
8
- * - Relations with proper decorators
9
- * - Indexes
10
- * - JSDoc comments for sync-added fields
11
- */
12
1
  import { canonicalToTypeScript } from '../../schema/canonicalType.js';
13
2
  import { DEFAULT_FOREIGN_KEY_ACTION, } from '../../schema/types.js';
14
3
  import { camelCase, lowerFirst, pascalCase, singularize } from '../../util/string.util.js';
15
4
  import { buildFieldOptionsSource, fieldNeedsRaw } from './fieldOptionsSource.js';
16
5
  import { buildIndexDecoratorSource, indexNeedsRaw, isPlainFieldIndex } from './indexDecoratorSource.js';
17
6
  import { memberSource } from './sourceLiteral.js';
7
+ /** The decorator on the other side of a relation. */
8
+ const INVERSE_RELATION = {
9
+ OneToOne: 'OneToOne',
10
+ OneToMany: 'ManyToOne',
11
+ ManyToOne: 'OneToMany',
12
+ ManyToMany: 'ManyToMany',
13
+ };
18
14
  /**
19
15
  * Generates TypeScript entity code from SchemaAST.
20
16
  */
@@ -87,7 +83,7 @@ export class EntityCodeGenerator {
87
83
  // Check for relation decorators
88
84
  if (this.options.includeRelations) {
89
85
  for (const rel of [...table.incomingRelations, ...table.outgoingRelations]) {
90
- uqlImports.add(this.getRelationDecoratorName(rel.type));
86
+ uqlImports.add(rel.type);
91
87
  const relatedTable = rel.from.table === table ? rel.to.table : rel.from.table;
92
88
  const relatedClassName = this.options.classNameTransformer(relatedTable.name);
93
89
  if (!relatedImports.includes(relatedClassName)) {
@@ -175,7 +171,7 @@ export class EntityCodeGenerator {
175
171
  * Build Field decorator options.
176
172
  */
177
173
  buildFieldOptions(col, propertyName) {
178
- const indexes = this.options.includeIndexes ? this.ast.getTableIndexes(col.table.name) : [];
174
+ const indexes = this.options.includeIndexes ? col.table.indexes : [];
179
175
  const fieldIndex = indexes.find((idx) => isPlainFieldIndex(idx) && idx.entries[0]?.column === col.name);
180
176
  return buildFieldOptionsSource(col, propertyName, fieldIndex?.name);
181
177
  }
@@ -184,7 +180,7 @@ export class EntityCodeGenerator {
184
180
  * carry on its own.
185
181
  */
186
182
  declaredIndexes(table) {
187
- return this.ast.getTableIndexes(table.name).filter((index) => !isPlainFieldIndex(index));
183
+ return table.indexes.filter((index) => !isPlainFieldIndex(index));
188
184
  }
189
185
  /**
190
186
  * Build relation definitions.
@@ -222,15 +218,11 @@ export class EntityCodeGenerator {
222
218
  else {
223
219
  propertyName = this.options.propertyNameTransformer(this.options.singularize(rel.to.table.name));
224
220
  }
225
- const decoratorName = this.getRelationDecoratorName(rel.type);
226
221
  // JSDoc
227
222
  if (this.options.addSyncComments) {
228
223
  lines.push(' /**');
229
224
  lines.push(` * @sync-added ${new Date().toISOString().split('T')[0]}`);
230
225
  lines.push(` * Relation to ${rel.to.table.name} via ${rel.from.columns.map((c) => c.name).join(', ')}`);
231
- if (rel.confidence !== undefined && rel.confidence < 1.0) {
232
- lines.push(` * Inferred (${(rel.confidence * 100).toFixed(0)}% confidence)`);
233
- }
234
226
  lines.push(' */');
235
227
  }
236
228
  // Decorator. `onDelete`/`onUpdate` only when introspection found a real referential action, so a
@@ -243,7 +235,7 @@ export class EntityCodeGenerator {
243
235
  options.push(`onDelete: '${rel.onDelete}'`);
244
236
  if (rel.onUpdate && rel.onUpdate !== DEFAULT_FOREIGN_KEY_ACTION)
245
237
  options.push(`onUpdate: '${rel.onUpdate}'`);
246
- lines.push(` @${decoratorName}({ ${options.join(', ')} })`);
238
+ lines.push(` @${rel.type}({ ${options.join(', ')} })`);
247
239
  // Property
248
240
  lines.push(` ${propertyName}?: ${relatedClassName};`);
249
241
  return lines.join('\n');
@@ -274,8 +266,6 @@ export class EntityCodeGenerator {
274
266
  const lines = [];
275
267
  const relatedClassName = this.options.classNameTransformer(rel.from.table.name);
276
268
  const propertyName = this.options.propertyNameTransformer(rel.from.table.name);
277
- const inverseType = this.ast.getInverseRelationType(rel.type);
278
- const decoratorName = this.getRelationDecoratorName(inverseType);
279
269
  // JSDoc
280
270
  if (this.options.addSyncComments) {
281
271
  lines.push(' /**');
@@ -286,31 +276,12 @@ export class EntityCodeGenerator {
286
276
  // The inverse side, mapped by the related class's property that points back at this one.
287
277
  const param = lowerFirst(relatedClassName);
288
278
  const inverse = memberSource(param, this.options.propertyNameTransformer(this.options.singularize(table.name)));
289
- lines.push(` @${decoratorName}({ entity: () => ${relatedClassName}, mappedBy: (${param}) => ${inverse} })`);
290
- // Property
291
- if (inverseType === 'OneToMany' || inverseType === 'ManyToMany') {
292
- lines.push(` ${propertyName}?: ${relatedClassName}[];`);
293
- }
294
- else {
295
- lines.push(` ${propertyName}?: ${relatedClassName};`);
296
- }
279
+ const inverseType = INVERSE_RELATION[rel.type];
280
+ lines.push(` @${inverseType}({ entity: () => ${relatedClassName}, mappedBy: (${param}) => ${inverse} })`);
281
+ const many = inverseType === 'OneToMany' || inverseType === 'ManyToMany';
282
+ lines.push(` ${propertyName}?: ${relatedClassName}${many ? '[]' : ''};`);
297
283
  return lines.join('\n');
298
284
  }
299
- /**
300
- * Get decorator name for relation type.
301
- */
302
- getRelationDecoratorName(type) {
303
- switch (type) {
304
- case 'OneToOne':
305
- return 'OneToOne';
306
- case 'OneToMany':
307
- return 'OneToMany';
308
- case 'ManyToOne':
309
- return 'ManyToOne';
310
- case 'ManyToMany':
311
- return 'ManyToMany';
312
- }
313
- }
314
285
  /**
315
286
  * Format type for description.
316
287
  */
@@ -1,12 +1,5 @@
1
1
  import type { ColumnNode } from '../../schema/types.js';
2
- /**
3
- * A column's `@Field({ ... })` options as source, or `''` when it needs none.
4
- *
5
- * Shared by the entity generator and the merger because they emit the same decorator. They each had
6
- * their own copy, and the copies had drifted: the merger's dropped `unique` and `defaultValue`, so
7
- * merging a column into an existing entity file quietly produced a weaker field than generating the
8
- * file from scratch.
9
- */
2
+ /** A column's `@Field({ ... })` options as source, `''` where it needs none: shared by the generator and the merger. */
10
3
  export declare function buildFieldOptionsSource(col: ColumnNode, propertyName: string, indexName?: string): string;
11
4
  /** Whether the field's decorator needs `raw` imported, the way {@link indexNeedsRaw} does for an index. */
12
5
  export declare function fieldNeedsRaw(col: ColumnNode): boolean;
@@ -1,14 +1,6 @@
1
1
  import { canonicalToColumnType } from '../../schema/canonicalType.js';
2
2
  import { quoted, rawTag } from './sourceLiteral.js';
3
- /**
4
- * What each field of a {@link ColumnNode} contributes to `@Field({ ... })`, in emit order, and `null`
5
- * where nothing does.
6
- *
7
- * The `satisfies` is the point: a field the node gains cannot reach here without someone answering
8
- * whether an entity generated from a database keeps it. Written as a hand-rolled `if` chain, this had
9
- * already dropped `comment` - introspection reads one on Postgres and MySQL, and regenerating an
10
- * entity threw it away.
11
- */
3
+ /** What each field of a {@link ColumnNode} contributes to `@Field({ ... })`, in emit order; `satisfies` makes a new field answer. */
12
4
  const OPTION_SOURCE = {
13
5
  // Without this the entity maps to a column named after the property, which for anything the
14
6
  // transformer rewrote - every `user_id` - is a column the database does not have.
@@ -36,14 +28,7 @@ const OPTION_SOURCE = {
36
28
  references: null,
37
29
  referencedBy: null,
38
30
  };
39
- /**
40
- * A column's `@Field({ ... })` options as source, or `''` when it needs none.
41
- *
42
- * Shared by the entity generator and the merger because they emit the same decorator. They each had
43
- * their own copy, and the copies had drifted: the merger's dropped `unique` and `defaultValue`, so
44
- * merging a column into an existing entity file quietly produced a weaker field than generating the
45
- * file from scratch.
46
- */
31
+ /** A column's `@Field({ ... })` options as source, `''` where it needs none: shared by the generator and the merger. */
47
32
  export function buildFieldOptionsSource(col, propertyName, indexName) {
48
33
  const context = { propertyName, indexName };
49
34
  const options = [
@@ -57,11 +42,7 @@ export function buildFieldOptionsSource(col, propertyName, indexName) {
57
42
  export function fieldNeedsRaw(col) {
58
43
  return col.generatedAs !== undefined;
59
44
  }
60
- /**
61
- * A default value as source. Strings stay single-quoted, expressions included: `defaultValue: 'now()'`
62
- * is what reaches the DDL. The generator used to branch on `CURRENT_TIMESTAMP`/`NEXTVAL`/`(` first, but
63
- * both branches emitted a quoted string and only the fallthrough escaped embedded quotes.
64
- */
45
+ /** A default value as source, a string single-quoted and escaped, an expression included: `defaultValue: 'now()'`. */
65
46
  function defaultValueSource(value) {
66
47
  if (typeof value === 'string') {
67
48
  return quoted(value);
@@ -6,11 +6,8 @@ export declare function assertIndexType(index: IndexSchema, types: ReadonlySet<I
6
6
  /** Refuses an index asking for a feature `features` lacks. */
7
7
  export declare function assertIndexFeatures(index: IndexSchema, features: ReadonlySet<IndexFeature>, dialectName: string): void;
8
8
  /**
9
- * `CREATE INDEX` for SQL dialects: the statement and the fragments each engine spells differently.
10
- * The migrator's rather than the dialect's, since {@link SqlSchemaGenerator} is the only thing that
11
- * emits DDL - which is what keeps a `CAST(... ARRAY)` table out of every runtime consumer's entry.
12
- * The form here is the portable one, which SQLite (and so libSQL, Turso and D1) takes verbatim: no
13
- * access-method clause, no operator classes, no tuning parameters.
9
+ * `CREATE INDEX` in its portable form, which the SQLite family takes as is; the engines with more override
10
+ * the fragments. The migrator's own, so no runtime entry carries it.
14
11
  */
15
12
  export declare class IndexDdl<D extends AbstractSqlDialect = AbstractSqlDialect> {
16
13
  protected readonly dialect: D;
@@ -32,11 +32,8 @@ export function assertIndexFeatures(index, features, dialectName) {
32
32
  }
33
33
  }
34
34
  /**
35
- * `CREATE INDEX` for SQL dialects: the statement and the fragments each engine spells differently.
36
- * The migrator's rather than the dialect's, since {@link SqlSchemaGenerator} is the only thing that
37
- * emits DDL - which is what keeps a `CAST(... ARRAY)` table out of every runtime consumer's entry.
38
- * The form here is the portable one, which SQLite (and so libSQL, Turso and D1) takes verbatim: no
39
- * access-method clause, no operator classes, no tuning parameters.
35
+ * `CREATE INDEX` in its portable form, which the SQLite family takes as is; the engines with more override
36
+ * the fragments. The migrator's own, so no runtime entry carries it.
40
37
  */
41
38
  export class IndexDdl {
42
39
  dialect;