relq 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli/commands/add.cjs +252 -12
- package/dist/cjs/cli/commands/commit.cjs +12 -1
- package/dist/cjs/cli/commands/export.cjs +25 -19
- package/dist/cjs/cli/commands/import.cjs +219 -100
- package/dist/cjs/cli/commands/init.cjs +86 -14
- package/dist/cjs/cli/commands/pull.cjs +104 -23
- package/dist/cjs/cli/commands/push.cjs +38 -3
- package/dist/cjs/cli/index.cjs +9 -1
- package/dist/cjs/cli/utils/ast/codegen/builder.cjs +297 -0
- package/dist/cjs/cli/utils/ast/codegen/constraints.cjs +185 -0
- package/dist/cjs/cli/utils/ast/codegen/defaults.cjs +311 -0
- package/dist/cjs/cli/utils/ast/codegen/index.cjs +24 -0
- package/dist/cjs/cli/utils/ast/codegen/type-map.cjs +116 -0
- package/dist/cjs/cli/utils/ast/codegen/utils.cjs +69 -0
- package/dist/cjs/cli/utils/ast/index.cjs +19 -0
- package/dist/cjs/cli/utils/ast/transformer/helpers.cjs +154 -0
- package/dist/cjs/cli/utils/ast/transformer/index.cjs +25 -0
- package/dist/cjs/cli/utils/ast/types.cjs +2 -0
- package/dist/cjs/cli/utils/ast-codegen.cjs +949 -0
- package/dist/cjs/cli/utils/ast-transformer.cjs +916 -0
- package/dist/cjs/cli/utils/change-tracker.cjs +50 -1
- package/dist/cjs/cli/utils/cli-utils.cjs +151 -0
- package/dist/cjs/cli/utils/fast-introspect.cjs +149 -23
- package/dist/cjs/cli/utils/pg-parser.cjs +1 -0
- package/dist/cjs/cli/utils/repo-manager.cjs +121 -4
- package/dist/cjs/cli/utils/schema-comparator.cjs +98 -14
- package/dist/cjs/cli/utils/schema-introspect.cjs +56 -19
- package/dist/cjs/cli/utils/snapshot-manager.cjs +0 -1
- package/dist/cjs/cli/utils/sql-generator.cjs +353 -64
- package/dist/cjs/cli/utils/type-generator.cjs +114 -15
- package/dist/cjs/core/relq-client.cjs +22 -6
- package/dist/cjs/schema-definition/column-types.cjs +150 -13
- package/dist/cjs/schema-definition/defaults.cjs +72 -0
- package/dist/cjs/schema-definition/index.cjs +15 -1
- package/dist/cjs/schema-definition/introspection.cjs +7 -3
- package/dist/cjs/schema-definition/pg-relations.cjs +169 -0
- package/dist/cjs/schema-definition/pg-view.cjs +30 -0
- package/dist/cjs/schema-definition/table-definition.cjs +110 -4
- package/dist/cjs/types/config-types.cjs +13 -4
- package/dist/cjs/utils/aws-dsql.cjs +177 -0
- package/dist/config.d.ts +146 -1
- package/dist/esm/cli/commands/add.js +250 -13
- package/dist/esm/cli/commands/commit.js +12 -1
- package/dist/esm/cli/commands/export.js +25 -19
- package/dist/esm/cli/commands/import.js +221 -102
- package/dist/esm/cli/commands/init.js +86 -14
- package/dist/esm/cli/commands/pull.js +106 -25
- package/dist/esm/cli/commands/push.js +39 -4
- package/dist/esm/cli/index.js +9 -1
- package/dist/esm/cli/utils/ast/codegen/builder.js +291 -0
- package/dist/esm/cli/utils/ast/codegen/constraints.js +176 -0
- package/dist/esm/cli/utils/ast/codegen/defaults.js +305 -0
- package/dist/esm/cli/utils/ast/codegen/index.js +6 -0
- package/dist/esm/cli/utils/ast/codegen/type-map.js +111 -0
- package/dist/esm/cli/utils/ast/codegen/utils.js +60 -0
- package/dist/esm/cli/utils/ast/index.js +3 -0
- package/dist/esm/cli/utils/ast/transformer/helpers.js +141 -0
- package/dist/esm/cli/utils/ast/transformer/index.js +2 -0
- package/dist/esm/cli/utils/ast/types.js +1 -0
- package/dist/esm/cli/utils/ast-codegen.js +945 -0
- package/dist/esm/cli/utils/ast-transformer.js +907 -0
- package/dist/esm/cli/utils/change-tracker.js +50 -1
- package/dist/esm/cli/utils/cli-utils.js +147 -0
- package/dist/esm/cli/utils/fast-introspect.js +149 -23
- package/dist/esm/cli/utils/pg-parser.js +1 -0
- package/dist/esm/cli/utils/repo-manager.js +114 -4
- package/dist/esm/cli/utils/schema-comparator.js +98 -14
- package/dist/esm/cli/utils/schema-introspect.js +56 -19
- package/dist/esm/cli/utils/snapshot-manager.js +0 -1
- package/dist/esm/cli/utils/sql-generator.js +353 -64
- package/dist/esm/cli/utils/type-generator.js +114 -15
- package/dist/esm/core/relq-client.js +23 -7
- package/dist/esm/schema-definition/column-types.js +147 -12
- package/dist/esm/schema-definition/defaults.js +69 -0
- package/dist/esm/schema-definition/index.js +3 -0
- package/dist/esm/schema-definition/introspection.js +7 -3
- package/dist/esm/schema-definition/pg-relations.js +161 -0
- package/dist/esm/schema-definition/pg-view.js +24 -0
- package/dist/esm/schema-definition/table-definition.js +110 -4
- package/dist/esm/types/config-types.js +12 -4
- package/dist/esm/utils/aws-dsql.js +139 -0
- package/dist/index.d.ts +159 -1
- package/dist/schema-builder.d.ts +1314 -32
- package/package.json +1 -1
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { escapeString } from "./utils.js";
|
|
2
|
+
let needsDefaultImport = false;
|
|
3
|
+
let needsSqlImport = false;
|
|
4
|
+
export function resetDefaultImportFlags() {
|
|
5
|
+
needsDefaultImport = false;
|
|
6
|
+
needsSqlImport = false;
|
|
7
|
+
}
|
|
8
|
+
export function getDefaultImportNeeded() {
|
|
9
|
+
return needsDefaultImport;
|
|
10
|
+
}
|
|
11
|
+
export function getDefaultSqlImportNeeded() {
|
|
12
|
+
return needsSqlImport;
|
|
13
|
+
}
|
|
14
|
+
export function formatDefaultValue(value, columnType) {
|
|
15
|
+
if (!value)
|
|
16
|
+
return "''";
|
|
17
|
+
const trimmed = value.trim();
|
|
18
|
+
const upper = trimmed.toUpperCase();
|
|
19
|
+
if (upper === 'TRUE')
|
|
20
|
+
return 'true';
|
|
21
|
+
if (upper === 'FALSE')
|
|
22
|
+
return 'false';
|
|
23
|
+
if (upper === 'NULL')
|
|
24
|
+
return 'null';
|
|
25
|
+
if (upper === 'GEN_RANDOM_UUID()' || upper.includes('GEN_RANDOM_UUID')) {
|
|
26
|
+
needsDefaultImport = true;
|
|
27
|
+
return 'DEFAULT.genRandomUuid()';
|
|
28
|
+
}
|
|
29
|
+
if (upper === 'UUID_GENERATE_V4()' || upper.includes('UUID_GENERATE_V4')) {
|
|
30
|
+
needsDefaultImport = true;
|
|
31
|
+
return 'DEFAULT.uuidGenerateV4()';
|
|
32
|
+
}
|
|
33
|
+
if (upper === 'UUID_GENERATE_V1()' || upper.includes('UUID_GENERATE_V1()')) {
|
|
34
|
+
needsDefaultImport = true;
|
|
35
|
+
return 'DEFAULT.uuidGenerateV1()';
|
|
36
|
+
}
|
|
37
|
+
if (upper === 'UUID_GENERATE_V1MC()') {
|
|
38
|
+
needsDefaultImport = true;
|
|
39
|
+
return 'DEFAULT.uuidGenerateV1mc()';
|
|
40
|
+
}
|
|
41
|
+
if (upper === 'UUID_NIL()') {
|
|
42
|
+
needsDefaultImport = true;
|
|
43
|
+
return 'DEFAULT.uuidNil()';
|
|
44
|
+
}
|
|
45
|
+
if (upper === 'NOW()' || upper === 'NOW') {
|
|
46
|
+
needsDefaultImport = true;
|
|
47
|
+
return 'DEFAULT.now()';
|
|
48
|
+
}
|
|
49
|
+
if (upper === 'CURRENT_TIMESTAMP' || upper === 'CURRENT_TIMESTAMP()') {
|
|
50
|
+
needsDefaultImport = true;
|
|
51
|
+
return 'DEFAULT.currentTimestamp()';
|
|
52
|
+
}
|
|
53
|
+
if (upper === 'CURRENT_DATE' || upper === 'CURRENT_DATE()') {
|
|
54
|
+
needsDefaultImport = true;
|
|
55
|
+
return 'DEFAULT.currentDate()';
|
|
56
|
+
}
|
|
57
|
+
if (upper === 'CURRENT_TIME' || upper === 'CURRENT_TIME()') {
|
|
58
|
+
needsDefaultImport = true;
|
|
59
|
+
return 'DEFAULT.currentTime()';
|
|
60
|
+
}
|
|
61
|
+
if (upper === 'LOCALTIMESTAMP' || upper === 'LOCALTIMESTAMP()') {
|
|
62
|
+
needsDefaultImport = true;
|
|
63
|
+
return 'DEFAULT.localTimestamp()';
|
|
64
|
+
}
|
|
65
|
+
if (upper === 'LOCALTIME' || upper === 'LOCALTIME()') {
|
|
66
|
+
needsDefaultImport = true;
|
|
67
|
+
return 'DEFAULT.localTime()';
|
|
68
|
+
}
|
|
69
|
+
if (upper === 'TRANSACTION_TIMESTAMP()') {
|
|
70
|
+
needsDefaultImport = true;
|
|
71
|
+
return 'DEFAULT.transactionTimestamp()';
|
|
72
|
+
}
|
|
73
|
+
if (upper === 'STATEMENT_TIMESTAMP()') {
|
|
74
|
+
needsDefaultImport = true;
|
|
75
|
+
return 'DEFAULT.statementTimestamp()';
|
|
76
|
+
}
|
|
77
|
+
if (upper === 'CLOCK_TIMESTAMP()') {
|
|
78
|
+
needsDefaultImport = true;
|
|
79
|
+
return 'DEFAULT.clockTimestamp()';
|
|
80
|
+
}
|
|
81
|
+
if (upper === 'TIMEOFDAY()') {
|
|
82
|
+
needsDefaultImport = true;
|
|
83
|
+
return 'DEFAULT.timeofday()';
|
|
84
|
+
}
|
|
85
|
+
const intervalMatch = trimmed.match(/^'([^']+)'::interval$/i);
|
|
86
|
+
if (intervalMatch) {
|
|
87
|
+
needsDefaultImport = true;
|
|
88
|
+
return `DEFAULT.interval('${intervalMatch[1]}')`;
|
|
89
|
+
}
|
|
90
|
+
if (upper === 'CURRENT_USER' || upper === 'CURRENT_USER()') {
|
|
91
|
+
needsDefaultImport = true;
|
|
92
|
+
return 'DEFAULT.currentUser()';
|
|
93
|
+
}
|
|
94
|
+
if (upper === 'SESSION_USER' || upper === 'SESSION_USER()') {
|
|
95
|
+
needsDefaultImport = true;
|
|
96
|
+
return 'DEFAULT.sessionUser()';
|
|
97
|
+
}
|
|
98
|
+
if (upper === 'USER' || upper === 'USER()') {
|
|
99
|
+
needsDefaultImport = true;
|
|
100
|
+
return 'DEFAULT.user()';
|
|
101
|
+
}
|
|
102
|
+
if (upper === 'CURRENT_SCHEMA()' || upper === 'CURRENT_SCHEMA') {
|
|
103
|
+
needsDefaultImport = true;
|
|
104
|
+
return 'DEFAULT.currentSchema()';
|
|
105
|
+
}
|
|
106
|
+
if (upper === 'CURRENT_DATABASE()') {
|
|
107
|
+
needsDefaultImport = true;
|
|
108
|
+
return 'DEFAULT.currentDatabase()';
|
|
109
|
+
}
|
|
110
|
+
if (upper === 'CURRENT_CATALOG' || upper === 'CURRENT_CATALOG()') {
|
|
111
|
+
needsDefaultImport = true;
|
|
112
|
+
return 'DEFAULT.currentCatalog()';
|
|
113
|
+
}
|
|
114
|
+
if (upper === 'INET_CLIENT_ADDR()') {
|
|
115
|
+
needsDefaultImport = true;
|
|
116
|
+
return 'DEFAULT.inetClientAddr()';
|
|
117
|
+
}
|
|
118
|
+
if (upper === 'INET_SERVER_ADDR()') {
|
|
119
|
+
needsDefaultImport = true;
|
|
120
|
+
return 'DEFAULT.inetServerAddr()';
|
|
121
|
+
}
|
|
122
|
+
if (upper === 'PG_BACKEND_PID()') {
|
|
123
|
+
needsDefaultImport = true;
|
|
124
|
+
return 'DEFAULT.pgBackendPid()';
|
|
125
|
+
}
|
|
126
|
+
const nextvalMatch = trimmed.match(/^nextval\('([^']+)'(?:::regclass)?\)$/i);
|
|
127
|
+
if (nextvalMatch) {
|
|
128
|
+
needsDefaultImport = true;
|
|
129
|
+
return `DEFAULT.nextval('${nextvalMatch[1]}')`;
|
|
130
|
+
}
|
|
131
|
+
const currvalMatch = trimmed.match(/^currval\('([^']+)'(?:::regclass)?\)$/i);
|
|
132
|
+
if (currvalMatch) {
|
|
133
|
+
needsDefaultImport = true;
|
|
134
|
+
return `DEFAULT.currval('${currvalMatch[1]}')`;
|
|
135
|
+
}
|
|
136
|
+
if (upper === 'LASTVAL()') {
|
|
137
|
+
needsDefaultImport = true;
|
|
138
|
+
return 'DEFAULT.lastval()';
|
|
139
|
+
}
|
|
140
|
+
if (upper === 'RANDOM()') {
|
|
141
|
+
needsDefaultImport = true;
|
|
142
|
+
return 'DEFAULT.random()';
|
|
143
|
+
}
|
|
144
|
+
if (upper === 'PI()') {
|
|
145
|
+
needsDefaultImport = true;
|
|
146
|
+
return 'DEFAULT.pi()';
|
|
147
|
+
}
|
|
148
|
+
if (trimmed === "''" || trimmed === '""') {
|
|
149
|
+
needsDefaultImport = true;
|
|
150
|
+
return 'DEFAULT.emptyString()';
|
|
151
|
+
}
|
|
152
|
+
if (trimmed === "'{}'::jsonb" || upper === "'{}'::JSONB") {
|
|
153
|
+
needsDefaultImport = true;
|
|
154
|
+
return 'DEFAULT.emptyJsonb()';
|
|
155
|
+
}
|
|
156
|
+
if (trimmed === "'{}'::json" || upper === "'{}'::JSON") {
|
|
157
|
+
needsDefaultImport = true;
|
|
158
|
+
return 'DEFAULT.emptyJson()';
|
|
159
|
+
}
|
|
160
|
+
if (trimmed === "'{}'" || trimmed === "'{}'") {
|
|
161
|
+
needsDefaultImport = true;
|
|
162
|
+
return 'DEFAULT.emptyObject()';
|
|
163
|
+
}
|
|
164
|
+
if (trimmed === "'[]'::jsonb" || upper === "'[]'::JSONB" || trimmed === "'[]'::json" || upper === "'[]'::JSON") {
|
|
165
|
+
needsDefaultImport = true;
|
|
166
|
+
return 'DEFAULT.emptyArray()';
|
|
167
|
+
}
|
|
168
|
+
const emptyArrayMatch = trimmed.match(/^ARRAY\[\]::(\w+)\[\]$/i);
|
|
169
|
+
if (emptyArrayMatch) {
|
|
170
|
+
needsDefaultImport = true;
|
|
171
|
+
return 'DEFAULT.emptyArray()';
|
|
172
|
+
}
|
|
173
|
+
const emptyArrayLiteralMatch = trimmed.match(/^'\{\}'::(\w+)\[\]$/i);
|
|
174
|
+
if (emptyArrayLiteralMatch) {
|
|
175
|
+
needsDefaultImport = true;
|
|
176
|
+
return 'DEFAULT.emptyArray()';
|
|
177
|
+
}
|
|
178
|
+
if (upper === "'EMPTY'::INT4RANGE") {
|
|
179
|
+
needsDefaultImport = true;
|
|
180
|
+
return 'DEFAULT.emptyInt4range()';
|
|
181
|
+
}
|
|
182
|
+
if (upper === "'EMPTY'::INT8RANGE") {
|
|
183
|
+
needsDefaultImport = true;
|
|
184
|
+
return 'DEFAULT.emptyInt8range()';
|
|
185
|
+
}
|
|
186
|
+
if (upper === "'EMPTY'::NUMRANGE") {
|
|
187
|
+
needsDefaultImport = true;
|
|
188
|
+
return 'DEFAULT.emptyNumrange()';
|
|
189
|
+
}
|
|
190
|
+
if (upper === "'EMPTY'::TSRANGE") {
|
|
191
|
+
needsDefaultImport = true;
|
|
192
|
+
return 'DEFAULT.emptyTsrange()';
|
|
193
|
+
}
|
|
194
|
+
if (upper === "'EMPTY'::TSTZRANGE") {
|
|
195
|
+
needsDefaultImport = true;
|
|
196
|
+
return 'DEFAULT.emptyTstzrange()';
|
|
197
|
+
}
|
|
198
|
+
if (upper === "'EMPTY'::DATERANGE") {
|
|
199
|
+
needsDefaultImport = true;
|
|
200
|
+
return 'DEFAULT.emptyDaterange()';
|
|
201
|
+
}
|
|
202
|
+
if (upper === "''::TSVECTOR") {
|
|
203
|
+
needsDefaultImport = true;
|
|
204
|
+
return 'DEFAULT.emptyTsvector()';
|
|
205
|
+
}
|
|
206
|
+
if (upper === "''::HSTORE") {
|
|
207
|
+
needsDefaultImport = true;
|
|
208
|
+
return 'DEFAULT.emptyHstore()';
|
|
209
|
+
}
|
|
210
|
+
if (trimmed === "'\\x'::bytea" || upper === "'\\X'::BYTEA") {
|
|
211
|
+
needsDefaultImport = true;
|
|
212
|
+
return 'DEFAULT.emptyBytea()';
|
|
213
|
+
}
|
|
214
|
+
const moneyMatch = trimmed.match(/^'([^']+)'::money$/i);
|
|
215
|
+
if (moneyMatch) {
|
|
216
|
+
needsDefaultImport = true;
|
|
217
|
+
if (moneyMatch[1] === '0' || moneyMatch[1] === '0.00') {
|
|
218
|
+
return 'DEFAULT.zeroMoney()';
|
|
219
|
+
}
|
|
220
|
+
return `DEFAULT.money('${moneyMatch[1]}')`;
|
|
221
|
+
}
|
|
222
|
+
const inetMatch = trimmed.match(/^'([^']+)'::inet$/i);
|
|
223
|
+
if (inetMatch) {
|
|
224
|
+
needsDefaultImport = true;
|
|
225
|
+
return `DEFAULT.inet('${inetMatch[1]}')`;
|
|
226
|
+
}
|
|
227
|
+
const cidrMatch = trimmed.match(/^'([^']+)'::cidr$/i);
|
|
228
|
+
if (cidrMatch) {
|
|
229
|
+
needsDefaultImport = true;
|
|
230
|
+
return `DEFAULT.cidr('${cidrMatch[1]}')`;
|
|
231
|
+
}
|
|
232
|
+
const macaddrMatch = trimmed.match(/^'([^']+)'::macaddr$/i);
|
|
233
|
+
if (macaddrMatch) {
|
|
234
|
+
needsDefaultImport = true;
|
|
235
|
+
return `DEFAULT.macaddr('${macaddrMatch[1]}')`;
|
|
236
|
+
}
|
|
237
|
+
const pointMatch = trimmed.match(/^point\(([^,]+),\s*([^)]+)\)$/i);
|
|
238
|
+
if (pointMatch) {
|
|
239
|
+
needsDefaultImport = true;
|
|
240
|
+
return `DEFAULT.point(${pointMatch[1]}, ${pointMatch[2]})`;
|
|
241
|
+
}
|
|
242
|
+
const castMatch = trimmed.match(/^'([^']*)'::(.+)$/i);
|
|
243
|
+
if (castMatch) {
|
|
244
|
+
const castValue = castMatch[1];
|
|
245
|
+
const castType = castMatch[2].toLowerCase().trim();
|
|
246
|
+
if ((castType === 'jsonb' || castType === 'json') && castValue.startsWith('[')) {
|
|
247
|
+
try {
|
|
248
|
+
const parsed = JSON.parse(castValue);
|
|
249
|
+
return JSON.stringify(parsed);
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if ((castType === 'jsonb' || castType === 'json') && castValue.startsWith('{')) {
|
|
255
|
+
try {
|
|
256
|
+
const parsed = JSON.parse(castValue);
|
|
257
|
+
return JSON.stringify(parsed);
|
|
258
|
+
}
|
|
259
|
+
catch {
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
if (['varchar', 'text', 'char', 'bpchar', 'character', 'character varying'].includes(castType)) {
|
|
263
|
+
return `'${castValue.replace(/'/g, "\\'")}'`;
|
|
264
|
+
}
|
|
265
|
+
if (['int', 'int2', 'int4', 'int8', 'integer', 'smallint', 'bigint'].includes(castType)) {
|
|
266
|
+
const num = parseInt(castValue, 10);
|
|
267
|
+
if (!isNaN(num)) {
|
|
268
|
+
if (castType === 'int8' || castType === 'bigint') {
|
|
269
|
+
return `${num}n`;
|
|
270
|
+
}
|
|
271
|
+
return String(num);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
if (castType === 'boolean' || castType === 'bool') {
|
|
275
|
+
return castValue.toLowerCase() === 'true' ? 'true' : 'false';
|
|
276
|
+
}
|
|
277
|
+
if (['numeric', 'decimal', 'real', 'float', 'float4', 'float8', 'double precision'].includes(castType)) {
|
|
278
|
+
const num = parseFloat(castValue);
|
|
279
|
+
if (!isNaN(num)) {
|
|
280
|
+
return String(num);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return `'${castValue.replace(/'/g, "\\'")}'`;
|
|
284
|
+
}
|
|
285
|
+
const normalizedColType = columnType?.toLowerCase().trim();
|
|
286
|
+
const isBigintColumn = normalizedColType === 'int8' || normalizedColType === 'bigint';
|
|
287
|
+
if (/^-?\d+$/.test(trimmed)) {
|
|
288
|
+
if (isBigintColumn) {
|
|
289
|
+
return `${trimmed}n`;
|
|
290
|
+
}
|
|
291
|
+
return trimmed;
|
|
292
|
+
}
|
|
293
|
+
if (/^-?\d+\.\d+$/.test(trimmed)) {
|
|
294
|
+
return trimmed;
|
|
295
|
+
}
|
|
296
|
+
if (trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
297
|
+
const inner = trimmed.slice(1, -1);
|
|
298
|
+
return `'${inner.replace(/'/g, "\\'")}'`;
|
|
299
|
+
}
|
|
300
|
+
if (/^CAST\s*\(\s*(?:'?\{\}'?|ARRAY\s*\[\s*\])\s+AS\s+\w+\s*\[\s*\]\s*\)$/i.test(trimmed)) {
|
|
301
|
+
return '[]';
|
|
302
|
+
}
|
|
303
|
+
needsSqlImport = true;
|
|
304
|
+
return `sql\`${escapeString(trimmed)}\``;
|
|
305
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
export const TYPE_MAP = {
|
|
2
|
+
'int2': 'smallint',
|
|
3
|
+
'int4': 'integer',
|
|
4
|
+
'int8': 'bigint',
|
|
5
|
+
'smallint': 'smallint',
|
|
6
|
+
'integer': 'integer',
|
|
7
|
+
'bigint': 'bigint',
|
|
8
|
+
'serial': 'serial',
|
|
9
|
+
'smallserial': 'smallserial',
|
|
10
|
+
'bigserial': 'bigserial',
|
|
11
|
+
'float4': 'real',
|
|
12
|
+
'float8': 'doublePrecision',
|
|
13
|
+
'real': 'real',
|
|
14
|
+
'double precision': 'doublePrecision',
|
|
15
|
+
'numeric': 'numeric',
|
|
16
|
+
'decimal': 'numeric',
|
|
17
|
+
'money': 'money',
|
|
18
|
+
'text': 'text',
|
|
19
|
+
'varchar': 'varchar',
|
|
20
|
+
'character varying': 'varchar',
|
|
21
|
+
'char': 'char',
|
|
22
|
+
'character': 'char',
|
|
23
|
+
'bpchar': 'char',
|
|
24
|
+
'citext': 'citext',
|
|
25
|
+
'name': 'name',
|
|
26
|
+
'bytea': 'bytea',
|
|
27
|
+
'bool': 'boolean',
|
|
28
|
+
'boolean': 'boolean',
|
|
29
|
+
'date': 'date',
|
|
30
|
+
'time': 'time',
|
|
31
|
+
'timetz': 'timetz',
|
|
32
|
+
'timestamp': 'timestamp',
|
|
33
|
+
'timestamptz': 'timestamptz',
|
|
34
|
+
'interval': 'interval',
|
|
35
|
+
'uuid': 'uuid',
|
|
36
|
+
'json': 'json',
|
|
37
|
+
'jsonb': 'jsonb',
|
|
38
|
+
'inet': 'inet',
|
|
39
|
+
'cidr': 'cidr',
|
|
40
|
+
'macaddr': 'macaddr',
|
|
41
|
+
'macaddr8': 'macaddr8',
|
|
42
|
+
'point': 'point',
|
|
43
|
+
'line': 'line',
|
|
44
|
+
'lseg': 'lseg',
|
|
45
|
+
'box': 'box',
|
|
46
|
+
'path': 'path',
|
|
47
|
+
'polygon': 'polygon',
|
|
48
|
+
'circle': 'circle',
|
|
49
|
+
'int4range': 'int4range',
|
|
50
|
+
'int8range': 'int8range',
|
|
51
|
+
'numrange': 'numrange',
|
|
52
|
+
'tsrange': 'tsrange',
|
|
53
|
+
'tstzrange': 'tstzrange',
|
|
54
|
+
'daterange': 'daterange',
|
|
55
|
+
'tsvector': 'tsvector',
|
|
56
|
+
'tsquery': 'tsquery',
|
|
57
|
+
'xml': 'xml',
|
|
58
|
+
'bit': 'bit',
|
|
59
|
+
'varbit': 'varbit',
|
|
60
|
+
'ltree': 'ltree',
|
|
61
|
+
'cube': 'cube',
|
|
62
|
+
'hstore': 'hstore',
|
|
63
|
+
};
|
|
64
|
+
export function getColumnBuilder(type, params) {
|
|
65
|
+
const result = getColumnBuilderWithInfo(type, params);
|
|
66
|
+
if (result.length != null) {
|
|
67
|
+
return `${result.builderName}(${result.length})`;
|
|
68
|
+
}
|
|
69
|
+
return result.builder;
|
|
70
|
+
}
|
|
71
|
+
export function getColumnBuilderWithInfo(type, params) {
|
|
72
|
+
const normalizedType = type.toLowerCase().trim();
|
|
73
|
+
const builderName = TYPE_MAP[normalizedType] || 'text';
|
|
74
|
+
let builder = `${builderName}()`;
|
|
75
|
+
let length;
|
|
76
|
+
if (params) {
|
|
77
|
+
if ((builderName === 'varchar' || builderName === 'char') && params.length) {
|
|
78
|
+
length = params.length;
|
|
79
|
+
}
|
|
80
|
+
else if (builderName === 'numeric' && params.precision != null) {
|
|
81
|
+
if (params.scale != null && params.scale > 0) {
|
|
82
|
+
builder = `numeric(${params.precision}, ${params.scale})`;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
builder = `numeric(${params.precision})`;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else if (builderName === 'bit' && params.length) {
|
|
89
|
+
builder = `bit(${params.length})`;
|
|
90
|
+
}
|
|
91
|
+
else if (builderName === 'varbit' && params.length) {
|
|
92
|
+
builder = `varbit(${params.length})`;
|
|
93
|
+
}
|
|
94
|
+
else if (builderName === 'time' && params.precision != null) {
|
|
95
|
+
builder = `time(${params.precision})`;
|
|
96
|
+
}
|
|
97
|
+
else if (builderName === 'timetz' && params.precision != null) {
|
|
98
|
+
builder = `timetz(${params.precision})`;
|
|
99
|
+
}
|
|
100
|
+
else if (builderName === 'timestamp' && params.precision != null) {
|
|
101
|
+
builder = `timestamp(${params.precision})`;
|
|
102
|
+
}
|
|
103
|
+
else if (builderName === 'timestamptz' && params.precision != null) {
|
|
104
|
+
builder = `timestamptz(${params.precision})`;
|
|
105
|
+
}
|
|
106
|
+
else if (builderName === 'interval' && params.precision != null) {
|
|
107
|
+
builder = `interval(${params.precision})`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return { builder, builderName, length };
|
|
111
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export function toCamelCase(str) {
|
|
2
|
+
if (!str)
|
|
3
|
+
return 'unknown';
|
|
4
|
+
const cleaned = str.replace(/^[_0-9]+/, '');
|
|
5
|
+
return cleaned
|
|
6
|
+
.split('_')
|
|
7
|
+
.map((word, i) => i === 0 ? word.toLowerCase() : word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
8
|
+
.join('');
|
|
9
|
+
}
|
|
10
|
+
export function toPascalCase(str) {
|
|
11
|
+
if (!str)
|
|
12
|
+
return 'Unknown';
|
|
13
|
+
const cleaned = str.replace(/^[_0-9]+/, '');
|
|
14
|
+
return cleaned
|
|
15
|
+
.split('_')
|
|
16
|
+
.map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
17
|
+
.join('');
|
|
18
|
+
}
|
|
19
|
+
export function escapeString(str) {
|
|
20
|
+
return str.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
|
|
21
|
+
}
|
|
22
|
+
export function escapeJsDocString(str) {
|
|
23
|
+
return str.replace(/\*\//g, '*\\/').replace(/\n/g, '\n * ');
|
|
24
|
+
}
|
|
25
|
+
export function pluralize(word) {
|
|
26
|
+
if (!word)
|
|
27
|
+
return word;
|
|
28
|
+
if (word.endsWith('s') || word.endsWith('x') || word.endsWith('z') ||
|
|
29
|
+
word.endsWith('ch') || word.endsWith('sh')) {
|
|
30
|
+
return word + 'es';
|
|
31
|
+
}
|
|
32
|
+
if (word.endsWith('y') && !['a', 'e', 'i', 'o', 'u'].includes(word[word.length - 2])) {
|
|
33
|
+
return word.slice(0, -1) + 'ies';
|
|
34
|
+
}
|
|
35
|
+
return word + 's';
|
|
36
|
+
}
|
|
37
|
+
export function isBalanced(str) {
|
|
38
|
+
let count = 0;
|
|
39
|
+
for (const char of str) {
|
|
40
|
+
if (char === '(')
|
|
41
|
+
count++;
|
|
42
|
+
if (char === ')')
|
|
43
|
+
count--;
|
|
44
|
+
if (count < 0)
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return count === 0;
|
|
48
|
+
}
|
|
49
|
+
export function getComparisonMethod(op) {
|
|
50
|
+
switch (op) {
|
|
51
|
+
case '>': return 'gt';
|
|
52
|
+
case '>=': return 'gte';
|
|
53
|
+
case '<': return 'lt';
|
|
54
|
+
case '<=': return 'lte';
|
|
55
|
+
case '=': return 'eq';
|
|
56
|
+
case '<>':
|
|
57
|
+
case '!=': return 'neq';
|
|
58
|
+
default: return 'eq';
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { deparse } from 'pgsql-deparser';
|
|
2
|
+
export function extractTypeName(typeName) {
|
|
3
|
+
if (!typeName)
|
|
4
|
+
return { name: 'text', isArray: false };
|
|
5
|
+
const names = typeName.names?.map((n) => n.String?.sval).filter(Boolean) || [];
|
|
6
|
+
let name = names.length > 1 ? names[names.length - 1] : names[0] || 'text';
|
|
7
|
+
if (names[0] === 'pg_catalog') {
|
|
8
|
+
name = names[1] || 'text';
|
|
9
|
+
}
|
|
10
|
+
const isArray = (typeName.arrayBounds?.length ?? 0) > 0;
|
|
11
|
+
const arrayDims = typeName.arrayBounds?.length;
|
|
12
|
+
let params;
|
|
13
|
+
if (typeName.typmods && typeName.typmods.length > 0) {
|
|
14
|
+
const mods = typeName.typmods.map((m) => {
|
|
15
|
+
if (m.A_Const?.ival?.ival !== undefined)
|
|
16
|
+
return m.A_Const.ival.ival;
|
|
17
|
+
if (m.A_Const?.sval?.sval !== undefined)
|
|
18
|
+
return m.A_Const.sval.sval;
|
|
19
|
+
return undefined;
|
|
20
|
+
}).filter((v) => v !== undefined);
|
|
21
|
+
if (mods.length === 1) {
|
|
22
|
+
if (['varchar', 'character varying', 'char', 'character', 'bit', 'varbit'].includes(name.toLowerCase())) {
|
|
23
|
+
params = { length: mods[0] };
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
params = { precision: mods[0] };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
else if (mods.length === 2) {
|
|
30
|
+
params = { precision: mods[0], scale: mods[1] };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { name, params, isArray, arrayDims };
|
|
34
|
+
}
|
|
35
|
+
export function extractConstraintType(contype) {
|
|
36
|
+
const types = {
|
|
37
|
+
0: 'NULL',
|
|
38
|
+
1: 'NOT NULL',
|
|
39
|
+
2: 'DEFAULT',
|
|
40
|
+
3: 'IDENTITY',
|
|
41
|
+
4: 'GENERATED',
|
|
42
|
+
5: 'CHECK',
|
|
43
|
+
6: 'PRIMARY KEY',
|
|
44
|
+
7: 'UNIQUE',
|
|
45
|
+
8: 'EXCLUSION',
|
|
46
|
+
9: 'FOREIGN KEY',
|
|
47
|
+
};
|
|
48
|
+
return types[contype] || 'UNKNOWN';
|
|
49
|
+
}
|
|
50
|
+
export function extractFkAction(action) {
|
|
51
|
+
if (!action)
|
|
52
|
+
return undefined;
|
|
53
|
+
const actions = {
|
|
54
|
+
'a': 'NO ACTION',
|
|
55
|
+
'r': 'RESTRICT',
|
|
56
|
+
'c': 'CASCADE',
|
|
57
|
+
'n': 'SET NULL',
|
|
58
|
+
'd': 'SET DEFAULT',
|
|
59
|
+
};
|
|
60
|
+
return actions[action];
|
|
61
|
+
}
|
|
62
|
+
export function extractFkMatch(matchType) {
|
|
63
|
+
if (!matchType)
|
|
64
|
+
return undefined;
|
|
65
|
+
const matches = {
|
|
66
|
+
's': 'SIMPLE',
|
|
67
|
+
'f': 'FULL',
|
|
68
|
+
};
|
|
69
|
+
return matches[matchType];
|
|
70
|
+
}
|
|
71
|
+
export async function deparseNode(node) {
|
|
72
|
+
try {
|
|
73
|
+
const result = await deparse([node]);
|
|
74
|
+
return result.trim();
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return '';
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export function normalizeTypeName(dataType, udtName) {
|
|
81
|
+
if (dataType === 'ARRAY' && udtName) {
|
|
82
|
+
const baseType = udtName.replace(/^_/, '');
|
|
83
|
+
return baseType;
|
|
84
|
+
}
|
|
85
|
+
const typeMap = {
|
|
86
|
+
'integer': 'int4',
|
|
87
|
+
'smallint': 'int2',
|
|
88
|
+
'bigint': 'int8',
|
|
89
|
+
'real': 'float4',
|
|
90
|
+
'double precision': 'float8',
|
|
91
|
+
'character varying': 'varchar',
|
|
92
|
+
'character': 'char',
|
|
93
|
+
'boolean': 'bool',
|
|
94
|
+
'timestamp without time zone': 'timestamp',
|
|
95
|
+
'timestamp with time zone': 'timestamptz',
|
|
96
|
+
'time without time zone': 'time',
|
|
97
|
+
'time with time zone': 'timetz',
|
|
98
|
+
};
|
|
99
|
+
const lower = dataType.toLowerCase();
|
|
100
|
+
return typeMap[lower] || udtName || lower;
|
|
101
|
+
}
|
|
102
|
+
export function extractTypeParams(col) {
|
|
103
|
+
if (col.characterMaxLength) {
|
|
104
|
+
return { length: col.characterMaxLength };
|
|
105
|
+
}
|
|
106
|
+
if (col.numericPrecision != null) {
|
|
107
|
+
if (col.numericScale != null && col.numericScale > 0) {
|
|
108
|
+
return { precision: col.numericPrecision, scale: col.numericScale };
|
|
109
|
+
}
|
|
110
|
+
return { precision: col.numericPrecision };
|
|
111
|
+
}
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
export function extractColumnsFromDefinition(definition) {
|
|
115
|
+
const match = definition.match(/\(([^)]+)\)/);
|
|
116
|
+
if (!match)
|
|
117
|
+
return [];
|
|
118
|
+
return match[1].split(',').map(s => s.trim().replace(/"/g, ''));
|
|
119
|
+
}
|
|
120
|
+
export function extractCheckExpression(definition) {
|
|
121
|
+
const match = definition.match(/CHECK\s*\((.+)\)/is);
|
|
122
|
+
return match ? match[1].trim() : definition;
|
|
123
|
+
}
|
|
124
|
+
export function extractExcludeExpression(definition) {
|
|
125
|
+
const match = definition.match(/EXCLUDE\s+USING\s+\w+\s*\((.+)\)/is);
|
|
126
|
+
return match ? match[1].trim() : definition;
|
|
127
|
+
}
|
|
128
|
+
export function parseArgTypes(argTypes) {
|
|
129
|
+
if (!argTypes)
|
|
130
|
+
return [];
|
|
131
|
+
if (Array.isArray(argTypes)) {
|
|
132
|
+
return argTypes.map(t => ({ type: t }));
|
|
133
|
+
}
|
|
134
|
+
return argTypes.split(',').map(arg => {
|
|
135
|
+
const parts = arg.trim().split(/\s+/);
|
|
136
|
+
if (parts.length > 1) {
|
|
137
|
+
return { name: parts[0], type: parts.slice(1).join(' ') };
|
|
138
|
+
}
|
|
139
|
+
return { type: parts[0] };
|
|
140
|
+
}).filter(a => a.type);
|
|
141
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|