pgsql-deparser 17.17.2 → 17.18.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.
@@ -1,240 +0,0 @@
1
- import { keywordKindOf } from '../kwlist';
2
- export class QuoteUtils {
3
- static escape(literal) {
4
- return `'${literal.replace(/'/g, "''")}'`;
5
- }
6
- /**
7
- * Escapes a string value for use in E-prefixed string literals
8
- * Handles both backslashes and single quotes properly
9
- */
10
- static escapeEString(value) {
11
- return value.replace(/\\/g, '\\\\').replace(/'/g, "''");
12
- }
13
- /**
14
- * Formats a string as an E-prefixed string literal with proper escaping
15
- * This wraps the complete E-prefix logic including detection and formatting
16
- */
17
- static formatEString(value) {
18
- const needsEscape = QuoteUtils.needsEscapePrefix(value);
19
- if (needsEscape) {
20
- const escapedValue = QuoteUtils.escapeEString(value);
21
- return `E'${escapedValue}'`;
22
- }
23
- else {
24
- return QuoteUtils.escape(value);
25
- }
26
- }
27
- /**
28
- * Determines if a string value needs E-prefix for escaped string literals
29
- * Detects backslash escape sequences that require E-prefix in PostgreSQL
30
- */
31
- static needsEscapePrefix(value) {
32
- // Always use E'' if the string contains any backslashes,
33
- // unless it's a raw \x... bytea-style literal.
34
- return !/^\\x[0-9a-fA-F]+$/i.test(value) && value.includes('\\');
35
- }
36
- /**
37
- * Quote an identifier only if needed
38
- *
39
- * This is a TypeScript port of PostgreSQL's quote_identifier() function from ruleutils.c
40
- * https://github.com/postgres/postgres/blob/fab5cd3dd1323f9e66efeb676c4bb212ff340204/src/backend/utils/adt/ruleutils.c#L13055-L13137
41
- *
42
- * Can avoid quoting if ident starts with a lowercase letter or underscore
43
- * and contains only lowercase letters, digits, and underscores, *and* is
44
- * not any SQL keyword. Otherwise, supply quotes.
45
- *
46
- * When quotes are needed, embedded double quotes are properly escaped as "".
47
- */
48
- static quoteIdentifier(ident) {
49
- if (!ident)
50
- return ident;
51
- let safe = true;
52
- // Check first character: must be lowercase letter or underscore
53
- const firstChar = ident[0];
54
- if (!((firstChar >= 'a' && firstChar <= 'z') || firstChar === '_')) {
55
- safe = false;
56
- }
57
- // Check all characters
58
- for (let i = 0; i < ident.length; i++) {
59
- const ch = ident[i];
60
- if ((ch >= 'a' && ch <= 'z') ||
61
- (ch >= '0' && ch <= '9') ||
62
- (ch === '_')) {
63
- // okay
64
- }
65
- else {
66
- safe = false;
67
- }
68
- }
69
- if (safe) {
70
- // Check for keyword. We quote keywords except for unreserved ones.
71
- // (In some cases we could avoid quoting a col_name or type_func_name
72
- // keyword, but it seems much harder than it's worth to tell that.)
73
- const kwKind = keywordKindOf(ident);
74
- if (kwKind !== 'NO_KEYWORD' && kwKind !== 'UNRESERVED_KEYWORD') {
75
- safe = false;
76
- }
77
- }
78
- if (safe) {
79
- return ident; // no change needed
80
- }
81
- // Build quoted identifier with escaped embedded quotes
82
- let result = '"';
83
- for (let i = 0; i < ident.length; i++) {
84
- const ch = ident[i];
85
- if (ch === '"') {
86
- result += '"'; // escape " as ""
87
- }
88
- result += ch;
89
- }
90
- result += '"';
91
- return result;
92
- }
93
- /**
94
- * Quote an identifier that appears after a dot in a qualified name.
95
- *
96
- * In PostgreSQL's grammar, identifiers that appear after a dot (e.g., schema.name,
97
- * table.column) are in a more permissive position that accepts all keyword categories
98
- * including RESERVED_KEYWORD. This means we only need to quote for lexical reasons
99
- * (uppercase, special characters, leading digits) not for keyword reasons.
100
- *
101
- * Empirically verified: `myschema.select`, `myschema.float`, `t.from` all parse
102
- * successfully in PostgreSQL without quotes.
103
- */
104
- static quoteIdentifierAfterDot(ident) {
105
- if (!ident)
106
- return ident;
107
- let safe = true;
108
- const firstChar = ident[0];
109
- if (!((firstChar >= 'a' && firstChar <= 'z') || firstChar === '_')) {
110
- safe = false;
111
- }
112
- for (let i = 0; i < ident.length; i++) {
113
- const ch = ident[i];
114
- if ((ch >= 'a' && ch <= 'z') ||
115
- (ch >= '0' && ch <= '9') ||
116
- (ch === '_')) {
117
- // okay
118
- }
119
- else {
120
- safe = false;
121
- }
122
- }
123
- if (safe) {
124
- return ident;
125
- }
126
- let result = '"';
127
- for (let i = 0; i < ident.length; i++) {
128
- const ch = ident[i];
129
- if (ch === '"') {
130
- result += '"';
131
- }
132
- result += ch;
133
- }
134
- result += '"';
135
- return result;
136
- }
137
- /**
138
- * Quote a dotted name (e.g., schema.table, catalog.schema.table).
139
- *
140
- * The first part uses strict quoting (keywords are quoted), while subsequent
141
- * parts use relaxed quoting (keywords allowed, only quote for lexical reasons).
142
- *
143
- * This reflects PostgreSQL's grammar where the first identifier in a statement
144
- * may conflict with keywords, but identifiers after a dot are in a more
145
- * permissive position.
146
- */
147
- static quoteDottedName(parts) {
148
- if (!parts || parts.length === 0)
149
- return '';
150
- if (parts.length === 1) {
151
- return QuoteUtils.quoteIdentifier(parts[0]);
152
- }
153
- return parts.map((part, index) => index === 0 ? QuoteUtils.quoteIdentifier(part) : QuoteUtils.quoteIdentifierAfterDot(part)).join('.');
154
- }
155
- /**
156
- * Quote a possibly-qualified identifier
157
- *
158
- * This is inspired by PostgreSQL's quote_qualified_identifier() function from ruleutils.c
159
- * but uses relaxed quoting for the tail component since PostgreSQL's grammar accepts
160
- * all keywords in qualified name positions.
161
- *
162
- * Return a name of the form qualifier.ident, or just ident if qualifier
163
- * is null/undefined, quoting each component if necessary.
164
- */
165
- static quoteQualifiedIdentifier(qualifier, ident) {
166
- if (qualifier) {
167
- return `${QuoteUtils.quoteIdentifier(qualifier)}.${QuoteUtils.quoteIdentifierAfterDot(ident)}`;
168
- }
169
- return QuoteUtils.quoteIdentifier(ident);
170
- }
171
- /**
172
- * Quote an identifier that appears as a type name.
173
- *
174
- * Type names in PostgreSQL have a less strict quoting policy than standalone identifiers.
175
- * In type positions, COL_NAME_KEYWORD and TYPE_FUNC_NAME_KEYWORD are allowed unquoted
176
- * (e.g., 'json', 'int', 'boolean', 'interval'). Only RESERVED_KEYWORD must be quoted.
177
- *
178
- * This is different from:
179
- * - quoteIdentifier(): quotes all keywords except UNRESERVED_KEYWORD
180
- * - quoteIdentifierAfterDot(): only quotes for lexical reasons (no keyword checking)
181
- *
182
- * Type names still need quoting for lexical reasons (uppercase, special chars, etc.).
183
- */
184
- static quoteIdentifierTypeName(ident) {
185
- if (!ident)
186
- return ident;
187
- let safe = true;
188
- // Check first character: must be lowercase letter or underscore
189
- const firstChar = ident[0];
190
- if (!((firstChar >= 'a' && firstChar <= 'z') || firstChar === '_')) {
191
- safe = false;
192
- }
193
- // Check all characters
194
- for (let i = 0; i < ident.length; i++) {
195
- const ch = ident[i];
196
- if ((ch >= 'a' && ch <= 'z') ||
197
- (ch >= '0' && ch <= '9') ||
198
- (ch === '_')) {
199
- // okay
200
- }
201
- else {
202
- safe = false;
203
- }
204
- }
205
- if (safe) {
206
- // For type names, only quote RESERVED_KEYWORD
207
- // COL_NAME_KEYWORD and TYPE_FUNC_NAME_KEYWORD are allowed unquoted in type positions
208
- const kwKind = keywordKindOf(ident);
209
- if (kwKind === 'RESERVED_KEYWORD') {
210
- safe = false;
211
- }
212
- }
213
- if (safe) {
214
- return ident; // no change needed
215
- }
216
- // Build quoted identifier with escaped embedded quotes
217
- let result = '"';
218
- for (let i = 0; i < ident.length; i++) {
219
- const ch = ident[i];
220
- if (ch === '"') {
221
- result += '"'; // escape " as ""
222
- }
223
- result += ch;
224
- }
225
- result += '"';
226
- return result;
227
- }
228
- /**
229
- * Quote a dotted type name (e.g., schema.typename).
230
- *
231
- * For type names, we use type-name quoting for all parts since the entire
232
- * qualified name is in a type context. This allows keywords like 'json',
233
- * 'int', 'boolean' to remain unquoted in user-defined schema-qualified types.
234
- */
235
- static quoteTypeDottedName(parts) {
236
- if (!parts || parts.length === 0)
237
- return '';
238
- return parts.map(part => QuoteUtils.quoteIdentifierTypeName(part)).join('.');
239
- }
240
- }
package/kwlist.d.ts DELETED
@@ -1,16 +0,0 @@
1
- /**
2
- * Generated from PostgreSQL kwlist.h
3
- * DO NOT EDIT BY HAND.
4
- */
5
- export type KeywordKind = "NO_KEYWORD" | "UNRESERVED_KEYWORD" | "COL_NAME_KEYWORD" | "TYPE_FUNC_NAME_KEYWORD" | "RESERVED_KEYWORD";
6
- export declare const kwlist: {
7
- readonly UNRESERVED_KEYWORD: readonly ["abort", "absent", "absolute", "access", "action", "add", "admin", "after", "aggregate", "also", "alter", "always", "asensitive", "assertion", "assignment", "at", "atomic", "attach", "attribute", "backward", "before", "begin", "breadth", "by", "cache", "call", "called", "cascade", "cascaded", "catalog", "chain", "characteristics", "checkpoint", "class", "close", "cluster", "columns", "comment", "comments", "commit", "committed", "compression", "conditional", "configuration", "conflict", "connection", "constraints", "content", "continue", "conversion", "copy", "cost", "csv", "cube", "current", "cursor", "cycle", "data", "database", "day", "deallocate", "declare", "defaults", "deferred", "definer", "delete", "delimiter", "delimiters", "depends", "depth", "detach", "dictionary", "disable", "discard", "document", "domain", "double", "drop", "each", "empty", "enable", "encoding", "encrypted", "enforced", "enum", "error", "escape", "event", "exclude", "excluding", "exclusive", "execute", "explain", "expression", "extension", "external", "family", "filter", "finalize", "first", "following", "force", "format", "forward", "function", "functions", "generated", "global", "granted", "groups", "handler", "header", "hold", "hour", "identity", "if", "ignore", "immediate", "immutable", "implicit", "import", "include", "including", "increment", "indent", "index", "indexes", "inherit", "inherits", "inline", "input", "insensitive", "insert", "instead", "invoker", "isolation", "keep", "key", "keys", "label", "language", "large", "last", "leakproof", "level", "listen", "load", "local", "location", "lock", "locked", "logged", "lsn", "mapping", "match", "matched", "materialized", "maxvalue", "merge", "method", "minute", "minvalue", "mode", "month", "move", "name", "names", "nested", "new", "next", "nfc", "nfd", "nfkc", "nfkd", "no", "normalized", "nothing", "notify", "nowait", "nulls", "object", "objects", "of", "off", "oids", "old", "omit", "operator", "option", "options", "ordinality", "others", "over", "overriding", "owned", "owner", "parallel", "parameter", "parser", "partial", "partition", "partitions", "passing", "password", "path", "period", "plan", "plans", "policy", "preceding", "prepare", "prepared", "preserve", "prior", "privileges", "procedural", "procedure", "procedures", "program", "publication", "quote", "quotes", "range", "read", "reassign", "recursive", "ref", "referencing", "refresh", "reindex", "relative", "release", "rename", "repeatable", "replace", "replica", "reset", "respect", "restart", "restrict", "return", "returns", "revoke", "role", "rollback", "rollup", "routine", "routines", "rows", "rule", "savepoint", "scalar", "schema", "schemas", "scroll", "search", "second", "security", "sequence", "sequences", "serializable", "server", "session", "set", "sets", "share", "show", "simple", "skip", "snapshot", "source", "split", "sql", "stable", "standalone", "start", "statement", "statistics", "stdin", "stdout", "storage", "stored", "strict", "string", "strip", "subscription", "support", "sysid", "system", "tables", "tablespace", "target", "temp", "template", "temporary", "text", "ties", "transaction", "transform", "trigger", "truncate", "trusted", "type", "types", "uescape", "unbounded", "uncommitted", "unconditional", "unencrypted", "unknown", "unlisten", "unlogged", "until", "update", "vacuum", "valid", "validate", "validator", "value", "varying", "version", "view", "views", "virtual", "volatile", "wait", "whitespace", "within", "without", "work", "wrapper", "write", "xml", "year", "yes", "zone"];
8
- readonly RESERVED_KEYWORD: readonly ["all", "analyse", "analyze", "and", "any", "array", "as", "asc", "asymmetric", "both", "case", "cast", "check", "collate", "column", "constraint", "create", "current_catalog", "current_date", "current_role", "current_time", "current_timestamp", "current_user", "default", "deferrable", "desc", "distinct", "do", "else", "end", "except", "false", "fetch", "for", "foreign", "from", "grant", "group", "having", "in", "initially", "intersect", "into", "lateral", "leading", "limit", "localtime", "localtimestamp", "not", "null", "offset", "on", "only", "or", "order", "placing", "primary", "references", "returning", "select", "session_user", "some", "symmetric", "system_user", "table", "then", "to", "trailing", "true", "union", "unique", "user", "using", "variadic", "when", "where", "window", "with"];
9
- readonly TYPE_FUNC_NAME_KEYWORD: readonly ["authorization", "binary", "collation", "concurrently", "cross", "current_schema", "freeze", "full", "ilike", "inner", "is", "isnull", "join", "left", "like", "natural", "notnull", "outer", "overlaps", "right", "similar", "tablesample", "verbose"];
10
- readonly COL_NAME_KEYWORD: readonly ["between", "bigint", "bit", "boolean", "char", "character", "coalesce", "dec", "decimal", "exists", "extract", "float", "greatest", "grouping", "inout", "int", "integer", "interval", "json", "json_array", "json_arrayagg", "json_exists", "json_object", "json_objectagg", "json_query", "json_scalar", "json_serialize", "json_table", "json_value", "least", "merge_action", "national", "nchar", "none", "normalize", "nullif", "numeric", "out", "overlay", "position", "precision", "real", "row", "setof", "smallint", "substring", "time", "timestamp", "treat", "trim", "values", "varchar", "xmlattributes", "xmlconcat", "xmlelement", "xmlexists", "xmlforest", "xmlnamespaces", "xmlparse", "xmlpi", "xmlroot", "xmlserialize", "xmltable"];
11
- };
12
- export declare const RESERVED_KEYWORDS: Set<string>;
13
- export declare const UNRESERVED_KEYWORDS: Set<string>;
14
- export declare const COL_NAME_KEYWORDS: Set<string>;
15
- export declare const TYPE_FUNC_NAME_KEYWORDS: Set<string>;
16
- export declare function keywordKindOf(word: string): KeywordKind;