uql-orm 0.53.0 → 0.54.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 (41) hide show
  1. package/dist/browser/uql-browser.min.js.map +1 -1
  2. package/dist/cockroachdb/cockroachDialect.d.ts +2 -5
  3. package/dist/cockroachdb/cockroachDialect.js +2 -5
  4. package/dist/dialect/abstractSqlDialect.d.ts +6 -0
  5. package/dist/dialect/abstractSqlDialect.js +9 -3
  6. package/dist/dialect/mysqlLikeSqlDialect.d.ts +0 -3
  7. package/dist/dialect/mysqlLikeSqlDialect.js +0 -3
  8. package/dist/entity/decorator/members.d.ts +3 -10
  9. package/dist/entity/metadata/definition.js +0 -4
  10. package/dist/migrate/builder/migrationBuilder.js +0 -4
  11. package/dist/migrate/migrator.d.ts +3 -7
  12. package/dist/migrate/migrator.js +3 -7
  13. package/dist/migrate/schemaGenerator.d.ts +0 -13
  14. package/dist/migrate/schemaGenerator.js +0 -13
  15. package/dist/migrate/storage/databaseStorage.d.ts +2 -2
  16. package/dist/migrate/storage/databaseStorage.js +2 -2
  17. package/dist/mongo/mongodbQuerier.d.ts +3 -5
  18. package/dist/mongo/mongodbQuerier.js +18 -19
  19. package/dist/mssql/mssqlDialect.d.ts +2 -0
  20. package/dist/mssql/mssqlDialect.js +2 -0
  21. package/dist/querier/abstractQuerier.d.ts +17 -22
  22. package/dist/querier/abstractQuerier.js +80 -57
  23. package/dist/querier/abstractSqlQuerier.d.ts +9 -9
  24. package/dist/querier/abstractSqlQuerier.js +68 -84
  25. package/dist/schema/schemaASTBuilder.js +7 -7
  26. package/dist/type/entity.d.ts +6 -11
  27. package/dist/type/migration.d.ts +0 -3
  28. package/dist/type/query.d.ts +12 -12
  29. package/dist/type/query.js +0 -6
  30. package/dist/type/universalQuerier.d.ts +3 -3
  31. package/dist/util/dialect.util.d.ts +3 -2
  32. package/dist/util/dialect.util.js +1 -0
  33. package/dist/util/field.util.d.ts +4 -16
  34. package/dist/util/field.util.js +6 -19
  35. package/dist/util/fieldOption.util.d.ts +1 -4
  36. package/dist/util/fieldOption.util.js +0 -2
  37. package/dist/util/logger.d.ts +3 -3
  38. package/dist/util/logger.js +3 -0
  39. package/dist/util/raw.d.ts +3 -10
  40. package/dist/util/sql.util.js +2 -2
  41. package/package.json +1 -1
@@ -7,7 +7,7 @@
7
7
  */
8
8
  import { getMeta, soleIdOf } from '../entity/metadata/definition.js';
9
9
  import { ddlText } from '../util/ddlExpression.util.js';
10
- import { computedExpression, isInlinedExpression } from '../util/field.util.js';
10
+ import { isInlinedExpression } from '../util/field.util.js';
11
11
  import { isSoleIdField } from '../util/field.util.js';
12
12
  import { isAutoIncrement } from '../util/field.util.js';
13
13
  import { derivedForeignKeyName, derivedIndexName, qualifyName } from '../util/sql.util.js';
@@ -101,7 +101,7 @@ function addTableFromEntity(ctx, meta) {
101
101
  isPrimaryKey,
102
102
  isAutoIncrement: isAutoIncrement(field, isSoleKey),
103
103
  isUnique: field.unique ?? false,
104
- generatedAs: ddlText(computedExpression(field), `the computed column '${columnName}'`),
104
+ generatedAs: ddlText(field.computed, `the computed column '${columnName}'`),
105
105
  comment: field.comment,
106
106
  enum: field.enum,
107
107
  table,
@@ -202,16 +202,16 @@ function addIndexesFromEntity(ctx, meta) {
202
202
  addCompositeIndex(ctx, table, meta, idxMeta);
203
203
  }
204
204
  }
205
- /**
206
- * One `@Index([...])`. Its entries keep the authored form (expression, prefix length, order) with
207
- * names resolved, so the generator renders exactly what was declared; `columns` is the resolvable
208
- * subset, which is what diffing and introspection compare.
209
- */
210
205
  /** An `include` column is named like any other, so a naming strategy has to reach it too. */
211
206
  function resolveIncludeColumn(ctx, meta, column) {
212
207
  const field = meta.fields[column];
213
208
  return field ? ctx.resolveColumnName(column, field) : column;
214
209
  }
210
+ /**
211
+ * One `@Index([...])`. Its entries keep the authored form (expression, prefix length, order) with
212
+ * names resolved, so the generator renders exactly what was declared; `columns` is the resolvable
213
+ * subset, which is what diffing and introspection compare.
214
+ */
215
215
  function addCompositeIndex(ctx, table, meta, idxMeta) {
216
216
  // An entry survives if it is an expression (nothing to resolve) or names a column that exists;
217
217
  // an index left with none is dropped, the same as one naming only unknown columns always was.
@@ -359,11 +359,6 @@ export type FieldOptions<V = TsTypeOf<FieldType>> = {
359
359
  * @example `@Field({ type: String, enum: ['draft', 'paid'] as const })`
360
360
  */
361
361
  readonly enum?: EnumValues;
362
- /**
363
- * @deprecated Renamed to {@link FieldOptions.computed}, which also takes `stored`. `npx uql-codemod`
364
- * rewrites it. Giving both throws.
365
- */
366
- readonly virtual?: QueryRaw;
367
362
  /**
368
363
  * An expression the database computes, rather than a value the caller writes. Never part of an
369
364
  * insert or update either way.
@@ -818,12 +813,6 @@ export type EntityMeta<E> = {
818
813
  /** The revision `getMeta` last finalized, which is what makes finalizing idempotent and re-entrant. */
819
814
  processedAt?: number;
820
815
  };
821
- /**
822
- * Configurable options for an entity (`@Entity()` / `defineEntity`).
823
- *
824
- * Optional `fields`, `relations`, `indexes`, and `hooks` register metadata in one call for
825
- * decorator-free setups. Omit them when using `@Field` / `@ManyToOne` / etc.
826
- */
827
816
  /**
828
817
  * A table-level `CHECK`. The expression is `raw` with no interpolation, like an index expression:
829
818
  * this is DDL, so there is no placeholder a bound value could go into.
@@ -843,6 +832,12 @@ export type EntityMembers = {
843
832
  readonly relations?: Readonly<Record<string, RelationOptions | undefined>>;
844
833
  readonly hooks?: Readonly<Partial<Record<HookEvent, readonly string[]>>>;
845
834
  };
835
+ /**
836
+ * Configurable options for an entity (`@Entity()` / `defineEntity`).
837
+ *
838
+ * Optional `fields`, `relations`, `indexes`, and `hooks` register metadata in one call for
839
+ * decorator-free setups. Omit them when using `@Field` / `@ManyToOne` / etc.
840
+ */
846
841
  export type EntityOptions<E = unknown> = {
847
842
  readonly name?: string;
848
843
  /**
@@ -372,9 +372,6 @@ export interface SchemaIntrospector {
372
372
  * the database side never reports it, and no migration can close the gap.
373
373
  */
374
374
  readonly indexFacets: ReadonlySet<IndexFacet>;
375
- /**
376
- * Introspect entire database schema and return SchemaAST.
377
- */
378
375
  /** The whole database, or just the tables named. Names nothing matches are left out. */
379
376
  introspect(tables?: readonly string[]): Promise<SchemaAST>;
380
377
  /**
@@ -59,17 +59,17 @@ export type QueryExclude<E> = QuerySelect<E>;
59
59
  export type QueryPopulate<E> = {
60
60
  [K in RelationKey<E>]?: BooleanLike | QueryPopulateRelationOptions<E[K]>;
61
61
  };
62
+ /**
63
+ * The key a read carries its relation tallies under. One spelling for the type and the runtime that
64
+ * fills it: they sit in different modules, so a drift would type-check and answer `undefined`.
65
+ */
66
+ export declare const COUNT_RESULT_KEY = "_count";
62
67
  /**
63
68
  * How many rows each named relation holds per parent, `true` for all of them or a filter to narrow
64
69
  * which ones count. One statement per relation named here, batched over every parent at once, so it
65
70
  * stays flat however many rows the read returned. Comes back under `_count`, which keeps it clear of
66
71
  * a relation of the same name that `$populate` filled with rows.
67
72
  */
68
- /**
69
- * The key a read carries its relation tallies under. One spelling for the type and the runtime that
70
- * fills it: they sit in different modules, so a drift would type-check and answer `undefined`.
71
- */
72
- export declare const COUNT_RESULT_KEY = "_count";
73
73
  export type QueryCount<E> = {
74
74
  [K in ToManyRelationKey<E>]?: BooleanLike | QueryFilter<RelationTarget<E[K]>>;
75
75
  };
@@ -141,6 +141,13 @@ type ToOneRelationKey<E> = {
141
141
  }[RelationKey<E>];
142
142
  /** The relation names a parent holds many rows of, which a populated query fills with a list. */
143
143
  type ToManyRelationKey<E> = Exclude<RelationKey<E>, ToOneRelationKey<E>>;
144
+ /**
145
+ * Ordering parents by how many rows a to-many relation holds - "the ten users with the most posts".
146
+ * The tally is computed per parent as a correlated count, never by loading the rows.
147
+ */
148
+ export type QuerySortByCount = {
149
+ $count: QuerySortDirection;
150
+ };
144
151
  /**
145
152
  * sort by map - supports field keys, JSON dot-notation paths (restricted to real JSON fields,
146
153
  * like `QueryWhere`), relation sort via nested objects, and vector similarity search on
@@ -153,13 +160,6 @@ type ToManyRelationKey<E> = Exclude<RelationKey<E>, ToOneRelationKey<E>>;
153
160
  * against an intersection is repeated per constituent, which made this the single most expensive
154
161
  * type in the package to check.
155
162
  */
156
- /**
157
- * Ordering parents by how many rows a to-many relation holds - "the ten users with the most posts".
158
- * The tally is computed per parent as a correlated count, never by loading the rows.
159
- */
160
- export type QuerySortByCount = {
161
- $count: QuerySortDirection;
162
- };
163
163
  export type QuerySortMap<E, Vector extends boolean = true> = {
164
164
  [K in FieldKey<E> | JsonFieldPaths<E> | RelationKey<E>]?: K extends RelationKey<E> ? IsMany<E[K]> extends true ? QuerySortByCount : QuerySortMap<RelationTarget<E[K]>, false> : K extends FieldKey<E> ? Vector extends true ? NonNullable<E[K]> extends readonly number[] ? QuerySortValue : QuerySortDirection : QuerySortDirection : QuerySortDirection;
165
165
  };
@@ -1,9 +1,3 @@
1
- /**
2
- * How many rows each named relation holds per parent, `true` for all of them or a filter to narrow
3
- * which ones count. One statement per relation named here, batched over every parent at once, so it
4
- * stays flat however many rows the read returned. Comes back under `_count`, which keeps it clear of
5
- * a relation of the same name that `$populate` filled with rows.
6
- */
7
1
  /**
8
2
  * The key a read carries its relation tallies under. One spelling for the type and the runtime that
9
3
  * fills it: they sit in different modules, so a drift would type-check and answer `undefined`.
@@ -126,7 +126,7 @@ export interface UniversalQuerier extends SharedQuerier<'server', QueryOptions>
126
126
  * on MySQL/SQLite they are inferred from the driver header, which is only reliable for
127
127
  * auto-increment keys in batches without explicit IDs - otherwise those entries are
128
128
  * `undefined` rather than potentially wrong values. A composite key is never one the statement
129
- * reports, so those rows are named from the payload instead.
129
+ * reports, so those rows are named as written, `onInsert` columns included.
130
130
  * @param entity the entity to persist on
131
131
  * @param payload the data to be persisted
132
132
  * @return the IDs
@@ -137,7 +137,7 @@ export interface UniversalQuerier extends SharedQuerier<'server', QueryOptions>
137
137
  * @param entity the entity to persist on
138
138
  * @param conflictPaths the keys to use for the unique search
139
139
  * @param payload the data to be persisted
140
- * @return operation metadata; see {@link QueryUpdateResult}
140
+ * @return the id and whether it was created; see {@link QueryUpsertOneResult}
141
141
  */
142
142
  upsertOne<E extends object>(entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: EntityData<E>): Promise<QueryUpsertOneResult<E>>;
143
143
  /**
@@ -145,7 +145,7 @@ export interface UniversalQuerier extends SharedQuerier<'server', QueryOptions>
145
145
  * @param entity the entity to persist on
146
146
  * @param conflictPaths the keys to use for the unique search
147
147
  * @param payload the data to be persisted
148
- * @return operation metadata; see {@link QueryUpdateResult}
148
+ * @return the ids, in payload order; see {@link QueryUpsertManyResult}
149
149
  */
150
150
  upsertMany<E extends object>(entity: Type<E>, conflictPaths: QueryConflictPaths<E>, payload: EntityData<E>[]): Promise<QueryUpsertManyResult<E>>;
151
151
  /**
@@ -1,4 +1,4 @@
1
- import { type CascadeType, type EntityData, type EntityId, type EntityIndexMeta, type EntityMeta, type FieldKey, type FieldOptions, type JsonUpdateOp, type OnFieldCallback, type Query, type QueryAggMap, type QueryAggregateOp, type QueryExclude, type QueryGroupMap, type QueryOptions, QueryRaw, type QuerySearch, type QuerySelect, type QuerySelectValue, type QuerySizeComparisonOps, type QuerySortMap, type QueryVectorSearch, type QueryWhere, type RelationKey } from '../type/index.js';
1
+ import { type CascadeType, type EntityData, type EntityId, type EntityIndexMeta, type EntityMeta, type FieldKey, type FieldOptions, type JsonUpdateOp, type OnFieldCallback, type Query, type QueryAggMap, type QueryAggregateOp, type QueryExclude, type QueryGroupMap, type QueryOptions, QueryRaw, type QuerySearch, type QuerySelect, type QuerySelectValue, type QuerySizeComparisonOps, type QuerySortMap, type QueryVectorSearch, type QueryWhere, type RelationKey, type UpdatePayload } from '../type/index.js';
2
2
  export type CallbackKey = keyof Pick<FieldOptions, 'onInsert' | 'onUpdate'>;
3
3
  export declare function filterFieldKeys<E>(meta: EntityMeta<E>, payload: EntityData<E>, callbackKey: CallbackKey): FieldKey<E>[];
4
4
  /** Appends `record`'s not-yet-`seen` insertable keys (real, caller-written, defined value) to `keys`. */
@@ -35,7 +35,8 @@ export declare function getSoftDeleteValue(field: FieldOptions): string | number
35
35
  }[] | readonly number[] | Uint8Array<ArrayBufferLike> | {
36
36
  readonly __json?: never;
37
37
  };
38
- export declare function fillOnFields<E>(meta: EntityMeta<E>, payload: EntityData<E> | EntityData<E>[], callbackKey: CallbackKey): EntityData<E>[];
38
+ /** Fills each field `callbackKey` generates on `payload` in place, where the caller left it unset. */
39
+ export declare function fillOnFields<E, R extends EntityData<E> | UpdatePayload<E>>(meta: EntityMeta<E>, payload: R | R[], callbackKey: CallbackKey): R[];
39
40
  /**
40
41
  * The relation keys present in `payload` whose cascade configuration allows `action`. Only
41
42
  * `payload`'s keys are read, so any keys-bearing object works (an entity, an update payload,
@@ -73,6 +73,7 @@ export function getFieldCallbackValue(val) {
73
73
  export function getSoftDeleteValue(field) {
74
74
  return field.softDelete === true ? new Date() : getFieldCallbackValue(field.softDelete);
75
75
  }
76
+ /** Fills each field `callbackKey` generates on `payload` in place, where the caller left it unset. */
76
77
  export function fillOnFields(meta, payload, callbackKey) {
77
78
  const payloads = Array.isArray(payload) ? payload : [payload];
78
79
  const keys = getKeys(meta.fields).filter((key) => meta.fields[key][callbackKey]);
@@ -1,5 +1,4 @@
1
1
  import type { EntityMeta, FieldOptions } from '../type/index.js';
2
- import type { QueryRaw } from '../type/queryRaw.js';
3
2
  /**
4
3
  * The kind of column a field lands on, which is what decides whether an option means anything on it:
5
4
  * `length` is a string's, `precision` a number's, `dimensions` a vector's. Named in the words an
@@ -23,26 +22,15 @@ export declare const COLUMN_TYPES_BY_FAMILY: {
23
22
  };
24
23
  /** The family of a logical field type, or `undefined` where it names none. */
25
24
  export declare function columnFamily(type: unknown): ColumnFamily | undefined;
26
- /**
27
- * The expression the database computes for this field, whichever key declared it.
28
- *
29
- * `virtual` is `computed` under its old name and is read here so both spell one behaviour. Giving
30
- * both is refused at registration rather than resolved, since only the author knows which was meant.
31
- */
32
- export declare function computedExpression(field: FieldOptions): QueryRaw | undefined;
33
25
  /**
34
26
  * Whether the field's expression is spliced into each statement that reads it, rather than stored.
35
- *
36
- * One of the two questions `virtual` used to answer alone. Every read site asks this - the DDL skip,
37
- * the projection, the `$where` operand, the `ORDER BY` operand - because an inlined field has no
38
- * column to name, while a stored one is read exactly like any other.
27
+ * Every read site asks this - the DDL skip, the projection, the `$where` and `ORDER BY` operands -
28
+ * because an inlined field has no column to name, while a stored one is read like any other.
39
29
  */
40
30
  export declare function isInlinedExpression(field: FieldOptions): boolean;
41
31
  /**
42
- * Whether the database supplies this field's value, so no insert or update may write it.
43
- *
44
- * The other question, and the one that makes `stored` more than a rename: a stored computed column
45
- * *is* a real column, so it is read like one - but writing to it is an error on every engine.
32
+ * Whether the database supplies this field's value, so no insert or update may write it: a stored
33
+ * computed column *is* a real column, read like one, but writing to it is an error on every engine.
46
34
  */
47
35
  export declare function isDatabaseWritten(field: FieldOptions): boolean;
48
36
  /**
@@ -46,33 +46,20 @@ for (const family of getKeys(COLUMN_TYPES_BY_FAMILY)) {
46
46
  export function columnFamily(type) {
47
47
  return FAMILY_OF.get(typeof type === 'string' ? type.toLowerCase() : type);
48
48
  }
49
- /**
50
- * The expression the database computes for this field, whichever key declared it.
51
- *
52
- * `virtual` is `computed` under its old name and is read here so both spell one behaviour. Giving
53
- * both is refused at registration rather than resolved, since only the author knows which was meant.
54
- */
55
- export function computedExpression(field) {
56
- return field.computed ?? field.virtual;
57
- }
58
49
  /**
59
50
  * Whether the field's expression is spliced into each statement that reads it, rather than stored.
60
- *
61
- * One of the two questions `virtual` used to answer alone. Every read site asks this - the DDL skip,
62
- * the projection, the `$where` operand, the `ORDER BY` operand - because an inlined field has no
63
- * column to name, while a stored one is read exactly like any other.
51
+ * Every read site asks this - the DDL skip, the projection, the `$where` and `ORDER BY` operands -
52
+ * because an inlined field has no column to name, while a stored one is read like any other.
64
53
  */
65
54
  export function isInlinedExpression(field) {
66
- return computedExpression(field) !== undefined && field.stored !== true;
55
+ return field.computed !== undefined && field.stored !== true;
67
56
  }
68
57
  /**
69
- * Whether the database supplies this field's value, so no insert or update may write it.
70
- *
71
- * The other question, and the one that makes `stored` more than a rename: a stored computed column
72
- * *is* a real column, so it is read like one - but writing to it is an error on every engine.
58
+ * Whether the database supplies this field's value, so no insert or update may write it: a stored
59
+ * computed column *is* a real column, read like one, but writing to it is an error on every engine.
73
60
  */
74
61
  export function isDatabaseWritten(field) {
75
- return computedExpression(field) !== undefined;
62
+ return field.computed !== undefined;
76
63
  }
77
64
  /**
78
65
  * Whether the field is the entity's *whole* primary key - the only kind a serial can stand in for,
@@ -14,7 +14,6 @@ declare const FIELD_OPTION_FAMILY: {
14
14
  readonly references: '*';
15
15
  readonly onDelete: '*';
16
16
  readonly enum: '*';
17
- readonly virtual: '*';
18
17
  readonly computed: '*';
19
18
  readonly stored: '*';
20
19
  readonly updatable: '*';
@@ -39,7 +38,7 @@ declare const FIELD_OPTION_FAMILY: {
39
38
  * rather than on each option that dies, because it is one fact rather than nineteen - and because an
40
39
  * option added without a thought then lands on the safe side of it.
41
40
  */
42
- declare const INLINE_READS: readonly ["type", "virtual", "computed", "stored", "enum", "eager", "distance"];
41
+ declare const INLINE_READS: readonly ["type", "computed", "stored", "enum", "eager", "distance"];
43
42
  type InlineRead = (typeof INLINE_READS)[number];
44
43
  /**
45
44
  * What a column the *database* writes cannot use. A stored computed column is a real column - it has
@@ -66,8 +65,6 @@ type FamilyOfType<T> = T extends NumericColumnType | NumberConstructor | BigIntC
66
65
  type DeadOptions<O> = (O extends {
67
66
  readonly stored: true;
68
67
  } ? GeneratedWrite : O extends {
69
- readonly virtual: QueryRaw;
70
- } | {
71
68
  readonly computed: QueryRaw;
72
69
  } ? Exclude<keyof FieldOptions, InlineRead> : never) | (O extends {
73
70
  readonly isId: true;
@@ -14,7 +14,6 @@ const FIELD_OPTION_FAMILY = {
14
14
  references: '*',
15
15
  onDelete: '*',
16
16
  enum: '*',
17
- virtual: '*',
18
17
  computed: '*',
19
18
  stored: '*',
20
19
  updatable: '*',
@@ -41,7 +40,6 @@ const FIELD_OPTION_FAMILY = {
41
40
  */
42
41
  const INLINE_READS = [
43
42
  'type',
44
- 'virtual',
45
43
  'computed',
46
44
  'stored',
47
45
  'enum',
@@ -12,9 +12,6 @@ export declare class DefaultLogger implements Logger {
12
12
  logMigration(message: string): void;
13
13
  logSkippedMigration(message: string): void;
14
14
  }
15
- /**
16
- * A wrapper class that implements the Logger interface and handles different logging options.
17
- */
18
15
  /**
19
16
  * Secondary {@link LoggerWrapper} settings, alongside the primary `options: LoggingOptions`
20
17
  * constructor argument.
@@ -28,6 +25,9 @@ export interface LoggerWrapperConfig {
28
25
  /** Threshold in milliseconds - queries exceeding this are logged as slow. */
29
26
  slowQuery?: number;
30
27
  }
28
+ /**
29
+ * A wrapper class that implements the Logger interface and handles different logging options.
30
+ */
31
31
  export declare class LoggerWrapper implements Logger {
32
32
  private readonly levels;
33
33
  private readonly logger?;
@@ -40,6 +40,9 @@ export class DefaultLogger {
40
40
  console.info(`\x1b[33mskipped migration:\x1b[0m ${message}`);
41
41
  }
42
42
  }
43
+ /**
44
+ * A wrapper class that implements the Logger interface and handles different logging options.
45
+ */
43
46
  export class LoggerWrapper {
44
47
  levels;
45
48
  logger;
@@ -1,4 +1,4 @@
1
- import { QueryRaw, type QueryRawFn, type Scalar } from '../type/index.js';
1
+ import { QueryRaw, type QueryRawFn } from '../type/index.js';
2
2
  /**
3
3
  * Create a raw SQL expression.
4
4
  *
@@ -19,18 +19,11 @@ import { QueryRaw, type QueryRawFn, type Scalar } from '../type/index.js';
19
19
  * The callback form remains for SQL a template cannot express, such as a sub-query generated through
20
20
  * `dialect.find(...)`. See {@link col} for a context-aware column reference.
21
21
  *
22
- * **⚠️ Security:** the tag is safe because it binds; the other two forms are not. `raw('SQL')` emits
23
- * its argument verbatim and a callback emits whatever it writes, so build neither from user input.
24
- * Inside a callback, bind with `ctx.addValue()`.
22
+ * **⚠️ Security:** the tag is safe because it binds; a callback is not, since it emits whatever it
23
+ * writes, so never build one from user input. Inside a callback, bind with `ctx.addValue()`.
25
24
  */
26
25
  export declare function raw(strings: TemplateStringsArray, ...values: readonly unknown[]): QueryRaw;
27
26
  export declare function raw(value: QueryRawFn, alias?: string): QueryRaw;
28
- /**
29
- * @deprecated Emits its argument verbatim, so it cannot bind a value. Use the tagged template:
30
- * `raw('"a" > 1')` becomes `` raw`"a" > 1` ``, and `raw('LOG10(x)', 'score')` becomes
31
- * `` raw`LOG10(x)`.as('score') ``. `npx uql-codemod` rewrites both.
32
- */
33
- export declare function raw(value: Scalar, alias?: string): QueryRaw;
34
27
  /**
35
28
  * A column of the entity being queried, alias-qualified and escaped for the dialect. This is what a
36
29
  * template cannot know on its own: the alias is decided while the statement is built, not where the
@@ -200,8 +200,8 @@ export function buildUpdateResult(payload) {
200
200
  // UPDATE` convention makes `changes` a per-row weighted sum (1=insert, 2=update, 0=no-op), so a
201
201
  // batch mixing an insert and an update would fabricate ids for rows that were never touched. This
202
202
  // function has no way to tell the two call sites apart (`internalRun` reports the same header
203
- // shape either way), so `AbstractSqlQuerier.upsertMany` strips `ids`/`firstId`/`created` back down
204
- // to just `changes` for a multi-row `firstId`-dialect upsert after calling this.
203
+ // shape either way), so `AbstractSqlQuerier`'s `runUpsert` discards them for a multi-row `firstId`
204
+ // upsert and reads the ids back by the conflict columns instead.
205
205
  let ids = [];
206
206
  if (rows?.length) {
207
207
  ids = rows.map((r) => r['id']);
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.53.0",
6
+ "version": "0.54.0",
7
7
  "type": "module",
8
8
  "engines": {
9
9
  "node": ">=24"