pgsql-deparser 13.5.0 → 13.6.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.
@@ -2,18 +2,20 @@ import { format } from 'util';
2
2
  import { objtypeName, getConstraintFromConstrType } from 'pgsql-enums';
3
3
  let TAB_CHAR = '\t';
4
4
  let NEWLINE_CHAR = '\n';
5
+
5
6
  const isEmptyObject = obj => {
6
7
  return !obj || typeof obj === 'object' && !Object.keys(obj).length;
7
8
  };
9
+
8
10
  const dotty = require('dotty');
11
+
9
12
  const fail = (type, node) => {
10
13
  throw new Error(format('Unhandled %s node: %s', type, JSON.stringify(node)));
11
- };
14
+ }; // select word from pg_get_keywords() where catcode = 'R';
12
15
 
13
- // select word from pg_get_keywords() where catcode = 'R';
14
- const RESERVED_WORDS = new Set(['all', 'analyse', 'analyze', 'and', 'any', 'array', 'as', 'asc', 'asymmetric', 'both', 'case', 'cast', 'check', 'collate', 'column', 'constraint', 'create', 'current_catalog', 'current_date', 'current_role', 'current_time', 'current_timestamp', 'current_user', 'default', 'deferrable', 'desc', 'distinct', 'do', 'else', 'end', 'except', 'false', 'fetch', 'for', 'foreign', 'from', 'grant', 'group', 'having', 'in', 'initially', 'intersect', 'into', 'lateral', 'leading', 'limit', 'localtime', 'localtimestamp', 'not', 'null', 'offset', 'on', 'only', 'or', 'order', 'placing', 'primary', 'references', 'returning', 'select', 'session_user', 'some', 'symmetric', 'table', 'then', 'to', 'trailing', 'true', 'union', 'unique', 'user', 'using', 'variadic', 'when', 'where', 'window', 'with']);
15
16
 
16
- // https://github.com/pganalyze/libpg_query/blob/b2790f8140721ff7f047167ecd7d44267b0a3880/src/postgres/include/storage/lockdefs.h
17
+ const RESERVED_WORDS = new Set(['all', 'analyse', 'analyze', 'and', 'any', 'array', 'as', 'asc', 'asymmetric', 'both', 'case', 'cast', 'check', 'collate', 'column', 'constraint', 'create', 'current_catalog', 'current_date', 'current_role', 'current_time', 'current_timestamp', 'current_user', 'default', 'deferrable', 'desc', 'distinct', 'do', 'else', 'end', 'except', 'false', 'fetch', 'for', 'foreign', 'from', 'grant', 'group', 'having', 'in', 'initially', 'intersect', 'into', 'lateral', 'leading', 'limit', 'localtime', 'localtimestamp', 'not', 'null', 'offset', 'on', 'only', 'or', 'order', 'placing', 'primary', 'references', 'returning', 'select', 'session_user', 'some', 'symmetric', 'table', 'then', 'to', 'trailing', 'true', 'union', 'unique', 'user', 'using', 'variadic', 'when', 'where', 'window', 'with']); // https://github.com/pganalyze/libpg_query/blob/b2790f8140721ff7f047167ecd7d44267b0a3880/src/postgres/include/storage/lockdefs.h
18
+
17
19
  const LOCK_MODES = {
18
20
  1: 'ACCESS SHARE',
19
21
  2: 'ROW SHARE',
@@ -24,20 +26,23 @@ const LOCK_MODES = {
24
26
  7: 'EXCLUSIVE',
25
27
  8: 'ACCESS EXCLUSIVE'
26
28
  };
27
- const isReserved = value => RESERVED_WORDS.has(value.toLowerCase());
28
29
 
29
- // has uppercase and lowercase, or non word characters
30
- const needsQuotesRegex = /[a-z]+[\W\w]*[A-Z]+|[A-Z]+[\W\w]*[a-z]+|\W/;
30
+ const isReserved = value => RESERVED_WORDS.has(value.toLowerCase()); // has uppercase and lowercase, or non word characters
31
+
31
32
 
32
- // usually the AST lowercases all the things, so if we
33
+ const needsQuotesRegex = /[a-z]+[\W\w]*[A-Z]+|[A-Z]+[\W\w]*[a-z]+|\W/; // usually the AST lowercases all the things, so if we
33
34
  // have both, the author most likely used double quotes
35
+
34
36
  const needsQuotes = value => needsQuotesRegex.test(value) || isReserved(value);
37
+
35
38
  const compact = o => o.filter(e => {
36
39
  const isFalsy = !e;
37
40
  return !isFalsy && e.toString().length;
38
41
  });
42
+
39
43
  const flatten = o => {
40
44
  const flattened = [];
45
+
41
46
  for (let i = 0; i < o.length; i++) {
42
47
  if (Array.isArray(o[i])) {
43
48
  for (let j = 0; j < o[i].length; j++) {
@@ -47,208 +52,276 @@ const flatten = o => {
47
52
  flattened.push(o[i]);
48
53
  }
49
54
  }
55
+
50
56
  return flattened;
51
57
  };
58
+
52
59
  const inverted = o => {
53
60
  const objInverted = {};
54
61
  const keys = Object.keys(o);
62
+
55
63
  for (let i = 0; i < keys.length; i++) {
56
64
  const key = keys[i];
57
65
  objInverted[o[key]] = key;
58
66
  }
67
+
59
68
  return objInverted;
60
69
  };
70
+
61
71
  const parens = string => {
62
72
  return '(' + string + ')';
63
73
  };
74
+
64
75
  const indent = (text, count = 1) => text;
76
+
65
77
  const unwrapList = obj => obj !== undefined && obj.List !== undefined ? obj.List.items : obj;
78
+
66
79
  export default class Deparser {
67
80
  static deparse(query, opts) {
68
81
  return new Deparser(query, opts).deparseQuery();
69
82
  }
83
+
70
84
  constructor(tree, opts = {}) {
71
85
  this.tree = tree;
86
+
72
87
  if (opts.hasOwnProperty('newline')) {
73
88
  NEWLINE_CHAR = opts.newline;
74
89
  }
90
+
75
91
  if (opts.hasOwnProperty('tab')) {
76
92
  TAB_CHAR = opts.tab;
77
93
  }
94
+
78
95
  if (!Array.isArray(this.tree)) this.tree = [this.tree];
79
96
  }
97
+
80
98
  deparseQuery() {
81
99
  return this.tree.map(node => this.deparse(node)).join(NEWLINE_CHAR + NEWLINE_CHAR);
82
100
  }
101
+
83
102
  deparseNodes(nodes, context) {
84
103
  return unwrapList(nodes).map(node => {
85
104
  const unwrapped = unwrapList(node);
86
105
  return Array.isArray(unwrapped) ? this.list(unwrapped, ', ', '', context) : this.deparse(node, context);
87
106
  });
88
107
  }
108
+
89
109
  deparseReturningList(list, context) {
90
110
  return unwrapList(list).map(returning => this.deparse(returning.ResTarget.val, context) + (returning.ResTarget.name ? ' AS ' + this.quote(returning.ResTarget.name) : '')).join(',');
91
111
  }
112
+
92
113
  list(nodes, separator = ', ', prefix = '', context) {
93
114
  if (!nodes) {
94
115
  return '';
95
116
  }
117
+
96
118
  return this.deparseNodes(nodes, context).map(l => `${prefix}${l}`).join(separator);
97
119
  }
120
+
98
121
  listQuotes(nodes, separator = ', ') {
99
122
  return this.list(unwrapList(nodes), separator).split(separator).map(a => this.quote(a.trim())).join(separator);
100
123
  }
124
+
101
125
  quote(value) {
102
126
  if (value == null) {
103
127
  return null;
104
128
  }
129
+
105
130
  const unwrapped = unwrapList(value);
131
+
106
132
  if (Array.isArray(unwrapped)) {
107
133
  return unwrapped.map(o => this.quote(o));
108
134
  }
135
+
109
136
  if (needsQuotes(value)) {
110
137
  return '"' + value + '"';
111
138
  }
139
+
112
140
  return value;
113
- }
141
+ } // SELECT encode(E'''123\\000\\001', 'base64')
142
+
114
143
 
115
- // SELECT encode(E'''123\\000\\001', 'base64')
116
144
  escape(literal) {
117
145
  return "'" + literal.replace(/'/g, "''") + "'";
118
146
  }
147
+
119
148
  getPgCatalogTypeName(typeName, size) {
120
149
  switch (typeName) {
121
150
  case 'bpchar':
122
151
  if (size != null) {
123
152
  return 'char';
124
- }
125
- // return `pg_catalog.bpchar` below so that the following is symmetric
153
+ } // return `pg_catalog.bpchar` below so that the following is symmetric
126
154
  // SELECT char 'c' = char 'c' AS true
155
+
156
+
127
157
  return 'pg_catalog.bpchar';
158
+
128
159
  case 'varchar':
129
160
  return 'varchar';
161
+
130
162
  case 'numeric':
131
163
  return 'numeric';
164
+
132
165
  case 'bool':
133
166
  return 'boolean';
167
+
134
168
  case 'int2':
135
169
  return 'smallint';
170
+
136
171
  case 'int4':
137
172
  return 'int';
173
+
138
174
  case 'int8':
139
175
  return 'bigint';
176
+
140
177
  case 'real':
141
178
  return 'pg_catalog.float4';
179
+
142
180
  case 'time':
143
181
  return 'time';
182
+
144
183
  case 'timestamp':
145
184
  return 'timestamp';
185
+
146
186
  case 'interval':
147
187
  return 'interval';
188
+
148
189
  case 'bit':
149
190
  return 'bit';
191
+
150
192
  default:
151
193
  return 'pg_catalog.' + typeName;
152
194
  }
153
195
  }
196
+
154
197
  type(names, args) {
155
198
  const catalogAndType = unwrapList(names).map(name => this.deparse(name));
156
199
  const catalog = catalogAndType[0];
157
200
  const type = catalogAndType[1];
201
+
158
202
  const mods = (name, size) => {
159
203
  if (size != null) {
160
204
  return name + '(' + size + ')';
161
205
  }
206
+
162
207
  return name;
163
- };
208
+ }; // handle the special "char" (in quotes) type
209
+
164
210
 
165
- // handle the special "char" (in quotes) type
166
211
  if (catalog === 'char' && !type) {
167
212
  return mods('"char"', args);
168
213
  }
214
+
169
215
  if (catalog === 'pg_catalog' && type === 'char') {
170
216
  return mods('pg_catalog."char"', args);
171
217
  }
218
+
172
219
  if (catalog !== 'pg_catalog') {
173
220
  return mods(this.listQuotes(names, '.'), args);
174
221
  }
222
+
175
223
  const res = this.getPgCatalogTypeName(type, args);
176
224
  return mods(res, args);
177
225
  }
226
+
178
227
  deparse(item, context) {
179
228
  if (item == null) {
180
229
  return null;
181
230
  }
231
+
182
232
  if (typeof item === 'number' || item instanceof Number) {
183
233
  return item;
184
234
  }
235
+
185
236
  const type = Object.keys(item)[0];
186
237
  const node = item[type];
238
+
187
239
  if (this[type] == null) {
188
240
  throw new Error(type + ' is not implemented: ' + JSON.stringify(node));
189
241
  }
242
+
190
243
  return this[type](node, context);
191
244
  }
245
+
192
246
  ['RawStmt'](node, context = {}) {
193
247
  if (node.stmt_len) {
194
248
  return this.deparse(node.stmt, context) + ';';
195
249
  }
250
+
196
251
  return this.deparse(node.stmt, context);
197
252
  }
253
+
198
254
  ['RuleStmt'](node, context = {}) {
199
255
  const output = [];
200
256
  output.push('CREATE');
201
257
  output.push('RULE');
258
+
202
259
  if (node.rulename === '_RETURN') {
203
260
  // special rules
204
261
  output.push('"_RETURN"');
205
262
  } else {
206
263
  output.push(node.rulename);
207
264
  }
265
+
208
266
  output.push('AS');
209
267
  output.push('ON');
268
+
210
269
  switch (node.event) {
211
270
  case 'CMD_SELECT':
212
271
  output.push('SELECT');
213
272
  break;
273
+
214
274
  case 'CMD_UPDATE':
215
275
  output.push('UPDATE');
216
276
  break;
277
+
217
278
  case 'CMD_INSERT':
218
279
  output.push('INSERT');
219
280
  break;
281
+
220
282
  case 'CMD_DELETE':
221
283
  output.push('DELETE');
222
284
  break;
285
+
223
286
  default:
224
287
  throw new Error('event type not yet implemented for RuleStmt');
225
288
  }
289
+
226
290
  output.push('TO');
227
291
  output.push(this.RangeVar(node.relation, context));
292
+
228
293
  if (node.whereClause) {
229
294
  output.push('WHERE');
230
295
  output.push(this.deparse(node.whereClause, context));
231
296
  }
297
+
232
298
  output.push('DO');
299
+
233
300
  if (node.instead) {
234
301
  output.push('INSTEAD');
235
302
  }
303
+
236
304
  const actions = unwrapList(node.actions);
305
+
237
306
  if (!actions || !actions.length) {
238
307
  output.push('NOTHING');
239
308
  } else {
240
309
  // TODO how do multiple actions happen?
241
310
  output.push(this.deparse(actions[0], context));
242
311
  }
312
+
243
313
  return output.join(' ');
244
314
  }
315
+
245
316
  ['A_Expr'](node, context = {}) {
246
317
  const output = [];
247
318
  const nodeName = unwrapList(node.name);
319
+
248
320
  switch (node.kind) {
249
321
  case 'AEXPR_OP':
250
322
  {
251
323
  let operator;
324
+
252
325
  if (node.lexpr) {
253
326
  // PARENS
254
327
  if (node.lexpr !== undefined && node.lexpr.A_Expr !== undefined) {
@@ -257,6 +330,7 @@ export default class Deparser {
257
330
  output.push(this.deparse(node.lexpr, context));
258
331
  }
259
332
  }
333
+
260
334
  if (nodeName.length > 1) {
261
335
  const schema = this.deparse(nodeName[0], context);
262
336
  operator = this.deparse(nodeName[1], context);
@@ -265,6 +339,7 @@ export default class Deparser {
265
339
  operator = this.deparse(nodeName[0], context);
266
340
  output.push(operator);
267
341
  }
342
+
268
343
  if (node.rexpr) {
269
344
  // PARENS
270
345
  if (node.rexpr !== undefined && node.rexpr.A_Expr !== undefined) {
@@ -273,66 +348,84 @@ export default class Deparser {
273
348
  output.push(this.deparse(node.rexpr, context));
274
349
  }
275
350
  }
351
+
276
352
  if (output.length === 2) {
277
353
  return output.join('');
278
354
  }
355
+
279
356
  if (['->', '->>'].includes(operator)) {
280
357
  return output.join('');
281
358
  }
359
+
282
360
  return output.join(' ');
283
361
  }
362
+
284
363
  case 'AEXPR_OP_ANY':
285
364
  /* scalar op ANY (array) */
286
365
  output.push(this.deparse(node.lexpr, context));
287
366
  output.push(format('ANY (%s)', this.deparse(node.rexpr, context)));
288
367
  return output.join(` ${this.deparse(nodeName[0], context)} `);
368
+
289
369
  case 'AEXPR_OP_ALL':
290
370
  /* scalar op ALL (array) */
291
371
  output.push(this.deparse(node.lexpr, context));
292
372
  output.push(format('ALL (%s)', this.deparse(node.rexpr, context)));
293
373
  return output.join(` ${this.deparse(nodeName[0], context)} `);
374
+
294
375
  case 'AEXPR_DISTINCT':
295
376
  /* IS DISTINCT FROM - name must be "=" */
296
377
  return format('%s IS DISTINCT FROM %s', this.deparse(node.lexpr, context), this.deparse(node.rexpr, context));
378
+
297
379
  case 'AEXPR_NOT_DISTINCT':
298
380
  /* IS NOT DISTINCT FROM - name must be "=" */
299
381
  return format('%s IS NOT DISTINCT FROM %s', this.deparse(node.lexpr, context), this.deparse(node.rexpr, context));
382
+
300
383
  case 'AEXPR_NULLIF':
301
384
  /* NULLIF - name must be "=" */
302
385
  return format('NULLIF(%s, %s)', this.deparse(node.lexpr, context), this.deparse(node.rexpr, context));
386
+
303
387
  case 'AEXPR_OF':
304
388
  {
305
389
  /* IS [NOT] OF - name must be "=" or "<>" */
306
390
  const op = nodeName[0].String.str === '=' ? 'IS OF' : 'IS NOT OF';
307
391
  return format('%s %s (%s)', this.deparse(node.lexpr, context), op, this.list(node.rexpr, ', ', '', context));
308
392
  }
393
+
309
394
  case 'AEXPR_IN':
310
395
  {
311
396
  /* [NOT] IN - name must be "=" or "<>" */
312
397
  const operator = nodeName[0].String.str === '=' ? 'IN' : 'NOT IN';
313
398
  return format('%s %s (%s)', this.deparse(node.lexpr, context), operator, this.list(node.rexpr, ', ', '', context));
314
399
  }
400
+
315
401
  case 'AEXPR_LIKE':
316
402
  /* [NOT] LIKE - name must be "~~" or "!~~" */
317
403
  output.push(this.deparse(node.lexpr, context));
404
+
318
405
  if (nodeName[0].String.str === '!~~') {
319
406
  output.push(format('NOT LIKE (%s)', this.deparse(node.rexpr, context)));
320
407
  } else {
321
408
  output.push(format('LIKE (%s)', this.deparse(node.rexpr, context)));
322
409
  }
410
+
323
411
  return output.join(' ');
412
+
324
413
  case 'AEXPR_ILIKE':
325
414
  /* [NOT] ILIKE - name must be "~~*" or "!~~*" */
326
415
  output.push(this.deparse(node.lexpr, context));
416
+
327
417
  if (nodeName[0].String.str === '!~~*') {
328
418
  output.push(format('NOT ILIKE (%s)', this.deparse(node.rexpr, context)));
329
419
  } else {
330
420
  output.push(format('ILIKE (%s)', this.deparse(node.rexpr, context)));
331
421
  }
422
+
332
423
  return output.join(' ');
424
+
333
425
  case 'AEXPR_SIMILAR':
334
426
  // SIMILAR TO emits a similar_escape FuncCall node with the first argument
335
427
  output.push(this.deparse(node.lexpr, context));
428
+
336
429
  if (nodeName[0].String.str === '~') {
337
430
  if (unwrapList(node.rexpr.FuncCall.args).length > 1) {
338
431
  output.push(format('SIMILAR TO %s ESCAPE %s', this.deparse(unwrapList(node.rexpr.FuncCall.args)[0], context), this.deparse(unwrapList(node.rexpr.FuncCall.args)[1], context)));
@@ -346,24 +439,28 @@ export default class Deparser {
346
439
  output.push(format('NOT SIMILAR TO %s', this.deparse(unwrapList(node.rexpr.FuncCall.args)[0], context)));
347
440
  }
348
441
  }
442
+
349
443
  return output.join(' ');
444
+
350
445
  case 'AEXPR_BETWEEN':
351
446
  output.push(this.deparse(node.lexpr, context));
352
447
  output.push(format('BETWEEN %s AND %s', this.deparse(unwrapList(node.rexpr)[0], context), this.deparse(unwrapList(node.rexpr)[1], context)));
353
448
  return output.join(' ');
449
+
354
450
  case 'AEXPR_NOT_BETWEEN':
355
451
  output.push(this.deparse(node.lexpr, context));
356
452
  output.push(format('NOT BETWEEN %s AND %s', this.deparse(unwrapList(node.rexpr)[0], context), this.deparse(unwrapList(node.rexpr)[1], context)));
357
453
  return output.join(' ');
454
+
358
455
  case 'AEXPR_BETWEEN_SYM':
359
456
  output.push(this.deparse(node.lexpr, context));
360
457
  output.push(format('BETWEEN SYMMETRIC %s AND %s', this.deparse(unwrapList(node.rexpr)[0], context), this.deparse(unwrapList(node.rexpr)[1], context)));
361
458
  return output.join(' ');
459
+
362
460
  case 'AEXPR_NOT_BETWEEN_SYM':
363
461
  output.push(this.deparse(node.lexpr, context));
364
462
  output.push(format('NOT BETWEEN SYMMETRIC %s AND %s', this.deparse(unwrapList(node.rexpr)[0], context), this.deparse(unwrapList(node.rexpr)[1], context)));
365
463
  return output.join(' ');
366
-
367
464
  // case 15:
368
465
  // AEXPR_PAREN
369
466
 
@@ -371,35 +468,42 @@ export default class Deparser {
371
468
  return fail('A_Expr', node);
372
469
  }
373
470
  }
471
+
374
472
  ['Alias'](node, context = {}) {
375
473
  const name = node.aliasname;
376
474
  const output = ['AS'];
475
+
377
476
  if (node.colnames) {
378
477
  output.push(this.quote(name) + parens(this.listQuotes(node.colnames)));
379
478
  } else {
380
479
  output.push(this.quote(name));
381
480
  }
481
+
382
482
  return output.join(' ');
383
483
  }
484
+
384
485
  ['A_ArrayExpr'](node) {
385
486
  return format('ARRAY[%s]', this.list(node.elements));
386
487
  }
488
+
387
489
  ['A_Const'](node, context = {}) {
388
490
  if (node.val.String) {
389
491
  return this.escape(this.deparse(node.val, context));
390
492
  }
493
+
391
494
  return this.deparse(node.val, context);
392
495
  }
496
+
393
497
  ['A_Indices'](node, context = {}) {
394
498
  if (node.lidx) {
395
499
  return format('[%s:%s]', this.deparse(node.lidx, context), this.deparse(node.uidx, context));
396
500
  }
501
+
397
502
  return format('[%s]', this.deparse(node.uidx, context));
398
503
  }
399
- ['A_Indirection'](node, context = {}) {
400
- const output = [`(${this.deparse(node.arg, context)})`];
401
504
 
402
- // TODO(zhm) figure out the actual rules for when a '.' is needed
505
+ ['A_Indirection'](node, context = {}) {
506
+ const output = [`(${this.deparse(node.arg, context)})`]; // TODO(zhm) figure out the actual rules for when a '.' is needed
403
507
  //
404
508
  // select a.b[0] from a;
405
509
  // select (select row(1)).*
@@ -407,8 +511,10 @@ export default class Deparser {
407
511
  // select c2.a[2].f2[1].f3[0].a1 from comptable
408
512
 
409
513
  const indirection = unwrapList(node.indirection);
514
+
410
515
  for (let i = 0; i < indirection.length; i++) {
411
516
  const subnode = indirection[i];
517
+
412
518
  if (subnode.String || subnode.A_Star) {
413
519
  const value = subnode.A_Star ? '*' : this.quote(subnode.String.str);
414
520
  output.push(`.${value}`);
@@ -416,90 +522,121 @@ export default class Deparser {
416
522
  output.push(this.deparse(subnode, context));
417
523
  }
418
524
  }
525
+
419
526
  return output.join('');
420
527
  }
528
+
421
529
  ['A_Star'](node) {
422
530
  return '*';
423
531
  }
532
+
424
533
  ['BitString'](node) {
425
534
  const prefix = node.str[0];
426
535
  return `${prefix}'${node.str.substring(1)}'`;
427
536
  }
537
+
428
538
  ['BoolExpr'](node, context = {}) {
429
539
  let fmt_str = '%s';
540
+
430
541
  if (context.bool) {
431
542
  fmt_str = '(%s)';
432
543
  }
544
+
433
545
  const ctx = Object.assign({}, context);
434
546
  ctx.bool = true;
547
+
435
548
  switch (node.boolop) {
436
549
  case 'AND_EXPR':
437
550
  return format(fmt_str, this.list(node.args, ' AND ', '', ctx));
551
+
438
552
  case 'OR_EXPR':
439
553
  return format(fmt_str, this.list(node.args, ' OR ', '', ctx));
554
+
440
555
  case 'NOT_EXPR':
441
556
  return format('NOT (%s)', this.deparse(unwrapList(node.args)[0], context));
557
+
442
558
  default:
443
559
  return fail('BoolExpr', node);
444
560
  }
445
561
  }
562
+
446
563
  ['BooleanTest'](node, context = {}) {
447
564
  const output = [];
448
565
  const ctx = Object.assign({}, context);
449
566
  ctx.bool = true;
450
567
  output.push(this.deparse(node.arg, ctx));
568
+
451
569
  switch (node.booltesttype) {
452
570
  case 'IS_TRUE':
453
571
  output.push('IS TRUE');
454
572
  break;
573
+
455
574
  case 'IS_NOT_TRUE':
456
575
  output.push('IS NOT TRUE');
457
576
  break;
577
+
458
578
  case 'IS_FALSE':
459
579
  output.push('IS FALSE');
460
580
  break;
581
+
461
582
  case 'IS_NOT_FALSE':
462
583
  output.push('IS NOT FALSE');
463
584
  break;
585
+
464
586
  case 'IS_UNKNOWN':
465
587
  output.push('IS UNKNOWN');
466
588
  break;
589
+
467
590
  case 'IS_NOT_UNKNOWN':
468
591
  output.push('IS NOT UNKNOWN');
469
592
  break;
470
593
  }
594
+
471
595
  return output.join(' ');
472
596
  }
597
+
473
598
  ['CaseExpr'](node, context = {}) {
474
599
  const output = ['CASE'];
600
+
475
601
  if (node.arg) {
476
602
  output.push(this.deparse(node.arg, context));
477
603
  }
604
+
478
605
  const args = unwrapList(node.args);
606
+
479
607
  for (let i = 0; i < args.length; i++) {
480
608
  output.push(this.deparse(args[i], context));
481
609
  }
610
+
482
611
  if (node.defresult) {
483
612
  output.push('ELSE');
484
613
  output.push(this.deparse(node.defresult, context));
485
614
  }
615
+
486
616
  output.push('END');
487
617
  return output.join(' ');
488
618
  }
619
+
489
620
  ['CoalesceExpr'](node, context = {}) {
490
621
  return format('COALESCE(%s)', this.list(node.args, ', ', '', context));
491
622
  }
623
+
492
624
  ['CollateClause'](node, context = {}) {
493
625
  const output = [];
626
+
494
627
  if (node.arg) {
495
628
  output.push(this.deparse(node.arg, context));
496
629
  }
630
+
497
631
  output.push('COLLATE');
632
+
498
633
  if (node.collname) {
499
634
  output.push(this.quote(this.deparseNodes(node.collname, context)));
500
635
  }
636
+
501
637
  return output.join(' ');
502
638
  }
639
+
503
640
  ['CompositeTypeStmt'](node, context = {}) {
504
641
  const output = [];
505
642
  output.push('CREATE TYPE');
@@ -510,14 +647,18 @@ export default class Deparser {
510
647
  output.push(')');
511
648
  return output.join(' ');
512
649
  }
650
+
513
651
  ['RenameStmt'](node, context = {}) {
514
652
  const output = [];
653
+
515
654
  if (node.renameType === 'OBJECT_FUNCTION' || node.renameType === 'OBJECT_FOREIGN_TABLE' || node.renameType === 'OBJECT_FDW' || node.renameType === 'OBJECT_FOREIGN_SERVER') {
516
655
  output.push('ALTER');
517
656
  output.push(objtypeName(node.renameType));
657
+
518
658
  if (node.missing_ok) {
519
659
  output.push('IF EXISTS');
520
660
  }
661
+
521
662
  output.push(this.deparse(node.object, context));
522
663
  output.push('RENAME');
523
664
  output.push('TO');
@@ -525,9 +666,11 @@ export default class Deparser {
525
666
  } else if (node.renameType === 'OBJECT_ATTRIBUTE') {
526
667
  output.push('ALTER');
527
668
  output.push(objtypeName(node.relationType));
669
+
528
670
  if (node.missing_ok) {
529
671
  output.push('IF EXISTS');
530
672
  }
673
+
531
674
  output.push(this.RangeVar(node.relation, context));
532
675
  output.push('RENAME');
533
676
  output.push(objtypeName(node.renameType));
@@ -537,9 +680,11 @@ export default class Deparser {
537
680
  } else if (node.renameType === 'OBJECT_DOMAIN' || node.renameType === 'OBJECT_TYPE') {
538
681
  output.push('ALTER');
539
682
  output.push(objtypeName(node.renameType));
683
+
540
684
  if (node.missing_ok) {
541
685
  output.push('IF EXISTS');
542
686
  }
687
+
543
688
  const typObj = {
544
689
  TypeName: {
545
690
  names: node.object
@@ -552,9 +697,11 @@ export default class Deparser {
552
697
  } else if (node.renameType === 'OBJECT_SCHEMA') {
553
698
  output.push('ALTER');
554
699
  output.push(objtypeName(node.renameType));
700
+
555
701
  if (node.missing_ok) {
556
702
  output.push('IF EXISTS');
557
703
  }
704
+
558
705
  output.push(this.quote(node.subname));
559
706
  output.push('RENAME');
560
707
  output.push('TO');
@@ -562,9 +709,11 @@ export default class Deparser {
562
709
  } else if (node.renameType === 'OBJECT_DOMCONSTRAINT') {
563
710
  output.push('ALTER');
564
711
  output.push('DOMAIN');
712
+
565
713
  if (node.missing_ok) {
566
714
  output.push('IF EXISTS');
567
715
  }
716
+
568
717
  const typObj = {
569
718
  TypeName: {
570
719
  names: node.object
@@ -578,114 +727,146 @@ export default class Deparser {
578
727
  } else {
579
728
  output.push('ALTER');
580
729
  output.push('TABLE');
730
+
581
731
  if (node.missing_ok) {
582
732
  output.push('IF EXISTS');
583
733
  }
734
+
584
735
  output.push(this.RangeVar(node.relation, context));
585
736
  output.push('RENAME');
586
737
  output.push(this.quote(node.subname));
587
738
  output.push('TO');
588
739
  output.push(this.quote(node.newname));
589
740
  }
741
+
590
742
  if (node.behavior === 'DROP_CASCADE') {
591
743
  output.push('CASCADE');
592
744
  }
745
+
593
746
  return output.join(' ');
594
747
  }
748
+
595
749
  ['AlterOwnerStmt'](node, context = {}) {
596
750
  const output = [];
597
751
  output.push('ALTER');
598
752
  output.push(objtypeName(node.objectType));
599
753
  const unwrapped = unwrapList(node.object);
754
+
600
755
  if (Array.isArray(unwrapped)) {
601
756
  output.push(this.listQuotes(unwrapped, '.'));
602
757
  } else {
603
758
  output.push(this.deparse(node.object, context));
604
759
  }
760
+
605
761
  output.push('OWNER TO');
606
762
  output.push(this.RoleSpec(node.newowner, context));
607
763
  return output.join(' ');
608
764
  }
765
+
609
766
  ['AlterObjectSchemaStmt'](node, context = {}) {
610
767
  const output = [];
768
+
611
769
  if (node.objectType === 'OBJECT_TABLE') {
612
770
  output.push('ALTER');
613
771
  output.push(objtypeName(node.objectType));
772
+
614
773
  if (node.missing_ok) {
615
774
  output.push('IF EXISTS');
616
775
  }
776
+
617
777
  output.push(this.RangeVar(node.relation, context));
618
778
  output.push('SET SCHEMA');
619
779
  output.push(this.quote(node.newschema));
620
780
  } else {
621
781
  output.push('ALTER');
622
782
  output.push(objtypeName(node.objectType));
783
+
623
784
  if (node.missing_ok) {
624
785
  output.push('IF EXISTS');
625
786
  }
787
+
626
788
  const unwrapped = unwrapList(node.object);
789
+
627
790
  if (Array.isArray(unwrapped)) {
628
791
  output.push(this.listQuotes(unwrapped, '.'));
629
792
  } else {
630
793
  output.push(this.deparse(node.object, context));
631
794
  }
795
+
632
796
  output.push('SET SCHEMA');
633
797
  output.push(this.quote(node.newschema));
634
798
  }
799
+
635
800
  return output.join(' ');
636
801
  }
802
+
637
803
  ['ColumnDef'](node, context = {}) {
638
804
  const output = [this.quote(node.colname)];
639
805
  output.push(this.TypeName(node.typeName, context));
806
+
640
807
  if (node.raw_default) {
641
808
  output.push('USING');
642
809
  output.push(this.deparse(node.raw_default, context));
643
810
  }
811
+
644
812
  if (node.constraints) {
645
813
  output.push(this.list(node.constraints, ' ', '', context));
646
814
  }
815
+
647
816
  if (node.collClause) {
648
817
  output.push('COLLATE');
649
818
  const str = unwrapList(node.collClause.collname)[0].String.str;
650
819
  output.push(this.quote(str));
651
820
  }
821
+
652
822
  return compact(output).join(' ');
653
823
  }
824
+
654
825
  ['SQLValueFunction'](node) {
655
826
  if (node.op === 'SVFOP_CURRENT_DATE') {
656
827
  return 'CURRENT_DATE';
657
828
  }
829
+
658
830
  if (node.op === 'SVFOP_CURRENT_TIMESTAMP') {
659
831
  return 'CURRENT_TIMESTAMP';
660
832
  }
833
+
661
834
  if (node.op === 'SVFOP_CURRENT_USER') {
662
835
  return 'CURRENT_USER';
663
836
  }
837
+
664
838
  if (node.op === 'SVFOP_SESSION_USER') {
665
839
  return 'SESSION_USER';
666
840
  }
841
+
667
842
  throw new Error(`op=${node.op} SQLValueFunction not implemented`);
668
843
  }
844
+
669
845
  ['ColumnRef'](node, context = {}) {
670
846
  const KEYWORDS = ['old', 'new'];
671
847
  const fields = unwrapList(node.fields).map(field => {
672
848
  if (field.String) {
673
849
  const value = this.deparse(field, context);
850
+
674
851
  if (context === 'trigger' && KEYWORDS.includes(value.toLowerCase())) {
675
852
  return value.toUpperCase();
676
853
  }
854
+
677
855
  return this.quote(value);
678
856
  }
857
+
679
858
  return this.deparse(field, context);
680
859
  });
681
860
  return fields.join('.');
682
861
  }
862
+
683
863
  ['CommentStmt'](node, context = {}) {
684
864
  const output = [];
685
865
  output.push('COMMENT');
686
866
  output.push('ON');
687
867
  output.push(objtypeName(node.objtype));
688
868
  const object = unwrapList(node.object);
869
+
689
870
  if (node.objtype === 'OBJECT_CAST') {
690
871
  output.push('(');
691
872
  output.push(this.deparse(object[0], context));
@@ -740,16 +921,20 @@ export default class Deparser {
740
921
  } else {
741
922
  output.push(this.deparse(object, context));
742
923
  }
924
+
743
925
  if (node.objargs) {
744
926
  output.push('(');
745
927
  output.push(this.list(node.objargs, ', ', '', context));
746
928
  output.push(')');
747
929
  }
748
930
  }
931
+
749
932
  output.push('IS');
933
+
750
934
  const escapeComment = str => {
751
935
  return str.replace(/\\/g, '\\');
752
936
  };
937
+
753
938
  if (node.comment) {
754
939
  if (/[^a-zA-Z0-9]/.test(node.comment)) {
755
940
  // special chars we care about...
@@ -761,70 +946,91 @@ export default class Deparser {
761
946
  } else {
762
947
  output.push('NULL');
763
948
  }
949
+
764
950
  return output.join(' ');
765
951
  }
952
+
766
953
  ['CommonTableExpr'](node, context = {}) {
767
954
  const output = [];
768
955
  output.push(node.ctename);
956
+
769
957
  if (node.aliascolnames) {
770
958
  const colnames = this.quote(this.deparseNodes(node.aliascolnames, context));
771
959
  output.push(`(${colnames.join(', ')})`);
772
960
  }
961
+
773
962
  output.push('AS');
963
+
774
964
  if (node.ctematerialized === 'CTEMaterializeAlways') {
775
965
  output.push('MATERIALIZED');
776
966
  } else if (node.ctematerialized === 'CTEMaterializeNever') {
777
967
  output.push('NOT MATERIALIZED');
778
968
  }
969
+
779
970
  output.push(format('(%s)', this.deparse(node.ctequery)));
780
971
  return output.join(' ');
781
972
  }
973
+
782
974
  ['DefineStmt'](node, context = {}) {
783
975
  const output = [];
784
976
  output.push('CREATE');
977
+
785
978
  if (node.replace) {
786
979
  output.push('OR REPLACE');
787
980
  }
981
+
788
982
  switch (node.kind) {
789
983
  case 'OBJECT_AGGREGATE':
790
984
  output.push('AGGREGATE');
791
985
  break;
986
+
792
987
  case 'OBJECT_OPERATOR':
793
988
  output.push('OPERATOR');
794
989
  break;
990
+
795
991
  case 'OBJECT_TYPE':
796
992
  output.push('TYPE');
797
993
  break;
994
+
798
995
  case 'OBJECT_TSPARSER':
799
996
  output.push('TEXT SEARCH PARSER');
800
997
  break;
998
+
801
999
  case 'OBJECT_TSDICTIONARY':
802
1000
  output.push('TEXT SEARCH DICTIONARY');
803
1001
  break;
1002
+
804
1003
  case 'OBJECT_TSTEMPLATE':
805
1004
  output.push('TEXT SEARCH TEMPLATE');
806
1005
  break;
1006
+
807
1007
  case 'OBJECT_TSCONFIGURATION':
808
1008
  output.push('TEXT SEARCH CONFIGURATION');
809
1009
  break;
1010
+
810
1011
  case 'OBJECT_COLLATION':
811
1012
  output.push('COLLATION');
812
1013
  break;
1014
+
813
1015
  default:
814
1016
  throw new Error('DefineStmt not recognized');
815
1017
  }
1018
+
816
1019
  if (node.if_not_exists) {
817
1020
  output.push('IF NOT EXISTS');
818
1021
  }
1022
+
819
1023
  switch (node.kind) {
820
1024
  case 'OBJECT_AGGREGATE':
821
1025
  // output.push(this.deparse(node.defnames));
822
1026
  output.push(this.list(node.defnames, '.', '', context));
823
1027
  break;
1028
+
824
1029
  case 'OBJECT_OPERATOR':
825
- output.push(this.list(node.defnames, '.', '', context));
826
- // output.push(this.deparse(node.defnames));
1030
+ output.push(this.list(node.defnames, '.', '', context)); // output.push(this.deparse(node.defnames));
1031
+
827
1032
  break;
1033
+
828
1034
  case 'OBJECT_TYPE':
829
1035
  case 'OBJECT_TSPARSER':
830
1036
  case 'OBJECT_TSDICTIONARY':
@@ -833,49 +1039,65 @@ export default class Deparser {
833
1039
  case 'OBJECT_COLLATION':
834
1040
  output.push(this.deparse(node.defnames));
835
1041
  break;
1042
+
836
1043
  default:
837
1044
  throw new Error('DefineStmt not recognized');
838
1045
  }
1046
+
839
1047
  if (!node.oldstyle && node.kind == 'OBJECT_AGGREGATE') {
840
1048
  output.push('(');
841
1049
  output.push(`${this.listQuotes(node.args[0], ',')}`);
842
1050
  output.push(')');
843
1051
  }
1052
+
844
1053
  const definition = unwrapList(node.definition);
1054
+
845
1055
  if (definition.length > 0) {
846
1056
  output.push('(');
1057
+
847
1058
  for (let n = 0; n < definition.length; n++) {
848
1059
  const defElement = definition[n].DefElem;
849
1060
  output.push(defElement.defname);
1061
+
850
1062
  if (defElement.arg) {
851
1063
  output.push('=');
852
1064
  output.push(this.deparse(defElement.arg));
853
1065
  }
1066
+
854
1067
  if (n !== definition.length - 1) {
855
1068
  output.push(',');
856
1069
  }
857
1070
  }
1071
+
858
1072
  output.push(')');
859
1073
  }
1074
+
860
1075
  return output.join(' ');
861
1076
  }
1077
+
862
1078
  ['DefElem'](node, context = {}) {
863
1079
  if (node.defname === 'transaction_isolation') {
864
1080
  return format('ISOLATION LEVEL %s', node.arg.A_Const.val.String.str.toUpperCase());
865
1081
  }
1082
+
866
1083
  if (node.defname === 'transaction_read_only') {
867
1084
  return node.arg.A_Const.val.Integer.ival === 0 ? 'READ WRITE' : 'READ ONLY';
868
1085
  }
1086
+
869
1087
  if (node.defname === 'transaction_deferrable') {
870
1088
  return node.arg.A_Const.val.Integer.ival === 0 ? 'NOT DEFERRABLE' : 'DEFERRABLE';
871
1089
  }
1090
+
872
1091
  if (node.defname === 'set') {
873
1092
  return this.deparse(node.arg, context);
874
1093
  }
1094
+
875
1095
  let name = node.defname;
1096
+
876
1097
  if (node.defnamespace) {
877
1098
  name = `${node.defnamespace}.${node.defname}`;
878
1099
  }
1100
+
879
1101
  if (context === 'generated' || context === 'sequence') {
880
1102
  switch (name) {
881
1103
  case 'start':
@@ -883,35 +1105,43 @@ export default class Deparser {
883
1105
  const start = this.deparse(node.arg, context);
884
1106
  return `START WITH ${start}`;
885
1107
  }
1108
+
886
1109
  case 'increment':
887
1110
  {
888
1111
  const inc = this.deparse(node.arg, context);
1112
+
889
1113
  if (context === 'sequence') {
890
1114
  // we need 'simple' so it doesn't wrap negative numbers in parens
891
1115
  return `${name} ${this.deparse(node.arg, 'simple')}`;
892
1116
  }
1117
+
893
1118
  return `INCREMENT BY ${inc}`;
894
1119
  }
1120
+
895
1121
  case 'sequence_name':
896
1122
  {
897
1123
  return `SEQUENCE NAME ${this.listQuotes(node.arg, '.')}`;
898
1124
  }
1125
+
899
1126
  case 'cycle':
900
1127
  {
901
1128
  const on = this.deparse(node.arg, context) + '' === '1';
902
1129
  return on ? 'CYCLE' : 'NO CYCLE';
903
1130
  }
1131
+
904
1132
  case 'minvalue':
905
1133
  {
906
1134
  const off = !node.hasOwnProperty('arg');
907
1135
  return off ? 'NO MINVALUE' : `${name} ${this.deparse(node.arg, 'simple')}`;
908
1136
  }
1137
+
909
1138
  case 'maxvalue':
910
1139
  {
911
1140
  const off = !node.hasOwnProperty('arg');
912
1141
  return off ? 'NO MAXVALUE' : `${name} ${this.deparse(node.arg, 'simple')}`;
913
1142
  }
914
1143
  // alter
1144
+
915
1145
  case 'owned_by':
916
1146
  {
917
1147
  const output = [];
@@ -921,18 +1151,22 @@ export default class Deparser {
921
1151
  return `OWNED BY ${output.join('.')}`;
922
1152
  }
923
1153
  // alter
1154
+
924
1155
  case 'restart':
925
1156
  {
926
1157
  if (node.arg) {
927
1158
  return `RESTART WITH ${this.deparse(node.arg, context)}`;
928
1159
  }
1160
+
929
1161
  return `RESTART`;
930
1162
  }
1163
+
931
1164
  default:
932
1165
  if (node.arg) {
933
1166
  // we need 'simple' so it doesn't wrap negative numbers in parens
934
1167
  return `${name} ${this.deparse(node.arg, 'simple')}`;
935
1168
  }
1169
+
936
1170
  }
937
1171
  } else if (context === 'explain') {
938
1172
  if (node.arg) {
@@ -941,162 +1175,211 @@ export default class Deparser {
941
1175
  } else if (node.arg) {
942
1176
  return `${name} = ${this.deparse(node.arg, context)}`;
943
1177
  }
1178
+
944
1179
  return name;
945
1180
  }
1181
+
946
1182
  ['DoStmt'](node) {
947
1183
  return `DO $$${NEWLINE_CHAR} ${dotty.get(node, 'args.0.DefElem.arg.String.str').trim()} $$`;
948
1184
  }
1185
+
949
1186
  ['Float'](node) {
950
1187
  // wrap negative numbers in parens, SELECT (-2147483648)::int4 * (-1)::int4
951
1188
  if (node.str[0] === '-') {
952
1189
  return `(${node.str})`;
953
1190
  }
1191
+
954
1192
  return node.str;
955
1193
  }
1194
+
956
1195
  ['FuncCall'](node, context = {}) {
957
1196
  const output = [];
958
1197
  let params = [];
1198
+
959
1199
  if (node.args) {
960
1200
  params = unwrapList(node.args).map(item => {
961
1201
  return this.deparse(item, context);
962
1202
  });
963
- }
1203
+ } // COUNT(*)
1204
+
964
1205
 
965
- // COUNT(*)
966
1206
  if (node.agg_star) {
967
1207
  params.push('*');
968
1208
  }
1209
+
969
1210
  const name = this.list(node.funcname, '.', '', context);
970
1211
  const order = [];
971
1212
  const withinGroup = node.agg_within_group;
1213
+
972
1214
  if (node.agg_order) {
973
1215
  order.push('ORDER BY');
974
1216
  order.push(this.list(node.agg_order, ', ', '', context));
975
1217
  }
1218
+
976
1219
  const call = [];
977
1220
  call.push(name + '(');
1221
+
978
1222
  if (node.agg_distinct) {
979
1223
  call.push('DISTINCT ');
980
- }
981
-
982
- // prepend variadic before the last parameter
1224
+ } // prepend variadic before the last parameter
983
1225
  // SELECT CONCAT('|', VARIADIC ARRAY['1','2','3'])
1226
+
1227
+
984
1228
  if (node.func_variadic) {
985
1229
  params[params.length - 1] = 'VARIADIC ' + params[params.length - 1];
986
1230
  }
1231
+
987
1232
  call.push(params.join(', '));
1233
+
988
1234
  if (order.length && !withinGroup) {
989
1235
  call.push(' ');
990
1236
  call.push(order.join(' '));
991
1237
  }
1238
+
992
1239
  call.push(')');
993
1240
  output.push(compact(call).join(''));
1241
+
994
1242
  if (order.length && withinGroup) {
995
1243
  output.push('WITHIN GROUP');
996
1244
  output.push(parens(order.join(' ')));
997
1245
  }
1246
+
998
1247
  if (node.agg_filter != null) {
999
1248
  output.push(format('FILTER (WHERE %s)', this.deparse(node.agg_filter, context)));
1000
1249
  }
1250
+
1001
1251
  if (node.over != null) {
1002
1252
  output.push(format('OVER %s', this.WindowDef(node.over, context)));
1003
1253
  }
1254
+
1004
1255
  return output.join(' ');
1005
1256
  }
1257
+
1006
1258
  ['GroupingFunc'](node, context = {}) {
1007
1259
  return 'GROUPING(' + this.list(node.args, ', ', '', context) + ')';
1008
1260
  }
1261
+
1009
1262
  ['GroupingSet'](node, context = {}) {
1010
1263
  switch (node.kind) {
1011
1264
  case 'GROUPING_SET_EMPTY':
1012
1265
  return '()';
1266
+
1013
1267
  case 'GROUPING_SET_SIMPLE':
1014
1268
  return fail('GroupingSet', node);
1269
+
1015
1270
  case 'GROUPING_SET_ROLLUP':
1016
1271
  return 'ROLLUP (' + this.list(node.content, ', ', '', context) + ')';
1272
+
1017
1273
  case 'GROUPING_SET_CUBE':
1018
1274
  return 'CUBE (' + this.list(node.content, ', ', '', context) + ')';
1275
+
1019
1276
  case 'GROUPING_SET_SETS':
1020
1277
  return 'GROUPING SETS (' + this.list(node.content, ', ', '', context) + ')';
1278
+
1021
1279
  default:
1022
1280
  return fail('GroupingSet', node);
1023
1281
  }
1024
1282
  }
1283
+
1025
1284
  ['IndexStmt'](node, context = {}) {
1026
1285
  const output = [];
1027
1286
  output.push('CREATE');
1287
+
1028
1288
  if (node.unique) {
1029
1289
  output.push('UNIQUE');
1030
1290
  }
1291
+
1031
1292
  output.push('INDEX');
1293
+
1032
1294
  if (node.concurrent) {
1033
1295
  output.push('CONCURRENTLY');
1034
1296
  }
1297
+
1035
1298
  if (node.idxname) {
1036
1299
  output.push(node.idxname);
1037
1300
  }
1301
+
1038
1302
  output.push('ON');
1039
1303
  output.push(this.RangeVar(node.relation, context));
1304
+
1040
1305
  if (node.accessMethod) {
1041
1306
  const accessMethod = node.accessMethod.toUpperCase();
1307
+
1042
1308
  if (accessMethod !== 'BTREE') {
1043
1309
  output.push('USING');
1044
1310
  output.push(accessMethod);
1045
1311
  }
1046
1312
  }
1313
+
1047
1314
  if (node.indexParams) {
1048
1315
  output.push('(');
1049
1316
  output.push(this.list(node.indexParams, ', ', '', context));
1050
1317
  output.push(')');
1051
1318
  }
1319
+
1052
1320
  if (node.indexIncludingParams) {
1053
1321
  output.push('INCLUDE (');
1054
1322
  output.push(this.list(node.indexIncludingParams, ', ', '', context));
1055
1323
  output.push(')');
1056
1324
  }
1325
+
1057
1326
  if (node.whereClause) {
1058
1327
  output.push('WHERE');
1059
1328
  output.push(this.deparse(node.whereClause, context));
1060
1329
  }
1330
+
1061
1331
  return output.join(' ');
1062
1332
  }
1333
+
1063
1334
  ['IndexElem'](node, context = {}) {
1064
1335
  const output = [];
1336
+
1065
1337
  if (node.name) {
1066
1338
  output.push(node.name);
1339
+
1067
1340
  if (node.ordering === 'SORTBY_DESC') {
1068
1341
  output.push('DESC');
1069
1342
  } else if (node.ordering === 'SORTBY_ASC') {
1070
1343
  output.push('ASC');
1071
1344
  }
1345
+
1072
1346
  return output.join(' ');
1073
1347
  }
1348
+
1074
1349
  if (node.expr) {
1075
1350
  return this.deparse(node.expr, context);
1076
1351
  }
1352
+
1077
1353
  return fail('IndexElem', node);
1078
1354
  }
1355
+
1079
1356
  ['InsertStmt'](node, context = {}) {
1080
1357
  const output = [];
1358
+
1081
1359
  if (node.withClause) {
1082
1360
  output.push(this.WithClause(node.withClause, context));
1083
1361
  }
1362
+
1084
1363
  output.push('INSERT INTO');
1085
1364
  output.push(this.RangeVar(node.relation, context));
1086
1365
  const cols = unwrapList(node.cols);
1366
+
1087
1367
  if (cols && cols.length) {
1088
1368
  output.push('(');
1089
1369
  output.push(this.list(cols, ', ', '', context));
1090
1370
  output.push(')');
1091
1371
  }
1372
+
1092
1373
  if (node.selectStmt) {
1093
1374
  output.push(this.deparse(node.selectStmt, context));
1094
1375
  } else {
1095
1376
  output.push('DEFAULT VALUES');
1096
1377
  }
1378
+
1097
1379
  if (node.onConflictClause) {
1098
1380
  const clause = node.onConflictClause;
1099
1381
  output.push('ON CONFLICT');
1382
+
1100
1383
  if (clause.infer.indexElems) {
1101
1384
  output.push('(');
1102
1385
  output.push(this.list(clause.infer.indexElems, ', ', '', context));
@@ -1105,66 +1388,86 @@ export default class Deparser {
1105
1388
  output.push('ON CONSTRAINT');
1106
1389
  output.push(clause.infer.conname);
1107
1390
  }
1391
+
1108
1392
  switch (clause.action) {
1109
1393
  case 'ONCONFLICT_NOTHING':
1110
1394
  output.push('DO NOTHING');
1111
1395
  break;
1396
+
1112
1397
  case 'ONCONFLICT_UPDATE':
1113
1398
  output.push('DO');
1114
1399
  output.push(this.UpdateStmt(clause, context));
1115
1400
  break;
1401
+
1116
1402
  default:
1117
1403
  throw new Error('unhandled CONFLICT CLAUSE');
1118
1404
  }
1119
1405
  }
1406
+
1120
1407
  if (node.returningList) {
1121
1408
  output.push('RETURNING');
1122
1409
  output.push(this.deparseReturningList(node.returningList, context));
1123
1410
  }
1411
+
1124
1412
  return output.join(' ');
1125
1413
  }
1414
+
1126
1415
  ['SetToDefault'](node) {
1127
1416
  return 'DEFAULT';
1128
1417
  }
1418
+
1129
1419
  ['MultiAssignRef'](node, context = {}) {
1130
1420
  const output = [];
1131
1421
  output.push(this.deparse(node.source, context));
1132
1422
  return output.join(' ');
1133
1423
  }
1424
+
1134
1425
  ['DeleteStmt'](node, context = {}) {
1135
1426
  const output = [''];
1427
+
1136
1428
  if (node.withClause) {
1137
1429
  output.push(this.WithClause(node.withClause, context));
1138
1430
  }
1431
+
1139
1432
  output.push('DELETE');
1140
1433
  output.push('FROM');
1141
1434
  output.push(this.RangeVar(node.relation, context));
1435
+
1142
1436
  if (node.usingClause) {
1143
1437
  output.push('USING');
1144
1438
  output.push(this.list(node.usingClause, ', ', '', context));
1145
1439
  }
1440
+
1146
1441
  if (node.whereClause) {
1147
1442
  output.push('WHERE');
1148
1443
  output.push(this.deparse(node.whereClause, context));
1149
1444
  }
1445
+
1150
1446
  if (node.returningList) {
1151
1447
  output.push('RETURNING');
1152
1448
  output.push(this.deparseReturningList(node.returningList, context));
1153
1449
  }
1450
+
1154
1451
  return output.join(' ');
1155
1452
  }
1453
+
1156
1454
  ['UpdateStmt'](node, context = {}) {
1157
1455
  const output = [];
1456
+
1158
1457
  if (node.withClause) {
1159
1458
  output.push(this.WithClause(node.withClause, context));
1160
1459
  }
1460
+
1161
1461
  output.push('UPDATE');
1462
+
1162
1463
  if (node.relation) {
1163
1464
  // onConflictClause no relation..
1164
1465
  output.push(this.RangeVar(node.relation, context));
1165
1466
  }
1467
+
1166
1468
  output.push('SET');
1167
1469
  const targetList = unwrapList(node.targetList);
1470
+
1168
1471
  if (targetList && targetList.length) {
1169
1472
  if (targetList[0].ResTarget && targetList[0].ResTarget.val && targetList[0].ResTarget.val.MultiAssignRef) {
1170
1473
  output.push('(');
@@ -1176,60 +1479,79 @@ export default class Deparser {
1176
1479
  output.push(targetList.map(target => this.deparse(target, 'update')).join(','));
1177
1480
  }
1178
1481
  }
1482
+
1179
1483
  if (node.fromClause) {
1180
1484
  output.push('FROM');
1181
1485
  output.push(this.list(node.fromClause, ', ', '', context));
1182
1486
  }
1487
+
1183
1488
  if (node.whereClause) {
1184
1489
  output.push('WHERE');
1185
1490
  output.push(this.deparse(node.whereClause, context));
1186
1491
  }
1492
+
1187
1493
  if (node.returningList) {
1188
1494
  output.push('RETURNING');
1189
1495
  output.push(this.deparseReturningList(node.returningList, context));
1190
1496
  }
1497
+
1191
1498
  return output.join(' ');
1192
1499
  }
1500
+
1193
1501
  ['Integer'](node, context = {}) {
1194
1502
  if (node.ival < 0 && context !== 'simple') {
1195
1503
  return `(${node.ival})`;
1196
1504
  }
1505
+
1197
1506
  return node.ival.toString();
1198
1507
  }
1508
+
1199
1509
  ['IntoClause'](node, context = {}) {
1200
1510
  return this.RangeVar(node.rel, context);
1201
1511
  }
1512
+
1202
1513
  ['JoinExpr'](node, context = {}) {
1203
1514
  const output = [];
1204
1515
  output.push(this.deparse(node.larg, context));
1516
+
1205
1517
  if (node.isNatural) {
1206
1518
  output.push('NATURAL');
1207
1519
  }
1520
+
1208
1521
  let join = null;
1522
+
1209
1523
  switch (true) {
1210
1524
  case node.jointype === 'JOIN_INNER' && node.quals != null:
1211
1525
  join = 'INNER JOIN';
1212
1526
  break;
1527
+
1213
1528
  case node.jointype === 'JOIN_INNER' && !node.isNatural && !(node.quals != null) && !(node.usingClause != null):
1214
1529
  join = 'CROSS JOIN';
1215
1530
  break;
1531
+
1216
1532
  case node.jointype === 'JOIN_INNER':
1217
1533
  join = 'JOIN';
1218
1534
  break;
1535
+
1219
1536
  case node.jointype === 'JOIN_LEFT':
1220
1537
  join = 'LEFT OUTER JOIN';
1221
1538
  break;
1539
+
1222
1540
  case node.jointype === 'JOIN_FULL':
1223
1541
  join = 'FULL OUTER JOIN';
1224
1542
  break;
1543
+
1225
1544
  case node.jointype === 'JOIN_RIGHT':
1226
1545
  join = 'RIGHT OUTER JOIN';
1227
1546
  break;
1547
+
1228
1548
  default:
1229
1549
  fail('JoinExpr', node);
1230
1550
  break;
1231
1551
  }
1552
+
1232
1553
  output.push(join);
1554
+
1233
1555
  if (node.rarg) {
1234
1556
  // wrap nested join expressions in parens to make the following symmetric:
1235
1557
  // select * from int8_tbl x cross join (int4_tbl x cross join lateral (select x.f1) ss)
@@ -1239,46 +1561,61 @@ export default class Deparser {
1239
1561
  output.push(this.deparse(node.rarg, context));
1240
1562
  }
1241
1563
  }
1564
+
1242
1565
  if (node.quals) {
1243
1566
  output.push(`ON ${this.deparse(node.quals, context)}`);
1244
1567
  }
1568
+
1245
1569
  if (node.usingClause) {
1246
1570
  const using = this.quote(this.deparseNodes(node.usingClause, context)).join(', ');
1247
1571
  output.push(`USING (${using})`);
1248
1572
  }
1573
+
1249
1574
  const wrapped = node.rarg.JoinExpr != null || node.alias ? '(' + output.join(' ') + ')' : output.join(' ');
1575
+
1250
1576
  if (node.alias) {
1251
1577
  return wrapped + ' ' + this.Alias(node.alias, context);
1252
1578
  }
1579
+
1253
1580
  return wrapped;
1254
1581
  }
1582
+
1255
1583
  ['LockingClause'](node, context = {}) {
1256
1584
  const output = [];
1585
+
1257
1586
  switch (node.strength) {
1258
1587
  case 'LCS_NONE':
1259
1588
  output.push('NONE');
1260
1589
  break;
1590
+
1261
1591
  case 'LCS_FORKEYSHARE':
1262
1592
  output.push('FOR KEY SHARE');
1263
1593
  break;
1594
+
1264
1595
  case 'LCS_FORSHARE':
1265
1596
  output.push('FOR SHARE');
1266
1597
  break;
1598
+
1267
1599
  case 'LCS_FORNOKEYUPDATE':
1268
1600
  output.push('FOR NO KEY UPDATE');
1269
1601
  break;
1602
+
1270
1603
  case 'LCS_FORUPDATE':
1271
1604
  output.push('FOR UPDATE');
1272
1605
  break;
1606
+
1273
1607
  default:
1274
1608
  return fail('LockingClause', node);
1275
1609
  }
1610
+
1276
1611
  if (node.lockedRels) {
1277
1612
  output.push('OF');
1278
1613
  output.push(this.list(node.lockedRels, ', ', '', context));
1279
1614
  }
1615
+
1280
1616
  return output.join(' ');
1281
1617
  }
1618
+
1282
1619
  ['LockStmt'](node, context = {}) {
1283
1620
  const output = ['LOCK'];
1284
1621
  output.push(this.list(node.relations, ', ', '', {
@@ -1287,21 +1624,27 @@ export default class Deparser {
1287
1624
  output.push('IN');
1288
1625
  output.push(LOCK_MODES[node.mode]);
1289
1626
  output.push('MODE');
1627
+
1290
1628
  if (node.nowait) {
1291
1629
  output.push('NOWAIT');
1292
1630
  }
1631
+
1293
1632
  return output.join(' ');
1294
1633
  }
1634
+
1295
1635
  ['MinMaxExpr'](node, context = {}) {
1296
1636
  const output = [];
1637
+
1297
1638
  if (node.op === 'IS_GREATEST') {
1298
1639
  output.push('GREATEST');
1299
1640
  } else {
1300
1641
  output.push('LEAST');
1301
1642
  }
1643
+
1302
1644
  output.push(parens(this.list(node.args, ', ', '', context)));
1303
1645
  return output.join('');
1304
1646
  }
1647
+
1305
1648
  ['NamedArgExpr'](node, context = {}) {
1306
1649
  const output = [];
1307
1650
  output.push(node.name);
@@ -1309,110 +1652,147 @@ export default class Deparser {
1309
1652
  output.push(this.deparse(node.arg, context));
1310
1653
  return output.join(' ');
1311
1654
  }
1655
+
1312
1656
  ['Null'](node) {
1313
1657
  return 'NULL';
1314
1658
  }
1659
+
1315
1660
  ['NullTest'](node, context = {}) {
1316
1661
  const output = [this.deparse(node.arg, context)];
1662
+
1317
1663
  if (node.nulltesttype === 'IS_NULL') {
1318
1664
  output.push('IS NULL');
1319
1665
  } else if (node.nulltesttype === 'IS_NOT_NULL') {
1320
1666
  output.push('IS NOT NULL');
1321
1667
  }
1668
+
1322
1669
  return output.join(' ');
1323
1670
  }
1671
+
1324
1672
  ['ParamRef'](node) {
1325
1673
  if (node.number >= 0) {
1326
1674
  return ['$', node.number].join('');
1327
1675
  }
1676
+
1328
1677
  return '?';
1329
1678
  }
1679
+
1330
1680
  ['RangeFunction'](node, context = {}) {
1331
1681
  const output = [];
1682
+
1332
1683
  if (node.lateral) {
1333
1684
  output.push('LATERAL');
1334
1685
  }
1686
+
1335
1687
  const funcs = [];
1336
1688
  const functions = unwrapList(node.functions);
1689
+
1337
1690
  for (let i = 0; i < functions.length; i++) {
1338
1691
  const funcCall = unwrapList(functions[i]);
1339
1692
  const call = [this.deparse(funcCall[0], context)];
1340
1693
  const secondFuncCall = unwrapList(funcCall[1]);
1694
+
1341
1695
  if (secondFuncCall && secondFuncCall.length) {
1342
1696
  call.push(format('AS (%s)', this.list(secondFuncCall, ', ', '', context)));
1343
1697
  }
1698
+
1344
1699
  funcs.push(call.join(' '));
1345
1700
  }
1701
+
1346
1702
  const calls = funcs.join(', ');
1703
+
1347
1704
  if (node.is_rowsfrom) {
1348
1705
  output.push(`ROWS FROM (${calls})`);
1349
1706
  } else {
1350
1707
  output.push(calls);
1351
1708
  }
1709
+
1352
1710
  if (node.ordinality) {
1353
1711
  output.push('WITH ORDINALITY');
1354
1712
  }
1713
+
1355
1714
  if (node.alias) {
1356
1715
  output.push(this.Alias(node.alias, context));
1357
1716
  }
1717
+
1358
1718
  if (node.coldeflist) {
1359
1719
  const defList = this.list(node.coldeflist, ', ', '', context);
1720
+
1360
1721
  if (!node.alias) {
1361
1722
  output.push(` AS (${defList})`);
1362
1723
  } else {
1363
1724
  output.push(`(${defList})`);
1364
1725
  }
1365
1726
  }
1727
+
1366
1728
  return output.join(' ');
1367
1729
  }
1730
+
1368
1731
  ['RangeSubselect'](node, context = {}) {
1369
1732
  let output = '';
1733
+
1370
1734
  if (node.lateral) {
1371
1735
  output += 'LATERAL ';
1372
1736
  }
1737
+
1373
1738
  output += parens(this.deparse(node.subquery, context));
1739
+
1374
1740
  if (node.alias) {
1375
1741
  return output + ' ' + this.Alias(node.alias, context);
1376
1742
  }
1743
+
1377
1744
  return output;
1378
1745
  }
1746
+
1379
1747
  ['RangeTableSample'](node, context = {}) {
1380
1748
  const output = [];
1381
1749
  output.push(this.deparse(node.relation, context));
1382
1750
  output.push('TABLESAMPLE');
1383
1751
  output.push(this.deparse(unwrapList(node.method)[0], context));
1752
+
1384
1753
  if (node.args) {
1385
1754
  output.push(parens(this.list(node.args, ', ', '', context)));
1386
1755
  }
1756
+
1387
1757
  if (node.repeatable) {
1388
1758
  output.push('REPEATABLE(' + this.deparse(node.repeatable, context) + ')');
1389
1759
  }
1760
+
1390
1761
  return output.join(' ');
1391
1762
  }
1763
+
1392
1764
  ['RangeVar'](node, context = {}) {
1393
1765
  const output = [];
1766
+
1394
1767
  if (node.inhOpt === 0) {
1395
1768
  output.push('ONLY');
1396
1769
  }
1770
+
1397
1771
  if (!node.inh && (context.lock || context === 'truncate')) {
1398
1772
  output.push('ONLY');
1399
1773
  }
1774
+
1400
1775
  if (node.relpersistence === 'u') {
1401
1776
  output.push('UNLOGGED');
1402
1777
  }
1778
+
1403
1779
  if (node.relpersistence === 't' && context !== 'view') {
1404
1780
  output.push('TEMPORARY TABLE');
1405
1781
  }
1782
+
1406
1783
  if (node.schemaname != null) {
1407
1784
  output.push(`${this.quote(node.schemaname)}.${this.quote(node.relname)}`);
1408
1785
  } else {
1409
1786
  output.push(this.quote(node.relname));
1410
1787
  }
1788
+
1411
1789
  if (node.alias) {
1412
1790
  output.push(this.Alias(node.alias, context));
1413
1791
  }
1792
+
1414
1793
  return output.join(' ');
1415
1794
  }
1795
+
1416
1796
  ['ResTarget'](node, context = {}) {
1417
1797
  if (context === 'select') {
1418
1798
  return compact([this.deparse(node.val, context), this.quote(node.name)]).join(' AS ');
@@ -1421,30 +1801,39 @@ export default class Deparser {
1421
1801
  } else if (!(node.val != null)) {
1422
1802
  return this.quote(node.name);
1423
1803
  }
1804
+
1424
1805
  return fail('ResTarget', node);
1425
1806
  }
1807
+
1426
1808
  ['RowExpr'](node, context = {}) {
1427
1809
  if (node.row_format === 'COERCE_IMPLICIT_CAST') {
1428
1810
  return parens(this.list(node.args, ', ', '', context));
1429
1811
  }
1812
+
1430
1813
  return format('ROW(%s)', this.list(node.args, ', ', '', context));
1431
1814
  }
1815
+
1432
1816
  ['ExplainStmt'](node, context = {}) {
1433
1817
  const output = [];
1434
1818
  output.push('EXPLAIN');
1819
+
1435
1820
  if (node.options) {
1436
1821
  output.push('(');
1437
1822
  output.push(this.list(node.options, ', ', '', 'explain'));
1438
1823
  output.push(')');
1439
1824
  }
1825
+
1440
1826
  output.push(this.deparse(node.query, context));
1441
1827
  return output.join(' ');
1442
1828
  }
1829
+
1443
1830
  ['SelectStmt'](node, context = {}) {
1444
1831
  const output = [];
1832
+
1445
1833
  if (node.withClause) {
1446
1834
  output.push(this.WithClause(node.withClause, context));
1447
1835
  }
1836
+
1448
1837
  if (node.op === 'SETOP_NONE') {
1449
1838
  // VALUES select's don't get SELECT
1450
1839
  if (node.valuesLists == null) {
@@ -1452,54 +1841,67 @@ export default class Deparser {
1452
1841
  }
1453
1842
  } else {
1454
1843
  output.push(parens(this.SelectStmt(node.larg, context)));
1844
+
1455
1845
  switch (node.op) {
1456
1846
  case 'SETOP_NONE':
1457
1847
  output.push('NONE');
1458
1848
  break;
1849
+
1459
1850
  case 'SETOP_UNION':
1460
1851
  output.push('UNION');
1461
1852
  break;
1853
+
1462
1854
  case 'SETOP_INTERSECT':
1463
1855
  output.push('INTERSECT');
1464
1856
  break;
1857
+
1465
1858
  case 'SETOP_EXCEPT':
1466
1859
  output.push('EXCEPT');
1467
1860
  break;
1861
+
1468
1862
  default:
1469
1863
  throw new Error('bad SelectStmt op');
1470
1864
  }
1865
+
1471
1866
  if (node.all) {
1472
1867
  output.push('ALL');
1473
1868
  }
1869
+
1474
1870
  output.push(parens(this.SelectStmt(node.rarg, context)));
1475
1871
  }
1872
+
1476
1873
  if (node.distinctClause) {
1477
1874
  const distinctClause = unwrapList(node.distinctClause);
1478
- if (!isEmptyObject(distinctClause[0])
1479
- // new change distinctClause can be {}
1875
+
1876
+ if (!isEmptyObject(distinctClause[0]) // new change distinctClause can be {}
1480
1877
  ) {
1481
- output.push('DISTINCT ON');
1482
- const clause = distinctClause.map(e => this.deparse(e, 'select')).join(`,${NEWLINE_CHAR}`);
1483
- output.push(`(${clause})`);
1484
- } else {
1878
+ output.push('DISTINCT ON');
1879
+ const clause = distinctClause.map(e => this.deparse(e, 'select')).join(`,${NEWLINE_CHAR}`);
1880
+ output.push(`(${clause})`);
1881
+ } else {
1485
1882
  output.push('DISTINCT');
1486
1883
  }
1487
1884
  }
1885
+
1488
1886
  if (node.targetList) {
1489
1887
  output.push(indent(unwrapList(node.targetList).map(e => this.deparse(e, 'select')).join(`,${NEWLINE_CHAR}`)));
1490
1888
  }
1889
+
1491
1890
  if (node.intoClause) {
1492
1891
  output.push('INTO');
1493
1892
  output.push(indent(this.IntoClause(node.intoClause, context)));
1494
1893
  }
1894
+
1495
1895
  if (node.fromClause) {
1496
1896
  output.push('FROM');
1497
1897
  output.push(indent(unwrapList(node.fromClause).map(e => this.deparse(e, 'from')).join(`,${NEWLINE_CHAR}`)));
1498
1898
  }
1899
+
1499
1900
  if (node.whereClause) {
1500
1901
  output.push('WHERE');
1501
1902
  output.push(indent(this.deparse(node.whereClause, context)));
1502
1903
  }
1904
+
1503
1905
  if (node.valuesLists) {
1504
1906
  output.push('VALUES');
1505
1907
  const lists = unwrapList(node.valuesLists).map(list => {
@@ -1507,87 +1909,112 @@ export default class Deparser {
1507
1909
  });
1508
1910
  output.push(lists.join(', '));
1509
1911
  }
1912
+
1510
1913
  if (node.groupClause) {
1511
1914
  output.push('GROUP BY');
1512
1915
  output.push(indent(unwrapList(node.groupClause).map(e => this.deparse(e, 'group')).join(`,${NEWLINE_CHAR}`)));
1513
1916
  }
1917
+
1514
1918
  if (node.havingClause) {
1515
1919
  output.push('HAVING');
1516
1920
  output.push(indent(this.deparse(node.havingClause, context)));
1517
1921
  }
1922
+
1518
1923
  if (node.windowClause) {
1519
1924
  output.push('WINDOW');
1520
1925
  const windows = [];
1521
1926
  const windowClause = unwrapList(node.windowClause);
1927
+
1522
1928
  for (let i = 0; i < windowClause.length; i++) {
1523
1929
  const w = windowClause[i];
1524
1930
  const window = [];
1931
+
1525
1932
  if (w.WindowDef.name) {
1526
1933
  window.push(this.quote(w.WindowDef.name) + ' AS');
1527
1934
  }
1935
+
1528
1936
  window.push(parens(this.deparse(w, 'window')));
1529
1937
  windows.push(window.join(' '));
1530
1938
  }
1939
+
1531
1940
  output.push(windows.join(', '));
1532
1941
  }
1942
+
1533
1943
  if (node.sortClause) {
1534
1944
  output.push('ORDER BY');
1535
1945
  output.push(indent(unwrapList(node.sortClause).map(e => this.deparse(e, 'sort')).join(`,${NEWLINE_CHAR}`)));
1536
1946
  }
1947
+
1537
1948
  if (node.limitCount) {
1538
1949
  output.push('LIMIT');
1539
1950
  output.push(indent(this.deparse(node.limitCount, context)));
1540
1951
  }
1952
+
1541
1953
  if (node.limitOffset) {
1542
1954
  output.push('OFFSET');
1543
1955
  output.push(indent(this.deparse(node.limitOffset, context)));
1544
1956
  }
1957
+
1545
1958
  if (node.lockingClause) {
1546
1959
  node.lockingClause.forEach(item => {
1547
1960
  return output.push(this.deparse(item, context));
1548
1961
  });
1549
1962
  }
1963
+
1550
1964
  return output.join(' ');
1551
1965
  }
1966
+
1552
1967
  ['TruncateStmt'](node, context = {}) {
1553
1968
  const output = ['TRUNCATE TABLE'];
1554
1969
  output.push(this.list(node.relations, ', ', '', 'truncate'));
1970
+
1555
1971
  if (node.restart_seqs) {
1556
1972
  output.push('RESTART IDENTITY');
1557
1973
  }
1974
+
1558
1975
  if (node.behavior === 'DROP_CASCADE') {
1559
1976
  output.push('CASCADE');
1560
1977
  }
1978
+
1561
1979
  return output.join(' ');
1562
1980
  }
1981
+
1563
1982
  ['AlterDefaultPrivilegesStmt'](node, context = {}) {
1564
1983
  const output = [];
1565
1984
  output.push('ALTER DEFAULT PRIVILEGES');
1566
1985
  const options = unwrapList(dotty.get(node, 'options'));
1986
+
1567
1987
  if (options) {
1568
1988
  const elem = options.find(el => el.hasOwnProperty('DefElem'));
1569
1989
  const elemDefElemArg = unwrapList(elem.DefElem.arg);
1990
+
1570
1991
  if (elem.DefElem.defname === 'schemas') {
1571
1992
  output.push('IN SCHEMA');
1572
1993
  output.push(elemDefElemArg[0].String.str);
1573
1994
  }
1995
+
1574
1996
  if (elem.DefElem.defname === 'roles') {
1575
1997
  output.push('FOR ROLE');
1576
1998
  const roleSpec = elemDefElemArg[0];
1577
1999
  output.push(this.deparse(roleSpec, context));
1578
2000
  }
2001
+
1579
2002
  output.push(NEWLINE_CHAR);
1580
2003
  }
2004
+
1581
2005
  output.push(this.GrantStmt(node.action, context));
1582
2006
  return output.join(' ');
1583
2007
  }
2008
+
1584
2009
  ['AlterTableStmt'](node, context = {}) {
1585
2010
  const output = [];
1586
2011
  const ctx = Object.assign({}, context);
1587
2012
  output.push('ALTER');
2013
+
1588
2014
  if (node.relkind === 'OBJECT_TABLE') {
1589
2015
  output.push('TABLE');
1590
2016
  const inh = dotty.get(node, 'relation.inh');
2017
+
1591
2018
  if (!inh) {
1592
2019
  output.push('ONLY');
1593
2020
  }
@@ -1596,32 +2023,40 @@ export default class Deparser {
1596
2023
  } else {
1597
2024
  fail('AlterTableStmt', node);
1598
2025
  }
2026
+
1599
2027
  if (node.missing_ok) {
1600
2028
  output.push('IF EXISTS');
1601
2029
  }
2030
+
1602
2031
  ctx.alterType = node.relkind;
1603
2032
  output.push(this.RangeVar(node.relation, ctx));
1604
2033
  output.push(this.list(node.cmds, ', ', '', ctx));
1605
2034
  return output.join(' ');
1606
2035
  }
2036
+
1607
2037
  ['AlterTableCmd'](node, context = {}) {
1608
2038
  const output = [];
1609
2039
  let subType = 'COLUMN';
2040
+
1610
2041
  if (context && context.alterType === 'OBJECT_TYPE') {
1611
2042
  subType = 'ATTRIBUTE';
1612
2043
  }
2044
+
1613
2045
  if (node.subtype === 'AT_AddColumn') {
1614
2046
  output.push('ADD');
1615
2047
  output.push(subType);
2048
+
1616
2049
  if (node.missing_ok) {
1617
2050
  output.push('IF NOT EXISTS');
1618
2051
  }
2052
+
1619
2053
  output.push(this.quote(node.name));
1620
2054
  output.push(this.deparse(node.def, context));
1621
2055
  } else if (node.subtype === 'AT_ColumnDefault') {
1622
2056
  output.push('ALTER');
1623
2057
  output.push(subType);
1624
2058
  output.push(this.quote(node.name));
2059
+
1625
2060
  if (node.def) {
1626
2061
  output.push('SET DEFAULT');
1627
2062
  output.push(this.deparse(node.def, context));
@@ -1655,6 +2090,7 @@ export default class Deparser {
1655
2090
  output.push('ALTER');
1656
2091
  output.push(this.quote(node.name));
1657
2092
  output.push('SET STORAGE');
2093
+
1658
2094
  if (node.def) {
1659
2095
  output.push(this.deparse(node.def, context));
1660
2096
  } else {
@@ -1663,9 +2099,11 @@ export default class Deparser {
1663
2099
  } else if (node.subtype === 'AT_DropColumn') {
1664
2100
  output.push('DROP');
1665
2101
  output.push(subType);
2102
+
1666
2103
  if (node.missing_ok) {
1667
2104
  output.push('IF EXISTS');
1668
2105
  }
2106
+
1669
2107
  output.push(this.quote(node.name));
1670
2108
  } else if (node.subtype === 'AT_AddConstraint') {
1671
2109
  // output.push('ADD CONSTRAINT');
@@ -1676,9 +2114,11 @@ export default class Deparser {
1676
2114
  output.push(this.quote(node.name, context));
1677
2115
  } else if (node.subtype === 'AT_DropConstraint') {
1678
2116
  output.push('DROP CONSTRAINT');
2117
+
1679
2118
  if (node.missing_ok) {
1680
2119
  output.push('IF EXISTS');
1681
2120
  }
2121
+
1682
2122
  output.push(this.quote(node.name));
1683
2123
  } else if (node.subtype === 'AT_AlterColumnType') {
1684
2124
  output.push('ALTER');
@@ -1724,8 +2164,7 @@ export default class Deparser {
1724
2164
  output.push('OF');
1725
2165
  output.push(this.deparse(node.def, context));
1726
2166
  } else if (node.subtype === 'AT_DropOf') {
1727
- output.push('NOT OF');
1728
- //output.push(this.deparse(node.def));
2167
+ output.push('NOT OF'); //output.push(this.deparse(node.def));
1729
2168
  } else if (node.subtype === 'AT_EnableRowSecurity') {
1730
2169
  output.push('ENABLE ROW LEVEL SECURITY');
1731
2170
  } else if (node.subtype === 'AT_DisableRowSecurity') {
@@ -1735,11 +2174,14 @@ export default class Deparser {
1735
2174
  } else if (node.subtype === 'AT_NoForceRowSecurity') {
1736
2175
  output.push('NO FORCE ROW SECURITY');
1737
2176
  }
2177
+
1738
2178
  if (node.behavior === 'DROP_CASCADE') {
1739
2179
  output.push('CASCADE');
1740
2180
  }
2181
+
1741
2182
  return output.join(' ');
1742
2183
  }
2184
+
1743
2185
  ['CreateEnumStmt'](node, context = {}) {
1744
2186
  const output = [];
1745
2187
  output.push('CREATE TYPE');
@@ -1757,6 +2199,7 @@ export default class Deparser {
1757
2199
  output.push(`${NEWLINE_CHAR})`);
1758
2200
  return output.join(' ');
1759
2201
  }
2202
+
1760
2203
  ['AlterEnumStmt'](node, context = {}) {
1761
2204
  const output = [];
1762
2205
  output.push('ALTER TYPE');
@@ -1766,25 +2209,31 @@ export default class Deparser {
1766
2209
  }
1767
2210
  };
1768
2211
  output.push(this.deparse(typObj, context));
2212
+
1769
2213
  if (node.newVal) {
1770
2214
  output.push('ADD VALUE');
1771
2215
  const result = node.newVal.replace(/'/g, "''");
1772
2216
  output.push(`'${result}'`);
1773
2217
  }
2218
+
1774
2219
  if (node.newValNeighbor) {
1775
2220
  if (node.newValIsAfter) {
1776
2221
  output.push('AFTER');
1777
2222
  } else {
1778
2223
  output.push('BEFORE');
1779
2224
  }
2225
+
1780
2226
  const result = node.newValNeighbor.replace(/'/g, "''");
1781
2227
  output.push(`'${result}'`);
1782
2228
  }
2229
+
1783
2230
  if (node.behavior === 'DROP_CASCADE') {
1784
2231
  output.push('CASCADE');
1785
2232
  }
2233
+
1786
2234
  return output.join(' ');
1787
2235
  }
2236
+
1788
2237
  ['AlterDomainStmt'](node, context = {}) {
1789
2238
  const output = [];
1790
2239
  output.push('ALTER DOMAIN');
@@ -1794,6 +2243,7 @@ export default class Deparser {
1794
2243
  }
1795
2244
  };
1796
2245
  output.push(this.deparse(typObj, context));
2246
+
1797
2247
  if (node.subtype === 'C') {
1798
2248
  output.push('ADD');
1799
2249
  output.push(this.deparse(node.def, context));
@@ -1806,43 +2256,56 @@ export default class Deparser {
1806
2256
  output.push('CONSTRAINT');
1807
2257
  output.push(this.quote(node.name));
1808
2258
  }
2259
+
1809
2260
  if (node.behavior === 'DROP_CASCADE') {
1810
2261
  output.push('CASCADE');
1811
2262
  }
2263
+
1812
2264
  return output.join(' ');
1813
2265
  }
2266
+
1814
2267
  ['CreateExtensionStmt'](node) {
1815
2268
  const output = [];
1816
2269
  output.push('CREATE EXTENSION');
2270
+
1817
2271
  if (node.if_not_exists) {
1818
2272
  output.push('IF NOT EXISTS');
1819
2273
  }
2274
+
1820
2275
  output.push(this.quote(node.extname));
2276
+
1821
2277
  if (node.options) {
1822
2278
  node.options.forEach(opt => {
1823
2279
  if (opt.DefElem.defname === 'cascade' && opt.DefElem.arg.Integer.ival === 1) {
1824
2280
  output.push('CASCADE');
1825
2281
  }
2282
+
1826
2283
  if (opt.DefElem.defname === 'schema') {
1827
2284
  output.push('WITH SCHEMA');
1828
2285
  output.push(this.quote(this.deparse(opt.DefElem.arg)));
1829
2286
  }
1830
2287
  });
1831
2288
  }
2289
+
1832
2290
  return output.join(' ');
1833
2291
  }
2292
+
1834
2293
  ['DropStmt'](node, context = {}) {
1835
2294
  const output = [];
1836
2295
  output.push('DROP');
1837
2296
  output.push(objtypeName(node.removeType));
2297
+
1838
2298
  if (node.missing_ok) {
1839
2299
  output.push('IF EXISTS');
1840
2300
  }
2301
+
1841
2302
  const stmts = [];
1842
2303
  const objects = unwrapList(node.objects);
2304
+
1843
2305
  for (let s = 0; s < objects.length; s++) {
1844
2306
  const children = unwrapList(objects[s]);
1845
2307
  const stmt = [];
2308
+
1846
2309
  if (node.removeType === 'OBJECT_TABLE' || node.removeType === 'OBJECT_CONVERSION' || node.removeType === 'OBJECT_COLLATION' || node.removeType === 'OBJECT_MATVIEW' || node.removeType === 'OBJECT_INDEX' || node.removeType === 'OBJECT_FOREIGN_TABLE') {
1847
2310
  if (children.length === 1) {
1848
2311
  stmt.push(this.quote(this.deparse(children[0])));
@@ -1898,15 +2361,14 @@ export default class Deparser {
1898
2361
  stmt.push(this.listQuotes(children, '.'));
1899
2362
  } else {
1900
2363
  throw new Error('bad drop value stmt: ' + JSON.stringify(node, null, 2));
1901
- }
1902
- // } else if (node.removeType === 'OBJECT_OPERATOR') {
2364
+ } // } else if (node.removeType === 'OBJECT_OPERATOR') {
2365
+
1903
2366
  } else if (node.removeType === 'OBJECT_CAST') {
1904
2367
  stmt.push('(');
1905
2368
  stmt.push(this.deparse(children[0], context));
1906
2369
  stmt.push('AS');
1907
2370
  stmt.push(this.deparse(children[1], context));
1908
- stmt.push(')');
1909
- // } else if (node.removeType === 'OBJECT_OPERATOR') {
2371
+ stmt.push(')'); // } else if (node.removeType === 'OBJECT_OPERATOR') {
1910
2372
  // stmt.push(this.deparse(children, 'noquotes')); // in this case children is not an array
1911
2373
  } else if (node.removeType === 'OBJECT_AGGREGATE') {
1912
2374
  stmt.push(this.deparse(children, context)); // in this case children is not an array
@@ -1925,146 +2387,181 @@ export default class Deparser {
1925
2387
  } else {
1926
2388
  throw new Error('bad drop stmt: ' + JSON.stringify(node, null, 2));
1927
2389
  }
2390
+
1928
2391
  stmts.push(stmt.join(' '));
1929
2392
  }
2393
+
1930
2394
  output.push(stmts.join(','));
2395
+
1931
2396
  if (node.behavior === 'DROP_CASCADE') {
1932
2397
  output.push('CASCADE');
1933
2398
  }
2399
+
1934
2400
  return output.join(' ');
1935
2401
  }
2402
+
1936
2403
  ['CreatePolicyStmt'](node, context = {}) {
1937
2404
  const output = [];
1938
2405
  output.push('CREATE POLICY');
1939
2406
  output.push(this.quote(node.policy_name));
2407
+
1940
2408
  if (node.table) {
1941
2409
  output.push('ON');
1942
2410
  output.push(this.RangeVar(node.table, context));
1943
2411
  }
1944
- if (node.permissive) {
1945
- // permissive is the default!
2412
+
2413
+ if (node.permissive) {// permissive is the default!
1946
2414
  } else {
1947
2415
  output.push('AS');
1948
2416
  output.push('RESTRICTIVE');
1949
2417
  }
2418
+
1950
2419
  if (node.cmd_name) {
1951
2420
  output.push('FOR');
1952
2421
  output.push(node.cmd_name.toUpperCase());
1953
2422
  }
2423
+
1954
2424
  output.push('TO');
1955
2425
  output.push(this.list(node.roles));
2426
+
1956
2427
  if (node.qual) {
1957
2428
  output.push('USING');
1958
2429
  output.push('(');
1959
2430
  output.push(this.deparse(node.qual, context));
1960
2431
  output.push(')');
1961
2432
  }
2433
+
1962
2434
  if (node.with_check) {
1963
2435
  output.push('WITH CHECK');
1964
2436
  output.push('(');
1965
2437
  output.push(this.deparse(node.with_check, context));
1966
2438
  output.push(')');
1967
2439
  }
2440
+
1968
2441
  return output.join(' ');
1969
2442
  }
2443
+
1970
2444
  ['AlterPolicyStmt'](node, context = {}) {
1971
2445
  const output = [];
1972
2446
  output.push('ALTER POLICY');
1973
2447
  output.push(this.quote(node.policy_name));
2448
+
1974
2449
  if (node.table) {
1975
2450
  output.push('ON');
1976
2451
  output.push(this.RangeVar(node.table, context));
1977
2452
  }
2453
+
1978
2454
  output.push('TO');
1979
2455
  output.push(this.list(node.roles));
2456
+
1980
2457
  if (node.qual) {
1981
2458
  output.push('USING');
1982
2459
  output.push('(');
1983
2460
  output.push(this.deparse(node.qual, context));
1984
2461
  output.push(')');
1985
2462
  }
2463
+
1986
2464
  if (node.with_check) {
1987
2465
  output.push('WITH CHECK');
1988
2466
  output.push('(');
1989
2467
  output.push(this.deparse(node.with_check, context));
1990
2468
  output.push(')');
1991
2469
  }
2470
+
1992
2471
  return output.join(' ');
1993
2472
  }
2473
+
1994
2474
  ['ViewStmt'](node, context = {}) {
1995
2475
  const output = [];
1996
2476
  output.push('CREATE');
1997
2477
  if (node.replace) output.push('OR REPLACE');
2478
+
1998
2479
  if (node.view.relpersistence === 't') {
1999
2480
  output.push('TEMPORARY');
2000
2481
  }
2482
+
2001
2483
  output.push('VIEW');
2002
2484
  output.push(this.RangeVar(node.view, 'view'));
2485
+
2003
2486
  if (node.aliases) {
2004
2487
  output.push('(');
2005
2488
  output.push(this.list(node.aliases, ', ', '', context));
2006
2489
  output.push(')');
2007
2490
  }
2491
+
2008
2492
  output.push('AS');
2009
2493
  output.push(this.deparse(node.query, context));
2494
+
2010
2495
  if (node.withCheckOption === 'LOCAL_CHECK_OPTION') {
2011
2496
  output.push('WITH LOCAL CHECK OPTION');
2012
2497
  } else if (node.withCheckOption === 'CASCADED_CHECK_OPTION') {
2013
2498
  output.push('WITH CASCADED CHECK OPTION');
2014
2499
  }
2500
+
2015
2501
  return output.join(' ');
2016
2502
  }
2503
+
2017
2504
  ['CreateSeqStmt'](node, context = {}) {
2018
2505
  const output = [];
2019
2506
  output.push('CREATE SEQUENCE');
2020
2507
  output.push(this.RangeVar(node.sequence, context));
2021
2508
  const options = unwrapList(node.options);
2509
+
2022
2510
  if (options && options.length) {
2023
2511
  options.forEach(opt => {
2024
2512
  output.push(this.deparse(opt, 'sequence'));
2025
2513
  });
2026
2514
  }
2515
+
2027
2516
  return output.join(' ');
2028
2517
  }
2518
+
2029
2519
  ['AlterSeqStmt'](node, context = {}) {
2030
2520
  const output = [];
2031
2521
  output.push('ALTER SEQUENCE');
2032
2522
  output.push(this.RangeVar(node.sequence, context));
2033
2523
  const options = unwrapList(node.options);
2524
+
2034
2525
  if (options && options.length) {
2035
2526
  options.forEach(opt => {
2036
2527
  output.push(this.deparse(opt, 'sequence'));
2037
2528
  });
2038
2529
  }
2530
+
2039
2531
  return output.join(' ');
2040
2532
  }
2533
+
2041
2534
  ['CreateTableAsStmt'](node, context = {}) {
2042
2535
  const output = ['CREATE'];
2043
2536
  const relpersistence = dotty.get(node, 'into.rel.relpersistence');
2537
+
2044
2538
  if (node.relkind === 'OBJECT_MATVIEW') {
2045
2539
  output.push('MATERIALIZED VIEW');
2046
2540
  } else if (relpersistence !== 't') {
2047
2541
  output.push('TABLE');
2542
+
2048
2543
  if (node.if_not_exists) {
2049
2544
  output.push('IF NOT EXISTS');
2050
2545
  }
2051
2546
  }
2547
+
2052
2548
  output.push(this.IntoClause(node.into, context));
2053
2549
  output.push('AS');
2054
2550
  output.push(this.deparse(node.query, context));
2055
2551
  return output.join(' ');
2056
2552
  }
2553
+
2057
2554
  ['CreateTrigStmt'](node, context = {}) {
2058
2555
  const output = [];
2059
2556
  output.push('CREATE');
2557
+
2060
2558
  if (node.isconstraint) {
2061
2559
  output.push('CONSTRAINT');
2062
2560
  }
2561
+
2063
2562
  output.push('TRIGGER');
2064
2563
  output.push(this.quote(node.trigname));
2065
- output.push(NEWLINE_CHAR);
2066
-
2067
- // int16 timing; BEFORE, AFTER, or INSTEAD
2564
+ output.push(NEWLINE_CHAR); // int16 timing; BEFORE, AFTER, or INSTEAD
2068
2565
 
2069
2566
  if (node.timing === 64) {
2070
2567
  output.push('INSTEAD OF');
@@ -2072,15 +2569,13 @@ export default class Deparser {
2072
2569
  output.push('BEFORE');
2073
2570
  } else {
2074
2571
  output.push('AFTER');
2075
- }
2076
-
2077
- // int16 events; "OR" of INSERT/UPDATE/DELETE/TRUNCATE
2078
-
2572
+ } // int16 events; "OR" of INSERT/UPDATE/DELETE/TRUNCATE
2079
2573
  // 4 = 0b000100 (insert)
2080
2574
  // 8 = 0b001000 (delete)
2081
2575
  // 16 = 0b010000 (update)
2082
2576
  // 32 = 0b100000 (TRUNCATE)
2083
2577
 
2578
+
2084
2579
  const TRIGGER_EVENTS = {
2085
2580
  INSERT: 4,
2086
2581
  DELETE: 8,
@@ -2088,32 +2583,36 @@ export default class Deparser {
2088
2583
  TRUNCATE: 32
2089
2584
  };
2090
2585
  const events = [];
2586
+
2091
2587
  if ((TRIGGER_EVENTS.INSERT & node.events) === TRIGGER_EVENTS.INSERT) {
2092
2588
  events.push('INSERT');
2093
2589
  }
2590
+
2094
2591
  if ((TRIGGER_EVENTS.UPDATE & node.events) === TRIGGER_EVENTS.UPDATE) {
2095
2592
  events.push('UPDATE');
2096
2593
  }
2594
+
2097
2595
  if ((TRIGGER_EVENTS.DELETE & node.events) === TRIGGER_EVENTS.DELETE) {
2098
2596
  events.push('DELETE');
2099
2597
  }
2598
+
2100
2599
  if ((TRIGGER_EVENTS.TRUNCATE & node.events) === TRIGGER_EVENTS.TRUNCATE) {
2101
2600
  events.push('TRUNCATE');
2102
- }
2601
+ } // events
2103
2602
 
2104
- // events
2105
- output.push(events.join(' OR '));
2106
2603
 
2107
- // columns
2604
+ output.push(events.join(' OR ')); // columns
2605
+
2108
2606
  if (node.columns) {
2109
2607
  output.push('OF');
2110
2608
  output.push(this.list(node.columns, ', ', '', context));
2111
- }
2609
+ } // ON
2610
+
2112
2611
 
2113
- // ON
2114
2612
  output.push('ON');
2115
2613
  output.push(this.RangeVar(node.relation, context));
2116
2614
  output.push(NEWLINE_CHAR);
2615
+
2117
2616
  if (node.transitionRels) {
2118
2617
  output.push('REFERENCING');
2119
2618
  node.transitionRels.forEach(({
@@ -2125,23 +2624,27 @@ export default class Deparser {
2125
2624
  output.push(`OLD TABLE AS ${TriggerTransition.name}`);
2126
2625
  }
2127
2626
  });
2128
- }
2627
+ } // opts
2628
+
2129
2629
 
2130
- // opts
2131
2630
  if (node.deferrable || node.initdeferred) {
2132
2631
  if (node.deferrable) {
2133
2632
  output.push('DEFERRABLE');
2134
2633
  }
2634
+
2135
2635
  if (node.deferrable) {
2136
2636
  output.push('INITIALLY DEFERRED');
2137
2637
  }
2638
+
2138
2639
  output.push(NEWLINE_CHAR);
2139
2640
  }
2641
+
2140
2642
  if (node.row) {
2141
2643
  output.push(`FOR EACH ROW${NEWLINE_CHAR}`);
2142
2644
  } else {
2143
2645
  output.push(`FOR EACH STATEMENT${NEWLINE_CHAR}`);
2144
2646
  }
2647
+
2145
2648
  if (node.whenClause) {
2146
2649
  output.push('WHEN');
2147
2650
  output.push('(');
@@ -2149,56 +2652,69 @@ export default class Deparser {
2149
2652
  output.push(')');
2150
2653
  output.push(NEWLINE_CHAR);
2151
2654
  }
2655
+
2152
2656
  output.push('EXECUTE PROCEDURE');
2153
2657
  output.push(this.listQuotes(node.funcname).split(',').join('.'));
2154
2658
  output.push('(');
2155
2659
  let args = [];
2660
+
2156
2661
  if (node.args) {
2157
2662
  args = unwrapList(node.args);
2158
- }
2159
- // seems that it's only parsing strings?
2663
+ } // seems that it's only parsing strings?
2664
+
2665
+
2160
2666
  args = args.map(arg => {
2161
2667
  if (arg.String !== undefined && arg.String.str !== undefined) {
2162
2668
  return `'${arg.String.str}'`;
2163
2669
  }
2670
+
2164
2671
  return this.deparse(arg, context);
2165
2672
  }).filter(a => a);
2166
2673
  output.push(args.join(','));
2167
2674
  output.push(')');
2168
2675
  return output.join(' ');
2169
2676
  }
2677
+
2170
2678
  ['CreateDomainStmt'](node, context = {}) {
2171
2679
  const output = [];
2172
2680
  output.push('CREATE DOMAIN');
2173
2681
  output.push(this.list(node.domainname, '.', '', context));
2174
2682
  output.push('AS');
2175
2683
  output.push(this.TypeName(node.typeName, context));
2684
+
2176
2685
  if (node.constraints) {
2177
2686
  output.push(this.list(node.constraints, ', ', '', context));
2178
2687
  }
2688
+
2179
2689
  return output.join(' ');
2180
2690
  }
2691
+
2181
2692
  ['CreateStmt'](node, context = {}) {
2182
2693
  const output = [];
2183
2694
  const relpersistence = dotty.get(node, 'relation.relpersistence');
2695
+
2184
2696
  if (relpersistence === 't') {
2185
2697
  output.push('CREATE');
2186
2698
  } else {
2187
2699
  output.push('CREATE TABLE');
2700
+
2188
2701
  if (node.if_not_exists) {
2189
2702
  output.push('IF NOT EXISTS');
2190
2703
  }
2191
2704
  }
2705
+
2192
2706
  output.push(this.RangeVar(node.relation, context));
2193
2707
  output.push(`(${NEWLINE_CHAR}`);
2194
2708
  output.push(this.list(node.tableElts, `,${NEWLINE_CHAR}`, TAB_CHAR, context));
2195
2709
  output.push(`${NEWLINE_CHAR})`);
2710
+
2196
2711
  if (node.hasOwnProperty('inhRelations')) {
2197
2712
  output.push('INHERITS');
2198
2713
  output.push('(');
2199
2714
  output.push(this.list(node.inhRelations, ', ', '', context));
2200
2715
  output.push(')');
2201
2716
  }
2717
+
2202
2718
  if (node.options) {
2203
2719
  // TODO was this deprecated?
2204
2720
  node.options.forEach(opt => {
@@ -2211,27 +2727,34 @@ export default class Deparser {
2211
2727
  }
2212
2728
  });
2213
2729
  }
2730
+
2214
2731
  return output.join(' ');
2215
2732
  }
2733
+
2216
2734
  ['ConstraintStmt'](node) {
2217
2735
  const output = [];
2218
2736
  const constraint = getConstraintFromConstrType(node.contype);
2737
+
2219
2738
  if (node.conname) {
2220
2739
  output.push('CONSTRAINT');
2221
2740
  output.push(node.conname);
2741
+
2222
2742
  if (!node.pktable) {
2223
2743
  output.push(constraint);
2224
2744
  }
2225
2745
  } else if (node.contype === 'CONSTR_IDENTITY') {
2226
2746
  // IDENTITY
2227
2747
  output.push('GENERATED');
2748
+
2228
2749
  if (node.generated_when == 'a') {
2229
2750
  output.push('ALWAYS AS');
2230
2751
  } else {
2231
2752
  output.push('BY DEFAULT AS');
2232
2753
  }
2754
+
2233
2755
  output.push('IDENTITY');
2234
2756
  const options = unwrapList(node.options);
2757
+
2235
2758
  if (options && options.length) {
2236
2759
  output.push('(');
2237
2760
  output.push(this.list(options, ' ', '', 'generated'));
@@ -2239,21 +2762,26 @@ export default class Deparser {
2239
2762
  }
2240
2763
  } else if (node.contype === 'CONSTR_GENERATED') {
2241
2764
  output.push('GENERATED');
2765
+
2242
2766
  if (node.generated_when == 'a') {
2243
2767
  output.push('ALWAYS AS');
2244
2768
  }
2245
2769
  } else {
2246
2770
  output.push(constraint);
2247
2771
  }
2772
+
2248
2773
  return output.join(' ');
2249
2774
  }
2775
+
2250
2776
  ['ReferenceConstraint'](node, context = {}) {
2251
2777
  const output = [];
2778
+
2252
2779
  if (node.pk_attrs && node.fk_attrs) {
2253
2780
  if (node.conname) {
2254
2781
  output.push('CONSTRAINT');
2255
2782
  output.push(node.conname);
2256
2783
  }
2784
+
2257
2785
  output.push('FOREIGN KEY');
2258
2786
  output.push('(');
2259
2787
  output.push(this.listQuotes(node.fk_attrs));
@@ -2274,6 +2802,7 @@ export default class Deparser {
2274
2802
  output.push('CONSTRAINT');
2275
2803
  output.push(node.conname);
2276
2804
  }
2805
+
2277
2806
  output.push('FOREIGN KEY');
2278
2807
  output.push('(');
2279
2808
  output.push(this.listQuotes(node.fk_attrs));
@@ -2284,23 +2813,29 @@ export default class Deparser {
2284
2813
  output.push(this.ConstraintStmt(node, context));
2285
2814
  output.push(this.RangeVar(node.pktable, context));
2286
2815
  }
2816
+
2287
2817
  return output.join(' ');
2288
2818
  }
2819
+
2289
2820
  ['ExclusionConstraint'](node, context = {}) {
2290
2821
  const output = [];
2822
+
2291
2823
  function getExclusionGroup(nde) {
2292
2824
  const exclusions = unwrapList(nde.exclusions);
2293
2825
  const a = exclusions.map(excl => {
2294
2826
  const firstExcl = unwrapList(excl)[0];
2827
+
2295
2828
  if (firstExcl.IndexElem.name) {
2296
2829
  return firstExcl.IndexElem.name;
2297
2830
  }
2831
+
2298
2832
  return firstExcl.IndexElem.expr ? this.deparse(firstExcl.IndexElem.expr, context) : null;
2299
2833
  });
2300
2834
  const b = exclusions.map(excl => this.deparse(unwrapList(unwrapList(excl)[1])[0], context));
2301
2835
  const stmts = a.map((_v, i) => `${a[i]} WITH ${b[i]}`);
2302
2836
  return stmts.join(', ');
2303
2837
  }
2838
+
2304
2839
  if (node.exclusions && node.access_method) {
2305
2840
  output.push('USING');
2306
2841
  output.push(node.access_method);
@@ -2308,107 +2843,139 @@ export default class Deparser {
2308
2843
  output.push(getExclusionGroup.call(this, node));
2309
2844
  output.push(')');
2310
2845
  }
2846
+
2311
2847
  return output.join(' ');
2312
2848
  }
2849
+
2313
2850
  ['Constraint'](node, context = {}) {
2314
2851
  const output = [];
2852
+
2315
2853
  if (node.contype === 'CONSTR_FOREIGN') {
2316
2854
  output.push(this.ReferenceConstraint(node, context));
2317
2855
  } else {
2318
2856
  output.push(this.ConstraintStmt(node, context));
2319
2857
  }
2858
+
2320
2859
  if (node.keys) {
2321
2860
  output.push('(');
2322
2861
  output.push(this.listQuotes(node.keys));
2323
2862
  output.push(')');
2324
2863
  }
2864
+
2325
2865
  if (node.raw_expr) {
2326
2866
  output.push('(');
2327
2867
  output.push(this.deparse(node.raw_expr, context));
2328
2868
  output.push(')');
2869
+
2329
2870
  if (node.contype == 'CONSTR_GENERATED') {
2330
2871
  output.push('STORED');
2331
2872
  }
2332
2873
  }
2874
+
2333
2875
  if (node.fk_del_action) {
2334
2876
  switch (node.fk_del_action) {
2335
2877
  case 'r':
2336
2878
  output.push('ON DELETE RESTRICT');
2337
2879
  break;
2880
+
2338
2881
  case 'c':
2339
2882
  output.push('ON DELETE CASCADE');
2340
2883
  break;
2884
+
2341
2885
  case 'n':
2342
2886
  output.push('ON DELETE SET NULL');
2343
2887
  break;
2888
+
2344
2889
  case 'd':
2345
2890
  output.push('ON DELETE SET DEFAULT');
2346
2891
  break;
2892
+
2347
2893
  case 'a':
2348
2894
  // output.push('ON DELETE NO ACTION');
2349
2895
  break;
2896
+
2350
2897
  default:
2351
2898
  }
2352
2899
  }
2900
+
2353
2901
  if (node.fk_upd_action) {
2354
2902
  switch (node.fk_upd_action) {
2355
2903
  case 'r':
2356
2904
  output.push('ON UPDATE RESTRICT');
2357
2905
  break;
2906
+
2358
2907
  case 'c':
2359
2908
  output.push('ON UPDATE CASCADE');
2360
2909
  break;
2910
+
2361
2911
  case 'n':
2362
2912
  output.push('ON UPDATE SET NULL');
2363
2913
  break;
2914
+
2364
2915
  case 'd':
2365
2916
  output.push('ON UPDATE SET DEFAULT');
2366
2917
  break;
2918
+
2367
2919
  case 'a':
2368
2920
  // output.push('ON UPDATE NO ACTION');
2369
2921
  break;
2922
+
2370
2923
  default:
2371
2924
  }
2372
2925
  }
2926
+
2373
2927
  if (node.fk_matchtype === 'f') {
2374
2928
  output.push('MATCH FULL');
2375
2929
  }
2930
+
2376
2931
  if (node.is_no_inherit === true) {
2377
2932
  output.push('NO INHERIT');
2378
2933
  }
2934
+
2379
2935
  if (node.skip_validation === true) {
2380
2936
  output.push('NOT VALID');
2381
2937
  }
2938
+
2382
2939
  if (node.contype === 'CONSTR_EXCLUSION') {
2383
2940
  output.push(this.ExclusionConstraint(node, context));
2384
2941
  }
2942
+
2385
2943
  if (node.deferrable) {
2386
2944
  output.push('deferrable');
2387
2945
  }
2946
+
2388
2947
  return output.join(' ');
2389
2948
  }
2949
+
2390
2950
  ['AccessPriv'](node) {
2391
2951
  const output = [];
2952
+
2392
2953
  if (node.priv_name) {
2393
2954
  output.push(node.priv_name.toUpperCase());
2394
2955
  } else {
2395
2956
  output.push('ALL');
2396
2957
  }
2958
+
2397
2959
  if (node.cols) {
2398
2960
  output.push('(');
2399
2961
  output.push(this.listQuotes(node.cols));
2400
2962
  output.push(')');
2401
2963
  }
2964
+
2402
2965
  return output.join(' ');
2403
2966
  }
2967
+
2404
2968
  ['VariableSetStmt'](node) {
2405
2969
  switch (node.kind) {
2406
2970
  case 'VAR_SET_VALUE':
2407
2971
  return format('SET %s%s = %s', node.is_local ? 'LOCAL ' : '', node.name, this.deparseNodes(node.args, 'simple').join(', '));
2972
+
2408
2973
  case 'VAR_SET_DEFAULT':
2409
2974
  return format('SET %s TO DEFAULT', node.name);
2975
+
2410
2976
  case 'VAR_SET_CURRENT':
2411
2977
  return format('SET %s FROM CURRENT', node.name);
2978
+
2412
2979
  case 'VAR_SET_MULTI':
2413
2980
  {
2414
2981
  const name = {
@@ -2417,17 +2984,22 @@ export default class Deparser {
2417
2984
  }[node.name];
2418
2985
  return format('SET %s %s', name, this.deparseNodes(node.args, 'simple').join(', '));
2419
2986
  }
2987
+
2420
2988
  case 'VAR_RESET':
2421
2989
  return format('RESET %s', node.name);
2990
+
2422
2991
  case 'VAR_RESET_ALL':
2423
2992
  return 'RESET ALL';
2993
+
2424
2994
  default:
2425
2995
  return fail('VariableSetKind', node);
2426
2996
  }
2427
2997
  }
2998
+
2428
2999
  ['VariableShowStmt'](node) {
2429
3000
  return format('SHOW %s', node.name);
2430
3001
  }
3002
+
2431
3003
  ['FuncWithArgs'](node, context = {}) {
2432
3004
  const output = [];
2433
3005
  output.push(this.deparse(unwrapList(node.funcname)[0], context));
@@ -2436,38 +3008,50 @@ export default class Deparser {
2436
3008
  output.push(')');
2437
3009
  return output.join(' ');
2438
3010
  }
3011
+
2439
3012
  ['FunctionParameter'](node, context = {}) {
2440
3013
  const output = [];
3014
+
2441
3015
  if (node.mode === 'FUNC_PARAM_VARIADIC') {
2442
3016
  output.push('VARIADIC');
2443
3017
  }
3018
+
2444
3019
  if (node.mode === 'FUNC_PARAM_OUT') {
2445
3020
  output.push('OUT');
2446
3021
  }
3022
+
2447
3023
  if (node.mode === 'FUNC_PARAM_INOUT') {
2448
3024
  output.push('INOUT');
2449
3025
  }
3026
+
2450
3027
  output.push(node.name);
2451
3028
  output.push(this.TypeName(node.argType, context));
3029
+
2452
3030
  if (node.defexpr) {
2453
3031
  output.push('DEFAULT');
2454
3032
  output.push(this.deparse(node.defexpr, context));
2455
3033
  }
3034
+
2456
3035
  return output.join(' ');
2457
3036
  }
3037
+
2458
3038
  ['CreateFunctionStmt'](node, context = {}) {
2459
3039
  const output = [];
2460
3040
  output.push('CREATE');
3041
+
2461
3042
  if (node.replace) {
2462
3043
  output.push('OR REPLACE');
2463
3044
  }
3045
+
2464
3046
  output.push('FUNCTION');
2465
3047
  output.push(unwrapList(node.funcname).map(name => this.deparse(name, context)).join('.'));
2466
3048
  output.push('(');
2467
3049
  let parameters = [];
3050
+
2468
3051
  if (node.parameters) {
2469
3052
  parameters = unwrapList(node.parameters);
2470
3053
  }
3054
+
2471
3055
  const parametersList = parameters.filter(({
2472
3056
  FunctionParameter
2473
3057
  }) => FunctionParameter.mode === 'FUNC_PARAM_VARIADIC' || FunctionParameter.mode === 'FUNC_PARAM_OUT' || FunctionParameter.mode === 'FUNC_PARAM_INOUT' || FunctionParameter.mode === 'FUNC_PARAM_IN');
@@ -2476,6 +3060,7 @@ export default class Deparser {
2476
3060
  const returns = parameters.filter(({
2477
3061
  FunctionParameter
2478
3062
  }) => FunctionParameter.mode === 'FUNC_PARAM_TABLE');
3063
+
2479
3064
  if (returns.length > 0) {
2480
3065
  output.push('RETURNS');
2481
3066
  output.push('TABLE');
@@ -2486,151 +3071,204 @@ export default class Deparser {
2486
3071
  output.push('RETURNS');
2487
3072
  output.push(this.TypeName(node.returnType, context));
2488
3073
  }
3074
+
2489
3075
  node.options.forEach((option, i) => {
2490
3076
  if (option && option.DefElem) {
2491
3077
  let value = '';
3078
+
2492
3079
  switch (option.DefElem.defname) {
2493
3080
  case 'as':
2494
3081
  value = this.deparse(unwrapList(option.DefElem.arg)[0], context);
2495
3082
  output.push(`AS $EOFCODE$${value}$EOFCODE$`);
2496
3083
  break;
3084
+
2497
3085
  case 'language':
2498
3086
  value = this.deparse(option.DefElem.arg, context);
2499
3087
  output.push('LANGUAGE');
2500
3088
  output.push(value);
2501
3089
  break;
3090
+
2502
3091
  case 'security':
2503
3092
  output.push('SECURITY');
2504
3093
  value = Number(option.DefElem.arg.Integer.ival);
3094
+
2505
3095
  if (value > 0) {
2506
3096
  output.push('DEFINER');
2507
3097
  } else {
2508
3098
  output.push('INVOKER');
2509
3099
  }
3100
+
2510
3101
  break;
3102
+
2511
3103
  case 'leakproof':
2512
3104
  value = Number(option.DefElem.arg.Integer.ival);
3105
+
2513
3106
  if (value > 0) {
2514
3107
  output.push('LEAKPROOF');
2515
3108
  }
3109
+
2516
3110
  break;
3111
+
2517
3112
  case 'window':
2518
3113
  value = Number(option.DefElem.arg.Integer.ival);
3114
+
2519
3115
  if (value > 0) {
2520
3116
  output.push('WINDOW');
2521
3117
  }
3118
+
2522
3119
  break;
3120
+
2523
3121
  case 'strict':
2524
3122
  value = Number(option.DefElem.arg.Integer.ival);
3123
+
2525
3124
  if (value > 0) {
2526
3125
  output.push('STRICT');
2527
3126
  } else {
2528
3127
  output.push('CALLED ON NULL INPUT');
2529
3128
  }
3129
+
2530
3130
  break;
3131
+
2531
3132
  case 'set':
2532
3133
  output.push(this.deparse(option, context));
2533
3134
  break;
3135
+
2534
3136
  case 'volatility':
2535
3137
  value = this.deparse(option.DefElem.arg, context);
2536
3138
  output.push(value.toUpperCase());
2537
3139
  break;
3140
+
2538
3141
  default:
2539
3142
  }
2540
3143
  }
2541
3144
  });
2542
3145
  return output.join(' ');
2543
3146
  }
3147
+
2544
3148
  ['CreateSchemaStmt'](node) {
2545
3149
  const output = [];
2546
3150
  output.push('CREATE');
3151
+
2547
3152
  if (node.replace) {
2548
3153
  output.push('OR REPLACE');
2549
3154
  }
3155
+
2550
3156
  output.push('SCHEMA');
3157
+
2551
3158
  if (node.if_not_exists) {
2552
3159
  output.push('IF NOT EXISTS');
2553
3160
  }
3161
+
2554
3162
  output.push(node.schemaname);
2555
3163
  return output.join(' ');
2556
3164
  }
3165
+
2557
3166
  ['RoleSpec'](node) {
2558
3167
  switch (node.roletype) {
2559
3168
  case 'ROLESPEC_CSTRING':
2560
3169
  return this.quote(node.rolename);
3170
+
2561
3171
  case 'ROLESPEC_CURRENT_USER':
2562
3172
  return 'CURRENT_USER';
3173
+
2563
3174
  case 'ROLESPEC_SESSION_USER':
2564
3175
  return 'SESSION_USER';
3176
+
2565
3177
  case 'ROLESPEC_PUBLIC':
2566
3178
  return 'PUBLIC';
3179
+
2567
3180
  default:
2568
3181
  return fail('RoleSpec', node);
2569
3182
  }
2570
3183
  }
3184
+
2571
3185
  ['GrantStmt'](node) {
2572
3186
  const output = [];
3187
+
2573
3188
  const getTypeFromNode = nodeObj => {
2574
3189
  switch (nodeObj.objtype) {
2575
3190
  case 'OBJECT_TABLE':
2576
3191
  if (nodeObj.targtype === 'ACL_TARGET_ALL_IN_SCHEMA') {
2577
3192
  return 'ALL TABLES IN SCHEMA';
2578
3193
  }
3194
+
2579
3195
  if (nodeObj.targtype === 'ACL_TARGET_DEFAULTS') {
2580
3196
  return 'TABLES';
2581
- }
2582
- // todo could be view
3197
+ } // todo could be view
3198
+
3199
+
2583
3200
  return 'TABLE';
3201
+
2584
3202
  case 'OBJECT_SEQUENCE':
2585
3203
  if (nodeObj.targtype === 'ACL_TARGET_ALL_IN_SCHEMA') {
2586
3204
  return 'ALL SEQUENCES IN SCHEMA';
2587
3205
  }
3206
+
2588
3207
  if (nodeObj.targtype === 'ACL_TARGET_DEFAULTS') {
2589
3208
  return 'SEQUENCES';
2590
3209
  }
3210
+
2591
3211
  return 'SEQUENCE';
3212
+
2592
3213
  case 'OBJECT_DATABASE':
2593
3214
  return 'DATABASE';
3215
+
2594
3216
  case 'OBJECT_DOMAIN':
2595
3217
  return 'DOMAIN';
3218
+
2596
3219
  case 'OBJECT_FDW':
2597
3220
  return 'FOREIGN DATA WRAPPER';
3221
+
2598
3222
  case 'OBJECT_FOREIGN_SERVER':
2599
3223
  return 'FOREIGN SERVER';
3224
+
2600
3225
  case 'OBJECT_FUNCTION':
2601
3226
  if (nodeObj.targtype === 'ACL_TARGET_ALL_IN_SCHEMA') {
2602
3227
  return 'ALL FUNCTIONS IN SCHEMA';
2603
3228
  }
3229
+
2604
3230
  if (nodeObj.targtype === 'ACL_TARGET_DEFAULTS') {
2605
3231
  return 'FUNCTIONS';
2606
3232
  }
3233
+
2607
3234
  return 'FUNCTION';
3235
+
2608
3236
  case 'OBJECT_LANGUAGE':
2609
3237
  return 'LANGUAGE';
3238
+
2610
3239
  case 'OBJECT_LARGEOBJECT':
2611
3240
  return 'LARGE OBJECT';
3241
+
2612
3242
  case 'OBJECT_SCHEMA':
2613
3243
  return 'SCHEMA';
3244
+
2614
3245
  case 'OBJECT_TABLESPACE':
2615
3246
  return 'TABLESPACE';
3247
+
2616
3248
  case 'OBJECT_TYPE':
2617
3249
  return 'TYPE';
3250
+
2618
3251
  default:
2619
3252
  }
3253
+
2620
3254
  return fail('GrantStmt', node);
2621
3255
  };
3256
+
2622
3257
  if (node.objtype !== 'OBJECT_COLUMN') {
2623
3258
  if (!node.is_grant) {
2624
3259
  output.push('REVOKE');
3260
+
2625
3261
  if (node.grant_option) {
2626
3262
  output.push('GRANT OPTION');
2627
3263
  output.push('FOR');
2628
3264
  }
3265
+
2629
3266
  if (node.privileges) {
2630
3267
  output.push(this.list(node.privileges));
2631
3268
  } else {
2632
3269
  output.push('ALL');
2633
3270
  }
3271
+
2634
3272
  output.push('ON');
2635
3273
  output.push(getTypeFromNode(node));
2636
3274
  output.push(this.list(node.objects));
@@ -2638,28 +3276,35 @@ export default class Deparser {
2638
3276
  output.push(this.list(node.grantees));
2639
3277
  } else {
2640
3278
  output.push('GRANT');
3279
+
2641
3280
  if (node.privileges) {
2642
3281
  output.push(this.list(node.privileges));
2643
3282
  } else {
2644
3283
  output.push('ALL');
2645
3284
  }
3285
+
2646
3286
  output.push('ON');
2647
3287
  output.push(getTypeFromNode(node));
2648
3288
  output.push(this.list(node.objects));
2649
3289
  output.push('TO');
2650
3290
  output.push(this.list(node.grantees));
3291
+
2651
3292
  if (node.grant_option) {
2652
3293
  output.push('WITH GRANT OPTION');
2653
3294
  }
2654
3295
  }
3296
+
2655
3297
  if (node.behavior === 'DROP_CASCADE') {
2656
3298
  output.push('CASCADE');
2657
3299
  }
2658
3300
  }
3301
+
2659
3302
  return output.join(' ');
2660
3303
  }
3304
+
2661
3305
  ['GrantRoleStmt'](node, context = {}) {
2662
3306
  const output = [];
3307
+
2663
3308
  if (!node.is_grant) {
2664
3309
  output.push('REVOKE');
2665
3310
  output.push(this.list(node.granted_roles, ', ', '', context));
@@ -2671,291 +3316,385 @@ export default class Deparser {
2671
3316
  output.push('TO');
2672
3317
  output.push(this.list(node.grantee_roles, ', ', '', context));
2673
3318
  }
3319
+
2674
3320
  if (node.admin_opt) {
2675
3321
  output.push('WITH ADMIN OPTION');
2676
3322
  }
3323
+
2677
3324
  return output.join(' ');
2678
3325
  }
3326
+
2679
3327
  ['CreateRoleStmt'](node, context = {}) {
2680
3328
  const output = [];
3329
+
2681
3330
  const roleOption = (nodeObj, i, val1, val2) => {
2682
3331
  const val = Number(dotty.get(unwrapList(nodeObj.options), `${i}.DefElem.arg.Integer.ival`));
3332
+
2683
3333
  if (val > 0) {
2684
3334
  output.push(val1);
2685
3335
  } else {
2686
3336
  output.push(val2);
2687
3337
  }
2688
3338
  };
3339
+
2689
3340
  output.push('CREATE');
3341
+
2690
3342
  switch (node.stmt_type) {
2691
3343
  case 'ROLESTMT_USER':
2692
3344
  output.push('USER');
2693
3345
  break;
3346
+
2694
3347
  case 'ROLESTMT_GROUP':
2695
3348
  output.push('GROUP');
2696
3349
  break;
3350
+
2697
3351
  default:
2698
3352
  output.push('ROLE');
2699
3353
  }
3354
+
2700
3355
  output.push(`"${node.role}"`);
3356
+
2701
3357
  if (node.options) {
2702
3358
  const options = unwrapList(node.options);
2703
3359
  const opts = dotty.search(options, '*.DefElem.defname');
2704
- if (opts.length === 1 && opts[0] === 'addroleto') {
2705
- // only one case
3360
+
3361
+ if (opts.length === 1 && opts[0] === 'addroleto') {// only one case
2706
3362
  } else {
2707
3363
  output.push('WITH');
2708
3364
  }
3365
+
2709
3366
  opts.forEach((option, i) => {
2710
3367
  let value = '';
3368
+
2711
3369
  switch (option) {
2712
3370
  case 'canlogin':
2713
3371
  roleOption(node, i, 'LOGIN', 'NOLOGIN');
2714
3372
  break;
3373
+
2715
3374
  case 'addroleto':
2716
3375
  output.push('IN ROLE');
2717
3376
  output.push(dotty.search(flatten(dotty.search(options, `${i}.DefElem.arg`).map(unwrapList)), '*.RoleSpec.rolename').join(','));
2718
3377
  break;
3378
+
2719
3379
  case 'password':
2720
3380
  output.push('PASSWORD');
2721
3381
  value = dotty.get(options, `${i}.DefElem.arg.String.str`);
2722
3382
  output.push(`'${value}'`);
2723
3383
  break;
3384
+
2724
3385
  case 'adminmembers':
2725
3386
  output.push('ADMIN');
2726
3387
  output.push(this.list(options[i].DefElem.arg, ', ', '', context));
2727
3388
  break;
3389
+
2728
3390
  case 'rolemembers':
2729
3391
  output.push('USER');
2730
3392
  output.push(this.list(options[i].DefElem.arg, ', ', '', context));
2731
3393
  break;
3394
+
2732
3395
  case 'createdb':
2733
3396
  roleOption(node, i, 'CREATEDB', 'NOCREATEDB');
2734
3397
  break;
3398
+
2735
3399
  case 'isreplication':
2736
3400
  roleOption(node, i, 'REPLICATION', 'NOREPLICATION');
2737
3401
  break;
3402
+
2738
3403
  case 'bypassrls':
2739
3404
  roleOption(node, i, 'BYPASSRLS', 'NOBYPASSRLS');
2740
3405
  break;
3406
+
2741
3407
  case 'inherit':
2742
3408
  roleOption(node, i, 'INHERIT', 'NOINHERIT');
2743
3409
  break;
3410
+
2744
3411
  case 'superuser':
2745
3412
  roleOption(node, i, 'SUPERUSER', 'NOSUPERUSER');
2746
3413
  break;
3414
+
2747
3415
  case 'createrole':
2748
3416
  roleOption(node, i, 'CREATEROLE', 'NOCREATEROLE');
2749
3417
  break;
3418
+
2750
3419
  case 'validUntil':
2751
3420
  output.push('VALID UNTIL');
2752
3421
  value = dotty.get(options[i], `DefElem.arg.String.str`);
2753
3422
  output.push(`'${value}'`);
2754
3423
  break;
3424
+
2755
3425
  default:
2756
3426
  }
2757
3427
  });
2758
3428
  }
3429
+
2759
3430
  return output.join(' ');
2760
3431
  }
3432
+
2761
3433
  ['TransactionStmt'](node, context = {}) {
2762
3434
  const output = [];
3435
+
2763
3436
  const begin = nodeOpts => {
2764
3437
  const options = unwrapList(nodeOpts.options);
2765
3438
  const opts = options ? dotty.search(options, '*.DefElem.defname') : [];
3439
+
2766
3440
  if (opts.includes('transaction_read_only')) {
2767
3441
  const index = opts.indexOf('transaction_read_only');
2768
3442
  const obj = options[index];
2769
3443
  let set = false;
2770
3444
  const flag = Number(this.deparse(dotty.get(obj, 'DefElem.arg'), context));
3445
+
2771
3446
  if (flag > 0) {
2772
3447
  set = true;
2773
3448
  }
3449
+
2774
3450
  if (set) {
2775
3451
  return 'BEGIN TRANSACTION READ ONLY';
2776
3452
  }
3453
+
2777
3454
  return 'BEGIN TRANSACTION READ WRITE';
2778
3455
  }
3456
+
2779
3457
  if (opts.includes('transaction_isolation')) {
2780
3458
  const index = opts.indexOf('transaction_isolation');
2781
3459
  const obj = options[index];
2782
3460
  const lopts = this.deparse(dotty.get(obj, 'DefElem.arg'), context).replace(/['"]+/g, '');
2783
3461
  return `BEGIN TRANSACTION ISOLATION LEVEL ${lopts.toUpperCase()}`;
2784
3462
  }
3463
+
2785
3464
  return 'BEGIN';
2786
3465
  };
3466
+
2787
3467
  const start = nodeOpts => {
2788
3468
  const options = unwrapList(nodeOpts.options);
2789
3469
  const opts = options ? dotty.search(options, '*.DefElem.defname') : [];
3470
+
2790
3471
  if (opts.includes('transaction_read_only')) {
2791
3472
  const index = opts.indexOf('transaction_read_only');
2792
3473
  const obj = options[index];
2793
3474
  let set = false;
2794
3475
  const flag = Number(this.deparse(dotty.get(obj, 'DefElem.arg'), context));
3476
+
2795
3477
  if (flag > 0) {
2796
3478
  set = true;
2797
3479
  }
3480
+
2798
3481
  if (set) {
2799
3482
  return 'START TRANSACTION READ ONLY';
2800
3483
  }
3484
+
2801
3485
  return 'START TRANSACTION READ WRITE';
2802
3486
  }
3487
+
2803
3488
  return 'START TRANSACTION';
2804
3489
  };
3490
+
2805
3491
  const nodeOptions = unwrapList(node.options);
3492
+
2806
3493
  switch (node.kind) {
2807
3494
  case 'TRANS_STMT_BEGIN':
2808
3495
  return begin(node);
3496
+
2809
3497
  case 'TRANS_STMT_START':
2810
3498
  return start(node);
3499
+
2811
3500
  case 'TRANS_STMT_COMMIT':
2812
3501
  return 'COMMIT';
3502
+
2813
3503
  case 'TRANS_STMT_ROLLBACK':
2814
3504
  return 'ROLLBACK';
3505
+
2815
3506
  case 'TRANS_STMT_SAVEPOINT':
2816
3507
  output.push('SAVEPOINT');
2817
3508
  output.push(this.deparse(nodeOptions[0].DefElem.arg, context));
2818
3509
  break;
3510
+
2819
3511
  case 'TRANS_STMT_RELEASE':
2820
3512
  output.push('RELEASE SAVEPOINT');
2821
3513
  output.push(this.deparse(nodeOptions[0].DefElem.arg, context));
2822
3514
  break;
3515
+
2823
3516
  case 'TRANS_STMT_ROLLBACK_TO':
2824
3517
  output.push('ROLLBACK TO');
2825
3518
  output.push(this.deparse(nodeOptions[0].DefElem.arg, context));
2826
3519
  break;
3520
+
2827
3521
  case 'TRANS_STMT_PREPARE':
2828
3522
  output.push('PREPARE TRANSACTION');
2829
3523
  output.push(`'${node.gid}'`);
2830
3524
  break;
3525
+
2831
3526
  case 'TRANS_STMT_COMMIT_PREPARED':
2832
3527
  output.push('COMMIT PREPARED');
2833
3528
  output.push(`'${node.gid}'`);
2834
3529
  break;
3530
+
2835
3531
  case 'TRANS_STMT_ROLLBACK_PREPARED':
2836
3532
  output.push('ROLLBACK PREPARED');
2837
3533
  output.push(`'${node.gid}'`);
2838
3534
  break;
3535
+
2839
3536
  default:
2840
3537
  }
3538
+
2841
3539
  return output.join(' ');
2842
3540
  }
3541
+
2843
3542
  ['SortBy'](node, context = {}) {
2844
3543
  const output = [];
2845
3544
  output.push(this.deparse(node.node, context));
3545
+
2846
3546
  switch (node.sortby_dir) {
2847
3547
  case 'SORTBY_ASC':
2848
3548
  output.push('ASC');
2849
3549
  break;
3550
+
2850
3551
  case 'SORTBY_DESC':
2851
3552
  output.push('DESC');
2852
3553
  break;
3554
+
2853
3555
  case 'SORTBY_USING':
2854
3556
  output.push(`USING ${this.deparseNodes(node.useOp, context)}`);
2855
3557
  break;
3558
+
2856
3559
  case 'SORTBY_DEFAULT':
2857
3560
  break;
3561
+
2858
3562
  default:
2859
3563
  return fail('SortBy', node);
2860
3564
  }
3565
+
2861
3566
  if (node.sortby_nulls === 'SORTBY_NULLS_FIRST') {
2862
3567
  output.push('NULLS FIRST');
2863
3568
  }
3569
+
2864
3570
  if (node.sortby_nulls === 'SORTBY_NULLS_LAST') {
2865
3571
  output.push('NULLS LAST');
2866
3572
  }
3573
+
2867
3574
  return output.join(' ');
2868
3575
  }
3576
+
2869
3577
  ['ObjectWithArgs'](node, context = {}) {
2870
3578
  const output = [];
3579
+
2871
3580
  if (context === 'noquotes') {
2872
3581
  output.push(this.list(node.objname, ', ', '', context));
2873
3582
  } else {
2874
3583
  output.push(this.listQuotes(node.objname, '.'));
2875
3584
  }
3585
+
2876
3586
  const objargs = unwrapList(node.objargs);
3587
+
2877
3588
  if (objargs && objargs.length) {
2878
3589
  output.push('(');
2879
3590
  output.push(objargs.map(arg => {
2880
3591
  if (isEmptyObject(arg)) {
2881
3592
  return 'NONE';
2882
3593
  }
3594
+
2883
3595
  return this.deparse(arg, context);
2884
3596
  }).join(','));
2885
3597
  output.push(')');
2886
3598
  } else if (!node.args_unspecified) {
2887
3599
  output.push('()');
2888
3600
  }
3601
+
2889
3602
  return output.join(' ');
2890
3603
  }
3604
+
2891
3605
  ['String'](node) {
2892
3606
  return node.str;
2893
3607
  }
3608
+
2894
3609
  ['SubLink'](node, context = {}) {
2895
3610
  switch (true) {
2896
3611
  case node.subLinkType === 'EXISTS_SUBLINK':
2897
3612
  return format('EXISTS (%s)', this.deparse(node.subselect, context));
3613
+
2898
3614
  case node.subLinkType === 'ALL_SUBLINK':
2899
3615
  return format('%s %s ALL (%s)', this.deparse(node.testexpr, context), this.deparse(node.operName[0], context), this.deparse(node.subselect, context));
3616
+
2900
3617
  case node.subLinkType === 'ANY_SUBLINK' && !(node.operName != null):
2901
3618
  return format('%s IN (%s)', this.deparse(node.testexpr, context), this.deparse(node.subselect, context));
3619
+
2902
3620
  case node.subLinkType === 'ANY_SUBLINK':
2903
3621
  return format('%s %s ANY (%s)', this.deparse(node.testexpr, context), this.deparse(node.operName[0], context), this.deparse(node.subselect, context));
3622
+
2904
3623
  case node.subLinkType === 'ROWCOMPARE_SUBLINK':
2905
3624
  return format('%s %s (%s)', this.deparse(node.testexpr, context), this.deparse(node.operName[0], context), this.deparse(node.subselect, context));
3625
+
2906
3626
  case node.subLinkType === 'EXPR_SUBLINK':
2907
3627
  return format('(%s)', this.deparse(node.subselect, context));
3628
+
2908
3629
  case node.subLinkType === 'MULTIEXPR_SUBLINK':
2909
3630
  // TODO(zhm) what is this?
2910
3631
  return fail('SubLink', node);
2911
3632
  // MULTIEXPR_SUBLINK
2912
3633
  // format('(%s)', @deparse(node.subselect))
3634
+
2913
3635
  case node.subLinkType === 'ARRAY_SUBLINK':
2914
3636
  return format('ARRAY (%s)', this.deparse(node.subselect, context));
3637
+
2915
3638
  default:
2916
3639
  return fail('SubLink', node);
2917
3640
  }
2918
3641
  }
3642
+
2919
3643
  ['TypeCast'](node, context = {}) {
2920
3644
  const type = this.TypeName(node.typeName, context);
2921
3645
  let arg = this.deparse(node.arg, context);
3646
+
2922
3647
  if (node.arg !== undefined && node.arg.A_Expr !== undefined) {
2923
3648
  arg = format('(%s)', arg);
2924
3649
  }
3650
+
2925
3651
  if (type === 'boolean') {
2926
3652
  const value = dotty.get(node, 'arg.A_Const.val.String.str');
3653
+
2927
3654
  if (value === 'f') {
2928
3655
  return 'FALSE';
2929
3656
  }
3657
+
2930
3658
  if (value === 't') {
2931
3659
  return 'TRUE';
2932
3660
  }
2933
3661
  }
3662
+
2934
3663
  return format('%s::%s', arg, type);
2935
3664
  }
3665
+
2936
3666
  ['TypeName'](node, context = {}) {
2937
3667
  const names = unwrapList(node.names);
3668
+
2938
3669
  if (names[names.length - 1].String.str === 'interval') {
2939
3670
  return this.deparseInterval(node);
2940
3671
  }
3672
+
2941
3673
  const output = [];
3674
+
2942
3675
  if (node.setof) {
2943
3676
  output.push('SETOF');
2944
3677
  }
3678
+
2945
3679
  let args = null;
3680
+
2946
3681
  if (node.typmods != null) {
2947
3682
  args = unwrapList(node.typmods).map(item => {
2948
3683
  return this.deparse(item, context);
2949
3684
  });
2950
3685
  }
3686
+
2951
3687
  const type = [];
2952
3688
  type.push(this.type(names, args && args.join(', ')));
3689
+
2953
3690
  if (node.arrayBounds != null) {
2954
3691
  type.push('[]');
2955
3692
  }
3693
+
2956
3694
  output.push(type.join(''));
2957
3695
  return output.join(' ');
2958
3696
  }
3697
+
2959
3698
  ['CaseWhen'](node, context = {}) {
2960
3699
  const output = ['WHEN'];
2961
3700
  output.push(this.deparse(node.expr, context));
@@ -2963,20 +3702,26 @@ export default class Deparser {
2963
3702
  output.push(this.deparse(node.result, context));
2964
3703
  return output.join(' ');
2965
3704
  }
3705
+
2966
3706
  ['WindowDef'](node, context = {}) {
2967
3707
  const output = [];
3708
+
2968
3709
  if (context !== 'window') {
2969
3710
  if (node.name) {
2970
3711
  output.push(node.name);
2971
3712
  }
2972
3713
  }
3714
+
2973
3715
  const empty = !(node.partitionClause != null) && !(node.orderClause != null);
2974
3716
  const frameOptions = this.deparseFrameOptions(node.frameOptions, node.refname, node.startOffset, node.endOffset);
3717
+
2975
3718
  if (empty && context !== 'window' && !(node.name != null) && frameOptions.length === 0) {
2976
3719
  return '()';
2977
3720
  }
3721
+
2978
3722
  const windowParts = [];
2979
3723
  let useParens = false;
3724
+
2980
3725
  if (node.partitionClause) {
2981
3726
  const partition = ['PARTITION BY'];
2982
3727
  const clause = unwrapList(node.partitionClause).map(item => this.deparse(item, context));
@@ -2984,6 +3729,7 @@ export default class Deparser {
2984
3729
  windowParts.push(partition.join(' '));
2985
3730
  useParens = true;
2986
3731
  }
3732
+
2987
3733
  if (node.orderClause) {
2988
3734
  windowParts.push('ORDER BY');
2989
3735
  const orders = unwrapList(node.orderClause).map(item => {
@@ -2992,38 +3738,49 @@ export default class Deparser {
2992
3738
  windowParts.push(orders.join(', '));
2993
3739
  useParens = true;
2994
3740
  }
3741
+
2995
3742
  if (frameOptions.length) {
2996
3743
  useParens = true;
2997
3744
  windowParts.push(frameOptions);
2998
3745
  }
3746
+
2999
3747
  if (useParens && context !== 'window') {
3000
3748
  return output.join(' ') + ' (' + windowParts.join(' ') + ')';
3001
3749
  }
3750
+
3002
3751
  return output.join(' ') + windowParts.join(' ');
3003
3752
  }
3753
+
3004
3754
  ['WithClause'](node, context = {}) {
3005
3755
  const output = ['WITH'];
3756
+
3006
3757
  if (node.recursive) {
3007
3758
  output.push('RECURSIVE');
3008
3759
  }
3760
+
3009
3761
  output.push(this.list(node.ctes, ', ', '', context));
3010
3762
  return output.join(' ');
3011
3763
  }
3764
+
3012
3765
  ['CopyStmt'](node, context = {}) {
3013
3766
  const output = ['COPY'];
3014
3767
  output.push('(' + this.deparse(node.query, context) + ')');
3015
3768
  output.push('TO');
3016
3769
  output.push(`'${node.filename}'`);
3017
3770
  const options = unwrapList(node.options);
3771
+
3018
3772
  if (options?.length > 0 && options[0].DefElem.defname === 'format') {
3019
3773
  output.push(`(FORMAT '${this.deparse(options[0].DefElem.arg)}')`);
3020
3774
  }
3775
+
3021
3776
  return output.join(' ');
3022
3777
  }
3778
+
3023
3779
  ['CallStmt'](node, context = {}) {
3024
3780
  const output = ['CALL'];
3025
3781
  output.push(this.deparse(unwrapList(node.funccall.funcname)[0]));
3026
3782
  const funccallArgs = unwrapList(node.funccall.args);
3783
+
3027
3784
  if (funccallArgs && funccallArgs.length) {
3028
3785
  // we have arguments
3029
3786
  output.push('(' + this.list(funccallArgs, ', ', '', context) + ')');
@@ -3031,29 +3788,65 @@ export default class Deparser {
3031
3788
  // just close parens
3032
3789
  output.push('()');
3033
3790
  }
3791
+
3034
3792
  return output.join(' ');
3035
3793
  }
3794
+
3036
3795
  deparseFrameOptions(options, refName, startOffset, endOffset) {
3037
3796
  // https://github.com/pganalyze/libpg_query/blob/442b1748d06364ecd3779bc558899176c02efaf0/src/postgres/include/nodes/parsenodes.h#L505-L522
3038
- const FRAMEOPTION_NONDEFAULT = 0x00001; /* any specified? */
3039
- const FRAMEOPTION_RANGE = 0x00002; /* RANGE behavior */
3040
- const FRAMEOPTION_ROWS = 0x00004; /* ROWS behavior */
3041
- const FRAMEOPTION_GROUPS = 0x00008; /* GROUPS behavior */
3042
- const FRAMEOPTION_BETWEEN = 0x00010; /* BETWEEN given? */
3043
- const FRAMEOPTION_START_UNBOUNDED_PRECEDING = 0x00020; /* start is U. P. */
3044
- const FRAMEOPTION_END_UNBOUNDED_PRECEDING = 0x00040; /* (disallowed) */
3045
- const FRAMEOPTION_START_UNBOUNDED_FOLLOWING = 0x00080; /* (disallowed) */
3046
- const FRAMEOPTION_END_UNBOUNDED_FOLLOWING = 0x00100; /* end is U. F. */
3047
- const FRAMEOPTION_START_CURRENT_ROW = 0x00200; /* start is C. R. */
3048
- const FRAMEOPTION_END_CURRENT_ROW = 0x00400; /* end is C. R. */
3049
- const FRAMEOPTION_START_OFFSET_PRECEDING = 0x00800; /* start is O. P. */
3050
- const FRAMEOPTION_END_OFFSET_PRECEDING = 0x01000; /* end is O. P. */
3051
- const FRAMEOPTION_START_OFFSET_FOLLOWING = 0x02000; /* start is O. F. */
3052
- const FRAMEOPTION_END_OFFSET_FOLLOWING = 0x04000; /* end is O. F. */
3053
- const FRAMEOPTION_EXCLUDE_CURRENT_ROW = 0x08000; /* omit C.R. */
3054
- const FRAMEOPTION_EXCLUDE_GROUP = 0x10000; /* omit C.R. & peers */
3055
- const FRAMEOPTION_EXCLUDE_TIES = 0x20000; /* omit C.R.'s peers */
3797
+ const FRAMEOPTION_NONDEFAULT = 0x00001;
3798
+ /* any specified? */
3799
+
3800
+ const FRAMEOPTION_RANGE = 0x00002;
3801
+ /* RANGE behavior */
3802
+
3803
+ const FRAMEOPTION_ROWS = 0x00004;
3804
+ /* ROWS behavior */
3805
+
3806
+ const FRAMEOPTION_GROUPS = 0x00008;
3807
+ /* GROUPS behavior */
3808
+
3809
+ const FRAMEOPTION_BETWEEN = 0x00010;
3810
+ /* BETWEEN given? */
3811
+
3812
+ const FRAMEOPTION_START_UNBOUNDED_PRECEDING = 0x00020;
3813
+ /* start is U. P. */
3056
3814
 
3815
+ const FRAMEOPTION_END_UNBOUNDED_PRECEDING = 0x00040;
3816
+ /* (disallowed) */
3817
+
3818
+ const FRAMEOPTION_START_UNBOUNDED_FOLLOWING = 0x00080;
3819
+ /* (disallowed) */
3820
+
3821
+ const FRAMEOPTION_END_UNBOUNDED_FOLLOWING = 0x00100;
3822
+ /* end is U. F. */
3823
+
3824
+ const FRAMEOPTION_START_CURRENT_ROW = 0x00200;
3825
+ /* start is C. R. */
3826
+
3827
+ const FRAMEOPTION_END_CURRENT_ROW = 0x00400;
3828
+ /* end is C. R. */
3829
+
3830
+ const FRAMEOPTION_START_OFFSET_PRECEDING = 0x00800;
3831
+ /* start is O. P. */
3832
+
3833
+ const FRAMEOPTION_END_OFFSET_PRECEDING = 0x01000;
3834
+ /* end is O. P. */
3835
+
3836
+ const FRAMEOPTION_START_OFFSET_FOLLOWING = 0x02000;
3837
+ /* start is O. F. */
3838
+
3839
+ const FRAMEOPTION_END_OFFSET_FOLLOWING = 0x04000;
3840
+ /* end is O. F. */
3841
+
3842
+ const FRAMEOPTION_EXCLUDE_CURRENT_ROW = 0x08000;
3843
+ /* omit C.R. */
3844
+
3845
+ const FRAMEOPTION_EXCLUDE_GROUP = 0x10000;
3846
+ /* omit C.R. & peers */
3847
+
3848
+ const FRAMEOPTION_EXCLUDE_TIES = 0x20000;
3849
+ /* omit C.R.'s peers */
3057
3850
  // const FRAMEOPTION_START_OFFSET =
3058
3851
  // FRAMEOPTION_START_OFFSET_PRECEDING | FRAMEOPTION_START_OFFSET_FOLLOWING;
3059
3852
  // const FRAMEOPTION_END_OFFSET =
@@ -3062,7 +3855,6 @@ export default class Deparser {
3062
3855
  // FRAMEOPTION_EXCLUDE_CURRENT_ROW |
3063
3856
  // FRAMEOPTION_EXCLUDE_GROUP |
3064
3857
  // FRAMEOPTION_EXCLUDE_TIES;
3065
-
3066
3858
  // const FRAMEOPTION_DEFAULTS =
3067
3859
  // FRAMEOPTION_RANGE |
3068
3860
  // FRAMEOPTION_START_UNBOUNDED_PRECEDING |
@@ -3071,66 +3863,86 @@ export default class Deparser {
3071
3863
  if (!(options & FRAMEOPTION_NONDEFAULT)) {
3072
3864
  return '';
3073
3865
  }
3866
+
3074
3867
  const output = [];
3868
+
3075
3869
  if (refName != null) {
3076
3870
  output.push(refName);
3077
3871
  }
3872
+
3078
3873
  if (options & FRAMEOPTION_RANGE) {
3079
3874
  output.push('RANGE');
3080
3875
  }
3876
+
3081
3877
  if (options & FRAMEOPTION_ROWS) {
3082
3878
  output.push('ROWS');
3083
3879
  }
3880
+
3084
3881
  const between = options & FRAMEOPTION_BETWEEN;
3882
+
3085
3883
  if (between) {
3086
3884
  output.push('BETWEEN');
3087
3885
  }
3886
+
3088
3887
  if (options & FRAMEOPTION_START_UNBOUNDED_PRECEDING) {
3089
3888
  output.push('UNBOUNDED PRECEDING');
3090
3889
  }
3890
+
3091
3891
  if (options & FRAMEOPTION_START_UNBOUNDED_FOLLOWING) {
3092
3892
  output.push('UNBOUNDED FOLLOWING');
3093
3893
  }
3894
+
3094
3895
  if (options & FRAMEOPTION_START_CURRENT_ROW) {
3095
3896
  output.push('CURRENT ROW');
3096
3897
  }
3898
+
3097
3899
  if (options & FRAMEOPTION_START_OFFSET_PRECEDING) {
3098
3900
  output.push(this.deparse(startOffset) + ' PRECEDING');
3099
3901
  }
3902
+
3100
3903
  if (options & FRAMEOPTION_START_OFFSET_FOLLOWING) {
3101
3904
  output.push(this.deparse(startOffset) + ' FOLLOWING');
3102
3905
  }
3906
+
3103
3907
  if (between) {
3104
3908
  output.push('AND');
3909
+
3105
3910
  if (options & FRAMEOPTION_END_UNBOUNDED_PRECEDING) {
3106
3911
  output.push('UNBOUNDED PRECEDING');
3107
3912
  }
3913
+
3108
3914
  if (options & FRAMEOPTION_END_UNBOUNDED_FOLLOWING) {
3109
3915
  output.push('UNBOUNDED FOLLOWING');
3110
3916
  }
3917
+
3111
3918
  if (options & FRAMEOPTION_END_CURRENT_ROW) {
3112
3919
  output.push('CURRENT ROW');
3113
3920
  }
3921
+
3114
3922
  if (options & FRAMEOPTION_END_OFFSET_PRECEDING) {
3115
3923
  output.push(this.deparse(endOffset) + ' PRECEDING');
3116
3924
  }
3925
+
3117
3926
  if (options & FRAMEOPTION_END_OFFSET_FOLLOWING) {
3118
3927
  output.push(this.deparse(endOffset) + ' FOLLOWING');
3119
3928
  }
3120
3929
  }
3930
+
3121
3931
  return output.join(' ');
3122
3932
  }
3933
+
3123
3934
  deparseInterval(node) {
3124
3935
  const type = ['interval'];
3936
+
3125
3937
  if (node.arrayBounds != null) {
3126
3938
  type.push('[]');
3127
3939
  }
3940
+
3128
3941
  if (node.typmods) {
3129
3942
  const nodeTypmods = unwrapList(node.typmods);
3130
3943
  const typmods = nodeTypmods.map(item => this.deparse(item));
3131
- let intervals = this.interval(typmods[0]);
3944
+ let intervals = this.interval(typmods[0]); // SELECT interval(0) '1 day 01:23:45.6789'
3132
3945
 
3133
- // SELECT interval(0) '1 day 01:23:45.6789'
3134
3946
  if (nodeTypmods[0] && nodeTypmods[0].A_Const && nodeTypmods[0].A_Const.val.Integer.ival === 32767 && nodeTypmods[1] && nodeTypmods[1].A_Const != null) {
3135
3947
  intervals = [`(${nodeTypmods[1].A_Const.val.Integer.ival})`];
3136
3948
  } else {
@@ -3138,13 +3950,17 @@ export default class Deparser {
3138
3950
  if (part === 'second' && typmods.length === 2) {
3139
3951
  return 'second(' + typmods[typmods.length - 1] + ')';
3140
3952
  }
3953
+
3141
3954
  return part;
3142
3955
  });
3143
3956
  }
3957
+
3144
3958
  type.push(intervals.join(' to '));
3145
3959
  }
3960
+
3146
3961
  return type.join(' ');
3147
3962
  }
3963
+
3148
3964
  interval(mask) {
3149
3965
  // ported from https://github.com/lfittl/pg_query/blob/master/lib/pg_query/deparse/interval.rb
3150
3966
  if (this.MASKS == null) {
@@ -3180,9 +3996,11 @@ export default class Deparser {
3180
3996
  28: 'DTZMOD'
3181
3997
  };
3182
3998
  }
3999
+
3183
4000
  if (this.BITS == null) {
3184
4001
  this.BITS = inverted(this.MASKS);
3185
4002
  }
4003
+
3186
4004
  if (this.INTERVALS == null) {
3187
4005
  this.INTERVALS = {};
3188
4006
  this.INTERVALS[1 << this.BITS.YEAR] = ['year'];
@@ -3197,12 +4015,13 @@ export default class Deparser {
3197
4015
  this.INTERVALS[1 << this.BITS.DAY | 1 << this.BITS.HOUR | 1 << this.BITS.MINUTE | 1 << this.BITS.SECOND] = ['day', 'second'];
3198
4016
  this.INTERVALS[1 << this.BITS.HOUR | 1 << this.BITS.MINUTE] = ['hour', 'minute'];
3199
4017
  this.INTERVALS[1 << this.BITS.HOUR | 1 << this.BITS.MINUTE | 1 << this.BITS.SECOND] = ['hour', 'second'];
3200
- this.INTERVALS[1 << this.BITS.MINUTE | 1 << this.BITS.SECOND] = ['minute', 'second'];
3201
-
3202
- // utils/timestamp.h
4018
+ this.INTERVALS[1 << this.BITS.MINUTE | 1 << this.BITS.SECOND] = ['minute', 'second']; // utils/timestamp.h
3203
4019
  // #define INTERVAL_FULL_RANGE (0x7FFF)
4020
+
3204
4021
  this.INTERVALS[this.INTERVAL_FULL_RANGE = '32767'] = [];
3205
4022
  }
4023
+
3206
4024
  return this.INTERVALS[mask.toString()];
3207
4025
  }
4026
+
3208
4027
  }