uql-orm 0.21.0 → 0.23.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 (214) hide show
  1. package/README.md +5 -4
  2. package/dist/browser/uql-browser.min.js.map +3 -3
  3. package/dist/bunSql/bunSqlCockroachDialect.d.ts +2 -2
  4. package/dist/bunSql/bunSqlCockroachDialect.js +4 -10
  5. package/dist/bunSql/bunSqlPostgresDialect.d.ts +2 -2
  6. package/dist/bunSql/bunSqlPostgresDialect.js +4 -10
  7. package/dist/cockroachdb/cockroachDialect.d.ts +20 -4
  8. package/dist/cockroachdb/cockroachDialect.js +33 -18
  9. package/dist/d1/d1Querier.d.ts +4 -3
  10. package/dist/d1/d1Querier.js +0 -3
  11. package/dist/d1/d1SqliteDialect.d.ts +7 -0
  12. package/dist/d1/d1SqliteDialect.js +9 -0
  13. package/dist/dialect/abstractDialect.d.ts +8 -3
  14. package/dist/dialect/abstractDialect.js +9 -4
  15. package/dist/dialect/abstractSqlDialect.d.ts +49 -8
  16. package/dist/dialect/abstractSqlDialect.js +95 -47
  17. package/dist/dialect/index.d.ts +1 -0
  18. package/dist/dialect/index.js +1 -0
  19. package/dist/dialect/indexSqlDialect.d.ts +57 -0
  20. package/dist/dialect/indexSqlDialect.js +101 -0
  21. package/dist/dialect/mysqlLikeSqlDialect.d.ts +26 -1
  22. package/dist/dialect/mysqlLikeSqlDialect.js +57 -1
  23. package/dist/dialect/pgLikeSqlDialect.d.ts +37 -22
  24. package/dist/dialect/pgLikeSqlDialect.js +97 -68
  25. package/dist/dialect/vectorCast.d.ts +21 -0
  26. package/dist/dialect/vectorCast.js +28 -0
  27. package/dist/dialect/vectorSqlDialect.d.ts +10 -3
  28. package/dist/dialect/vectorSqlDialect.js +19 -8
  29. package/dist/entity/decorator/bag.d.ts +35 -0
  30. package/dist/entity/decorator/bag.js +54 -0
  31. package/dist/entity/decorator/entity.d.ts +28 -2
  32. package/dist/entity/decorator/entity.js +40 -2
  33. package/dist/entity/decorator/members.d.ts +51 -0
  34. package/dist/entity/decorator/members.js +51 -0
  35. package/dist/entity/index.d.ts +3 -1
  36. package/dist/entity/index.js +3 -1
  37. package/dist/entity/metadata/definition.d.ts +23 -8
  38. package/dist/entity/metadata/definition.js +56 -100
  39. package/dist/http/contract.js +1 -2
  40. package/dist/http/handler.js +5 -26
  41. package/dist/http/query.js +1 -1
  42. package/dist/libsql/libsqlDialect.d.ts +12 -2
  43. package/dist/libsql/libsqlDialect.js +14 -2
  44. package/dist/libsql/libsqlQuerier.d.ts +9 -22
  45. package/dist/libsql/libsqlQuerier.js +9 -85
  46. package/dist/libsql/libsqlQuerierPool.d.ts +10 -8
  47. package/dist/libsql/libsqlQuerierPool.js +17 -15
  48. package/dist/maria/mariaDialect.d.ts +26 -4
  49. package/dist/maria/mariaDialect.js +54 -15
  50. package/dist/migrate/acquireQuerierForMigrations.d.ts +13 -1
  51. package/dist/migrate/acquireQuerierForMigrations.js +28 -0
  52. package/dist/migrate/builder/migrationBuilder.d.ts +9 -29
  53. package/dist/migrate/builder/migrationBuilder.js +58 -76
  54. package/dist/migrate/builder/splitSqlStatements.d.ts +0 -2
  55. package/dist/migrate/builder/splitSqlStatements.js +0 -2
  56. package/dist/migrate/builder/tableBuilder.d.ts +12 -2
  57. package/dist/migrate/builder/tableBuilder.js +71 -119
  58. package/dist/migrate/builder/types.d.ts +30 -41
  59. package/dist/migrate/cli-config.js +24 -8
  60. package/dist/migrate/cli.d.ts +3 -2
  61. package/dist/migrate/cli.js +26 -49
  62. package/dist/migrate/codegen/entityCodeGenerator.d.ts +0 -4
  63. package/dist/migrate/codegen/entityCodeGenerator.js +8 -67
  64. package/dist/migrate/codegen/fieldOptionsSource.d.ts +10 -0
  65. package/dist/migrate/codegen/fieldOptionsSource.js +55 -0
  66. package/dist/migrate/codegen/index.d.ts +0 -3
  67. package/dist/migrate/codegen/index.js +0 -6
  68. package/dist/migrate/drift/driftDetector.d.ts +10 -1
  69. package/dist/migrate/drift/driftDetector.js +22 -5
  70. package/dist/migrate/generator/indexNodeToSchema.d.ts +9 -0
  71. package/dist/migrate/generator/indexNodeToSchema.js +14 -0
  72. package/dist/migrate/generator/mongoCommand.d.ts +57 -0
  73. package/dist/migrate/generator/mongoCommand.js +26 -0
  74. package/dist/migrate/generator/mongoSchemaGenerator.d.ts +9 -20
  75. package/dist/migrate/generator/mongoSchemaGenerator.js +40 -82
  76. package/dist/migrate/index.d.ts +0 -1
  77. package/dist/migrate/index.js +0 -1
  78. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.d.ts +30 -11
  79. package/dist/migrate/introspection/abstractSqlSchemaIntrospector.js +61 -57
  80. package/dist/migrate/introspection/baseSqlIntrospector.d.ts +0 -1
  81. package/dist/migrate/introspection/baseSqlIntrospector.js +3 -12
  82. package/dist/migrate/introspection/mongoIntrospector.js +9 -15
  83. package/dist/migrate/introspection/mysqlIntrospector.d.ts +5 -8
  84. package/dist/migrate/introspection/mysqlIntrospector.js +4 -10
  85. package/dist/migrate/introspection/postgresIntrospector.d.ts +5 -8
  86. package/dist/migrate/introspection/postgresIntrospector.js +4 -10
  87. package/dist/migrate/introspection/sqliteIntrospector.d.ts +6 -5
  88. package/dist/migrate/introspection/sqliteIntrospector.js +26 -18
  89. package/dist/migrate/migrator.d.ts +23 -3
  90. package/dist/migrate/migrator.js +101 -150
  91. package/dist/migrate/schemaGenerator.d.ts +26 -37
  92. package/dist/migrate/schemaGenerator.js +69 -174
  93. package/dist/migrate/schemaGeneratorAsync.d.ts +2 -2
  94. package/dist/migrate/schemaGeneratorAsync.js +3 -3
  95. package/dist/migrate/storage/databaseStorage.d.ts +2 -0
  96. package/dist/migrate/storage/databaseStorage.js +12 -27
  97. package/dist/mongo/mongoDialect.d.ts +2 -0
  98. package/dist/mongo/mongoDialect.js +14 -3
  99. package/dist/mongo/mongodbQuerier.js +171 -229
  100. package/dist/mysql/mysqlDialect.d.ts +8 -0
  101. package/dist/mysql/mysqlDialect.js +13 -0
  102. package/dist/nestjs/uqlContextInterceptor.js +58 -22
  103. package/dist/nestjs/uqlModule.d.ts +2 -11
  104. package/dist/nestjs/uqlModule.js +93 -44
  105. package/dist/postgres/postgresDialect.js +2 -2
  106. package/dist/querier/abstractQuerier.d.ts +28 -0
  107. package/dist/querier/abstractQuerier.js +47 -22
  108. package/dist/querier/abstractQuerierPool.d.ts +3 -0
  109. package/dist/querier/abstractQuerierPool.js +5 -3
  110. package/dist/querier/abstractSqlQuerier.d.ts +1 -3
  111. package/dist/querier/abstractSqlQuerier.js +48 -96
  112. package/dist/querier/index.d.ts +3 -1
  113. package/dist/querier/index.js +3 -1
  114. package/dist/querier/querierContext.browser.d.ts +12 -0
  115. package/dist/querier/querierContext.browser.js +18 -0
  116. package/dist/querier/querierContext.d.ts +22 -0
  117. package/dist/querier/querierContext.js +42 -0
  118. package/dist/querier/queryError.d.ts +22 -0
  119. package/dist/querier/queryError.js +20 -0
  120. package/dist/querier/transactional.d.ts +26 -0
  121. package/dist/querier/transactional.js +43 -0
  122. package/dist/schema/canonicalType.d.ts +14 -2
  123. package/dist/schema/canonicalType.js +41 -31
  124. package/dist/schema/index.d.ts +1 -1
  125. package/dist/schema/schemaASTBuilder.d.ts +9 -2
  126. package/dist/schema/schemaASTBuilder.js +58 -49
  127. package/dist/schema/types.d.ts +10 -58
  128. package/dist/sqlite/abstractSqliteQuerier.d.ts +46 -0
  129. package/dist/sqlite/abstractSqliteQuerier.js +44 -0
  130. package/dist/sqlite/bunSqliteAdapter.bun.d.ts +26 -0
  131. package/dist/sqlite/bunSqliteAdapter.bun.js +25 -0
  132. package/dist/sqlite/hranaQuerier.d.ts +54 -0
  133. package/dist/sqlite/hranaQuerier.js +68 -0
  134. package/dist/sqlite/hranaQuerierPool.d.ts +21 -0
  135. package/dist/sqlite/hranaQuerierPool.js +25 -0
  136. package/dist/sqlite/index.d.ts +3 -1
  137. package/dist/sqlite/index.js +3 -1
  138. package/dist/sqlite/localSqliteQuerierPool.d.ts +31 -0
  139. package/dist/sqlite/localSqliteQuerierPool.js +34 -0
  140. package/dist/sqlite/nodeSqliteAdapter.d.ts +35 -0
  141. package/dist/sqlite/nodeSqliteAdapter.js +28 -0
  142. package/dist/sqlite/nodeSqliteQuerierPool.d.ts +28 -0
  143. package/dist/sqlite/nodeSqliteQuerierPool.js +29 -0
  144. package/dist/sqlite/sqliteDialect.d.ts +18 -5
  145. package/dist/sqlite/sqliteDialect.js +23 -36
  146. package/dist/sqlite/sqliteQuerier.d.ts +16 -9
  147. package/dist/sqlite/sqliteQuerier.js +4 -27
  148. package/dist/sqlite/sqliteQuerierPool.d.ts +11 -14
  149. package/dist/sqlite/sqliteQuerierPool.js +16 -24
  150. package/dist/turso/index.d.ts +3 -0
  151. package/dist/turso/index.js +3 -0
  152. package/dist/turso/local.d.ts +3 -0
  153. package/dist/turso/local.js +3 -0
  154. package/dist/turso/tursoDialect.d.ts +15 -0
  155. package/dist/turso/tursoDialect.js +18 -0
  156. package/dist/turso/tursoLocalQuerier.d.ts +25 -0
  157. package/dist/turso/tursoLocalQuerier.js +20 -0
  158. package/dist/turso/tursoLocalQuerierPool.d.ts +32 -0
  159. package/dist/turso/tursoLocalQuerierPool.js +39 -0
  160. package/dist/turso/tursoQuerier.d.ts +10 -0
  161. package/dist/turso/tursoQuerier.js +10 -0
  162. package/dist/turso/tursoQuerierPool.d.ts +39 -0
  163. package/dist/turso/tursoQuerierPool.js +38 -0
  164. package/dist/type/config.d.ts +0 -6
  165. package/dist/type/dialect.d.ts +12 -4
  166. package/dist/type/dialect.js +7 -1
  167. package/dist/type/entity.d.ts +154 -26
  168. package/dist/type/migration.d.ts +32 -23
  169. package/dist/type/querier.d.ts +6 -0
  170. package/dist/type/vector.d.ts +5 -2
  171. package/dist/util/hook.util.js +1 -1
  172. package/dist/util/index.d.ts +1 -0
  173. package/dist/util/index.js +1 -0
  174. package/dist/util/indexColumn.util.d.ts +6 -0
  175. package/dist/util/indexColumn.util.js +26 -0
  176. package/package.json +21 -16
  177. package/dist/entity/decorator/field.d.ts +0 -2
  178. package/dist/entity/decorator/field.js +0 -7
  179. package/dist/entity/decorator/filter.d.ts +0 -7
  180. package/dist/entity/decorator/filter.js +0 -11
  181. package/dist/entity/decorator/hook.d.ts +0 -7
  182. package/dist/entity/decorator/hook.js +0 -14
  183. package/dist/entity/decorator/id.d.ts +0 -2
  184. package/dist/entity/decorator/id.js +0 -7
  185. package/dist/entity/decorator/index-decorator.d.ts +0 -29
  186. package/dist/entity/decorator/index-decorator.js +0 -26
  187. package/dist/entity/decorator/index.d.ts +0 -8
  188. package/dist/entity/decorator/index.js +0 -8
  189. package/dist/entity/decorator/relation.d.ts +0 -8
  190. package/dist/entity/decorator/relation.js +0 -19
  191. package/dist/migrate/codegen/entityMerger.d.ts +0 -114
  192. package/dist/migrate/codegen/entityMerger.js +0 -293
  193. package/dist/migrate/codegen/migrationCodeGenerator.d.ts +0 -61
  194. package/dist/migrate/codegen/migrationCodeGenerator.js +0 -355
  195. package/dist/migrate/codegen/smartRelationDetector.d.ts +0 -47
  196. package/dist/migrate/codegen/smartRelationDetector.js +0 -134
  197. package/dist/migrate/generator/index.d.ts +0 -2
  198. package/dist/migrate/generator/index.js +0 -2
  199. package/dist/migrate/sync/index.d.ts +0 -6
  200. package/dist/migrate/sync/index.js +0 -6
  201. package/dist/migrate/sync/schemaSync.d.ts +0 -131
  202. package/dist/migrate/sync/schemaSync.js +0 -259
  203. package/dist/querier/decorator/index.d.ts +0 -4
  204. package/dist/querier/decorator/index.js +0 -4
  205. package/dist/querier/decorator/injectQuerier.d.ts +0 -3
  206. package/dist/querier/decorator/injectQuerier.js +0 -33
  207. package/dist/querier/decorator/log.d.ts +0 -32
  208. package/dist/querier/decorator/log.js +0 -52
  209. package/dist/querier/decorator/serialized.d.ts +0 -6
  210. package/dist/querier/decorator/serialized.js +0 -13
  211. package/dist/querier/decorator/transactional.d.ts +0 -6
  212. package/dist/querier/decorator/transactional.js +0 -48
  213. package/dist/sqlite/betterSqlite3Dialect.d.ts +0 -9
  214. package/dist/sqlite/betterSqlite3Dialect.js +0 -9
@@ -0,0 +1,51 @@
1
+ import { memberRegistrations } from './bag.js';
2
+ export function Field(opts) {
3
+ return (_value, context) => {
4
+ memberRegistrations(context.metadata).fields[String(context.name)] = opts;
5
+ };
6
+ }
7
+ /**
8
+ * Declares the primary key, checked the same way as `@Field`.
9
+ *
10
+ * @example `@Id({ type: Number }) id?: number;`
11
+ * @example `@Id({ type: 'uuid', onInsert: uuidv7 }) id?: string;`
12
+ */
13
+ export function Id(opts) {
14
+ return (_value, context) => {
15
+ memberRegistrations(context.metadata).fields[String(context.name)] = { ...opts, isId: true };
16
+ };
17
+ }
18
+ function relation(opts) {
19
+ return (_value, context) => {
20
+ memberRegistrations(context.metadata).relations[String(context.name)] = opts;
21
+ };
22
+ }
23
+ export function OneToOne(opts) {
24
+ return relation({ cardinality: '11', ...opts });
25
+ }
26
+ export function ManyToOne(opts) {
27
+ return relation({ cardinality: 'm1', ...opts });
28
+ }
29
+ export function OneToMany(opts) {
30
+ return relation({ cardinality: '1m', ...opts });
31
+ }
32
+ export function ManyToMany(opts) {
33
+ return relation({ cardinality: 'mm', ...opts });
34
+ }
35
+ function hook(event) {
36
+ return () =>
37
+ // Generic in `This` so a hook declared with an explicit `this` parameter still matches; the default
38
+ // on `ClassMethodDecoratorContext` pins `this` to `unknown` and would reject it.
39
+ (_value, context) => {
40
+ const { hooks } = memberRegistrations(context.metadata);
41
+ hooks[event] ??= [];
42
+ hooks[event].push(String(context.name));
43
+ };
44
+ }
45
+ export const BeforeInsert = hook('beforeInsert');
46
+ export const AfterInsert = hook('afterInsert');
47
+ export const BeforeUpdate = hook('beforeUpdate');
48
+ export const AfterUpdate = hook('afterUpdate');
49
+ export const BeforeDelete = hook('beforeDelete');
50
+ export const AfterDelete = hook('afterDelete');
51
+ export const AfterLoad = hook('afterLoad');
@@ -1 +1,3 @@
1
- export * from './decorator/index.js';
1
+ export * from './decorator/entity.js';
2
+ export * from './decorator/members.js';
3
+ export { defineEntity, defineField, defineFilter, defineHook, defineId, defineIndex, defineRelation, getEntities, getMeta, } from './metadata/definition.js';
@@ -1 +1,3 @@
1
- export * from './decorator/index.js';
1
+ export * from './decorator/entity.js';
2
+ export * from './decorator/members.js';
3
+ export { defineEntity, defineField, defineFilter, defineHook, defineId, defineIndex, defineRelation, getEntities, getMeta, } from './metadata/definition.js';
@@ -1,16 +1,31 @@
1
- import type { EntityIndexMeta, EntityMeta, EntityOptions, FieldOptions, FilterOptions, HookEvent, RelationOptions, Type } from '../../type/index.js';
2
- /**
3
- * Append a composite index entry with normalized `unique` (default false).
4
- */
5
- export declare function appendEntityIndex<E>(meta: EntityMeta<E>, index: EntityIndexMeta): void;
1
+ import type { EntityIndexInput, EntityMeta, EntityOptions, FieldKey, FieldOptions, FilterOptions, HookEvent, RelationOptions, Type } from '../../type/index.js';
6
2
  export declare function defineField<E>(entity: Type<E>, key: string, opts?: FieldOptions): EntityMeta<E>;
7
3
  export declare function defineId<E>(entity: Type<E>, key: string, opts: FieldOptions): EntityMeta<E>;
8
- export declare function defineRelation<E>(entity: Type<E>, key: string, opts: RelationOptions<E>): EntityMeta<E>;
4
+ export declare function defineRelation<E>(entity: Type<E>, key: string, opts: RelationOptions): EntityMeta<E>;
9
5
  export declare function defineHook<E>(entity: Type<E>, methodName: string, event: HookEvent): EntityMeta<E>;
10
- export declare function defineIndex<E>(entity: Type<E>, index: EntityIndexMeta): EntityMeta<E>;
6
+ /**
7
+ * Declares a composite index. `unique` and the authored column sugar are normalized here, which is what
8
+ * lets the dialects render one shape instead of re-parsing it.
9
+ */
10
+ export declare function defineIndex<E>(entity: Type<E>, index: EntityIndexInput<FieldKey<E>>): EntityMeta<E>;
11
11
  export declare function defineFilter<E>(entity: Type<E>, name: string, opts: FilterOptions<E>): EntityMeta<E>;
12
+ /**
13
+ * What a decorator bag and {@link EntityOptions} have in common at registration time. The keyed mapped
14
+ * types in `EntityOptions<E>` are what check the imperative call; a member decorator has no class to key
15
+ * against, so by the time either reaches the primitives the keys are plain strings.
16
+ */
17
+ type MemberSpecs = {
18
+ readonly fields?: Readonly<Record<string, FieldOptions | undefined>>;
19
+ readonly relations?: Readonly<Record<string, RelationOptions | undefined>>;
20
+ readonly hooks?: Readonly<Partial<Record<HookEvent, readonly string[]>>>;
21
+ };
22
+ /**
23
+ * Feeds fields, relations and hooks into the `define*` primitives, so the decorators and the imperative
24
+ * API converge on one registration path before anything is finalized.
25
+ */
26
+ export declare function applyMembers<E>(entity: Type<E>, specs: MemberSpecs | undefined): void;
12
27
  export declare function defineEntity<E>(entity: Type<E>, opts?: EntityOptions<E>): EntityMeta<E>;
13
28
  export declare function getEntities(): Type<unknown>[];
14
29
  export declare function ensureMeta<E>(entity: Type<E>): EntityMeta<E>;
15
30
  export declare function getMeta<E>(entity: Type<E>): EntityMeta<E>;
16
- export declare function isValidEntityType(type: unknown): type is Type<unknown>;
31
+ export {};
@@ -1,51 +1,45 @@
1
- import { getKeys, hasKeys, lowerFirst, upperFirst } from '../../util/index.js';
2
- import { LoggerWrapper } from '../../util/logger.js';
1
+ import { getKeys, hasKeys, lowerFirst, normalizeIndexColumn, upperFirst } from '../../util/index.js';
2
+ import { ownRegistrations } from '../decorator/bag.js';
3
3
  // Held on `globalThis` via the global symbol registry so a single metadata map survives multiple
4
- // evaluations of this module (HMR, duplicated/federated bundles, ESM+CJS dual-loading).
4
+ // evaluations of this module (HMR, duplicated/federated bundles, ESM+CJS dual-loading). Version-suffixed
5
+ // because v1 changed the `FieldOptions` shape: a tree holding both majors gets two maps rather than one
6
+ // map with entries the other major cannot read.
5
7
  const holder = globalThis;
6
- const metaKey = Symbol.for('uql-orm/entity/metadata');
8
+ const metaKey = Symbol.for('uql-orm/entity/metadata/v1');
7
9
  const metas = holder[metaKey] ?? new Map();
8
10
  holder[metaKey] = metas;
9
- const registrationLogger = new LoggerWrapper(true);
10
- /**
11
- * Append a composite index entry with normalized `unique` (default false).
12
- */
13
- export function appendEntityIndex(meta, index) {
14
- if (!meta.indexes)
15
- meta.indexes = [];
16
- meta.indexes.push({ ...index, unique: index.unique ?? false });
17
- }
18
11
  export function defineField(entity, key, opts = {}) {
19
12
  const meta = ensureMeta(entity);
20
- if (opts.type) {
21
- opts = { ...opts, typeInferred: false };
22
- }
23
- else {
24
- opts = { ...opts, type: inferType(entity, key), typeInferred: true };
13
+ if (!opts.type && !opts.references && !opts.virtual) {
14
+ throw new TypeError(`'${entity.name}.${key}' needs a 'type'. Declare it - '@Field({ type: String })' - or point the field ` +
15
+ "at another entity with 'references', which resolves the column type from its primary key.");
25
16
  }
26
17
  const fieldKey = key;
27
- meta.fields[fieldKey] = { ...meta.fields[fieldKey], ...{ name: key, ...opts } };
18
+ // Flagged when the author gave `references` but no `type`, so schema generation knows to resolve the
19
+ // column from the referenced primary key (picking up its `columnType`, length and chained keys)
20
+ // instead of treating whatever ends up in `type` as deliberate.
21
+ const resolved = opts.type ? opts : { ...opts, typeFromReference: true };
22
+ meta.fields[fieldKey] = { ...meta.fields[fieldKey], ...{ name: key, ...resolved } };
28
23
  return meta;
29
24
  }
30
25
  export function defineId(entity, key, opts) {
31
26
  const meta = ensureMeta(entity);
32
27
  const id = getIdKey(meta);
33
28
  if (id) {
34
- registrationLogger.logInfo(`Overriding ID property for '${entity.name}' from '${id}' to '${key}'`);
29
+ // A subclass narrowing the inherited primary key: drop the old one so exactly one stays marked.
35
30
  delete meta.fields[id];
36
31
  }
37
32
  return defineField(entity, key, { ...opts, isId: true });
38
33
  }
34
+ // `RelationOptions` is parameterized by the *target* entity, which is independent of the owner `E`, so it
35
+ // is left at its default here rather than tied to the class being registered.
39
36
  export function defineRelation(entity, key, opts) {
40
- const resolved = opts.entity
41
- ? opts
42
- : (() => {
43
- const inferredType = inferEntityType(entity, key);
44
- return { ...opts, entity: () => inferredType };
45
- })();
37
+ if (!opts.entity) {
38
+ throw new TypeError(`'${entity.name}.${key}' needs an 'entity' getter, e.g. '@ManyToOne({ entity: () => Company })'.`);
39
+ }
46
40
  const meta = ensureMeta(entity);
47
41
  const relKey = key;
48
- meta.relations[relKey] = { ...meta.relations[relKey], ...resolved };
42
+ meta.relations[relKey] = { ...meta.relations[relKey], ...opts };
49
43
  return meta;
50
44
  }
51
45
  export function defineHook(entity, methodName, event) {
@@ -57,9 +51,15 @@ export function defineHook(entity, methodName, event) {
57
51
  meta.hooks[event].push({ methodName });
58
52
  return meta;
59
53
  }
54
+ /**
55
+ * Declares a composite index. `unique` and the authored column sugar are normalized here, which is what
56
+ * lets the dialects render one shape instead of re-parsing it.
57
+ */
60
58
  export function defineIndex(entity, index) {
61
59
  const meta = ensureMeta(entity);
62
- appendEntityIndex(meta, index);
60
+ if (!meta.indexes)
61
+ meta.indexes = [];
62
+ meta.indexes.push({ ...index, unique: index.unique ?? false, columns: index.columns.map(normalizeIndexColumn) });
63
63
  return meta;
64
64
  }
65
65
  export function defineFilter(entity, name, opts) {
@@ -75,9 +75,12 @@ export function defineFilter(entity, name, opts) {
75
75
  meta.filters[name] = opts;
76
76
  return meta;
77
77
  }
78
- function applyBulkFields(entity, fields) {
79
- for (const key of Object.keys(fields)) {
80
- const spec = fields[key];
78
+ /**
79
+ * Feeds fields, relations and hooks into the `define*` primitives, so the decorators and the imperative
80
+ * API converge on one registration path before anything is finalized.
81
+ */
82
+ export function applyMembers(entity, specs) {
83
+ for (const [key, spec] of Object.entries(specs?.fields ?? {})) {
81
84
  if (!spec)
82
85
  continue;
83
86
  if (spec.isId) {
@@ -87,64 +90,43 @@ function applyBulkFields(entity, fields) {
87
90
  defineField(entity, key, spec);
88
91
  }
89
92
  }
90
- }
91
- function applyBulkRelations(entity, relations) {
92
- for (const key of Object.keys(relations)) {
93
- const spec = relations[key];
93
+ for (const [key, spec] of Object.entries(specs?.relations ?? {})) {
94
94
  if (spec)
95
95
  defineRelation(entity, key, spec);
96
96
  }
97
- }
98
- function applyBulkIndexes(entity, indexes) {
99
- const meta = ensureMeta(entity);
100
- for (const idx of indexes) {
101
- appendEntityIndex(meta, idx);
102
- }
103
- }
104
- function applyBulkHooks(entity, hooks) {
105
- for (const event of Object.keys(hooks)) {
106
- const methodNames = hooks[event];
107
- if (!methodNames?.length)
108
- continue;
109
- for (const methodName of methodNames) {
97
+ for (const [event, methodNames] of Object.entries(specs?.hooks ?? {})) {
98
+ for (const methodName of methodNames ?? []) {
110
99
  defineHook(entity, methodName, event);
111
100
  }
112
101
  }
113
102
  }
114
- function applyBulkFilters(entity, filters) {
115
- for (const name of Object.keys(filters)) {
116
- const spec = filters[name];
103
+ export function defineEntity(entity, opts = {}) {
104
+ const meta = ensureMeta(entity);
105
+ // Covers `defineEntity(Decorated)` called on a class whose members carry decorators. `@Entity()`
106
+ // drains `context.metadata` itself, because TypeScript only attaches `Symbol.metadata` to the class
107
+ // after class decorators return; draining empties the bag, so whichever runs second is a no-op.
108
+ applyMembers(entity, ownRegistrations(entity));
109
+ applyMembers(entity, opts);
110
+ for (const index of opts.indexes ?? []) {
111
+ defineIndex(entity, index);
112
+ }
113
+ for (const [name, spec] of Object.entries(opts.filters ?? {})) {
117
114
  if (spec)
118
115
  defineFilter(entity, name, spec);
119
116
  }
120
- }
121
- /**
122
- * Applies `fields`, `relations`, `indexes`, and `hooks` from {@link EntityOptions} before
123
- * entity finalization. Used by `defineEntity` for decorator-free registration.
124
- */
125
- function applyBulkEntityOptions(entity, opts) {
126
- if (opts.fields)
127
- applyBulkFields(entity, opts.fields);
128
- if (opts.relations)
129
- applyBulkRelations(entity, opts.relations);
130
- if (opts.indexes?.length)
131
- applyBulkIndexes(entity, opts.indexes);
132
- if (opts.hooks)
133
- applyBulkHooks(entity, opts.hooks);
134
- if (opts.filters)
135
- applyBulkFilters(entity, opts.filters);
136
- }
137
- export function defineEntity(entity, opts = {}) {
138
- const meta = ensureMeta(entity);
139
- applyBulkEntityOptions(entity, opts);
140
117
  if (!hasKeys(meta.fields)) {
141
118
  throw TypeError(`'${entity.name}' must have fields`);
142
119
  }
143
120
  meta.name = opts.name ?? entity.name;
144
121
  let proto = Object.getPrototypeOf(entity.prototype);
145
122
  while (proto.constructor !== Object) {
146
- const parentMeta = ensureMeta(proto.constructor);
147
- extendMeta(meta, parentMeta);
123
+ const parent = proto.constructor;
124
+ // An `abstract class BaseEntity` carrying `@Field`s but no `@Entity()` has nobody to drain its
125
+ // registrations, so do it here. Walking the *class* prototype chain rather than reading through the
126
+ // metadata object's is what makes this work on every transformer: tsc and esbuild chain metadata
127
+ // across `extends`, SWC does not.
128
+ applyMembers(parent, ownRegistrations(parent));
129
+ extendMeta(meta, ensureMeta(parent));
148
130
  proto = Object.getPrototypeOf(proto);
149
131
  }
150
132
  // Derive soft-delete from the (inheritance-merged) fields, so own and inherited markers are handled
@@ -240,7 +222,7 @@ function fillRelations(meta) {
240
222
  name: fkKey,
241
223
  type: relatedIdField?.type ?? Number,
242
224
  references: relOpts.entity,
243
- typeInferred: true,
225
+ typeFromReference: true,
244
226
  };
245
227
  }
246
228
  }
@@ -341,29 +323,3 @@ function extendMeta(target, source) {
341
323
  }
342
324
  }
343
325
  }
344
- /** Reads the `design:type` emitted by `emitDecoratorMetadata`, if the optional polyfill is loaded. */
345
- function inferType(entity, key) {
346
- const { getMetadata } = Reflect;
347
- if (!getMetadata) {
348
- throw new TypeError(`'${entity.name}.${key}' has no explicit type and 'design:type' metadata is unavailable. Either declare the type - '@Field({ type: String })' or '@Relation({ entity: () => Other })' - or install 'reflect-metadata' and add 'import "reflect-metadata"' once at your app entry point.`);
349
- }
350
- return getMetadata('design:type', entity.prototype, key);
351
- }
352
- // biome-ignore lint/suspicious/noExplicitAny: reflected type is unknown at compile time
353
- function inferEntityType(entity, key) {
354
- const inferredType = inferType(entity, key);
355
- const isValidType = isValidEntityType(inferredType);
356
- if (!isValidType) {
357
- throw TypeError(`'${entity.name}.${key}' type was auto-inferred with invalid type '${inferredType?.name}'`);
358
- }
359
- return inferredType;
360
- }
361
- export function isValidEntityType(type) {
362
- return (typeof type === 'function' &&
363
- type !== Boolean &&
364
- type !== String &&
365
- type !== Number &&
366
- type !== BigInt &&
367
- type !== Date &&
368
- type !== Symbol);
369
- }
@@ -1,5 +1,4 @@
1
- // import from the specific util modules (not the barrel) to keep entity
2
- // metadata and reflect-metadata out of the browser bundle
1
+ // the specific util modules, not the barrel, so the browser bundle does not pull in entity metadata
3
2
  import { getKeys } from '../util/object.util.js';
4
3
  import { kebabCase } from '../util/string.util.js';
5
4
  /**
@@ -1,6 +1,6 @@
1
1
  import { withContext } from '../context/context.js';
2
2
  import { getEntities, getMeta } from '../entity/index.js';
3
- import { getQuerier } from '../options.js';
3
+ import { getQuerierPool } from '../options.js';
4
4
  import { entityPath, matchRoute, } from './contract.js';
5
5
  import { parseQueryParams } from './query.js';
6
6
  export function createRequestHandler(opts = {}) {
@@ -135,31 +135,10 @@ export function createRequestHandler(opts = {}) {
135
135
  function ok(body) {
136
136
  return { status: 200, body };
137
137
  }
138
- async function withQuerier(fn) {
139
- const querier = await getQuerier();
140
- try {
141
- return await fn(querier);
142
- }
143
- finally {
144
- await querier.release();
145
- }
146
- }
147
- async function withTransaction(fn) {
148
- const querier = await getQuerier();
149
- try {
150
- await querier.beginTransaction();
151
- const resp = await fn(querier);
152
- await querier.commitTransaction();
153
- return resp;
154
- }
155
- catch (err) {
156
- await querier.rollbackTransaction().catch(() => { });
157
- throw err;
158
- }
159
- finally {
160
- await querier.release();
161
- }
162
- }
138
+ /** Read paths: the pool acquires and releases; nothing here owns a connection. */
139
+ const withQuerier = (fn) => getQuerierPool().withQuerier(fn);
140
+ /** Write paths: same, plus commit on success and rollback on failure. */
141
+ const withTransaction = (fn) => getQuerierPool().transaction(fn);
163
142
  function buildIdQuery(meta, id, query) {
164
143
  const idKey = meta.id;
165
144
  const where = query.$where;
@@ -1,4 +1,4 @@
1
- // specific util module (not the barrel) to keep reflect-metadata out of the browser bundle
1
+ // the specific util module, not the barrel, so the browser bundle does not pull in entity metadata
2
2
  import { getKeys } from '../util/object.util.js';
3
3
  const JSON_QUERY_KEYS = [
4
4
  '$select',
@@ -1,9 +1,19 @@
1
1
  import { SqliteDialect } from '../sqlite/sqliteDialect.js';
2
+ import type { VectorDistance } from '../type/index.js';
2
3
  /**
3
4
  * SQLite Dialect specialization for the `@libsql/client` driver.
4
5
  *
5
- * @remarks Empty subclass by design: distinct type for `LibsqlQuerierPool` and a hook
6
- * for future libsql-specific behavior.
6
+ * @remarks Distinct type for `LibsqlQuerierPool` and the home of the libSQL engine's built-in vector
7
+ * functions, which `TursoDialect` inherits.
7
8
  */
8
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 `TursoDialect`) 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
+ */
18
+ protected readonly vectorDistanceFns: ReadonlyMap<VectorDistance, string>;
9
19
  }
@@ -2,8 +2,20 @@ import { SqliteDialect } from '../sqlite/sqliteDialect.js';
2
2
  /**
3
3
  * SQLite Dialect specialization for the `@libsql/client` driver.
4
4
  *
5
- * @remarks Empty subclass by design: distinct type for `LibsqlQuerierPool` and a hook
6
- * for future libsql-specific behavior.
5
+ * @remarks Distinct type for `LibsqlQuerierPool` and the home of the libSQL engine's built-in vector
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 `TursoDialect`) 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
+ */
17
+ vectorDistanceFns = new Map([
18
+ ['cosine', 'vector_distance_cos'],
19
+ ['l2', 'vector_distance_l2'],
20
+ ]);
9
21
  }
@@ -1,23 +1,10 @@
1
- import type { Client } from '@libsql/client';
2
- import { AbstractSqliteQuerier } from '../sqlite/abstractSqliteQuerier.js';
3
- import type { SqliteDialect } from '../sqlite/sqliteDialect.js';
4
- import type { ExtraOptions, TransactionOptions } from '../type/index.js';
5
- /** Connection lifecycle for a {@link LibsqlQuerier} (separate from {@link ExtraOptions}). */
6
- export type LibsqlQuerierConnectionOptions = {
7
- /** When set, {@link release} closes {@link LibsqlQuerier.client} (one-shot migration connections). */
8
- closeClientOnRelease?: boolean;
9
- };
10
- export declare class LibsqlQuerier extends AbstractSqliteQuerier {
11
- readonly client: Client;
12
- readonly extra?: ExtraOptions | undefined;
13
- private tx?;
14
- private readonly closeClientOnRelease;
15
- constructor(client: Client, dialect: SqliteDialect, extra?: ExtraOptions | undefined, connection?: LibsqlQuerierConnectionOptions);
16
- internalAll<T>(query: string, values?: unknown[]): Promise<T[]>;
17
- internalRun(query: string, values?: unknown[]): Promise<import("../type/query.js").QueryUpdateResult>;
18
- get hasOpenTransaction(): boolean;
19
- beginTransaction(_opts?: TransactionOptions): Promise<void>;
20
- commitTransaction(): Promise<void>;
21
- rollbackTransaction(): Promise<void>;
22
- internalRelease(): Promise<void>;
1
+ import { HranaQuerier } from '../sqlite/hranaQuerier.js';
2
+ /**
3
+ * Querier for the `@libsql/client` driver.
4
+ *
5
+ * @remarks Empty subclass by design: that client speaks the Hrana protocol, so the whole
6
+ * implementation is inherited. Kept as a distinct type for `LibsqlQuerierPool` and as a hook for
7
+ * future libsql-specific behavior.
8
+ */
9
+ export declare class LibsqlQuerier extends HranaQuerier {
23
10
  }
@@ -1,86 +1,10 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- var __metadata = (this && this.__metadata) || function (k, v) {
8
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
- };
10
- import { Serialized } from '../querier/decorator/index.js';
11
- import { AbstractSqliteQuerier } from '../sqlite/abstractSqliteQuerier.js';
12
- import { throwNoPendingTransaction, throwPendingTransaction } from '../util/index.js';
13
- export class LibsqlQuerier extends AbstractSqliteQuerier {
14
- client;
15
- extra;
16
- tx;
17
- closeClientOnRelease;
18
- constructor(client, dialect, extra, connection) {
19
- super(dialect, extra);
20
- this.client = client;
21
- this.extra = extra;
22
- this.closeClientOnRelease = connection?.closeClientOnRelease ?? false;
23
- }
24
- async internalAll(query, values) {
25
- const target = this.tx || this.client;
26
- const res = await target.execute({ sql: query, args: values });
27
- return res.rows;
28
- }
29
- async internalRun(query, values) {
30
- const target = this.tx || this.client;
31
- const res = await target.execute({ sql: query, args: values });
32
- const rows = res.rows;
33
- // `rowsAffected` is unreliably 0 whenever the statement has a RETURNING clause, so prefer
34
- // the actual row count when rows were returned.
35
- return this.buildUpdateResult({ rows, changes: rows.length || res.rowsAffected, id: res.lastInsertRowid });
36
- }
37
- get hasOpenTransaction() {
38
- return !!this.tx;
39
- }
40
- async beginTransaction(_opts) {
41
- if (this.tx) {
42
- throwPendingTransaction();
43
- }
44
- this.tx = await this.client.transaction('write');
45
- }
46
- async commitTransaction() {
47
- if (!this.tx) {
48
- throwNoPendingTransaction();
49
- }
50
- await this.tx.commit();
51
- this.tx = undefined;
52
- }
53
- async rollbackTransaction() {
54
- if (!this.tx) {
55
- throwNoPendingTransaction();
56
- }
57
- await this.tx.rollback();
58
- this.tx = undefined;
59
- }
60
- async internalRelease() {
61
- if (this.tx) {
62
- throwPendingTransaction();
63
- }
64
- if (this.closeClientOnRelease) {
65
- this.client.close();
66
- }
67
- }
1
+ import { HranaQuerier } from '../sqlite/hranaQuerier.js';
2
+ /**
3
+ * Querier for the `@libsql/client` driver.
4
+ *
5
+ * @remarks Empty subclass by design: that client speaks the Hrana protocol, so the whole
6
+ * implementation is inherited. Kept as a distinct type for `LibsqlQuerierPool` and as a hook for
7
+ * future libsql-specific behavior.
8
+ */
9
+ export class LibsqlQuerier extends HranaQuerier {
68
10
  }
69
- __decorate([
70
- Serialized(),
71
- __metadata("design:type", Function),
72
- __metadata("design:paramtypes", [Object]),
73
- __metadata("design:returntype", Promise)
74
- ], LibsqlQuerier.prototype, "beginTransaction", null);
75
- __decorate([
76
- Serialized(),
77
- __metadata("design:type", Function),
78
- __metadata("design:paramtypes", []),
79
- __metadata("design:returntype", Promise)
80
- ], LibsqlQuerier.prototype, "commitTransaction", null);
81
- __decorate([
82
- Serialized(),
83
- __metadata("design:type", Function),
84
- __metadata("design:paramtypes", []),
85
- __metadata("design:returntype", Promise)
86
- ], LibsqlQuerier.prototype, "rollbackTransaction", null);
@@ -1,19 +1,21 @@
1
- import { type Client, type Config } from '@libsql/client';
2
- import { AbstractSqlQuerierPool } from '../querier/index.js';
1
+ import type { Config } from '@libsql/client';
2
+ import type { HranaClient, HranaQuerierConnectionOptions } from '../sqlite/hranaQuerier.js';
3
+ import { AbstractHranaQuerierPool } from '../sqlite/hranaQuerierPool.js';
3
4
  import type { ExtraOptions } from '../type/index.js';
4
5
  import { LibsqlDialect } from './libsqlDialect.js';
5
6
  import { LibsqlQuerier } from './libsqlQuerier.js';
6
7
  /** Embedded replica: local `file:` DB + `syncUrl` remote - DDL should run on the remote (sqld). */
7
8
  export declare function libsqlUseRemoteForMigrations(config: Pick<Config, 'url' | 'syncUrl'>): boolean;
8
- export declare class LibsqlQuerierPool extends AbstractSqlQuerierPool<LibsqlQuerier, LibsqlDialect> {
9
- readonly client: Client;
10
- private readonly libsqlConfig;
9
+ export declare class LibsqlQuerierPool extends AbstractHranaQuerierPool<LibsqlQuerier, LibsqlDialect> {
10
+ private readonly conf;
11
11
  constructor(conf: Config, extra?: ExtraOptions);
12
- getQuerier(): Promise<LibsqlQuerier>;
12
+ protected openClient(): Promise<HranaClient>;
13
+ protected buildQuerier(client: HranaClient, connection?: HranaQuerierConnectionOptions): LibsqlQuerier;
13
14
  /**
14
15
  * For embedded replicas (`file:` + `syncUrl`), returns a querier connected to `syncUrl` so migrations hit sqld.
15
- * Otherwise same as {@link getQuerier}. The migrator calls this for `up`/`down`, `syncForce`, and `autoSync` DDL.
16
+ * Otherwise same as `getQuerier`. The migrator calls this for `up`/`down`, `syncForce`, and `autoSync` DDL.
16
17
  */
17
18
  getMigrationQuerier(): Promise<LibsqlQuerier>;
18
- end(): Promise<void>;
19
+ /** Imported on use, so `uql-orm/libsql` loads without the optional `@libsql/client` peer installed. */
20
+ private createClient;
19
21
  }