neonctl 2.27.1 → 2.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/README.md +35 -3
  2. package/dist/analytics.js +52 -34
  3. package/dist/api.js +643 -13
  4. package/dist/auth.js +50 -44
  5. package/dist/cli.js +8 -1
  6. package/dist/commands/auth.js +64 -51
  7. package/dist/commands/bootstrap.js +115 -157
  8. package/dist/commands/branches.js +160 -150
  9. package/dist/commands/bucket.js +183 -146
  10. package/dist/commands/checkout.js +51 -51
  11. package/dist/commands/config.js +228 -82
  12. package/dist/commands/connection_string.js +62 -62
  13. package/dist/commands/data_api.js +100 -101
  14. package/dist/commands/databases.js +29 -26
  15. package/dist/commands/deploy.js +12 -12
  16. package/dist/commands/dev.js +114 -114
  17. package/dist/commands/env.js +43 -43
  18. package/dist/commands/functions.js +101 -104
  19. package/dist/commands/index.js +27 -25
  20. package/dist/commands/init.js +23 -22
  21. package/dist/commands/ip_allow.js +29 -29
  22. package/dist/commands/link.js +232 -182
  23. package/dist/commands/neon_auth.js +385 -370
  24. package/dist/commands/operations.js +11 -11
  25. package/dist/commands/orgs.js +8 -8
  26. package/dist/commands/projects.js +103 -101
  27. package/dist/commands/psql.js +31 -31
  28. package/dist/commands/roles.js +27 -24
  29. package/dist/commands/schema_diff.js +25 -26
  30. package/dist/commands/set_context.js +17 -17
  31. package/dist/commands/status.js +40 -0
  32. package/dist/commands/user.js +5 -5
  33. package/dist/commands/vpc_endpoints.js +50 -50
  34. package/dist/config.js +7 -7
  35. package/dist/config_format.js +5 -5
  36. package/dist/context.js +37 -14
  37. package/dist/current_branch_fast_path.js +55 -0
  38. package/dist/dev/env.js +33 -33
  39. package/dist/dev/functions.js +4 -4
  40. package/dist/dev/inputs.js +6 -6
  41. package/dist/dev/runtime.js +25 -25
  42. package/dist/env.js +14 -14
  43. package/dist/env_file.js +13 -13
  44. package/dist/errors.js +68 -5
  45. package/dist/functions_api.js +10 -10
  46. package/dist/help.js +15 -15
  47. package/dist/index.js +110 -107
  48. package/dist/log.js +2 -2
  49. package/dist/parameters.gen.js +14 -14
  50. package/dist/pkg.js +5 -5
  51. package/dist/psql/cli.js +4 -2
  52. package/dist/psql/command/cmd_cond.js +61 -61
  53. package/dist/psql/command/cmd_connect.js +159 -154
  54. package/dist/psql/command/cmd_copy.js +107 -97
  55. package/dist/psql/command/cmd_describe.js +368 -363
  56. package/dist/psql/command/cmd_format.js +276 -263
  57. package/dist/psql/command/cmd_io.js +269 -263
  58. package/dist/psql/command/cmd_lo.js +74 -66
  59. package/dist/psql/command/cmd_meta.js +148 -148
  60. package/dist/psql/command/cmd_misc.js +17 -17
  61. package/dist/psql/command/cmd_pipeline.js +142 -135
  62. package/dist/psql/command/cmd_restrict.js +25 -25
  63. package/dist/psql/command/cmd_show.js +183 -168
  64. package/dist/psql/command/dispatch.js +26 -26
  65. package/dist/psql/command/shared.js +14 -14
  66. package/dist/psql/complete/filenames.js +16 -16
  67. package/dist/psql/complete/index.js +4 -4
  68. package/dist/psql/complete/matcher.js +33 -32
  69. package/dist/psql/complete/psqlVars.js +173 -173
  70. package/dist/psql/complete/queries.js +5 -3
  71. package/dist/psql/complete/rules.js +900 -863
  72. package/dist/psql/core/common.js +136 -133
  73. package/dist/psql/core/help.js +343 -343
  74. package/dist/psql/core/mainloop.js +160 -153
  75. package/dist/psql/core/prompt.js +126 -123
  76. package/dist/psql/core/settings.js +111 -111
  77. package/dist/psql/core/sqlHelp.js +150 -150
  78. package/dist/psql/core/startup.js +211 -205
  79. package/dist/psql/core/syncVars.js +14 -14
  80. package/dist/psql/core/variables.js +24 -24
  81. package/dist/psql/describe/formatters.js +302 -289
  82. package/dist/psql/describe/processNamePattern.js +28 -28
  83. package/dist/psql/describe/queries.js +656 -651
  84. package/dist/psql/index.js +436 -411
  85. package/dist/psql/io/history.js +36 -36
  86. package/dist/psql/io/input.js +15 -15
  87. package/dist/psql/io/lineEditor/buffer.js +27 -25
  88. package/dist/psql/io/lineEditor/complete.js +15 -15
  89. package/dist/psql/io/lineEditor/filename.js +22 -22
  90. package/dist/psql/io/lineEditor/index.js +65 -62
  91. package/dist/psql/io/lineEditor/keymap.js +325 -318
  92. package/dist/psql/io/lineEditor/vt100.js +60 -60
  93. package/dist/psql/io/pgpass.js +18 -18
  94. package/dist/psql/io/pgservice.js +14 -14
  95. package/dist/psql/io/psqlrc.js +46 -46
  96. package/dist/psql/print/aligned.js +175 -166
  97. package/dist/psql/print/asciidoc.js +51 -51
  98. package/dist/psql/print/crosstab.js +34 -31
  99. package/dist/psql/print/csv.js +25 -22
  100. package/dist/psql/print/html.js +54 -54
  101. package/dist/psql/print/json.js +12 -12
  102. package/dist/psql/print/latex.js +118 -118
  103. package/dist/psql/print/pager.js +28 -26
  104. package/dist/psql/print/troff.js +48 -48
  105. package/dist/psql/print/unaligned.js +15 -14
  106. package/dist/psql/print/units.js +17 -17
  107. package/dist/psql/scanner/slash.js +48 -46
  108. package/dist/psql/scanner/sql.js +88 -84
  109. package/dist/psql/scanner/stringutils.js +21 -17
  110. package/dist/psql/types/index.js +7 -7
  111. package/dist/psql/types/scanner.js +8 -8
  112. package/dist/psql/wire/connection.js +341 -327
  113. package/dist/psql/wire/copy.js +7 -7
  114. package/dist/psql/wire/pipeline.js +26 -24
  115. package/dist/psql/wire/protocol.js +102 -102
  116. package/dist/psql/wire/sasl.js +62 -62
  117. package/dist/psql/wire/tls.js +79 -73
  118. package/dist/storage_api.js +22 -23
  119. package/dist/test_utils/fixtures.js +74 -41
  120. package/dist/test_utils/oauth_server.js +5 -5
  121. package/dist/utils/api_enums.js +33 -0
  122. package/dist/utils/branch_notice.js +5 -5
  123. package/dist/utils/branch_picker.js +26 -26
  124. package/dist/utils/compute_units.js +4 -4
  125. package/dist/utils/enrichers.js +28 -16
  126. package/dist/utils/esbuild.js +28 -28
  127. package/dist/utils/formats.js +1 -1
  128. package/dist/utils/middlewares.js +3 -3
  129. package/dist/utils/package_manager.js +68 -0
  130. package/dist/utils/point_in_time.js +12 -12
  131. package/dist/utils/psql.js +30 -30
  132. package/dist/utils/string.js +2 -2
  133. package/dist/utils/ui.js +9 -9
  134. package/dist/utils/zip.js +1 -1
  135. package/dist/writer.js +17 -17
  136. package/package.json +10 -12
@@ -96,653 +96,653 @@
96
96
  * The shape mirrors the C source closely enough that adding new rules is
97
97
  * mechanical: drop a new `if (TailMatches(...))` arm in the right region.
98
98
  */
99
- import { completeFilenames, isCopyFromOrTo } from './filenames.js';
100
- import { HeadMatches, MatchAny, TailMatches, tokenize } from './matcher.js';
101
- import { Query_for_constraint_of_table, Query_for_constraint_of_table_in_schema, Query_for_list_of_casts, Query_for_list_of_databases, Query_for_list_of_datatypes, Query_for_list_of_enum_values_quoted, Query_for_list_of_extensions, Query_for_list_of_functions, Query_for_list_of_index_access_methods, Query_for_list_of_indexes, Query_for_list_of_languages, Query_for_list_of_matviews, Query_for_list_of_operators, Query_for_list_of_publications, Query_for_list_of_relations_in_schema, Query_for_list_of_roles, Query_for_list_of_schemas, Query_for_list_of_sequences, Query_for_list_of_set_vars, Query_for_list_of_subscriptions, Query_for_list_of_tables, Query_for_list_of_tables_for_constraint, Query_for_list_of_tables_for_constraint_in_schema, Query_for_list_of_tables_views, Query_for_list_of_tablespaces, Query_for_list_of_timezone_names_quoted_in, Query_for_list_of_timezone_names_quoted_out, Query_for_list_of_types, Query_for_list_of_views, Query_for_values_of_enum_GUC, runCatalogQuery, } from './queries.js';
102
- import { ENCODINGS, PSET_OPTIONS, SPECIAL_VARIABLES, psetValuesFor, variableValuesFor, } from './psqlVars.js';
99
+ import { completeFilenames, isCopyFromOrTo } from "./filenames.js";
100
+ import { HeadMatches, MatchAny, TailMatches, tokenize } from "./matcher.js";
101
+ import { ENCODINGS, PSET_OPTIONS, psetValuesFor, SPECIAL_VARIABLES, variableValuesFor, } from "./psqlVars.js";
102
+ import { Query_for_constraint_of_table, Query_for_constraint_of_table_in_schema, Query_for_list_of_casts, Query_for_list_of_databases, Query_for_list_of_datatypes, Query_for_list_of_enum_values_quoted, Query_for_list_of_extensions, Query_for_list_of_functions, Query_for_list_of_index_access_methods, Query_for_list_of_indexes, Query_for_list_of_languages, Query_for_list_of_matviews, Query_for_list_of_operators, Query_for_list_of_publications, Query_for_list_of_relations_in_schema, Query_for_list_of_roles, Query_for_list_of_schemas, Query_for_list_of_sequences, Query_for_list_of_set_vars, Query_for_list_of_subscriptions, Query_for_list_of_tables, Query_for_list_of_tables_for_constraint, Query_for_list_of_tables_for_constraint_in_schema, Query_for_list_of_tables_views, Query_for_list_of_tablespaces, Query_for_list_of_timezone_names_quoted_in, Query_for_list_of_timezone_names_quoted_out, Query_for_list_of_types, Query_for_list_of_views, Query_for_values_of_enum_GUC, runCatalogQuery, } from "./queries.js";
103
103
  /** Backslash command names psql tab-completes (mirrors backslash_commands[]). */
104
104
  export const BACKSLASH_COMMANDS = [
105
- '\\a',
106
- '\\bind',
107
- '\\bind_named',
108
- '\\c',
109
- '\\C',
110
- '\\cd',
111
- '\\close_prepared',
112
- '\\conninfo',
113
- '\\connect',
114
- '\\copy',
115
- '\\copyright',
116
- '\\crosstabview',
117
- '\\d',
118
- '\\dA',
119
- '\\dAc',
120
- '\\dAf',
121
- '\\dAo',
122
- '\\dAp',
123
- '\\da',
124
- '\\db',
125
- '\\dC',
126
- '\\dc',
127
- '\\dconfig',
128
- '\\dD',
129
- '\\dd',
130
- '\\ddp',
131
- '\\dE',
132
- '\\des',
133
- '\\det',
134
- '\\deu',
135
- '\\dew',
136
- '\\df',
137
- '\\dF',
138
- '\\dFd',
139
- '\\dFp',
140
- '\\dFt',
141
- '\\dg',
142
- '\\di',
143
- '\\dl',
144
- '\\dL',
145
- '\\dm',
146
- '\\dn',
147
- '\\do',
148
- '\\dO',
149
- '\\dp',
150
- '\\dP',
151
- '\\dPi',
152
- '\\dPt',
153
- '\\drds',
154
- '\\drg',
155
- '\\dRs',
156
- '\\dRp',
157
- '\\ds',
158
- '\\dt',
159
- '\\dT',
160
- '\\dv',
161
- '\\du',
162
- '\\dx',
163
- '\\dX',
164
- '\\dy',
165
- '\\echo',
166
- '\\edit',
167
- '\\ef',
168
- '\\elif',
169
- '\\else',
170
- '\\encoding',
171
- '\\endif',
172
- '\\endpipeline',
173
- '\\errverbose',
174
- '\\ev',
175
- '\\f',
176
- '\\flush',
177
- '\\flushrequest',
178
- '\\g',
179
- '\\gdesc',
180
- '\\getenv',
181
- '\\getresults',
182
- '\\gexec',
183
- '\\gset',
184
- '\\gx',
185
- '\\help',
186
- '\\html',
187
- '\\if',
188
- '\\include',
189
- '\\include_relative',
190
- '\\ir',
191
- '\\l',
192
- '\\list',
193
- '\\lo_export',
194
- '\\lo_import',
195
- '\\lo_list',
196
- '\\lo_unlink',
197
- '\\o',
198
- '\\out',
199
- '\\parse',
200
- '\\password',
201
- '\\print',
202
- '\\prompt',
203
- '\\pset',
204
- '\\q',
205
- '\\qecho',
206
- '\\quit',
207
- '\\reset',
208
- '\\restrict',
209
- '\\s',
210
- '\\sendpipeline',
211
- '\\set',
212
- '\\setenv',
213
- '\\sf',
214
- '\\startpipeline',
215
- '\\sv',
216
- '\\syncpipeline',
217
- '\\t',
218
- '\\T',
219
- '\\timing',
220
- '\\unrestrict',
221
- '\\unset',
222
- '\\w',
223
- '\\warn',
224
- '\\watch',
225
- '\\write',
226
- '\\x',
227
- '\\z',
228
- '\\!',
229
- '\\?',
105
+ "\\a",
106
+ "\\bind",
107
+ "\\bind_named",
108
+ "\\c",
109
+ "\\C",
110
+ "\\cd",
111
+ "\\close_prepared",
112
+ "\\conninfo",
113
+ "\\connect",
114
+ "\\copy",
115
+ "\\copyright",
116
+ "\\crosstabview",
117
+ "\\d",
118
+ "\\dA",
119
+ "\\dAc",
120
+ "\\dAf",
121
+ "\\dAo",
122
+ "\\dAp",
123
+ "\\da",
124
+ "\\db",
125
+ "\\dC",
126
+ "\\dc",
127
+ "\\dconfig",
128
+ "\\dD",
129
+ "\\dd",
130
+ "\\ddp",
131
+ "\\dE",
132
+ "\\des",
133
+ "\\det",
134
+ "\\deu",
135
+ "\\dew",
136
+ "\\df",
137
+ "\\dF",
138
+ "\\dFd",
139
+ "\\dFp",
140
+ "\\dFt",
141
+ "\\dg",
142
+ "\\di",
143
+ "\\dl",
144
+ "\\dL",
145
+ "\\dm",
146
+ "\\dn",
147
+ "\\do",
148
+ "\\dO",
149
+ "\\dp",
150
+ "\\dP",
151
+ "\\dPi",
152
+ "\\dPt",
153
+ "\\drds",
154
+ "\\drg",
155
+ "\\dRs",
156
+ "\\dRp",
157
+ "\\ds",
158
+ "\\dt",
159
+ "\\dT",
160
+ "\\dv",
161
+ "\\du",
162
+ "\\dx",
163
+ "\\dX",
164
+ "\\dy",
165
+ "\\echo",
166
+ "\\edit",
167
+ "\\ef",
168
+ "\\elif",
169
+ "\\else",
170
+ "\\encoding",
171
+ "\\endif",
172
+ "\\endpipeline",
173
+ "\\errverbose",
174
+ "\\ev",
175
+ "\\f",
176
+ "\\flush",
177
+ "\\flushrequest",
178
+ "\\g",
179
+ "\\gdesc",
180
+ "\\getenv",
181
+ "\\getresults",
182
+ "\\gexec",
183
+ "\\gset",
184
+ "\\gx",
185
+ "\\help",
186
+ "\\html",
187
+ "\\if",
188
+ "\\include",
189
+ "\\include_relative",
190
+ "\\ir",
191
+ "\\l",
192
+ "\\list",
193
+ "\\lo_export",
194
+ "\\lo_import",
195
+ "\\lo_list",
196
+ "\\lo_unlink",
197
+ "\\o",
198
+ "\\out",
199
+ "\\parse",
200
+ "\\password",
201
+ "\\print",
202
+ "\\prompt",
203
+ "\\pset",
204
+ "\\q",
205
+ "\\qecho",
206
+ "\\quit",
207
+ "\\reset",
208
+ "\\restrict",
209
+ "\\s",
210
+ "\\sendpipeline",
211
+ "\\set",
212
+ "\\setenv",
213
+ "\\sf",
214
+ "\\startpipeline",
215
+ "\\sv",
216
+ "\\syncpipeline",
217
+ "\\t",
218
+ "\\T",
219
+ "\\timing",
220
+ "\\unrestrict",
221
+ "\\unset",
222
+ "\\w",
223
+ "\\warn",
224
+ "\\watch",
225
+ "\\write",
226
+ "\\x",
227
+ "\\z",
228
+ "\\!",
229
+ "\\?",
230
230
  ];
231
231
  /** Top-level SQL statement keywords. */
232
232
  export const SQL_TOP_KEYWORDS = [
233
- 'ABORT',
234
- 'ALTER',
235
- 'ANALYZE',
236
- 'BEGIN',
237
- 'CALL',
238
- 'CHECKPOINT',
239
- 'CLOSE',
240
- 'CLUSTER',
241
- 'COMMENT',
242
- 'COMMIT',
243
- 'COPY',
244
- 'CREATE',
245
- 'DEALLOCATE',
246
- 'DECLARE',
247
- 'DELETE FROM',
248
- 'DISCARD',
249
- 'DO',
250
- 'DROP',
251
- 'END',
252
- 'EXECUTE',
253
- 'EXPLAIN',
254
- 'FETCH',
255
- 'GRANT',
256
- 'IMPORT',
257
- 'INSERT INTO',
258
- 'LISTEN',
259
- 'LOAD',
260
- 'LOCK',
261
- 'MERGE',
262
- 'MOVE',
263
- 'NOTIFY',
264
- 'PREPARE',
265
- 'REASSIGN',
266
- 'REFRESH MATERIALIZED VIEW',
267
- 'REINDEX',
268
- 'RELEASE',
269
- 'RESET',
270
- 'REVOKE',
271
- 'ROLLBACK',
272
- 'SAVEPOINT',
273
- 'SECURITY LABEL',
274
- 'SELECT',
275
- 'SET',
276
- 'SHOW',
277
- 'START TRANSACTION',
278
- 'TABLE',
279
- 'TRUNCATE',
280
- 'UNLISTEN',
281
- 'UPDATE',
282
- 'VACUUM',
283
- 'VALUES',
284
- 'WITH',
233
+ "ABORT",
234
+ "ALTER",
235
+ "ANALYZE",
236
+ "BEGIN",
237
+ "CALL",
238
+ "CHECKPOINT",
239
+ "CLOSE",
240
+ "CLUSTER",
241
+ "COMMENT",
242
+ "COMMIT",
243
+ "COPY",
244
+ "CREATE",
245
+ "DEALLOCATE",
246
+ "DECLARE",
247
+ "DELETE FROM",
248
+ "DISCARD",
249
+ "DO",
250
+ "DROP",
251
+ "END",
252
+ "EXECUTE",
253
+ "EXPLAIN",
254
+ "FETCH",
255
+ "GRANT",
256
+ "IMPORT",
257
+ "INSERT INTO",
258
+ "LISTEN",
259
+ "LOAD",
260
+ "LOCK",
261
+ "MERGE",
262
+ "MOVE",
263
+ "NOTIFY",
264
+ "PREPARE",
265
+ "REASSIGN",
266
+ "REFRESH MATERIALIZED VIEW",
267
+ "REINDEX",
268
+ "RELEASE",
269
+ "RESET",
270
+ "REVOKE",
271
+ "ROLLBACK",
272
+ "SAVEPOINT",
273
+ "SECURITY LABEL",
274
+ "SELECT",
275
+ "SET",
276
+ "SHOW",
277
+ "START TRANSACTION",
278
+ "TABLE",
279
+ "TRUNCATE",
280
+ "UNLISTEN",
281
+ "UPDATE",
282
+ "VACUUM",
283
+ "VALUES",
284
+ "WITH",
285
285
  ];
286
286
  /** Keywords accepted after CREATE. */
287
287
  export const CREATE_OBJECTS = [
288
- 'ACCESS METHOD',
289
- 'AGGREGATE',
290
- 'CAST',
291
- 'COLLATION',
292
- 'CONVERSION',
293
- 'DATABASE',
294
- 'DEFAULT PRIVILEGES',
295
- 'DOMAIN',
296
- 'EVENT TRIGGER',
297
- 'EXTENSION',
298
- 'FOREIGN DATA WRAPPER',
299
- 'FOREIGN TABLE',
300
- 'FUNCTION',
301
- 'GLOBAL',
302
- 'GROUP',
303
- 'INDEX',
304
- 'LANGUAGE',
305
- 'LOCAL',
306
- 'MATERIALIZED VIEW',
307
- 'OPERATOR',
308
- 'OR REPLACE',
309
- 'POLICY',
310
- 'PROCEDURE',
311
- 'PUBLICATION',
312
- 'ROLE',
313
- 'RULE',
314
- 'SCHEMA',
315
- 'SEQUENCE',
316
- 'SERVER',
317
- 'STATISTICS',
318
- 'SUBSCRIPTION',
319
- 'TABLE',
320
- 'TABLESPACE',
321
- 'TEMP',
322
- 'TEMPORARY',
323
- 'TEXT SEARCH',
324
- 'TRANSFORM',
325
- 'TRIGGER',
326
- 'TYPE',
327
- 'UNIQUE',
328
- 'UNLOGGED',
329
- 'USER',
330
- 'VIEW',
288
+ "ACCESS METHOD",
289
+ "AGGREGATE",
290
+ "CAST",
291
+ "COLLATION",
292
+ "CONVERSION",
293
+ "DATABASE",
294
+ "DEFAULT PRIVILEGES",
295
+ "DOMAIN",
296
+ "EVENT TRIGGER",
297
+ "EXTENSION",
298
+ "FOREIGN DATA WRAPPER",
299
+ "FOREIGN TABLE",
300
+ "FUNCTION",
301
+ "GLOBAL",
302
+ "GROUP",
303
+ "INDEX",
304
+ "LANGUAGE",
305
+ "LOCAL",
306
+ "MATERIALIZED VIEW",
307
+ "OPERATOR",
308
+ "OR REPLACE",
309
+ "POLICY",
310
+ "PROCEDURE",
311
+ "PUBLICATION",
312
+ "ROLE",
313
+ "RULE",
314
+ "SCHEMA",
315
+ "SEQUENCE",
316
+ "SERVER",
317
+ "STATISTICS",
318
+ "SUBSCRIPTION",
319
+ "TABLE",
320
+ "TABLESPACE",
321
+ "TEMP",
322
+ "TEMPORARY",
323
+ "TEXT SEARCH",
324
+ "TRANSFORM",
325
+ "TRIGGER",
326
+ "TYPE",
327
+ "UNIQUE",
328
+ "UNLOGGED",
329
+ "USER",
330
+ "VIEW",
331
331
  ];
332
332
  /** Keywords accepted after DROP. */
333
333
  export const DROP_OBJECTS = [
334
- 'ACCESS METHOD',
335
- 'AGGREGATE',
336
- 'CAST',
337
- 'COLLATION',
338
- 'CONVERSION',
339
- 'DATABASE',
340
- 'DOMAIN',
341
- 'EVENT TRIGGER',
342
- 'EXTENSION',
343
- 'FOREIGN DATA WRAPPER',
344
- 'FOREIGN TABLE',
345
- 'FUNCTION',
346
- 'GROUP',
347
- 'INDEX',
348
- 'LANGUAGE',
349
- 'MATERIALIZED VIEW',
350
- 'OPERATOR',
351
- 'OWNED',
352
- 'POLICY',
353
- 'PROCEDURE',
354
- 'PUBLICATION',
355
- 'ROLE',
356
- 'RULE',
357
- 'SCHEMA',
358
- 'SEQUENCE',
359
- 'SERVER',
360
- 'STATISTICS',
361
- 'SUBSCRIPTION',
362
- 'TABLE',
363
- 'TABLESPACE',
364
- 'TEXT SEARCH',
365
- 'TRANSFORM',
366
- 'TRIGGER',
367
- 'TYPE',
368
- 'USER',
369
- 'VIEW',
334
+ "ACCESS METHOD",
335
+ "AGGREGATE",
336
+ "CAST",
337
+ "COLLATION",
338
+ "CONVERSION",
339
+ "DATABASE",
340
+ "DOMAIN",
341
+ "EVENT TRIGGER",
342
+ "EXTENSION",
343
+ "FOREIGN DATA WRAPPER",
344
+ "FOREIGN TABLE",
345
+ "FUNCTION",
346
+ "GROUP",
347
+ "INDEX",
348
+ "LANGUAGE",
349
+ "MATERIALIZED VIEW",
350
+ "OPERATOR",
351
+ "OWNED",
352
+ "POLICY",
353
+ "PROCEDURE",
354
+ "PUBLICATION",
355
+ "ROLE",
356
+ "RULE",
357
+ "SCHEMA",
358
+ "SEQUENCE",
359
+ "SERVER",
360
+ "STATISTICS",
361
+ "SUBSCRIPTION",
362
+ "TABLE",
363
+ "TABLESPACE",
364
+ "TEXT SEARCH",
365
+ "TRANSFORM",
366
+ "TRIGGER",
367
+ "TYPE",
368
+ "USER",
369
+ "VIEW",
370
370
  ];
371
371
  /** Keywords accepted after ALTER. */
372
372
  export const ALTER_OBJECTS = [
373
- 'AGGREGATE',
374
- 'COLLATION',
375
- 'CONVERSION',
376
- 'DATABASE',
377
- 'DEFAULT PRIVILEGES',
378
- 'DOMAIN',
379
- 'EVENT TRIGGER',
380
- 'EXTENSION',
381
- 'FOREIGN DATA WRAPPER',
382
- 'FOREIGN TABLE',
383
- 'FUNCTION',
384
- 'GROUP',
385
- 'INDEX',
386
- 'LANGUAGE',
387
- 'LARGE OBJECT',
388
- 'MATERIALIZED VIEW',
389
- 'OPERATOR',
390
- 'POLICY',
391
- 'PROCEDURE',
392
- 'PUBLICATION',
393
- 'ROLE',
394
- 'RULE',
395
- 'SCHEMA',
396
- 'SEQUENCE',
397
- 'SERVER',
398
- 'STATISTICS',
399
- 'SUBSCRIPTION',
400
- 'SYSTEM',
401
- 'TABLE',
402
- 'TABLESPACE',
403
- 'TEXT SEARCH',
404
- 'TRIGGER',
405
- 'TYPE',
406
- 'USER',
407
- 'VIEW',
373
+ "AGGREGATE",
374
+ "COLLATION",
375
+ "CONVERSION",
376
+ "DATABASE",
377
+ "DEFAULT PRIVILEGES",
378
+ "DOMAIN",
379
+ "EVENT TRIGGER",
380
+ "EXTENSION",
381
+ "FOREIGN DATA WRAPPER",
382
+ "FOREIGN TABLE",
383
+ "FUNCTION",
384
+ "GROUP",
385
+ "INDEX",
386
+ "LANGUAGE",
387
+ "LARGE OBJECT",
388
+ "MATERIALIZED VIEW",
389
+ "OPERATOR",
390
+ "POLICY",
391
+ "PROCEDURE",
392
+ "PUBLICATION",
393
+ "ROLE",
394
+ "RULE",
395
+ "SCHEMA",
396
+ "SEQUENCE",
397
+ "SERVER",
398
+ "STATISTICS",
399
+ "SUBSCRIPTION",
400
+ "SYSTEM",
401
+ "TABLE",
402
+ "TABLESPACE",
403
+ "TEXT SEARCH",
404
+ "TRIGGER",
405
+ "TYPE",
406
+ "USER",
407
+ "VIEW",
408
408
  ];
409
409
  /** Sub-actions for ALTER TABLE. */
410
410
  export const ALTER_TABLE_ACTIONS = [
411
- 'ADD',
412
- 'ALTER',
413
- 'ATTACH PARTITION',
414
- 'CLUSTER ON',
415
- 'DETACH PARTITION',
416
- 'DISABLE',
417
- 'DROP',
418
- 'ENABLE',
419
- 'INHERIT',
420
- 'NO INHERIT',
421
- 'OF',
422
- 'NOT OF',
423
- 'OWNER TO',
424
- 'RENAME',
425
- 'REPLICA IDENTITY',
426
- 'RESET',
427
- 'SET',
428
- 'VALIDATE CONSTRAINT',
411
+ "ADD",
412
+ "ALTER",
413
+ "ATTACH PARTITION",
414
+ "CLUSTER ON",
415
+ "DETACH PARTITION",
416
+ "DISABLE",
417
+ "DROP",
418
+ "ENABLE",
419
+ "INHERIT",
420
+ "NO INHERIT",
421
+ "OF",
422
+ "NOT OF",
423
+ "OWNER TO",
424
+ "RENAME",
425
+ "REPLICA IDENTITY",
426
+ "RESET",
427
+ "SET",
428
+ "VALIDATE CONSTRAINT",
429
429
  ];
430
430
  /** Continuation after `ALTER TABLE x ADD`. */
431
431
  export const ALTER_TABLE_ADD = [
432
- 'COLUMN',
433
- 'CONSTRAINT',
434
- 'CHECK',
435
- 'FOREIGN KEY',
436
- 'PRIMARY KEY',
437
- 'UNIQUE',
438
- 'EXCLUDE',
432
+ "COLUMN",
433
+ "CONSTRAINT",
434
+ "CHECK",
435
+ "FOREIGN KEY",
436
+ "PRIMARY KEY",
437
+ "UNIQUE",
438
+ "EXCLUDE",
439
439
  ];
440
440
  /** Continuation after `ALTER TABLE x ALTER [COLUMN] y`. */
441
441
  export const ALTER_TABLE_ALTER_COLUMN = [
442
- 'ADD GENERATED',
443
- 'DROP DEFAULT',
444
- 'DROP EXPRESSION',
445
- 'DROP IDENTITY',
446
- 'DROP NOT NULL',
447
- 'RESET',
448
- 'RESTART',
449
- 'SET',
450
- 'SET DATA TYPE',
451
- 'SET DEFAULT',
452
- 'SET EXPRESSION',
453
- 'SET GENERATED',
454
- 'SET NOT NULL',
455
- 'SET STATISTICS',
456
- 'SET STORAGE',
457
- 'TYPE',
442
+ "ADD GENERATED",
443
+ "DROP DEFAULT",
444
+ "DROP EXPRESSION",
445
+ "DROP IDENTITY",
446
+ "DROP NOT NULL",
447
+ "RESET",
448
+ "RESTART",
449
+ "SET",
450
+ "SET DATA TYPE",
451
+ "SET DEFAULT",
452
+ "SET EXPRESSION",
453
+ "SET GENERATED",
454
+ "SET NOT NULL",
455
+ "SET STATISTICS",
456
+ "SET STORAGE",
457
+ "TYPE",
458
458
  ];
459
459
  /** Continuation after `ALTER TABLE x DROP`. */
460
460
  export const ALTER_TABLE_DROP = [
461
- 'COLUMN',
462
- 'CONSTRAINT',
463
- 'IF EXISTS',
461
+ "COLUMN",
462
+ "CONSTRAINT",
463
+ "IF EXISTS",
464
464
  ];
465
465
  /** Continuation after `ALTER TABLE x RENAME`. */
466
466
  export const ALTER_TABLE_RENAME = [
467
- 'COLUMN',
468
- 'CONSTRAINT',
469
- 'TO',
467
+ "COLUMN",
468
+ "CONSTRAINT",
469
+ "TO",
470
470
  ];
471
471
  /** Continuation after `ALTER TABLE x SET`. */
472
472
  export const ALTER_TABLE_SET = [
473
- '(',
474
- 'LOGGED',
475
- 'SCHEMA',
476
- 'TABLESPACE',
477
- 'UNLOGGED',
478
- 'WITHOUT CLUSTER',
479
- 'WITHOUT OIDS',
473
+ "(",
474
+ "LOGGED",
475
+ "SCHEMA",
476
+ "TABLESPACE",
477
+ "UNLOGGED",
478
+ "WITHOUT CLUSTER",
479
+ "WITHOUT OIDS",
480
480
  ];
481
481
  /** Continuation after `ALTER TABLE x ENABLE`. */
482
482
  export const ALTER_TABLE_ENABLE = [
483
- 'ALWAYS',
484
- 'REPLICA',
485
- 'ROW LEVEL SECURITY',
486
- 'RULE',
487
- 'TRIGGER',
483
+ "ALWAYS",
484
+ "REPLICA",
485
+ "ROW LEVEL SECURITY",
486
+ "RULE",
487
+ "TRIGGER",
488
488
  ];
489
489
  /** Continuation after `ALTER TABLE x DISABLE`. */
490
490
  export const ALTER_TABLE_DISABLE = [
491
- 'ROW LEVEL SECURITY',
492
- 'RULE',
493
- 'TRIGGER',
491
+ "ROW LEVEL SECURITY",
492
+ "RULE",
493
+ "TRIGGER",
494
494
  ];
495
495
  /** Continuation after `ALTER TABLE x REPLICA IDENTITY`. */
496
496
  export const ALTER_TABLE_REPLICA_IDENTITY = [
497
- 'DEFAULT',
498
- 'FULL',
499
- 'NOTHING',
500
- 'USING INDEX',
497
+ "DEFAULT",
498
+ "FULL",
499
+ "NOTHING",
500
+ "USING INDEX",
501
501
  ];
502
502
  /** Sub-actions for ALTER VIEW. */
503
503
  export const ALTER_VIEW_ACTIONS = [
504
- 'ALTER',
505
- 'OWNER TO',
506
- 'RENAME',
507
- 'RESET',
508
- 'SET',
504
+ "ALTER",
505
+ "OWNER TO",
506
+ "RENAME",
507
+ "RESET",
508
+ "SET",
509
509
  ];
510
510
  /** Sub-actions for ALTER MATERIALIZED VIEW. */
511
511
  export const ALTER_MATVIEW_ACTIONS = [
512
- 'ALTER',
513
- 'CLUSTER ON',
514
- 'DEPENDS ON EXTENSION',
515
- 'NO DEPENDS ON EXTENSION',
516
- 'OWNER TO',
517
- 'RENAME',
518
- 'RESET',
519
- 'SET',
512
+ "ALTER",
513
+ "CLUSTER ON",
514
+ "DEPENDS ON EXTENSION",
515
+ "NO DEPENDS ON EXTENSION",
516
+ "OWNER TO",
517
+ "RENAME",
518
+ "RESET",
519
+ "SET",
520
520
  ];
521
521
  /** Sub-actions for ALTER INDEX. */
522
522
  export const ALTER_INDEX_ACTIONS = [
523
- 'ALTER COLUMN',
524
- 'ATTACH PARTITION',
525
- 'DEPENDS ON EXTENSION',
526
- 'NO DEPENDS ON EXTENSION',
527
- 'OWNER TO',
528
- 'RENAME',
529
- 'RESET',
530
- 'SET',
523
+ "ALTER COLUMN",
524
+ "ATTACH PARTITION",
525
+ "DEPENDS ON EXTENSION",
526
+ "NO DEPENDS ON EXTENSION",
527
+ "OWNER TO",
528
+ "RENAME",
529
+ "RESET",
530
+ "SET",
531
531
  ];
532
532
  /** Sub-actions for ALTER SEQUENCE. */
533
533
  export const ALTER_SEQUENCE_ACTIONS = [
534
- 'AS',
535
- 'CACHE',
536
- 'CYCLE',
537
- 'INCREMENT BY',
538
- 'MAXVALUE',
539
- 'MINVALUE',
540
- 'NO CYCLE',
541
- 'NO MAXVALUE',
542
- 'NO MINVALUE',
543
- 'OWNED BY',
544
- 'OWNER TO',
545
- 'RENAME TO',
546
- 'RESTART',
547
- 'SET SCHEMA',
548
- 'START WITH',
534
+ "AS",
535
+ "CACHE",
536
+ "CYCLE",
537
+ "INCREMENT BY",
538
+ "MAXVALUE",
539
+ "MINVALUE",
540
+ "NO CYCLE",
541
+ "NO MAXVALUE",
542
+ "NO MINVALUE",
543
+ "OWNED BY",
544
+ "OWNER TO",
545
+ "RENAME TO",
546
+ "RESTART",
547
+ "SET SCHEMA",
548
+ "START WITH",
549
549
  ];
550
550
  /** Sub-actions for ALTER FUNCTION / PROCEDURE / ROUTINE. */
551
551
  export const ALTER_FUNCTION_ACTIONS = [
552
- 'CALLED ON NULL INPUT',
553
- 'COST',
554
- 'DEPENDS ON EXTENSION',
555
- 'IMMUTABLE',
556
- 'LEAKPROOF',
557
- 'NO DEPENDS ON EXTENSION',
558
- 'NOT LEAKPROOF',
559
- 'OWNER TO',
560
- 'PARALLEL',
561
- 'RENAME TO',
562
- 'RESET',
563
- 'RETURNS NULL ON NULL INPUT',
564
- 'ROWS',
565
- 'SECURITY DEFINER',
566
- 'SECURITY INVOKER',
567
- 'SET',
568
- 'SET SCHEMA',
569
- 'STABLE',
570
- 'STRICT',
571
- 'SUPPORT',
572
- 'VOLATILE',
552
+ "CALLED ON NULL INPUT",
553
+ "COST",
554
+ "DEPENDS ON EXTENSION",
555
+ "IMMUTABLE",
556
+ "LEAKPROOF",
557
+ "NO DEPENDS ON EXTENSION",
558
+ "NOT LEAKPROOF",
559
+ "OWNER TO",
560
+ "PARALLEL",
561
+ "RENAME TO",
562
+ "RESET",
563
+ "RETURNS NULL ON NULL INPUT",
564
+ "ROWS",
565
+ "SECURITY DEFINER",
566
+ "SECURITY INVOKER",
567
+ "SET",
568
+ "SET SCHEMA",
569
+ "STABLE",
570
+ "STRICT",
571
+ "SUPPORT",
572
+ "VOLATILE",
573
573
  ];
574
574
  /** Sub-actions for ALTER TYPE. */
575
575
  export const ALTER_TYPE_ACTIONS = [
576
- 'ADD ATTRIBUTE',
577
- 'ADD VALUE',
578
- 'ALTER ATTRIBUTE',
579
- 'DROP ATTRIBUTE',
580
- 'OWNER TO',
581
- 'RENAME',
582
- 'RENAME ATTRIBUTE',
583
- 'RENAME VALUE',
584
- 'SET SCHEMA',
585
- 'SET',
576
+ "ADD ATTRIBUTE",
577
+ "ADD VALUE",
578
+ "ALTER ATTRIBUTE",
579
+ "DROP ATTRIBUTE",
580
+ "OWNER TO",
581
+ "RENAME",
582
+ "RENAME ATTRIBUTE",
583
+ "RENAME VALUE",
584
+ "SET SCHEMA",
585
+ "SET",
586
586
  ];
587
587
  /** Sub-actions for ALTER ROLE / USER. */
588
588
  export const ALTER_ROLE_ACTIONS = [
589
- 'BYPASSRLS',
590
- 'CONNECTION LIMIT',
591
- 'CREATEDB',
592
- 'CREATEROLE',
593
- 'ENCRYPTED PASSWORD',
594
- 'IN DATABASE',
595
- 'INHERIT',
596
- 'LOGIN',
597
- 'NOBYPASSRLS',
598
- 'NOCREATEDB',
599
- 'NOCREATEROLE',
600
- 'NOINHERIT',
601
- 'NOLOGIN',
602
- 'NOREPLICATION',
603
- 'NOSUPERUSER',
604
- 'PASSWORD',
605
- 'RENAME TO',
606
- 'REPLICATION',
607
- 'RESET',
608
- 'SET',
609
- 'SUPERUSER',
610
- 'VALID UNTIL',
611
- 'WITH',
589
+ "BYPASSRLS",
590
+ "CONNECTION LIMIT",
591
+ "CREATEDB",
592
+ "CREATEROLE",
593
+ "ENCRYPTED PASSWORD",
594
+ "IN DATABASE",
595
+ "INHERIT",
596
+ "LOGIN",
597
+ "NOBYPASSRLS",
598
+ "NOCREATEDB",
599
+ "NOCREATEROLE",
600
+ "NOINHERIT",
601
+ "NOLOGIN",
602
+ "NOREPLICATION",
603
+ "NOSUPERUSER",
604
+ "PASSWORD",
605
+ "RENAME TO",
606
+ "REPLICATION",
607
+ "RESET",
608
+ "SET",
609
+ "SUPERUSER",
610
+ "VALID UNTIL",
611
+ "WITH",
612
612
  ];
613
613
  /** Sub-actions for ALTER DATABASE. */
614
614
  export const ALTER_DATABASE_ACTIONS = [
615
- 'ALLOW_CONNECTIONS',
616
- 'CONNECTION LIMIT',
617
- 'IS_TEMPLATE',
618
- 'OWNER TO',
619
- 'REFRESH COLLATION VERSION',
620
- 'RENAME TO',
621
- 'RESET',
622
- 'SET',
623
- 'SET TABLESPACE',
624
- 'WITH',
615
+ "ALLOW_CONNECTIONS",
616
+ "CONNECTION LIMIT",
617
+ "IS_TEMPLATE",
618
+ "OWNER TO",
619
+ "REFRESH COLLATION VERSION",
620
+ "RENAME TO",
621
+ "RESET",
622
+ "SET",
623
+ "SET TABLESPACE",
624
+ "WITH",
625
625
  ];
626
626
  /** Sub-actions for ALTER SCHEMA. */
627
627
  export const ALTER_SCHEMA_ACTIONS = [
628
- 'OWNER TO',
629
- 'RENAME TO',
628
+ "OWNER TO",
629
+ "RENAME TO",
630
630
  ];
631
631
  /** Sub-actions for ALTER EXTENSION. */
632
632
  export const ALTER_EXTENSION_ACTIONS = [
633
- 'ADD',
634
- 'DROP',
635
- 'SET SCHEMA',
636
- 'UPDATE',
633
+ "ADD",
634
+ "DROP",
635
+ "SET SCHEMA",
636
+ "UPDATE",
637
637
  ];
638
638
  /** Sub-actions for ALTER POLICY. */
639
- export const ALTER_POLICY_ACTIONS = ['ON', 'RENAME TO'];
639
+ export const ALTER_POLICY_ACTIONS = ["ON", "RENAME TO"];
640
640
  /** Sub-actions for ALTER PUBLICATION. */
641
641
  export const ALTER_PUBLICATION_ACTIONS = [
642
- 'ADD',
643
- 'DROP',
644
- 'OWNER TO',
645
- 'RENAME TO',
646
- 'SET',
642
+ "ADD",
643
+ "DROP",
644
+ "OWNER TO",
645
+ "RENAME TO",
646
+ "SET",
647
647
  ];
648
648
  /** Sub-actions for ALTER SUBSCRIPTION. */
649
649
  export const ALTER_SUBSCRIPTION_ACTIONS = [
650
- 'ADD PUBLICATION',
651
- 'CONNECTION',
652
- 'DISABLE',
653
- 'DROP PUBLICATION',
654
- 'ENABLE',
655
- 'OWNER TO',
656
- 'REFRESH PUBLICATION',
657
- 'RENAME TO',
658
- 'SET',
659
- 'SET PUBLICATION',
660
- 'SKIP',
650
+ "ADD PUBLICATION",
651
+ "CONNECTION",
652
+ "DISABLE",
653
+ "DROP PUBLICATION",
654
+ "ENABLE",
655
+ "OWNER TO",
656
+ "REFRESH PUBLICATION",
657
+ "RENAME TO",
658
+ "SET",
659
+ "SET PUBLICATION",
660
+ "SKIP",
661
661
  ];
662
662
  /** CREATE INDEX top-level options. */
663
663
  export const CREATE_INDEX_OPTIONS = [
664
- 'CONCURRENTLY',
665
- 'IF NOT EXISTS',
666
- 'ON',
667
- 'UNIQUE',
664
+ "CONCURRENTLY",
665
+ "IF NOT EXISTS",
666
+ "ON",
667
+ "UNIQUE",
668
668
  ];
669
669
  /** Window frame clauses after `OVER (`. */
670
670
  export const WINDOW_FRAME_KEYWORDS = [
671
- 'GROUPS',
672
- 'ORDER BY',
673
- 'PARTITION BY',
674
- 'RANGE',
675
- 'ROWS',
671
+ "GROUPS",
672
+ "ORDER BY",
673
+ "PARTITION BY",
674
+ "RANGE",
675
+ "ROWS",
676
676
  ];
677
677
  /** Tail keywords that follow a `FROM <table>` clause in a query. */
678
678
  export const POST_FROM_KEYWORDS = [
679
- 'AS',
680
- 'CROSS JOIN',
681
- 'EXCEPT',
682
- 'FETCH',
683
- 'FOR',
684
- 'FULL JOIN',
685
- 'FULL OUTER JOIN',
686
- 'GROUP BY',
687
- 'HAVING',
688
- 'INNER JOIN',
689
- 'INTERSECT',
690
- 'JOIN',
691
- 'LATERAL',
692
- 'LEFT JOIN',
693
- 'LEFT OUTER JOIN',
694
- 'LIMIT',
695
- 'NATURAL JOIN',
696
- 'OFFSET',
697
- 'ON',
698
- 'ORDER BY',
699
- 'RIGHT JOIN',
700
- 'RIGHT OUTER JOIN',
701
- 'TABLESAMPLE',
702
- 'UNION',
703
- 'USING',
704
- 'WHERE',
705
- 'WINDOW',
679
+ "AS",
680
+ "CROSS JOIN",
681
+ "EXCEPT",
682
+ "FETCH",
683
+ "FOR",
684
+ "FULL JOIN",
685
+ "FULL OUTER JOIN",
686
+ "GROUP BY",
687
+ "HAVING",
688
+ "INNER JOIN",
689
+ "INTERSECT",
690
+ "JOIN",
691
+ "LATERAL",
692
+ "LEFT JOIN",
693
+ "LEFT OUTER JOIN",
694
+ "LIMIT",
695
+ "NATURAL JOIN",
696
+ "OFFSET",
697
+ "ON",
698
+ "ORDER BY",
699
+ "RIGHT JOIN",
700
+ "RIGHT OUTER JOIN",
701
+ "TABLESAMPLE",
702
+ "UNION",
703
+ "USING",
704
+ "WHERE",
705
+ "WINDOW",
706
706
  ];
707
707
  /** Continuations within a WHERE expression. */
708
708
  export const WHERE_CONTINUATIONS = [
709
- 'AND',
710
- 'BETWEEN',
711
- 'IN',
712
- 'IS',
713
- 'LIKE',
714
- 'NOT',
715
- 'OR',
709
+ "AND",
710
+ "BETWEEN",
711
+ "IN",
712
+ "IS",
713
+ "LIKE",
714
+ "NOT",
715
+ "OR",
716
716
  ];
717
717
  /** Boolean-style values used with `\set` for AUTOCOMMIT etc. (extends ON_OFF). */
718
718
  export const DATESTYLE_VALUES = [
719
- 'GERMAN',
720
- 'ISO',
721
- 'POSTGRES',
722
- 'SQL',
719
+ "GERMAN",
720
+ "ISO",
721
+ "POSTGRES",
722
+ "SQL",
723
723
  ];
724
724
  /** GRANT / REVOKE privileges. */
725
725
  export const PRIVILEGE_KEYWORDS = [
726
- 'ALL',
727
- 'CREATE',
728
- 'CONNECT',
729
- 'DELETE',
730
- 'EXECUTE',
731
- 'INSERT',
732
- 'REFERENCES',
733
- 'SELECT',
734
- 'TEMPORARY',
735
- 'TRIGGER',
736
- 'TRUNCATE',
737
- 'UPDATE',
738
- 'USAGE',
726
+ "ALL",
727
+ "CREATE",
728
+ "CONNECT",
729
+ "DELETE",
730
+ "EXECUTE",
731
+ "INSERT",
732
+ "REFERENCES",
733
+ "SELECT",
734
+ "TEMPORARY",
735
+ "TRIGGER",
736
+ "TRUNCATE",
737
+ "UPDATE",
738
+ "USAGE",
739
739
  ];
740
740
  /** Common transaction/savepoint keywords. */
741
741
  export const TRANSACTION_KEYWORDS = [
742
- 'ISOLATION LEVEL',
743
- 'READ ONLY',
744
- 'READ WRITE',
745
- 'TRANSACTION',
742
+ "ISOLATION LEVEL",
743
+ "READ ONLY",
744
+ "READ WRITE",
745
+ "TRANSACTION",
746
746
  ];
747
747
  /**
748
748
  * Built-in scalar type keywords that psql tab-completion mixes in
@@ -753,13 +753,13 @@ export const TRANSACTION_KEYWORDS = [
753
753
  * boundaries.
754
754
  */
755
755
  export const BUILTIN_DATATYPE_KEYWORDS = [
756
- 'bigint',
757
- 'boolean',
758
- 'character',
759
- 'double precision',
760
- 'integer',
761
- 'real',
762
- 'smallint',
756
+ "bigint",
757
+ "boolean",
758
+ "character",
759
+ "double precision",
760
+ "integer",
761
+ "real",
762
+ "smallint",
763
763
  ];
764
764
  /**
765
765
  * COPY ... FROM ... WITH ( ... ) option keywords. Mirrors upstream's
@@ -768,34 +768,34 @@ export const BUILTIN_DATATYPE_KEYWORDS = [
768
768
  * ON_ERROR, REJECT_LIMIT).
769
769
  */
770
770
  export const COPY_FROM_OPTIONS = [
771
- 'DELIMITER',
772
- 'ENCODING',
773
- 'ESCAPE',
774
- 'FORMAT',
775
- 'HEADER',
776
- 'NULL',
777
- 'QUOTE',
778
- 'DEFAULT',
779
- 'FORCE_NOT_NULL',
780
- 'FORCE_NULL',
781
- 'FREEZE',
782
- 'LOG_VERBOSITY',
783
- 'ON_ERROR',
784
- 'REJECT_LIMIT',
771
+ "DELIMITER",
772
+ "ENCODING",
773
+ "ESCAPE",
774
+ "FORMAT",
775
+ "HEADER",
776
+ "NULL",
777
+ "QUOTE",
778
+ "DEFAULT",
779
+ "FORCE_NOT_NULL",
780
+ "FORCE_NULL",
781
+ "FREEZE",
782
+ "LOG_VERBOSITY",
783
+ "ON_ERROR",
784
+ "REJECT_LIMIT",
785
785
  ];
786
786
  /**
787
787
  * COPY ... TO ... WITH ( ... ) option keywords. Mirrors upstream's
788
788
  * `Copy_to_options` macro = `Copy_common_options` + `FORCE_QUOTE`.
789
789
  */
790
790
  export const COPY_TO_OPTIONS = [
791
- 'DELIMITER',
792
- 'ENCODING',
793
- 'ESCAPE',
794
- 'FORMAT',
795
- 'HEADER',
796
- 'NULL',
797
- 'QUOTE',
798
- 'FORCE_QUOTE',
791
+ "DELIMITER",
792
+ "ENCODING",
793
+ "ESCAPE",
794
+ "FORMAT",
795
+ "HEADER",
796
+ "NULL",
797
+ "QUOTE",
798
+ "FORCE_QUOTE",
799
799
  ];
800
800
  /**
801
801
  * Apply a case-insensitive prefix filter. Empty `prefix` returns the whole
@@ -848,14 +848,14 @@ const applyCase = (candidate, typed, settings) => {
848
848
  // - preserve-lower → lowercase.
849
849
  // The same rule applies when the first char is a non-letter (digit, `_`,
850
850
  // punctuation) — those preserve the mode's default direction.
851
- const first = typed[0] ?? '';
851
+ const first = typed[0] ?? "";
852
852
  const firstIsLower = /[a-z]/.test(first);
853
853
  const firstIsAlpha = /[A-Za-z]/.test(first);
854
- const lowerCaseIt = mode === 'lower' ||
855
- ((mode === 'preserve-lower' || mode === 'preserve-upper') &&
854
+ const lowerCaseIt = mode === "lower" ||
855
+ ((mode === "preserve-lower" || mode === "preserve-upper") &&
856
856
  firstIsLower) ||
857
- (mode === 'preserve-lower' && !firstIsAlpha);
858
- if (mode === 'upper')
857
+ (mode === "preserve-lower" && !firstIsAlpha);
858
+ if (mode === "upper")
859
859
  return candidate.toUpperCase();
860
860
  return lowerCaseIt ? candidate.toLowerCase() : candidate.toUpperCase();
861
861
  };
@@ -867,13 +867,13 @@ const containsNonKeywordChar = (s) => /[^A-Za-z0-9 ]/.test(s);
867
867
  * to fold its case in the rendered output.
868
868
  */
869
869
  const splitSchemaPrefix = (word) => {
870
- const dot = word.indexOf('.');
870
+ const dot = word.indexOf(".");
871
871
  if (dot < 0)
872
872
  return null;
873
873
  // Reject if anything after the dot looks like another dot (we only handle
874
874
  // schema.relation, not catalog.schema.relation).
875
875
  const after = word.slice(dot + 1);
876
- if (after.includes('.'))
876
+ if (after.includes("."))
877
877
  return null;
878
878
  // Strip optional quoting on the schema.
879
879
  let schema = word.slice(0, dot);
@@ -914,7 +914,7 @@ const parseTableRef = (refTokens) => {
914
914
  // token on the dot when the relation half is quoted).
915
915
  if (refTokens.length === 2) {
916
916
  const first = refTokens[0];
917
- if (!first.endsWith('.'))
917
+ if (!first.endsWith("."))
918
918
  return null;
919
919
  const s = stripQuote(first.slice(0, -1));
920
920
  const t = stripQuote(refTokens[1]);
@@ -937,7 +937,7 @@ const parseTableRef = (refTokens) => {
937
937
  if (ch === '"') {
938
938
  inQuote = !inQuote;
939
939
  }
940
- else if (ch === '.' && !inQuote) {
940
+ else if (ch === "." && !inQuote) {
941
941
  dot = i;
942
942
  break;
943
943
  }
@@ -974,18 +974,18 @@ export const findCompletions = async (prevWords, currentWord, ctx) => {
974
974
  // takes priority over anything else. The interpolation forms are valid
975
975
  // both inside SQL and inside backslash-command args (`\echo :VERB`),
976
976
  // so this branch fires regardless of `prevWords`.
977
- if (currentWord.startsWith(':') && !currentWord.startsWith('::')) {
977
+ if (currentWord.startsWith(":") && !currentWord.startsWith("::")) {
978
978
  const names = listVarNames(ctx.settings);
979
979
  const lc = (s) => s.toLowerCase();
980
980
  // `:{?NAME}` — test-form (psqlscan_test_variable upstream). The
981
981
  // candidate must close the `}` so the user's literal `:{?VERB`
982
982
  // expands to `:{?VERBOSITY}` in one Tab.
983
- if (currentWord.startsWith(':{?')) {
983
+ if (currentWord.startsWith(":{?")) {
984
984
  const prefix = currentWord.slice(3);
985
985
  const lp = lc(prefix);
986
986
  const cands = names
987
987
  .filter((n) => lc(n).startsWith(lp))
988
- .map((n) => ':{?' + n + '}');
988
+ .map((n) => ":{?" + n + "}");
989
989
  return { candidates: cands };
990
990
  }
991
991
  // `:'NAME'` / `:"NAME"` — quoted-substitution forms (psqlscan emits
@@ -1010,18 +1010,20 @@ export const findCompletions = async (prevWords, currentWord, ctx) => {
1010
1010
  // Plain `:NAME` — bare substitution.
1011
1011
  const prefix = currentWord.slice(1);
1012
1012
  const lp = lc(prefix);
1013
- const filt = names.filter((n) => lc(n).startsWith(lp)).map((n) => ':' + n);
1013
+ const filt = names
1014
+ .filter((n) => lc(n).startsWith(lp))
1015
+ .map((n) => ":" + n);
1014
1016
  return { candidates: filt };
1015
1017
  }
1016
1018
  // ----- Backslash-command name completion.
1017
1019
  // Trigger: the user is mid-token and the token starts with '\'.
1018
- if (currentWord.startsWith('\\') && prevWords.length === 0) {
1020
+ if (currentWord.startsWith("\\") && prevWords.length === 0) {
1019
1021
  return {
1020
1022
  candidates: BACKSLASH_COMMANDS.filter((c) => c.toLowerCase().startsWith(currentWord.toLowerCase())),
1021
1023
  };
1022
1024
  }
1023
1025
  // ----- Backslash-command argument completion.
1024
- if (prevWords.length > 0 && prevWords[0].startsWith('\\')) {
1026
+ if (prevWords.length > 0 && prevWords[0].startsWith("\\")) {
1025
1027
  return await backslashArgRules(prevWords, currentWord, ctx, conn);
1026
1028
  }
1027
1029
  // ----- Multi-line SQL: rules that need to see across the line boundary
@@ -1096,12 +1098,12 @@ const multiLineSqlRules = async (combined, prevWords, currentWord, ctx, conn) =>
1096
1098
  // Our scanner splits `(` and `,` as their own tokens (the C tokenizer
1097
1099
  // keeps `(verbose` as one word), so `ends_with(prev_wd, '(')` becomes
1098
1100
  // "previous token IS `(`" and similarly for `,`.
1099
- if (HeadMatches(combined, ['ANALYZE']) &&
1101
+ if (HeadMatches(combined, ["ANALYZE"]) &&
1100
1102
  isInsideOpenParen(combined.slice(1))) {
1101
1103
  const lastTok = combined[combined.length - 1];
1102
- if (lastTok === '(' || lastTok === ',') {
1104
+ if (lastTok === "(" || lastTok === ",") {
1103
1105
  return {
1104
- candidates: filterAndCase(['VERBOSE', 'SKIP_LOCKED', 'BUFFER_USAGE_LIMIT'], currentWord, ctx.settings),
1106
+ candidates: filterAndCase(["VERBOSE", "SKIP_LOCKED", "BUFFER_USAGE_LIMIT"], currentWord, ctx.settings),
1105
1107
  };
1106
1108
  }
1107
1109
  // Inside the option list with a partial option name in the current
@@ -1109,13 +1111,13 @@ const multiLineSqlRules = async (combined, prevWords, currentWord, ctx, conn) =>
1109
1111
  if (currentWord.length > 0 &&
1110
1112
  (lastTok === undefined || /^[A-Za-z_]+$/.test(currentWord))) {
1111
1113
  return {
1112
- candidates: filterAndCase(['VERBOSE', 'SKIP_LOCKED', 'BUFFER_USAGE_LIMIT'], currentWord, ctx.settings),
1114
+ candidates: filterAndCase(["VERBOSE", "SKIP_LOCKED", "BUFFER_USAGE_LIMIT"], currentWord, ctx.settings),
1113
1115
  };
1114
1116
  }
1115
1117
  // `VERBOSE` / `SKIP_LOCKED` boolean continuation — ON / OFF.
1116
- if (TailMatches(combined, ['VERBOSE|SKIP_LOCKED'])) {
1118
+ if (TailMatches(combined, ["VERBOSE|SKIP_LOCKED"])) {
1117
1119
  return {
1118
- candidates: filterAndCase(['ON', 'OFF'], currentWord, ctx.settings),
1120
+ candidates: filterAndCase(["ON", "OFF"], currentWord, ctx.settings),
1119
1121
  };
1120
1122
  }
1121
1123
  }
@@ -1128,7 +1130,7 @@ const multiLineSqlRules = async (combined, prevWords, currentWord, ctx, conn) =>
1128
1130
  // We allow the rule to fire even when the line-local `prevWords` only
1129
1131
  // sees the trailing `ON` — the COMBINED tokens carry the
1130
1132
  // `COMMENT ON CONSTRAINT <name>` prefix from the previous line.
1131
- if (TailMatches(combined, ['COMMENT', 'ON', 'CONSTRAINT', MatchAny, 'ON'])) {
1133
+ if (TailMatches(combined, ["COMMENT", "ON", "CONSTRAINT", MatchAny, "ON"])) {
1132
1134
  if (!conn)
1133
1135
  return { candidates: [] };
1134
1136
  // `combined` ends in `ON`. The constraint name is the token just
@@ -1146,7 +1148,7 @@ const multiLineSqlRules = async (combined, prevWords, currentWord, ctx, conn) =>
1146
1148
  ? split.schema
1147
1149
  : split.schema.toLowerCase();
1148
1150
  return {
1149
- candidates: rows.map((r) => canonicalSchema + '.' + r),
1151
+ candidates: rows.map((r) => canonicalSchema + "." + r),
1150
1152
  };
1151
1153
  }
1152
1154
  // Unqualified: list tables that have the constraint, plus the schemas
@@ -1155,7 +1157,7 @@ const multiLineSqlRules = async (combined, prevWords, currentWord, ctx, conn) =>
1155
1157
  runCatalogQuery(conn, Query_for_list_of_tables_for_constraint, currentWord, [constraintName]),
1156
1158
  runCatalogQuery(conn, Query_for_list_of_schemas, currentWord),
1157
1159
  ]);
1158
- return { candidates: [...tables, ...schemas.map((s) => s + '.')] };
1160
+ return { candidates: [...tables, ...schemas.map((s) => s + ".")] };
1159
1161
  }
1160
1162
  void conn;
1161
1163
  return null;
@@ -1171,11 +1173,11 @@ const isInsideOpenParen = (tokens) => {
1171
1173
  let depth = 0;
1172
1174
  let sawOpen = false;
1173
1175
  for (const t of tokens) {
1174
- if (t === '(') {
1176
+ if (t === "(") {
1175
1177
  depth++;
1176
1178
  sawOpen = true;
1177
1179
  }
1178
- else if (t === ')') {
1180
+ else if (t === ")") {
1179
1181
  depth--;
1180
1182
  }
1181
1183
  }
@@ -1184,7 +1186,7 @@ const isInsideOpenParen = (tokens) => {
1184
1186
  /** Strip surrounding `"..."` quoting from a constraint/identifier token. */
1185
1187
  const stripIdentifierQuote = (raw) => {
1186
1188
  if (raw === undefined)
1187
- return '';
1189
+ return "";
1188
1190
  if (raw.length >= 2 && raw.startsWith('"') && raw.endsWith('"')) {
1189
1191
  return raw.slice(1, -1).replace(/""/g, '"');
1190
1192
  }
@@ -1196,7 +1198,7 @@ const stripIdentifierQuote = (raw) => {
1196
1198
  const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1197
1199
  const cmd = prevWords[0]; // e.g. '\dt'
1198
1200
  // \c [DBNAME], \connect [DBNAME]: complete database names.
1199
- if (cmd === '\\c' || cmd === '\\connect') {
1201
+ if (cmd === "\\c" || cmd === "\\connect") {
1200
1202
  if (prevWords.length === 1 && conn) {
1201
1203
  const rows = await runCatalogQuery(conn, Query_for_list_of_databases, currentWord);
1202
1204
  return { candidates: rows };
@@ -1204,7 +1206,7 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1204
1206
  return { candidates: [] };
1205
1207
  }
1206
1208
  // \dn[+] [schema]
1207
- if (cmd === '\\dn' || cmd === '\\dn+') {
1209
+ if (cmd === "\\dn" || cmd === "\\dn+") {
1208
1210
  if (prevWords.length === 1 && conn) {
1209
1211
  const rows = await runCatalogQuery(conn, Query_for_list_of_schemas, currentWord);
1210
1212
  return { candidates: rows };
@@ -1212,16 +1214,16 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1212
1214
  return { candidates: [] };
1213
1215
  }
1214
1216
  // \df, \dfa, \dfn, \dfp, \dft, \dfw, \ef, \sf
1215
- if (cmd === '\\df' ||
1216
- cmd === '\\df+' ||
1217
- cmd === '\\dfa' ||
1218
- cmd === '\\dfn' ||
1219
- cmd === '\\dfp' ||
1220
- cmd === '\\dft' ||
1221
- cmd === '\\dfw' ||
1222
- cmd === '\\ef' ||
1223
- cmd === '\\sf' ||
1224
- cmd === '\\sf+') {
1217
+ if (cmd === "\\df" ||
1218
+ cmd === "\\df+" ||
1219
+ cmd === "\\dfa" ||
1220
+ cmd === "\\dfn" ||
1221
+ cmd === "\\dfp" ||
1222
+ cmd === "\\dft" ||
1223
+ cmd === "\\dfw" ||
1224
+ cmd === "\\ef" ||
1225
+ cmd === "\\sf" ||
1226
+ cmd === "\\sf+") {
1225
1227
  if (prevWords.length === 1 && conn) {
1226
1228
  const rows = await runCatalogQuery(conn, Query_for_list_of_functions, currentWord);
1227
1229
  return { candidates: rows };
@@ -1229,7 +1231,10 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1229
1231
  return { candidates: [] };
1230
1232
  }
1231
1233
  // \du, \dg → roles.
1232
- if (cmd === '\\du' || cmd === '\\dg' || cmd === '\\du+' || cmd === '\\dg+') {
1234
+ if (cmd === "\\du" ||
1235
+ cmd === "\\dg" ||
1236
+ cmd === "\\du+" ||
1237
+ cmd === "\\dg+") {
1233
1238
  if (prevWords.length === 1 && conn) {
1234
1239
  const rows = await runCatalogQuery(conn, Query_for_list_of_roles, currentWord);
1235
1240
  return { candidates: rows };
@@ -1237,7 +1242,7 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1237
1242
  return { candidates: [] };
1238
1243
  }
1239
1244
  // \dx → extensions.
1240
- if (cmd === '\\dx' || cmd === '\\dx+') {
1245
+ if (cmd === "\\dx" || cmd === "\\dx+") {
1241
1246
  if (prevWords.length === 1 && conn) {
1242
1247
  const rows = await runCatalogQuery(conn, Query_for_list_of_extensions, currentWord);
1243
1248
  return { candidates: rows };
@@ -1245,7 +1250,7 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1245
1250
  return { candidates: [] };
1246
1251
  }
1247
1252
  // \dL → languages.
1248
- if (cmd === '\\dL' || cmd === '\\dL+') {
1253
+ if (cmd === "\\dL" || cmd === "\\dL+") {
1249
1254
  if (prevWords.length === 1 && conn) {
1250
1255
  const rows = await runCatalogQuery(conn, Query_for_list_of_languages, currentWord);
1251
1256
  return { candidates: rows };
@@ -1253,7 +1258,7 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1253
1258
  return { candidates: [] };
1254
1259
  }
1255
1260
  // \dT → types.
1256
- if (cmd === '\\dT' || cmd === '\\dT+') {
1261
+ if (cmd === "\\dT" || cmd === "\\dT+") {
1257
1262
  if (prevWords.length === 1 && conn) {
1258
1263
  const rows = await runCatalogQuery(conn, Query_for_list_of_types, currentWord);
1259
1264
  return { candidates: rows };
@@ -1261,10 +1266,10 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1261
1266
  return { candidates: [] };
1262
1267
  }
1263
1268
  // \do → operators.
1264
- if (cmd === '\\do' ||
1265
- cmd === '\\do+' ||
1266
- cmd === '\\doS' ||
1267
- cmd === '\\doS+') {
1269
+ if (cmd === "\\do" ||
1270
+ cmd === "\\do+" ||
1271
+ cmd === "\\doS" ||
1272
+ cmd === "\\doS+") {
1268
1273
  if (prevWords.length === 1 && conn) {
1269
1274
  const rows = await runCatalogQuery(conn, Query_for_list_of_operators, currentWord);
1270
1275
  return { candidates: rows };
@@ -1272,7 +1277,7 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1272
1277
  return { candidates: [] };
1273
1278
  }
1274
1279
  // \dC → casts (free-form pattern of "src AS tgt").
1275
- if (cmd === '\\dC' || cmd === '\\dC+') {
1280
+ if (cmd === "\\dC" || cmd === "\\dC+") {
1276
1281
  if (prevWords.length === 1 && conn) {
1277
1282
  const rows = await runCatalogQuery(conn, Query_for_list_of_casts, currentWord);
1278
1283
  return { candidates: rows };
@@ -1280,13 +1285,13 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1280
1285
  return { candidates: [] };
1281
1286
  }
1282
1287
  // \dt / \dtv / \d / \dv / \dm / \di / \ds → relations of various kinds.
1283
- if (cmd === '\\dt' ||
1284
- cmd === '\\dt+' ||
1285
- cmd === '\\dtv' ||
1286
- cmd === '\\d' ||
1287
- cmd === '\\d+' ||
1288
- cmd === '\\dE' ||
1289
- cmd === '\\dE+') {
1288
+ if (cmd === "\\dt" ||
1289
+ cmd === "\\dt+" ||
1290
+ cmd === "\\dtv" ||
1291
+ cmd === "\\d" ||
1292
+ cmd === "\\d+" ||
1293
+ cmd === "\\dE" ||
1294
+ cmd === "\\dE+") {
1290
1295
  if (prevWords.length === 1 && conn) {
1291
1296
  return {
1292
1297
  candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_tables),
@@ -1294,7 +1299,7 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1294
1299
  }
1295
1300
  return { candidates: [] };
1296
1301
  }
1297
- if (cmd === '\\dv' || cmd === '\\dv+') {
1302
+ if (cmd === "\\dv" || cmd === "\\dv+") {
1298
1303
  if (prevWords.length === 1 && conn) {
1299
1304
  return {
1300
1305
  candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_views),
@@ -1302,7 +1307,7 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1302
1307
  }
1303
1308
  return { candidates: [] };
1304
1309
  }
1305
- if (cmd === '\\dm' || cmd === '\\dm+') {
1310
+ if (cmd === "\\dm" || cmd === "\\dm+") {
1306
1311
  if (prevWords.length === 1 && conn) {
1307
1312
  return {
1308
1313
  candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_matviews),
@@ -1310,7 +1315,7 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1310
1315
  }
1311
1316
  return { candidates: [] };
1312
1317
  }
1313
- if (cmd === '\\di' || cmd === '\\di+') {
1318
+ if (cmd === "\\di" || cmd === "\\di+") {
1314
1319
  if (prevWords.length === 1 && conn) {
1315
1320
  return {
1316
1321
  candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_indexes),
@@ -1318,7 +1323,7 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1318
1323
  }
1319
1324
  return { candidates: [] };
1320
1325
  }
1321
- if (cmd === '\\ds' || cmd === '\\ds+') {
1326
+ if (cmd === "\\ds" || cmd === "\\ds+") {
1322
1327
  if (prevWords.length === 1 && conn) {
1323
1328
  return {
1324
1329
  candidates: await completeSchemaOrRelations(conn, currentWord, Query_for_list_of_sequences),
@@ -1327,10 +1332,10 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1327
1332
  return { candidates: [] };
1328
1333
  }
1329
1334
  // \l[+] / \list → databases.
1330
- if (cmd === '\\l' ||
1331
- cmd === '\\l+' ||
1332
- cmd === '\\list' ||
1333
- cmd === '\\list+') {
1335
+ if (cmd === "\\l" ||
1336
+ cmd === "\\l+" ||
1337
+ cmd === "\\list" ||
1338
+ cmd === "\\list+") {
1334
1339
  if (prevWords.length === 1 && conn) {
1335
1340
  const rows = await runCatalogQuery(conn, Query_for_list_of_databases, currentWord);
1336
1341
  return { candidates: rows };
@@ -1338,14 +1343,14 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1338
1343
  return { candidates: [] };
1339
1344
  }
1340
1345
  // \encoding NAME
1341
- if (cmd === '\\encoding') {
1346
+ if (cmd === "\\encoding") {
1342
1347
  if (prevWords.length === 1) {
1343
1348
  return { candidates: filterCi(ENCODINGS, currentWord) };
1344
1349
  }
1345
1350
  return { candidates: [] };
1346
1351
  }
1347
1352
  // \pset OPT [value]
1348
- if (cmd === '\\pset') {
1353
+ if (cmd === "\\pset") {
1349
1354
  if (prevWords.length === 1) {
1350
1355
  return { candidates: filterCi(PSET_OPTIONS, currentWord) };
1351
1356
  }
@@ -1358,7 +1363,7 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1358
1363
  return { candidates: [] };
1359
1364
  }
1360
1365
  // \set NAME [VALUE]
1361
- if (cmd === '\\set') {
1366
+ if (cmd === "\\set") {
1362
1367
  if (prevWords.length === 1) {
1363
1368
  return {
1364
1369
  candidates: filterCi(listAllVarNames(ctx.settings), currentWord),
@@ -1373,15 +1378,17 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1373
1378
  return { candidates: [] };
1374
1379
  }
1375
1380
  // \unset NAME — only existing variables.
1376
- if (cmd === '\\unset') {
1381
+ if (cmd === "\\unset") {
1377
1382
  if (prevWords.length === 1) {
1378
- return { candidates: filterCi(listVarNames(ctx.settings), currentWord) };
1383
+ return {
1384
+ candidates: filterCi(listVarNames(ctx.settings), currentWord),
1385
+ };
1379
1386
  }
1380
1387
  return { candidates: [] };
1381
1388
  }
1382
1389
  // \echo / \warn / \qecho — variable expansion only (handled above).
1383
1390
  // \prompt — variable name argument is the 1st positional.
1384
- if (cmd === '\\prompt') {
1391
+ if (cmd === "\\prompt") {
1385
1392
  if (prevWords.length === 2) {
1386
1393
  return {
1387
1394
  candidates: filterCi(listAllVarNames(ctx.settings), currentWord),
@@ -1392,16 +1399,16 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1392
1399
  // \lo_import / \lo_export → filesystem-driven filename completion.
1393
1400
  // psql parses the path as a backslash-argument literal — no SQL string
1394
1401
  // quoting required, so we use the unquoted candidate form.
1395
- if (cmd === '\\lo_import' || cmd === '\\lo_export') {
1402
+ if (cmd === "\\lo_import" || cmd === "\\lo_export") {
1396
1403
  if (prevWords.length === 1) {
1397
- return { candidates: completeFilenames(currentWord, 'none') };
1404
+ return { candidates: completeFilenames(currentWord, "none") };
1398
1405
  }
1399
1406
  return { candidates: [] };
1400
1407
  }
1401
1408
  // \copy <table> [FROM|TO] <path> — once the FROM/TO keyword has been
1402
1409
  // typed, the next token is a filename (backslash-context, so bare paths
1403
1410
  // are fine).
1404
- if (cmd === '\\copy') {
1411
+ if (cmd === "\\copy") {
1405
1412
  // First arg: a table name.
1406
1413
  if (prevWords.length === 1 && conn) {
1407
1414
  return {
@@ -1411,20 +1418,20 @@ const backslashArgRules = async (prevWords, currentWord, ctx, conn) => {
1411
1418
  // Second arg: the FROM/TO keyword.
1412
1419
  if (prevWords.length === 2) {
1413
1420
  return {
1414
- candidates: filterAndCase(['FROM', 'TO'], currentWord, ctx.settings),
1421
+ candidates: filterAndCase(["FROM", "TO"], currentWord, ctx.settings),
1415
1422
  };
1416
1423
  }
1417
1424
  // Third arg (after FROM/TO): the filename.
1418
1425
  if (prevWords.length >= 3) {
1419
1426
  const last = prevWords[prevWords.length - 1].toUpperCase();
1420
- if (last === 'FROM' || last === 'TO') {
1421
- return { candidates: completeFilenames(currentWord, 'none') };
1427
+ if (last === "FROM" || last === "TO") {
1428
+ return { candidates: completeFilenames(currentWord, "none") };
1422
1429
  }
1423
1430
  }
1424
1431
  return { candidates: [] };
1425
1432
  }
1426
1433
  // \drds, \drg → roles (for the first arg).
1427
- if (cmd === '\\drds' || cmd === '\\drg') {
1434
+ if (cmd === "\\drds" || cmd === "\\drg") {
1428
1435
  if (prevWords.length === 1 && conn) {
1429
1436
  const rows = await runCatalogQuery(conn, Query_for_list_of_roles, currentWord);
1430
1437
  return { candidates: rows };
@@ -1451,34 +1458,35 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1451
1458
  // string-literal context. MUST come before the generic `FROM <prefix>`
1452
1459
  // rule below, which would otherwise treat the path as a table name.
1453
1460
  if (isCopyFromOrTo(prevWords)) {
1454
- return { candidates: completeFilenames(currentWord, 'sql') };
1461
+ return { candidates: completeFilenames(currentWord, "sql") };
1455
1462
  }
1456
1463
  // FROM <prefix>: tables/views/matviews. EXCLUDE `REVOKE … FROM <role>`,
1457
1464
  // which must complete role names — otherwise this generic rule shadows the
1458
1465
  // REVOKE-roles arm below, making it dead code (review item #26).
1459
- if (TailMatches(prevWords, ['FROM']) && !HeadMatches(prevWords, ['REVOKE'])) {
1466
+ if (TailMatches(prevWords, ["FROM"]) &&
1467
+ !HeadMatches(prevWords, ["REVOKE"])) {
1460
1468
  return completeTables(Query_for_list_of_tables_views);
1461
1469
  }
1462
1470
  // After FROM x, suggest JOIN/WHERE/etc — handled below.
1463
1471
  // UPDATE <prefix>: tables.
1464
- if (TailMatches(prevWords, ['UPDATE']))
1472
+ if (TailMatches(prevWords, ["UPDATE"]))
1465
1473
  return completeTables();
1466
1474
  // DELETE FROM <prefix>: tables.
1467
- if (TailMatches(prevWords, ['DELETE', 'FROM']))
1475
+ if (TailMatches(prevWords, ["DELETE", "FROM"]))
1468
1476
  return completeTables();
1469
1477
  // INSERT INTO <prefix>: tables. The tokenizer might give us
1470
1478
  // ['INSERT'] [INTO] or ['INSERT', 'INTO'] depending on whether the user
1471
1479
  // typed an extra space.
1472
- if (TailMatches(prevWords, ['INTO']))
1480
+ if (TailMatches(prevWords, ["INTO"]))
1473
1481
  return completeTables();
1474
1482
  // JOIN <prefix>: tables. Most common: SELECT … FROM x JOIN <prefix>.
1475
- if (TailMatches(prevWords, ['JOIN'])) {
1483
+ if (TailMatches(prevWords, ["JOIN"])) {
1476
1484
  return completeTables(Query_for_list_of_tables_views);
1477
1485
  }
1478
1486
  // After JOIN x, suggest ON or USING.
1479
- if (TailMatches(prevWords, ['JOIN', MatchAny])) {
1487
+ if (TailMatches(prevWords, ["JOIN", MatchAny])) {
1480
1488
  return {
1481
- candidates: filterAndCase(['ON', 'USING'], currentWord, ctx.settings),
1489
+ candidates: filterAndCase(["ON", "USING"], currentWord, ctx.settings),
1482
1490
  };
1483
1491
  }
1484
1492
  // After `FROM table_name <TAB>` (or `FROM table AS alias <TAB>`) — offer
@@ -1486,15 +1494,15 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1486
1494
  // SELECT/INSERT/UPDATE/DELETE (i.e. a SELECT-list-friendly context), so
1487
1495
  // we don't trample more specific rules like `ALTER TABLE x` or
1488
1496
  // `INSERT INTO x` which look "FROM-like" structurally.
1489
- const inSelectContext = HeadMatches(prevWords, ['SELECT']) ||
1490
- HeadMatches(prevWords, ['INSERT']) ||
1491
- HeadMatches(prevWords, ['UPDATE']) ||
1492
- HeadMatches(prevWords, ['DELETE']) ||
1493
- HeadMatches(prevWords, ['WITH']) ||
1494
- HeadMatches(prevWords, ['EXPLAIN']);
1497
+ const inSelectContext = HeadMatches(prevWords, ["SELECT"]) ||
1498
+ HeadMatches(prevWords, ["INSERT"]) ||
1499
+ HeadMatches(prevWords, ["UPDATE"]) ||
1500
+ HeadMatches(prevWords, ["DELETE"]) ||
1501
+ HeadMatches(prevWords, ["WITH"]) ||
1502
+ HeadMatches(prevWords, ["EXPLAIN"]);
1495
1503
  if (inSelectContext &&
1496
- (TailMatches(prevWords, ['FROM', MatchAny]) ||
1497
- TailMatches(prevWords, ['FROM', MatchAny, MatchAny]))) {
1504
+ (TailMatches(prevWords, ["FROM", MatchAny]) ||
1505
+ TailMatches(prevWords, ["FROM", MatchAny, MatchAny]))) {
1498
1506
  // `FROM x` or `FROM x alias` → post-FROM continuations.
1499
1507
  return {
1500
1508
  candidates: filterAndCase(POST_FROM_KEYWORDS, currentWord, ctx.settings),
@@ -1502,7 +1510,7 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1502
1510
  }
1503
1511
  // Window-function frame clause: `OVER (` then `<TAB>`. The tokenizer
1504
1512
  // emits the `(` as its own token, so prevWords ends with '('.
1505
- if (TailMatches(prevWords, ['OVER', '('])) {
1513
+ if (TailMatches(prevWords, ["OVER", "("])) {
1506
1514
  return {
1507
1515
  candidates: filterAndCase(WINDOW_FRAME_KEYWORDS, currentWord, ctx.settings),
1508
1516
  };
@@ -1512,8 +1520,8 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1512
1520
  // suggest boolean continuations. We trigger on the simple case
1513
1521
  // `WHERE <ident>` and `WHERE … AND/OR <ident>`.
1514
1522
  if (inSelectContext &&
1515
- TailMatches(prevWords, ['WHERE', MatchAny]) &&
1516
- !TailMatches(prevWords, ['WHERE'])) {
1523
+ TailMatches(prevWords, ["WHERE", MatchAny]) &&
1524
+ !TailMatches(prevWords, ["WHERE"])) {
1517
1525
  return {
1518
1526
  candidates: filterAndCase(WHERE_CONTINUATIONS, currentWord, ctx.settings),
1519
1527
  };
@@ -1523,14 +1531,14 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1523
1531
  // 3-token fallback `ALTER TABLE x` (which lists generic sub-actions).
1524
1532
  // The deeper rules use HeadMatches so they survive an arbitrary trailing
1525
1533
  // option list like `ALTER TABLE foo ADD CONSTRAINT bar CHECK (...)`.
1526
- if (HeadMatches(prevWords, ['ALTER', 'TABLE']) &&
1527
- TailMatches(prevWords, ['ADD'])) {
1534
+ if (HeadMatches(prevWords, ["ALTER", "TABLE"]) &&
1535
+ TailMatches(prevWords, ["ADD"])) {
1528
1536
  return {
1529
1537
  candidates: filterAndCase(ALTER_TABLE_ADD, currentWord, ctx.settings),
1530
1538
  };
1531
1539
  }
1532
- if (HeadMatches(prevWords, ['ALTER', 'TABLE']) &&
1533
- TailMatches(prevWords, ['DROP'])) {
1540
+ if (HeadMatches(prevWords, ["ALTER", "TABLE"]) &&
1541
+ TailMatches(prevWords, ["DROP"])) {
1534
1542
  return {
1535
1543
  candidates: filterAndCase(ALTER_TABLE_DROP, currentWord, ctx.settings),
1536
1544
  };
@@ -1538,8 +1546,8 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1538
1546
  // `ALTER TABLE <ref> DROP CONSTRAINT <prefix>` — constraint names on
1539
1547
  // the referenced table. Mirrors upstream tab-complete.in.c ~line 1280
1540
1548
  // (`COMPLETE_WITH_QUERY(Query_for_constraint_of_table)`).
1541
- if (HeadMatches(prevWords, ['ALTER', 'TABLE']) &&
1542
- TailMatches(prevWords, ['DROP', 'CONSTRAINT'])) {
1549
+ if (HeadMatches(prevWords, ["ALTER", "TABLE"]) &&
1550
+ TailMatches(prevWords, ["DROP", "CONSTRAINT"])) {
1543
1551
  if (!conn)
1544
1552
  return { candidates: [] };
1545
1553
  const refTokens = prevWords.slice(2, prevWords.length - 2);
@@ -1551,94 +1559,98 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1551
1559
  : await runCatalogQuery(conn, Query_for_constraint_of_table_in_schema, currentWord, [ref.schema, ref.table]);
1552
1560
  return { candidates: cands };
1553
1561
  }
1554
- if (HeadMatches(prevWords, ['ALTER', 'TABLE']) &&
1555
- TailMatches(prevWords, ['RENAME'])) {
1562
+ if (HeadMatches(prevWords, ["ALTER", "TABLE"]) &&
1563
+ TailMatches(prevWords, ["RENAME"])) {
1556
1564
  return {
1557
1565
  candidates: filterAndCase(ALTER_TABLE_RENAME, currentWord, ctx.settings),
1558
1566
  };
1559
1567
  }
1560
- if (HeadMatches(prevWords, ['ALTER', 'TABLE']) &&
1561
- (TailMatches(prevWords, ['ALTER']) ||
1562
- TailMatches(prevWords, ['ALTER', 'COLUMN', MatchAny]))) {
1568
+ if (HeadMatches(prevWords, ["ALTER", "TABLE"]) &&
1569
+ (TailMatches(prevWords, ["ALTER"]) ||
1570
+ TailMatches(prevWords, ["ALTER", "COLUMN", MatchAny]))) {
1563
1571
  return {
1564
1572
  candidates: filterAndCase(ALTER_TABLE_ALTER_COLUMN, currentWord, ctx.settings),
1565
1573
  };
1566
1574
  }
1567
- if (HeadMatches(prevWords, ['ALTER', 'TABLE']) &&
1568
- TailMatches(prevWords, ['SET'])) {
1575
+ if (HeadMatches(prevWords, ["ALTER", "TABLE"]) &&
1576
+ TailMatches(prevWords, ["SET"])) {
1569
1577
  return {
1570
1578
  candidates: filterAndCase(ALTER_TABLE_SET, currentWord, ctx.settings),
1571
1579
  };
1572
1580
  }
1573
- if (HeadMatches(prevWords, ['ALTER', 'TABLE']) &&
1574
- TailMatches(prevWords, ['ENABLE'])) {
1581
+ if (HeadMatches(prevWords, ["ALTER", "TABLE"]) &&
1582
+ TailMatches(prevWords, ["ENABLE"])) {
1575
1583
  return {
1576
1584
  candidates: filterAndCase(ALTER_TABLE_ENABLE, currentWord, ctx.settings),
1577
1585
  };
1578
1586
  }
1579
- if (HeadMatches(prevWords, ['ALTER', 'TABLE']) &&
1580
- TailMatches(prevWords, ['DISABLE'])) {
1587
+ if (HeadMatches(prevWords, ["ALTER", "TABLE"]) &&
1588
+ TailMatches(prevWords, ["DISABLE"])) {
1581
1589
  return {
1582
1590
  candidates: filterAndCase(ALTER_TABLE_DISABLE, currentWord, ctx.settings),
1583
1591
  };
1584
1592
  }
1585
- if (HeadMatches(prevWords, ['ALTER', 'TABLE']) &&
1586
- TailMatches(prevWords, ['REPLICA', 'IDENTITY'])) {
1593
+ if (HeadMatches(prevWords, ["ALTER", "TABLE"]) &&
1594
+ TailMatches(prevWords, ["REPLICA", "IDENTITY"])) {
1587
1595
  return {
1588
1596
  candidates: filterAndCase(ALTER_TABLE_REPLICA_IDENTITY, currentWord, ctx.settings),
1589
1597
  };
1590
1598
  }
1591
1599
  // ALTER TABLE x — sub-actions (must come AFTER the deep continuations above).
1592
- if (TailMatches(prevWords, ['ALTER', 'TABLE', MatchAny])) {
1600
+ if (TailMatches(prevWords, ["ALTER", "TABLE", MatchAny])) {
1593
1601
  return {
1594
1602
  candidates: filterAndCase(ALTER_TABLE_ACTIONS, currentWord, ctx.settings),
1595
1603
  };
1596
1604
  }
1597
1605
  // ALTER TABLE — table name.
1598
- if (TailMatches(prevWords, ['ALTER', 'TABLE']))
1606
+ if (TailMatches(prevWords, ["ALTER", "TABLE"]))
1599
1607
  return completeTables();
1600
1608
  // ---- ALTER VIEW / MATERIALIZED VIEW ----
1601
- if (TailMatches(prevWords, ['ALTER', 'VIEW', MatchAny])) {
1609
+ if (TailMatches(prevWords, ["ALTER", "VIEW", MatchAny])) {
1602
1610
  return {
1603
1611
  candidates: filterAndCase(ALTER_VIEW_ACTIONS, currentWord, ctx.settings),
1604
1612
  };
1605
1613
  }
1606
- if (TailMatches(prevWords, ['ALTER', 'VIEW'])) {
1614
+ if (TailMatches(prevWords, ["ALTER", "VIEW"])) {
1607
1615
  return completeTables(Query_for_list_of_views);
1608
1616
  }
1609
- if (TailMatches(prevWords, ['ALTER', 'MATERIALIZED', 'VIEW', MatchAny])) {
1617
+ if (TailMatches(prevWords, ["ALTER", "MATERIALIZED", "VIEW", MatchAny])) {
1610
1618
  return {
1611
1619
  candidates: filterAndCase(ALTER_MATVIEW_ACTIONS, currentWord, ctx.settings),
1612
1620
  };
1613
1621
  }
1614
- if (TailMatches(prevWords, ['ALTER', 'MATERIALIZED', 'VIEW'])) {
1622
+ if (TailMatches(prevWords, ["ALTER", "MATERIALIZED", "VIEW"])) {
1615
1623
  return completeTables(Query_for_list_of_matviews);
1616
1624
  }
1617
1625
  // ---- ALTER INDEX ----
1618
- if (TailMatches(prevWords, ['ALTER', 'INDEX', MatchAny])) {
1626
+ if (TailMatches(prevWords, ["ALTER", "INDEX", MatchAny])) {
1619
1627
  return {
1620
1628
  candidates: filterAndCase(ALTER_INDEX_ACTIONS, currentWord, ctx.settings),
1621
1629
  };
1622
1630
  }
1623
- if (TailMatches(prevWords, ['ALTER', 'INDEX'])) {
1631
+ if (TailMatches(prevWords, ["ALTER", "INDEX"])) {
1624
1632
  return completeTables(Query_for_list_of_indexes);
1625
1633
  }
1626
1634
  // ---- ALTER SEQUENCE ----
1627
- if (TailMatches(prevWords, ['ALTER', 'SEQUENCE', MatchAny])) {
1635
+ if (TailMatches(prevWords, ["ALTER", "SEQUENCE", MatchAny])) {
1628
1636
  return {
1629
1637
  candidates: filterAndCase(ALTER_SEQUENCE_ACTIONS, currentWord, ctx.settings),
1630
1638
  };
1631
1639
  }
1632
- if (TailMatches(prevWords, ['ALTER', 'SEQUENCE'])) {
1640
+ if (TailMatches(prevWords, ["ALTER", "SEQUENCE"])) {
1633
1641
  return completeTables(Query_for_list_of_sequences);
1634
1642
  }
1635
1643
  // ---- ALTER FUNCTION / PROCEDURE / ROUTINE ----
1636
- if (TailMatches(prevWords, ['ALTER', 'FUNCTION|PROCEDURE|ROUTINE', MatchAny])) {
1644
+ if (TailMatches(prevWords, [
1645
+ "ALTER",
1646
+ "FUNCTION|PROCEDURE|ROUTINE",
1647
+ MatchAny,
1648
+ ])) {
1637
1649
  return {
1638
1650
  candidates: filterAndCase(ALTER_FUNCTION_ACTIONS, currentWord, ctx.settings),
1639
1651
  };
1640
1652
  }
1641
- if (TailMatches(prevWords, ['ALTER', 'FUNCTION|PROCEDURE|ROUTINE'])) {
1653
+ if (TailMatches(prevWords, ["ALTER", "FUNCTION|PROCEDURE|ROUTINE"])) {
1642
1654
  if (!conn)
1643
1655
  return { candidates: [] };
1644
1656
  return {
@@ -1649,7 +1661,13 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1649
1661
  // `ALTER TYPE <enum> RENAME VALUE 'X<TAB>` — enum labels of the named
1650
1662
  // type, wrapped in single quotes since the user is mid-string-literal.
1651
1663
  // Mirrors upstream tab-complete.in.c ~line 1480.
1652
- if (TailMatches(prevWords, ['ALTER', 'TYPE', MatchAny, 'RENAME', 'VALUE']) &&
1664
+ if (TailMatches(prevWords, [
1665
+ "ALTER",
1666
+ "TYPE",
1667
+ MatchAny,
1668
+ "RENAME",
1669
+ "VALUE",
1670
+ ]) &&
1653
1671
  currentWord.startsWith("'")) {
1654
1672
  if (!conn)
1655
1673
  return { candidates: [] };
@@ -1660,12 +1678,12 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1660
1678
  const cands = await runCatalogQuery(conn, Query_for_list_of_enum_values_quoted, labelPrefix, [typeName]);
1661
1679
  return { candidates: cands };
1662
1680
  }
1663
- if (TailMatches(prevWords, ['ALTER', 'TYPE', MatchAny])) {
1681
+ if (TailMatches(prevWords, ["ALTER", "TYPE", MatchAny])) {
1664
1682
  return {
1665
1683
  candidates: filterAndCase(ALTER_TYPE_ACTIONS, currentWord, ctx.settings),
1666
1684
  };
1667
1685
  }
1668
- if (TailMatches(prevWords, ['ALTER', 'TYPE'])) {
1686
+ if (TailMatches(prevWords, ["ALTER", "TYPE"])) {
1669
1687
  if (!conn)
1670
1688
  return { candidates: [] };
1671
1689
  return {
@@ -1673,12 +1691,12 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1673
1691
  };
1674
1692
  }
1675
1693
  // ---- ALTER ROLE / USER / GROUP ----
1676
- if (TailMatches(prevWords, ['ALTER', 'ROLE|USER|GROUP', MatchAny])) {
1694
+ if (TailMatches(prevWords, ["ALTER", "ROLE|USER|GROUP", MatchAny])) {
1677
1695
  return {
1678
1696
  candidates: filterAndCase(ALTER_ROLE_ACTIONS, currentWord, ctx.settings),
1679
1697
  };
1680
1698
  }
1681
- if (TailMatches(prevWords, ['ALTER', 'ROLE|USER|GROUP'])) {
1699
+ if (TailMatches(prevWords, ["ALTER", "ROLE|USER|GROUP"])) {
1682
1700
  if (!conn)
1683
1701
  return { candidates: [] };
1684
1702
  return {
@@ -1686,12 +1704,12 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1686
1704
  };
1687
1705
  }
1688
1706
  // ---- ALTER DATABASE ----
1689
- if (TailMatches(prevWords, ['ALTER', 'DATABASE', MatchAny])) {
1707
+ if (TailMatches(prevWords, ["ALTER", "DATABASE", MatchAny])) {
1690
1708
  return {
1691
1709
  candidates: filterAndCase(ALTER_DATABASE_ACTIONS, currentWord, ctx.settings),
1692
1710
  };
1693
1711
  }
1694
- if (TailMatches(prevWords, ['ALTER', 'DATABASE'])) {
1712
+ if (TailMatches(prevWords, ["ALTER", "DATABASE"])) {
1695
1713
  if (!conn)
1696
1714
  return { candidates: [] };
1697
1715
  return {
@@ -1699,12 +1717,12 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1699
1717
  };
1700
1718
  }
1701
1719
  // ---- ALTER SCHEMA ----
1702
- if (TailMatches(prevWords, ['ALTER', 'SCHEMA', MatchAny])) {
1720
+ if (TailMatches(prevWords, ["ALTER", "SCHEMA", MatchAny])) {
1703
1721
  return {
1704
1722
  candidates: filterAndCase(ALTER_SCHEMA_ACTIONS, currentWord, ctx.settings),
1705
1723
  };
1706
1724
  }
1707
- if (TailMatches(prevWords, ['ALTER', 'SCHEMA'])) {
1725
+ if (TailMatches(prevWords, ["ALTER", "SCHEMA"])) {
1708
1726
  if (!conn)
1709
1727
  return { candidates: [] };
1710
1728
  return {
@@ -1712,12 +1730,12 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1712
1730
  };
1713
1731
  }
1714
1732
  // ---- ALTER EXTENSION ----
1715
- if (TailMatches(prevWords, ['ALTER', 'EXTENSION', MatchAny])) {
1733
+ if (TailMatches(prevWords, ["ALTER", "EXTENSION", MatchAny])) {
1716
1734
  return {
1717
1735
  candidates: filterAndCase(ALTER_EXTENSION_ACTIONS, currentWord, ctx.settings),
1718
1736
  };
1719
1737
  }
1720
- if (TailMatches(prevWords, ['ALTER', 'EXTENSION'])) {
1738
+ if (TailMatches(prevWords, ["ALTER", "EXTENSION"])) {
1721
1739
  if (!conn)
1722
1740
  return { candidates: [] };
1723
1741
  return {
@@ -1725,26 +1743,26 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1725
1743
  };
1726
1744
  }
1727
1745
  // ---- ALTER POLICY <name> ON <table> ----
1728
- if (TailMatches(prevWords, ['ALTER', 'POLICY', MatchAny])) {
1746
+ if (TailMatches(prevWords, ["ALTER", "POLICY", MatchAny])) {
1729
1747
  return {
1730
1748
  candidates: filterAndCase(ALTER_POLICY_ACTIONS, currentWord, ctx.settings),
1731
1749
  };
1732
1750
  }
1733
- if (HeadMatches(prevWords, ['ALTER', 'POLICY']) &&
1734
- TailMatches(prevWords, ['ON'])) {
1751
+ if (HeadMatches(prevWords, ["ALTER", "POLICY"]) &&
1752
+ TailMatches(prevWords, ["ON"])) {
1735
1753
  return completeTables();
1736
1754
  }
1737
- if (TailMatches(prevWords, ['ALTER', 'POLICY'])) {
1755
+ if (TailMatches(prevWords, ["ALTER", "POLICY"])) {
1738
1756
  // Free-form policy name.
1739
1757
  return { candidates: [] };
1740
1758
  }
1741
1759
  // ---- ALTER PUBLICATION ----
1742
- if (TailMatches(prevWords, ['ALTER', 'PUBLICATION', MatchAny])) {
1760
+ if (TailMatches(prevWords, ["ALTER", "PUBLICATION", MatchAny])) {
1743
1761
  return {
1744
1762
  candidates: filterAndCase(ALTER_PUBLICATION_ACTIONS, currentWord, ctx.settings),
1745
1763
  };
1746
1764
  }
1747
- if (TailMatches(prevWords, ['ALTER', 'PUBLICATION'])) {
1765
+ if (TailMatches(prevWords, ["ALTER", "PUBLICATION"])) {
1748
1766
  if (!conn)
1749
1767
  return { candidates: [] };
1750
1768
  return {
@@ -1752,12 +1770,12 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1752
1770
  };
1753
1771
  }
1754
1772
  // ---- ALTER SUBSCRIPTION ----
1755
- if (TailMatches(prevWords, ['ALTER', 'SUBSCRIPTION', MatchAny])) {
1773
+ if (TailMatches(prevWords, ["ALTER", "SUBSCRIPTION", MatchAny])) {
1756
1774
  return {
1757
1775
  candidates: filterAndCase(ALTER_SUBSCRIPTION_ACTIONS, currentWord, ctx.settings),
1758
1776
  };
1759
1777
  }
1760
- if (TailMatches(prevWords, ['ALTER', 'SUBSCRIPTION'])) {
1778
+ if (TailMatches(prevWords, ["ALTER", "SUBSCRIPTION"])) {
1761
1779
  if (!conn)
1762
1780
  return { candidates: [] };
1763
1781
  return {
@@ -1765,27 +1783,27 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1765
1783
  };
1766
1784
  }
1767
1785
  // Bare ALTER — sub-object keywords.
1768
- if (TailMatches(prevWords, ['ALTER'])) {
1786
+ if (TailMatches(prevWords, ["ALTER"])) {
1769
1787
  return {
1770
1788
  candidates: filterAndCase(ALTER_OBJECTS, currentWord, ctx.settings),
1771
1789
  };
1772
1790
  }
1773
1791
  // DROP TABLE, DROP VIEW, DROP INDEX, ...
1774
- if (TailMatches(prevWords, ['DROP', 'TABLE']))
1792
+ if (TailMatches(prevWords, ["DROP", "TABLE"]))
1775
1793
  return completeTables();
1776
- if (TailMatches(prevWords, ['DROP', 'VIEW'])) {
1794
+ if (TailMatches(prevWords, ["DROP", "VIEW"])) {
1777
1795
  return completeTables(Query_for_list_of_views);
1778
1796
  }
1779
- if (TailMatches(prevWords, ['DROP', 'MATERIALIZED', 'VIEW'])) {
1797
+ if (TailMatches(prevWords, ["DROP", "MATERIALIZED", "VIEW"])) {
1780
1798
  return completeTables(Query_for_list_of_matviews);
1781
1799
  }
1782
- if (TailMatches(prevWords, ['DROP', 'INDEX'])) {
1800
+ if (TailMatches(prevWords, ["DROP", "INDEX"])) {
1783
1801
  return completeTables(Query_for_list_of_indexes);
1784
1802
  }
1785
- if (TailMatches(prevWords, ['DROP', 'SEQUENCE'])) {
1803
+ if (TailMatches(prevWords, ["DROP", "SEQUENCE"])) {
1786
1804
  return completeTables(Query_for_list_of_sequences);
1787
1805
  }
1788
- if (TailMatches(prevWords, ['DROP', 'TYPE'])) {
1806
+ if (TailMatches(prevWords, ["DROP", "TYPE"])) {
1789
1807
  // Built-in scalar type keywords mirror upstream's
1790
1808
  // `Keywords_for_list_of_datatypes` attached to the SchemaQuery; psql
1791
1809
  // mixes them with user-defined types so `DROP TYPE big<TAB>` resolves
@@ -1796,56 +1814,56 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1796
1814
  const types = await runCatalogQuery(conn, Query_for_list_of_types, currentWord);
1797
1815
  return { candidates: [...keywords, ...types] };
1798
1816
  }
1799
- if (TailMatches(prevWords, ['DROP', 'SCHEMA'])) {
1817
+ if (TailMatches(prevWords, ["DROP", "SCHEMA"])) {
1800
1818
  if (!conn)
1801
1819
  return { candidates: [] };
1802
1820
  return {
1803
1821
  candidates: await runCatalogQuery(conn, Query_for_list_of_schemas, currentWord),
1804
1822
  };
1805
1823
  }
1806
- if (TailMatches(prevWords, ['DROP', 'EXTENSION'])) {
1824
+ if (TailMatches(prevWords, ["DROP", "EXTENSION"])) {
1807
1825
  if (!conn)
1808
1826
  return { candidates: [] };
1809
1827
  return {
1810
1828
  candidates: await runCatalogQuery(conn, Query_for_list_of_extensions, currentWord),
1811
1829
  };
1812
1830
  }
1813
- if (TailMatches(prevWords, ['DROP', 'ROLE|USER|GROUP'])) {
1831
+ if (TailMatches(prevWords, ["DROP", "ROLE|USER|GROUP"])) {
1814
1832
  if (!conn)
1815
1833
  return { candidates: [] };
1816
1834
  return {
1817
1835
  candidates: await runCatalogQuery(conn, Query_for_list_of_roles, currentWord),
1818
1836
  };
1819
1837
  }
1820
- if (TailMatches(prevWords, ['DROP', 'DATABASE'])) {
1838
+ if (TailMatches(prevWords, ["DROP", "DATABASE"])) {
1821
1839
  if (!conn)
1822
1840
  return { candidates: [] };
1823
1841
  return {
1824
1842
  candidates: await runCatalogQuery(conn, Query_for_list_of_databases, currentWord),
1825
1843
  };
1826
1844
  }
1827
- if (TailMatches(prevWords, ['DROP', 'FUNCTION'])) {
1845
+ if (TailMatches(prevWords, ["DROP", "FUNCTION"])) {
1828
1846
  if (!conn)
1829
1847
  return { candidates: [] };
1830
1848
  return {
1831
1849
  candidates: await runCatalogQuery(conn, Query_for_list_of_functions, currentWord),
1832
1850
  };
1833
1851
  }
1834
- if (TailMatches(prevWords, ['DROP', 'LANGUAGE'])) {
1852
+ if (TailMatches(prevWords, ["DROP", "LANGUAGE"])) {
1835
1853
  if (!conn)
1836
1854
  return { candidates: [] };
1837
1855
  return {
1838
1856
  candidates: await runCatalogQuery(conn, Query_for_list_of_languages, currentWord),
1839
1857
  };
1840
1858
  }
1841
- if (TailMatches(prevWords, ['DROP', 'TABLESPACE'])) {
1859
+ if (TailMatches(prevWords, ["DROP", "TABLESPACE"])) {
1842
1860
  if (!conn)
1843
1861
  return { candidates: [] };
1844
1862
  return {
1845
1863
  candidates: await runCatalogQuery(conn, Query_for_list_of_tablespaces, currentWord),
1846
1864
  };
1847
1865
  }
1848
- if (TailMatches(prevWords, ['DROP', 'PUBLICATION'])) {
1866
+ if (TailMatches(prevWords, ["DROP", "PUBLICATION"])) {
1849
1867
  // Mirrors upstream's `words_after_create` PUBLICATION entry
1850
1868
  // (VersionedQuery on `Query_for_list_of_publications`). Two-step
1851
1869
  // completion: `DROP PUBLIC<TAB>` first resolves to `PUBLICATION`
@@ -1857,7 +1875,7 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1857
1875
  candidates: await runCatalogQuery(conn, Query_for_list_of_publications, currentWord),
1858
1876
  };
1859
1877
  }
1860
- if (TailMatches(prevWords, ['DROP', 'SUBSCRIPTION'])) {
1878
+ if (TailMatches(prevWords, ["DROP", "SUBSCRIPTION"])) {
1861
1879
  // Same shape as DROP PUBLICATION — paired here for parity with the
1862
1880
  // ALTER block above.
1863
1881
  if (!conn)
@@ -1867,7 +1885,7 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1867
1885
  };
1868
1886
  }
1869
1887
  // Bare DROP — sub-object keywords.
1870
- if (TailMatches(prevWords, ['DROP'])) {
1888
+ if (TailMatches(prevWords, ["DROP"])) {
1871
1889
  return {
1872
1890
  candidates: filterAndCase(DROP_OBJECTS, currentWord, ctx.settings),
1873
1891
  };
@@ -1875,44 +1893,44 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1875
1893
  // ---- CREATE INDEX deep handling (specific arms BEFORE generic CREATE). ----
1876
1894
  // CREATE INDEX <TAB> → CONCURRENTLY, IF NOT EXISTS, ON (no name = use ON
1877
1895
  // directly), or a free-form index name.
1878
- if (TailMatches(prevWords, ['CREATE', 'INDEX'])) {
1896
+ if (TailMatches(prevWords, ["CREATE", "INDEX"])) {
1879
1897
  return {
1880
1898
  candidates: filterAndCase(CREATE_INDEX_OPTIONS, currentWord, ctx.settings),
1881
1899
  };
1882
1900
  }
1883
- if (TailMatches(prevWords, ['CREATE', 'UNIQUE', 'INDEX'])) {
1901
+ if (TailMatches(prevWords, ["CREATE", "UNIQUE", "INDEX"])) {
1884
1902
  return {
1885
1903
  candidates: filterAndCase(CREATE_INDEX_OPTIONS, currentWord, ctx.settings),
1886
1904
  };
1887
1905
  }
1888
1906
  // CREATE INDEX <name> <TAB> → ON.
1889
- if (TailMatches(prevWords, ['CREATE', 'INDEX', MatchAny]) ||
1890
- TailMatches(prevWords, ['CREATE', 'UNIQUE', 'INDEX', MatchAny])) {
1891
- return { candidates: filterAndCase(['ON'], currentWord, ctx.settings) };
1907
+ if (TailMatches(prevWords, ["CREATE", "INDEX", MatchAny]) ||
1908
+ TailMatches(prevWords, ["CREATE", "UNIQUE", "INDEX", MatchAny])) {
1909
+ return { candidates: filterAndCase(["ON"], currentWord, ctx.settings) };
1892
1910
  }
1893
1911
  // CREATE INDEX ... ON <TAB> → tables.
1894
- if (TailMatches(prevWords, ['CREATE', 'INDEX', MatchAny, 'ON']) ||
1895
- TailMatches(prevWords, ['CREATE', 'INDEX', 'ON']) ||
1896
- TailMatches(prevWords, ['CREATE', 'UNIQUE', 'INDEX', MatchAny, 'ON']) ||
1897
- TailMatches(prevWords, ['CREATE', 'UNIQUE', 'INDEX', 'ON'])) {
1912
+ if (TailMatches(prevWords, ["CREATE", "INDEX", MatchAny, "ON"]) ||
1913
+ TailMatches(prevWords, ["CREATE", "INDEX", "ON"]) ||
1914
+ TailMatches(prevWords, ["CREATE", "UNIQUE", "INDEX", MatchAny, "ON"]) ||
1915
+ TailMatches(prevWords, ["CREATE", "UNIQUE", "INDEX", "ON"])) {
1898
1916
  return completeTables();
1899
1917
  }
1900
1918
  // CREATE INDEX ... ON <table> <TAB> → USING / (.
1901
- if ((HeadMatches(prevWords, ['CREATE', 'INDEX']) ||
1902
- HeadMatches(prevWords, ['CREATE', 'UNIQUE', 'INDEX'])) &&
1903
- TailMatches(prevWords, ['ON', MatchAny])) {
1919
+ if ((HeadMatches(prevWords, ["CREATE", "INDEX"]) ||
1920
+ HeadMatches(prevWords, ["CREATE", "UNIQUE", "INDEX"])) &&
1921
+ TailMatches(prevWords, ["ON", MatchAny])) {
1904
1922
  return {
1905
- candidates: filterAndCase(['USING', '('], currentWord, ctx.settings),
1923
+ candidates: filterAndCase(["USING", "("], currentWord, ctx.settings),
1906
1924
  };
1907
1925
  }
1908
1926
  // CREATE INDEX ... USING <TAB> → access methods.
1909
- if ((HeadMatches(prevWords, ['CREATE', 'INDEX']) ||
1910
- HeadMatches(prevWords, ['CREATE', 'UNIQUE', 'INDEX'])) &&
1911
- TailMatches(prevWords, ['USING'])) {
1927
+ if ((HeadMatches(prevWords, ["CREATE", "INDEX"]) ||
1928
+ HeadMatches(prevWords, ["CREATE", "UNIQUE", "INDEX"])) &&
1929
+ TailMatches(prevWords, ["USING"])) {
1912
1930
  if (!conn) {
1913
1931
  // Even without a connection, offer the built-in AMs as a fallback.
1914
1932
  return {
1915
- candidates: filterAndCase(['btree', 'hash', 'gist', 'gin', 'spgist', 'brin'], currentWord, ctx.settings),
1933
+ candidates: filterAndCase(["btree", "hash", "gist", "gin", "spgist", "brin"], currentWord, ctx.settings),
1916
1934
  };
1917
1935
  }
1918
1936
  return {
@@ -1920,12 +1938,12 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1920
1938
  };
1921
1939
  }
1922
1940
  // CREATE ... — first sub-object keyword.
1923
- if (TailMatches(prevWords, ['CREATE'])) {
1941
+ if (TailMatches(prevWords, ["CREATE"])) {
1924
1942
  return {
1925
1943
  candidates: filterAndCase(CREATE_OBJECTS, currentWord, ctx.settings),
1926
1944
  };
1927
1945
  }
1928
- if (TailMatches(prevWords, ['CREATE', 'TABLE'])) {
1946
+ if (TailMatches(prevWords, ["CREATE", "TABLE"])) {
1929
1947
  // Upstream's `words_after_create` fallback (tab-complete.in.c
1930
1948
  // ~lines 2062-2082) runs `Query_for_list_of_tables` when the
1931
1949
  // word immediately before the cursor is `TABLE`. The intent is to
@@ -1937,31 +1955,38 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1937
1955
  return completeTables();
1938
1956
  }
1939
1957
  // Inside CREATE TABLE column-list parens: `<col_name> <TAB>` → types.
1940
- if (HeadMatches(prevWords, ['CREATE', 'TABLE']) &&
1941
- TailMatches(prevWords, ['(|,', MatchAny])) {
1958
+ if (HeadMatches(prevWords, ["CREATE", "TABLE"]) &&
1959
+ TailMatches(prevWords, ["(|,", MatchAny])) {
1942
1960
  if (!conn)
1943
1961
  return { candidates: [] };
1944
1962
  return {
1945
1963
  candidates: await runCatalogQuery(conn, Query_for_list_of_datatypes, currentWord),
1946
1964
  };
1947
1965
  }
1948
- if (TailMatches(prevWords, ['CREATE', 'OR', 'REPLACE'])) {
1966
+ if (TailMatches(prevWords, ["CREATE", "OR", "REPLACE"])) {
1949
1967
  return {
1950
- candidates: filterAndCase(['FUNCTION', 'PROCEDURE', 'VIEW', 'TRIGGER', 'AGGREGATE', 'TRANSFORM'], currentWord, ctx.settings),
1968
+ candidates: filterAndCase([
1969
+ "FUNCTION",
1970
+ "PROCEDURE",
1971
+ "VIEW",
1972
+ "TRIGGER",
1973
+ "AGGREGATE",
1974
+ "TRANSFORM",
1975
+ ], currentWord, ctx.settings),
1951
1976
  };
1952
1977
  }
1953
1978
  // TRUNCATE [TABLE] x
1954
- if (TailMatches(prevWords, ['TRUNCATE'])) {
1979
+ if (TailMatches(prevWords, ["TRUNCATE"])) {
1955
1980
  return {
1956
1981
  candidates: [
1957
- ...filterAndCase(['TABLE', 'ONLY'], currentWord, ctx.settings),
1982
+ ...filterAndCase(["TABLE", "ONLY"], currentWord, ctx.settings),
1958
1983
  ...(await tableCandidates(conn, currentWord)),
1959
1984
  ],
1960
1985
  };
1961
1986
  }
1962
- if (TailMatches(prevWords, ['TRUNCATE', 'TABLE']))
1987
+ if (TailMatches(prevWords, ["TRUNCATE", "TABLE"]))
1963
1988
  return completeTables();
1964
- if (TailMatches(prevWords, ['TRUNCATE', 'ONLY']))
1989
+ if (TailMatches(prevWords, ["TRUNCATE", "ONLY"]))
1965
1990
  return completeTables();
1966
1991
  // COPY ... FROM <sth> WITH ( — option keywords inside the WITH
1967
1992
  // parenthesised list. The tokenizer splits `(` and `,` into their
@@ -1973,16 +1998,16 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1973
1998
  // `Copy_to_options`). The `HeadMatches` guard restricts the rule
1974
1999
  // to a real COPY statement so the generic `(`/`,` pattern doesn't
1975
2000
  // fire inside CREATE TABLE / SELECT lists.
1976
- if (HeadMatches(prevWords, ['COPY|\\copy']) &&
1977
- HeadMatches(prevWords, [MatchAny, MatchAny, 'FROM']) &&
1978
- (TailMatches(prevWords, ['(']) || TailMatches(prevWords, [',']))) {
2001
+ if (HeadMatches(prevWords, ["COPY|\\copy"]) &&
2002
+ HeadMatches(prevWords, [MatchAny, MatchAny, "FROM"]) &&
2003
+ (TailMatches(prevWords, ["("]) || TailMatches(prevWords, [","]))) {
1979
2004
  return {
1980
2005
  candidates: filterAndCase(COPY_FROM_OPTIONS, currentWord, ctx.settings),
1981
2006
  };
1982
2007
  }
1983
- if (HeadMatches(prevWords, ['COPY|\\copy']) &&
1984
- HeadMatches(prevWords, [MatchAny, MatchAny, 'TO']) &&
1985
- (TailMatches(prevWords, ['(']) || TailMatches(prevWords, [',']))) {
2008
+ if (HeadMatches(prevWords, ["COPY|\\copy"]) &&
2009
+ HeadMatches(prevWords, [MatchAny, MatchAny, "TO"]) &&
2010
+ (TailMatches(prevWords, ["("]) || TailMatches(prevWords, [","]))) {
1986
2011
  return {
1987
2012
  candidates: filterAndCase(COPY_TO_OPTIONS, currentWord, ctx.settings),
1988
2013
  };
@@ -1990,46 +2015,53 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
1990
2015
  // COPY x → tables. (The `COPY x FROM/TO <path>` filename completion is
1991
2016
  // handled by the early `isCopyFromOrTo` check at the top of this
1992
2017
  // function so it wins over the generic `FROM <prefix>` table rule.)
1993
- if (TailMatches(prevWords, ['COPY']))
2018
+ if (TailMatches(prevWords, ["COPY"]))
1994
2019
  return completeTables();
1995
- if (TailMatches(prevWords, ['COPY', MatchAny])) {
2020
+ if (TailMatches(prevWords, ["COPY", MatchAny])) {
1996
2021
  return {
1997
- candidates: filterAndCase(['FROM', 'TO'], currentWord, ctx.settings),
2022
+ candidates: filterAndCase(["FROM", "TO"], currentWord, ctx.settings),
1998
2023
  };
1999
2024
  }
2000
2025
  // ANALYZE x → tables (optional VERBOSE first).
2001
- if (TailMatches(prevWords, ['ANALYZE']) ||
2002
- TailMatches(prevWords, ['ANALYZE', 'VERBOSE'])) {
2026
+ if (TailMatches(prevWords, ["ANALYZE"]) ||
2027
+ TailMatches(prevWords, ["ANALYZE", "VERBOSE"])) {
2003
2028
  return completeTables();
2004
2029
  }
2005
2030
  // VACUUM x → tables.
2006
- if (TailMatches(prevWords, ['VACUUM']) ||
2007
- TailMatches(prevWords, ['VACUUM', 'VERBOSE'])) {
2031
+ if (TailMatches(prevWords, ["VACUUM"]) ||
2032
+ TailMatches(prevWords, ["VACUUM", "VERBOSE"])) {
2008
2033
  return completeTables();
2009
2034
  }
2010
- if (TailMatches(prevWords, ['VACUUM', 'FULL']))
2035
+ if (TailMatches(prevWords, ["VACUUM", "FULL"]))
2011
2036
  return completeTables();
2012
- if (TailMatches(prevWords, ['VACUUM', 'ANALYZE']))
2037
+ if (TailMatches(prevWords, ["VACUUM", "ANALYZE"]))
2013
2038
  return completeTables();
2014
2039
  // REINDEX [TABLE|INDEX|SCHEMA|DATABASE] x
2015
- if (TailMatches(prevWords, ['REINDEX'])) {
2040
+ if (TailMatches(prevWords, ["REINDEX"])) {
2016
2041
  return {
2017
- candidates: filterAndCase(['TABLE', 'INDEX', 'SCHEMA', 'DATABASE', 'SYSTEM', 'CONCURRENTLY'], currentWord, ctx.settings),
2042
+ candidates: filterAndCase([
2043
+ "TABLE",
2044
+ "INDEX",
2045
+ "SCHEMA",
2046
+ "DATABASE",
2047
+ "SYSTEM",
2048
+ "CONCURRENTLY",
2049
+ ], currentWord, ctx.settings),
2018
2050
  };
2019
2051
  }
2020
- if (TailMatches(prevWords, ['REINDEX', 'TABLE']))
2052
+ if (TailMatches(prevWords, ["REINDEX", "TABLE"]))
2021
2053
  return completeTables();
2022
- if (TailMatches(prevWords, ['REINDEX', 'INDEX'])) {
2054
+ if (TailMatches(prevWords, ["REINDEX", "INDEX"])) {
2023
2055
  return completeTables(Query_for_list_of_indexes);
2024
2056
  }
2025
- if (TailMatches(prevWords, ['REINDEX', 'SCHEMA'])) {
2057
+ if (TailMatches(prevWords, ["REINDEX", "SCHEMA"])) {
2026
2058
  if (!conn)
2027
2059
  return { candidates: [] };
2028
2060
  return {
2029
2061
  candidates: await runCatalogQuery(conn, Query_for_list_of_schemas, currentWord),
2030
2062
  };
2031
2063
  }
2032
- if (TailMatches(prevWords, ['REINDEX', 'DATABASE'])) {
2064
+ if (TailMatches(prevWords, ["REINDEX", "DATABASE"])) {
2033
2065
  if (!conn)
2034
2066
  return { candidates: [] };
2035
2067
  return {
@@ -2037,25 +2069,27 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
2037
2069
  };
2038
2070
  }
2039
2071
  // GRANT … ON … TO …
2040
- if (TailMatches(prevWords, ['GRANT']) || TailMatches(prevWords, ['REVOKE'])) {
2072
+ if (TailMatches(prevWords, ["GRANT"]) ||
2073
+ TailMatches(prevWords, ["REVOKE"])) {
2041
2074
  return {
2042
2075
  candidates: filterAndCase(PRIVILEGE_KEYWORDS, currentWord, ctx.settings),
2043
2076
  };
2044
2077
  }
2045
- if (TailMatches(prevWords, ['ON'])) {
2078
+ if (TailMatches(prevWords, ["ON"])) {
2046
2079
  // Could be either GRANT/REVOKE … ON or CREATE INDEX … ON. We try
2047
2080
  // tables; if the prior keyword set is CREATE INDEX the rule above
2048
2081
  // already short-circuited.
2049
2082
  return completeTables();
2050
2083
  }
2051
- if (TailMatches(prevWords, ['TO'])) {
2052
- if (HeadMatches(prevWords, ['GRANT']) && conn) {
2084
+ if (TailMatches(prevWords, ["TO"])) {
2085
+ if (HeadMatches(prevWords, ["GRANT"]) && conn) {
2053
2086
  return {
2054
2087
  candidates: await runCatalogQuery(conn, Query_for_list_of_roles, currentWord),
2055
2088
  };
2056
2089
  }
2057
2090
  }
2058
- if (TailMatches(prevWords, ['FROM']) && HeadMatches(prevWords, ['REVOKE'])) {
2091
+ if (TailMatches(prevWords, ["FROM"]) &&
2092
+ HeadMatches(prevWords, ["REVOKE"])) {
2059
2093
  if (!conn)
2060
2094
  return { candidates: [] };
2061
2095
  return {
@@ -2063,45 +2097,45 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
2063
2097
  };
2064
2098
  }
2065
2099
  // LOCK [TABLE] x
2066
- if (TailMatches(prevWords, ['LOCK'])) {
2100
+ if (TailMatches(prevWords, ["LOCK"])) {
2067
2101
  return {
2068
2102
  candidates: [
2069
- ...filterAndCase(['TABLE'], currentWord, ctx.settings),
2103
+ ...filterAndCase(["TABLE"], currentWord, ctx.settings),
2070
2104
  ...(await tableCandidates(conn, currentWord)),
2071
2105
  ],
2072
2106
  };
2073
2107
  }
2074
- if (TailMatches(prevWords, ['LOCK', 'TABLE']))
2108
+ if (TailMatches(prevWords, ["LOCK", "TABLE"]))
2075
2109
  return completeTables();
2076
2110
  // SET search_path, SET ROLE, SET SCHEMA, etc.
2077
- if (TailMatches(prevWords, ['SET', 'ROLE'])) {
2111
+ if (TailMatches(prevWords, ["SET", "ROLE"])) {
2078
2112
  if (!conn)
2079
2113
  return { candidates: [] };
2080
2114
  return {
2081
2115
  candidates: await runCatalogQuery(conn, Query_for_list_of_roles, currentWord),
2082
2116
  };
2083
2117
  }
2084
- if (TailMatches(prevWords, ['SET', 'SCHEMA'])) {
2118
+ if (TailMatches(prevWords, ["SET", "SCHEMA"])) {
2085
2119
  if (!conn)
2086
2120
  return { candidates: [] };
2087
2121
  return {
2088
2122
  candidates: await runCatalogQuery(conn, Query_for_list_of_schemas, currentWord),
2089
2123
  };
2090
2124
  }
2091
- if (TailMatches(prevWords, ['SET', 'SESSION'])) {
2125
+ if (TailMatches(prevWords, ["SET", "SESSION"])) {
2092
2126
  return {
2093
- candidates: filterAndCase(['AUTHORIZATION', 'CHARACTERISTICS AS TRANSACTION'], currentWord, ctx.settings),
2127
+ candidates: filterAndCase(["AUTHORIZATION", "CHARACTERISTICS AS TRANSACTION"], currentWord, ctx.settings),
2094
2128
  };
2095
2129
  }
2096
- if (TailMatches(prevWords, ['SET', 'TRANSACTION'])) {
2130
+ if (TailMatches(prevWords, ["SET", "TRANSACTION"])) {
2097
2131
  return {
2098
- candidates: filterAndCase(['ISOLATION LEVEL', 'READ ONLY', 'READ WRITE', 'DEFERRABLE'], currentWord, ctx.settings),
2132
+ candidates: filterAndCase(["ISOLATION LEVEL", "READ ONLY", "READ WRITE", "DEFERRABLE"], currentWord, ctx.settings),
2099
2133
  };
2100
2134
  }
2101
2135
  // `SET <name> TO|= <TAB>` — for DateStyle we can suggest the formats.
2102
- if (TailMatches(prevWords, ['SET', 'DateStyle', 'TO|=']) ||
2103
- TailMatches(prevWords, ['SET', 'DATESTYLE', 'TO|=']) ||
2104
- TailMatches(prevWords, ['SET', 'datestyle', 'TO|='])) {
2136
+ if (TailMatches(prevWords, ["SET", "DateStyle", "TO|="]) ||
2137
+ TailMatches(prevWords, ["SET", "DATESTYLE", "TO|="]) ||
2138
+ TailMatches(prevWords, ["SET", "datestyle", "TO|="])) {
2105
2139
  return {
2106
2140
  candidates: filterAndCase(DATESTYLE_VALUES, currentWord, ctx.settings),
2107
2141
  };
@@ -2118,9 +2152,9 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
2118
2152
  // pattern against the quoted form so the partial `'America/New_`
2119
2153
  // resolves correctly.
2120
2154
  // Mirrors upstream tab-complete.in.c ~line 4530.
2121
- if (TailMatches(prevWords, ['SET', 'timezone', 'TO|=']) ||
2122
- TailMatches(prevWords, ['SET', 'TIMEZONE', 'TO|=']) ||
2123
- TailMatches(prevWords, ['SET', 'TimeZone', 'TO|='])) {
2155
+ if (TailMatches(prevWords, ["SET", "timezone", "TO|="]) ||
2156
+ TailMatches(prevWords, ["SET", "TIMEZONE", "TO|="]) ||
2157
+ TailMatches(prevWords, ["SET", "TimeZone", "TO|="])) {
2124
2158
  if (!conn)
2125
2159
  return { candidates: [] };
2126
2160
  const query = currentWord.startsWith("'")
@@ -2136,7 +2170,7 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
2136
2170
  // value completion; non-enum GUCs return an empty rowset (no candidates)
2137
2171
  // — matching upstream, which also emits nothing for unknown GUCs once a
2138
2172
  // value position is reached.
2139
- if (TailMatches(prevWords, ['SET', MatchAny, 'TO|='])) {
2173
+ if (TailMatches(prevWords, ["SET", MatchAny, "TO|="])) {
2140
2174
  if (!conn)
2141
2175
  return { candidates: [] };
2142
2176
  // Walk back to the GUC name (the word before TO/=).
@@ -2150,21 +2184,21 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
2150
2184
  // single unique completion so `set foo<tab><tab>` resolves to
2151
2185
  // `set foo TO ` rather than listing two near-synonymous separators.
2152
2186
  // Verified against vanilla psql 18 + upstream test line 366.
2153
- if (TailMatches(prevWords, ['SET', MatchAny])) {
2187
+ if (TailMatches(prevWords, ["SET", MatchAny])) {
2154
2188
  return {
2155
- candidates: filterAndCase(['TO'], currentWord, ctx.settings),
2189
+ candidates: filterAndCase(["TO"], currentWord, ctx.settings),
2156
2190
  };
2157
2191
  }
2158
2192
  // Bare SET <TAB>: GUC name OR top-level SET sub-keywords (ROLE, SCHEMA, …).
2159
- if (TailMatches(prevWords, ['SET'])) {
2193
+ if (TailMatches(prevWords, ["SET"])) {
2160
2194
  const staticKw = filterAndCase([
2161
- 'CONSTRAINTS',
2162
- 'LOCAL',
2163
- 'ROLE',
2164
- 'SCHEMA',
2165
- 'SESSION',
2166
- 'TIME ZONE',
2167
- 'TRANSACTION',
2195
+ "CONSTRAINTS",
2196
+ "LOCAL",
2197
+ "ROLE",
2198
+ "SCHEMA",
2199
+ "SESSION",
2200
+ "TIME ZONE",
2201
+ "TRANSACTION",
2168
2202
  ], currentWord, ctx.settings);
2169
2203
  if (!conn)
2170
2204
  return { candidates: staticKw };
@@ -2172,21 +2206,21 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
2172
2206
  return { candidates: [...staticKw, ...guc] };
2173
2207
  }
2174
2208
  // SHOW <TAB> — ALL keyword plus the live GUC list.
2175
- if (TailMatches(prevWords, ['SHOW'])) {
2176
- const staticKw = filterAndCase(['ALL'], currentWord, ctx.settings);
2209
+ if (TailMatches(prevWords, ["SHOW"])) {
2210
+ const staticKw = filterAndCase(["ALL"], currentWord, ctx.settings);
2177
2211
  if (!conn) {
2178
2212
  return {
2179
2213
  candidates: [
2180
2214
  ...staticKw,
2181
2215
  ...filterAndCase([
2182
- 'search_path',
2183
- 'role',
2184
- 'session_authorization',
2185
- 'transaction_isolation',
2186
- 'client_encoding',
2187
- 'server_encoding',
2188
- 'server_version',
2189
- 'timezone',
2216
+ "search_path",
2217
+ "role",
2218
+ "session_authorization",
2219
+ "transaction_isolation",
2220
+ "client_encoding",
2221
+ "server_encoding",
2222
+ "server_version",
2223
+ "timezone",
2190
2224
  ], currentWord, ctx.settings),
2191
2225
  ],
2192
2226
  };
@@ -2195,47 +2229,48 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
2195
2229
  return { candidates: [...staticKw, ...guc] };
2196
2230
  }
2197
2231
  // RESET <TAB> — ALL or the live GUC list.
2198
- if (TailMatches(prevWords, ['RESET'])) {
2199
- const staticKw = filterAndCase(['ALL', 'SESSION AUTHORIZATION', 'ROLE'], currentWord, ctx.settings);
2232
+ if (TailMatches(prevWords, ["RESET"])) {
2233
+ const staticKw = filterAndCase(["ALL", "SESSION AUTHORIZATION", "ROLE"], currentWord, ctx.settings);
2200
2234
  if (!conn)
2201
2235
  return { candidates: staticKw };
2202
2236
  const guc = await runCatalogQuery(conn, Query_for_list_of_set_vars, currentWord);
2203
2237
  return { candidates: [...staticKw, ...guc] };
2204
2238
  }
2205
2239
  // START / BEGIN [TRANSACTION] …
2206
- if (TailMatches(prevWords, ['BEGIN']) || TailMatches(prevWords, ['START'])) {
2240
+ if (TailMatches(prevWords, ["BEGIN"]) ||
2241
+ TailMatches(prevWords, ["START"])) {
2207
2242
  return {
2208
2243
  candidates: filterAndCase(TRANSACTION_KEYWORDS, currentWord, ctx.settings),
2209
2244
  };
2210
2245
  }
2211
2246
  // COMMIT / ROLLBACK / RELEASE / SAVEPOINT - small completions
2212
- if (TailMatches(prevWords, ['ROLLBACK'])) {
2247
+ if (TailMatches(prevWords, ["ROLLBACK"])) {
2213
2248
  return {
2214
- candidates: filterAndCase(['TO SAVEPOINT', 'TRANSACTION', 'AND CHAIN', 'AND NO CHAIN'], currentWord, ctx.settings),
2249
+ candidates: filterAndCase(["TO SAVEPOINT", "TRANSACTION", "AND CHAIN", "AND NO CHAIN"], currentWord, ctx.settings),
2215
2250
  };
2216
2251
  }
2217
2252
  // EXPLAIN … — pass through to SELECT-/INSERT-/UPDATE-style rules by
2218
2253
  // letting subsequent words drive completion. For the first word after
2219
2254
  // EXPLAIN, offer the options + statement keywords.
2220
- if (TailMatches(prevWords, ['EXPLAIN'])) {
2255
+ if (TailMatches(prevWords, ["EXPLAIN"])) {
2221
2256
  return {
2222
2257
  candidates: filterAndCase([
2223
- 'ANALYZE',
2224
- 'VERBOSE',
2225
- 'SELECT',
2226
- 'INSERT INTO',
2227
- 'UPDATE',
2228
- 'DELETE FROM',
2229
- '(',
2258
+ "ANALYZE",
2259
+ "VERBOSE",
2260
+ "SELECT",
2261
+ "INSERT INTO",
2262
+ "UPDATE",
2263
+ "DELETE FROM",
2264
+ "(",
2230
2265
  ], currentWord, ctx.settings),
2231
2266
  };
2232
2267
  }
2233
2268
  // DECLARE … CURSOR FOR …
2234
- if (TailMatches(prevWords, ['DECLARE'])) {
2269
+ if (TailMatches(prevWords, ["DECLARE"])) {
2235
2270
  return { candidates: [] };
2236
2271
  }
2237
2272
  // CALL / DO — no completion beyond keywords (procedure args / language).
2238
- if (TailMatches(prevWords, ['CALL'])) {
2273
+ if (TailMatches(prevWords, ["CALL"])) {
2239
2274
  if (!conn)
2240
2275
  return { candidates: [] };
2241
2276
  return {
@@ -2243,27 +2278,29 @@ const sqlRules = async (prevWords, currentWord, ctx, conn) => {
2243
2278
  };
2244
2279
  }
2245
2280
  // After SELECT — offer FROM / common functions.
2246
- if (TailMatches(prevWords, ['SELECT'])) {
2281
+ if (TailMatches(prevWords, ["SELECT"])) {
2247
2282
  // The next word can be anything (column list); offer DISTINCT/ALL/* as a
2248
2283
  // small hint set.
2249
2284
  return {
2250
2285
  candidates: filterAndCase([
2251
- 'DISTINCT',
2252
- 'ALL',
2253
- '*',
2254
- 'CURRENT_DATE',
2255
- 'CURRENT_TIME',
2256
- 'CURRENT_TIMESTAMP',
2257
- 'CURRENT_USER',
2258
- 'NULL',
2259
- 'TRUE',
2260
- 'FALSE',
2286
+ "DISTINCT",
2287
+ "ALL",
2288
+ "*",
2289
+ "CURRENT_DATE",
2290
+ "CURRENT_TIME",
2291
+ "CURRENT_TIMESTAMP",
2292
+ "CURRENT_USER",
2293
+ "NULL",
2294
+ "TRUE",
2295
+ "FALSE",
2261
2296
  ], currentWord, ctx.settings),
2262
2297
  };
2263
2298
  }
2264
2299
  // Trailing-keyword fallthrough: WHERE, ORDER BY, GROUP BY, LIMIT etc.
2265
- if (TailMatches(prevWords, ['SELECT', '*'])) {
2266
- return { candidates: filterAndCase(['FROM'], currentWord, ctx.settings) };
2300
+ if (TailMatches(prevWords, ["SELECT", "*"])) {
2301
+ return {
2302
+ candidates: filterAndCase(["FROM"], currentWord, ctx.settings),
2303
+ };
2267
2304
  }
2268
2305
  // No specific rule fired.
2269
2306
  return { candidates: [] };
@@ -2309,14 +2346,14 @@ const completeSchemaOrRelations = async (conn, word, query) => {
2309
2346
  const canonicalSchema = split.schemaWasQuoted
2310
2347
  ? split.schema
2311
2348
  : split.schema.toLowerCase();
2312
- return rows.map((r) => canonicalSchema + '.' + r);
2349
+ return rows.map((r) => canonicalSchema + "." + r);
2313
2350
  }
2314
2351
  // Unqualified: combine relations + schemas (schemas suffixed with `.`).
2315
2352
  const [rels, schemas] = await Promise.all([
2316
2353
  runCatalogQuery(conn, query, word),
2317
2354
  runCatalogQuery(conn, Query_for_list_of_schemas, word),
2318
2355
  ]);
2319
- return [...rels, ...schemas.map((s) => s + '.')];
2356
+ return [...rels, ...schemas.map((s) => s + ".")];
2320
2357
  };
2321
2358
  /**
2322
2359
  * Search the catalog for relations matching a user-supplied prefix that
@@ -2328,7 +2365,7 @@ const completeSchemaOrRelations = async (conn, word, query) => {
2328
2365
  */
2329
2366
  const completeQuotedRelations = async (conn, word, query) => {
2330
2367
  // Strip leading `"` (and any trailing `"` the user pre-typed).
2331
- const inside = word.slice(1).replace(/"$/, '');
2368
+ const inside = word.slice(1).replace(/"$/, "");
2332
2369
  // Use a case-sensitive raw-relname LIKE — the inside-the-quote portion
2333
2370
  // is taken verbatim.
2334
2371
  const sql = caseSensitiveRelnameVariant(query);
@@ -2351,13 +2388,13 @@ const caseSensitiveRelnameVariant = (sql) => {
2351
2388
  // We rewrite the SELECT/WHERE clauses on the standard relation queries.
2352
2389
  // The only shape we need to support is `c.relname ILIKE $1` against
2353
2390
  // `pg_catalog.pg_class c`, with various `c.relkind IN (...)` filters.
2354
- if (!sql.includes('pg_catalog.pg_class c'))
2391
+ if (!sql.includes("pg_catalog.pg_class c"))
2355
2392
  return null;
2356
- if (!sql.includes('c.relname ILIKE $1'))
2393
+ if (!sql.includes("c.relname ILIKE $1"))
2357
2394
  return null;
2358
2395
  return sql
2359
- .replace('SELECT pg_catalog.quote_ident(c.relname)', 'SELECT c.relname')
2360
- .replace('c.relname ILIKE $1', 'c.relname LIKE $1');
2396
+ .replace("SELECT pg_catalog.quote_ident(c.relname)", "SELECT c.relname")
2397
+ .replace("c.relname ILIKE $1", "c.relname LIKE $1");
2361
2398
  };
2362
2399
  /** Case-insensitive prefix filter; preserves the candidate's original casing. */
2363
2400
  const filterCi = (candidates, prefix) => {