uql-orm 0.62.0 → 0.64.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 (104) hide show
  1. package/dist/bunSql/bunSql.util.d.ts +15 -15
  2. package/dist/bunSql/bunSql.util.js +22 -35
  3. package/dist/bunSql/bunSqlQuerier.d.ts +2 -2
  4. package/dist/bunSql/bunSqlQuerier.js +3 -3
  5. package/dist/bunSql/bunSqlQuerierPool.d.ts +1 -13
  6. package/dist/bunSql/bunSqlQuerierPool.js +3 -34
  7. package/dist/d1/d1Querier.d.ts +12 -4
  8. package/dist/d1/d1Querier.js +6 -11
  9. package/dist/d1/d1QuerierPool.d.ts +7 -3
  10. package/dist/d1/d1QuerierPool.js +5 -3
  11. package/dist/entity/decorator/entity.d.ts +5 -9
  12. package/dist/entity/decorator/entity.js +3 -7
  13. package/dist/entity/metadata/definition.d.ts +2 -2
  14. package/dist/entity/metadata/definition.js +13 -22
  15. package/dist/libsql/libsqlDialect.d.ts +1 -1
  16. package/dist/libsql/libsqlDialect.js +1 -1
  17. package/dist/libsql/libsqlQuerierPool.d.ts +18 -9
  18. package/dist/libsql/libsqlQuerierPool.js +32 -20
  19. package/dist/migrate/builder/expressions.js +1 -15
  20. package/dist/migrate/builder/migrationBuilder.d.ts +6 -28
  21. package/dist/migrate/builder/migrationBuilder.js +9 -83
  22. package/dist/migrate/builder/types.d.ts +14 -24
  23. package/dist/migrate/cli.d.ts +1 -6
  24. package/dist/migrate/cli.js +3 -10
  25. package/dist/migrate/codegen/index.d.ts +1 -1
  26. package/dist/migrate/codegen/index.js +1 -1
  27. package/dist/migrate/codegen/indexDecoratorSource.d.ts +1 -1
  28. package/dist/migrate/codegen/indexDecoratorSource.js +4 -8
  29. package/dist/migrate/codegen/migrationFile.d.ts +9 -5
  30. package/dist/migrate/codegen/migrationFile.js +2 -3
  31. package/dist/migrate/ddl/indexDdl.d.ts +4 -2
  32. package/dist/migrate/ddl/indexDdl.js +16 -15
  33. package/dist/migrate/generator/mongoCommand.d.ts +9 -9
  34. package/dist/migrate/generator/mongoCommand.js +1 -1
  35. package/dist/migrate/generator/mongoSchemaGenerator.d.ts +21 -26
  36. package/dist/migrate/generator/mongoSchemaGenerator.js +103 -80
  37. package/dist/migrate/index.d.ts +1 -1
  38. package/dist/migrate/index.js +1 -1
  39. package/dist/migrate/indexPredicate.d.ts +8 -0
  40. package/dist/migrate/indexPredicate.js +52 -0
  41. package/dist/migrate/migrationTarget.d.ts +23 -0
  42. package/dist/migrate/migrationTarget.js +48 -0
  43. package/dist/migrate/migrator.d.ts +17 -45
  44. package/dist/migrate/migrator.js +80 -179
  45. package/dist/migrate/schemaGenerator.d.ts +12 -13
  46. package/dist/migrate/schemaGenerator.js +43 -9
  47. package/dist/mongo/mongoDialect.d.ts +6 -1
  48. package/dist/querier/abstractSharedHandleQuerierPool.d.ts +5 -5
  49. package/dist/querier/abstractSharedHandleQuerierPool.js +5 -5
  50. package/dist/schema/schemaASTBuilder.d.ts +2 -0
  51. package/dist/schema/schemaASTBuilder.js +9 -22
  52. package/dist/sqlite/abstractSqliteQuerier.d.ts +11 -28
  53. package/dist/sqlite/abstractSqliteQuerier.js +14 -33
  54. package/dist/sqlite/bunSqliteAdapter.bun.d.ts +5 -4
  55. package/dist/sqlite/bunSqliteAdapter.bun.js +1 -1
  56. package/dist/sqlite/hranaQuerier.d.ts +6 -4
  57. package/dist/sqlite/hranaQuerier.js +4 -13
  58. package/dist/sqlite/index.d.ts +0 -1
  59. package/dist/sqlite/index.js +0 -1
  60. package/dist/sqlite/localSqliteQuerierPool.d.ts +14 -5
  61. package/dist/sqlite/nodeSqliteAdapter.d.ts +3 -4
  62. package/dist/sqlite/nodeSqliteAdapter.js +3 -6
  63. package/dist/sqlite/nodeSqliteQuerierPool.d.ts +2 -3
  64. package/dist/sqlite/nodeSqliteQuerierPool.js +3 -1
  65. package/dist/sqlite/sqliteDialect.d.ts +1 -1
  66. package/dist/sqlite/sqliteDialect.js +1 -1
  67. package/dist/sqlite/sqlitePragmas.d.ts +2 -11
  68. package/dist/sqlite/sqlitePragmas.js +1 -1
  69. package/dist/sqlite/sqliteQuerier.d.ts +29 -10
  70. package/dist/sqlite/sqliteQuerier.js +26 -4
  71. package/dist/sqlite/sqliteQuerierPool.d.ts +7 -3
  72. package/dist/sqlite/sqliteQuerierPool.js +12 -8
  73. package/dist/turso/index.d.ts +1 -0
  74. package/dist/turso/index.js +1 -0
  75. package/dist/turso/local.d.ts +1 -1
  76. package/dist/turso/local.js +1 -1
  77. package/dist/turso/tursoDialect.d.ts +4 -9
  78. package/dist/turso/tursoDialect.js +4 -12
  79. package/dist/turso/tursoLocalDialect.d.ts +10 -0
  80. package/dist/turso/tursoLocalDialect.js +13 -0
  81. package/dist/turso/tursoLocalQuerierPool.d.ts +8 -13
  82. package/dist/turso/tursoLocalQuerierPool.js +6 -5
  83. package/dist/turso/tursoQuerierPool.d.ts +15 -30
  84. package/dist/turso/tursoQuerierPool.js +13 -23
  85. package/dist/turso/tursoSessionQuerier.d.ts +57 -0
  86. package/dist/turso/tursoSessionQuerier.js +50 -0
  87. package/dist/type/entity.d.ts +37 -62
  88. package/dist/type/migration.d.ts +11 -40
  89. package/dist/type/queryRaw.d.ts +8 -0
  90. package/dist/type/queryRaw.js +11 -0
  91. package/dist/util/ddlExpression.util.d.ts +5 -3
  92. package/dist/util/ddlExpression.util.js +19 -12
  93. package/dist/util/raw.d.ts +6 -1
  94. package/dist/util/raw.js +11 -8
  95. package/dist/util/sqlLiteral.js +5 -3
  96. package/dist/util/wideNumber.d.ts +2 -2
  97. package/dist/util/wideNumber.js +2 -2
  98. package/package.json +2 -2
  99. package/dist/migrate/schemaGeneratorAsync.d.ts +0 -7
  100. package/dist/migrate/schemaGeneratorAsync.js +0 -12
  101. package/dist/sqlite/hranaQuerierPool.d.ts +0 -20
  102. package/dist/sqlite/hranaQuerierPool.js +0 -26
  103. package/dist/turso/tursoLocalQuerier.d.ts +0 -24
  104. package/dist/turso/tursoLocalQuerier.js +0 -20
@@ -1,6 +1,6 @@
1
1
  import type { EnumValues, ForeignKeyAction, IndexType } from '../schema/types.js';
2
2
  import type { FilterOptions } from './query.js';
3
- import type { QueryRaw } from './queryRaw.js';
3
+ import type { ColumnRef, QueryRaw } from './queryRaw.js';
4
4
  import type { QueryWhere } from './queryWhere.js';
5
5
  import type { Except, IsMany, Json, Scalar, Type, Unpacked } from './utility.js';
6
6
  import type { VectorDistance, VectorIndexOptions, VectorIndexType } from './vector.js';
@@ -595,14 +595,6 @@ type RelationOptionsThroughOwner<E, O> = Pick<RelationOptions<E, O>, 'entity' |
595
595
  export type KeyMap<E> = {
596
596
  readonly [K in keyof E]-?: K;
597
597
  };
598
- declare const COLUMN_KEY: unique symbol;
599
- /**
600
- * A field of an entity as SQL, read off a {@link RefMap}: interpolated into `raw`, it renders as that
601
- * field's column. A `QueryRaw` like any other fragment, branded with the field `K` it names.
602
- */
603
- export type ColumnRef<K extends string = string> = QueryRaw & {
604
- readonly [COLUMN_KEY]?: K;
605
- };
606
598
  /**
607
599
  * The fields of `E` as {@link ColumnRef}s, for SQL that names them: `refs(User)` in a statement, the
608
600
  * callback's parameter in a definition. Keyed over a type parameter constrained to `keyof E`, as
@@ -612,15 +604,13 @@ export type RefMap<E, F extends keyof E = FieldKey<E>> = {
612
604
  readonly [K in F]-?: ColumnRef<K & string>;
613
605
  };
614
606
  /**
615
- * A callback reading an entity's fields off a {@link RefMap} for the SQL it returns. Declared as a
616
- * method, bivariant in its refs, so one typed for its entity still fits where the entity is erased: the
617
- * registry, which resolves it.
607
+ * SQL a definition writes: `raw`, or a callback reading the entity's fields off its refs. The callback is
608
+ * declared as a method, bivariant in its refs, so one typed for its entity still fits where the entity is
609
+ * erased: the registry, which resolves it.
618
610
  */
619
- export type SqlCallback<E> = {
620
- sql(row: RefMap<E>): QueryRaw;
611
+ export type EntitySql<E> = QueryRaw | {
612
+ sql(refs: RefMap<E>): QueryRaw;
621
613
  }['sql'];
622
- /** SQL a definition writes: `raw`, or a {@link SqlCallback} for SQL that names the entity's fields. */
623
- export type EntitySql<E> = QueryRaw | SqlCallback<E>;
624
614
  /**
625
615
  * A predicate DDL carries, over the entity's own fields: a relation, full-text search and a sub-query
626
616
  * have nothing a `CHECK` or a partial index can hold. An intersection rather than `Except`, which would
@@ -677,41 +667,24 @@ export type IndexTypeOptions = {
677
667
  distance?: never;
678
668
  };
679
669
  /**
680
- * One entry of an index: a column by default, a {@link SqlCallback} to index an expression, or an object
681
- * when the entry needs more than that.
682
- *
683
- * @example
684
- * ```ts
685
- * @Index((post) => [post.tenantId, { column: post.createdAt, order: 'desc' }]) // keyset pagination
686
- * @Index(() => [(post) => raw`lower(${post.email})`], { unique: true }) // case-insensitive uniqueness
687
- * @Index((post) => [{ column: post.body, length: 64 }]) // MySQL needs a prefix on TEXT
688
- * @Index((post) => [post.data], { type: 'gin' }) // JSONB containment
689
- * ```
690
- *
691
- * `C` is the entity's `FieldKey` on the `@Index`/`defineEntity` paths, where the decorated class says
692
- * which columns exist, and `E` the entity itself, which is what checks a JSON entry's path. Both
693
- * default to the unchecked form for the migration builder's `table.index(...)`, which names raw
694
- * table columns with no entity in scope.
695
- */
696
- export type IndexColumnInput<C extends string = string, E = unknown> = C | SqlCallback<E> | IndexColumnOptions<C, E> | IndexJsonColumnOptions<C, E>;
697
- /**
698
- * The JSON entries, whose `path` is checked against the payload of the column the same entry names -
699
- * a mapped union, one arm per JSON field, so `{ column: 'kind', jsonPath: { path: 'thema.color' } }`
700
- * cannot compile. It matters more here than anywhere else in the index API: a path that is merely
701
- * *misspelled* still builds a perfectly valid index, one no query will ever match, and nothing at
702
- * runtime can tell that from the index you meant.
703
- *
704
- * `jsonArray`'s path is the array's own, so on a column that *is* the array (`Json<string[]>`) it
705
- * resolves to `never` and the property can only be omitted, which is exactly the truth.
706
- *
707
- * Falls back to the unchecked shape only where there is no entity to check against - the migration
708
- * builder. An entity with no JSON field at all offers no arm, which is also the truth.
670
+ * One index entry as the migration builder takes it: a column name, `raw` for an expression, or an object
671
+ * when the entry needs more. An entity's entries are this too, which is what `normalizeIndexColumn` reads.
672
+ */
673
+ export type IndexColumnInput = string | QueryRaw | EntityIndexColumn;
674
+ /**
675
+ * One entry of an entity's index, read off its refs: a column, `raw` for an expression, or an object when
676
+ * the entry needs more, a JSON entry's path checked against its column.
677
+ * @example `@Index((post) => [post.tenantId, { column: post.createdAt, order: 'desc' }, raw`lower(${post.email})`])`
709
678
  */
710
- type IndexJsonColumnOptions<C extends string, E> = unknown extends E ? IndexColumnModifiers & {
711
- readonly column: C;
712
- } : {
679
+ export type EntityIndexColumnInput<E> = QueryRaw | IndexColumnOptions | IndexJsonColumnOptions<E>;
680
+ /**
681
+ * The JSON entries, one arm per JSON field, each `path` checked against the payload of the column its own
682
+ * entry names: a misspelled path still builds a valid index that no query matches. On a column that is
683
+ * the array (`Json<string[]>`), `jsonArray`'s path resolves to `never`, so it can only be omitted.
684
+ */
685
+ type IndexJsonColumnOptions<E> = {
713
686
  [K in JsonColumnKey<E>]: IndexColumnPlainModifiers & {
714
- readonly column: K;
687
+ readonly column: ColumnRef<K & string>;
715
688
  } & ({
716
689
  readonly jsonPath: WithCheckedPath<IndexJsonPath, E, K>;
717
690
  readonly jsonArray?: never;
@@ -727,7 +700,7 @@ type IndexJsonColumnOptions<C extends string, E> = unknown extends E ? IndexColu
727
700
  * subject is that column.
728
701
  */
729
702
  type JsonColumnKey<E> = {
730
- readonly [K in keyof E]-?: IsJson<NonNullable<E[K]>> extends true ? K : IsJson<JsonElement<E[K]>> extends true ? K : never;
703
+ readonly [K in keyof E]-?: IsJsonColumn<NonNullable<E[K]>> extends true ? K : never;
731
704
  }[Key<E>];
732
705
  /** The payload a path is checked against: the column's own brand, or that of the documents it holds. */
733
706
  type JsonColumnPayload<V> = IsJson<NonNullable<V>> extends true ? UnwrapJson<NonNullable<V>> : JsonPayload<V>;
@@ -807,15 +780,19 @@ export type IndexJsonArray = {
807
780
  };
808
781
  /** The modifiers that do not name a JSON path, and so need no entity to be checked against. */
809
782
  type IndexColumnPlainModifiers = Except<IndexColumnModifiers, 'jsonPath' | 'jsonArray'>;
810
- export type IndexColumnOptions<C extends string = string, E = unknown> = IndexColumnPlainModifiers & {
811
- /** The column to index, or a {@link SqlCallback} for an expression. */
812
- readonly column: C | SqlCallback<E>;
783
+ /**
784
+ * An entity's entry with plain modifiers. `jsonPath` and `jsonArray` are `never` here, since a JSON entry
785
+ * would otherwise match this shape too, its path unchecked.
786
+ */
787
+ type IndexColumnOptions = IndexColumnPlainModifiers & {
788
+ /** A column read off the refs, or `raw` for an expression. */
789
+ readonly column: QueryRaw;
813
790
  readonly jsonPath?: never;
814
791
  readonly jsonArray?: never;
815
792
  };
816
793
  /**
817
- * One index entry, normalized: {@link IndexColumnInput}'s three authored shapes all reduce to this
818
- * before any dialect or generator sees them, so rendering never re-parses the sugar.
794
+ * One index entry, normalized: every authored shape reduces to this before any dialect or generator sees
795
+ * it, so rendering never re-parses the sugar.
819
796
  */
820
797
  export type IndexColumnSchema = IndexColumnModifiers & {
821
798
  /** A column name, or raw SQL when {@link expression} is set. */
@@ -967,27 +944,25 @@ export type EntityOptions<E = unknown> = {
967
944
  * and through {@link EntityIndexOptions} `@Index` and `defineEntity`. `Except` (not plain `Omit`) keeps
968
945
  * `type`/`distance` a discriminated pair: omitting `distance` on a vector index type is a compile error.
969
946
  */
970
- export type IndexOptions = Except<EntityIndexMeta, 'columns' | 'include' | 'where'> & {
971
- /** Non-key columns stored in the index, by column name; a typo builds nothing, the server refusing it. */
972
- readonly include?: readonly string[];
947
+ export type IndexOptions = Except<EntityIndexMeta, 'columns' | 'where'> & {
973
948
  /** Partial-index predicate, as `raw` with no interpolation: the migration builder has no entity to compile one against. */
974
949
  readonly where?: QueryRaw;
975
950
  };
976
951
  /**
977
- * {@link IndexOptions} on an entity, whose stored columns are read off its key map, `(post) => [post.slug]`,
952
+ * {@link IndexOptions} on an entity, whose stored columns are read off its refs, `(post) => [post.slug]`,
978
953
  * so they are checked against it and follow a rename. The migration builder names raw columns instead.
979
954
  */
980
955
  export type EntityIndexOptions<E> = Except<IndexOptions, 'include' | 'where'> & {
981
- readonly include?: (keys: KeyMap<E>) => readonly FieldKey<E>[];
956
+ readonly include?: (refs: RefMap<E>) => readonly ColumnRef<FieldKey<E>>[];
982
957
  /** Partial-index predicate. See {@link EntityWhere}. */
983
958
  readonly where?: EntityWhere<E>;
984
959
  };
985
960
  /**
986
- * An index as authored on an entity, before `defineIndex` reads its columns off the key map. Only the
961
+ * An index as authored on an entity, before `defineIndex` reads its columns off the refs. Only the
987
962
  * member lists are callbacks: TypeScript never checks a callback's returned literal for excess properties,
988
963
  * so the options stay a literal of their own, where `uniqe: true` is a compile error.
989
964
  */
990
965
  export type EntityIndexInput<E> = EntityIndexOptions<E> & {
991
- readonly columns: (keys: KeyMap<E>) => readonly IndexColumnInput<FieldKey<E>, E>[];
966
+ readonly columns: (refs: RefMap<E>) => readonly EntityIndexColumnInput<E>[];
992
967
  };
993
968
  export {};
@@ -1,8 +1,8 @@
1
1
  import type { VectorCast } from '../dialect/vectorCast.js';
2
- import type { FullColumnDefinition, IndexDefinition, TableDefinition } from '../migrate/builder/types.js';
2
+ import type { AnyMigrationOperation } from '../migrate/builder/types.js';
3
3
  import type { IndexFacet } from '../schema/indexDifferences.js';
4
4
  import type { SchemaAST } from '../schema/schemaAST.js';
5
- import type { ColumnNode, ForeignKeyAction, IndexNode, IndexType, TableNode } from '../schema/types.js';
5
+ import type { ColumnNode, ForeignKeyAction, IndexType, TableNode } from '../schema/types.js';
6
6
  import type { EntityMeta, EntityWhereMeta, FieldOptions, IndexColumnSchema, LoggingOptions, Querier, SqlQuerier, Type, VectorIndexOptions } from './index.js';
7
7
  /**
8
8
  * Defines a migration using a simple object literal. `Q` is `MongoQuerier` for a MongoDB migration.
@@ -148,7 +148,7 @@ export interface IndexSchema extends VectorIndexOptions {
148
148
  readonly unique: boolean;
149
149
  /** Index type (btree, hnsw, ivfflat, etc.) */
150
150
  readonly type?: IndexType;
151
- /** Partial index condition (WHERE clause) */
151
+ /** Partial index predicate as its engine writes it: SQL, or on MongoDB the JSON of its filter document. */
152
152
  readonly where?: string;
153
153
  /** Non-key columns stored in the index (Postgres-wire `INCLUDE`). */
154
154
  readonly include?: readonly string[];
@@ -292,14 +292,20 @@ export interface SchemaGenerator {
292
292
  */
293
293
  generateDropIndex(tableName: string, indexName: string): string;
294
294
  /**
295
- * Get the SQL type for a field based on its options
295
+ * The statements one migration builder operation runs as, one string each. An operation the engine
296
+ * has no form for throws: MongoDB has no columns, constraints or SQL.
296
297
  */
297
- getSqlType(fieldOptions: FieldOptions): string;
298
+ generateOperation(operation: AnyMigrationOperation): string[];
298
299
  /**
299
300
  * The text of SQL an entity declares - a check, a stored computed column, an index expression or
300
301
  * predicate - rendered for this engine, which is what building an entity's schema needs from it.
301
302
  */
302
303
  compileDdl(sql: EntityWhereMeta<object>, entity: Type<object>): string;
304
+ /**
305
+ * A partial index's `$where` as this engine writes it into {@link IndexSchema.where}, refused where its
306
+ * index takes less of a predicate than a query does: SQL Server's filter has no `OR`.
307
+ */
308
+ compileIndexPredicate(where: EntityWhereMeta<object>, entity: Type<object>, indexName: string): string;
303
309
  /**
304
310
  * Compare an entity with a database table node and return the differences.
305
311
  *
@@ -333,41 +339,6 @@ export interface SchemaGenerator {
333
339
  * Resolve column name using field options and naming strategy
334
340
  */
335
341
  resolveColumnName(key: string, field: FieldOptions): string;
336
- /** DDL from a `TableNode`, one string per `querier.run`. */
337
- generateCreateTableFromNode(table: TableNode, options?: {
338
- ifNotExists?: boolean;
339
- }): string[];
340
- /** Generate CREATE INDEX statement from an IndexNode */
341
- generateCreateIndexFromNode(index: IndexNode, options?: {
342
- ifNotExists?: boolean;
343
- }): string;
344
- /** DDL from a `TableDefinition`, one string per `querier.run`. */
345
- generateCreateTableFromDefinition(table: TableDefinition, options?: {
346
- ifNotExists?: boolean;
347
- }): string[];
348
- /** Generate RENAME TABLE statement */
349
- generateRenameTableSql(oldName: string, newName: string): string;
350
- }
351
- /**
352
- * The column and constraint DDL a migration builder emits, which only a SQL engine has. Split from
353
- * {@link SchemaGenerator} because MongoDB used to satisfy these six by returning `''`: a document store
354
- * has no `ADD COLUMN`, and an empty statement silently did nothing rather than saying so.
355
- */
356
- export interface SqlDdlGenerator extends SchemaGenerator {
357
- /** Generate ADD COLUMN statement */
358
- generateAddColumnSql(tableName: string, column: FullColumnDefinition): string;
359
- /** Generate ALTER COLUMN statement */
360
- generateAlterColumnSql(tableName: string, columnName: string, column: FullColumnDefinition): string;
361
- /** Generate DROP COLUMN statement */
362
- generateDropColumnSql(tableName: string, columnName: string): string;
363
- /** Generate RENAME COLUMN statement */
364
- generateRenameColumnSql(tableName: string, oldName: string, newName: string): string;
365
- /** Generate ADD FOREIGN KEY statement */
366
- generateAddForeignKeySql(tableName: string, foreignKey: ForeignKeySchema): string;
367
- /** Generate DROP FOREIGN KEY statement */
368
- generateDropForeignKeySql(tableName: string, constraintName: string): string;
369
- /** CREATE INDEX from a builder's {@link IndexDefinition}, its SQL rendered for this engine. */
370
- generateCreateIndexFromDefinition(tableName: string, index: IndexDefinition): string;
371
342
  }
372
343
  /**
373
344
  * Interface for introspecting the current database schema
@@ -43,3 +43,11 @@ export declare class QueryRaw {
43
43
  */
44
44
  render(opts: QueryRawRenderOptions): void;
45
45
  }
46
+ /**
47
+ * A field of an entity as SQL, read off `refs(Entity)` or a definition's refs: interpolated into `raw`, it
48
+ * renders as the field's column. Its `key` is how an index tells a column from an expression.
49
+ */
50
+ export declare class ColumnRef<K extends string = string> extends QueryRaw {
51
+ readonly key: K;
52
+ constructor(key: K, value: QueryRawFn);
53
+ }
@@ -26,3 +26,14 @@ export class QueryRaw {
26
26
  }
27
27
  }
28
28
  }
29
+ /**
30
+ * A field of an entity as SQL, read off `refs(Entity)` or a definition's refs: interpolated into `raw`, it
31
+ * renders as the field's column. Its `key` is how an index tells a column from an expression.
32
+ */
33
+ export class ColumnRef extends QueryRaw {
34
+ key;
35
+ constructor(key, value) {
36
+ super(value);
37
+ this.key = key;
38
+ }
39
+ }
@@ -1,9 +1,11 @@
1
- import { type EntityIndexColumn, type IndexColumnInput, type IndexColumnSchema, QueryRaw } from '../type/index.js';
1
+ import { type EntityIndexColumn, type EntityIndexMeta, type EntityMeta, type IndexColumnInput, type IndexColumnSchema, QueryRaw } from '../type/index.js';
2
2
  /**
3
- * Reduces an authored index entry to the form metadata keeps, so the shapes users write - a column
4
- * name, an expression's callback, an options object - reach the schema as one, each callback resolved.
3
+ * Reduces an authored index entry to the form metadata keeps, so a column, an expression and an options
4
+ * object reach the schema as one: a column read off the refs as its key, any other `raw` as it is.
5
5
  */
6
6
  export declare function normalizeIndexColumn(entry: IndexColumnInput): EntityIndexColumn;
7
+ /** Every index an entity declares: each `@Field({ index })` as the one-column `@Index` it is, then its `@Index`es. */
8
+ export declare function declaredIndexes<E>(meta: EntityMeta<E>): EntityIndexMeta<E>[];
7
9
  /** An index entry as the schema holds it, its expression rendered to text by `render`. */
8
10
  export declare function renderIndexColumn(entry: EntityIndexColumn, render: (sql: QueryRaw) => string): IndexColumnSchema;
9
11
  /** What an unnamed index's name is built from: each entry's column, or `expr<n>` for an expression, which has none. */
@@ -1,18 +1,25 @@
1
- import { QueryRaw } from '../type/index.js';
2
- import { entitySql } from './raw.js';
1
+ import { ColumnRef, QueryRaw, } from '../type/index.js';
2
+ import { definedEntries } from './object.util.js';
3
3
  /**
4
- * Reduces an authored index entry to the form metadata keeps, so the shapes users write - a column
5
- * name, an expression's callback, an options object - reach the schema as one, each callback resolved.
4
+ * Reduces an authored index entry to the form metadata keeps, so a column, an expression and an options
5
+ * object reach the schema as one: a column read off the refs as its key, any other `raw` as it is.
6
6
  */
7
7
  export function normalizeIndexColumn(entry) {
8
- if (typeof entry === 'string') {
9
- return { column: entry };
10
- }
11
- if (typeof entry === 'function') {
12
- return { column: entitySql(entry) };
13
- }
14
- const { column } = entry;
15
- return { ...entry, column: typeof column === 'function' ? entitySql(column) : column };
8
+ const { column, ...modifiers } = typeof entry === 'string' || entry instanceof QueryRaw ? { column: entry } : entry;
9
+ return { ...modifiers, column: column instanceof ColumnRef ? column.key : column };
10
+ }
11
+ /** Every index an entity declares: each `@Field({ index })` as the one-column `@Index` it is, then its `@Index`es. */
12
+ export function declaredIndexes(meta) {
13
+ const fieldIndexes = definedEntries(meta.fields).flatMap(([key, field]) => field.index
14
+ ? [
15
+ {
16
+ columns: [{ column: key }],
17
+ name: typeof field.index === 'string' ? field.index : undefined,
18
+ unique: field.unique,
19
+ },
20
+ ]
21
+ : []);
22
+ return [...fieldIndexes, ...(meta.indexes ?? [])];
16
23
  }
17
24
  /** An index entry as the schema holds it, its expression rendered to text by `render`. */
18
25
  export function renderIndexColumn(entry, render) {
@@ -32,7 +32,12 @@ export declare function raw(value: QueryRawFn): QueryRaw;
32
32
  * in scope. Metadata is read when a ref renders, so the map serves before the fields are registered.
33
33
  */
34
34
  export declare function refs<E>(entity: Type<E>): RefMap<E>;
35
- /** SQL a definition writes, a callback's refs read off {@link MEMBER_REFS}. */
35
+ /**
36
+ * The refs a definition's callbacks read: an index's, a check's, a computed field's. A member decorator
37
+ * sees no class, so these name no entity and resolve against the one rendering them.
38
+ */
39
+ export declare function memberRefs<E>(): RefMap<E>;
40
+ /** SQL a definition writes, a callback's refs read off {@link memberRefs}. */
36
41
  export declare function entitySql<E>(sql: EntitySql<E>): QueryRaw;
37
42
  /** A definition's predicate, its callback resolved the way {@link entitySql} resolves one. */
38
43
  export declare function entityWhere<E>(where: EntityWhere<E>): EntityWhereMeta<E>;
package/dist/util/raw.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { getMeta } from '../entity/metadata/definition.js';
2
- import { QueryRaw, } from '../type/index.js';
2
+ import { ColumnRef, QueryRaw, } from '../type/index.js';
3
3
  import { isInlinedExpression } from './field.util.js';
4
4
  export function raw(value, ...rest) {
5
5
  if (!isTemplateStrings(value)) {
@@ -27,22 +27,25 @@ export function raw(value, ...rest) {
27
27
  export function refs(entity) {
28
28
  return new Proxy({}, { get: (_, key) => columnRef(entity, String(key)) });
29
29
  }
30
+ const MEMBER_REFS = new Proxy({}, { get: (_, key) => columnRef(undefined, String(key)) });
30
31
  /**
31
- * The refs a definition's callback reads. A member decorator sees no class, so these name no entity and
32
- * resolve against the one rendering them: a computed field's own, or the one whose schema is built.
32
+ * The refs a definition's callbacks read: an index's, a check's, a computed field's. A member decorator
33
+ * sees no class, so these name no entity and resolve against the one rendering them.
33
34
  */
34
- const MEMBER_REFS = new Proxy({}, { get: (_, key) => columnRef(undefined, String(key)) });
35
- /** SQL a definition writes, a callback's refs read off {@link MEMBER_REFS}. */
35
+ export function memberRefs() {
36
+ return MEMBER_REFS;
37
+ }
38
+ /** SQL a definition writes, a callback's refs read off {@link memberRefs}. */
36
39
  export function entitySql(sql) {
37
- return sql instanceof QueryRaw ? sql : sql(MEMBER_REFS);
40
+ return sql instanceof QueryRaw ? sql : sql(memberRefs());
38
41
  }
39
42
  /** A definition's predicate, its callback resolved the way {@link entitySql} resolves one. */
40
43
  export function entityWhere(where) {
41
- return typeof where === 'function' ? where(MEMBER_REFS) : where;
44
+ return typeof where === 'function' ? where(memberRefs()) : where;
42
45
  }
43
46
  /** One field as SQL, against its own entity or, read off a definition, the entity rendering it. */
44
47
  function columnRef(entity, key) {
45
- return new QueryRaw((opts) => {
48
+ return new ColumnRef(key, (opts) => {
46
49
  const owner = entity ?? opts.entity;
47
50
  if (!owner) {
48
51
  throw new TypeError(`'${key}' was read off a definition's refs, so it renders only inside its entity's SQL`);
@@ -32,7 +32,6 @@ const MYSQL_ESCAPES = {
32
32
  '\\': '\\\\',
33
33
  };
34
34
  const mysqlStringLiteral = (val) => `'${val.replace(MYSQL_SPECIALS, (char) => MYSQL_ESCAPES[char])}'`;
35
- const pad = (value, len) => String(value).padStart(len, '0');
36
35
  const HEX_BYTES = Array.from({ length: 256 }, (_, byte) => byte.toString(16).padStart(2, '0'));
37
36
  /** Native hex encoder where available (~130x faster on 4 KB); lookup table for browsers. */
38
37
  function bytesToHexLiteral(bytes) {
@@ -49,8 +48,11 @@ function bytesToHexLiteral(bytes) {
49
48
  * measured 1.1-1.5x slower. Rejects unsupported types rather than stringifying them into SQL.
50
49
  */
51
50
  function createEscaper(escapeString) {
52
- /** `YYYY-MM-DD HH:mm:ss.mmm` in local time, wrapped as a quoted literal. */
53
- const dateLiteral = (date) => escapeString(`${pad(date.getFullYear(), 4)}-${pad(date.getMonth() + 1, 2)}-${pad(date.getDate(), 2)} ${pad(date.getHours(), 2)}:${pad(date.getMinutes(), 2)}:${pad(date.getSeconds(), 2)}.${pad(date.getMilliseconds(), 3)}`);
51
+ /**
52
+ * `YYYY-MM-DD HH:mm:ss.SSS` in UTC, so the SQL is the same whichever machine wrote it. Not `toISOString`
53
+ * as it is, whose `T` and `Z` MySQL rejects outright ("Invalid default value").
54
+ */
55
+ const dateLiteral = (date) => escapeString(date.toISOString().replace('T', ' ').replace('Z', ''));
54
56
  const sqlList = (arr) => {
55
57
  let sql = '';
56
58
  for (let i = 0; i < arr.length; i++) {
@@ -8,7 +8,7 @@ import type { RawRow } from '../type/index.js';
8
8
  export declare function decodeWideNumber(value: string | bigint): number | string;
9
9
  /**
10
10
  * {@link decodeWideNumber} over every `bigint` cell of a row, for the drivers that hand a BIGINT back
11
- * as one (`bun:sql` with `bigint: true`, `mariadb`). In place: the row is the driver's fresh object, and
12
- * a copy per row cost more than the decode it carried.
11
+ * as one (`bun:sql`, `mariadb`, and every SQLite driver but D1). In place: the row is the driver's fresh
12
+ * object, and a copy per row cost more than the decode it carried.
13
13
  */
14
14
  export declare function decodeBigInts(row: RawRow): RawRow;
@@ -10,8 +10,8 @@ export function decodeWideNumber(value) {
10
10
  }
11
11
  /**
12
12
  * {@link decodeWideNumber} over every `bigint` cell of a row, for the drivers that hand a BIGINT back
13
- * as one (`bun:sql` with `bigint: true`, `mariadb`). In place: the row is the driver's fresh object, and
14
- * a copy per row cost more than the decode it carried.
13
+ * as one (`bun:sql`, `mariadb`, and every SQLite driver but D1). In place: the row is the driver's fresh
14
+ * object, and a copy per row cost more than the decode it carried.
15
15
  */
16
16
  export function decodeBigInts(row) {
17
17
  for (const key in row) {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "homepage": "https://uql-orm.dev",
4
4
  "description": "The JSON-native TypeScript ORM for Bun, Browsers, Edge, Deno, Node, Workers. Supports PostgreSQL, PGlite, MySQL, MariaDB, SQLite, CockroachDB, SQL Server, Turso, Neon, Cloudflare D1 and MongoDB. Queries are plain JSON, typed to the leaf.",
5
5
  "license": "MIT",
6
- "version": "0.62.0",
6
+ "version": "0.64.0",
7
7
  "type": "module",
8
8
  "engines": {
9
9
  "node": ">=24"
@@ -71,7 +71,7 @@
71
71
  "@nestjs/common": ">=10.0.0",
72
72
  "@nestjs/core": ">=10.0.0",
73
73
  "@tursodatabase/database": ">=0.7.0",
74
- "@tursodatabase/serverless": ">=1.0.0",
74
+ "@tursodatabase/serverless": ">=1.3.0",
75
75
  "better-sqlite3": ">=9.0.0",
76
76
  "express": ">=5.0.0",
77
77
  "mariadb": ">=3.0.0",
@@ -1,7 +0,0 @@
1
- import type { ForeignKeyAction } from '../schema/types.js';
2
- import type { MigratorDialect, SchemaGenerator } from '../type/index.js';
3
- /**
4
- * Async factory for schema generators. Use this for MongoDB so the optional peer
5
- * `mongodb` is only loaded when this path runs. SQL dialects delegate to {@link createSchemaGenerator}.
6
- */
7
- export declare function createSchemaGeneratorAsync(dialect: MigratorDialect, defaultForeignKeyAction?: ForeignKeyAction): Promise<SchemaGenerator | undefined>;
@@ -1,12 +0,0 @@
1
- import { createSchemaGenerator } from './schemaGenerator.js';
2
- /**
3
- * Async factory for schema generators. Use this for MongoDB so the optional peer
4
- * `mongodb` is only loaded when this path runs. SQL dialects delegate to {@link createSchemaGenerator}.
5
- */
6
- export async function createSchemaGeneratorAsync(dialect, defaultForeignKeyAction) {
7
- if (dialect.dialectName === 'mongodb') {
8
- const { MongoSchemaGenerator } = await import('./generator/mongoSchemaGenerator.js');
9
- return new MongoSchemaGenerator(dialect.namingStrategy, defaultForeignKeyAction);
10
- }
11
- return createSchemaGenerator(dialect, defaultForeignKeyAction);
12
- }
@@ -1,20 +0,0 @@
1
- import { AbstractSqlQuerierPool } from '../querier/index.js';
2
- import { type HranaClient, HranaQuerier } from './hranaQuerier.js';
3
- import type { SqliteDialect } from './sqliteDialect.js';
4
- /**
5
- * Pool for SQLite databases reached over the Hrana wire protocol (`@libsql/client`,
6
- * `@tursodatabase/serverless/compat`).
7
- *
8
- * @remarks The client is shared by every querier, since Hrana keeps no per-connection state: a
9
- * transaction takes its own session handle. It is resolved on first use rather than in the
10
- * constructor, so building a pool never throws when the optional driver peer is absent, which is what
11
- * lets a Workers bundle construct one at module scope.
12
- */
13
- export declare abstract class AbstractHranaQuerierPool<D extends SqliteDialect> extends AbstractSqlQuerierPool<HranaQuerier, D> {
14
- private client?;
15
- /** False when the caller injected their own client, in which case they own its lifecycle. */
16
- protected readonly ownsClient: boolean;
17
- protected abstract openClient(): Promise<HranaClient>;
18
- getQuerier(): Promise<HranaQuerier>;
19
- end(): Promise<void>;
20
- }
@@ -1,26 +0,0 @@
1
- import { AbstractSqlQuerierPool } from '../querier/index.js';
2
- import { HranaQuerier } from './hranaQuerier.js';
3
- /**
4
- * Pool for SQLite databases reached over the Hrana wire protocol (`@libsql/client`,
5
- * `@tursodatabase/serverless/compat`).
6
- *
7
- * @remarks The client is shared by every querier, since Hrana keeps no per-connection state: a
8
- * transaction takes its own session handle. It is resolved on first use rather than in the
9
- * constructor, so building a pool never throws when the optional driver peer is absent, which is what
10
- * lets a Workers bundle construct one at module scope.
11
- */
12
- export class AbstractHranaQuerierPool extends AbstractSqlQuerierPool {
13
- client;
14
- /** False when the caller injected their own client, in which case they own its lifecycle. */
15
- ownsClient = true;
16
- async getQuerier() {
17
- this.client ??= await this.openClient();
18
- return new HranaQuerier(this.client, this.dialect, this.extra);
19
- }
20
- async end() {
21
- if (this.ownsClient) {
22
- this.client?.close();
23
- }
24
- this.client = undefined;
25
- }
26
- }
@@ -1,24 +0,0 @@
1
- import { PreparedSqliteQuerier, type SqlitePreparedStatement } from '../sqlite/abstractSqliteQuerier.js';
2
- import type { SqliteDialect } from '../sqlite/sqliteDialect.js';
3
- import type { ExtraOptions } from '../type/index.js';
4
- /**
5
- * Structural subset of the `@tursodatabase/database` API actually used here, declared locally so
6
- * this package does not couple its published types to a pre-1.0 dependency.
7
- */
8
- export type TursoDatabase = {
9
- prepare(sql: string): Promise<SqlitePreparedStatement>;
10
- close(): Promise<void>;
11
- };
12
- /**
13
- * Querier for the embedded Turso engine.
14
- *
15
- * @remarks The engine exposes better-sqlite3 semantics (`reader`, `{changes, lastInsertRowid}`,
16
- * array-bound values) over an async API, so all it supplies is the awaited `prepare`.
17
- * `BEGIN`/`COMMIT` work as plain statements, leaving transactions to the base class.
18
- */
19
- export declare class TursoLocalQuerier extends PreparedSqliteQuerier {
20
- readonly db: TursoDatabase;
21
- readonly extra?: ExtraOptions | undefined;
22
- constructor(db: TursoDatabase, dialect: SqliteDialect, extra?: ExtraOptions | undefined);
23
- protected prepare(query: string): Promise<SqlitePreparedStatement>;
24
- }
@@ -1,20 +0,0 @@
1
- import { PreparedSqliteQuerier } from '../sqlite/abstractSqliteQuerier.js';
2
- /**
3
- * Querier for the embedded Turso engine.
4
- *
5
- * @remarks The engine exposes better-sqlite3 semantics (`reader`, `{changes, lastInsertRowid}`,
6
- * array-bound values) over an async API, so all it supplies is the awaited `prepare`.
7
- * `BEGIN`/`COMMIT` work as plain statements, leaving transactions to the base class.
8
- */
9
- export class TursoLocalQuerier extends PreparedSqliteQuerier {
10
- db;
11
- extra;
12
- constructor(db, dialect, extra) {
13
- super(dialect, extra);
14
- this.db = db;
15
- this.extra = extra;
16
- }
17
- prepare(query) {
18
- return this.db.prepare(query);
19
- }
20
- }