rado 0.1.28 → 0.1.30

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.
@@ -4,17 +4,7 @@ import { BinOp, Expr, ExprData, ExprType, UnOp } from "./Expr.js";
4
4
  import { OrderDirection } from "./OrderBy.js";
5
5
  import { ParamType } from "./Param.js";
6
6
  import { Query, QueryType } from "./Query.js";
7
- import {
8
- Statement,
9
- call,
10
- identifier,
11
- newline,
12
- param,
13
- parenthesis,
14
- raw,
15
- separated,
16
- value
17
- } from "./Statement.js";
7
+ import { Statement } from "./Statement.js";
18
8
  import { Target, TargetType } from "./Target.js";
19
9
  var binOps = {
20
10
  [BinOp.Add]: "+",
@@ -44,281 +34,386 @@ var joins = {
44
34
  var Formatter = class {
45
35
  constructor() {
46
36
  }
47
- formatAccess(on, field, formatAsJson) {
48
- return formatAsJson ? this.formatJsonAccess(on, field) : this.formatSqlAccess(on, field);
49
- }
50
37
  compile(query, formatInline = false) {
51
- const result = this.format(query, {
52
- formatSubject: (select) => call("json_object", raw("'result'"), select),
53
- nameResult: "result"
54
- }).compile(this, formatInline);
38
+ const stmt = new Statement();
39
+ const result = this.format(
40
+ {
41
+ stmt,
42
+ formatSubject: (mkSubject) => {
43
+ stmt.raw("json_object('result', ");
44
+ mkSubject();
45
+ stmt.raw(")");
46
+ },
47
+ nameResult: "result"
48
+ },
49
+ query
50
+ ).compile(this, formatInline);
55
51
  return result;
56
52
  }
57
- format(query, ctx = {}) {
53
+ format(ctx, query) {
58
54
  switch (query.type) {
59
55
  case QueryType.Select:
60
- return this.formatSelect(query, ctx);
56
+ return this.formatSelect(ctx, query);
61
57
  case QueryType.Insert:
62
- return this.formatInsert(query, ctx);
58
+ return this.formatInsert(ctx, query);
63
59
  case QueryType.Update:
64
- return this.formatUpdate(query, ctx);
60
+ return this.formatUpdate(ctx, query);
65
61
  case QueryType.Delete:
66
- return this.formatDelete(query, ctx);
62
+ return this.formatDelete(ctx, query);
67
63
  case QueryType.CreateTable:
68
- return this.formatCreateTable(query, ctx);
64
+ return this.formatCreateTable(ctx, query);
69
65
  case QueryType.CreateIndex:
70
- return this.formatCreateIndex(query, ctx);
66
+ return this.formatCreateIndex(ctx, query);
71
67
  case QueryType.DropIndex:
72
- return this.formatDropIndex(query, ctx);
68
+ return this.formatDropIndex(ctx, query);
73
69
  case QueryType.AlterTable:
74
- return this.formatAlterTable(query, ctx);
70
+ return this.formatAlterTable(ctx, query);
75
71
  case QueryType.Transaction:
76
- return this.formatTransaction(query, ctx);
72
+ return this.formatTransaction(ctx, query);
77
73
  case QueryType.Batch:
78
- return this.formatBatch(query.queries, ctx);
74
+ return this.formatBatch(ctx, query.queries);
79
75
  case QueryType.Raw:
80
- return this.formatRaw(query, ctx);
76
+ return this.formatRaw(ctx, query);
81
77
  }
82
78
  }
83
- formatSelect(query, ctx) {
84
- return raw("SELECT").add(this.formatSelection(query.selection, ctx)).addLine("FROM").add(this.formatTarget(query.from, ctx)).add(this.formatWhere(query.where, ctx)).add(this.formatGroupBy(query.groupBy, ctx)).add(this.formatHaving(query.having, ctx)).add(this.formatOrderBy(query.orderBy, ctx)).add(this.formatLimit(query, ctx));
79
+ formatSelect(ctx, query) {
80
+ const { stmt } = ctx;
81
+ stmt.add("SELECT").space();
82
+ this.formatSelection(ctx, query.selection);
83
+ stmt.addLine("FROM").space();
84
+ this.formatTarget(ctx, query.from);
85
+ this.formatWhere(ctx, query.where);
86
+ this.formatGroupBy(ctx, query.groupBy);
87
+ this.formatHaving(ctx, query.having);
88
+ this.formatOrderBy(ctx, query.orderBy);
89
+ this.formatLimit(ctx, query);
90
+ return stmt;
85
91
  }
86
- formatInsert(query, ctx) {
92
+ formatInsert(ctx, query) {
93
+ const { stmt } = ctx;
87
94
  const columns = Object.values(query.into.columns);
88
- return raw("INSERT INTO").addIdentifier(query.into.name).addIf(query.into.alias, () => raw("AS").addIdentifier(query.into.alias)).parenthesis(
89
- separated(columns.map((column) => this.formatString(column.name)))
90
- ).add("VALUES").addSeparated(
91
- query.data.map((row) => this.formatInsertRow(query.into.columns, row))
92
- ).addIf(
93
- query.selection,
94
- () => raw("RETURNING").add(this.formatSelection(query.selection, ctx))
95
- );
95
+ stmt.add("INSERT INTO").addIdentifier(query.into.name);
96
+ if (query.into.alias)
97
+ stmt.raw("AS").addIdentifier(query.into.alias);
98
+ for (const column of stmt.call(columns))
99
+ this.formatString(ctx, column.name);
100
+ stmt.add("VALUES");
101
+ for (const row of stmt.separate(query.data))
102
+ this.formatInsertRow(ctx, query.into.columns, row);
103
+ if (query.selection) {
104
+ stmt.add("RETURNING").space();
105
+ this.formatSelection(ctx, query.selection);
106
+ }
107
+ return stmt;
96
108
  }
97
- formatUpdate(query, ctx) {
109
+ formatUpdate(ctx, query) {
110
+ const { stmt } = ctx;
98
111
  const data = query.set || {};
99
- return raw("UPDATE").addIdentifier(query.table.name).add("SET").addSeparated(
100
- Object.keys(data).map((key) => {
101
- const column = query.table.columns[key];
102
- const exprData = data[key];
103
- return identifier(key).add("=").add(
104
- this.formatExpr(ExprData.create(data[key]), {
105
- ...ctx,
106
- formatAsJson: true
107
- })
108
- );
109
- })
110
- ).add(this.formatWhere(query.where, ctx)).add(this.formatLimit(query, ctx));
111
- }
112
- formatDelete(query, ctx) {
113
- return raw("DELETE FROM").addIdentifier(query.table.name).add(this.formatWhere(query.where, ctx)).add(this.formatLimit(query, ctx));
114
- }
115
- formatCreateTable(query, ctx) {
116
- return raw("CREATE TABLE").addIf(query.ifNotExists, "IF NOT EXISTS").addCall(
117
- query.table.name,
118
- ...Object.values(query.table.columns).map((column) => {
119
- return this.formatColumn(column);
120
- })
121
- );
112
+ stmt.add("UPDATE").addIdentifier(query.table.name).add("SET").space();
113
+ for (const key of stmt.separate(Object.keys(data))) {
114
+ stmt.identifier(key).add("=").space();
115
+ this.formatExpr(
116
+ {
117
+ ...ctx,
118
+ formatAsJson: true
119
+ },
120
+ ExprData.create(data[key])
121
+ );
122
+ }
123
+ this.formatWhere(ctx, query.where);
124
+ this.formatLimit(ctx, query);
125
+ return stmt;
126
+ }
127
+ formatDelete(ctx, query) {
128
+ const { stmt } = ctx;
129
+ stmt.add("DELETE FROM").addIdentifier(query.table.name);
130
+ stmt.space();
131
+ this.formatWhere(ctx, query.where);
132
+ stmt.space();
133
+ this.formatLimit(ctx, query);
134
+ return stmt;
122
135
  }
123
- formatCreateIndex(query, ctx = {}) {
124
- return raw("CREATE").addIf(query.index.unique, "UNIQUE").add("INDEX").addIf(query.ifNotExists, "IF NOT EXISTS").addIdentifier(query.index.name).add("ON").addIdentifier(query.table.name).parenthesis(
125
- separated(
126
- query.index.on.map(
127
- (expr) => this.formatExprValue(expr, {
128
- ...ctx,
129
- skipTableName: true,
130
- forceInline: true
131
- })
132
- )
133
- )
134
- ).add(this.formatWhere(query.where, ctx));
135
- }
136
- formatDropIndex(query, ctx) {
137
- return raw("DROP INDEX").addIf(query.ifExists, "IF EXISTS").addIdentifier(query.name);
138
- }
139
- formatAlterTable(query, ctx) {
140
- let stmt = raw("ALTER TABLE").addIdentifier(query.table.name);
136
+ formatCreateTable(ctx, query) {
137
+ const { stmt } = ctx;
138
+ stmt.add("CREATE TABLE");
139
+ if (query.ifNotExists)
140
+ stmt.add("IF NOT EXISTS");
141
+ stmt.addIdentifier(query.table.name);
142
+ for (const column of stmt.call(Object.values(query.table.columns))) {
143
+ this.formatColumn(ctx, column);
144
+ }
145
+ return stmt;
146
+ }
147
+ formatCreateIndex(ctx, query) {
148
+ const { stmt } = ctx;
149
+ stmt.add("CREATE");
150
+ if (query.index.unique)
151
+ stmt.add("UNIQUE");
152
+ stmt.add("INDEX");
153
+ if (query.ifNotExists)
154
+ stmt.add("IF NOT EXISTS");
155
+ stmt.addIdentifier(query.index.name).add("ON").addIdentifier(query.table.name);
156
+ for (const expr of stmt.call(query.index.on)) {
157
+ this.formatExprValue(
158
+ {
159
+ ...ctx,
160
+ skipTableName: true,
161
+ forceInline: true
162
+ },
163
+ expr
164
+ );
165
+ }
166
+ this.formatWhere(ctx, query.where);
167
+ return stmt;
168
+ }
169
+ formatDropIndex(ctx, query) {
170
+ const { stmt } = ctx;
171
+ stmt.add("DROP INDEX");
172
+ if (query.ifExists)
173
+ stmt.add("IF EXISTS");
174
+ stmt.addIdentifier(query.name);
175
+ return stmt;
176
+ }
177
+ formatAlterTable(ctx, query) {
178
+ const { stmt } = ctx;
179
+ stmt.add("ALTER TABLE").addIdentifier(query.table.name);
141
180
  if (query.addColumn) {
142
- stmt = stmt.add("ADD COLUMN").add(this.formatColumn(query.addColumn));
181
+ stmt.add("ADD COLUMN");
182
+ this.formatColumn(ctx, query.addColumn);
143
183
  } else if (query.dropColumn) {
144
- stmt = stmt.add("DROP COLUMN").addIdentifier(query.dropColumn);
184
+ stmt.add("DROP COLUMN").addIdentifier(query.dropColumn);
145
185
  } else if (query.alterColumn) {
146
186
  throw new Error(`Not available in this formatter: alter column`);
147
187
  }
148
188
  return stmt;
149
189
  }
150
- formatTransaction({ op, id }, ctx) {
190
+ formatTransaction(ctx, { op, id }) {
191
+ const { stmt } = ctx;
151
192
  switch (op) {
152
193
  case Query.TransactionOperation.Begin:
153
- return raw("SAVEPOINT").addIdentifier(id);
194
+ return stmt.raw("SAVEPOINT").addIdentifier(id);
154
195
  case Query.TransactionOperation.Commit:
155
- return raw("RELEASE").addIdentifier(id);
196
+ return stmt.raw("RELEASE").addIdentifier(id);
156
197
  case Query.TransactionOperation.Rollback:
157
- return raw("ROLLBACK TO").addIdentifier(id);
198
+ return stmt.raw("ROLLBACK TO").addIdentifier(id);
158
199
  }
159
200
  }
160
- formatBatch(queries, ctx) {
161
- return separated(
162
- queries.map((query) => this.format(query, ctx)),
163
- "; "
164
- );
201
+ formatBatch(ctx, queries) {
202
+ const { stmt } = ctx;
203
+ for (const query of stmt.separate(queries, ";"))
204
+ this.format(ctx, query);
205
+ return stmt;
165
206
  }
166
- formatRaw({ strings, params }, ctx) {
167
- return Statement.tag(
168
- strings,
169
- params.map((param2) => {
170
- if (param2 instanceof Expr)
171
- return this.formatExpr(param2.expr, ctx);
172
- return this.formatValue(param2, ctx);
173
- })
174
- );
207
+ formatRaw(ctx, { strings, params }) {
208
+ const { stmt } = ctx;
209
+ for (let i = 0; i < strings.length; i++) {
210
+ ctx.stmt.raw(strings[i]);
211
+ if (i < params.length) {
212
+ const param = params[i];
213
+ if (param instanceof Expr)
214
+ this.formatExpr(ctx, param.expr);
215
+ else
216
+ this.formatValue(ctx, param);
217
+ }
218
+ }
219
+ return stmt;
175
220
  }
176
- formatColumn(column) {
177
- return identifier(column.name).add(this.formatType(column.type)).addIf(column.unique, "UNIQUE").addIf(column.autoIncrement, "AUTOINCREMENT").addIf(column.primaryKey, "PRIMARY KEY").addIf(!column.nullable, "NOT NULL").addIf(
178
- column.defaultValue,
179
- () => raw("DEFAULT").addParenthesis(
180
- this.formatExpr(column.defaultValue, {
221
+ formatColumn(ctx, column) {
222
+ const { stmt } = ctx;
223
+ stmt.identifier(column.name).space();
224
+ this.formatType(ctx, column.type);
225
+ if (column.unique)
226
+ stmt.add("UNIQUE");
227
+ if (column.autoIncrement)
228
+ stmt.add("AUTOINCREMENT");
229
+ if (column.primaryKey)
230
+ stmt.add("PRIMARY KEY");
231
+ if (!column.nullable)
232
+ stmt.add("NOT NULL");
233
+ if (column.defaultValue !== void 0) {
234
+ stmt.add("DEFAULT").space();
235
+ stmt.openParenthesis();
236
+ this.formatExpr(
237
+ {
238
+ ...ctx,
181
239
  formatAsJson: true,
182
240
  forceInline: true
183
- })
184
- )
185
- ).addIf(column.references, () => {
186
- return this.formatContraintReference(column.references);
187
- });
241
+ },
242
+ column.defaultValue
243
+ );
244
+ stmt.closeParenthesis();
245
+ }
246
+ if (column.references)
247
+ this.formatContraintReference(ctx, column.references);
248
+ return stmt;
188
249
  }
189
- formatContraintReference(reference) {
250
+ formatContraintReference(ctx, reference) {
251
+ const { stmt } = ctx;
190
252
  if (reference.type !== ExprType.Field || reference.expr.type !== ExprType.Row)
191
253
  throw new Error("not supported");
192
254
  const from = reference.expr.target;
193
- return raw("REFERENCES").addIdentifier(Target.source(from).name).parenthesis(identifier(reference.field));
255
+ return stmt.add("REFERENCES").addIdentifier(Target.source(from).name).openParenthesis().identifier(reference.field).closeParenthesis();
194
256
  }
195
- formatType(type) {
257
+ formatType(ctx, type) {
258
+ const { stmt } = ctx;
196
259
  switch (type) {
197
260
  case ColumnType.String:
198
- return raw("TEXT");
261
+ return stmt.raw("TEXT");
199
262
  case ColumnType.Json:
200
- return raw("JSON");
263
+ return stmt.raw("JSON");
201
264
  case ColumnType.Number:
202
- return raw("NUMERIC");
265
+ return stmt.raw("NUMERIC");
203
266
  case ColumnType.Boolean:
204
- return raw("BOOLEAN");
267
+ return stmt.raw("BOOLEAN");
205
268
  case ColumnType.Integer:
206
- return raw("INTEGER");
269
+ return stmt.raw("INTEGER");
207
270
  }
208
271
  }
209
- formatInsertRow(columns, row) {
210
- return parenthesis(
211
- separated(
212
- Object.entries(columns).map(([property, column]) => {
213
- const columnValue = row[property];
214
- return this.formatColumnValue(column, columnValue);
215
- })
216
- )
217
- );
272
+ formatInsertRow(ctx, columns, row) {
273
+ const { stmt } = ctx;
274
+ for (const [property, column] of stmt.call(Object.entries(columns))) {
275
+ const columnValue = row[property];
276
+ this.formatColumnValue(ctx, column, columnValue);
277
+ }
278
+ return stmt;
218
279
  }
219
- formatColumnValue(column, columnValue) {
280
+ formatColumnValue(ctx, column, columnValue) {
281
+ const { stmt } = ctx;
220
282
  if (columnValue instanceof Expr)
221
- return this.formatExprValue(columnValue.expr, {});
283
+ return this.formatExprValue(ctx, columnValue.expr);
222
284
  const isNull = columnValue === void 0 || columnValue === null;
223
285
  const isOptional = column.nullable || column.autoIncrement || column.primaryKey;
224
286
  if (isNull) {
225
287
  if (column.defaultValue !== void 0)
226
- return this.formatExpr(column.defaultValue, { formatAsJson: true });
288
+ return this.formatExprJson(ctx, column.defaultValue);
227
289
  if (!isOptional)
228
290
  throw new TypeError(`Expected value for column ${column.name}`);
229
- return raw("NULL");
291
+ return stmt.raw("NULL");
230
292
  }
231
293
  switch (column.type) {
232
294
  case ColumnType.String:
233
295
  if (typeof columnValue !== "string")
234
296
  throw new TypeError(`Expected string for column ${column.name}`);
235
- return value(columnValue);
297
+ return stmt.value(columnValue);
236
298
  case ColumnType.Integer:
237
299
  case ColumnType.Number:
238
300
  if (typeof columnValue !== "number")
239
301
  throw new TypeError(`Expected number for column ${column.name}`);
240
- return value(columnValue);
302
+ return stmt.value(columnValue);
241
303
  case ColumnType.Boolean:
242
304
  if (typeof columnValue !== "boolean")
243
305
  throw new TypeError(`Expected boolean for column ${column.name}`);
244
- return raw(this.escapeValue(columnValue));
306
+ return stmt.raw(this.escapeValue(columnValue));
245
307
  case ColumnType.Json:
246
308
  if (typeof columnValue !== "object")
247
309
  throw new TypeError(`Expected object for column ${column.name}`);
248
- return value(JSON.stringify(columnValue));
310
+ return stmt.value(JSON.stringify(columnValue));
249
311
  }
250
312
  }
251
- formatTarget(target, ctx) {
313
+ formatTarget(ctx, target) {
314
+ const { stmt } = ctx;
252
315
  switch (target.type) {
253
316
  case TargetType.Table:
254
- return identifier(target.table.name).addIf(
255
- target.table.alias,
256
- () => raw("AS").addIdentifier(target.table.alias)
257
- );
317
+ stmt.identifier(target.table.name);
318
+ if (target.table.alias)
319
+ stmt.add("AS").addIdentifier(target.table.alias);
320
+ return stmt;
258
321
  case TargetType.Join:
259
322
  const { left, right, joinType } = target;
260
- return this.formatTarget(left, ctx).addLine(joins[joinType]).add("JOIN").add(this.formatTarget(right, ctx)).add("ON").add(this.formatExprValue(target.on, ctx));
323
+ this.formatTarget(ctx, left);
324
+ stmt.addLine(joins[joinType]).add("JOIN");
325
+ this.formatTarget(ctx, right);
326
+ stmt.add("ON");
327
+ this.formatExprValue(ctx, target.on);
328
+ return stmt;
261
329
  default:
262
330
  throw new Error(`Cannot format target of type ${target.type}`);
263
331
  }
264
332
  }
265
- formatWhere(expr, ctx) {
333
+ formatWhere(ctx, expr) {
334
+ const { stmt } = ctx;
266
335
  if (!expr)
267
- return;
268
- return newline().raw("WHERE").add(this.formatExprValue(expr, ctx));
336
+ return stmt;
337
+ stmt.newline().raw("WHERE");
338
+ this.formatExprValue(ctx, expr);
339
+ return stmt;
269
340
  }
270
- formatHaving(expr, ctx) {
341
+ formatHaving(ctx, expr) {
342
+ const { stmt } = ctx;
271
343
  if (!expr)
272
- return;
273
- return newline().raw("HAVING").add(this.formatExprValue(expr, ctx));
344
+ return stmt;
345
+ stmt.newline().raw("HAVING");
346
+ this.formatExprValue(ctx, expr);
347
+ return stmt;
274
348
  }
275
- formatGroupBy(groupBy, ctx) {
349
+ formatGroupBy(ctx, groupBy) {
350
+ const { stmt } = ctx;
276
351
  if (!groupBy)
277
- return;
278
- return newline().raw("GROUP BY").addSeparated(groupBy.map((expr) => this.formatExprValue(expr, ctx)));
352
+ return stmt;
353
+ stmt.newline().raw("GROUP BY");
354
+ for (const expr of stmt.separate(groupBy))
355
+ this.formatExprValue(ctx, expr);
356
+ return stmt;
279
357
  }
280
- formatOrderBy(orderBy, ctx) {
358
+ formatOrderBy(ctx, orderBy) {
359
+ const { stmt } = ctx;
281
360
  if (!orderBy)
282
- return;
283
- return newline().raw("ORDER BY").addSeparated(
284
- orderBy.map(
285
- ({ expr, order }) => this.formatExprValue(expr, ctx).add(
286
- order === OrderDirection.Asc ? "ASC" : "DESC"
287
- )
288
- )
289
- );
361
+ return stmt;
362
+ stmt.newline().raw("ORDER BY");
363
+ for (const { expr, order } of stmt.separate(orderBy)) {
364
+ this.formatExprValue(ctx, expr);
365
+ stmt.add(order === OrderDirection.Asc ? "ASC" : "DESC");
366
+ }
367
+ return stmt;
290
368
  }
291
- formatLimit({ limit, offset, singleResult }, ctx) {
369
+ formatLimit(ctx, { limit, offset, singleResult }) {
370
+ const { stmt } = ctx;
292
371
  if (!limit && !offset && !singleResult)
293
- return;
294
- return newline().raw("LIMIT").addValue(singleResult ? 1 : limit).addIf(offset && offset > 0, raw("OFFSET").addValue(offset));
295
- }
296
- formatSelection(selection, ctx) {
297
- const { formatSubject } = ctx;
298
- const subject = this.formatExpr(selection, {
299
- ...ctx,
300
- formatSubject: void 0,
301
- formatAsJson: true
302
- });
303
- return (formatSubject ? formatSubject(subject) : subject).addIf(
304
- ctx.nameResult,
305
- raw("AS").addIdentifier(ctx.nameResult)
372
+ return stmt;
373
+ stmt.newline().raw("LIMIT").addValue(singleResult ? 1 : limit);
374
+ if (offset && offset > 0)
375
+ stmt.raw("OFFSET").addValue(offset);
376
+ return stmt;
377
+ }
378
+ formatSelection(ctx, selection) {
379
+ const { stmt, formatSubject } = ctx;
380
+ const mkSubject = () => this.formatExpr(
381
+ {
382
+ ...ctx,
383
+ formatSubject: void 0,
384
+ formatAsJson: true
385
+ },
386
+ selection
306
387
  );
388
+ if (formatSubject)
389
+ formatSubject(mkSubject);
390
+ else
391
+ mkSubject();
392
+ if (ctx.nameResult)
393
+ stmt.add("AS").addIdentifier(ctx.nameResult);
394
+ return stmt;
395
+ }
396
+ formatExprJson(ctx, expr) {
397
+ return this.formatExpr({ ...ctx, formatAsJson: true }, expr);
307
398
  }
308
- formatExprValue(expr, ctx) {
309
- return this.formatExpr(expr, { ...ctx, formatAsJson: false });
399
+ formatExprValue(ctx, expr) {
400
+ return this.formatExpr({ ...ctx, formatAsJson: false }, expr);
310
401
  }
311
- formatIn(expr, ctx) {
402
+ formatIn(ctx, expr) {
403
+ const { stmt } = ctx;
312
404
  switch (expr.type) {
313
405
  case ExprType.Field:
314
- return this.formatUnwrapArray(this.formatExprValue(expr, ctx));
406
+ stmt.openParenthesis();
407
+ stmt.raw("SELECT value FROM json_each");
408
+ stmt.openParenthesis();
409
+ this.formatExprJson(ctx, expr);
410
+ stmt.closeParenthesis();
411
+ stmt.closeParenthesis();
412
+ return stmt;
315
413
  default:
316
- return this.formatExprValue(expr, ctx);
414
+ return this.formatExprValue(ctx, expr);
317
415
  }
318
416
  }
319
- formatUnwrapArray(stmt) {
320
- return parenthesis(raw("SELECT value FROM").addCall("json_each", stmt));
321
- }
322
417
  retrieveField(expr, field) {
323
418
  switch (expr.type) {
324
419
  case ExprType.Record:
@@ -329,123 +424,140 @@ var Formatter = class {
329
424
  return void 0;
330
425
  }
331
426
  }
332
- formatField(expr, field, ctx) {
427
+ formatField(ctx, expr, field) {
428
+ const { stmt } = ctx;
333
429
  const fieldExpr = this.retrieveField(expr, field);
334
430
  if (fieldExpr)
335
- return this.formatExpr(fieldExpr, ctx);
431
+ return this.formatExpr(ctx, fieldExpr);
336
432
  switch (expr.type) {
337
433
  case ExprType.Row:
338
434
  switch (expr.target.type) {
339
435
  case TargetType.Table:
340
- const selection = ctx.skipTableName ? identifier(field) : identifier(expr.target.table.alias || expr.target.table.name).raw(".").identifier(field);
341
436
  const column = expr.target.table.columns[field];
342
- switch (column?.type) {
343
- case ColumnType.Json:
344
- if (ctx.formatAsJson)
345
- return call("json", selection);
346
- default:
347
- return selection;
437
+ const asJson = column?.type === ColumnType.Json && ctx.formatAsJson;
438
+ if (asJson) {
439
+ stmt.add("json");
440
+ stmt.openParenthesis();
348
441
  }
442
+ if (!ctx.skipTableName) {
443
+ stmt.identifier(expr.target.table.alias || expr.target.table.name).raw(".");
444
+ }
445
+ stmt.identifier(field);
446
+ if (asJson)
447
+ stmt.closeParenthesis();
448
+ return stmt;
349
449
  }
350
450
  default:
351
- return this.formatAccess(
352
- this.formatExpr(expr, ctx),
353
- field,
354
- ctx.formatAsJson
355
- );
451
+ return this.formatAccess(ctx, () => this.formatExpr(ctx, expr), field);
356
452
  }
357
453
  }
358
- formatString(input) {
359
- return raw(this.escapeValue(String(input)));
454
+ formatString(ctx, input) {
455
+ const { stmt } = ctx;
456
+ return stmt.raw(this.escapeValue(String(input)));
360
457
  }
361
- formatInlineValue(rawValue) {
458
+ formatInlineValue(ctx, rawValue) {
459
+ const { stmt } = ctx;
362
460
  switch (true) {
363
461
  case (rawValue === null || rawValue === void 0):
364
- return raw("NULL");
462
+ return stmt.raw("NULL");
365
463
  case typeof rawValue === "boolean":
366
- return rawValue ? raw("TRUE") : raw("FALSE");
464
+ return rawValue ? stmt.raw("TRUE") : stmt.raw("FALSE");
367
465
  case (typeof rawValue === "string" || typeof rawValue === "number"):
368
- return this.formatString(rawValue);
466
+ return this.formatString(ctx, rawValue);
369
467
  default:
370
- return this.formatString(JSON.stringify(rawValue));
468
+ return this.formatString(ctx, JSON.stringify(rawValue));
371
469
  }
372
470
  }
373
- formatValue(rawValue, ctx) {
374
- const { formatAsJson, forceInline } = ctx;
471
+ formatValue(ctx, rawValue) {
472
+ const { stmt, formatAsJson, forceInline } = ctx;
375
473
  switch (true) {
376
474
  case (rawValue === null || rawValue === void 0):
377
- return raw("NULL");
475
+ return stmt.raw("NULL");
378
476
  case (!formatAsJson && typeof rawValue === "boolean"):
379
- return rawValue ? raw("1") : raw("0");
477
+ return rawValue ? stmt.raw("1") : stmt.raw("0");
380
478
  case Array.isArray(rawValue):
381
- const res = parenthesis(
382
- separated(
383
- rawValue.map(
384
- (v) => this.formatValue(v, { ...ctx, formatAsJson: false })
385
- )
386
- )
387
- );
388
- return formatAsJson ? raw("json_array").concat(res) : res;
479
+ if (formatAsJson) {
480
+ stmt.raw("json_array");
481
+ stmt.openParenthesis();
482
+ }
483
+ for (const v of stmt.separate(rawValue))
484
+ this.formatValue({ ...ctx, formatAsJson: false }, v);
485
+ if (formatAsJson)
486
+ stmt.closeParenthesis();
487
+ return stmt;
389
488
  case (typeof rawValue === "string" || typeof rawValue === "number"):
390
489
  if (forceInline)
391
- return raw(this.escapeValue(rawValue));
392
- return value(rawValue);
490
+ return stmt.raw(this.escapeValue(rawValue));
491
+ return stmt.value(rawValue);
393
492
  default:
394
- const expr = this.formatString(JSON.stringify(rawValue));
493
+ if (formatAsJson) {
494
+ stmt.raw("json");
495
+ stmt.openParenthesis();
496
+ }
497
+ this.formatString(ctx, JSON.stringify(rawValue));
395
498
  if (formatAsJson)
396
- return call("json", expr);
397
- return expr;
499
+ stmt.closeParenthesis();
500
+ return stmt;
398
501
  }
399
502
  }
400
- formatExpr(expr, ctx) {
503
+ formatExpr(ctx, expr) {
504
+ const { stmt } = ctx;
401
505
  switch (expr.type) {
402
506
  case ExprType.UnOp:
403
507
  switch (expr.op) {
404
508
  case UnOp.IsNull:
405
- return this.formatExprValue(expr.expr, ctx).add("IS NULL");
509
+ return this.formatExprValue(ctx, expr.expr).add("IS NULL");
406
510
  case UnOp.Not:
407
- return raw("NOT").addParenthesis(
408
- this.formatExprValue(expr.expr, ctx)
409
- );
511
+ stmt.raw("NOT").openParenthesis();
512
+ this.formatExprValue(ctx, expr.expr);
513
+ return stmt.closeParenthesis();
410
514
  }
411
515
  case ExprType.BinOp:
412
- return parenthesis(
413
- this.formatExprValue(expr.a, ctx).add(binOps[expr.op]).add(
414
- expr.op === BinOp.In || expr.op === BinOp.NotIn ? this.formatIn(expr.b, ctx) : this.formatExprValue(expr.b, ctx)
415
- )
416
- );
516
+ stmt.openParenthesis();
517
+ this.formatExprValue(ctx, expr.a).add(binOps[expr.op]).space();
518
+ if (expr.op === BinOp.In || expr.op === BinOp.NotIn)
519
+ this.formatIn(ctx, expr.b);
520
+ else
521
+ this.formatExprValue(ctx, expr.b);
522
+ return stmt.closeParenthesis();
417
523
  case ExprType.Param:
418
524
  switch (expr.param.type) {
419
525
  case ParamType.Value:
420
- return this.formatValue(expr.param.value, ctx);
526
+ return this.formatValue(ctx, expr.param.value);
421
527
  case ParamType.Named:
422
- return param(expr.param.name);
528
+ return stmt.param(expr.param.name);
423
529
  }
424
530
  case ExprType.Field:
425
- return this.formatField(expr.expr, expr.field, ctx);
531
+ return this.formatField(ctx, expr.expr, expr.field);
426
532
  case ExprType.Call: {
427
533
  if (expr.method === "cast") {
428
534
  const [e, type] = expr.params;
429
535
  const typeName = type.type === ExprType.Param && type.param.type === ParamType.Value && type.param.value;
430
- return raw("cast").parenthesis(
431
- this.formatExprValue(e, ctx).add("as").add(this.formatString(typeName))
432
- );
536
+ stmt.raw("cast").openParenthesis();
537
+ this.formatExprValue(ctx, e).add("as").space();
538
+ this.formatString(ctx, typeName);
539
+ return stmt.closeParenthesis();
433
540
  } else {
434
- const params = expr.params.map(
435
- (expr2) => this.formatExprValue(expr2, ctx)
436
- );
437
- return call(expr.method, ...params);
541
+ stmt.addIdentifier(expr.method).openParenthesis();
542
+ for (const param of stmt.separate(expr.params))
543
+ this.formatExprValue(ctx, param);
544
+ return stmt.closeParenthesis();
438
545
  }
439
546
  }
440
547
  case ExprType.Query:
441
- if (!ctx.formatAsJson)
442
- return parenthesis(this.format(expr.query, ctx));
443
- const subQuery = this.format(expr.query, { ...ctx, nameResult: "result" });
444
- if (expr.query.singleResult)
445
- return call("json", parenthesis(subQuery));
446
- return parenthesis(
447
- raw("SELECT json_group_array(json(result))").newline().raw("FROM").addParenthesis(subQuery)
448
- );
548
+ if (!ctx.formatAsJson) {
549
+ stmt.openParenthesis();
550
+ this.format(ctx, expr.query);
551
+ return stmt.closeParenthesis();
552
+ }
553
+ if (expr.query.singleResult) {
554
+ stmt.raw("json").openParenthesis().openParenthesis();
555
+ this.format({ ...ctx, nameResult: "result" }, expr.query);
556
+ return stmt.closeParenthesis().closeParenthesis();
557
+ }
558
+ stmt.openParenthesis().raw("SELECT json_group_array(json(result))").newline().raw("FROM").openParenthesis();
559
+ this.format({ ...ctx, nameResult: "result" }, expr.query);
560
+ return stmt.closeParenthesis().closeParenthesis();
449
561
  case ExprType.Row:
450
562
  switch (expr.target.type) {
451
563
  case TargetType.Table:
@@ -453,6 +565,7 @@ var Formatter = class {
453
565
  if (!table)
454
566
  throw new Error(`Cannot select empty target`);
455
567
  return this.formatExpr(
568
+ ctx,
456
569
  ExprData.Record(
457
570
  Object.fromEntries(
458
571
  Object.entries(table.columns).map(([key, column]) => [
@@ -460,39 +573,35 @@ var Formatter = class {
460
573
  ExprData.Field(ExprData.Row(expr.target), column.name)
461
574
  ])
462
575
  )
463
- ),
464
- ctx
576
+ )
465
577
  );
466
578
  case TargetType.Each:
467
- return identifier(expr.target.alias).raw(".value");
579
+ return stmt.identifier(expr.target.alias).raw(".value");
468
580
  default:
469
581
  throw new Error(`Cannot select from ${expr.target.type}`);
470
582
  }
471
583
  case ExprType.Merge:
472
- return call(
473
- "json_patch",
474
- this.formatExpr(expr.a, { ...ctx, formatAsJson: true }),
475
- this.formatExpr(expr.b, { ...ctx, formatAsJson: true })
476
- );
584
+ stmt.identifier("json_patch").openParenthesis();
585
+ this.formatExpr({ ...ctx, formatAsJson: true }, expr.a);
586
+ stmt.raw(", ");
587
+ this.formatExpr({ ...ctx, formatAsJson: true }, expr.b);
588
+ return stmt.closeParenthesis();
477
589
  case ExprType.Record:
478
- return call(
479
- "json_object",
480
- ...Object.entries(expr.fields).map(([key, value2]) => {
481
- return this.formatString(key).raw(", ").concat(this.formatExpr(value2, { ...ctx, formatAsJson: true }));
482
- })
483
- );
590
+ stmt.identifier("json_object");
591
+ for (const [key, value] of stmt.call(Object.entries(expr.fields))) {
592
+ this.formatString(ctx, key).raw(", ");
593
+ this.formatExprJson(ctx, value);
594
+ }
595
+ return stmt;
484
596
  case ExprType.Filter: {
485
597
  const { target, condition } = expr;
486
598
  switch (target.type) {
487
599
  case TargetType.Each:
488
- return parenthesis(
489
- raw("SELECT json_group_array(json(result)) FROM").addParenthesis(
490
- raw("SELECT value AS result").add("FROM").addCall(
491
- "json_each",
492
- this.formatExpr(target.expr, { ...ctx, formatAsJson: true })
493
- ).add("AS").addIdentifier(target.alias).add("WHERE").add(this.formatExprValue(condition, ctx))
494
- )
495
- );
600
+ stmt.openParenthesis().raw("SELECT json_group_array(json(result)) FROM ").openParenthesis().raw("SELECT value AS result").add("FROM json_each").openParenthesis();
601
+ this.formatExpr(ctx, target.expr);
602
+ stmt.closeParenthesis().add("AS").addIdentifier(target.alias).add("WHERE").space();
603
+ this.formatExprValue(ctx, condition);
604
+ return stmt.closeParenthesis().closeParenthesis();
496
605
  default:
497
606
  throw new Error("todo");
498
607
  }
@@ -501,14 +610,10 @@ var Formatter = class {
501
610
  const { target, result } = expr;
502
611
  switch (target.type) {
503
612
  case TargetType.Each:
504
- return parenthesis(
505
- raw("SELECT json_group_array(json(result)) FROM").addParenthesis(
506
- raw("SELECT").add(this.formatExpr(result, { ...ctx, formatAsJson: true })).add("AS").addIdentifier("result").add("FROM").addCall(
507
- "json_each",
508
- this.formatExpr(target.expr, { ...ctx, formatAsJson: true })
509
- ).add("AS").addIdentifier(target.alias)
510
- )
511
- );
613
+ stmt.openParenthesis().raw("SELECT json_group_array(json(result)) FROM ").openParenthesis().raw("SELECT").space();
614
+ this.formatExprJson(ctx, result).add("AS result").add("FROM json_each").openParenthesis();
615
+ this.formatExprJson(ctx, target.expr);
616
+ return stmt.closeParenthesis().add("AS").addIdentifier(target.alias).closeParenthesis().closeParenthesis();
512
617
  default:
513
618
  throw new Error("todo");
514
619
  }