rado 1.2.1 → 1.3.0-preview.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +163 -257
  2. package/dist/compat.d.ts +3 -0
  3. package/dist/core/Builder.d.ts +16 -9
  4. package/dist/core/Builder.js +52 -4
  5. package/dist/core/Column.d.ts +25 -21
  6. package/dist/core/Column.js +39 -23
  7. package/dist/core/Constraint.d.ts +2 -1
  8. package/dist/core/Constraint.js +2 -1
  9. package/dist/core/Database.d.ts +5 -4
  10. package/dist/core/Database.js +14 -13
  11. package/dist/core/Emitter.d.ts +2 -2
  12. package/dist/core/Index.d.ts +1 -1
  13. package/dist/core/Internal.d.ts +19 -2
  14. package/dist/core/Internal.js +29 -11
  15. package/dist/core/Param.js +2 -0
  16. package/dist/core/Queries.d.ts +1 -0
  17. package/dist/core/Queries.js +11 -1
  18. package/dist/core/Resolver.js +2 -2
  19. package/dist/core/Schema.d.ts +1 -3
  20. package/dist/core/Selection.d.ts +9 -4
  21. package/dist/core/Selection.js +94 -5
  22. package/dist/core/Sql.d.ts +4 -3
  23. package/dist/core/Sql.js +8 -2
  24. package/dist/core/Table.d.ts +18 -11
  25. package/dist/core/Table.js +45 -25
  26. package/dist/core/View.d.ts +34 -0
  27. package/dist/core/View.js +153 -0
  28. package/dist/core/Virtual.d.ts +7 -2
  29. package/dist/core/Virtual.js +14 -10
  30. package/dist/core/expr/Conditions.d.ts +7 -7
  31. package/dist/core/expr/Include.d.ts +4 -4
  32. package/dist/core/expr/Include.js +2 -2
  33. package/dist/core/expr/Input.d.ts +1 -1
  34. package/dist/core/expr/Input.js +5 -1
  35. package/dist/core/query/CTE.d.ts +3 -5
  36. package/dist/core/query/CTE.js +1 -13
  37. package/dist/core/query/Delete.d.ts +10 -10
  38. package/dist/core/query/Delete.js +2 -2
  39. package/dist/core/query/Insert.d.ts +6 -5
  40. package/dist/core/query/Insert.js +22 -9
  41. package/dist/core/query/Query.d.ts +26 -11
  42. package/dist/core/query/Select.d.ts +41 -8
  43. package/dist/core/query/Select.js +235 -25
  44. package/dist/core/query/Shared.d.ts +2 -1
  45. package/dist/core/query/Shared.js +8 -5
  46. package/dist/core/query/Update.d.ts +9 -9
  47. package/dist/core/query/Update.js +24 -12
  48. package/dist/driver/better-sqlite3.js +4 -0
  49. package/dist/driver/bun-sqlite.js +3 -0
  50. package/dist/driver/d1.js +3 -0
  51. package/dist/driver/libsql.js +4 -0
  52. package/dist/driver/mysql2.js +5 -0
  53. package/dist/driver/pg.d.ts +17 -1
  54. package/dist/driver/pg.js +10 -1
  55. package/dist/driver/pglite.js +21 -6
  56. package/dist/driver/sql.js.js +4 -0
  57. package/dist/index.d.ts +1 -0
  58. package/dist/index.js +1 -0
  59. package/dist/mysql/columns.d.ts +30 -30
  60. package/dist/mysql/columns.js +25 -24
  61. package/dist/mysql/dialect.js +6 -2
  62. package/dist/mysql/diff.js +1 -1
  63. package/dist/mysql.d.ts +1 -0
  64. package/dist/mysql.js +2 -0
  65. package/dist/postgres/columns.d.ts +103 -33
  66. package/dist/postgres/columns.js +317 -35
  67. package/dist/postgres/diff.js +3 -3
  68. package/dist/postgres/enum.d.ts +17 -0
  69. package/dist/postgres/enum.js +64 -0
  70. package/dist/postgres/schema.d.ts +19 -0
  71. package/dist/postgres/schema.js +47 -0
  72. package/dist/postgres.d.ts +3 -1
  73. package/dist/postgres.js +9 -2
  74. package/dist/sqlite/columns.d.ts +29 -14
  75. package/dist/sqlite/columns.js +41 -9
  76. package/dist/sqlite/dialect.js +3 -1
  77. package/dist/sqlite/diff.js +1 -1
  78. package/dist/sqlite/functions.d.ts +1 -1
  79. package/dist/sqlite/functions.js +1 -1
  80. package/dist/sqlite.d.ts +1 -0
  81. package/dist/sqlite.js +3 -6
  82. package/dist/universal/columns.d.ts +8 -8
  83. package/dist/universal/columns.js +10 -9
  84. package/dist/universal/functions.d.ts +1 -1
  85. package/dist/universal/functions.js +1 -1
  86. package/package.json +57 -38
@@ -1,12 +1,17 @@
1
1
  // src/core/query/Select.ts
2
+ import { and } from "../expr/Conditions.js";
2
3
  import {
3
4
  getData,
5
+ getField,
4
6
  getQuery,
5
7
  getSelection,
6
8
  getSql,
9
+ getTable,
7
10
  getTarget,
11
+ hasField,
8
12
  hasSelection,
9
13
  hasSql,
14
+ hasTable,
10
15
  hasTarget,
11
16
  internalData,
12
17
  internalQuery,
@@ -19,9 +24,23 @@ import {
19
24
  selection
20
25
  } from "../Selection.js";
21
26
  import { Sql, sql } from "../Sql.js";
22
- import { and } from "../expr/Conditions.js";
23
27
  import { formatCTE } from "./CTE.js";
24
28
  import { formatModifiers } from "./Shared.js";
29
+ function isUnionQuery(query) {
30
+ return Array.isArray(query.select);
31
+ }
32
+ function mapScalarSelection(query, selected) {
33
+ if (hasSql(selected)) return query.mapWith(getSql(selected));
34
+ if (selected && typeof selected === "object") {
35
+ const values = Object.values(selected);
36
+ if (values.length === 1) {
37
+ const first = values[0];
38
+ if (first && typeof first === "object" && hasSql(first))
39
+ return query.mapWith(getSql(first));
40
+ }
41
+ }
42
+ return query;
43
+ }
25
44
  var SelectFirst = class extends SingleQuery {
26
45
  [internalData];
27
46
  constructor(data) {
@@ -36,7 +55,10 @@ var SelectFirst = class extends SingleQuery {
36
55
  return selectQuery(getData(this));
37
56
  }
38
57
  get [internalSql]() {
39
- return sql`(${getQuery(this)})`;
58
+ return mapScalarSelection(
59
+ sql`(${getQuery(this)})`,
60
+ getSelection(this).input
61
+ );
40
62
  }
41
63
  };
42
64
  var UnionBase = class extends SingleQuery {
@@ -46,9 +68,14 @@ var UnionBase = class extends SingleQuery {
46
68
  this[internalData] = data;
47
69
  }
48
70
  as(alias) {
49
- const fields = getSelection(this).makeVirtual(alias);
50
- return Object.assign(fields, {
71
+ const selected = getSelection(this);
72
+ const fields = selected.makeVirtual(alias);
73
+ return Object.assign({}, fields, {
51
74
  [internalSelection]: selection(fields),
75
+ [internalSql]: mapScalarSelection(
76
+ sql`(${getQuery(this)})`,
77
+ selected.input
78
+ ),
52
79
  [internalTarget]: sql`(${getQuery(this)}) as ${sql.identifier(
53
80
  alias
54
81
  )}`.inlineFields(true)
@@ -63,15 +90,73 @@ var UnionBase = class extends SingleQuery {
63
90
  if (!("compound" in data)) throw new Error("No compound defined");
64
91
  return data.compound;
65
92
  }
93
+ #selectFields(select) {
94
+ return querySelection(select).fieldNames();
95
+ }
96
+ #segmentSelect(segment) {
97
+ const query = segment;
98
+ if (isUnionQuery(query)) return query.select[0];
99
+ if ("union" in segment) return this.#segmentSelect(segment.union);
100
+ if ("unionAll" in segment) return this.#segmentSelect(segment.unionAll);
101
+ if ("intersect" in segment) return this.#segmentSelect(segment.intersect);
102
+ if ("intersectAll" in segment)
103
+ return this.#segmentSelect(segment.intersectAll);
104
+ if ("except" in segment) return this.#segmentSelect(segment.except);
105
+ if ("exceptAll" in segment) return this.#segmentSelect(segment.exceptAll);
106
+ return segment;
107
+ }
108
+ #unionSegment(op, query) {
109
+ switch (op) {
110
+ case "union":
111
+ return { union: query };
112
+ case "unionAll":
113
+ return { unionAll: query };
114
+ case "intersect":
115
+ return { intersect: query };
116
+ case "intersectAll":
117
+ return { intersectAll: query };
118
+ case "except":
119
+ return { except: query };
120
+ case "exceptAll":
121
+ return { exceptAll: query };
122
+ }
123
+ }
124
+ #assertMatchingFields(left, right) {
125
+ const fields = this.#selectFields(left[0]);
126
+ const assert = (query) => {
127
+ const names = this.#selectFields(query);
128
+ if (fields.length !== names.length)
129
+ throw new Error("Union segments must have the same fields");
130
+ for (let i = 0; i < fields.length; i++)
131
+ if (fields[i] !== names[i])
132
+ throw new Error("Union segments must have the same fields");
133
+ };
134
+ for (const segment of left.slice(1)) assert(this.#segmentSelect(segment));
135
+ for (const segment of right) assert(this.#segmentSelect(segment));
136
+ }
137
+ #appendCompound(left, op, right) {
138
+ const [firstRight, ...restRight] = right.select;
139
+ if (restRight.length === 0)
140
+ return [...left, this.#unionSegment(op, firstRight)];
141
+ return [...left, this.#unionSegment(op, right)];
142
+ }
66
143
  #compound(op, target) {
67
144
  const left = this.#getSelect(this);
68
- const right = this.#getSelect(
69
- typeof target === "function" ? target(this.#makeSelf()) : target
70
- );
71
- const [on, ...rest] = right;
72
- const select = [...left, { [op]: on }, ...rest];
145
+ const rightBase = typeof target === "function" ? target(this.#makeSelf()) : target;
146
+ const rightData = getData(rightBase);
147
+ const rightSelect = this.#getSelect(rightBase);
148
+ const right = { ...rightData, select: rightSelect };
149
+ this.#assertMatchingFields(left, rightSelect);
150
+ const select = this.#appendCompound(left, op, right);
151
+ const {
152
+ resolver,
153
+ with: withDefs,
154
+ withRecursive
155
+ } = getData(this);
73
156
  return new Union({
74
- ...getData(this),
157
+ resolver,
158
+ with: withDefs,
159
+ withRecursive,
75
160
  select
76
161
  });
77
162
  }
@@ -94,6 +179,7 @@ var UnionBase = class extends SingleQuery {
94
179
  return this.#compound("exceptAll", target);
95
180
  }
96
181
  };
182
+ var forKeywords = ["update", "no key update", "share", "key share"];
97
183
  var Select = class _Select extends UnionBase {
98
184
  [internalData];
99
185
  constructor(data) {
@@ -105,6 +191,18 @@ var Select = class _Select extends UnionBase {
105
191
  from(from) {
106
192
  return new _Select({ ...getData(this), from });
107
193
  }
194
+ for(keyword, config = {}) {
195
+ if (!forKeywords.includes(keyword))
196
+ throw new Error(`Invalid FOR keyword: ${keyword}`);
197
+ return new _Select({
198
+ ...getData(this),
199
+ for: sql.query(sql.unsafe(keyword), {
200
+ of: config.of && sql.join([config.of].flat().map(getTarget), sql`, `),
201
+ nowait: config.noWait,
202
+ skipLocked: config.skipLocked
203
+ })
204
+ });
205
+ }
108
206
  #fromTarget() {
109
207
  const { from } = getData(this);
110
208
  if (!from) throw new Error("No target defined");
@@ -117,17 +215,26 @@ var Select = class _Select extends UnionBase {
117
215
  leftJoin(leftJoin, on) {
118
216
  return this.#join({ leftJoin, on });
119
217
  }
218
+ leftJoinLateral(leftJoinLateral, on) {
219
+ return this.#join({ leftJoinLateral, on });
220
+ }
120
221
  rightJoin(rightJoin, on) {
121
222
  return this.#join({ rightJoin, on });
122
223
  }
123
224
  innerJoin(innerJoin, on) {
124
225
  return this.#join({ innerJoin, on });
125
226
  }
227
+ innerJoinLateral(innerJoinLateral, on) {
228
+ return this.#join({ innerJoinLateral, on });
229
+ }
126
230
  fullJoin(fullJoin, on) {
127
231
  return this.#join({ fullJoin, on });
128
232
  }
129
- crossJoin(crossJoin, on) {
130
- return this.#join({ crossJoin, on });
233
+ crossJoin(crossJoin) {
234
+ return this.#join({ crossJoin });
235
+ }
236
+ crossJoinLateral(crossJoinLateral) {
237
+ return this.#join({ crossJoinLateral });
131
238
  }
132
239
  where(...where) {
133
240
  return new _Select({ ...getData(this), where: and(...where) });
@@ -163,17 +270,101 @@ var Select = class _Select extends UnionBase {
163
270
  return sql`(${getQuery(this)})`;
164
271
  }
165
272
  };
273
+ function collectReferencedTargets(input, names) {
274
+ if (hasSql(input)) {
275
+ if (hasField(input)) {
276
+ const field = getField(input);
277
+ const source = field.source;
278
+ if (!(source && typeof source === "object" && hasSql(source)))
279
+ names.add(field.targetName);
280
+ }
281
+ return;
282
+ }
283
+ if (!input || typeof input !== "object") return;
284
+ for (const value of Object.values(input))
285
+ collectReferencedTargets(value, names);
286
+ }
287
+ function collectFromTargets(from, names) {
288
+ if (!from) return;
289
+ const collect = (target) => {
290
+ if (hasTable(target)) {
291
+ names.add(getTable(target).aliased);
292
+ return;
293
+ }
294
+ if (!hasSelection(target)) return;
295
+ collectReferencedTargets(getSelection(target).input, names);
296
+ };
297
+ if (Array.isArray(from)) {
298
+ for (const entry of from) {
299
+ if (hasTarget(entry)) collect(entry);
300
+ else if (!hasSql(entry)) {
301
+ const { target } = joinOp(entry);
302
+ if (hasTarget(target)) collect(target);
303
+ }
304
+ }
305
+ return;
306
+ }
307
+ if (hasTarget(from)) collect(from);
308
+ }
309
+ function hasUnnamedDerivedSource(input) {
310
+ if (hasField(input)) {
311
+ const source = getField(input).source;
312
+ if (source && typeof source === "object" && hasSql(source)) {
313
+ const sourceSql = source;
314
+ if (!hasField(sourceSql) && !getSql(sourceSql).alias) return true;
315
+ }
316
+ return false;
317
+ }
318
+ if (hasSql(input)) return false;
319
+ if (!input || typeof input !== "object") return false;
320
+ return Object.values(input).some(
321
+ hasUnnamedDerivedSource
322
+ );
323
+ }
166
324
  function querySelection({ select, from }) {
167
- if (select) return selection(select);
325
+ if (select) {
326
+ if (from) {
327
+ const selectedTargets = /* @__PURE__ */ new Set();
328
+ const fromTargets = /* @__PURE__ */ new Set();
329
+ collectReferencedTargets(select, selectedTargets);
330
+ collectFromTargets(from, fromTargets);
331
+ if (fromTargets.size > 0) {
332
+ for (const targetName of selectedTargets)
333
+ if (!fromTargets.has(targetName))
334
+ throw new Error(`Unknown target in select: ${targetName}`);
335
+ }
336
+ }
337
+ if (hasSql(select) && hasSelection(select)) {
338
+ const selected = getSelection(select);
339
+ if (!from || !Array.isArray(from)) return selected;
340
+ const [, ...joins2] = from;
341
+ return applyJoins(selected, joins2);
342
+ }
343
+ if (!from || !Array.isArray(from))
344
+ return selection(select);
345
+ const [, ...joins] = from;
346
+ return applyJoins(selection(select), joins);
347
+ }
168
348
  if (!from) throw new Error("No selection defined");
169
349
  if (Array.isArray(from)) {
170
350
  const [target, ...joins] = from;
171
- return joins.reduce((result, join) => {
172
- const { target: target2, op } = joinOp(join);
173
- return result.join(target2, op);
174
- }, selection(target));
351
+ return applyJoins(selection(target), joins);
175
352
  }
176
- return hasSelection(from) ? getSelection(from) : selection(sql`*`);
353
+ if (hasSelection(from)) {
354
+ const selected = getSelection(from);
355
+ if (hasUnnamedDerivedSource(selected.input))
356
+ throw new Error("Cannot select all from subquery without alias");
357
+ return selected;
358
+ }
359
+ return selection(sql`*`);
360
+ }
361
+ function applyJoins(base, joins) {
362
+ let current = base;
363
+ for (const join of joins) {
364
+ const { target, op } = joinOp(join);
365
+ current = current.join(target, op);
366
+ }
367
+ return current;
177
368
  }
178
369
  function joinOp(join) {
179
370
  const { on, ...rest } = join;
@@ -181,22 +372,26 @@ function joinOp(join) {
181
372
  const target = rest[op];
182
373
  return { target, op, on };
183
374
  }
375
+ function formatTarget(target) {
376
+ if (hasTable(target)) return getTable(target).target();
377
+ return getTarget(target);
378
+ }
184
379
  function formatFrom(from) {
185
380
  if (!from) throw new Error("No target defined");
186
381
  if (Array.isArray(from)) {
187
382
  return sql.join(
188
383
  from.map((join) => {
189
- if (hasTarget(join)) return getTarget(join);
384
+ if (hasTarget(join)) return formatTarget(join);
190
385
  if (hasSql(join)) return getSql(join);
191
386
  const { target, op, on } = joinOp(join);
192
387
  return sql.query({
193
- [op]: hasTarget(target) ? getTarget(target) : getSql(target),
388
+ [op]: hasTarget(target) ? formatTarget(target) : getSql(target),
194
389
  on
195
390
  });
196
391
  })
197
392
  );
198
393
  }
199
- return hasTarget(from) ? getTarget(from) : getSql(from);
394
+ return hasTarget(from) ? formatTarget(from) : getSql(from);
200
395
  }
201
396
  function selectQuery(query) {
202
397
  const { from, where, groupBy, having, distinct, distinctOn } = query;
@@ -208,11 +403,12 @@ function selectQuery(query) {
208
403
  {
209
404
  select,
210
405
  from: from && formatFrom(from),
406
+ for: query.for,
211
407
  where,
212
408
  groupBy: groupBy && sql.join(groupBy, sql`, `),
213
409
  having: typeof having === "function" ? having(selected.input) : having
214
410
  },
215
- formatModifiers(query)
411
+ formatModifiers(query, selected)
216
412
  );
217
413
  }
218
414
  var Union = class _Union extends UnionBase {
@@ -281,19 +477,33 @@ function exceptAll(left, right, ...rest) {
281
477
  function unionQuery(query) {
282
478
  const { select } = query;
283
479
  let fields;
480
+ const firstSelect = (query2) => isUnionQuery(query2) ? query2.select[0] : query2;
481
+ const segmentQuery = (query2) => {
482
+ if (isUnionQuery(query2)) {
483
+ const nested = unionQuery(query2);
484
+ return sql.universal({
485
+ sqlite: sql`select * from (${nested})`,
486
+ default: sql`(${nested})`
487
+ });
488
+ }
489
+ const inner = selectQuery(query2);
490
+ return query2.orderBy || query2.limit !== void 0 || query2.offset !== void 0 ? sql`(${inner})` : inner;
491
+ };
284
492
  const segments = sql.join(
285
493
  select.map((segment, i) => {
286
494
  if (i === 0) {
287
495
  fields = querySelection(segment).fieldNames();
288
- return selectQuery(segment);
496
+ return segmentQuery(segment);
289
497
  }
290
498
  const op = Object.keys(segment)[0];
291
499
  const query2 = segment[op];
292
- const names = querySelection(query2).fieldNames();
500
+ const names = querySelection(firstSelect(query2)).fieldNames();
501
+ if (fields.length !== names.length)
502
+ throw new Error("Union segments must have the same fields");
293
503
  for (let i2 = 0; i2 < fields.length; i2++)
294
504
  if (fields[i2] !== names[i2])
295
505
  throw new Error("Union segments must have the same fields");
296
- return sql.query({ [op]: selectQuery(query2) });
506
+ return sql.query({ [op]: segmentQuery(query2) });
297
507
  })
298
508
  );
299
509
  return sql.query(formatCTE(query), segments, formatModifiers(query));
@@ -1,3 +1,4 @@
1
+ import type { Selection } from '../Selection.js';
1
2
  import { type Sql } from '../Sql.js';
2
3
  import type { ResultModifiers } from './Query.js';
3
- export declare function formatModifiers(modifiers: ResultModifiers): Sql | undefined;
4
+ export declare function formatModifiers(modifiers: ResultModifiers, selected?: Selection): Sql | undefined;
@@ -1,20 +1,23 @@
1
1
  // src/core/query/Shared.ts
2
+ import { input } from "../expr/Input.js";
2
3
  import { getSql } from "../Internal.js";
3
4
  import { sql } from "../Sql.js";
4
- import { input } from "../expr/Input.js";
5
- function formatModifiers(modifiers) {
5
+ function formatModifiers(modifiers, selected) {
6
6
  const { orderBy, limit, offset } = modifiers;
7
- if (!orderBy && limit === void 0 && offset === void 0) return void 0;
7
+ const normalizedLimit = typeof limit === "number" && limit < 0 ? void 0 : limit;
8
+ if (!orderBy && normalizedLimit === void 0 && offset === void 0)
9
+ return void 0;
8
10
  return sql.query({
9
11
  orderBy: orderBy && sql.join(
10
12
  orderBy.map((part) => {
11
- const { alias } = getSql(part);
13
+ const inner = getSql(part);
14
+ const alias = selected?.aliasOf(part) ?? inner.alias;
12
15
  if (alias) return sql.identifier(alias);
13
16
  return part;
14
17
  }),
15
18
  sql`, `
16
19
  ),
17
- limit: limit !== void 0 && input(limit),
20
+ limit: normalizedLimit !== void 0 && input(normalizedLimit),
18
21
  offset: offset !== void 0 && input(offset)
19
22
  });
20
23
  }
@@ -1,24 +1,24 @@
1
+ import { type Input as UserInput } from '../expr/Input.js';
1
2
  import { type HasQuery, type HasSql, internalData, internalQuery, internalSelection } from '../Internal.js';
2
3
  import type { IsPostgres, IsSqlite, QueryMeta } from '../MetaData.js';
3
4
  import { type QueryData, SingleQuery } from '../Queries.js';
4
5
  import { type Selection, type SelectionInput, type SelectionRow } from '../Selection.js';
5
6
  import { type Sql } from '../Sql.js';
6
- import type { TableDefinition, TableRow, TableUpdate } from '../Table.js';
7
- import { type Input } from '../expr/Input.js';
7
+ import type { TableDefinition, TableFields, TableUpdate } from '../Table.js';
8
8
  import type { UpdateQuery } from './Query.js';
9
- export declare class Update<Result, Meta extends QueryMeta = QueryMeta> extends SingleQuery<Array<Result>, Meta> implements HasQuery<Result> {
9
+ export declare class Update<Input, Meta extends QueryMeta = QueryMeta> extends SingleQuery<Array<SelectionRow<Input>>, Meta> implements HasQuery<Array<SelectionRow<Input>>> {
10
10
  readonly [internalData]: QueryData<Meta> & UpdateQuery;
11
11
  readonly [internalSelection]?: Selection;
12
12
  constructor(data: QueryData<Meta> & UpdateQuery);
13
- get [internalQuery](): Sql<Result>;
14
- limit(limit: Input<number>): Update<Result, Meta>;
15
- offset(offset: Input<number>): Update<Result, Meta>;
16
- orderBy(...orderBy: Array<HasSql>): Update<Result, Meta>;
13
+ get [internalQuery](): Sql<Array<SelectionRow<Input>>>;
14
+ limit(limit: UserInput<number>): Update<Input, Meta>;
15
+ offset(offset: UserInput<number>): Update<Input, Meta>;
16
+ orderBy(...orderBy: Array<HasSql>): Update<Input, Meta>;
17
17
  }
18
18
  export declare class UpdateTable<Definition extends TableDefinition, Meta extends QueryMeta> extends Update<void, Meta> {
19
19
  set(set: TableUpdate<Definition>): UpdateTable<Definition, Meta>;
20
20
  where(...where: Array<HasSql<boolean> | undefined>): UpdateTable<Definition, Meta>;
21
- returning(this: UpdateTable<Definition, IsPostgres | IsSqlite>): Update<TableRow<Definition>, Meta>;
22
- returning<Input extends SelectionInput>(this: UpdateTable<Definition, IsPostgres | IsSqlite>, returning?: Input): Update<SelectionRow<Input>, Meta>;
21
+ returning(this: UpdateTable<Definition, IsPostgres | IsSqlite>): Update<TableFields<Definition>, Meta>;
22
+ returning<Input extends SelectionInput>(this: UpdateTable<Definition, IsPostgres | IsSqlite>, returning?: Input): Update<Input, Meta>;
23
23
  }
24
24
  export declare function updateQuery(query: UpdateQuery): Sql;
@@ -1,4 +1,6 @@
1
1
  // src/core/query/Update.ts
2
+ import { and } from "../expr/Conditions.js";
3
+ import { mapToColumn } from "../expr/Input.js";
2
4
  import {
3
5
  getData,
4
6
  getTable,
@@ -11,8 +13,6 @@ import {
11
13
  selection
12
14
  } from "../Selection.js";
13
15
  import { sql } from "../Sql.js";
14
- import { and } from "../expr/Conditions.js";
15
- import { mapToColumn } from "../expr/Input.js";
16
16
  import { formatCTE } from "./CTE.js";
17
17
  import { formatModifiers } from "./Shared.js";
18
18
  var Update = class _Update extends SingleQuery {
@@ -37,7 +37,17 @@ var Update = class _Update extends SingleQuery {
37
37
  };
38
38
  var UpdateTable = class _UpdateTable extends Update {
39
39
  set(set) {
40
- return new _UpdateTable({ ...getData(this), set });
40
+ const data = getData(this);
41
+ const hasDefinedValue = Object.values(set).some(
42
+ (value) => value !== void 0
43
+ );
44
+ if (!hasDefinedValue) {
45
+ const hasOnUpdate = Object.values(getTable(data.update).columns).some(
46
+ (column) => !!getData(column).$onUpdate
47
+ );
48
+ if (!hasOnUpdate) throw new Error("No values to set");
49
+ }
50
+ return new _UpdateTable({ ...data, set });
41
51
  }
42
52
  where(...where) {
43
53
  return new _UpdateTable({
@@ -54,26 +64,28 @@ function updateQuery(query) {
54
64
  const { update: table, set: values, where, returning } = query;
55
65
  const tableApi = getTable(table);
56
66
  if (!values) throw new Error("Update values are required");
57
- const set = sql.join(
58
- Object.entries(tableApi.columns).map(([key, column]) => {
67
+ const assignments = Object.entries(tableApi.columns).flatMap(
68
+ ([key, column]) => {
59
69
  const columnApi = getData(column);
60
70
  const { name, $onUpdate } = columnApi;
71
+ const value = values[key];
61
72
  let expr;
62
- if (!(key in values)) {
73
+ if (value === void 0) {
63
74
  if ($onUpdate) expr = $onUpdate();
64
- else return;
75
+ else return [];
65
76
  } else {
66
- expr = mapToColumn(columnApi, values[key]);
77
+ expr = mapToColumn(columnApi, value);
67
78
  }
68
79
  const fieldName = name ?? key;
69
- return sql`${sql.identifier(fieldName)} = ${expr}`;
70
- }),
71
- sql`, `
80
+ return [sql`${sql.identifier(fieldName)} = ${expr}`];
81
+ }
72
82
  );
83
+ if (assignments.length === 0) throw new Error("No values to set");
84
+ const set = sql.join(assignments, sql`, `);
73
85
  return sql.query(
74
86
  formatCTE(query),
75
87
  {
76
- update: sql.identifier(tableApi.name),
88
+ update: tableApi.identifier(),
77
89
  set,
78
90
  where,
79
91
  returning: returning && selection(returning)
@@ -8,6 +8,8 @@ var PreparedStatement = class {
8
8
  this.stmt = stmt;
9
9
  this.isSelection = isSelection;
10
10
  }
11
+ stmt;
12
+ isSelection;
11
13
  all(params) {
12
14
  return this.stmt.all(...params);
13
15
  }
@@ -31,6 +33,8 @@ var BetterSqlite3Driver = class _BetterSqlite3Driver {
31
33
  this.client = client;
32
34
  this.depth = depth;
33
35
  }
36
+ client;
37
+ depth;
34
38
  parsesJson = false;
35
39
  supportsTransactions = true;
36
40
  exec(query) {
@@ -7,6 +7,7 @@ var PreparedStatement = class {
7
7
  constructor(stmt) {
8
8
  this.stmt = stmt;
9
9
  }
10
+ stmt;
10
11
  all(params) {
11
12
  return this.stmt.all(...params);
12
13
  }
@@ -28,6 +29,8 @@ var BunSqliteDriver = class _BunSqliteDriver {
28
29
  this.client = client;
29
30
  this.depth = depth;
30
31
  }
32
+ client;
33
+ depth;
31
34
  parsesJson = false;
32
35
  supportsTransactions = true;
33
36
  exec(query) {
package/dist/driver/d1.js CHANGED
@@ -7,6 +7,8 @@ var PreparedStatement = class {
7
7
  this.stmt = stmt;
8
8
  this.isSelection = isSelection;
9
9
  }
10
+ stmt;
11
+ isSelection;
10
12
  async all(params) {
11
13
  return this.stmt.bind(...params).all().then(({ results }) => results);
12
14
  }
@@ -28,6 +30,7 @@ var D1Driver = class {
28
30
  constructor(client) {
29
31
  this.client = client;
30
32
  }
33
+ client;
31
34
  parsesJson = false;
32
35
  supportsTransactions = false;
33
36
  async exec(query) {
@@ -7,6 +7,8 @@ var PreparedStatement = class {
7
7
  this.client = client;
8
8
  this.sql = sql;
9
9
  }
10
+ client;
11
+ sql;
10
12
  async all(params) {
11
13
  const result = await this.client.execute({ sql: this.sql, args: params });
12
14
  return result.rows;
@@ -29,6 +31,8 @@ var LibSQLClient = class _LibSQLClient {
29
31
  this.client = client;
30
32
  this.depth = depth;
31
33
  }
34
+ client;
35
+ depth;
32
36
  parsesJson = false;
33
37
  supportsTransactions = true;
34
38
  async exec(query) {
@@ -9,6 +9,9 @@ var PreparedStatement = class {
9
9
  this.sql = sql;
10
10
  this.name = name;
11
11
  }
12
+ client;
13
+ sql;
14
+ name;
12
15
  #transformParam = (param) => {
13
16
  if (param instanceof Uint8Array) return Buffer.from(param);
14
17
  return param;
@@ -37,6 +40,8 @@ var Mysql2Driver = class _Mysql2Driver {
37
40
  this.client = client;
38
41
  this.depth = depth;
39
42
  }
43
+ client;
44
+ depth;
40
45
  parsesJson = true;
41
46
  supportsTransactions = true;
42
47
  async exec(query) {
@@ -2,6 +2,22 @@ import type { Client, Pool, PoolClient } from 'pg';
2
2
  import { AsyncDatabase, type TransactionOptions } from '../core/Database.js';
3
3
  import type { AsyncDriver, AsyncStatement, BatchedQuery, PrepareOptions } from '../core/Driver.js';
4
4
  type Queryable = Client | Pool | PoolClient;
5
+ /**
6
+ * The query interface used by the driver. Packages providing a pg-compatible
7
+ * client, such as @vercel/postgres and @neondatabase/serverless, ship their
8
+ * own copy of the pg types which are not directly assignable to pg's. They
9
+ * are accepted through this minimal structural interface instead.
10
+ */
11
+ export interface PgCompatible {
12
+ query(queryConfig: {
13
+ name?: string;
14
+ text: string;
15
+ values?: Array<unknown>;
16
+ rowMode?: string;
17
+ }): Promise<{
18
+ rows: Array<any>;
19
+ }>;
20
+ }
5
21
  declare class PreparedStatement implements AsyncStatement {
6
22
  private client;
7
23
  private sql;
@@ -25,5 +41,5 @@ export declare class PgDriver implements AsyncDriver {
25
41
  batch(queries: Array<BatchedQuery>): Promise<Array<Array<unknown>>>;
26
42
  transaction<T>(run: (inner: AsyncDriver) => Promise<T>, options: TransactionOptions['postgres']): Promise<T>;
27
43
  }
28
- export declare function connect(client: Queryable): AsyncDatabase<'postgres'>;
44
+ export declare function connect(client: PgCompatible): AsyncDatabase<'postgres'>;
29
45
  export {};