prettier-plugin-postgresql 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +197 -0
- package/bin/dotnet/Google.Protobuf.dll +0 -0
- package/bin/dotnet/PgScriptDom.deps.json +95 -0
- package/bin/dotnet/PgScriptDom.dll +0 -0
- package/bin/dotnet/PrettierSql.Core.dll +0 -0
- package/bin/dotnet/libpg_query.dylib +0 -0
- package/bin/dotnet/pgsqlparser.dll +0 -0
- package/bin/dotnet/runtimes/linux-x64/native/libpg_query.so +0 -0
- package/bin/dotnet/runtimes/osx-arm64/native/libpg_query.dylib +0 -0
- package/bin/dotnet/runtimes/osx-x64/native/libpg_query.dylib +0 -0
- package/bin/dotnet/runtimes/win-x64/native/libpg_query.dll +0 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/language.d.ts +3 -0
- package/dist/language.d.ts.map +1 -0
- package/dist/language.js +9 -0
- package/dist/language.js.map +1 -0
- package/dist/parser/index.d.ts +5 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +58 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/printer/expressions.d.ts +8 -0
- package/dist/printer/expressions.d.ts.map +1 -0
- package/dist/printer/expressions.js +623 -0
- package/dist/printer/expressions.js.map +1 -0
- package/dist/printer/helpers.d.ts +6 -0
- package/dist/printer/helpers.d.ts.map +1 -0
- package/dist/printer/helpers.js +18 -0
- package/dist/printer/helpers.js.map +1 -0
- package/dist/printer/index.d.ts +4 -0
- package/dist/printer/index.d.ts.map +1 -0
- package/dist/printer/index.js +23 -0
- package/dist/printer/index.js.map +1 -0
- package/dist/printer/statements.d.ts +11 -0
- package/dist/printer/statements.d.ts.map +1 -0
- package/dist/printer/statements.js +1533 -0
- package/dist/printer/statements.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,1533 @@
|
|
|
1
|
+
import { keyword, hardline, join, indent, group, softline, softSep, hardSep, getDensity, } from '@prettier-sql/core/printer/utils';
|
|
2
|
+
import { prop, propArr, propStr, propBool, rangeVarName, qualifiedName } from './helpers.js';
|
|
3
|
+
import { printExpression, printWindowDef } from './expressions.js';
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Script root
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
export function printScript(node, opts) {
|
|
8
|
+
const statements = propArr(node, 'statements');
|
|
9
|
+
if (statements.length === 0)
|
|
10
|
+
return '';
|
|
11
|
+
const docs = statements.map((s) => printStatementWithComments(s, opts));
|
|
12
|
+
return [...join([hardline, hardline], docs), hardline];
|
|
13
|
+
}
|
|
14
|
+
function printStatementWithComments(node, opts) {
|
|
15
|
+
const leading = node.leadingComments;
|
|
16
|
+
const body = printStatement(node, opts);
|
|
17
|
+
const trailing = node.trailingComment ? [' ', node.trailingComment] : '';
|
|
18
|
+
if (!leading?.length)
|
|
19
|
+
return [body, trailing];
|
|
20
|
+
return [join(hardline, leading), hardline, body, trailing];
|
|
21
|
+
}
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Statement dispatcher
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
export function printStatement(node, opts) {
|
|
26
|
+
switch (node.type) {
|
|
27
|
+
case 'SelectStatement': return printSelect(node, opts);
|
|
28
|
+
case 'InsertStatement': return printInsert(node, opts);
|
|
29
|
+
case 'UpdateStatement': return printUpdate(node, opts);
|
|
30
|
+
case 'DeleteStatement': return printDelete(node, opts);
|
|
31
|
+
case 'SetOpStatement': return printSetOp(node, opts);
|
|
32
|
+
case 'ValuesStatement': return printValues(node, opts);
|
|
33
|
+
case 'CreateTableStatement': return printCreateTable(node, opts);
|
|
34
|
+
case 'AlterTableStatement': return printAlterTable(node, opts);
|
|
35
|
+
case 'CreateViewStatement': return printCreateView(node, opts);
|
|
36
|
+
case 'CreateFunctionStatement': return printCreateFunction(node, opts);
|
|
37
|
+
case 'CreateIndexStatement': return printCreateIndex(node, opts);
|
|
38
|
+
case 'DropStatement': return printDrop(node, opts);
|
|
39
|
+
case 'TruncateStatement': return printTruncate(node, opts);
|
|
40
|
+
case 'TransactionStatement': return printTransaction(node, opts);
|
|
41
|
+
case 'VariableSetStatement': return printVariableSet(node, opts);
|
|
42
|
+
case 'VariableShowStatement': return printVariableShow(node, opts);
|
|
43
|
+
case 'GrantStatement': return printGrant(node, opts);
|
|
44
|
+
case 'RevokeStatement': return printRevoke(node, opts);
|
|
45
|
+
case 'CreateRoleStatement': return printCreateRole(node, opts);
|
|
46
|
+
case 'AlterRoleStatement': return printAlterRole(node, opts);
|
|
47
|
+
case 'RenameStatement': return printRename(node, opts);
|
|
48
|
+
case 'CreateTypeStatement': return printCreateType(node, opts);
|
|
49
|
+
case 'AlterTypeStatement': return printAlterType(node, opts);
|
|
50
|
+
case 'CreateSequenceStatement': return printCreateSequence(node, opts);
|
|
51
|
+
case 'AlterSequenceStatement': return printAlterSequence(node, opts);
|
|
52
|
+
case 'CreateSchemaStatement': return printCreateSchema(node, opts);
|
|
53
|
+
case 'CreateExtensionStatement': return printCreateExtension(node, opts);
|
|
54
|
+
case 'CreateTableAsStatement': return printCreateTableAs(node, opts);
|
|
55
|
+
case 'CreateMatViewStatement': return printCreateMatView(node, opts);
|
|
56
|
+
case 'CreateTriggerStatement': return printCreateTrigger(node, opts);
|
|
57
|
+
case 'CommentStatement': return printComment(node, opts);
|
|
58
|
+
case 'CallStatement': return printCall(node, opts);
|
|
59
|
+
case 'DoStatement': return printDo(node, opts);
|
|
60
|
+
case 'MergeStatement': return printMerge(node, opts);
|
|
61
|
+
case 'AlterFunctionStatement': return printAlterFunction(node, opts);
|
|
62
|
+
case 'RefreshMatViewStatement': return printRefreshMatView(node, opts);
|
|
63
|
+
case 'SelectIntoStatement': return printSelectInto(node, opts);
|
|
64
|
+
case 'RuleStatement': return printRule(node, opts);
|
|
65
|
+
case 'CreatePolicyStatement': return printCreatePolicy(node, opts);
|
|
66
|
+
case 'AlterPolicyStatement': return printAlterPolicy(node, opts);
|
|
67
|
+
case 'DeclareCursorStatement': return printDeclareCursor(node, opts);
|
|
68
|
+
case 'FetchStatement': return printFetch(node, opts);
|
|
69
|
+
case 'ClosePortalStatement': return printClosePortal(node, opts);
|
|
70
|
+
case 'CopyStatement': return printCopy(node, opts);
|
|
71
|
+
case 'ExplainStatement': return printExplain(node, opts);
|
|
72
|
+
case 'PrepareStatement': return printPrepare(node, opts);
|
|
73
|
+
case 'ExecuteStatement': return printExecute(node, opts);
|
|
74
|
+
case 'DeallocateStatement': return printDeallocate(node, opts);
|
|
75
|
+
case 'ListenStatement': return printListen(node, opts);
|
|
76
|
+
case 'UnlistenStatement': return printUnlisten(node, opts);
|
|
77
|
+
case 'NotifyStatement': return printNotify(node, opts);
|
|
78
|
+
case 'LockStatement': return printLockTable(node, opts);
|
|
79
|
+
case 'CreateTablePartitionOfStatement': return printCreateTablePartitionOf(node, opts);
|
|
80
|
+
case 'VacuumStatement': return printVacuum(node, opts);
|
|
81
|
+
case 'ClusterStatement': return printCluster(node, opts);
|
|
82
|
+
case 'ReindexStatement': return printReindex(node, opts);
|
|
83
|
+
case 'CreateForeignServerStatement': return printCreateForeignServer(node, opts);
|
|
84
|
+
case 'CreateForeignTableStatement': return printCreateForeignTable(node, opts);
|
|
85
|
+
case 'CreateUserMappingStatement': return printCreateUserMapping(node, opts);
|
|
86
|
+
case 'ImportForeignSchemaStatement': return printImportForeignSchema(node, opts);
|
|
87
|
+
case 'CreatePublicationStatement': return printCreatePublication(node, opts);
|
|
88
|
+
case 'CreateSubscriptionStatement': return printCreateSubscription(node, opts);
|
|
89
|
+
case 'DropSubscriptionStatement': return printDropSubscription(node, opts);
|
|
90
|
+
case 'CreateAggregateStatement': return printCreateAggregate(node, opts);
|
|
91
|
+
case 'CreateOperatorStatement': return printCreateOperator(node, opts);
|
|
92
|
+
case 'CreateCollationStatement': return printCreateCollation(node, opts);
|
|
93
|
+
case 'SecurityLabelStatement': return printSecurityLabel(node, opts);
|
|
94
|
+
case 'AlterOwnerStatement': return printAlterOwner(node, opts);
|
|
95
|
+
case 'AlterObjectSchemaStatement': return printAlterObjectSchema(node, opts);
|
|
96
|
+
default: return node.text ?? node.type;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Print a SELECT, SET-op, or DML as a query expression (no trailing semicolon).
|
|
101
|
+
* Used when a query appears as a sub-expression: subquery, CTE body, INSERT source.
|
|
102
|
+
*/
|
|
103
|
+
export function printQueryExpr(node, opts) {
|
|
104
|
+
switch (node.type) {
|
|
105
|
+
case 'SetOpStatement': return printSetOpBody(node, opts);
|
|
106
|
+
case 'InsertStatement': return printInsertBody(node, opts);
|
|
107
|
+
case 'UpdateStatement': return printUpdateBody(node, opts);
|
|
108
|
+
case 'DeleteStatement': return printDeleteBody(node, opts);
|
|
109
|
+
default: return printSelectBody(node, opts);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// Shared helpers
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
function printWith(opts) {
|
|
116
|
+
return function printNode(n) {
|
|
117
|
+
return n.type.endsWith('Statement')
|
|
118
|
+
? printQueryExpr(n, opts)
|
|
119
|
+
: printExpression(n, opts, printNode);
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Density-aware boolean clause (WHERE / HAVING / ON CONFLICT WHERE).
|
|
124
|
+
* Single predicate: inline in compact/standard; indented in spacious.
|
|
125
|
+
* Multi-predicate (BoolExpr AND/OR): always indented.
|
|
126
|
+
*/
|
|
127
|
+
function printBoolClause(kw, where, opts, printNode) {
|
|
128
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
129
|
+
const density = getDensity(opts);
|
|
130
|
+
const isMulti = where.type === 'BoolExpr' && (propStr(where, 'op') ?? 'AND') !== 'NOT';
|
|
131
|
+
const inline = density !== 'spacious' && !isMulti;
|
|
132
|
+
const body = printNode(where);
|
|
133
|
+
return [makeKeyword(kw), inline ? [' ', body] : indent([hardline, body])];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Single-item keyword clause (GROUP BY, ORDER BY) — stays inline in standard/compact.
|
|
137
|
+
*/
|
|
138
|
+
function printListClause(kw, items, opts, printNode) {
|
|
139
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
140
|
+
const inline = getDensity(opts) !== 'spacious' && items.length === 1;
|
|
141
|
+
const body = join(hardSep(opts), items.map(printNode));
|
|
142
|
+
return [makeKeyword(kw), inline ? [' ', body] : indent([hardline, body])];
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* FROM clause: single non-join item stays inline; joins and multiple items are indented.
|
|
146
|
+
*/
|
|
147
|
+
function printFromClause(items, opts, printNode) {
|
|
148
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
149
|
+
const inline = items.length === 1 && items[0].type !== 'JoinExpr';
|
|
150
|
+
const body = join([',', hardline], items.map(printNode));
|
|
151
|
+
return [makeKeyword('FROM'), inline ? [' ', body] : indent([hardline, body])];
|
|
152
|
+
}
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
// SELECT
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
function printCtes(ctes, opts, printNode) {
|
|
157
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
158
|
+
const cteList = propArr(ctes, 'ctes');
|
|
159
|
+
const recursive = propBool(ctes, 'recursive');
|
|
160
|
+
const cteKw = recursive ? makeKeyword('WITH RECURSIVE') : makeKeyword('WITH');
|
|
161
|
+
const cteDocs = cteList.map((cte) => {
|
|
162
|
+
const name = propStr(cte, 'name') ?? '';
|
|
163
|
+
const query = prop(cte, 'query');
|
|
164
|
+
const search = prop(cte, 'search');
|
|
165
|
+
const cycle = prop(cte, 'cycle');
|
|
166
|
+
const parts = [name, ' ', makeKeyword('AS'), ' (', indent([hardline, query ? printNode(query) : '']), hardline, ')'];
|
|
167
|
+
if (search) {
|
|
168
|
+
const breadthFirst = propBool(search, 'breadthFirst');
|
|
169
|
+
const cols = search.props?.['columns'] ?? [];
|
|
170
|
+
const seqCol = propStr(search, 'seqColumn') ?? '';
|
|
171
|
+
const firstLast = breadthFirst ? makeKeyword('BREADTH FIRST') : makeKeyword('DEPTH FIRST');
|
|
172
|
+
parts.push(hardline, makeKeyword('SEARCH'), ' ', firstLast, ' ', makeKeyword('BY'), ' ', join(', ', cols), ' ', makeKeyword('SET'), ' ', seqCol);
|
|
173
|
+
}
|
|
174
|
+
if (cycle) {
|
|
175
|
+
const cols = cycle.props?.['columns'] ?? [];
|
|
176
|
+
const markCol = propStr(cycle, 'markColumn') ?? '';
|
|
177
|
+
const pathCol = propStr(cycle, 'pathColumn') ?? '';
|
|
178
|
+
parts.push(hardline, makeKeyword('CYCLE'), ' ', join(', ', cols), ' ', makeKeyword('SET'), ' ', markCol, ' ', makeKeyword('USING'), ' ', pathCol);
|
|
179
|
+
}
|
|
180
|
+
return parts;
|
|
181
|
+
});
|
|
182
|
+
return [[cteKw, indent([hardline, join([',', hardline], cteDocs)])]];
|
|
183
|
+
}
|
|
184
|
+
function printSelectBody(node, opts) {
|
|
185
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
186
|
+
const printNode = printWith(opts);
|
|
187
|
+
const ctes = prop(node, 'ctes');
|
|
188
|
+
const distinct = propBool(node, 'distinct');
|
|
189
|
+
const targets = propArr(node, 'targetList');
|
|
190
|
+
const from = propArr(node, 'from');
|
|
191
|
+
const where = prop(node, 'where');
|
|
192
|
+
const groupBy = propArr(node, 'groupBy');
|
|
193
|
+
const having = prop(node, 'having');
|
|
194
|
+
const orderBy = propArr(node, 'orderBy');
|
|
195
|
+
const limit = prop(node, 'limit');
|
|
196
|
+
const offset = prop(node, 'offset');
|
|
197
|
+
const parts = [];
|
|
198
|
+
if (ctes) {
|
|
199
|
+
parts.push(...printCtes(ctes, opts, printNode));
|
|
200
|
+
}
|
|
201
|
+
const distinctOn = propArr(node, 'distinctOn');
|
|
202
|
+
const selectKw = distinctOn.length > 0
|
|
203
|
+
? [makeKeyword('SELECT'), ' ', makeKeyword('DISTINCT ON'), ' (', join(', ', distinctOn.map(printNode)), ')']
|
|
204
|
+
: distinct
|
|
205
|
+
? [makeKeyword('SELECT'), ' ', makeKeyword('DISTINCT')]
|
|
206
|
+
: makeKeyword('SELECT');
|
|
207
|
+
const selectInline = getDensity(opts) !== 'spacious' && targets.length === 1;
|
|
208
|
+
const targetDoc = join(hardSep(opts), targets.map(printNode));
|
|
209
|
+
parts.push([selectKw, selectInline ? [' ', targetDoc] : indent([hardline, targetDoc])]);
|
|
210
|
+
if (from.length > 0) {
|
|
211
|
+
parts.push(printFromClause(from, opts, printNode));
|
|
212
|
+
}
|
|
213
|
+
if (where)
|
|
214
|
+
parts.push(printBoolClause('WHERE', where, opts, printNode));
|
|
215
|
+
if (groupBy.length > 0)
|
|
216
|
+
parts.push(printListClause('GROUP BY', groupBy, opts, printNode));
|
|
217
|
+
if (having)
|
|
218
|
+
parts.push(printBoolClause('HAVING', having, opts, printNode));
|
|
219
|
+
if (orderBy.length > 0)
|
|
220
|
+
parts.push(printListClause('ORDER BY', orderBy, opts, printNode));
|
|
221
|
+
if (limit)
|
|
222
|
+
parts.push([makeKeyword('LIMIT'), ' ', printNode(limit)]);
|
|
223
|
+
if (offset)
|
|
224
|
+
parts.push([makeKeyword('OFFSET'), ' ', printNode(offset)]);
|
|
225
|
+
const locking = propArr(node, 'locking');
|
|
226
|
+
for (const lc of locking) {
|
|
227
|
+
const strength = propStr(lc, 'strength') ?? 'FOR UPDATE';
|
|
228
|
+
const tables = propArr(lc, 'tables');
|
|
229
|
+
const waitPolicy = propStr(lc, 'waitPolicy');
|
|
230
|
+
const ofPart = tables.length > 0
|
|
231
|
+
? [' ', makeKeyword('OF'), ' ', join(', ', tables.map((t) => rangeVarName(t)))]
|
|
232
|
+
: '';
|
|
233
|
+
const waitPart = waitPolicy ? [' ', makeKeyword(waitPolicy)] : '';
|
|
234
|
+
parts.push([makeKeyword(strength), ofPart, waitPart]);
|
|
235
|
+
}
|
|
236
|
+
// Named WINDOW clauses: WINDOW w AS (PARTITION BY ... ORDER BY ...)
|
|
237
|
+
const windowClauses = propArr(node, 'windowClauses');
|
|
238
|
+
if (windowClauses.length > 0) {
|
|
239
|
+
const wDocs = windowClauses.map((w) => {
|
|
240
|
+
const wName = propStr(w, 'name') ?? '';
|
|
241
|
+
const wSpec = printWindowDef(w, opts, printNode);
|
|
242
|
+
return [wName, ' ', makeKeyword('AS'), ' (', wSpec, ')'];
|
|
243
|
+
});
|
|
244
|
+
parts.push([makeKeyword('WINDOW'), indent([hardline, join(hardSep(opts), wDocs)])]);
|
|
245
|
+
}
|
|
246
|
+
return group(join(hardline, parts));
|
|
247
|
+
}
|
|
248
|
+
function printSelect(node, opts) {
|
|
249
|
+
return [printSelectBody(node, opts), ';'];
|
|
250
|
+
}
|
|
251
|
+
// ---------------------------------------------------------------------------
|
|
252
|
+
// INSERT
|
|
253
|
+
// ---------------------------------------------------------------------------
|
|
254
|
+
function printInsertBody(node, opts) {
|
|
255
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
256
|
+
const printNode = printWith(opts);
|
|
257
|
+
const ctes = prop(node, 'ctes');
|
|
258
|
+
const target = prop(node, 'target');
|
|
259
|
+
const columns = propArr(node, 'columns');
|
|
260
|
+
const override = propStr(node, 'override');
|
|
261
|
+
const source = prop(node, 'source');
|
|
262
|
+
const onConflict = prop(node, 'onConflict');
|
|
263
|
+
const returning = propArr(node, 'returning');
|
|
264
|
+
const cteParts = ctes ? printCtes(ctes, opts, printNode) : [];
|
|
265
|
+
const colsPart = columns.length > 0
|
|
266
|
+
? group([' (', indent([softline, join(softSep(opts), columns.map((c) => propStr(c, 'name') ?? ''))]), softline, ')'])
|
|
267
|
+
: '';
|
|
268
|
+
const overridePart = override ? [' ', makeKeyword(`OVERRIDING ${override} VALUE`)] : '';
|
|
269
|
+
const sourcePart = source?.type === 'DefaultValues'
|
|
270
|
+
? [hardline, makeKeyword('DEFAULT VALUES')]
|
|
271
|
+
: source?.type === 'ValuesStatement'
|
|
272
|
+
? printValuesRows(source, opts, printNode)
|
|
273
|
+
: source
|
|
274
|
+
? [hardline, printQueryExpr(source, opts)]
|
|
275
|
+
: '';
|
|
276
|
+
const parts = [
|
|
277
|
+
...cteParts,
|
|
278
|
+
[makeKeyword('INSERT INTO'), ' ', rangeVarName(target), colsPart, overridePart, sourcePart],
|
|
279
|
+
];
|
|
280
|
+
if (onConflict)
|
|
281
|
+
parts.push(printOnConflict(onConflict, opts, printNode));
|
|
282
|
+
if (returning.length > 0) {
|
|
283
|
+
parts.push(printListClause('RETURNING', returning, opts, printNode));
|
|
284
|
+
}
|
|
285
|
+
return group(join(hardline, parts));
|
|
286
|
+
}
|
|
287
|
+
function printInsert(node, opts) {
|
|
288
|
+
return [printInsertBody(node, opts), ';'];
|
|
289
|
+
}
|
|
290
|
+
// ---------------------------------------------------------------------------
|
|
291
|
+
// UPDATE
|
|
292
|
+
// ---------------------------------------------------------------------------
|
|
293
|
+
function printUpdateBody(node, opts) {
|
|
294
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
295
|
+
const printNode = printWith(opts);
|
|
296
|
+
const ctes = prop(node, 'ctes');
|
|
297
|
+
const target = prop(node, 'target');
|
|
298
|
+
const sets = propArr(node, 'sets');
|
|
299
|
+
const from = propArr(node, 'from');
|
|
300
|
+
const where = prop(node, 'where');
|
|
301
|
+
const returning = propArr(node, 'returning');
|
|
302
|
+
const density = getDensity(opts);
|
|
303
|
+
const setDocs = sets.map((s) => {
|
|
304
|
+
const name = propStr(s, 'name') ?? '';
|
|
305
|
+
const val = prop(s, 'val');
|
|
306
|
+
return [name, ' = ', val ? printNode(val) : ''];
|
|
307
|
+
});
|
|
308
|
+
const parts = ctes ? printCtes(ctes, opts, printNode) : [];
|
|
309
|
+
parts.push([makeKeyword('UPDATE'), ' ', rangeVarName(target)], [
|
|
310
|
+
makeKeyword('SET'),
|
|
311
|
+
density !== 'spacious' && setDocs.length === 1
|
|
312
|
+
? [' ', setDocs[0]]
|
|
313
|
+
: indent([hardline, join(hardSep(opts), setDocs)]),
|
|
314
|
+
]);
|
|
315
|
+
if (from.length > 0) {
|
|
316
|
+
parts.push(printFromClause(from, opts, printNode));
|
|
317
|
+
}
|
|
318
|
+
if (where)
|
|
319
|
+
parts.push(printBoolClause('WHERE', where, opts, printNode));
|
|
320
|
+
if (returning.length > 0) {
|
|
321
|
+
parts.push(printListClause('RETURNING', returning, opts, printNode));
|
|
322
|
+
}
|
|
323
|
+
return group(join(hardline, parts));
|
|
324
|
+
}
|
|
325
|
+
function printUpdate(node, opts) {
|
|
326
|
+
return [printUpdateBody(node, opts), ';'];
|
|
327
|
+
}
|
|
328
|
+
// ---------------------------------------------------------------------------
|
|
329
|
+
// DELETE
|
|
330
|
+
// ---------------------------------------------------------------------------
|
|
331
|
+
function printDeleteBody(node, opts) {
|
|
332
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
333
|
+
const printNode = printWith(opts);
|
|
334
|
+
const ctes = prop(node, 'ctes');
|
|
335
|
+
const target = prop(node, 'target');
|
|
336
|
+
const using = propArr(node, 'using');
|
|
337
|
+
const where = prop(node, 'where');
|
|
338
|
+
const returning = propArr(node, 'returning');
|
|
339
|
+
const parts = ctes ? printCtes(ctes, opts, printNode) : [];
|
|
340
|
+
parts.push([makeKeyword('DELETE FROM'), ' ', rangeVarName(target)]);
|
|
341
|
+
if (using.length > 0)
|
|
342
|
+
parts.push(printListClause('USING', using, opts, printNode));
|
|
343
|
+
if (where)
|
|
344
|
+
parts.push(printBoolClause('WHERE', where, opts, printNode));
|
|
345
|
+
if (returning.length > 0) {
|
|
346
|
+
parts.push(printListClause('RETURNING', returning, opts, printNode));
|
|
347
|
+
}
|
|
348
|
+
return group(join(hardline, parts));
|
|
349
|
+
}
|
|
350
|
+
function printDelete(node, opts) {
|
|
351
|
+
return [printDeleteBody(node, opts), ';'];
|
|
352
|
+
}
|
|
353
|
+
// ---------------------------------------------------------------------------
|
|
354
|
+
// SET operations (UNION / INTERSECT / EXCEPT)
|
|
355
|
+
// ---------------------------------------------------------------------------
|
|
356
|
+
function printSetOpBody(node, opts) {
|
|
357
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
358
|
+
const op = propStr(node, 'op') ?? 'UNION';
|
|
359
|
+
const all = propBool(node, 'all');
|
|
360
|
+
const lhs = prop(node, 'lhs');
|
|
361
|
+
const rhs = prop(node, 'rhs');
|
|
362
|
+
const opKw = all ? makeKeyword(`${op} ALL`) : makeKeyword(op);
|
|
363
|
+
return [
|
|
364
|
+
lhs ? printQueryExpr(lhs, opts) : '',
|
|
365
|
+
hardline, opKw, hardline,
|
|
366
|
+
rhs ? printQueryExpr(rhs, opts) : '',
|
|
367
|
+
];
|
|
368
|
+
}
|
|
369
|
+
function printSetOp(node, opts) {
|
|
370
|
+
return [printSetOpBody(node, opts), ';'];
|
|
371
|
+
}
|
|
372
|
+
// ---------------------------------------------------------------------------
|
|
373
|
+
// VALUES
|
|
374
|
+
// ---------------------------------------------------------------------------
|
|
375
|
+
/**
|
|
376
|
+
* Render VALUES rows without a trailing semicolon — used as INSERT source.
|
|
377
|
+
* Uses softSep within each row and hardSep between rows, matching tsql style.
|
|
378
|
+
*/
|
|
379
|
+
function printValuesRows(node, opts, printNode) {
|
|
380
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
381
|
+
const rows = propArr(node, 'rows');
|
|
382
|
+
const rowDocs = rows.map((row) => {
|
|
383
|
+
const items = propArr(row, 'items').map(printNode);
|
|
384
|
+
return group(['(', indent([softline, join(softSep(opts), items)]), softline, ')']);
|
|
385
|
+
});
|
|
386
|
+
if (rowDocs.length === 1) {
|
|
387
|
+
return [hardline, makeKeyword('VALUES'), ' ', rowDocs[0]];
|
|
388
|
+
}
|
|
389
|
+
return [hardline, makeKeyword('VALUES'), indent([hardline, join(hardSep(opts), rowDocs)])];
|
|
390
|
+
}
|
|
391
|
+
function printValues(node, opts) {
|
|
392
|
+
return [printValuesRows(node, opts, printWith(opts)), ';'];
|
|
393
|
+
}
|
|
394
|
+
// ---------------------------------------------------------------------------
|
|
395
|
+
// ON CONFLICT
|
|
396
|
+
// ---------------------------------------------------------------------------
|
|
397
|
+
function printOnConflict(node, opts, printNode) {
|
|
398
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
399
|
+
const action = propStr(node, 'action') ?? 'NOTHING';
|
|
400
|
+
const target = prop(node, 'target');
|
|
401
|
+
const sets = propArr(node, 'sets');
|
|
402
|
+
const where = prop(node, 'where');
|
|
403
|
+
let targetDoc = '';
|
|
404
|
+
if (target) {
|
|
405
|
+
const cols = propArr(target, 'columns');
|
|
406
|
+
const constraint = propStr(target, 'constraint');
|
|
407
|
+
if (constraint) {
|
|
408
|
+
targetDoc = [' ', makeKeyword('ON CONSTRAINT'), ' ', constraint];
|
|
409
|
+
}
|
|
410
|
+
else if (cols.length > 0) {
|
|
411
|
+
targetDoc = group([' (', indent([softline, join(softSep(opts), cols.map((c) => propStr(c, 'name') ?? ''))]), softline, ')']);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (action === 'NOTHING') {
|
|
415
|
+
return [makeKeyword('ON CONFLICT'), targetDoc, ' ', makeKeyword('DO NOTHING')];
|
|
416
|
+
}
|
|
417
|
+
// DO UPDATE SET
|
|
418
|
+
const setDocs = sets.map((s) => {
|
|
419
|
+
const name = propStr(s, 'name') ?? '';
|
|
420
|
+
const val = prop(s, 'val');
|
|
421
|
+
return [name, ' = ', val ? printNode(val) : ''];
|
|
422
|
+
});
|
|
423
|
+
const density = getDensity(opts);
|
|
424
|
+
const parts = [
|
|
425
|
+
[makeKeyword('ON CONFLICT'), targetDoc, ' ', makeKeyword('DO UPDATE')],
|
|
426
|
+
[
|
|
427
|
+
makeKeyword('SET'),
|
|
428
|
+
density !== 'spacious' && setDocs.length === 1
|
|
429
|
+
? [' ', setDocs[0]]
|
|
430
|
+
: indent([hardline, join(hardSep(opts), setDocs)]),
|
|
431
|
+
],
|
|
432
|
+
];
|
|
433
|
+
if (where)
|
|
434
|
+
parts.push(printBoolClause('WHERE', where, opts, printNode));
|
|
435
|
+
return join(hardline, parts);
|
|
436
|
+
}
|
|
437
|
+
// ---------------------------------------------------------------------------
|
|
438
|
+
// DDL
|
|
439
|
+
// ---------------------------------------------------------------------------
|
|
440
|
+
function printCreateTable(node, opts) {
|
|
441
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
442
|
+
const printNode = printWith(opts);
|
|
443
|
+
const name = prop(node, 'name');
|
|
444
|
+
const columns = propArr(node, 'columns');
|
|
445
|
+
const partitionBy = prop(node, 'partitionBy');
|
|
446
|
+
const partitionDoc = partitionBy
|
|
447
|
+
? [hardline, makeKeyword('PARTITION BY'), ' ', makeKeyword(propStr(partitionBy, 'strategy') ?? 'RANGE'),
|
|
448
|
+
' (', join(', ', partitionBy.props?.['columns'] ?? []), ')']
|
|
449
|
+
: '';
|
|
450
|
+
return [
|
|
451
|
+
makeKeyword('CREATE TABLE'), ' ', rangeVarName(name), ' (',
|
|
452
|
+
indent([hardline, join([',', hardline], columns.map(printNode))]),
|
|
453
|
+
hardline, ')',
|
|
454
|
+
partitionDoc,
|
|
455
|
+
';',
|
|
456
|
+
];
|
|
457
|
+
}
|
|
458
|
+
function printAlterTable(node, opts) {
|
|
459
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
460
|
+
const printNode = printWith(opts);
|
|
461
|
+
const name = prop(node, 'name');
|
|
462
|
+
const commands = propArr(node, 'commands');
|
|
463
|
+
return [
|
|
464
|
+
makeKeyword('ALTER TABLE'), ' ', rangeVarName(name),
|
|
465
|
+
indent([hardline, join([',', hardline], commands.map(printNode))]),
|
|
466
|
+
';',
|
|
467
|
+
];
|
|
468
|
+
}
|
|
469
|
+
function printCreateView(node, opts) {
|
|
470
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
471
|
+
const name = prop(node, 'name');
|
|
472
|
+
const body = prop(node, 'body');
|
|
473
|
+
return [
|
|
474
|
+
makeKeyword('CREATE VIEW'), ' ', rangeVarName(name), hardline,
|
|
475
|
+
makeKeyword('AS'), hardline,
|
|
476
|
+
body ? printQueryExpr(body, opts) : '',
|
|
477
|
+
';',
|
|
478
|
+
];
|
|
479
|
+
}
|
|
480
|
+
function printCreateFunction(node, opts) {
|
|
481
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
482
|
+
const printNode = printWith(opts);
|
|
483
|
+
const name = propStr(node, 'name') ?? '';
|
|
484
|
+
const parameters = propArr(node, 'parameters');
|
|
485
|
+
const returnType = propStr(node, 'returnType');
|
|
486
|
+
const returnsTable = propArr(node, 'returnsTable');
|
|
487
|
+
const language = propStr(node, 'language');
|
|
488
|
+
const body = propStr(node, 'body');
|
|
489
|
+
const parts = [
|
|
490
|
+
makeKeyword('CREATE FUNCTION'), ' ', name,
|
|
491
|
+
'(', join(', ', parameters.map(printNode)), ')',
|
|
492
|
+
];
|
|
493
|
+
if (returnsTable.length > 0) {
|
|
494
|
+
parts.push(hardline, makeKeyword('RETURNS TABLE'), ' (', join(', ', returnsTable.map(printNode)), ')');
|
|
495
|
+
}
|
|
496
|
+
else if (returnType) {
|
|
497
|
+
parts.push(hardline, makeKeyword('RETURNS'), ' ', makeKeyword(returnType));
|
|
498
|
+
}
|
|
499
|
+
if (language)
|
|
500
|
+
parts.push(hardline, makeKeyword('LANGUAGE'), ' ', language);
|
|
501
|
+
if (body != null) {
|
|
502
|
+
parts.push(hardline, makeKeyword('AS'), ' ', '$$', body, '$$');
|
|
503
|
+
}
|
|
504
|
+
return [join('', parts), ';'];
|
|
505
|
+
}
|
|
506
|
+
function printCreateIndex(node, opts) {
|
|
507
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
508
|
+
const printNode = printWith(opts);
|
|
509
|
+
const unique = propBool(node, 'unique');
|
|
510
|
+
const concurrent = propBool(node, 'concurrent');
|
|
511
|
+
const ifNotExists = propBool(node, 'ifNotExists');
|
|
512
|
+
const indexName = propStr(node, 'indexName') ?? '';
|
|
513
|
+
const relation = prop(node, 'relation');
|
|
514
|
+
const columns = propArr(node, 'columns');
|
|
515
|
+
const including = propArr(node, 'including');
|
|
516
|
+
const accessMethod = propStr(node, 'accessMethod');
|
|
517
|
+
const where = prop(node, 'where');
|
|
518
|
+
const keyword1 = unique ? makeKeyword('CREATE UNIQUE INDEX') : makeKeyword('CREATE INDEX');
|
|
519
|
+
const parts = [keyword1];
|
|
520
|
+
if (concurrent)
|
|
521
|
+
parts.push(' ', makeKeyword('CONCURRENTLY'));
|
|
522
|
+
if (ifNotExists)
|
|
523
|
+
parts.push(' ', makeKeyword('IF NOT EXISTS'));
|
|
524
|
+
parts.push(' ', indexName, ' ', makeKeyword('ON'), ' ', rangeVarName(relation));
|
|
525
|
+
if (accessMethod)
|
|
526
|
+
parts.push(' ', makeKeyword('USING'), ' ', accessMethod);
|
|
527
|
+
parts.push(' (', join(', ', columns.map(printNode)), ')');
|
|
528
|
+
if (including.length > 0)
|
|
529
|
+
parts.push(' ', makeKeyword('INCLUDE'), ' (', join(', ', including.map(printNode)), ')');
|
|
530
|
+
if (where)
|
|
531
|
+
parts.push(' ', makeKeyword('WHERE'), ' ', printNode(where));
|
|
532
|
+
parts.push(';');
|
|
533
|
+
return parts;
|
|
534
|
+
}
|
|
535
|
+
function printTruncate(node, opts) {
|
|
536
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
537
|
+
const relations = propArr(node, 'relations');
|
|
538
|
+
const restart = propBool(node, 'restartSeqs');
|
|
539
|
+
const cascade = propBool(node, 'cascade');
|
|
540
|
+
return [
|
|
541
|
+
makeKeyword('TRUNCATE TABLE'), ' ', join(', ', relations.map(rangeVarName)),
|
|
542
|
+
restart ? [' ', makeKeyword('RESTART IDENTITY')] : '',
|
|
543
|
+
cascade ? [' ', makeKeyword('CASCADE')] : '',
|
|
544
|
+
';',
|
|
545
|
+
];
|
|
546
|
+
}
|
|
547
|
+
function printDrop(node, opts) {
|
|
548
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
549
|
+
const objectType = propStr(node, 'objectType') ?? '';
|
|
550
|
+
const names = node.props?.['names'] ?? [];
|
|
551
|
+
const ifExists = propBool(node, 'ifExists');
|
|
552
|
+
const cascade = propBool(node, 'cascade');
|
|
553
|
+
return [
|
|
554
|
+
makeKeyword('DROP'), ' ', makeKeyword(objectType),
|
|
555
|
+
ifExists ? [' ', makeKeyword('IF EXISTS')] : '',
|
|
556
|
+
names.length > 0 ? [' ', join(', ', names)] : '',
|
|
557
|
+
cascade ? [' ', makeKeyword('CASCADE')] : '',
|
|
558
|
+
';',
|
|
559
|
+
];
|
|
560
|
+
}
|
|
561
|
+
// ---------------------------------------------------------------------------
|
|
562
|
+
// SET / SHOW / RESET
|
|
563
|
+
// ---------------------------------------------------------------------------
|
|
564
|
+
function printVariableSet(node, opts) {
|
|
565
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
566
|
+
const kind = propStr(node, 'kind') ?? 'SET';
|
|
567
|
+
const name = propStr(node, 'name') ?? '';
|
|
568
|
+
const values = node.props?.['values'] ?? [];
|
|
569
|
+
const local = propBool(node, 'local');
|
|
570
|
+
if (kind === 'RESET ALL')
|
|
571
|
+
return [makeKeyword('RESET ALL'), ';'];
|
|
572
|
+
if (kind === 'RESET')
|
|
573
|
+
return [[makeKeyword('RESET'), ' ', name], ';'];
|
|
574
|
+
const localKw = local ? [makeKeyword('LOCAL'), ' '] : '';
|
|
575
|
+
if (kind === 'SET DEFAULT') {
|
|
576
|
+
return [[makeKeyword('SET'), ' ', localKw, name, ' ', makeKeyword('TO'), ' ', makeKeyword('DEFAULT')], ';'];
|
|
577
|
+
}
|
|
578
|
+
// SET name = value(s)
|
|
579
|
+
// - Starts with digit or contains special chars: must be quoted
|
|
580
|
+
// - Otherwise: lowercase (PostgreSQL normalizes unquoted identifiers)
|
|
581
|
+
const valDocs = values.map((v) => {
|
|
582
|
+
if (/^[0-9]/.test(v) || /[^a-zA-Z0-9_$]/.test(v))
|
|
583
|
+
return `'${v.replace(/'/g, "''")}'`;
|
|
584
|
+
return v.toLowerCase();
|
|
585
|
+
});
|
|
586
|
+
return [[makeKeyword('SET'), ' ', localKw, name, ' = ', join(', ', valDocs)], ';'];
|
|
587
|
+
}
|
|
588
|
+
function printVariableShow(node, opts) {
|
|
589
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
590
|
+
const name = propStr(node, 'name') ?? '';
|
|
591
|
+
return [[makeKeyword('SHOW'), ' ', name], ';'];
|
|
592
|
+
}
|
|
593
|
+
// ---------------------------------------------------------------------------
|
|
594
|
+
// GRANT / REVOKE
|
|
595
|
+
// ---------------------------------------------------------------------------
|
|
596
|
+
function printGrantRevoke(node, opts, isGrant) {
|
|
597
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
598
|
+
const printNode = printWith(opts);
|
|
599
|
+
const privs = node.props?.['privs'] ?? [];
|
|
600
|
+
const objtype = propStr(node, 'objtype') ?? '';
|
|
601
|
+
const objects = propArr(node, 'objects');
|
|
602
|
+
const grantees = node.props?.['grantees'] ?? [];
|
|
603
|
+
const grantOption = propBool(node, 'grantOption');
|
|
604
|
+
const cascade = propBool(node, 'cascade');
|
|
605
|
+
const privsDoc = privs.length > 0 ? join(', ', privs.map(makeKeyword)) : makeKeyword('ALL PRIVILEGES');
|
|
606
|
+
const verb = isGrant ? makeKeyword('GRANT') : makeKeyword('REVOKE');
|
|
607
|
+
const toFrom = isGrant ? makeKeyword('TO') : makeKeyword('FROM');
|
|
608
|
+
const objectsDoc = objects.length > 0
|
|
609
|
+
? join(', ', objects.map(printNode))
|
|
610
|
+
: '';
|
|
611
|
+
const parts = [
|
|
612
|
+
[verb, ' ', privsDoc, ' ', makeKeyword('ON'), ' ', makeKeyword(objtype), objectsDoc ? [' ', objectsDoc] : ''],
|
|
613
|
+
[toFrom, ' ', join(', ', grantees)],
|
|
614
|
+
];
|
|
615
|
+
if (isGrant && grantOption)
|
|
616
|
+
parts.push(makeKeyword('WITH GRANT OPTION'));
|
|
617
|
+
if (!isGrant && cascade)
|
|
618
|
+
parts.push(makeKeyword('CASCADE'));
|
|
619
|
+
return [join(hardline, parts), ';'];
|
|
620
|
+
}
|
|
621
|
+
function printGrant(node, opts) {
|
|
622
|
+
return printGrantRevoke(node, opts, true);
|
|
623
|
+
}
|
|
624
|
+
function printRevoke(node, opts) {
|
|
625
|
+
return printGrantRevoke(node, opts, false);
|
|
626
|
+
}
|
|
627
|
+
// ---------------------------------------------------------------------------
|
|
628
|
+
// CREATE / ALTER ROLE
|
|
629
|
+
// ---------------------------------------------------------------------------
|
|
630
|
+
function printCreateRole(node, opts) {
|
|
631
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
632
|
+
const stmtType = propStr(node, 'stmtType') ?? 'ROLE';
|
|
633
|
+
const name = propStr(node, 'name') ?? '';
|
|
634
|
+
const options = node.props?.['options'] ?? [];
|
|
635
|
+
const parts = [[makeKeyword(`CREATE ${stmtType}`), ' ', name]];
|
|
636
|
+
if (options.length > 0)
|
|
637
|
+
parts.push(join(' ', options.map(makeKeyword)));
|
|
638
|
+
return [join(hardline, parts), ';'];
|
|
639
|
+
}
|
|
640
|
+
function printAlterRole(node, opts) {
|
|
641
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
642
|
+
const name = propStr(node, 'name') ?? '';
|
|
643
|
+
const options = node.props?.['options'] ?? [];
|
|
644
|
+
const parts = [[makeKeyword('ALTER ROLE'), ' ', name]];
|
|
645
|
+
if (options.length > 0)
|
|
646
|
+
parts.push(join(' ', options.map(makeKeyword)));
|
|
647
|
+
return [join(hardline, parts), ';'];
|
|
648
|
+
}
|
|
649
|
+
// ---------------------------------------------------------------------------
|
|
650
|
+
// RENAME (ALTER TABLE ... RENAME / ALTER INDEX ... RENAME / etc.)
|
|
651
|
+
// ---------------------------------------------------------------------------
|
|
652
|
+
function printRename(node, opts) {
|
|
653
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
654
|
+
const renameType = propStr(node, 'renameType') ?? 'RENAME TABLE';
|
|
655
|
+
const relation = prop(node, 'relation');
|
|
656
|
+
const objName = propStr(node, 'objName');
|
|
657
|
+
const oldName = propStr(node, 'oldName');
|
|
658
|
+
const newName = propStr(node, 'newName') ?? '';
|
|
659
|
+
if (renameType === 'RENAME TABLE') {
|
|
660
|
+
return [[makeKeyword('ALTER TABLE'), ' ', rangeVarName(relation), ' ', makeKeyword('RENAME TO'), ' ', newName], ';'];
|
|
661
|
+
}
|
|
662
|
+
if (renameType === 'RENAME COLUMN') {
|
|
663
|
+
return [[makeKeyword('ALTER TABLE'), ' ', rangeVarName(relation), ' ', makeKeyword('RENAME COLUMN'), ' ', oldName ?? '', ' ', makeKeyword('TO'), ' ', newName], ';'];
|
|
664
|
+
}
|
|
665
|
+
// FUNCTION, PROCEDURE — use objName + arg types
|
|
666
|
+
if (renameType === 'RENAME FUNCTION' || renameType === 'RENAME PROCEDURE') {
|
|
667
|
+
const objKw = renameType.replace('RENAME ', '');
|
|
668
|
+
const argTypes = node.props?.['objArgTypes'] ?? [];
|
|
669
|
+
const argList = argTypes.length > 0 ? ['(', join(', ', argTypes.map((t) => makeKeyword(t))), ')'] : '()';
|
|
670
|
+
return [[makeKeyword(`ALTER ${objKw}`), ' ', objName ?? '', argList, ' ', makeKeyword('RENAME TO'), ' ', newName], ';'];
|
|
671
|
+
}
|
|
672
|
+
// INDEX, SCHEMA, VIEW, MATERIALIZED VIEW, SEQUENCE, TYPE, TRIGGER ...
|
|
673
|
+
const objKw = renameType.replace('RENAME ', '');
|
|
674
|
+
return [[makeKeyword(`ALTER ${objKw}`), ' ', objName ?? rangeVarName(relation) ?? oldName ?? '', ' ', makeKeyword('RENAME TO'), ' ', newName], ';'];
|
|
675
|
+
}
|
|
676
|
+
// ---------------------------------------------------------------------------
|
|
677
|
+
// CREATE TYPE / ALTER TYPE
|
|
678
|
+
// ---------------------------------------------------------------------------
|
|
679
|
+
function printCreateType(node, opts) {
|
|
680
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
681
|
+
const printNode = printWith(opts);
|
|
682
|
+
const kind = propStr(node, 'kind') ?? 'COMPOSITE';
|
|
683
|
+
const typeName = propStr(node, 'typeName') ?? '';
|
|
684
|
+
const columns = propArr(node, 'columns');
|
|
685
|
+
const values = node.props?.['values'] ?? [];
|
|
686
|
+
if (kind === 'ENUM') {
|
|
687
|
+
const valList = values.length > 0
|
|
688
|
+
? ['(', indent([hardline, join([',', hardline], values.map((v) => `'${v}'`))]), hardline, ')']
|
|
689
|
+
: '()';
|
|
690
|
+
return [[makeKeyword('CREATE TYPE'), ' ', typeName, ' ', makeKeyword('AS ENUM'), ' ', valList], ';'];
|
|
691
|
+
}
|
|
692
|
+
// COMPOSITE
|
|
693
|
+
return [
|
|
694
|
+
makeKeyword('CREATE TYPE'), ' ', typeName, ' ', makeKeyword('AS'), ' (',
|
|
695
|
+
indent([hardline, join([',', hardline], columns.map(printNode))]),
|
|
696
|
+
hardline, ');',
|
|
697
|
+
];
|
|
698
|
+
}
|
|
699
|
+
function printAlterType(node, opts) {
|
|
700
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
701
|
+
const typeName = propStr(node, 'typeName') ?? '';
|
|
702
|
+
const newVal = propStr(node, 'newVal') ?? '';
|
|
703
|
+
const neighbor = propStr(node, 'neighbor');
|
|
704
|
+
const isAfter = propBool(node, 'isAfter');
|
|
705
|
+
const ifNotExists = propBool(node, 'ifNotExists');
|
|
706
|
+
const ifNotExistsDoc = ifNotExists ? [makeKeyword('IF NOT EXISTS'), ' '] : '';
|
|
707
|
+
const placement = neighbor
|
|
708
|
+
? [' ', isAfter ? makeKeyword('AFTER') : makeKeyword('BEFORE'), ' ', `'${neighbor}'`]
|
|
709
|
+
: '';
|
|
710
|
+
return [[makeKeyword('ALTER TYPE'), ' ', typeName, ' ', makeKeyword('ADD VALUE'), ' ', ifNotExistsDoc, `'${newVal}'`, placement], ';'];
|
|
711
|
+
}
|
|
712
|
+
// ---------------------------------------------------------------------------
|
|
713
|
+
// CREATE / ALTER SEQUENCE
|
|
714
|
+
// ---------------------------------------------------------------------------
|
|
715
|
+
function printCreateSequence(node, opts) {
|
|
716
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
717
|
+
const schema = propStr(node, 'schema');
|
|
718
|
+
const name = propStr(node, 'name') ?? '';
|
|
719
|
+
const ifNotExists = propBool(node, 'ifNotExists');
|
|
720
|
+
const options = node.props?.['options'] ?? [];
|
|
721
|
+
const qname = qualifiedName(schema, name);
|
|
722
|
+
const ifNotExistsDoc = ifNotExists ? [makeKeyword('IF NOT EXISTS'), ' '] : '';
|
|
723
|
+
const parts = [[makeKeyword('CREATE SEQUENCE'), ' ', ifNotExistsDoc, qname]];
|
|
724
|
+
for (const opt of options)
|
|
725
|
+
parts.push(makeKeyword(opt));
|
|
726
|
+
return [join(hardline, parts), ';'];
|
|
727
|
+
}
|
|
728
|
+
function printAlterSequence(node, opts) {
|
|
729
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
730
|
+
const schema = propStr(node, 'schema');
|
|
731
|
+
const name = propStr(node, 'name') ?? '';
|
|
732
|
+
const options = node.props?.['options'] ?? [];
|
|
733
|
+
const qname = qualifiedName(schema, name);
|
|
734
|
+
const parts = [[makeKeyword('ALTER SEQUENCE'), ' ', qname]];
|
|
735
|
+
for (const opt of options)
|
|
736
|
+
parts.push(makeKeyword(opt));
|
|
737
|
+
return [join(hardline, parts), ';'];
|
|
738
|
+
}
|
|
739
|
+
// ---------------------------------------------------------------------------
|
|
740
|
+
// CREATE SCHEMA
|
|
741
|
+
// ---------------------------------------------------------------------------
|
|
742
|
+
function printCreateSchema(node, opts) {
|
|
743
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
744
|
+
const name = propStr(node, 'name') ?? '';
|
|
745
|
+
const authRole = propStr(node, 'authRole');
|
|
746
|
+
const ifNotExists = propBool(node, 'ifNotExists');
|
|
747
|
+
const ifNotExistsDoc = ifNotExists ? [makeKeyword('IF NOT EXISTS'), ' '] : '';
|
|
748
|
+
const authDoc = authRole ? [' ', makeKeyword('AUTHORIZATION'), ' ', authRole] : '';
|
|
749
|
+
return [[makeKeyword('CREATE SCHEMA'), ' ', ifNotExistsDoc, name, authDoc], ';'];
|
|
750
|
+
}
|
|
751
|
+
// ---------------------------------------------------------------------------
|
|
752
|
+
// CREATE EXTENSION
|
|
753
|
+
// ---------------------------------------------------------------------------
|
|
754
|
+
function printCreateExtension(node, opts) {
|
|
755
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
756
|
+
const name = propStr(node, 'name') ?? '';
|
|
757
|
+
const ifNotExists = propBool(node, 'ifNotExists');
|
|
758
|
+
const schema = propStr(node, 'schema');
|
|
759
|
+
const version = propStr(node, 'version');
|
|
760
|
+
const ifNotExistsDoc = ifNotExists ? [makeKeyword('IF NOT EXISTS'), ' '] : '';
|
|
761
|
+
const schemaDoc = schema ? [hardline, makeKeyword('SCHEMA'), ' ', schema] : '';
|
|
762
|
+
const versionDoc = version ? [hardline, makeKeyword('VERSION'), ' ', `'${version}'`] : '';
|
|
763
|
+
return [[makeKeyword('CREATE EXTENSION'), ' ', ifNotExistsDoc, `"${name}"`, schemaDoc, versionDoc], ';'];
|
|
764
|
+
}
|
|
765
|
+
// ---------------------------------------------------------------------------
|
|
766
|
+
// CREATE TABLE AS / CREATE MATERIALIZED VIEW
|
|
767
|
+
// ---------------------------------------------------------------------------
|
|
768
|
+
function printCreateTableAs(node, opts) {
|
|
769
|
+
return printCreateAsQuery(node, opts, 'CREATE TABLE');
|
|
770
|
+
}
|
|
771
|
+
function printCreateMatView(node, opts) {
|
|
772
|
+
return printCreateAsQuery(node, opts, 'CREATE MATERIALIZED VIEW');
|
|
773
|
+
}
|
|
774
|
+
function printCreateAsQuery(node, opts, kw) {
|
|
775
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
776
|
+
const schema = propStr(node, 'schema');
|
|
777
|
+
const name = propStr(node, 'name') ?? '';
|
|
778
|
+
const ifNotExists = propBool(node, 'ifNotExists');
|
|
779
|
+
const query = prop(node, 'query');
|
|
780
|
+
const qname = qualifiedName(schema, name);
|
|
781
|
+
const ifNotExistsDoc = ifNotExists ? [makeKeyword('IF NOT EXISTS'), ' '] : '';
|
|
782
|
+
return [
|
|
783
|
+
makeKeyword(kw), ' ', ifNotExistsDoc, qname, ' ', makeKeyword('AS'),
|
|
784
|
+
hardline, query ? printQueryExpr(query, opts) : '',
|
|
785
|
+
';',
|
|
786
|
+
];
|
|
787
|
+
}
|
|
788
|
+
// ---------------------------------------------------------------------------
|
|
789
|
+
// CREATE TRIGGER
|
|
790
|
+
// ---------------------------------------------------------------------------
|
|
791
|
+
function printCreateTrigger(node, opts) {
|
|
792
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
793
|
+
const printNode = printWith(opts);
|
|
794
|
+
const name = propStr(node, 'name') ?? '';
|
|
795
|
+
const timing = propStr(node, 'timing') ?? 'AFTER';
|
|
796
|
+
const events = node.props?.['events'] ?? [];
|
|
797
|
+
const relation = prop(node, 'relation');
|
|
798
|
+
const forEach = propStr(node, 'forEach') ?? 'ROW';
|
|
799
|
+
const funcName = propStr(node, 'funcName') ?? '';
|
|
800
|
+
const when = prop(node, 'when');
|
|
801
|
+
const eventDoc = join([' ', makeKeyword('OR'), ' '], events.map(makeKeyword));
|
|
802
|
+
const whenDoc = when ? [hardline, makeKeyword('WHEN'), ' (', printNode(when), ')'] : '';
|
|
803
|
+
return [
|
|
804
|
+
makeKeyword('CREATE TRIGGER'), ' ', name,
|
|
805
|
+
hardline, makeKeyword(timing), ' ', eventDoc, ' ', makeKeyword('ON'), ' ', rangeVarName(relation),
|
|
806
|
+
hardline, makeKeyword(`FOR EACH ${forEach}`),
|
|
807
|
+
whenDoc,
|
|
808
|
+
hardline, makeKeyword('EXECUTE FUNCTION'), ' ', funcName, '()',
|
|
809
|
+
';',
|
|
810
|
+
];
|
|
811
|
+
}
|
|
812
|
+
// ---------------------------------------------------------------------------
|
|
813
|
+
// COMMENT ON
|
|
814
|
+
// ---------------------------------------------------------------------------
|
|
815
|
+
function printComment(node, opts) {
|
|
816
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
817
|
+
const objtype = propStr(node, 'objtype') ?? '';
|
|
818
|
+
const object = propStr(node, 'object') ?? '';
|
|
819
|
+
const comment = propStr(node, 'comment');
|
|
820
|
+
const commentVal = comment != null ? `'${comment.replace(/'/g, "''")}'` : makeKeyword('NULL');
|
|
821
|
+
return [[makeKeyword('COMMENT ON'), ' ', makeKeyword(objtype), ' ', object, ' ', makeKeyword('IS'), ' ', commentVal], ';'];
|
|
822
|
+
}
|
|
823
|
+
// ---------------------------------------------------------------------------
|
|
824
|
+
// Transaction control
|
|
825
|
+
// ---------------------------------------------------------------------------
|
|
826
|
+
function printTransaction(node, opts) {
|
|
827
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
828
|
+
const kind = propStr(node, 'kind') ?? 'COMMIT';
|
|
829
|
+
const savepoint = propStr(node, 'savepoint');
|
|
830
|
+
const gid = propStr(node, 'gid');
|
|
831
|
+
const options = node.props?.['options'] ?? [];
|
|
832
|
+
const parts = [makeKeyword(kind)];
|
|
833
|
+
// SAVEPOINT, RELEASE SAVEPOINT, ROLLBACK TO SAVEPOINT all take a savepoint name
|
|
834
|
+
if (kind === 'RELEASE')
|
|
835
|
+
parts.push(' ', makeKeyword('SAVEPOINT'));
|
|
836
|
+
if (kind === 'ROLLBACK TO')
|
|
837
|
+
parts.push(' ', makeKeyword('SAVEPOINT'));
|
|
838
|
+
if (savepoint)
|
|
839
|
+
parts.push(' ', savepoint);
|
|
840
|
+
if (gid)
|
|
841
|
+
parts.push(' ', `'${gid}'`);
|
|
842
|
+
if (options.length > 0)
|
|
843
|
+
parts.push(' ', join(', ', options.map((o) => makeKeyword(o))));
|
|
844
|
+
return [parts, ';'];
|
|
845
|
+
}
|
|
846
|
+
// ---------------------------------------------------------------------------
|
|
847
|
+
// CALL
|
|
848
|
+
// ---------------------------------------------------------------------------
|
|
849
|
+
function printCall(node, opts) {
|
|
850
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
851
|
+
const printNode = printWith(opts);
|
|
852
|
+
const call = prop(node, 'call');
|
|
853
|
+
return [[makeKeyword('CALL'), ' ', call ? printNode(call) : ''], ';'];
|
|
854
|
+
}
|
|
855
|
+
// ---------------------------------------------------------------------------
|
|
856
|
+
// DO
|
|
857
|
+
// ---------------------------------------------------------------------------
|
|
858
|
+
function printDo(node, opts) {
|
|
859
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
860
|
+
const language = propStr(node, 'language') ?? 'plpgsql';
|
|
861
|
+
const body = propStr(node, 'body') ?? '';
|
|
862
|
+
// Standard convention: body first, LANGUAGE after
|
|
863
|
+
return [[makeKeyword('DO'), ' ', '$$', body, '$$', hardline, makeKeyword('LANGUAGE'), ' ', language], ';'];
|
|
864
|
+
}
|
|
865
|
+
// ---------------------------------------------------------------------------
|
|
866
|
+
// MERGE
|
|
867
|
+
// ---------------------------------------------------------------------------
|
|
868
|
+
function printMerge(node, opts) {
|
|
869
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
870
|
+
const printNode = printWith(opts);
|
|
871
|
+
const target = prop(node, 'target');
|
|
872
|
+
const source = prop(node, 'source');
|
|
873
|
+
const on = prop(node, 'on');
|
|
874
|
+
const whens = propArr(node, 'whens');
|
|
875
|
+
const returning = propArr(node, 'returning');
|
|
876
|
+
const ctes = prop(node, 'ctes');
|
|
877
|
+
const parts = [];
|
|
878
|
+
if (ctes)
|
|
879
|
+
parts.push(...printCtes(ctes, opts, printNode));
|
|
880
|
+
parts.push([makeKeyword('MERGE INTO'), ' ', target ? printNode(target) : '']);
|
|
881
|
+
parts.push([makeKeyword('USING'), ' ', source ? printNode(source) : '']);
|
|
882
|
+
parts.push([makeKeyword('ON'), ' ', on ? printNode(on) : '']);
|
|
883
|
+
for (const w of whens) {
|
|
884
|
+
const matchKind = propStr(w, 'matchKind') ?? 'MATCHED';
|
|
885
|
+
const cmd = propStr(w, 'cmd') ?? 'DO NOTHING';
|
|
886
|
+
const condition = prop(w, 'condition');
|
|
887
|
+
const targets = propArr(w, 'targets');
|
|
888
|
+
const values = propArr(w, 'values');
|
|
889
|
+
let whenLine = [makeKeyword('WHEN'), ' ', makeKeyword(matchKind)];
|
|
890
|
+
if (condition)
|
|
891
|
+
whenLine = [whenLine, ' ', makeKeyword('AND'), ' ', printNode(condition)];
|
|
892
|
+
whenLine = [whenLine, ' ', makeKeyword('THEN')];
|
|
893
|
+
let actionDoc;
|
|
894
|
+
if (cmd === 'DO NOTHING') {
|
|
895
|
+
actionDoc = makeKeyword('DO NOTHING');
|
|
896
|
+
}
|
|
897
|
+
else if (cmd === 'DELETE') {
|
|
898
|
+
actionDoc = makeKeyword('DELETE');
|
|
899
|
+
}
|
|
900
|
+
else if (cmd === 'UPDATE') {
|
|
901
|
+
// ResTarget: name=column, val=value → "col = val"
|
|
902
|
+
const assignments = targets.map((t) => {
|
|
903
|
+
const column = propStr(t, 'name') ?? '';
|
|
904
|
+
const val = prop(t, 'val');
|
|
905
|
+
return [column, ' = ', val ? printNode(val) : ''];
|
|
906
|
+
});
|
|
907
|
+
actionDoc = [makeKeyword('UPDATE SET'), indent([hardline, join(hardSep(opts), assignments)])];
|
|
908
|
+
}
|
|
909
|
+
else { // INSERT
|
|
910
|
+
const cols = targets.filter((t) => t.type === 'ResTarget').map((t) => propStr(t, 'name') ?? '');
|
|
911
|
+
const colList = cols.length > 0 ? [' (', join(', ', cols), ')'] : '';
|
|
912
|
+
const valList = values.length > 0
|
|
913
|
+
? [makeKeyword('VALUES'), ' (', join(', ', values.map(printNode)), ')']
|
|
914
|
+
: [makeKeyword('DEFAULT VALUES')];
|
|
915
|
+
actionDoc = [makeKeyword('INSERT'), colList, hardline, valList];
|
|
916
|
+
}
|
|
917
|
+
parts.push([whenLine, indent([hardline, actionDoc])]);
|
|
918
|
+
}
|
|
919
|
+
if (returning.length > 0) {
|
|
920
|
+
parts.push(printListClause('RETURNING', returning, opts, printNode));
|
|
921
|
+
}
|
|
922
|
+
return [join(hardline, parts), ';'];
|
|
923
|
+
}
|
|
924
|
+
// ---------------------------------------------------------------------------
|
|
925
|
+
// ALTER FUNCTION / PROCEDURE
|
|
926
|
+
// ---------------------------------------------------------------------------
|
|
927
|
+
function printAlterFunction(node, opts) {
|
|
928
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
929
|
+
const name = propStr(node, 'name') ?? '';
|
|
930
|
+
const argTypes = node.props?.['argTypes'] ?? [];
|
|
931
|
+
const rename = propStr(node, 'rename');
|
|
932
|
+
const options = node.props?.['options'] ?? [];
|
|
933
|
+
const argList = argTypes.length > 0
|
|
934
|
+
? ['(', join(', ', argTypes.map((t) => makeKeyword(t))), ')']
|
|
935
|
+
: '()';
|
|
936
|
+
if (rename) {
|
|
937
|
+
return [[makeKeyword('ALTER FUNCTION'), ' ', name, argList, ' ', makeKeyword('RENAME TO'), ' ', rename], ';'];
|
|
938
|
+
}
|
|
939
|
+
const optionDocs = options.map((o) => {
|
|
940
|
+
switch (o.name) {
|
|
941
|
+
case 'volatility': return makeKeyword(o.value ?? '');
|
|
942
|
+
case 'cost': return [makeKeyword('COST'), ' ', o.value ?? ''];
|
|
943
|
+
case 'rows': return [makeKeyword('ROWS'), ' ', o.value ?? ''];
|
|
944
|
+
case 'called': return makeKeyword(o.value === 'true' ? 'CALLED ON NULL INPUT' : 'STRICT');
|
|
945
|
+
case 'security': return makeKeyword(o.value === 'true' ? 'SECURITY DEFINER' : 'SECURITY INVOKER');
|
|
946
|
+
default: return [makeKeyword('SET'), ' ', o.name, ' = ', o.value ?? ''];
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
return [[makeKeyword('ALTER FUNCTION'), ' ', name, argList, indent([hardline, join(hardline, optionDocs)])], ';'];
|
|
950
|
+
}
|
|
951
|
+
// ---------------------------------------------------------------------------
|
|
952
|
+
// ALTER OWNER / ALTER ... SET SCHEMA
|
|
953
|
+
// ---------------------------------------------------------------------------
|
|
954
|
+
function printAlterOwner(node, opts) {
|
|
955
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
956
|
+
const objType = propStr(node, 'objType') ?? '';
|
|
957
|
+
const name = propStr(node, 'name') ?? '';
|
|
958
|
+
const newOwner = propStr(node, 'newOwner') ?? '';
|
|
959
|
+
return [[makeKeyword(`ALTER ${objType}`), ' ', name, ' ', makeKeyword('OWNER TO'), ' ', newOwner], ';'];
|
|
960
|
+
}
|
|
961
|
+
function printAlterObjectSchema(node, opts) {
|
|
962
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
963
|
+
const objType = propStr(node, 'objType') ?? '';
|
|
964
|
+
const name = propStr(node, 'name') ?? '';
|
|
965
|
+
const newSchema = propStr(node, 'newSchema') ?? '';
|
|
966
|
+
return [[makeKeyword(`ALTER ${objType}`), ' ', name, ' ', makeKeyword('SET SCHEMA'), ' ', newSchema], ';'];
|
|
967
|
+
}
|
|
968
|
+
// ---------------------------------------------------------------------------
|
|
969
|
+
// REFRESH MATERIALIZED VIEW
|
|
970
|
+
// ---------------------------------------------------------------------------
|
|
971
|
+
function printRefreshMatView(node, opts) {
|
|
972
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
973
|
+
const name = prop(node, 'name');
|
|
974
|
+
const concurrent = propBool(node, 'concurrent');
|
|
975
|
+
return [
|
|
976
|
+
makeKeyword('REFRESH MATERIALIZED VIEW'),
|
|
977
|
+
concurrent ? [' ', makeKeyword('CONCURRENTLY')] : '',
|
|
978
|
+
' ', rangeVarName(name),
|
|
979
|
+
';',
|
|
980
|
+
];
|
|
981
|
+
}
|
|
982
|
+
// ---------------------------------------------------------------------------
|
|
983
|
+
// SELECT INTO
|
|
984
|
+
// ---------------------------------------------------------------------------
|
|
985
|
+
function printSelectInto(node, opts) {
|
|
986
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
987
|
+
const printNode = printWith(opts);
|
|
988
|
+
const temp = propBool(node, 'temp');
|
|
989
|
+
const into = prop(node, 'into');
|
|
990
|
+
const targets = propArr(node, 'targetList');
|
|
991
|
+
const from = propArr(node, 'from');
|
|
992
|
+
const where = prop(node, 'where');
|
|
993
|
+
const groupBy = propArr(node, 'groupBy');
|
|
994
|
+
const having = prop(node, 'having');
|
|
995
|
+
const orderBy = propArr(node, 'orderBy');
|
|
996
|
+
const limit = prop(node, 'limit');
|
|
997
|
+
const offset = prop(node, 'offset');
|
|
998
|
+
const parts = [];
|
|
999
|
+
parts.push(printListClause('SELECT', targets, opts, printNode));
|
|
1000
|
+
const intoKw = temp ? [makeKeyword('INTO'), ' ', makeKeyword('TEMP')] : makeKeyword('INTO');
|
|
1001
|
+
parts.push([intoKw, indent([hardline, rangeVarName(into)])]);
|
|
1002
|
+
if (from.length > 0) {
|
|
1003
|
+
parts.push(printFromClause(from, opts, printNode));
|
|
1004
|
+
}
|
|
1005
|
+
if (where)
|
|
1006
|
+
parts.push(printBoolClause('WHERE', where, opts, printNode));
|
|
1007
|
+
if (groupBy.length > 0)
|
|
1008
|
+
parts.push(printListClause('GROUP BY', groupBy, opts, printNode));
|
|
1009
|
+
if (having)
|
|
1010
|
+
parts.push(printBoolClause('HAVING', having, opts, printNode));
|
|
1011
|
+
if (orderBy.length > 0)
|
|
1012
|
+
parts.push(printListClause('ORDER BY', orderBy, opts, printNode));
|
|
1013
|
+
if (limit)
|
|
1014
|
+
parts.push([makeKeyword('LIMIT'), ' ', printNode(limit)]);
|
|
1015
|
+
if (offset)
|
|
1016
|
+
parts.push([makeKeyword('OFFSET'), ' ', printNode(offset)]);
|
|
1017
|
+
return [join(hardline, parts), ';'];
|
|
1018
|
+
}
|
|
1019
|
+
// ---------------------------------------------------------------------------
|
|
1020
|
+
// CREATE RULE
|
|
1021
|
+
// ---------------------------------------------------------------------------
|
|
1022
|
+
function printRule(node, opts) {
|
|
1023
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1024
|
+
const printNode = printWith(opts);
|
|
1025
|
+
const ruleName = propStr(node, 'ruleName') ?? '';
|
|
1026
|
+
const relation = prop(node, 'relation');
|
|
1027
|
+
const event = propStr(node, 'event') ?? 'SELECT';
|
|
1028
|
+
const instead = propBool(node, 'instead');
|
|
1029
|
+
const doInstead = propBool(node, 'doInstead');
|
|
1030
|
+
const where = prop(node, 'where');
|
|
1031
|
+
const actions = propArr(node, 'actions');
|
|
1032
|
+
const parts = [];
|
|
1033
|
+
parts.push([makeKeyword('CREATE RULE'), ' ', ruleName]);
|
|
1034
|
+
parts.push([makeKeyword('AS ON'), ' ', makeKeyword(event)]);
|
|
1035
|
+
parts.push([makeKeyword('TO'), ' ', rangeVarName(relation)]);
|
|
1036
|
+
if (where)
|
|
1037
|
+
parts.push(printBoolClause('WHERE', where, opts, printNode));
|
|
1038
|
+
const doKw = instead ? makeKeyword('DO INSTEAD') : doInstead ? makeKeyword('DO ALSO') : makeKeyword('DO ALSO');
|
|
1039
|
+
if (actions.length === 0) {
|
|
1040
|
+
parts.push([doKw, ' ', makeKeyword('NOTHING')]);
|
|
1041
|
+
}
|
|
1042
|
+
else if (actions.length === 1) {
|
|
1043
|
+
const action = actions[0];
|
|
1044
|
+
if (action.type === 'NothingStmt') {
|
|
1045
|
+
parts.push([doKw, ' ', makeKeyword('NOTHING')]);
|
|
1046
|
+
}
|
|
1047
|
+
else {
|
|
1048
|
+
parts.push([doKw, indent([hardline, printQueryExpr(action, opts)])]);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
else {
|
|
1052
|
+
const actionDocs = actions.map((a) => a.type === 'NothingStmt' ? makeKeyword('NOTHING') : printQueryExpr(a, opts));
|
|
1053
|
+
parts.push([doKw, ' (', indent([hardline, join([';', hardline], actionDocs)]), hardline, ')']);
|
|
1054
|
+
}
|
|
1055
|
+
return [join(hardline, parts), ';'];
|
|
1056
|
+
}
|
|
1057
|
+
// ---------------------------------------------------------------------------
|
|
1058
|
+
// Row Security Policies
|
|
1059
|
+
// ---------------------------------------------------------------------------
|
|
1060
|
+
function printCreatePolicy(node, opts) {
|
|
1061
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1062
|
+
const printNode = printWith(opts);
|
|
1063
|
+
const policyName = propStr(node, 'policyName') ?? '';
|
|
1064
|
+
const table = prop(node, 'table');
|
|
1065
|
+
const cmdName = propStr(node, 'cmdName');
|
|
1066
|
+
const permissive = node.props?.['permissive']; // false = RESTRICTIVE, null = PERMISSIVE (default)
|
|
1067
|
+
const using = prop(node, 'using');
|
|
1068
|
+
const withCheck = prop(node, 'withCheck');
|
|
1069
|
+
const parts = [];
|
|
1070
|
+
parts.push([makeKeyword('CREATE POLICY'), ' ', policyName]);
|
|
1071
|
+
const onPart = permissive === false
|
|
1072
|
+
? [makeKeyword('AS'), ' ', makeKeyword('RESTRICTIVE'), ' ', makeKeyword('ON'), ' ', rangeVarName(table)]
|
|
1073
|
+
: [makeKeyword('ON'), ' ', rangeVarName(table)];
|
|
1074
|
+
parts.push(onPart);
|
|
1075
|
+
if (cmdName)
|
|
1076
|
+
parts.push([makeKeyword('FOR'), ' ', makeKeyword(cmdName)]);
|
|
1077
|
+
if (using)
|
|
1078
|
+
parts.push([makeKeyword('USING'), ' (', printNode(using), ')']);
|
|
1079
|
+
if (withCheck)
|
|
1080
|
+
parts.push([makeKeyword('WITH CHECK'), ' (', printNode(withCheck), ')']);
|
|
1081
|
+
return [join(hardline, parts), ';'];
|
|
1082
|
+
}
|
|
1083
|
+
function printAlterPolicy(node, opts) {
|
|
1084
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1085
|
+
const printNode = printWith(opts);
|
|
1086
|
+
const policyName = propStr(node, 'policyName') ?? '';
|
|
1087
|
+
const table = prop(node, 'table');
|
|
1088
|
+
const using = prop(node, 'using');
|
|
1089
|
+
const withCheck = prop(node, 'withCheck');
|
|
1090
|
+
const parts = [];
|
|
1091
|
+
parts.push([makeKeyword('ALTER POLICY'), ' ', policyName]);
|
|
1092
|
+
parts.push([makeKeyword('ON'), ' ', rangeVarName(table)]);
|
|
1093
|
+
if (using)
|
|
1094
|
+
parts.push([makeKeyword('USING'), ' (', printNode(using), ')']);
|
|
1095
|
+
if (withCheck)
|
|
1096
|
+
parts.push([makeKeyword('WITH CHECK'), ' (', printNode(withCheck), ')']);
|
|
1097
|
+
return [join(hardline, parts), ';'];
|
|
1098
|
+
}
|
|
1099
|
+
// ---------------------------------------------------------------------------
|
|
1100
|
+
// Cursors
|
|
1101
|
+
// ---------------------------------------------------------------------------
|
|
1102
|
+
function printDeclareCursor(node, opts) {
|
|
1103
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1104
|
+
const name = propStr(node, 'name') ?? '';
|
|
1105
|
+
const scroll = propBool(node, 'scroll');
|
|
1106
|
+
const noScroll = propBool(node, 'noScroll');
|
|
1107
|
+
const insensitive = propBool(node, 'insensitive');
|
|
1108
|
+
const binary = propBool(node, 'binary');
|
|
1109
|
+
const query = prop(node, 'query');
|
|
1110
|
+
const scrollKw = noScroll ? [' ', makeKeyword('NO SCROLL')] : scroll ? [' ', makeKeyword('SCROLL')] : '';
|
|
1111
|
+
const binaryKw = binary ? [makeKeyword('BINARY'), ' '] : '';
|
|
1112
|
+
const insensKw = insensitive ? [makeKeyword('INSENSITIVE'), ' '] : '';
|
|
1113
|
+
return [
|
|
1114
|
+
[makeKeyword('DECLARE'), ' ', name, scrollKw, ' ', insensKw, binaryKw, makeKeyword('CURSOR'), ' ', makeKeyword('FOR')],
|
|
1115
|
+
hardline,
|
|
1116
|
+
query ? printQueryExpr(query, opts) : '',
|
|
1117
|
+
';',
|
|
1118
|
+
];
|
|
1119
|
+
}
|
|
1120
|
+
function printFetch(node, opts) {
|
|
1121
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1122
|
+
const direction = propStr(node, 'direction') ?? 'NEXT';
|
|
1123
|
+
const count = node.props?.['count'];
|
|
1124
|
+
const cursor = propStr(node, 'cursor') ?? '';
|
|
1125
|
+
const isMove = propBool(node, 'isMove');
|
|
1126
|
+
const verb = isMove ? makeKeyword('MOVE') : makeKeyword('FETCH');
|
|
1127
|
+
let dirDoc;
|
|
1128
|
+
if (count !== undefined && count !== null && direction !== 'ALL') {
|
|
1129
|
+
// FETCH FORWARD 10 / FETCH ABSOLUTE 5 etc.
|
|
1130
|
+
dirDoc = [makeKeyword(direction), ' ', String(count)];
|
|
1131
|
+
}
|
|
1132
|
+
else {
|
|
1133
|
+
dirDoc = makeKeyword(direction);
|
|
1134
|
+
}
|
|
1135
|
+
return [[verb, ' ', dirDoc, ' ', makeKeyword('FROM'), ' ', cursor], ';'];
|
|
1136
|
+
}
|
|
1137
|
+
function printClosePortal(node, opts) {
|
|
1138
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1139
|
+
const cursor = propStr(node, 'cursor');
|
|
1140
|
+
return [[makeKeyword('CLOSE'), ' ', cursor ?? makeKeyword('ALL')], ';'];
|
|
1141
|
+
}
|
|
1142
|
+
// ---------------------------------------------------------------------------
|
|
1143
|
+
// COPY
|
|
1144
|
+
// ---------------------------------------------------------------------------
|
|
1145
|
+
function printCopy(node, opts) {
|
|
1146
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1147
|
+
const relation = prop(node, 'relation');
|
|
1148
|
+
const query = prop(node, 'query');
|
|
1149
|
+
const columns = node.props?.['columns'] ?? [];
|
|
1150
|
+
const isFrom = propBool(node, 'isFrom');
|
|
1151
|
+
const isProgram = propBool(node, 'isProgram');
|
|
1152
|
+
const filename = propStr(node, 'filename');
|
|
1153
|
+
const options = node.props?.['options'] ?? [];
|
|
1154
|
+
const colsPart = columns.length > 0 ? [' (', join(', ', columns), ')'] : '';
|
|
1155
|
+
let sourceDest;
|
|
1156
|
+
if (relation) {
|
|
1157
|
+
sourceDest = [rangeVarName(relation), colsPart];
|
|
1158
|
+
}
|
|
1159
|
+
else if (query) {
|
|
1160
|
+
sourceDest = ['(', indent([hardline, printQueryExpr(query, opts)]), hardline, ')'];
|
|
1161
|
+
}
|
|
1162
|
+
else {
|
|
1163
|
+
sourceDest = '';
|
|
1164
|
+
}
|
|
1165
|
+
const dirKw = isFrom ? makeKeyword('FROM') : makeKeyword('TO');
|
|
1166
|
+
let dest;
|
|
1167
|
+
if (isProgram && filename) {
|
|
1168
|
+
dest = [makeKeyword('PROGRAM'), ' ', `'${filename}'`];
|
|
1169
|
+
}
|
|
1170
|
+
else if (filename) {
|
|
1171
|
+
dest = `'${filename}'`;
|
|
1172
|
+
}
|
|
1173
|
+
else {
|
|
1174
|
+
dest = makeKeyword('STDOUT');
|
|
1175
|
+
}
|
|
1176
|
+
let optionPart = '';
|
|
1177
|
+
if (options.length > 0) {
|
|
1178
|
+
const optDocs = options.map((o) => {
|
|
1179
|
+
const val = o.value ?? '';
|
|
1180
|
+
// Quote if not already quoted, not a boolean, and not a plain identifier
|
|
1181
|
+
const fmtVal = val.startsWith("'") || val === 'true' || val === 'false'
|
|
1182
|
+
? val
|
|
1183
|
+
: /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(val) ? val : `'${val.replace(/'/g, "''")}'`;
|
|
1184
|
+
return [makeKeyword(o.name.toUpperCase()), ' ', fmtVal];
|
|
1185
|
+
});
|
|
1186
|
+
optionPart = [' (', join(', ', optDocs), ')'];
|
|
1187
|
+
}
|
|
1188
|
+
return [[makeKeyword('COPY'), ' ', sourceDest, ' ', dirKw, ' ', dest, optionPart], ';'];
|
|
1189
|
+
}
|
|
1190
|
+
// ---------------------------------------------------------------------------
|
|
1191
|
+
// EXPLAIN
|
|
1192
|
+
// ---------------------------------------------------------------------------
|
|
1193
|
+
function printExplain(node, opts) {
|
|
1194
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1195
|
+
const query = prop(node, 'query');
|
|
1196
|
+
const options = node.props?.['options'] ?? [];
|
|
1197
|
+
// Simple cases: no options at all, or just ANALYZE
|
|
1198
|
+
const analyzeOnly = options.length === 1 && options[0].name === 'analyze';
|
|
1199
|
+
const verboseOnly = options.length === 1 && options[0].name === 'verbose';
|
|
1200
|
+
if (options.length === 0) {
|
|
1201
|
+
return [[makeKeyword('EXPLAIN'), ' ', query ? printQueryExpr(query, opts) : ''], ';'];
|
|
1202
|
+
}
|
|
1203
|
+
if (analyzeOnly) {
|
|
1204
|
+
return [[makeKeyword('EXPLAIN'), ' ', makeKeyword('ANALYZE'), ' ', query ? printQueryExpr(query, opts) : ''], ';'];
|
|
1205
|
+
}
|
|
1206
|
+
if (verboseOnly) {
|
|
1207
|
+
return [[makeKeyword('EXPLAIN'), ' ', makeKeyword('VERBOSE'), ' ', query ? printQueryExpr(query, opts) : ''], ';'];
|
|
1208
|
+
}
|
|
1209
|
+
const optDocs = options.map((o) => {
|
|
1210
|
+
const val = o.value === 'true' ? makeKeyword('true') : o.value === 'false' ? makeKeyword('false') : o.value;
|
|
1211
|
+
return [makeKeyword(o.name.toUpperCase()), ' ', val];
|
|
1212
|
+
});
|
|
1213
|
+
return [[makeKeyword('EXPLAIN'), ' (', join(', ', optDocs), ') ', query ? printQueryExpr(query, opts) : ''], ';'];
|
|
1214
|
+
}
|
|
1215
|
+
// ---------------------------------------------------------------------------
|
|
1216
|
+
// PREPARE / EXECUTE / DEALLOCATE
|
|
1217
|
+
// ---------------------------------------------------------------------------
|
|
1218
|
+
function printPrepare(node, opts) {
|
|
1219
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1220
|
+
const name = propStr(node, 'name') ?? '';
|
|
1221
|
+
const argTypes = node.props?.['argTypes'] ?? [];
|
|
1222
|
+
const query = prop(node, 'query');
|
|
1223
|
+
const argsPart = argTypes.length > 0
|
|
1224
|
+
? ['(', join(', ', argTypes.map((t) => makeKeyword(t))), ')']
|
|
1225
|
+
: '';
|
|
1226
|
+
return [
|
|
1227
|
+
[makeKeyword('PREPARE'), ' ', name, argsPart, ' ', makeKeyword('AS')],
|
|
1228
|
+
hardline,
|
|
1229
|
+
query ? printQueryExpr(query, opts) : '',
|
|
1230
|
+
';',
|
|
1231
|
+
];
|
|
1232
|
+
}
|
|
1233
|
+
function printExecute(node, opts) {
|
|
1234
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1235
|
+
const printNode = printWith(opts);
|
|
1236
|
+
const name = propStr(node, 'name') ?? '';
|
|
1237
|
+
const params = propArr(node, 'params');
|
|
1238
|
+
const paramsPart = params.length > 0
|
|
1239
|
+
? ['(', join(', ', params.map(printNode)), ')']
|
|
1240
|
+
: '';
|
|
1241
|
+
return [[makeKeyword('EXECUTE'), ' ', name, paramsPart], ';'];
|
|
1242
|
+
}
|
|
1243
|
+
function printDeallocate(node, opts) {
|
|
1244
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1245
|
+
const name = propStr(node, 'name');
|
|
1246
|
+
return [[makeKeyword('DEALLOCATE'), ' ', name ? name : makeKeyword('ALL')], ';'];
|
|
1247
|
+
}
|
|
1248
|
+
// ---------------------------------------------------------------------------
|
|
1249
|
+
// LISTEN / UNLISTEN / NOTIFY
|
|
1250
|
+
// ---------------------------------------------------------------------------
|
|
1251
|
+
function printListen(node, opts) {
|
|
1252
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1253
|
+
const channel = propStr(node, 'channel') ?? '';
|
|
1254
|
+
return [[makeKeyword('LISTEN'), ' ', channel], ';'];
|
|
1255
|
+
}
|
|
1256
|
+
function printUnlisten(node, opts) {
|
|
1257
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1258
|
+
const channel = propStr(node, 'channel');
|
|
1259
|
+
return [[makeKeyword('UNLISTEN'), ' ', channel ? channel : '*'], ';'];
|
|
1260
|
+
}
|
|
1261
|
+
function printNotify(node, opts) {
|
|
1262
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1263
|
+
const channel = propStr(node, 'channel') ?? '';
|
|
1264
|
+
const payload = propStr(node, 'payload');
|
|
1265
|
+
const payloadPart = payload ? [', ', `'${payload}'`] : '';
|
|
1266
|
+
return [[makeKeyword('NOTIFY'), ' ', channel, payloadPart], ';'];
|
|
1267
|
+
}
|
|
1268
|
+
// ---------------------------------------------------------------------------
|
|
1269
|
+
// LOCK TABLE
|
|
1270
|
+
// ---------------------------------------------------------------------------
|
|
1271
|
+
function printLockTable(node, opts) {
|
|
1272
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1273
|
+
const relations = propArr(node, 'relations');
|
|
1274
|
+
const mode = propStr(node, 'mode') ?? 'ACCESS EXCLUSIVE';
|
|
1275
|
+
const nowait = propBool(node, 'nowait');
|
|
1276
|
+
return [
|
|
1277
|
+
makeKeyword('LOCK TABLE'), ' ', join(', ', relations.map(rangeVarName)),
|
|
1278
|
+
' ', makeKeyword('IN'), ' ', makeKeyword(mode), ' ', makeKeyword('MODE'),
|
|
1279
|
+
nowait ? [' ', makeKeyword('NOWAIT')] : '',
|
|
1280
|
+
';',
|
|
1281
|
+
];
|
|
1282
|
+
}
|
|
1283
|
+
// ---------------------------------------------------------------------------
|
|
1284
|
+
// P4: CREATE TABLE PARTITION OF
|
|
1285
|
+
// ---------------------------------------------------------------------------
|
|
1286
|
+
function printCreateTablePartitionOf(node, opts) {
|
|
1287
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1288
|
+
const name = prop(node, 'name');
|
|
1289
|
+
const parent = prop(node, 'parent');
|
|
1290
|
+
const bound = prop(node, 'bound');
|
|
1291
|
+
let boundDoc = '';
|
|
1292
|
+
if (bound) {
|
|
1293
|
+
const isDefault = propBool(bound, 'isDefault');
|
|
1294
|
+
const lower = bound.props?.['lower'] ?? [];
|
|
1295
|
+
const upper = bound.props?.['upper'] ?? [];
|
|
1296
|
+
const listDatums = bound.props?.['listDatums'] ?? [];
|
|
1297
|
+
const modulus = bound.props?.['modulus'];
|
|
1298
|
+
const remainder = bound.props?.['remainder'];
|
|
1299
|
+
if (isDefault) {
|
|
1300
|
+
boundDoc = [hardline, makeKeyword('DEFAULT')];
|
|
1301
|
+
}
|
|
1302
|
+
else if (lower.length > 0 || upper.length > 0) {
|
|
1303
|
+
boundDoc = [
|
|
1304
|
+
hardline, makeKeyword('FOR VALUES FROM'),
|
|
1305
|
+
' (', join(', ', lower), ')',
|
|
1306
|
+
' ', makeKeyword('TO'),
|
|
1307
|
+
' (', join(', ', upper), ')',
|
|
1308
|
+
];
|
|
1309
|
+
}
|
|
1310
|
+
else if (listDatums.length > 0) {
|
|
1311
|
+
boundDoc = [hardline, makeKeyword('FOR VALUES IN'), ' (', join(', ', listDatums), ')'];
|
|
1312
|
+
}
|
|
1313
|
+
else if (modulus !== undefined && remainder !== undefined) {
|
|
1314
|
+
boundDoc = [hardline, makeKeyword('FOR VALUES WITH'), ' (', makeKeyword('MODULUS'), ' ', String(modulus), ', ', makeKeyword('REMAINDER'), ' ', String(remainder), ')'];
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
return [
|
|
1318
|
+
makeKeyword('CREATE TABLE'), ' ', rangeVarName(name), hardline,
|
|
1319
|
+
indent([makeKeyword('PARTITION OF'), ' ', rangeVarName(parent)]),
|
|
1320
|
+
boundDoc,
|
|
1321
|
+
';',
|
|
1322
|
+
];
|
|
1323
|
+
}
|
|
1324
|
+
// ---------------------------------------------------------------------------
|
|
1325
|
+
// P4: VACUUM / ANALYZE / CLUSTER / REINDEX
|
|
1326
|
+
// ---------------------------------------------------------------------------
|
|
1327
|
+
function printVacuum(node, opts) {
|
|
1328
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1329
|
+
const isVacuum = propBool(node, 'isVacuum');
|
|
1330
|
+
const options = node.props?.['options'] ?? [];
|
|
1331
|
+
const relations = propArr(node, 'relations');
|
|
1332
|
+
const relDoc = relations.length > 0
|
|
1333
|
+
? [' ', join(', ', relations.map(rangeVarName))]
|
|
1334
|
+
: '';
|
|
1335
|
+
if (!isVacuum) {
|
|
1336
|
+
return [[makeKeyword('ANALYZE'), relDoc], ';'];
|
|
1337
|
+
}
|
|
1338
|
+
if (options.length === 0) {
|
|
1339
|
+
return [[makeKeyword('VACUUM'), relDoc], ';'];
|
|
1340
|
+
}
|
|
1341
|
+
if (options.length === 1 && (options[0] === 'VERBOSE' || options[0] === 'ANALYZE')) {
|
|
1342
|
+
return [[makeKeyword('VACUUM'), ' ', makeKeyword(options[0]), relDoc], ';'];
|
|
1343
|
+
}
|
|
1344
|
+
return [[makeKeyword('VACUUM'), ' (', join(', ', options.map((o) => makeKeyword(o.toLowerCase()))), ')', relDoc], ';'];
|
|
1345
|
+
}
|
|
1346
|
+
function printCluster(node, opts) {
|
|
1347
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1348
|
+
const relation = prop(node, 'relation');
|
|
1349
|
+
const indexName = propStr(node, 'indexName');
|
|
1350
|
+
return [
|
|
1351
|
+
[makeKeyword('CLUSTER'), ' ', rangeVarName(relation),
|
|
1352
|
+
indexName ? [' ', makeKeyword('USING'), ' ', indexName] : ''],
|
|
1353
|
+
';',
|
|
1354
|
+
];
|
|
1355
|
+
}
|
|
1356
|
+
function printReindex(node, opts) {
|
|
1357
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1358
|
+
const kind = propStr(node, 'kind') ?? 'TABLE';
|
|
1359
|
+
const relation = prop(node, 'relation');
|
|
1360
|
+
const options = node.props?.['options'] ?? [];
|
|
1361
|
+
const optDoc = options.length > 0
|
|
1362
|
+
? [' (', join(', ', options.map((o) => makeKeyword(o.toLowerCase()))), ')']
|
|
1363
|
+
: '';
|
|
1364
|
+
return [
|
|
1365
|
+
[makeKeyword('REINDEX'), optDoc, ' ', makeKeyword(kind), ' ', rangeVarName(relation)],
|
|
1366
|
+
';',
|
|
1367
|
+
];
|
|
1368
|
+
}
|
|
1369
|
+
// ---------------------------------------------------------------------------
|
|
1370
|
+
// P4: Foreign Data Wrappers
|
|
1371
|
+
// ---------------------------------------------------------------------------
|
|
1372
|
+
function printFdwOptions(node, opts) {
|
|
1373
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1374
|
+
const options = propArr(node, 'options');
|
|
1375
|
+
if (options.length === 0)
|
|
1376
|
+
return '';
|
|
1377
|
+
const pairs = options.map((o) => {
|
|
1378
|
+
const key = propStr(o, 'key') ?? '';
|
|
1379
|
+
const val = propStr(o, 'val') ?? '';
|
|
1380
|
+
return [key, " '", val, "'"].join('');
|
|
1381
|
+
});
|
|
1382
|
+
return [' ', makeKeyword('OPTIONS'), ' (', join(', ', pairs), ')'];
|
|
1383
|
+
}
|
|
1384
|
+
function printCreateForeignServer(node, opts) {
|
|
1385
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1386
|
+
const name = propStr(node, 'name') ?? '';
|
|
1387
|
+
const fdwName = propStr(node, 'fdwName') ?? '';
|
|
1388
|
+
return [
|
|
1389
|
+
[makeKeyword('CREATE SERVER'), ' ', name, hardline,
|
|
1390
|
+
indent([makeKeyword('FOREIGN DATA WRAPPER'), ' ', fdwName]),
|
|
1391
|
+
printFdwOptions(node, opts)],
|
|
1392
|
+
';',
|
|
1393
|
+
];
|
|
1394
|
+
}
|
|
1395
|
+
function printCreateForeignTable(node, opts) {
|
|
1396
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1397
|
+
const printNode = printWith(opts);
|
|
1398
|
+
const name = prop(node, 'name');
|
|
1399
|
+
const columns = propArr(node, 'columns');
|
|
1400
|
+
const serverName = propStr(node, 'serverName') ?? '';
|
|
1401
|
+
return [
|
|
1402
|
+
makeKeyword('CREATE FOREIGN TABLE'), ' ', rangeVarName(name), ' (',
|
|
1403
|
+
indent([hardline, join([',', hardline], columns.map(printNode))]),
|
|
1404
|
+
hardline, ')',
|
|
1405
|
+
hardline, indent([makeKeyword('SERVER'), ' ', serverName]),
|
|
1406
|
+
printFdwOptions(node, opts),
|
|
1407
|
+
';',
|
|
1408
|
+
];
|
|
1409
|
+
}
|
|
1410
|
+
function printCreateUserMapping(node, opts) {
|
|
1411
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1412
|
+
const user = propStr(node, 'user') ?? '';
|
|
1413
|
+
const serverName = propStr(node, 'serverName') ?? '';
|
|
1414
|
+
return [
|
|
1415
|
+
[makeKeyword('CREATE USER MAPPING FOR'), ' ', makeKeyword(user), hardline,
|
|
1416
|
+
indent([makeKeyword('SERVER'), ' ', serverName]),
|
|
1417
|
+
printFdwOptions(node, opts)],
|
|
1418
|
+
';',
|
|
1419
|
+
];
|
|
1420
|
+
}
|
|
1421
|
+
function printImportForeignSchema(node, opts) {
|
|
1422
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1423
|
+
const remoteSchema = propStr(node, 'remoteSchema') ?? '';
|
|
1424
|
+
const serverName = propStr(node, 'serverName') ?? '';
|
|
1425
|
+
const localSchema = propStr(node, 'localSchema') ?? '';
|
|
1426
|
+
return [
|
|
1427
|
+
[makeKeyword('IMPORT FOREIGN SCHEMA'), ' ', remoteSchema, hardline,
|
|
1428
|
+
makeKeyword('FROM SERVER'), ' ', serverName, hardline,
|
|
1429
|
+
makeKeyword('INTO'), ' ', localSchema],
|
|
1430
|
+
';',
|
|
1431
|
+
];
|
|
1432
|
+
}
|
|
1433
|
+
// ---------------------------------------------------------------------------
|
|
1434
|
+
// P4: Logical Replication
|
|
1435
|
+
// ---------------------------------------------------------------------------
|
|
1436
|
+
function printCreatePublication(node, opts) {
|
|
1437
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1438
|
+
const name = propStr(node, 'name') ?? '';
|
|
1439
|
+
const tables = propArr(node, 'tables');
|
|
1440
|
+
const forAll = propBool(node, 'forAllTables');
|
|
1441
|
+
let forPart;
|
|
1442
|
+
if (forAll) {
|
|
1443
|
+
forPart = [' ', makeKeyword('FOR ALL TABLES')];
|
|
1444
|
+
}
|
|
1445
|
+
else if (tables.length > 0) {
|
|
1446
|
+
forPart = [hardline, indent([makeKeyword('FOR TABLE'), ' ', join(', ', tables.map(rangeVarName))])];
|
|
1447
|
+
}
|
|
1448
|
+
else {
|
|
1449
|
+
forPart = '';
|
|
1450
|
+
}
|
|
1451
|
+
return [[makeKeyword('CREATE PUBLICATION'), ' ', name, forPart], ';'];
|
|
1452
|
+
}
|
|
1453
|
+
function printCreateSubscription(node, opts) {
|
|
1454
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1455
|
+
const name = propStr(node, 'name') ?? '';
|
|
1456
|
+
const conninfo = propStr(node, 'conninfo') ?? '';
|
|
1457
|
+
const publications = node.props?.['publications'] ?? [];
|
|
1458
|
+
return [
|
|
1459
|
+
[makeKeyword('CREATE SUBSCRIPTION'), ' ', name, hardline,
|
|
1460
|
+
indent([makeKeyword('CONNECTION'), " '", conninfo, "'"]), hardline,
|
|
1461
|
+
indent([makeKeyword('PUBLICATION'), ' ', join(', ', publications)])],
|
|
1462
|
+
';',
|
|
1463
|
+
];
|
|
1464
|
+
}
|
|
1465
|
+
function printDropSubscription(node, opts) {
|
|
1466
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1467
|
+
const name = propStr(node, 'name') ?? '';
|
|
1468
|
+
const ifExists = propBool(node, 'ifExists');
|
|
1469
|
+
return [
|
|
1470
|
+
[makeKeyword('DROP SUBSCRIPTION'), ifExists ? [' ', makeKeyword('IF EXISTS')] : '', ' ', name],
|
|
1471
|
+
';',
|
|
1472
|
+
];
|
|
1473
|
+
}
|
|
1474
|
+
// ---------------------------------------------------------------------------
|
|
1475
|
+
// P4: CREATE AGGREGATE / OPERATOR / COLLATION
|
|
1476
|
+
// ---------------------------------------------------------------------------
|
|
1477
|
+
function printDefOptions(options, _opts) {
|
|
1478
|
+
return join([',', hardline], options.map((o) => {
|
|
1479
|
+
const key = propStr(o, 'key') ?? '';
|
|
1480
|
+
const val = propStr(o, 'val');
|
|
1481
|
+
return val ? [key, ' = ', val] : [key];
|
|
1482
|
+
}));
|
|
1483
|
+
}
|
|
1484
|
+
function printCreateAggregate(node, opts) {
|
|
1485
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1486
|
+
const name = propStr(node, 'name') ?? '';
|
|
1487
|
+
const argTypes = node.props?.['argTypes'] ?? [];
|
|
1488
|
+
const options = propArr(node, 'options');
|
|
1489
|
+
return [
|
|
1490
|
+
makeKeyword('CREATE AGGREGATE'), ' ', name, ' (', join(', ', argTypes.map((t) => makeKeyword(t))), ') (',
|
|
1491
|
+
indent([hardline, printDefOptions(options, opts)]),
|
|
1492
|
+
hardline, ');',
|
|
1493
|
+
];
|
|
1494
|
+
}
|
|
1495
|
+
function printCreateOperator(node, opts) {
|
|
1496
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1497
|
+
const name = propStr(node, 'name') ?? '';
|
|
1498
|
+
const options = propArr(node, 'options');
|
|
1499
|
+
return [
|
|
1500
|
+
makeKeyword('CREATE OPERATOR'), ' ', name, ' (',
|
|
1501
|
+
indent([hardline, printDefOptions(options, opts)]),
|
|
1502
|
+
hardline, ');',
|
|
1503
|
+
];
|
|
1504
|
+
}
|
|
1505
|
+
function printCreateCollation(node, opts) {
|
|
1506
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1507
|
+
const name = propStr(node, 'name') ?? '';
|
|
1508
|
+
const fromName = propStr(node, 'fromName');
|
|
1509
|
+
const options = propArr(node, 'options');
|
|
1510
|
+
if (fromName) {
|
|
1511
|
+
return [[makeKeyword('CREATE COLLATION'), ' ', name, ' ', makeKeyword('FROM'), ' ', `"${fromName}"`], ';'];
|
|
1512
|
+
}
|
|
1513
|
+
return [
|
|
1514
|
+
makeKeyword('CREATE COLLATION'), ' ', name, ' (',
|
|
1515
|
+
printDefOptions(options, opts),
|
|
1516
|
+
');',
|
|
1517
|
+
];
|
|
1518
|
+
}
|
|
1519
|
+
// ---------------------------------------------------------------------------
|
|
1520
|
+
// P4: Security Labels
|
|
1521
|
+
// ---------------------------------------------------------------------------
|
|
1522
|
+
function printSecurityLabel(node, opts) {
|
|
1523
|
+
const makeKeyword = (k) => keyword(k, opts);
|
|
1524
|
+
const provider = propStr(node, 'provider') ?? '';
|
|
1525
|
+
const objType = propStr(node, 'objType') ?? 'table';
|
|
1526
|
+
const objName = propStr(node, 'objName') ?? '';
|
|
1527
|
+
const label = propStr(node, 'label') ?? '';
|
|
1528
|
+
return [
|
|
1529
|
+
[makeKeyword('SECURITY LABEL FOR'), ' ', provider, ' ', makeKeyword('ON'), ' ', makeKeyword(objType), ' ', objName, ' ', makeKeyword('IS'), " '", label, "'"],
|
|
1530
|
+
';',
|
|
1531
|
+
];
|
|
1532
|
+
}
|
|
1533
|
+
//# sourceMappingURL=statements.js.map
|