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
@@ -3,6 +3,7 @@ import { QueryRaw, } from '../type/index.js';
3
3
  import { escapeSingleQuotes } from '../util/sqlLiteral.js';
4
4
  import { AbstractSqlDialect } from './abstractSqlDialect.js';
5
5
  import { JSON_PULL_ALIAS, jsonSetTarget } from './jsonSql.js';
6
+ import { resolveVectorCast, toSparsevecLiteral } from './vectorCast.js';
6
7
  /**
7
8
  * Shared AST/quoting/JSONB/full-text-search/vector-search implementation between Postgres and
8
9
  * CockroachDB (wire- and SQL-compatible for everything below, including `to_tsvector`/`to_tsquery`
@@ -24,7 +25,7 @@ export class PgLikeSqlDialect extends AbstractSqlDialect {
24
25
  renameColumn: true,
25
26
  foreignKeyAlter: true,
26
27
  columnComment: false,
27
- vectorIndexStyle: 'create',
28
+ inlineVectorIndex: false,
28
29
  vectorSupportsLength: true,
29
30
  supportsTimestamptz: true,
30
31
  defaultStringAsText: true,
@@ -42,12 +43,16 @@ export class PgLikeSqlDialect extends AbstractSqlDialect {
42
43
  alterColumnStrategy = 'separate-clauses';
43
44
  insertIdSource = 'returning';
44
45
  maxBindValues = 65535;
45
- vectorOpsClass = new Map([
46
- ['cosine', 'vector_cosine_ops'],
47
- ['l2', 'vector_l2_ops'],
48
- ['inner', 'vector_ip_ops'],
49
- ['l1', 'vector_l1_ops'],
50
- ['hamming', 'bit_hamming_ops'],
46
+ /**
47
+ * Each metric's pgvector distance operator and the operator-class suffix its index takes, in one
48
+ * place so a dialect cannot end up with the operator but not the opclass. The key set is the single
49
+ * source of truth for which metrics the dialect supports at all: CockroachDB narrows it to three.
50
+ */
51
+ vectorMetrics = new Map([
52
+ ['cosine', { op: '<=>', opsSuffix: 'cosine' }],
53
+ ['l2', { op: '<->', opsSuffix: 'l2' }],
54
+ ['inner', { op: '<#>', opsSuffix: 'ip' }],
55
+ ['l1', { op: '<+>', opsSuffix: 'l1' }],
51
56
  ]);
52
57
  normalizeValue(value) {
53
58
  if (value != null && typeof value === 'object' && Array.isArray(value)) {
@@ -55,55 +60,88 @@ export class PgLikeSqlDialect extends AbstractSqlDialect {
55
60
  }
56
61
  return super.normalizeValue(value);
57
62
  }
58
- placeholder(index) {
59
- return `$${index}`;
63
+ /** pgvector's own index types; CockroachDB's native one widens this. */
64
+ isVectorIndex(index) {
65
+ return index.type === 'hnsw' || index.type === 'ivfflat';
66
+ }
67
+ indexAccessMethod(index) {
68
+ return index.type ? ` USING ${index.type}` : '';
69
+ }
70
+ indexFeatures = new Set([
71
+ 'expression',
72
+ 'nullsOrder',
73
+ 'opsClass',
74
+ 'include',
75
+ ]);
76
+ /**
77
+ * A vector index's operator class is named `{type}_{metric}_ops`: an index on a `halfvec` column
78
+ * needs `halfvec_cosine_ops`, and `vector_cosine_ops` there is rejected outright. An unsupported
79
+ * distance throws rather than being omitted, since a bare `USING hnsw ("embedding")` would build
80
+ * with the dialect's default metric instead of the one requested, with nothing signalling it.
81
+ * Everything else takes the operator class the entry declares, e.g. `jsonb_path_ops` for GIN.
82
+ */
83
+ indexColumnOpsClass(entry, index) {
84
+ if (!this.isVectorIndex(index) || !index.distance) {
85
+ return entry.opsClass ? ` ${entry.opsClass}` : '';
86
+ }
87
+ const metric = this.vectorMetrics.get(index.distance);
88
+ if (!metric) {
89
+ throw new TypeError(`${this.dialectName} does not support vector distance metric: ${index.distance} (index "${index.name}")`);
90
+ }
91
+ const vectorType = this.supportedVectorType(index.vectorType ?? 'vector');
92
+ const opsClass = `${vectorType}_${metric.opsSuffix}_ops`;
93
+ // IVFFlat has neither a sparsevec nor an L1 operator class; HNSW has all of them (pgvector 0.8.2).
94
+ if (index.type === 'ivfflat' && (vectorType === 'sparsevec' || index.distance === 'l1')) {
95
+ throw new TypeError(`ivfflat has no ${opsClass} operator class (index "${index.name}"); use hnsw`);
96
+ }
97
+ return ` ${opsClass}`;
98
+ }
99
+ indexInclude(index) {
100
+ return index.include?.length ? ` INCLUDE (${index.include.map((column) => this.escapeId(column)).join(', ')})` : '';
60
101
  }
61
- insert(ctx, entity, payload, opts) {
62
- super.insert(ctx, entity, payload, opts);
63
- ctx.append(' ' + this.returningId(entity));
102
+ indexTuning(index) {
103
+ if (!this.isVectorIndex(index)) {
104
+ return '';
105
+ }
106
+ const params = [];
107
+ if (index.m !== undefined)
108
+ params.push(`m = ${index.m}`);
109
+ if (index.efConstruction !== undefined)
110
+ params.push(`ef_construction = ${index.efConstruction}`);
111
+ if (index.lists !== undefined)
112
+ params.push(`lists = ${index.lists}`);
113
+ return params.length > 0 ? ` WITH (${params.join(', ')})` : '';
64
114
  }
65
- upsert(ctx, entity, conflictPaths, payload) {
66
- this.buildUpsertOnConflict(ctx, entity, conflictPaths, payload);
115
+ placeholder(index) {
116
+ return `$${index}`;
67
117
  }
68
118
  /**
69
- * Shared `INSERT ... ON CONFLICT (...) DO UPDATE/NOTHING RETURNING ...` builder, assembling
70
- * everything upfront rather than handing back fragments, for the `$N`-placeholder Postgres-wire
71
- * dialects. `extraReturning` lets {@link PostgresDialect} append `(xmax = 0) AS "_created"` to
72
- * detect insert-vs-update; CockroachDB has no `xmax`/`ctid` system columns, so it uses the default
73
- * (empty) and `created` stays `undefined` in the result.
119
+ * The same statement as the base, binding the assignments into the main context instead of a second
120
+ * one: `$N` placeholders carry their own index, so the values need not be in statement order, and
121
+ * computing them first is what keeps `appendInsertValues`' `onInsert` fields out of the update set.
74
122
  */
75
- buildUpsertOnConflict(ctx, entity, conflictPaths, payload, extraReturning = '') {
123
+ upsert(ctx, entity, conflictPaths, payload, extraReturning = '') {
76
124
  const meta = getMeta(entity);
77
- const update = this.getUpsertUpdateAssignments(ctx, meta, conflictPaths, payload, (name) => `EXCLUDED.${name}`);
78
- const keysStr = this.getUpsertConflictPathsStr(meta, conflictPaths);
125
+ const update = this.getUpsertUpdateAssignments(ctx, meta, conflictPaths, payload, this.upsertExcluded);
126
+ const keys = this.getUpsertConflictPathsStr(meta, conflictPaths);
79
127
  const onConflict = update ? `DO UPDATE SET ${update}` : 'DO NOTHING';
80
- super.insert(ctx, entity, payload);
81
- ctx.append(` ON CONFLICT (${keysStr}) ${onConflict} ${this.returningId(entity)}${extraReturning}`);
128
+ this.appendInsertValues(ctx, entity, payload);
129
+ ctx.append(` ON CONFLICT (${keys}) ${onConflict} ${this.returningId(entity)}${extraReturning}`);
82
130
  }
83
131
  /**
84
- * Full-text search: `to_tsvector(...) @@ websearch_to_tsquery(...)`. `websearch_to_tsquery` takes
85
- * free-form user input (quoted phrases, `or`, `-negation`) and never raises a syntax error, unlike
86
- * `to_tsquery`, which rejects anything unparseable - including a plain two-word search.
132
+ * `to_tsvector(...) @@ websearch_to_tsquery(...)`. `websearch_to_tsquery` takes free-form user input
133
+ * (quoted phrases, `or`, `-negation`) and never raises a syntax error, unlike `to_tsquery`, which
134
+ * rejects anything unparseable - including a plain two-word search.
87
135
  */
88
- compare(ctx, entity, key, val, opts = {}) {
89
- if (key === '$text') {
90
- const meta = getMeta(entity);
91
- const search = val;
92
- const fields = (search.$fields ?? [])
93
- .map((fKey) => {
94
- const field = meta.fields[fKey];
95
- const columnName = this.resolveColumnName(fKey, field);
96
- return this.escapeId(columnName);
97
- })
98
- .join(` || ' ' || `);
99
- // The config is bound once and its numbered placeholder reused by both calls.
100
- const config = search.$config ? `${this.addValue(ctx.values, search.$config)}::regconfig, ` : '';
101
- ctx.append(`to_tsvector(${config}${fields}) @@ websearch_to_tsquery(${config}`);
102
- ctx.addValue(search.$value);
103
- ctx.append(')');
104
- return;
105
- }
106
- super.compare(ctx, entity, key, val, opts);
136
+ appendTextSearch(ctx, _entity, meta, search) {
137
+ const fields = (search.$fields ?? [])
138
+ .map((key) => this.escapeId(this.resolveColumnName(key, meta.fields[key])))
139
+ .join(` || ' ' || `);
140
+ // The config is bound once and its numbered placeholder reused by both calls.
141
+ const config = search.$config ? `${this.addValue(ctx.values, search.$config)}::regconfig, ` : '';
142
+ ctx.append(`to_tsvector(${config}${fields}) @@ websearch_to_tsquery(${config}`);
143
+ ctx.addValue(search.$value);
144
+ ctx.append(')');
107
145
  }
108
146
  jsonAll(ctx, jsonField, value) {
109
147
  return `${jsonField} @> ${this.jsonVal(ctx, value)}`;
@@ -146,9 +184,14 @@ export class PgLikeSqlDialect extends AbstractSqlDialect {
146
184
  appendJsonValue(ctx, value, type) {
147
185
  ctx.append(this.jsonVal(ctx, value, type));
148
186
  }
149
- appendVectorValue(ctx, value) {
150
- ctx.addValue(`[${value.join(',')}]`);
151
- ctx.append('::vector');
187
+ /**
188
+ * pgvector needs the cast to pick the right type, and `sparsevec` needs its own literal: the dense
189
+ * `[1,0,2]` every other type takes is rejected as "invalid input syntax for type sparsevec".
190
+ */
191
+ appendVectorValue(ctx, value, field) {
192
+ const vectorType = this.supportedVectorType(resolveVectorCast(field));
193
+ ctx.addValue(vectorType === 'sparsevec' ? toSparsevecLiteral(value) : `[${value.join(',')}]`);
194
+ ctx.append(`::${vectorType}`);
152
195
  }
153
196
  /**
154
197
  * `create_if_missing => false` keeps an absent key (and a NULL column) untouched; `WITH
@@ -189,29 +232,15 @@ export class PgLikeSqlDialect extends AbstractSqlDialect {
189
232
  const ph = this.addValue(ctx.values, json);
190
233
  return this.features.explicitJsonCast ? `(${ph}::text)::${type}` : `${ph}::${type}`;
191
234
  }
192
- /**
193
- * pgvector distance operators. Not every dialect supports every metric - see
194
- * {@link CockroachDialect.vectorOpsClass} for which ones each dialect actually has; the
195
- * `vectorOpsClass` key set (checked in `appendVectorSort` below via `vectorOpsClass.get`)
196
- * is the single source of truth for that, not this map.
197
- */
198
- static VECTOR_OPS = {
199
- cosine: '<=>',
200
- l2: '<->',
201
- inner: '<#>',
202
- l1: '<+>',
203
- hamming: '<~>',
204
- };
205
235
  /** Emit a pgvector-style distance expression: `"col" <op> $N::<vectorType>`. */
206
236
  appendVectorSort(ctx, meta, key, search) {
207
- const { colName, distance, vectorCast } = this.resolveVectorSortParams(meta, key, search);
208
- if (!this.vectorOpsClass.get(distance)) {
237
+ const { colName, distance, field } = this.resolveVectorSortParams(meta, key, search);
238
+ const metric = this.vectorMetrics.get(distance);
239
+ if (!metric) {
209
240
  throw new TypeError(`${this.dialectName} does not support vector distance metric: ${distance}`);
210
241
  }
211
- const op = PgLikeSqlDialect.VECTOR_OPS[distance];
212
- ctx.append(`${this.escapeId(colName)} ${op} `);
213
- ctx.addValue(`[${search.$vector.join(',')}]`);
214
- ctx.append(`::${vectorCast}`);
242
+ ctx.append(`${this.escapeId(colName)} ${metric.op} `);
243
+ this.appendVectorValue(ctx, search.$vector, field);
215
244
  }
216
245
  }
217
246
  /**
@@ -2,10 +2,31 @@
2
2
  * Kept out of `schema/canonicalType.ts`: importing one function from that migration/codegen module
3
3
  * pulled all ~18 KB of its type-mapping tables into every consumer's bundle.
4
4
  */
5
+ import type { DialectName } from '../type/querier.js';
5
6
  /** Vector cast types supported by pgvector. */
6
7
  export type VectorCast = 'vector' | 'halfvec' | 'sparsevec';
8
+ /**
9
+ * The dialects that have more than one vector column type. pgvector is the only one: `halfvec` and
10
+ * `sparsevec` exist nowhere else (`HALFVEC(3)` is a syntax error on CockroachDB 26.2 and MariaDB 12.3,
11
+ * not merely unsupported at runtime), so a field declaring one is stored - and therefore cast - as
12
+ * plain `vector`. Both halves of that used to be stated separately, in this dialect layer and in the
13
+ * migration type maps.
14
+ */
15
+ export declare const MULTI_VECTOR_TYPE_DIALECTS: ReadonlySet<DialectName>;
16
+ /**
17
+ * Whether a declared field type is a vector of any width. Every dialect that treats vectors specially
18
+ * has to answer this for all three, not just `vector`: matching that one alone left `halfvec` and
19
+ * `sparsevec` fields binding as plain arrays on insert and reading back raw.
20
+ */
21
+ export declare function isVectorFieldType(type: unknown): boolean;
7
22
  /** Resolves the effective cast from field options, `columnType` taking priority over `type`. */
8
23
  export declare function resolveVectorCast(field: {
9
24
  type?: unknown;
10
25
  columnType?: unknown;
11
26
  } | undefined): VectorCast;
27
+ /**
28
+ * pgvector's `sparsevec` literal: 1-based `index:value` pairs of the non-zero elements, then the
29
+ * dimension count (`{1:1,3:2}/3`). A dense `[1,0,2]` is rejected outright by that type, so an entity
30
+ * declaring `type: 'sparsevec'` still hands UQL the dense array its field type promises.
31
+ */
32
+ export declare function toSparsevecLiteral(values: readonly unknown[]): string;
@@ -2,6 +2,22 @@
2
2
  * Kept out of `schema/canonicalType.ts`: importing one function from that migration/codegen module
3
3
  * pulled all ~18 KB of its type-mapping tables into every consumer's bundle.
4
4
  */
5
+ /**
6
+ * The dialects that have more than one vector column type. pgvector is the only one: `halfvec` and
7
+ * `sparsevec` exist nowhere else (`HALFVEC(3)` is a syntax error on CockroachDB 26.2 and MariaDB 12.3,
8
+ * not merely unsupported at runtime), so a field declaring one is stored - and therefore cast - as
9
+ * plain `vector`. Both halves of that used to be stated separately, in this dialect layer and in the
10
+ * migration type maps.
11
+ */
12
+ export const MULTI_VECTOR_TYPE_DIALECTS = new Set(['postgres']);
13
+ /**
14
+ * Whether a declared field type is a vector of any width. Every dialect that treats vectors specially
15
+ * has to answer this for all three, not just `vector`: matching that one alone left `halfvec` and
16
+ * `sparsevec` fields binding as plain arrays on insert and reading back raw.
17
+ */
18
+ export function isVectorFieldType(type) {
19
+ return type === 'vector' || type === 'halfvec' || type === 'sparsevec';
20
+ }
5
21
  /** Resolves the effective cast from field options, `columnType` taking priority over `type`. */
6
22
  export function resolveVectorCast(field) {
7
23
  const raw = field?.columnType ?? field?.type;
@@ -11,3 +27,15 @@ export function resolveVectorCast(field) {
11
27
  return 'sparsevec';
12
28
  return 'vector';
13
29
  }
30
+ /**
31
+ * pgvector's `sparsevec` literal: 1-based `index:value` pairs of the non-zero elements, then the
32
+ * dimension count (`{1:1,3:2}/3`). A dense `[1,0,2]` is rejected outright by that type, so an entity
33
+ * declaring `type: 'sparsevec'` still hands UQL the dense array its field type promises.
34
+ */
35
+ export function toSparsevecLiteral(values) {
36
+ const pairs = values
37
+ .map((value, index) => `${index + 1}:${value}`)
38
+ .filter((_, index) => Number(values[index]) !== 0)
39
+ .join(',');
40
+ return `{${pairs}}/${values.length}`;
41
+ }
@@ -14,8 +14,6 @@ import { type VectorCast } from './vectorCast.js';
14
14
  * {@link appendVectorSort} or filling {@link vectorDistanceFns}.
15
15
  */
16
16
  export declare abstract class VectorSqlDialect extends AbstractDialect {
17
- /** Vector index operator classes, keyed by distance metric. Partial: not every dialect supports every metric. */
18
- readonly vectorOpsClass: ReadonlyMap<VectorDistance, string> | undefined;
19
17
  readonly vectorExtension: string | undefined;
20
18
  /**
21
19
  * Mapping of UQL vector distance metrics to native SQL functions.
@@ -33,8 +31,17 @@ export declare abstract class VectorSqlDialect extends AbstractDialect {
33
31
  colName: string;
34
32
  distance: VectorDistance;
35
33
  field: FieldOptions | undefined;
36
- vectorCast: VectorCast;
37
34
  };
35
+ /**
36
+ * Binds a vector, both as a persisted value and as the query vector of a distance expression, so a
37
+ * dialect needing a conversion around it (`$1::vector`, `VEC_FromText(?)`) declares it once.
38
+ */
39
+ protected appendVectorValue(ctx: QueryContext, value: readonly unknown[], _field?: FieldOptions): void;
40
+ /**
41
+ * The vector type this dialect actually has for a declared one, so the cast follows the column
42
+ * rather than naming a type the engine does not define. See {@link MULTI_VECTOR_TYPE_DIALECTS}.
43
+ */
44
+ protected supportedVectorType(cast: VectorCast): VectorCast;
38
45
  /**
39
46
  * Append a vector similarity function call: `fn(col, ?)`.
40
47
  * Used by dialects that express vector distance via SQL functions (SQLite, MariaDB).
@@ -1,5 +1,5 @@
1
1
  import { AbstractDialect } from './abstractDialect.js';
2
- import { resolveVectorCast } from './vectorCast.js';
2
+ import { MULTI_VECTOR_TYPE_DIALECTS } from './vectorCast.js';
3
3
  /**
4
4
  * Vector similarity search for SQL dialects: the `ORDER BY <distance>` expression, its projection as
5
5
  * a named score, and the index metadata the schema generator reads.
@@ -13,8 +13,6 @@ import { resolveVectorCast } from './vectorCast.js';
13
13
  * {@link appendVectorSort} or filling {@link vectorDistanceFns}.
14
14
  */
15
15
  export class VectorSqlDialect extends AbstractDialect {
16
- /** Vector index operator classes, keyed by distance metric. Partial: not every dialect supports every metric. */
17
- vectorOpsClass = undefined;
18
16
  vectorExtension = undefined;
19
17
  /**
20
18
  * Mapping of UQL vector distance metrics to native SQL functions.
@@ -30,21 +28,34 @@ export class VectorSqlDialect extends AbstractDialect {
30
28
  const field = meta.fields[key];
31
29
  const colName = this.resolveColumnName(key, field);
32
30
  const distance = search.$distance ?? field?.distance ?? 'cosine';
33
- const vectorCast = resolveVectorCast(field);
34
- return { colName, distance, field, vectorCast };
31
+ return { colName, distance, field };
32
+ }
33
+ /**
34
+ * Binds a vector, both as a persisted value and as the query vector of a distance expression, so a
35
+ * dialect needing a conversion around it (`$1::vector`, `VEC_FromText(?)`) declares it once.
36
+ */
37
+ appendVectorValue(ctx, value, _field) {
38
+ ctx.addValue(`[${value.join(',')}]`);
39
+ }
40
+ /**
41
+ * The vector type this dialect actually has for a declared one, so the cast follows the column
42
+ * rather than naming a type the engine does not define. See {@link MULTI_VECTOR_TYPE_DIALECTS}.
43
+ */
44
+ supportedVectorType(cast) {
45
+ return MULTI_VECTOR_TYPE_DIALECTS.has(this.dialectName) ? cast : 'vector';
35
46
  }
36
47
  /**
37
48
  * Append a vector similarity function call: `fn(col, ?)`.
38
49
  * Used by dialects that express vector distance via SQL functions (SQLite, MariaDB).
39
50
  */
40
51
  appendFunctionVectorSort(ctx, meta, key, search) {
41
- const { colName, distance } = this.resolveVectorSortParams(meta, key, search);
52
+ const { colName, distance, field } = this.resolveVectorSortParams(meta, key, search);
42
53
  const fn = this.vectorDistanceFns.get(distance);
43
54
  if (!fn) {
44
55
  throw Error(`${this.dialectName} does not support vector distance metric: ${distance}`);
45
56
  }
46
57
  ctx.append(`${fn}(${this.escapeId(colName)}, `);
47
- ctx.addValue(`[${search.$vector.join(',')}]`);
58
+ this.appendVectorValue(ctx, search.$vector, field);
48
59
  ctx.append(')');
49
60
  }
50
61
  /**
@@ -64,6 +75,6 @@ export class VectorSqlDialect extends AbstractDialect {
64
75
  this.appendFunctionVectorSort(ctx, meta, key, search);
65
76
  return;
66
77
  }
67
- throw new TypeError('Vector similarity sort is not supported by this dialect. Use raw() for vector queries.');
78
+ throw new TypeError(`${this.dialectName} does not support vector similarity sort. Use raw() for vector queries.`);
68
79
  }
69
80
  }
@@ -0,0 +1,35 @@
1
+ import type { FieldOptions, HookEvent, RelationOptions, Type } from '../../type/index.js';
2
+ /**
3
+ * What the member decorators record for one class, waiting for `@Entity()` or `defineEntity` to drain
4
+ * it into the metadata registry. Member decorators receive no class reference under the standard
5
+ * decorator spec, so this object is the only channel between them and the class decorator that does.
6
+ */
7
+ export type MemberRegistrations = {
8
+ readonly fields: Record<string, FieldOptions>;
9
+ readonly relations: Record<string, RelationOptions>;
10
+ readonly hooks: Partial<Record<HookEvent, string[]>>;
11
+ };
12
+ /**
13
+ * The calling class's own registrations, created on first use.
14
+ *
15
+ * Deliberately holds **only** this class's members: inheritance is resolved later by walking the class
16
+ * prototype chain, not by reading through the metadata object's. tsc chains a subclass's metadata to its
17
+ * parent's and SWC does not, so anything built on that chain would work under one compiler and quietly
18
+ * lose inherited fields under the other. Keeping each bag to its own members also means a parent's map
19
+ * is never shared with its subclasses, and hooks cannot be registered twice.
20
+ */
21
+ export declare function memberRegistrations(metadata: DecoratorMetadata): MemberRegistrations;
22
+ /**
23
+ * Takes the registrations belonging to `metadata`, leaving none behind, so finalizing an entity twice
24
+ * cannot register its hooks twice.
25
+ */
26
+ export declare function drainRegistrations(metadata: DecoratorMetadata | undefined): MemberRegistrations | undefined;
27
+ /**
28
+ * The registrations a class made for itself.
29
+ *
30
+ * @remarks Only usable once the class is fully defined, which is why `@Entity()` reads
31
+ * `context.metadata` instead: TypeScript attaches `Symbol.metadata` to the class *after* its class
32
+ * decorators return. Ancestors are always fully defined by then, so this is how inherited members are
33
+ * collected.
34
+ */
35
+ export declare function ownRegistrations(entity: Type<unknown>): MemberRegistrations | undefined;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Polyfill `Symbol.metadata`, which no runtime we support defines yet (checked on Node 24 and Bun
3
+ * 1.3): TypeScript's decorator emit reads it to decide whether to build the metadata object at all, so
4
+ * without this every `context.metadata` is `undefined` and field registration is silently dropped
5
+ * rather than failing.
6
+ *
7
+ * `Symbol.for`, not `Symbol()`, so a duplicated copy of this module (HMR, federated bundles, ESM+CJS
8
+ * dual-loading) lands on the same symbol, and so it agrees with the key esbuild and SWC fall back to
9
+ * (`Symbol.metadata ?? Symbol.for('Symbol.metadata')`). Assigned through a widened alias because the
10
+ * lib declares the property `readonly`; when a runtime does define it, `??=` leaves it alone.
11
+ */
12
+ const symbolCtor = Symbol;
13
+ symbolCtor.metadata ??= Symbol.for('Symbol.metadata');
14
+ /** Where member registrations live on the per-class metadata object. */
15
+ const registrations = Symbol.for('uql-orm/entity/decoratorMembers');
16
+ /**
17
+ * The calling class's own registrations, created on first use.
18
+ *
19
+ * Deliberately holds **only** this class's members: inheritance is resolved later by walking the class
20
+ * prototype chain, not by reading through the metadata object's. tsc chains a subclass's metadata to its
21
+ * parent's and SWC does not, so anything built on that chain would work under one compiler and quietly
22
+ * lose inherited fields under the other. Keeping each bag to its own members also means a parent's map
23
+ * is never shared with its subclasses, and hooks cannot be registered twice.
24
+ */
25
+ export function memberRegistrations(metadata) {
26
+ if (!Object.hasOwn(metadata, registrations)) {
27
+ metadata[registrations] = { fields: {}, relations: {}, hooks: {} };
28
+ }
29
+ return metadata[registrations];
30
+ }
31
+ /**
32
+ * Takes the registrations belonging to `metadata`, leaving none behind, so finalizing an entity twice
33
+ * cannot register its hooks twice.
34
+ */
35
+ export function drainRegistrations(metadata) {
36
+ if (!metadata || !Object.hasOwn(metadata, registrations)) {
37
+ return undefined;
38
+ }
39
+ const own = metadata[registrations];
40
+ delete metadata[registrations];
41
+ return own;
42
+ }
43
+ /**
44
+ * The registrations a class made for itself.
45
+ *
46
+ * @remarks Only usable once the class is fully defined, which is why `@Entity()` reads
47
+ * `context.metadata` instead: TypeScript attaches `Symbol.metadata` to the class *after* its class
48
+ * decorators return. Ancestors are always fully defined by then, so this is how inherited members are
49
+ * collected.
50
+ */
51
+ export function ownRegistrations(entity) {
52
+ const metadata = Object.getOwnPropertyDescriptor(entity, Symbol.metadata)?.value;
53
+ return drainRegistrations(metadata);
54
+ }
@@ -1,2 +1,28 @@
1
- import type { EntityOptions, Type } from '../../type/index.js';
2
- export declare function Entity<E>(opts?: EntityOptions<E>): (entity: Type<E>) => void;
1
+ import type { EntityOptions, FieldKey, FilterOptions, IndexColumnInput, IndexOptions, Type } from '../../type/index.js';
2
+ /**
3
+ * Marks a class as an entity and finalizes its metadata.
4
+ *
5
+ * @remarks Takes the registrations from `context.metadata` rather than from the class. Member
6
+ * decorators have already run by the time a class decorator does, but TypeScript defines
7
+ * `Symbol.metadata` on the class *after* the class decorators return, so reading `entity[Symbol.metadata]`
8
+ * here would find only what the base class left behind. `defineEntity` reads it off the class instead,
9
+ * which is correct for the imperative path because it runs later still.
10
+ */
11
+ export declare function Entity<E>(opts?: EntityOptions<E>): (entity: Type<E>, context?: ClassDecoratorContext) => void;
12
+ /**
13
+ * Registers a named `$where` filter, applied to every query unless bypassed via `QueryOptions.filters`.
14
+ *
15
+ * @example `@Filter('active', { condition: { status: 'active' }, default: false })`
16
+ */
17
+ export declare function Filter<E>(name: string, opts: FilterOptions<E>): (entity: Type<E>) => void;
18
+ /**
19
+ * Declares a composite index. Stacks, so several may sit above one class.
20
+ *
21
+ * `E` is inferred from the class the returned decorator is applied to, which is what lets the column
22
+ * names be checked against it: `@Index(['nope'])` does not compile.
23
+ *
24
+ * @example `@Index(['lastName', 'firstName'], { name: 'idx_users_fullname' })`
25
+ * @example `@Index(['email'], { unique: true })`
26
+ * @example `@Index(['status'], { where: "status = 'active'" })`
27
+ */
28
+ export declare function Index<E>(columns: readonly IndexColumnInput<FieldKey<E>>[], options?: IndexOptions): (entity: Type<E>) => void;
@@ -1,6 +1,44 @@
1
- import { defineEntity } from '../metadata/definition.js';
1
+ import { applyMembers, defineEntity, defineFilter, defineIndex } from '../metadata/definition.js';
2
+ import { drainRegistrations } from './bag.js';
3
+ // The class-level decorators. Unlike the member ones they receive the class, so each is a direct call
4
+ // into the registry with no bag in between.
5
+ /**
6
+ * Marks a class as an entity and finalizes its metadata.
7
+ *
8
+ * @remarks Takes the registrations from `context.metadata` rather than from the class. Member
9
+ * decorators have already run by the time a class decorator does, but TypeScript defines
10
+ * `Symbol.metadata` on the class *after* the class decorators return, so reading `entity[Symbol.metadata]`
11
+ * here would find only what the base class left behind. `defineEntity` reads it off the class instead,
12
+ * which is correct for the imperative path because it runs later still.
13
+ */
2
14
  export function Entity(opts) {
3
- return (entity) => {
15
+ return (entity, context) => {
16
+ applyMembers(entity, drainRegistrations(context?.metadata));
4
17
  defineEntity(entity, opts);
5
18
  };
6
19
  }
20
+ /**
21
+ * Registers a named `$where` filter, applied to every query unless bypassed via `QueryOptions.filters`.
22
+ *
23
+ * @example `@Filter('active', { condition: { status: 'active' }, default: false })`
24
+ */
25
+ export function Filter(name, opts) {
26
+ return (entity) => {
27
+ defineFilter(entity, name, opts);
28
+ };
29
+ }
30
+ /**
31
+ * Declares a composite index. Stacks, so several may sit above one class.
32
+ *
33
+ * `E` is inferred from the class the returned decorator is applied to, which is what lets the column
34
+ * names be checked against it: `@Index(['nope'])` does not compile.
35
+ *
36
+ * @example `@Index(['lastName', 'firstName'], { name: 'idx_users_fullname' })`
37
+ * @example `@Index(['email'], { unique: true })`
38
+ * @example `@Index(['status'], { where: "status = 'active'" })`
39
+ */
40
+ export function Index(columns, options = {}) {
41
+ return (entity) => {
42
+ defineIndex(entity, { ...options, columns });
43
+ };
44
+ }
@@ -0,0 +1,51 @@
1
+ import type { EntityGetter, FieldOptions, FieldType, RelationManyToManyOptions, RelationManyToOneOptions, RelationOneToManyOptions, RelationOneToOneOptions, TsTypeOf } from '../../type/index.js';
2
+ /** A member decorator that also constrains the property it may be applied to. */
3
+ type MemberDecorator<V> = (value: undefined, context: ClassFieldDecoratorContext<unknown, V>) => void;
4
+ /**
5
+ * Declares a persisted field.
6
+ *
7
+ * `@Field({ type: String })` on a `number` property is a compile error rather than a silent TEXT column,
8
+ * which is what makes the now-mandatory `type` worth stating.
9
+ *
10
+ * @example `@Field({ type: String }) name?: string;`
11
+ * @example `@Field({ references: () => Company }) companyId?: string;`
12
+ */
13
+ export declare function Field<T extends FieldType>(opts: FieldOptions & {
14
+ readonly type: T;
15
+ }): MemberDecorator<TsTypeOf<T> | undefined>;
16
+ /**
17
+ * A foreign key may omit `type`: schema generation resolves it from the referenced primary key, so the
18
+ * column picks up that key's `columnType`, length and chained references rather than a guess.
19
+ */
20
+ export declare function Field(opts: FieldOptions & {
21
+ readonly references: EntityGetter;
22
+ }): MemberDecorator<unknown>;
23
+ /**
24
+ * Declares the primary key, checked the same way as `@Field`.
25
+ *
26
+ * @example `@Id({ type: Number }) id?: number;`
27
+ * @example `@Id({ type: 'uuid', onInsert: uuidv7 }) id?: string;`
28
+ */
29
+ export declare function Id<T extends FieldType>(opts: FieldOptions & {
30
+ readonly type: T;
31
+ }): MemberDecorator<TsTypeOf<T> | undefined>;
32
+ /**
33
+ * `E` comes from the mandatory `entity` getter, so the context can insist the property really holds that
34
+ * entity: `@ManyToOne({ entity: () => Other })` on a `Company` field stops compiling, and a to-many
35
+ * cardinality on a non-array property does too. `entity` is required because nothing reflects it now.
36
+ */
37
+ type WithEntity<E, O> = O & {
38
+ readonly entity: EntityGetter<E>;
39
+ };
40
+ export declare function OneToOne<E>(opts: WithEntity<E, RelationOneToOneOptions<E>>): MemberDecorator<E | undefined>;
41
+ export declare function ManyToOne<E>(opts: WithEntity<E, RelationManyToOneOptions<E>>): MemberDecorator<E | undefined>;
42
+ export declare function OneToMany<E>(opts: WithEntity<E, RelationOneToManyOptions<E>>): MemberDecorator<readonly E[] | undefined>;
43
+ export declare function ManyToMany<E>(opts: WithEntity<E, RelationManyToManyOptions<E>>): MemberDecorator<readonly E[] | undefined>;
44
+ export declare const BeforeInsert: () => <This>(_value: unknown, context: ClassMethodDecoratorContext<This>) => void;
45
+ export declare const AfterInsert: () => <This>(_value: unknown, context: ClassMethodDecoratorContext<This>) => void;
46
+ export declare const BeforeUpdate: () => <This>(_value: unknown, context: ClassMethodDecoratorContext<This>) => void;
47
+ export declare const AfterUpdate: () => <This>(_value: unknown, context: ClassMethodDecoratorContext<This>) => void;
48
+ export declare const BeforeDelete: () => <This>(_value: unknown, context: ClassMethodDecoratorContext<This>) => void;
49
+ export declare const AfterDelete: () => <This>(_value: unknown, context: ClassMethodDecoratorContext<This>) => void;
50
+ export declare const AfterLoad: () => <This>(_value: unknown, context: ClassMethodDecoratorContext<This>) => void;
51
+ export {};