relq 1.0.5 → 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 +149 -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 +146 -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
|
@@ -478,7 +478,7 @@ function generateSchemaCode(table, options) {
|
|
|
478
478
|
modifiers.push('.unique()');
|
|
479
479
|
}
|
|
480
480
|
if (col.default !== undefined) {
|
|
481
|
-
const defaultVal = formatDefaultValue(col.default);
|
|
481
|
+
const defaultVal = formatDefaultValue(col.default, col.type);
|
|
482
482
|
modifiers.push(`.default(${defaultVal})`);
|
|
483
483
|
}
|
|
484
484
|
if (col.references) {
|
|
@@ -583,7 +583,7 @@ function toPascalCase(str) {
|
|
|
583
583
|
function escapeString(str) {
|
|
584
584
|
return str.replace(/'/g, "\\'").replace(/\\/g, '\\\\');
|
|
585
585
|
}
|
|
586
|
-
function formatDefaultValue(value) {
|
|
586
|
+
function formatDefaultValue(value, colType) {
|
|
587
587
|
const upper = value.toUpperCase().trim();
|
|
588
588
|
if (upper === 'NOW()' || upper === 'CURRENT_TIMESTAMP' ||
|
|
589
589
|
upper === 'CURRENT_DATE' || upper === 'CURRENT_TIME') {
|
|
@@ -598,7 +598,11 @@ function formatDefaultValue(value) {
|
|
|
598
598
|
if (upper === 'NULL') {
|
|
599
599
|
return 'null';
|
|
600
600
|
}
|
|
601
|
-
|
|
601
|
+
const isBigint = colType?.toLowerCase().startsWith('bigint');
|
|
602
|
+
if (/^-?\d+$/.test(value)) {
|
|
603
|
+
return isBigint ? `${value}n` : value;
|
|
604
|
+
}
|
|
605
|
+
if (/^-?\d+\.\d+$/.test(value)) {
|
|
602
606
|
return value;
|
|
603
607
|
}
|
|
604
608
|
if (value.includes('(')) {
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pgRelations = pgRelations;
|
|
4
|
+
exports.defineRelations = defineRelations;
|
|
5
|
+
exports.actionCodeToString = actionCodeToString;
|
|
6
|
+
exports.stringToActionCode = stringToActionCode;
|
|
7
|
+
exports.matchCodeToString = matchCodeToString;
|
|
8
|
+
exports.generateReferencesSQL = generateReferencesSQL;
|
|
9
|
+
function createColumnRef(tableName, columnName, schemaKey) {
|
|
10
|
+
return {
|
|
11
|
+
$table: tableName,
|
|
12
|
+
$column: columnName,
|
|
13
|
+
$schemaKey: schemaKey,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function createTargetColumnRefs(schemaKey, table) {
|
|
17
|
+
const refs = {};
|
|
18
|
+
const actualTableName = table.$name;
|
|
19
|
+
for (const colName of Object.keys(table.$columns)) {
|
|
20
|
+
const colDef = table.$columns[colName];
|
|
21
|
+
const actualColName = colDef.$sqlName || colName;
|
|
22
|
+
refs[colName] = createColumnRef(actualTableName, actualColName, colName);
|
|
23
|
+
}
|
|
24
|
+
return refs;
|
|
25
|
+
}
|
|
26
|
+
function createReferenceToBuilder(schema, currentTableKey) {
|
|
27
|
+
return new Proxy({}, {
|
|
28
|
+
get(_, targetTableKey) {
|
|
29
|
+
const targetTable = schema[targetTableKey];
|
|
30
|
+
if (!targetTable) {
|
|
31
|
+
throw new Error(`Unknown table: ${targetTableKey}`);
|
|
32
|
+
}
|
|
33
|
+
return (callback) => {
|
|
34
|
+
const targetColRefs = createTargetColumnRefs(targetTableKey, targetTable);
|
|
35
|
+
const options = callback(targetColRefs);
|
|
36
|
+
const currentTable = schema[currentTableKey];
|
|
37
|
+
const currentTableName = currentTable?.$name || currentTableKey;
|
|
38
|
+
if ('columns' in options && Array.isArray(options.columns)) {
|
|
39
|
+
const compositeOpts = options;
|
|
40
|
+
return {
|
|
41
|
+
$type: 'foreignKey',
|
|
42
|
+
$targetTable: targetTable.$name,
|
|
43
|
+
$columns: compositeOpts.columns.map(c => ({
|
|
44
|
+
table: c.$table,
|
|
45
|
+
column: c.$column,
|
|
46
|
+
})),
|
|
47
|
+
$references: compositeOpts.references.map(r => ({
|
|
48
|
+
table: r.$table,
|
|
49
|
+
column: r.$column,
|
|
50
|
+
})),
|
|
51
|
+
$onDelete: compositeOpts.onDelete,
|
|
52
|
+
$onUpdate: compositeOpts.onUpdate,
|
|
53
|
+
$match: compositeOpts.match,
|
|
54
|
+
$deferrable: compositeOpts.deferrable,
|
|
55
|
+
$initiallyDeferred: compositeOpts.initiallyDeferred,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const singleOpts = options;
|
|
59
|
+
const referencesCol = singleOpts.references;
|
|
60
|
+
return {
|
|
61
|
+
$type: 'foreignKey',
|
|
62
|
+
$targetTable: targetTable.$name,
|
|
63
|
+
$columns: [],
|
|
64
|
+
$references: referencesCol ? [{
|
|
65
|
+
table: referencesCol.$table,
|
|
66
|
+
column: referencesCol.$column,
|
|
67
|
+
}] : undefined,
|
|
68
|
+
$onDelete: singleOpts.onDelete,
|
|
69
|
+
$onUpdate: singleOpts.onUpdate,
|
|
70
|
+
$match: singleOpts.match,
|
|
71
|
+
$deferrable: singleOpts.deferrable,
|
|
72
|
+
$initiallyDeferred: singleOpts.initiallyDeferred,
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function createSourceColumnRefs(schemaKey, table) {
|
|
79
|
+
const refs = {};
|
|
80
|
+
const actualTableName = table.$name;
|
|
81
|
+
for (const colName of Object.keys(table.$columns)) {
|
|
82
|
+
const colDef = table.$columns[colName];
|
|
83
|
+
const actualColName = colDef.$sqlName || colName;
|
|
84
|
+
refs[colName] = createColumnRef(actualTableName, actualColName, colName);
|
|
85
|
+
}
|
|
86
|
+
return refs;
|
|
87
|
+
}
|
|
88
|
+
function createFullBuilder(schema, currentTableKey) {
|
|
89
|
+
const builder = {
|
|
90
|
+
referenceTo: createReferenceToBuilder(schema, currentTableKey),
|
|
91
|
+
};
|
|
92
|
+
for (const [tableName, table] of Object.entries(schema)) {
|
|
93
|
+
builder[tableName] = createSourceColumnRefs(tableName, table);
|
|
94
|
+
}
|
|
95
|
+
return builder;
|
|
96
|
+
}
|
|
97
|
+
function pgRelations(schema, builder) {
|
|
98
|
+
const tables = {};
|
|
99
|
+
for (const tableKey of Object.keys(schema)) {
|
|
100
|
+
tables[tableKey] = (defineRelations) => {
|
|
101
|
+
const fullBuilder = createFullBuilder(schema, tableKey);
|
|
102
|
+
return defineRelations(fullBuilder);
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return builder(tables);
|
|
106
|
+
}
|
|
107
|
+
function defineRelations(schema, relationDefs) {
|
|
108
|
+
const result = {};
|
|
109
|
+
for (const [tableKey, defFn] of Object.entries(relationDefs)) {
|
|
110
|
+
if (typeof defFn === 'function') {
|
|
111
|
+
const fullBuilder = createFullBuilder(schema, tableKey);
|
|
112
|
+
result[tableKey] = defFn(fullBuilder);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return result;
|
|
116
|
+
}
|
|
117
|
+
function actionCodeToString(code) {
|
|
118
|
+
switch (code) {
|
|
119
|
+
case 'a': return 'NO ACTION';
|
|
120
|
+
case 'r': return 'RESTRICT';
|
|
121
|
+
case 'c': return 'CASCADE';
|
|
122
|
+
case 'n': return 'SET NULL';
|
|
123
|
+
case 'd': return 'SET DEFAULT';
|
|
124
|
+
default: return 'NO ACTION';
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function stringToActionCode(action) {
|
|
128
|
+
switch (action) {
|
|
129
|
+
case 'NO ACTION': return 'a';
|
|
130
|
+
case 'RESTRICT': return 'r';
|
|
131
|
+
case 'CASCADE': return 'c';
|
|
132
|
+
case 'SET NULL': return 'n';
|
|
133
|
+
case 'SET DEFAULT': return 'd';
|
|
134
|
+
default: return 'a';
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function matchCodeToString(code) {
|
|
138
|
+
switch (code) {
|
|
139
|
+
case 'f': return 'FULL';
|
|
140
|
+
case 's':
|
|
141
|
+
default: return 'SIMPLE';
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function generateReferencesSQL(relation, columnName, columnType = 'uuid') {
|
|
145
|
+
const parts = [`${columnName} ${columnType}`];
|
|
146
|
+
if (relation.$references && relation.$references.length > 0) {
|
|
147
|
+
const refCols = relation.$references.map(r => r.column).join(', ');
|
|
148
|
+
parts.push(`REFERENCES ${relation.$targetTable}(${refCols})`);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
parts.push(`REFERENCES ${relation.$targetTable}`);
|
|
152
|
+
}
|
|
153
|
+
if (relation.$onDelete && relation.$onDelete !== 'NO ACTION') {
|
|
154
|
+
parts.push(`ON DELETE ${relation.$onDelete}`);
|
|
155
|
+
}
|
|
156
|
+
if (relation.$onUpdate && relation.$onUpdate !== 'NO ACTION') {
|
|
157
|
+
parts.push(`ON UPDATE ${relation.$onUpdate}`);
|
|
158
|
+
}
|
|
159
|
+
if (relation.$match && relation.$match !== 'SIMPLE') {
|
|
160
|
+
parts.push(`MATCH ${relation.$match}`);
|
|
161
|
+
}
|
|
162
|
+
if (relation.$deferrable) {
|
|
163
|
+
parts.push('DEFERRABLE');
|
|
164
|
+
if (relation.$initiallyDeferred) {
|
|
165
|
+
parts.push('INITIALLY DEFERRED');
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return parts.join(' ');
|
|
169
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pgView = pgView;
|
|
4
|
+
exports.pgMaterializedView = pgMaterializedView;
|
|
5
|
+
exports.viewToSQL = viewToSQL;
|
|
6
|
+
exports.materializedViewToSQL = materializedViewToSQL;
|
|
7
|
+
function pgView(name, definition) {
|
|
8
|
+
return {
|
|
9
|
+
_type: 'view',
|
|
10
|
+
name,
|
|
11
|
+
definition: definition.trim(),
|
|
12
|
+
isMaterialized: false,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function pgMaterializedView(name, definition, options) {
|
|
16
|
+
return {
|
|
17
|
+
_type: 'materialized_view',
|
|
18
|
+
name,
|
|
19
|
+
definition: definition.trim(),
|
|
20
|
+
isMaterialized: true,
|
|
21
|
+
withData: options?.withData,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function viewToSQL(view) {
|
|
25
|
+
return `CREATE OR REPLACE VIEW "${view.name}" AS\n${view.definition};`;
|
|
26
|
+
}
|
|
27
|
+
function materializedViewToSQL(view) {
|
|
28
|
+
const withData = view.withData !== false ? ' WITH DATA' : ' WITH NO DATA';
|
|
29
|
+
return `CREATE MATERIALIZED VIEW IF NOT EXISTS "${view.name}" AS\n${view.definition}${withData};`;
|
|
30
|
+
}
|
|
@@ -43,6 +43,9 @@ function createColumnExpr(colName) {
|
|
|
43
43
|
neq(value) {
|
|
44
44
|
return whereCondition(`${this.$sql} != ${formatWhereValue(value)}`);
|
|
45
45
|
},
|
|
46
|
+
ne(value) {
|
|
47
|
+
return whereCondition(`${this.$sql} <> ${formatWhereValue(value)}`);
|
|
48
|
+
},
|
|
46
49
|
gt(value) {
|
|
47
50
|
return whereCondition(`${this.$sql} > ${formatWhereValue(value)}`);
|
|
48
51
|
},
|
|
@@ -177,6 +180,9 @@ function createCheckExpr(sql) {
|
|
|
177
180
|
neq(value) {
|
|
178
181
|
return createCheckWhereCondition(`${this.$sql} != ${formatVal(value)}`);
|
|
179
182
|
},
|
|
183
|
+
ne(value) {
|
|
184
|
+
return createCheckWhereCondition(`${this.$sql} <> ${formatVal(value)}`);
|
|
185
|
+
},
|
|
180
186
|
isNull() {
|
|
181
187
|
return createCheckWhereCondition(`${this.$sql} IS NULL`);
|
|
182
188
|
},
|
|
@@ -261,6 +267,53 @@ function createCheckConstraintBuilder() {
|
|
|
261
267
|
constraint(name, condition) {
|
|
262
268
|
return { name, expression: condition.$sql };
|
|
263
269
|
},
|
|
270
|
+
raw(expression) {
|
|
271
|
+
return createCheckWhereCondition(expression);
|
|
272
|
+
},
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function createConstraintBuilder() {
|
|
276
|
+
return {
|
|
277
|
+
primaryKey(...args) {
|
|
278
|
+
if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null && 'columns' in args[0]) {
|
|
279
|
+
const opts = args[0];
|
|
280
|
+
return {
|
|
281
|
+
$type: 'PRIMARY KEY',
|
|
282
|
+
$name: opts.name || '',
|
|
283
|
+
$columns: opts.columns.map(c => String(c)),
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
const columns = args;
|
|
287
|
+
return {
|
|
288
|
+
$type: 'PRIMARY KEY',
|
|
289
|
+
$name: '',
|
|
290
|
+
$columns: columns.map(c => String(c)),
|
|
291
|
+
};
|
|
292
|
+
},
|
|
293
|
+
unique(...args) {
|
|
294
|
+
if (args.length === 1 && typeof args[0] === 'object' && args[0] !== null && 'columns' in args[0]) {
|
|
295
|
+
const opts = args[0];
|
|
296
|
+
return {
|
|
297
|
+
$type: 'UNIQUE',
|
|
298
|
+
$name: opts.name || '',
|
|
299
|
+
$columns: opts.columns.map(c => String(c)),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
const columns = args;
|
|
303
|
+
return {
|
|
304
|
+
$type: 'UNIQUE',
|
|
305
|
+
$name: '',
|
|
306
|
+
$columns: columns.map(c => String(c)),
|
|
307
|
+
};
|
|
308
|
+
},
|
|
309
|
+
exclude(name, expression) {
|
|
310
|
+
return {
|
|
311
|
+
$type: 'EXCLUDE',
|
|
312
|
+
$name: name,
|
|
313
|
+
$columns: [],
|
|
314
|
+
$expression: expression,
|
|
315
|
+
};
|
|
316
|
+
},
|
|
264
317
|
};
|
|
265
318
|
}
|
|
266
319
|
function createColumnRefs(columns) {
|
|
@@ -272,6 +325,15 @@ function createColumnRefs(columns) {
|
|
|
272
325
|
}
|
|
273
326
|
return refs;
|
|
274
327
|
}
|
|
328
|
+
function createIndexTableRefs(columns) {
|
|
329
|
+
const refs = {};
|
|
330
|
+
for (const key of Object.keys(columns)) {
|
|
331
|
+
const col = columns[key];
|
|
332
|
+
const colName = col.$columnName || key;
|
|
333
|
+
refs[key] = createColumnExpr(colName);
|
|
334
|
+
}
|
|
335
|
+
return refs;
|
|
336
|
+
}
|
|
275
337
|
function createIndexFactory() {
|
|
276
338
|
const factory = (name) => {
|
|
277
339
|
const def = {
|
|
@@ -331,6 +393,22 @@ function createIndexFactory() {
|
|
|
331
393
|
def._opclass = opclass;
|
|
332
394
|
return Object.assign(this, { _opclass: opclass });
|
|
333
395
|
},
|
|
396
|
+
ifNotExists() {
|
|
397
|
+
def.ifNotExists = true;
|
|
398
|
+
return Object.assign(this, { ifNotExists: true });
|
|
399
|
+
},
|
|
400
|
+
tableOnly() {
|
|
401
|
+
def.tableOnly = true;
|
|
402
|
+
return Object.assign(this, { tableOnly: true });
|
|
403
|
+
},
|
|
404
|
+
comment(text) {
|
|
405
|
+
def.comment = text;
|
|
406
|
+
return Object.assign(this, { comment: text });
|
|
407
|
+
},
|
|
408
|
+
$id(trackingId) {
|
|
409
|
+
def.trackingId = trackingId;
|
|
410
|
+
return Object.assign(this, { trackingId: trackingId });
|
|
411
|
+
},
|
|
334
412
|
};
|
|
335
413
|
return {
|
|
336
414
|
on(...columns) {
|
|
@@ -354,10 +432,11 @@ function createIndexFactory() {
|
|
|
354
432
|
const indexFactory = createIndexFactory();
|
|
355
433
|
function defineTable(name, columns, options) {
|
|
356
434
|
const columnRefs = createColumnRefs(columns);
|
|
435
|
+
const indexTableRefs = createIndexTableRefs(columns);
|
|
357
436
|
let resolvedIndexes;
|
|
358
437
|
if (options?.indexes) {
|
|
359
438
|
if (typeof options.indexes === 'function') {
|
|
360
|
-
const rawIndexes = options.indexes(
|
|
439
|
+
const rawIndexes = options.indexes(indexTableRefs, indexFactory, sql_expressions_1.sqlFunctions);
|
|
361
440
|
resolvedIndexes = rawIndexes.map(normalizeIndexDef);
|
|
362
441
|
}
|
|
363
442
|
else {
|
|
@@ -375,6 +454,11 @@ function defineTable(name, columns, options) {
|
|
|
375
454
|
const constraints = options.checkConstraints(checkTableRefs, checkBuilder);
|
|
376
455
|
resolvedCheckConstraints = constraints.map(c => ({ expression: c.expression, name: c.name }));
|
|
377
456
|
}
|
|
457
|
+
let resolvedConstraints;
|
|
458
|
+
if (options?.constraints) {
|
|
459
|
+
const constraintBuilder = createConstraintBuilder();
|
|
460
|
+
resolvedConstraints = options.constraints(columnRefs, constraintBuilder);
|
|
461
|
+
}
|
|
378
462
|
const definition = {
|
|
379
463
|
$name: name,
|
|
380
464
|
$schema: options?.schema,
|
|
@@ -382,12 +466,14 @@ function defineTable(name, columns, options) {
|
|
|
382
466
|
$primaryKey: options?.primaryKey,
|
|
383
467
|
$uniqueConstraints: options?.uniqueConstraints,
|
|
384
468
|
$checkConstraints: resolvedCheckConstraints,
|
|
469
|
+
$constraints: resolvedConstraints,
|
|
385
470
|
$foreignKeys: options?.foreignKeys,
|
|
386
471
|
$indexes: resolvedIndexes,
|
|
387
472
|
$inherits: options?.inherits,
|
|
388
473
|
$partitionBy: resolvedPartitionBy,
|
|
389
474
|
$tablespace: options?.tablespace,
|
|
390
475
|
$withOptions: options?.withOptions,
|
|
476
|
+
$ifNotExists: options?.ifNotExists,
|
|
391
477
|
$inferSelect: {},
|
|
392
478
|
$inferInsert: {},
|
|
393
479
|
toSQL() {
|
|
@@ -416,13 +502,16 @@ function normalizeIndexDef(idx) {
|
|
|
416
502
|
nulls: idx.nulls,
|
|
417
503
|
order: idx.order,
|
|
418
504
|
include: idx.include,
|
|
505
|
+
ifNotExists: idx.ifNotExists,
|
|
506
|
+
tableOnly: idx.tableOnly,
|
|
419
507
|
};
|
|
420
508
|
}
|
|
421
509
|
function generateCreateTableSQL(def) {
|
|
422
510
|
const tableName = def.$schema
|
|
423
511
|
? `${pg_format_1.default.ident(def.$schema)}.${pg_format_1.default.ident(def.$name)}`
|
|
424
512
|
: pg_format_1.default.ident(def.$name);
|
|
425
|
-
const
|
|
513
|
+
const ifNotExistsClause = def.$ifNotExists ? 'IF NOT EXISTS ' : '';
|
|
514
|
+
const parts = [`CREATE TABLE ${ifNotExistsClause}${tableName} (`];
|
|
426
515
|
const columnDefs = [];
|
|
427
516
|
const constraints = [];
|
|
428
517
|
for (const [colName, colConfig] of Object.entries(def.$columns)) {
|
|
@@ -456,6 +545,12 @@ function generateCreateTableSQL(def) {
|
|
|
456
545
|
}
|
|
457
546
|
}
|
|
458
547
|
}
|
|
548
|
+
if (def.$constraints) {
|
|
549
|
+
for (const c of def.$constraints) {
|
|
550
|
+
const cols = c.$columns.map(col => pg_format_1.default.ident(col)).join(', ');
|
|
551
|
+
constraints.push(`CONSTRAINT ${pg_format_1.default.ident(c.$name)} ${c.$type} (${cols})`);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
459
554
|
if (def.$foreignKeys) {
|
|
460
555
|
for (const fk of def.$foreignKeys) {
|
|
461
556
|
const cols = fk.columns.map(c => pg_format_1.default.ident(c)).join(', ');
|
|
@@ -517,7 +612,10 @@ function generateColumnSQL(name, config) {
|
|
|
517
612
|
const defaultVal = typeof config.$default === 'function'
|
|
518
613
|
? config.$default()
|
|
519
614
|
: config.$default;
|
|
520
|
-
if (typeof defaultVal === '
|
|
615
|
+
if (typeof defaultVal === 'object' && defaultVal !== null && '$isDefault' in defaultVal && '$sql' in defaultVal) {
|
|
616
|
+
parts.push(`DEFAULT ${defaultVal.$sql}`);
|
|
617
|
+
}
|
|
618
|
+
else if (typeof defaultVal === 'symbol') {
|
|
521
619
|
const symDesc = defaultVal.description || String(defaultVal);
|
|
522
620
|
if (symDesc.includes('emptyObject')) {
|
|
523
621
|
parts.push(`DEFAULT '{}'::jsonb`);
|
|
@@ -593,7 +691,15 @@ function generateIndexSQL(def) {
|
|
|
593
691
|
if (idx.unique) {
|
|
594
692
|
sql += ' UNIQUE';
|
|
595
693
|
}
|
|
596
|
-
sql +=
|
|
694
|
+
sql += ' INDEX';
|
|
695
|
+
if (idx.ifNotExists) {
|
|
696
|
+
sql += ' IF NOT EXISTS';
|
|
697
|
+
}
|
|
698
|
+
sql += ` ${pg_format_1.default.ident(indexName)} ON`;
|
|
699
|
+
if (idx.tableOnly) {
|
|
700
|
+
sql += ' ONLY';
|
|
701
|
+
}
|
|
702
|
+
sql += ` ${tableName}`;
|
|
597
703
|
if (idx.using) {
|
|
598
704
|
sql += ` USING ${idx.using}`;
|
|
599
705
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isPoolingEnabled = isPoolingEnabled;
|
|
4
4
|
exports.toPoolConfig = toPoolConfig;
|
|
5
|
+
exports.isAwsDsqlConfig = isAwsDsqlConfig;
|
|
5
6
|
const pool_defaults_1 = require("../utils/pool-defaults.cjs");
|
|
6
7
|
function isPoolingEnabled(config) {
|
|
7
8
|
return config.pooling !== false;
|
|
@@ -10,18 +11,23 @@ function toPoolConfig(config) {
|
|
|
10
11
|
const smartDefaults = config.disableSmartDefaults
|
|
11
12
|
? { min: 0, max: 10, idleTimeoutMillis: 30000, connectionTimeoutMillis: 0 }
|
|
12
13
|
: (0, pool_defaults_1.mergeWithDefaults)(config.pool);
|
|
14
|
+
const isAws = !!config.aws;
|
|
15
|
+
const host = isAws ? config.aws.hostname : (config.host || 'localhost');
|
|
16
|
+
const port = config.aws?.port ?? config.port ?? 5432;
|
|
17
|
+
const user = config.aws?.user ?? config.user ?? (isAws ? 'admin' : undefined);
|
|
18
|
+
const ssl = isAws ? (config.aws.ssl ?? true) : config.ssl;
|
|
13
19
|
const poolConfig = {
|
|
14
|
-
host
|
|
15
|
-
port
|
|
20
|
+
host,
|
|
21
|
+
port,
|
|
16
22
|
database: config.database,
|
|
17
|
-
user
|
|
23
|
+
user,
|
|
18
24
|
password: config.password,
|
|
19
25
|
min: config.pool?.min ?? smartDefaults.min,
|
|
20
26
|
max: config.pool?.max ?? smartDefaults.max,
|
|
21
27
|
idleTimeoutMillis: config.pool?.idleTimeoutMillis ?? smartDefaults.idleTimeoutMillis,
|
|
22
28
|
connectionTimeoutMillis: config.pool?.connectionTimeoutMillis ?? smartDefaults.connectionTimeoutMillis,
|
|
23
29
|
application_name: config.pool?.application_name,
|
|
24
|
-
ssl: config.pool?.ssl,
|
|
30
|
+
ssl: config.pool?.ssl ?? ssl,
|
|
25
31
|
allowExitOnIdle: true
|
|
26
32
|
};
|
|
27
33
|
if (config.connectionString) {
|
|
@@ -38,3 +44,6 @@ function toPoolConfig(config) {
|
|
|
38
44
|
}
|
|
39
45
|
return poolConfig;
|
|
40
46
|
}
|
|
47
|
+
function isAwsDsqlConfig(config) {
|
|
48
|
+
return !!config.aws?.hostname && !!config.aws?.region;
|
|
49
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getAwsDsqlToken = getAwsDsqlToken;
|
|
37
|
+
exports.clearAwsDsqlToken = clearAwsDsqlToken;
|
|
38
|
+
exports.isAwsDsql = isAwsDsql;
|
|
39
|
+
const node_fs_1 = require("node:fs");
|
|
40
|
+
const node_path_1 = require("node:path");
|
|
41
|
+
const node_os_1 = require("node:os");
|
|
42
|
+
const node_crypto_1 = require("node:crypto");
|
|
43
|
+
const node_constants_1 = require("node:constants");
|
|
44
|
+
const relq_errors_1 = require("../errors/relq-errors.cjs");
|
|
45
|
+
const tokenCache = new Map();
|
|
46
|
+
function getCacheKey(config) {
|
|
47
|
+
const hash = (0, node_crypto_1.createHash)('md5')
|
|
48
|
+
.update(`${config.secretAccessKey ?? ''}-${config.accessKeyId ?? ''}-${config.region}-${config.hostname}`)
|
|
49
|
+
.digest('hex');
|
|
50
|
+
return hash;
|
|
51
|
+
}
|
|
52
|
+
function getTempFolder() {
|
|
53
|
+
return (0, node_path_1.join)((0, node_os_1.tmpdir)(), '.dsql_');
|
|
54
|
+
}
|
|
55
|
+
function isTempFolderAvailable() {
|
|
56
|
+
const tempFolder = getTempFolder();
|
|
57
|
+
try {
|
|
58
|
+
(0, node_fs_1.mkdirSync)(tempFolder, { recursive: true });
|
|
59
|
+
(0, node_fs_1.accessSync)(tempFolder, node_constants_1.F_OK | node_constants_1.R_OK | node_constants_1.W_OK);
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function getFromCache(cacheKey) {
|
|
67
|
+
const memoryToken = tokenCache.get(cacheKey);
|
|
68
|
+
if (memoryToken && memoryToken.expiresAt > Date.now()) {
|
|
69
|
+
return memoryToken;
|
|
70
|
+
}
|
|
71
|
+
const envName = `DSQL_TOKEN_${cacheKey}`;
|
|
72
|
+
const envToken = process.env[envName];
|
|
73
|
+
if (envToken) {
|
|
74
|
+
try {
|
|
75
|
+
const parsed = JSON.parse(envToken);
|
|
76
|
+
if (parsed.expiresAt > Date.now()) {
|
|
77
|
+
tokenCache.set(cacheKey, parsed);
|
|
78
|
+
return parsed;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch { }
|
|
82
|
+
}
|
|
83
|
+
if (isTempFolderAvailable()) {
|
|
84
|
+
const tokenFile = (0, node_path_1.join)(getTempFolder(), `${cacheKey}.json`);
|
|
85
|
+
if ((0, node_fs_1.existsSync)(tokenFile)) {
|
|
86
|
+
try {
|
|
87
|
+
const parsed = JSON.parse((0, node_fs_1.readFileSync)(tokenFile, 'utf8'));
|
|
88
|
+
if (parsed.expiresAt > Date.now()) {
|
|
89
|
+
tokenCache.set(cacheKey, parsed);
|
|
90
|
+
process.env[envName] = JSON.stringify(parsed);
|
|
91
|
+
return parsed;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch { }
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
function saveToCache(cacheKey, token) {
|
|
100
|
+
tokenCache.set(cacheKey, token);
|
|
101
|
+
const envName = `DSQL_TOKEN_${cacheKey}`;
|
|
102
|
+
process.env[envName] = JSON.stringify(token);
|
|
103
|
+
if (isTempFolderAvailable()) {
|
|
104
|
+
const tokenFile = (0, node_path_1.join)(getTempFolder(), `${cacheKey}.json`);
|
|
105
|
+
try {
|
|
106
|
+
(0, node_fs_1.writeFileSync)(tokenFile, JSON.stringify(token));
|
|
107
|
+
}
|
|
108
|
+
catch { }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
let DsqlSigner = null;
|
|
112
|
+
async function loadAwsSdk() {
|
|
113
|
+
if (!DsqlSigner) {
|
|
114
|
+
try {
|
|
115
|
+
const sdk = await Promise.resolve().then(() => __importStar(require('@aws-sdk/dsql-signer')));
|
|
116
|
+
DsqlSigner = sdk.DsqlSigner;
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
throw new relq_errors_1.RelqConfigError('AWS DSQL requires @aws-sdk/dsql-signer package.\n\n' +
|
|
120
|
+
'Install it with:\n' +
|
|
121
|
+
' npm install @aws-sdk/dsql-signer\n' +
|
|
122
|
+
' # or\n' +
|
|
123
|
+
' bun add @aws-sdk/dsql-signer', { field: '@aws-sdk/dsql-signer', value: 'not installed' });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return DsqlSigner;
|
|
127
|
+
}
|
|
128
|
+
async function getAwsDsqlToken(config) {
|
|
129
|
+
const cacheKey = getCacheKey(config);
|
|
130
|
+
const cached = getFromCache(cacheKey);
|
|
131
|
+
if (cached) {
|
|
132
|
+
return cached.token;
|
|
133
|
+
}
|
|
134
|
+
if (!config.useDefaultCredentials && (!config.accessKeyId || !config.secretAccessKey)) {
|
|
135
|
+
throw new relq_errors_1.RelqConfigError('AWS DSQL requires credentials. Either provide accessKeyId + secretAccessKey, ' +
|
|
136
|
+
'or set useDefaultCredentials: true to use AWS credential chain.', { field: 'aws.credentials', value: 'missing' });
|
|
137
|
+
}
|
|
138
|
+
const SignerClass = await loadAwsSdk();
|
|
139
|
+
const expiresIn = config.tokenExpiresIn ?? 604800;
|
|
140
|
+
const signerConfig = {
|
|
141
|
+
hostname: config.hostname,
|
|
142
|
+
region: config.region,
|
|
143
|
+
expiresIn,
|
|
144
|
+
};
|
|
145
|
+
if (!config.useDefaultCredentials) {
|
|
146
|
+
signerConfig.credentials = {
|
|
147
|
+
accessKeyId: config.accessKeyId,
|
|
148
|
+
secretAccessKey: config.secretAccessKey,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
const signer = new SignerClass(signerConfig);
|
|
152
|
+
const token = await signer.getDbConnectAdminAuthToken();
|
|
153
|
+
const cachedToken = {
|
|
154
|
+
token,
|
|
155
|
+
expiresAt: Date.now() + ((expiresIn - 30) * 1000)
|
|
156
|
+
};
|
|
157
|
+
saveToCache(cacheKey, cachedToken);
|
|
158
|
+
return token;
|
|
159
|
+
}
|
|
160
|
+
function clearAwsDsqlToken(config) {
|
|
161
|
+
const cacheKey = getCacheKey(config);
|
|
162
|
+
tokenCache.delete(cacheKey);
|
|
163
|
+
const envName = `DSQL_TOKEN_${cacheKey}`;
|
|
164
|
+
delete process.env[envName];
|
|
165
|
+
if (isTempFolderAvailable()) {
|
|
166
|
+
const tokenFile = (0, node_path_1.join)(getTempFolder(), `${cacheKey}.json`);
|
|
167
|
+
try {
|
|
168
|
+
if ((0, node_fs_1.existsSync)(tokenFile)) {
|
|
169
|
+
(0, node_fs_1.writeFileSync)(tokenFile, '');
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch { }
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function isAwsDsql(config) {
|
|
176
|
+
return !!config.aws?.hostname && !!config.aws?.region;
|
|
177
|
+
}
|