relq 1.0.24 → 1.0.26
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/commit.cjs +80 -0
- package/dist/cjs/cli/commands/import.cjs +1 -0
- package/dist/cjs/cli/commands/pull.cjs +8 -25
- package/dist/cjs/cli/commands/push.cjs +48 -8
- package/dist/cjs/cli/commands/rollback.cjs +205 -84
- package/dist/cjs/cli/commands/schema-ast.cjs +219 -0
- package/dist/cjs/cli/index.cjs +6 -0
- package/dist/cjs/cli/utils/ast-codegen.cjs +95 -3
- package/dist/cjs/cli/utils/ast-transformer.cjs +12 -0
- package/dist/cjs/cli/utils/change-tracker.cjs +135 -0
- package/dist/cjs/cli/utils/commit-manager.cjs +54 -0
- package/dist/cjs/cli/utils/migration-generator.cjs +319 -0
- package/dist/cjs/cli/utils/repo-manager.cjs +99 -3
- package/dist/cjs/cli/utils/schema-diff.cjs +390 -0
- package/dist/cjs/cli/utils/schema-hash.cjs +4 -0
- package/dist/cjs/cli/utils/schema-to-ast.cjs +477 -0
- package/dist/cjs/cli/utils/schema-validator.cjs +21 -1
- package/dist/cjs/schema-definition/column-types.cjs +63 -10
- package/dist/cjs/schema-definition/pg-enum.cjs +10 -0
- package/dist/cjs/schema-definition/pg-function.cjs +19 -0
- package/dist/cjs/schema-definition/pg-sequence.cjs +22 -1
- package/dist/cjs/schema-definition/pg-trigger.cjs +39 -0
- package/dist/cjs/schema-definition/pg-view.cjs +17 -0
- package/dist/cjs/schema-definition/sql-expressions.cjs +3 -0
- package/dist/cjs/schema-definition/table-definition.cjs +4 -0
- package/dist/config.d.ts +98 -0
- package/dist/esm/cli/commands/commit.js +83 -3
- package/dist/esm/cli/commands/import.js +1 -0
- package/dist/esm/cli/commands/pull.js +9 -26
- package/dist/esm/cli/commands/push.js +49 -9
- package/dist/esm/cli/commands/rollback.js +206 -85
- package/dist/esm/cli/commands/schema-ast.js +183 -0
- package/dist/esm/cli/index.js +6 -0
- package/dist/esm/cli/utils/ast-codegen.js +93 -3
- package/dist/esm/cli/utils/ast-transformer.js +12 -0
- package/dist/esm/cli/utils/change-tracker.js +134 -0
- package/dist/esm/cli/utils/commit-manager.js +51 -0
- package/dist/esm/cli/utils/migration-generator.js +318 -0
- package/dist/esm/cli/utils/repo-manager.js +96 -3
- package/dist/esm/cli/utils/schema-diff.js +389 -0
- package/dist/esm/cli/utils/schema-hash.js +4 -0
- package/dist/esm/cli/utils/schema-to-ast.js +447 -0
- package/dist/esm/cli/utils/schema-validator.js +21 -1
- package/dist/esm/schema-definition/column-types.js +63 -10
- package/dist/esm/schema-definition/pg-enum.js +10 -0
- package/dist/esm/schema-definition/pg-function.js +19 -0
- package/dist/esm/schema-definition/pg-sequence.js +22 -1
- package/dist/esm/schema-definition/pg-trigger.js +39 -0
- package/dist/esm/schema-definition/pg-view.js +17 -0
- package/dist/esm/schema-definition/sql-expressions.js +3 -0
- package/dist/esm/schema-definition/table-definition.js +4 -0
- package/dist/index.d.ts +98 -0
- package/dist/schema-builder.d.ts +223 -24
- package/package.json +1 -1
|
@@ -0,0 +1,477 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isTableDefinition = isTableDefinition;
|
|
4
|
+
exports.isEnumConfig = isEnumConfig;
|
|
5
|
+
exports.isDomainConfig = isDomainConfig;
|
|
6
|
+
exports.isCompositeConfig = isCompositeConfig;
|
|
7
|
+
exports.isSequenceConfig = isSequenceConfig;
|
|
8
|
+
exports.isViewConfig = isViewConfig;
|
|
9
|
+
exports.isMaterializedViewConfig = isMaterializedViewConfig;
|
|
10
|
+
exports.isFunctionConfig = isFunctionConfig;
|
|
11
|
+
exports.isTriggerConfig = isTriggerConfig;
|
|
12
|
+
exports.isExtensionsConfig = isExtensionsConfig;
|
|
13
|
+
exports.isRelationsConfig = isRelationsConfig;
|
|
14
|
+
exports.generateTrackingId = generateTrackingId;
|
|
15
|
+
exports.isValidTrackingId = isValidTrackingId;
|
|
16
|
+
exports.extractTrackingId = extractTrackingId;
|
|
17
|
+
exports.mapColumnTypeToPostgres = mapColumnTypeToPostgres;
|
|
18
|
+
exports.schemaToAST = schemaToAST;
|
|
19
|
+
exports.tableToAST = tableToAST;
|
|
20
|
+
exports.columnToAST = columnToAST;
|
|
21
|
+
exports.indexToAST = indexToAST;
|
|
22
|
+
exports.constraintToAST = constraintToAST;
|
|
23
|
+
exports.enumToAST = enumToAST;
|
|
24
|
+
exports.domainToAST = domainToAST;
|
|
25
|
+
exports.compositeToAST = compositeToAST;
|
|
26
|
+
exports.sequenceToAST = sequenceToAST;
|
|
27
|
+
exports.viewToAST = viewToAST;
|
|
28
|
+
exports.materializedViewToAST = materializedViewToAST;
|
|
29
|
+
exports.functionToAST = functionToAST;
|
|
30
|
+
exports.triggerToAST = triggerToAST;
|
|
31
|
+
function isTableDefinition(value) {
|
|
32
|
+
return value && typeof value === 'object' &&
|
|
33
|
+
typeof value.$name === 'string' &&
|
|
34
|
+
typeof value.$columns === 'object' &&
|
|
35
|
+
typeof value.toSQL === 'function';
|
|
36
|
+
}
|
|
37
|
+
function isEnumConfig(value) {
|
|
38
|
+
return value && typeof value === 'object' &&
|
|
39
|
+
typeof value.$enumName === 'string' &&
|
|
40
|
+
Array.isArray(value.$enumValues);
|
|
41
|
+
}
|
|
42
|
+
function isDomainConfig(value) {
|
|
43
|
+
return value && typeof value === 'object' &&
|
|
44
|
+
typeof value.$domainName === 'string' &&
|
|
45
|
+
typeof value.$baseType === 'string';
|
|
46
|
+
}
|
|
47
|
+
function isCompositeConfig(value) {
|
|
48
|
+
return value && typeof value === 'object' &&
|
|
49
|
+
typeof value.$typeName === 'string' &&
|
|
50
|
+
typeof value.$fields === 'object';
|
|
51
|
+
}
|
|
52
|
+
function isSequenceConfig(value) {
|
|
53
|
+
return value && typeof value === 'object' &&
|
|
54
|
+
value._type === 'sequence' &&
|
|
55
|
+
typeof value.name === 'string';
|
|
56
|
+
}
|
|
57
|
+
function isViewConfig(value) {
|
|
58
|
+
return value && typeof value === 'object' &&
|
|
59
|
+
value._type === 'view' &&
|
|
60
|
+
typeof value.name === 'string' &&
|
|
61
|
+
typeof value.definition === 'string';
|
|
62
|
+
}
|
|
63
|
+
function isMaterializedViewConfig(value) {
|
|
64
|
+
return value && typeof value === 'object' &&
|
|
65
|
+
value._type === 'materialized_view' &&
|
|
66
|
+
typeof value.name === 'string' &&
|
|
67
|
+
typeof value.definition === 'string';
|
|
68
|
+
}
|
|
69
|
+
function isFunctionConfig(value) {
|
|
70
|
+
return value && typeof value === 'object' &&
|
|
71
|
+
value.$type === 'function' &&
|
|
72
|
+
typeof value.$functionName === 'string';
|
|
73
|
+
}
|
|
74
|
+
function isTriggerConfig(value) {
|
|
75
|
+
return value && typeof value === 'object' &&
|
|
76
|
+
value.$type === 'trigger' &&
|
|
77
|
+
typeof value.$triggerName === 'string';
|
|
78
|
+
}
|
|
79
|
+
function isExtensionsConfig(value) {
|
|
80
|
+
return value && typeof value === 'object' &&
|
|
81
|
+
Array.isArray(value.extensions) &&
|
|
82
|
+
typeof value.toSQL === 'function';
|
|
83
|
+
}
|
|
84
|
+
function isRelationsConfig(value) {
|
|
85
|
+
return value && typeof value === 'object' &&
|
|
86
|
+
value.$type === 'relations';
|
|
87
|
+
}
|
|
88
|
+
function generateTrackingId() {
|
|
89
|
+
const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
|
90
|
+
let result = '';
|
|
91
|
+
for (let i = 0; i < 6; i++) {
|
|
92
|
+
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
93
|
+
}
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
function isValidTrackingId(id) {
|
|
97
|
+
return typeof id === 'string' && /^[a-z0-9]{6}$/.test(id);
|
|
98
|
+
}
|
|
99
|
+
function extractTrackingId(obj) {
|
|
100
|
+
if (!obj)
|
|
101
|
+
return undefined;
|
|
102
|
+
if (typeof obj.$trackingId === 'string') {
|
|
103
|
+
return obj.$trackingId;
|
|
104
|
+
}
|
|
105
|
+
if (typeof obj.$id === 'function') {
|
|
106
|
+
const id = obj.$id();
|
|
107
|
+
if (typeof id === 'string') {
|
|
108
|
+
return id;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
function mapColumnTypeToPostgres(type) {
|
|
114
|
+
const typeMap = {
|
|
115
|
+
'UUID': 'uuid',
|
|
116
|
+
'TEXT': 'text',
|
|
117
|
+
'VARCHAR': 'character varying',
|
|
118
|
+
'CHAR': 'character',
|
|
119
|
+
'INTEGER': 'integer',
|
|
120
|
+
'INT': 'integer',
|
|
121
|
+
'BIGINT': 'bigint',
|
|
122
|
+
'SMALLINT': 'smallint',
|
|
123
|
+
'SERIAL': 'serial',
|
|
124
|
+
'BIGSERIAL': 'bigserial',
|
|
125
|
+
'SMALLSERIAL': 'smallserial',
|
|
126
|
+
'BOOLEAN': 'boolean',
|
|
127
|
+
'BOOL': 'boolean',
|
|
128
|
+
'REAL': 'real',
|
|
129
|
+
'FLOAT4': 'real',
|
|
130
|
+
'DOUBLE PRECISION': 'double precision',
|
|
131
|
+
'FLOAT8': 'double precision',
|
|
132
|
+
'NUMERIC': 'numeric',
|
|
133
|
+
'DECIMAL': 'numeric',
|
|
134
|
+
'MONEY': 'money',
|
|
135
|
+
'DATE': 'date',
|
|
136
|
+
'TIME': 'time without time zone',
|
|
137
|
+
'TIME WITH TIME ZONE': 'time with time zone',
|
|
138
|
+
'TIMETZ': 'time with time zone',
|
|
139
|
+
'TIMESTAMP': 'timestamp without time zone',
|
|
140
|
+
'TIMESTAMP WITH TIME ZONE': 'timestamp with time zone',
|
|
141
|
+
'TIMESTAMPTZ': 'timestamp with time zone',
|
|
142
|
+
'INTERVAL': 'interval',
|
|
143
|
+
'JSON': 'json',
|
|
144
|
+
'JSONB': 'jsonb',
|
|
145
|
+
'BYTEA': 'bytea',
|
|
146
|
+
'INET': 'inet',
|
|
147
|
+
'CIDR': 'cidr',
|
|
148
|
+
'MACADDR': 'macaddr',
|
|
149
|
+
'MACADDR8': 'macaddr8',
|
|
150
|
+
'POINT': 'point',
|
|
151
|
+
'LINE': 'line',
|
|
152
|
+
'LSEG': 'lseg',
|
|
153
|
+
'BOX': 'box',
|
|
154
|
+
'PATH': 'path',
|
|
155
|
+
'POLYGON': 'polygon',
|
|
156
|
+
'CIRCLE': 'circle',
|
|
157
|
+
'TSVECTOR': 'tsvector',
|
|
158
|
+
'TSQUERY': 'tsquery',
|
|
159
|
+
'XML': 'xml',
|
|
160
|
+
'BIT': 'bit',
|
|
161
|
+
'BIT VARYING': 'bit varying',
|
|
162
|
+
'VARBIT': 'bit varying',
|
|
163
|
+
'PG_LSN': 'pg_lsn',
|
|
164
|
+
'PG_SNAPSHOT': 'pg_snapshot',
|
|
165
|
+
'INT4RANGE': 'int4range',
|
|
166
|
+
'INT8RANGE': 'int8range',
|
|
167
|
+
'NUMRANGE': 'numrange',
|
|
168
|
+
'TSRANGE': 'tsrange',
|
|
169
|
+
'TSTZRANGE': 'tstzrange',
|
|
170
|
+
'DATERANGE': 'daterange',
|
|
171
|
+
'CITEXT': 'citext',
|
|
172
|
+
'LTREE': 'ltree',
|
|
173
|
+
'HSTORE': 'hstore',
|
|
174
|
+
'CUBE': 'cube',
|
|
175
|
+
'VECTOR': 'vector',
|
|
176
|
+
};
|
|
177
|
+
const upperType = type.toUpperCase();
|
|
178
|
+
return typeMap[upperType] || type.toLowerCase();
|
|
179
|
+
}
|
|
180
|
+
function schemaToAST(schema) {
|
|
181
|
+
const result = {
|
|
182
|
+
enums: [],
|
|
183
|
+
domains: [],
|
|
184
|
+
compositeTypes: [],
|
|
185
|
+
sequences: [],
|
|
186
|
+
tables: [],
|
|
187
|
+
views: [],
|
|
188
|
+
functions: [],
|
|
189
|
+
triggers: [],
|
|
190
|
+
extensions: [],
|
|
191
|
+
};
|
|
192
|
+
for (const [key, value] of Object.entries(schema)) {
|
|
193
|
+
if (!value)
|
|
194
|
+
continue;
|
|
195
|
+
if (isTableDefinition(value)) {
|
|
196
|
+
const table = tableToAST(value);
|
|
197
|
+
if (table)
|
|
198
|
+
result.tables.push(table);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (isEnumConfig(value)) {
|
|
202
|
+
const enumDef = enumToAST(value);
|
|
203
|
+
if (enumDef)
|
|
204
|
+
result.enums.push(enumDef);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (isDomainConfig(value)) {
|
|
208
|
+
const domain = domainToAST(value);
|
|
209
|
+
if (domain)
|
|
210
|
+
result.domains.push(domain);
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (isCompositeConfig(value)) {
|
|
214
|
+
const composite = compositeToAST(value);
|
|
215
|
+
if (composite)
|
|
216
|
+
result.compositeTypes.push(composite);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (isSequenceConfig(value)) {
|
|
220
|
+
const sequence = sequenceToAST(value);
|
|
221
|
+
if (sequence)
|
|
222
|
+
result.sequences.push(sequence);
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (isViewConfig(value)) {
|
|
226
|
+
const view = viewToAST(value);
|
|
227
|
+
if (view)
|
|
228
|
+
result.views.push(view);
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (isMaterializedViewConfig(value)) {
|
|
232
|
+
const matView = materializedViewToAST(value);
|
|
233
|
+
if (matView)
|
|
234
|
+
result.views.push(matView);
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
if (isFunctionConfig(value)) {
|
|
238
|
+
const func = functionToAST(value);
|
|
239
|
+
if (func)
|
|
240
|
+
result.functions.push(func);
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (isTriggerConfig(value)) {
|
|
244
|
+
const trigger = triggerToAST(value);
|
|
245
|
+
if (trigger)
|
|
246
|
+
result.triggers.push(trigger);
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
if (isExtensionsConfig(value)) {
|
|
250
|
+
result.extensions.push(...value.extensions);
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return result;
|
|
255
|
+
}
|
|
256
|
+
function tableToAST(table) {
|
|
257
|
+
if (!isTableDefinition(table))
|
|
258
|
+
return null;
|
|
259
|
+
const columns = [];
|
|
260
|
+
for (const [colKey, colDef] of Object.entries(table.$columns || {})) {
|
|
261
|
+
const col = columnToAST(colDef, colKey);
|
|
262
|
+
if (col)
|
|
263
|
+
columns.push(col);
|
|
264
|
+
}
|
|
265
|
+
const indexes = [];
|
|
266
|
+
for (const idx of table.$indexes || []) {
|
|
267
|
+
const index = indexToAST(idx);
|
|
268
|
+
if (index)
|
|
269
|
+
indexes.push(index);
|
|
270
|
+
}
|
|
271
|
+
const constraints = [];
|
|
272
|
+
for (const con of table.$constraints || []) {
|
|
273
|
+
const constraint = constraintToAST(con);
|
|
274
|
+
if (constraint)
|
|
275
|
+
constraints.push(constraint);
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
name: table.$name,
|
|
279
|
+
schema: table.$schema || 'public',
|
|
280
|
+
columns,
|
|
281
|
+
constraints,
|
|
282
|
+
indexes,
|
|
283
|
+
isPartitioned: !!table.$partitionBy,
|
|
284
|
+
partitionType: table.$partitionBy?.type?.toUpperCase(),
|
|
285
|
+
partitionKey: table.$partitionBy?.columns,
|
|
286
|
+
comment: table.$comment,
|
|
287
|
+
trackingId: extractTrackingId(table),
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
function columnToAST(col, schemaKey) {
|
|
291
|
+
if (!col)
|
|
292
|
+
return null;
|
|
293
|
+
const config = col.$config || col;
|
|
294
|
+
return {
|
|
295
|
+
name: config.$sqlName || schemaKey,
|
|
296
|
+
type: mapColumnTypeToPostgres(config.$type || 'text'),
|
|
297
|
+
typeParams: {
|
|
298
|
+
precision: config.$precision,
|
|
299
|
+
scale: config.$scale,
|
|
300
|
+
length: config.$length,
|
|
301
|
+
},
|
|
302
|
+
isNullable: config.$nullable !== false,
|
|
303
|
+
isPrimaryKey: config.$primaryKey || false,
|
|
304
|
+
isUnique: config.$unique || false,
|
|
305
|
+
hasDefault: config.$default !== undefined,
|
|
306
|
+
defaultValue: config.$default?.toString(),
|
|
307
|
+
isGenerated: !!config.$generatedAlwaysAs,
|
|
308
|
+
generatedExpression: config.$generatedAlwaysAs?.toString(),
|
|
309
|
+
isArray: config.$isArray || false,
|
|
310
|
+
arrayDimensions: config.$arrayDimensions,
|
|
311
|
+
comment: config.$comment,
|
|
312
|
+
trackingId: extractTrackingId(config),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function indexToAST(idx) {
|
|
316
|
+
if (!idx)
|
|
317
|
+
return null;
|
|
318
|
+
return {
|
|
319
|
+
name: idx.$name || idx.name,
|
|
320
|
+
columns: idx.$columns || idx.columns || [],
|
|
321
|
+
isUnique: idx.$unique || idx.unique || false,
|
|
322
|
+
method: idx.$using || idx.using || 'btree',
|
|
323
|
+
whereClause: idx.$where?.toString(),
|
|
324
|
+
includeColumns: idx.$include,
|
|
325
|
+
comment: idx.$comment,
|
|
326
|
+
trackingId: extractTrackingId(idx),
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
function constraintToAST(con) {
|
|
330
|
+
if (!con)
|
|
331
|
+
return null;
|
|
332
|
+
return {
|
|
333
|
+
name: con.$name || con.name,
|
|
334
|
+
type: (con.$type || con.type || 'CHECK').toUpperCase(),
|
|
335
|
+
columns: con.$columns || con.columns || [],
|
|
336
|
+
expression: con.$expression || con.expression,
|
|
337
|
+
trackingId: extractTrackingId(con),
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
function enumToAST(enumDef) {
|
|
341
|
+
if (!isEnumConfig(enumDef))
|
|
342
|
+
return null;
|
|
343
|
+
return {
|
|
344
|
+
name: enumDef.$enumName,
|
|
345
|
+
schema: enumDef.$schema || 'public',
|
|
346
|
+
values: [...enumDef.$enumValues],
|
|
347
|
+
trackingId: extractTrackingId(enumDef),
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
function domainToAST(domain) {
|
|
351
|
+
if (!isDomainConfig(domain))
|
|
352
|
+
return null;
|
|
353
|
+
let checkExpression;
|
|
354
|
+
let checkName;
|
|
355
|
+
if (domain.$constraints && domain.$constraints.length > 0) {
|
|
356
|
+
const constraint = domain.$constraints[0];
|
|
357
|
+
const namedMatch = constraint.match(/^CONSTRAINT\s+(\w+)\s+CHECK\s*\((.+)\)$/i);
|
|
358
|
+
if (namedMatch) {
|
|
359
|
+
checkName = namedMatch[1];
|
|
360
|
+
checkExpression = namedMatch[2];
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
const simpleMatch = constraint.match(/^CHECK\s*\((.+)\)$/i);
|
|
364
|
+
if (simpleMatch) {
|
|
365
|
+
checkExpression = simpleMatch[1];
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return {
|
|
370
|
+
name: domain.$domainName,
|
|
371
|
+
schema: domain.$schema || 'public',
|
|
372
|
+
baseType: domain.$baseType,
|
|
373
|
+
notNull: domain.$notNull || false,
|
|
374
|
+
defaultValue: domain.$domainDefault?.toString(),
|
|
375
|
+
checkExpression,
|
|
376
|
+
checkName,
|
|
377
|
+
trackingId: extractTrackingId(domain),
|
|
378
|
+
};
|
|
379
|
+
}
|
|
380
|
+
function compositeToAST(composite) {
|
|
381
|
+
if (!isCompositeConfig(composite))
|
|
382
|
+
return null;
|
|
383
|
+
const attributes = [];
|
|
384
|
+
for (const [fieldName, fieldDef] of Object.entries(composite.$fields || {})) {
|
|
385
|
+
const config = fieldDef.$config || fieldDef;
|
|
386
|
+
attributes.push({
|
|
387
|
+
name: fieldName,
|
|
388
|
+
type: config.$type || 'text',
|
|
389
|
+
collation: config.$collation,
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
return {
|
|
393
|
+
name: composite.$typeName,
|
|
394
|
+
schema: composite.$schema || 'public',
|
|
395
|
+
attributes,
|
|
396
|
+
trackingId: extractTrackingId(composite),
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function sequenceToAST(seq) {
|
|
400
|
+
if (!isSequenceConfig(seq))
|
|
401
|
+
return null;
|
|
402
|
+
return {
|
|
403
|
+
name: seq.name,
|
|
404
|
+
schema: seq.schema || 'public',
|
|
405
|
+
startValue: seq.options?.start,
|
|
406
|
+
increment: seq.options?.increment,
|
|
407
|
+
minValue: seq.options?.minValue,
|
|
408
|
+
maxValue: seq.options?.maxValue,
|
|
409
|
+
cache: seq.options?.cache,
|
|
410
|
+
cycle: seq.options?.cycle || false,
|
|
411
|
+
ownedBy: seq.options?.ownedBy,
|
|
412
|
+
trackingId: extractTrackingId(seq),
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
function viewToAST(view) {
|
|
416
|
+
if (!isViewConfig(view))
|
|
417
|
+
return null;
|
|
418
|
+
return {
|
|
419
|
+
name: view.name,
|
|
420
|
+
schema: view.schema || 'public',
|
|
421
|
+
definition: view.definition,
|
|
422
|
+
isMaterialized: false,
|
|
423
|
+
trackingId: extractTrackingId(view),
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
function materializedViewToAST(matView) {
|
|
427
|
+
if (!isMaterializedViewConfig(matView))
|
|
428
|
+
return null;
|
|
429
|
+
return {
|
|
430
|
+
name: matView.name,
|
|
431
|
+
schema: matView.schema || 'public',
|
|
432
|
+
definition: matView.definition,
|
|
433
|
+
isMaterialized: true,
|
|
434
|
+
withData: matView.withData,
|
|
435
|
+
trackingId: extractTrackingId(matView),
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
function functionToAST(func) {
|
|
439
|
+
if (!isFunctionConfig(func))
|
|
440
|
+
return null;
|
|
441
|
+
const opts = func.$options || {};
|
|
442
|
+
return {
|
|
443
|
+
name: func.$functionName,
|
|
444
|
+
schema: opts.schema || 'public',
|
|
445
|
+
args: (opts.args || []).map((arg) => ({
|
|
446
|
+
name: arg.name,
|
|
447
|
+
type: arg.type,
|
|
448
|
+
mode: arg.mode,
|
|
449
|
+
default: arg.default,
|
|
450
|
+
})),
|
|
451
|
+
returnType: opts.returns || 'void',
|
|
452
|
+
language: opts.language || 'plpgsql',
|
|
453
|
+
body: opts.body || '',
|
|
454
|
+
volatility: opts.volatility?.toUpperCase(),
|
|
455
|
+
isStrict: opts.strict || false,
|
|
456
|
+
securityDefiner: opts.securityDefiner || false,
|
|
457
|
+
trackingId: extractTrackingId(func),
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
function triggerToAST(trigger) {
|
|
461
|
+
if (!isTriggerConfig(trigger))
|
|
462
|
+
return null;
|
|
463
|
+
const opts = trigger.$options || {};
|
|
464
|
+
return {
|
|
465
|
+
name: trigger.$triggerName,
|
|
466
|
+
table: opts.table || '',
|
|
467
|
+
timing: (opts.timing || 'BEFORE').toUpperCase(),
|
|
468
|
+
events: (opts.events || ['INSERT']).map((e) => e.toUpperCase()),
|
|
469
|
+
forEach: (opts.forEach || 'ROW').toUpperCase(),
|
|
470
|
+
functionName: opts.execute || '',
|
|
471
|
+
whenClause: opts.when,
|
|
472
|
+
isConstraint: opts.constraint || false,
|
|
473
|
+
deferrable: opts.deferrable,
|
|
474
|
+
initiallyDeferred: opts.initiallyDeferred,
|
|
475
|
+
trackingId: extractTrackingId(trigger),
|
|
476
|
+
};
|
|
477
|
+
}
|
|
@@ -89,7 +89,27 @@ function validateSchemaFile(schemaPath) {
|
|
|
89
89
|
getNewLine: () => '\n',
|
|
90
90
|
});
|
|
91
91
|
const syntacticDiagnostics = program.getSyntacticDiagnostics(sourceFile);
|
|
92
|
-
|
|
92
|
+
const ignoredErrorCodes = new Set([
|
|
93
|
+
2306,
|
|
94
|
+
2307,
|
|
95
|
+
2305,
|
|
96
|
+
2339,
|
|
97
|
+
2694,
|
|
98
|
+
2792,
|
|
99
|
+
2503,
|
|
100
|
+
2749,
|
|
101
|
+
2315,
|
|
102
|
+
2322,
|
|
103
|
+
2345,
|
|
104
|
+
2769,
|
|
105
|
+
2741,
|
|
106
|
+
2551,
|
|
107
|
+
2737,
|
|
108
|
+
]);
|
|
109
|
+
const semanticDiagnostics = program.getSemanticDiagnostics(sourceFile)
|
|
110
|
+
.filter(d => !ignoredErrorCodes.has(d.code));
|
|
111
|
+
const allDiagnostics = [...syntacticDiagnostics, ...semanticDiagnostics];
|
|
112
|
+
for (const diagnostic of allDiagnostics) {
|
|
93
113
|
if (diagnostic.file && diagnostic.start !== undefined) {
|
|
94
114
|
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
95
115
|
errors.push({
|
|
@@ -245,6 +245,7 @@ const generatedFnMethods = {
|
|
|
245
245
|
cast: (value, typeName) => chainableExpr(`(${formatGenValue(value)})::${typeName}`),
|
|
246
246
|
func: (name, ...args) => chainableExpr(`${name.toUpperCase()}(${args.map(formatGenValue).join(', ')})`),
|
|
247
247
|
sql: (expression) => chainableExpr(expression),
|
|
248
|
+
raw: (expression) => chainableExpr(expression),
|
|
248
249
|
op: (left, operator, right) => chainableExpr(`(${formatGenValue(left)} ${operator} ${formatGenValue(right)})`),
|
|
249
250
|
setweight: (tsvector, weight) => chainableExpr(`SETWEIGHT(${tsvector.$sql}, '${weight}')`),
|
|
250
251
|
setWeight: (tsvector, weight) => chainableExpr(`SETWEIGHT(${tsvector.$sql}, '${weight}')`),
|
|
@@ -317,12 +318,18 @@ function createColumn(type) {
|
|
|
317
318
|
return Object.assign(this, { $generated: config.$generated });
|
|
318
319
|
},
|
|
319
320
|
generatedAlwaysAs(callback, options) {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
321
|
+
let result;
|
|
322
|
+
if (callback.length === 1) {
|
|
323
|
+
result = callback(generatedFn);
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
const tableProxy = new Proxy({}, {
|
|
327
|
+
get(_target, prop) {
|
|
328
|
+
return chainableExpr(`"${prop}"`);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
result = callback(tableProxy, generatedFn);
|
|
332
|
+
}
|
|
326
333
|
const stored = options?.stored !== false;
|
|
327
334
|
config.$generated = { expression: result.$sql, stored };
|
|
328
335
|
return Object.assign(this, { $generated: config.$generated });
|
|
@@ -857,7 +864,21 @@ function pgDomain(name, baseType, checks) {
|
|
|
857
864
|
}
|
|
858
865
|
return col;
|
|
859
866
|
};
|
|
860
|
-
|
|
867
|
+
let checkExpression;
|
|
868
|
+
let checkName;
|
|
869
|
+
if (constraints.length > 0) {
|
|
870
|
+
const firstConstraint = constraints[0];
|
|
871
|
+
const namedMatch = firstConstraint.match(/^CONSTRAINT\s+(\w+)\s+CHECK\s*\((.+)\)$/i);
|
|
872
|
+
const unnamedMatch = firstConstraint.match(/^CHECK\s*\((.+)\)$/i);
|
|
873
|
+
if (namedMatch) {
|
|
874
|
+
checkName = namedMatch[1];
|
|
875
|
+
checkExpression = namedMatch[2];
|
|
876
|
+
}
|
|
877
|
+
else if (unnamedMatch) {
|
|
878
|
+
checkExpression = unnamedMatch[1];
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
const domainConfig = {
|
|
861
882
|
$domainName: name,
|
|
862
883
|
$baseType: baseTypeStr,
|
|
863
884
|
$constraints: constraints.length > 0 ? constraints : undefined,
|
|
@@ -865,7 +886,22 @@ function pgDomain(name, baseType, checks) {
|
|
|
865
886
|
$notNull: notNull,
|
|
866
887
|
$columnBuilder: baseType,
|
|
867
888
|
$validate: validateFn,
|
|
868
|
-
|
|
889
|
+
$trackingId: undefined,
|
|
890
|
+
toAST() {
|
|
891
|
+
return {
|
|
892
|
+
name: domainConfig.$domainName,
|
|
893
|
+
baseType: domainConfig.$baseType,
|
|
894
|
+
notNull: domainConfig.$notNull ?? false,
|
|
895
|
+
defaultValue: domainConfig.$domainDefault !== undefined
|
|
896
|
+
? String(domainConfig.$domainDefault)
|
|
897
|
+
: undefined,
|
|
898
|
+
checkExpression,
|
|
899
|
+
checkName,
|
|
900
|
+
trackingId: domainConfig.$trackingId,
|
|
901
|
+
};
|
|
902
|
+
},
|
|
903
|
+
};
|
|
904
|
+
Object.assign(domainFn, domainConfig);
|
|
869
905
|
return domainFn;
|
|
870
906
|
}
|
|
871
907
|
function generateDomainSQL(domain) {
|
|
@@ -887,11 +923,28 @@ function pgComposite(name, fields) {
|
|
|
887
923
|
col.$fields = fields;
|
|
888
924
|
return col;
|
|
889
925
|
};
|
|
890
|
-
Object.
|
|
926
|
+
const attributes = Object.entries(fields).map(([fieldName, fieldConfig]) => {
|
|
927
|
+
const config = fieldConfig;
|
|
928
|
+
return {
|
|
929
|
+
name: fieldName,
|
|
930
|
+
type: config.$type,
|
|
931
|
+
collation: undefined,
|
|
932
|
+
};
|
|
933
|
+
});
|
|
934
|
+
const compositeConfig = {
|
|
891
935
|
$typeName: name,
|
|
892
936
|
$fields: fields,
|
|
893
937
|
$inferType: {},
|
|
894
|
-
|
|
938
|
+
$trackingId: undefined,
|
|
939
|
+
toAST() {
|
|
940
|
+
return {
|
|
941
|
+
name: compositeConfig.$typeName,
|
|
942
|
+
attributes,
|
|
943
|
+
trackingId: compositeConfig.$trackingId,
|
|
944
|
+
};
|
|
945
|
+
},
|
|
946
|
+
};
|
|
947
|
+
Object.assign(compositeFn, compositeConfig);
|
|
895
948
|
return compositeFn;
|
|
896
949
|
}
|
|
897
950
|
function generateCompositeTypeSQL(composite) {
|
|
@@ -54,6 +54,16 @@ function pgEnum(name, values) {
|
|
|
54
54
|
},
|
|
55
55
|
enumerable: true,
|
|
56
56
|
},
|
|
57
|
+
toAST: {
|
|
58
|
+
value: function () {
|
|
59
|
+
return {
|
|
60
|
+
name: this.$enumName,
|
|
61
|
+
values: [...this.$enumValues],
|
|
62
|
+
trackingId: this.$trackingId,
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
enumerable: true,
|
|
66
|
+
},
|
|
57
67
|
});
|
|
58
68
|
return config;
|
|
59
69
|
}
|
|
@@ -81,6 +81,25 @@ function pgFunction(name, options) {
|
|
|
81
81
|
$functionName: name,
|
|
82
82
|
$options: options,
|
|
83
83
|
$type: 'function',
|
|
84
|
+
toAST() {
|
|
85
|
+
const opts = this.$options;
|
|
86
|
+
return {
|
|
87
|
+
name: this.$functionName,
|
|
88
|
+
args: (opts.args || []).map(arg => ({
|
|
89
|
+
name: arg.name,
|
|
90
|
+
type: arg.type,
|
|
91
|
+
mode: arg.mode,
|
|
92
|
+
default: arg.default,
|
|
93
|
+
})),
|
|
94
|
+
returnType: opts.returns,
|
|
95
|
+
language: opts.language || 'plpgsql',
|
|
96
|
+
body: opts.body || opts.raw || '',
|
|
97
|
+
volatility: opts.volatility,
|
|
98
|
+
isStrict: opts.strict || false,
|
|
99
|
+
securityDefiner: opts.security === 'DEFINER',
|
|
100
|
+
trackingId: this.$trackingId,
|
|
101
|
+
};
|
|
102
|
+
},
|
|
84
103
|
};
|
|
85
104
|
}
|
|
86
105
|
function isFunctionConfig(value) {
|
|
@@ -5,11 +5,32 @@ exports.generateSequenceSQL = generateSequenceSQL;
|
|
|
5
5
|
exports.dropSequenceSQL = dropSequenceSQL;
|
|
6
6
|
exports.isSequenceConfig = isSequenceConfig;
|
|
7
7
|
function pgSequence(name, options = {}) {
|
|
8
|
-
|
|
8
|
+
const config = {
|
|
9
9
|
_type: 'sequence',
|
|
10
10
|
name,
|
|
11
11
|
options,
|
|
12
|
+
toAST() {
|
|
13
|
+
return {
|
|
14
|
+
name: this.name,
|
|
15
|
+
startValue: this.options.start,
|
|
16
|
+
increment: this.options.increment,
|
|
17
|
+
minValue: this.options.minValue ?? undefined,
|
|
18
|
+
maxValue: this.options.maxValue ?? undefined,
|
|
19
|
+
cache: this.options.cache,
|
|
20
|
+
cycle: this.options.cycle ?? false,
|
|
21
|
+
ownedBy: this.options.ownedBy ? parseOwnedBy(this.options.ownedBy) : undefined,
|
|
22
|
+
trackingId: this.$trackingId,
|
|
23
|
+
};
|
|
24
|
+
},
|
|
12
25
|
};
|
|
26
|
+
return config;
|
|
27
|
+
}
|
|
28
|
+
function parseOwnedBy(ownedBy) {
|
|
29
|
+
const parts = ownedBy.split('.');
|
|
30
|
+
if (parts.length === 2) {
|
|
31
|
+
return { table: parts[0], column: parts[1] };
|
|
32
|
+
}
|
|
33
|
+
return undefined;
|
|
13
34
|
}
|
|
14
35
|
function generateSequenceSQL(seq) {
|
|
15
36
|
const parts = [`CREATE SEQUENCE ${seq.name}`];
|