@anthonyalayo/drizzle-kit 1.0.1
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/.gitignore +25 -0
- package/README.md +79 -0
- package/build.dev.ts +51 -0
- package/build.ts +112 -0
- package/imports-checker/analyze.ts +78 -0
- package/imports-checker/checker.ts +296 -0
- package/imports-checker/grammar/grammar.ohm +121 -0
- package/imports-checker/grammar/grammar.ohm-bundle.d.ts +164 -0
- package/imports-checker/grammar/grammar.ohm-bundle.js +753 -0
- package/imports-checker/index.ts +48 -0
- package/package.json +142 -0
- package/patches/difflib@0.2.4.patch +31 -0
- package/src/@types/utils.ts +58 -0
- package/src/api.ts +504 -0
- package/src/cli/commands/_es5.ts +2 -0
- package/src/cli/commands/check.ts +52 -0
- package/src/cli/commands/drop.ts +60 -0
- package/src/cli/commands/introspect.ts +772 -0
- package/src/cli/commands/libSqlPushUtils.ts +355 -0
- package/src/cli/commands/migrate.ts +1526 -0
- package/src/cli/commands/mysqlIntrospect.ts +53 -0
- package/src/cli/commands/mysqlPushUtils.ts +352 -0
- package/src/cli/commands/mysqlUp.ts +102 -0
- package/src/cli/commands/pgIntrospect.ts +55 -0
- package/src/cli/commands/pgPushUtils.ts +269 -0
- package/src/cli/commands/pgUp.ts +217 -0
- package/src/cli/commands/push.ts +637 -0
- package/src/cli/commands/singlestoreIntrospect.ts +53 -0
- package/src/cli/commands/singlestorePushUtils.ts +456 -0
- package/src/cli/commands/singlestoreUp.ts +1 -0
- package/src/cli/commands/sqliteIntrospect.ts +96 -0
- package/src/cli/commands/sqlitePushUtils.ts +322 -0
- package/src/cli/commands/sqliteUp.ts +52 -0
- package/src/cli/commands/utils.ts +858 -0
- package/src/cli/connections.ts +914 -0
- package/src/cli/index.ts +48 -0
- package/src/cli/schema.ts +794 -0
- package/src/cli/selector-ui.ts +38 -0
- package/src/cli/utils.ts +112 -0
- package/src/cli/validations/cli.ts +79 -0
- package/src/cli/validations/common.ts +193 -0
- package/src/cli/validations/libsql.ts +27 -0
- package/src/cli/validations/mysql.ts +61 -0
- package/src/cli/validations/outputs.ts +91 -0
- package/src/cli/validations/postgres.ts +83 -0
- package/src/cli/validations/singlestore.ts +61 -0
- package/src/cli/validations/sqlite.ts +104 -0
- package/src/cli/validations/studio.ts +24 -0
- package/src/cli/views.ts +658 -0
- package/src/extensions/getTablesFilterByExtensions.ts +16 -0
- package/src/extensions/vector.ts +10 -0
- package/src/global.ts +61 -0
- package/src/index.ts +326 -0
- package/src/introspect-mysql.ts +1030 -0
- package/src/introspect-pg.ts +1435 -0
- package/src/introspect-singlestore.ts +913 -0
- package/src/introspect-sqlite.ts +533 -0
- package/src/jsonDiffer.js +882 -0
- package/src/jsonStatements.ts +3590 -0
- package/src/loader.mjs +57 -0
- package/src/migrationPreparator.ts +217 -0
- package/src/schemaValidator.ts +23 -0
- package/src/serializer/index.ts +142 -0
- package/src/serializer/mysqlImports.ts +38 -0
- package/src/serializer/mysqlSchema.ts +423 -0
- package/src/serializer/mysqlSerializer.ts +999 -0
- package/src/serializer/pgImports.ts +106 -0
- package/src/serializer/pgSchema.ts +937 -0
- package/src/serializer/pgSerializer.ts +2223 -0
- package/src/serializer/singlestoreImports.ts +38 -0
- package/src/serializer/singlestoreSchema.ts +257 -0
- package/src/serializer/singlestoreSerializer.ts +767 -0
- package/src/serializer/sqliteImports.ts +41 -0
- package/src/serializer/sqliteSchema.ts +352 -0
- package/src/serializer/sqliteSerializer.ts +931 -0
- package/src/serializer/studio.ts +694 -0
- package/src/serializer/utils.ts +45 -0
- package/src/simulator.ts +157 -0
- package/src/snapshotsDiffer.ts +4398 -0
- package/src/sqlgenerator.ts +4212 -0
- package/src/statementCombiner.ts +597 -0
- package/src/utils/certs.ts +44 -0
- package/src/utils/words.ts +1333 -0
- package/src/utils.ts +370 -0
- package/tests/bin.test.ts +58 -0
- package/tests/cli/d1http.config.ts +12 -0
- package/tests/cli/drizzle.config.ts +9 -0
- package/tests/cli/durable-sqlite.config.ts +7 -0
- package/tests/cli/expo.config.ts +7 -0
- package/tests/cli/postgres.config.ts +13 -0
- package/tests/cli/postgres2.config.ts +17 -0
- package/tests/cli/schema.ts +1 -0
- package/tests/cli/turso.config.ts +10 -0
- package/tests/cli-export.test.ts +79 -0
- package/tests/cli-generate.test.ts +259 -0
- package/tests/cli-migrate.test.ts +103 -0
- package/tests/cli-push.test.ts +126 -0
- package/tests/common.ts +15 -0
- package/tests/indexes/common.ts +21 -0
- package/tests/indexes/pg.test.ts +245 -0
- package/tests/introspect/libsql.test.ts +35 -0
- package/tests/introspect/mysql.test.ts +319 -0
- package/tests/introspect/pg.test.ts +894 -0
- package/tests/introspect/singlestore.test.ts +275 -0
- package/tests/introspect/sqlite.test.ts +122 -0
- package/tests/libsql-checks.test.ts +308 -0
- package/tests/libsql-statements.test.ts +989 -0
- package/tests/libsql-views.test.ts +218 -0
- package/tests/migrate/libsq-schema.ts +6 -0
- package/tests/migrate/libsql-migrate.test.ts +58 -0
- package/tests/migrate/migrations/0000_little_blizzard.sql +4 -0
- package/tests/migrate/migrations/0001_nebulous_storm.sql +10 -0
- package/tests/migrate/migrations/meta/0000_snapshot.json +40 -0
- package/tests/migrate/migrations/meta/0001_snapshot.json +40 -0
- package/tests/migrate/migrations/meta/_journal.json +20 -0
- package/tests/mysql-checks.test.ts +291 -0
- package/tests/mysql-generated.test.ts +1290 -0
- package/tests/mysql-schemas.test.ts +156 -0
- package/tests/mysql-views.test.ts +553 -0
- package/tests/mysql.test.ts +863 -0
- package/tests/pg-array.test.ts +368 -0
- package/tests/pg-checks.test.ts +329 -0
- package/tests/pg-columns.test.ts +484 -0
- package/tests/pg-domains.test.ts +306 -0
- package/tests/pg-enums.test.ts +751 -0
- package/tests/pg-generated.test.ts +529 -0
- package/tests/pg-identity.test.ts +447 -0
- package/tests/pg-schemas.test.ts +105 -0
- package/tests/pg-sequences.test.ts +298 -0
- package/tests/pg-tables.test.ts +1021 -0
- package/tests/pg-views.test.ts +1929 -0
- package/tests/push/common.ts +58 -0
- package/tests/push/libsql.test.ts +1400 -0
- package/tests/push/mysql-push.test.ts +345 -0
- package/tests/push/mysql.test.ts +788 -0
- package/tests/push/pg.test.ts +4341 -0
- package/tests/push/singlestore-push.test.ts +894 -0
- package/tests/push/singlestore.test.ts +444 -0
- package/tests/push/sqlite.test.ts +1613 -0
- package/tests/rls/pg-policy.test.ts +1656 -0
- package/tests/rls/pg-role.test.ts +234 -0
- package/tests/schemaDiffer.ts +2852 -0
- package/tests/singlestore-generated.test.ts +1290 -0
- package/tests/singlestore-schemas.test.ts +155 -0
- package/tests/singlestore.test.ts +978 -0
- package/tests/sqlite-checks.test.ts +308 -0
- package/tests/sqlite-columns.test.ts +1049 -0
- package/tests/sqlite-generated.test.ts +1726 -0
- package/tests/sqlite-tables.test.ts +637 -0
- package/tests/sqlite-views.test.ts +218 -0
- package/tests/statements-combiner/libsql-statements-combiner.test.ts +1812 -0
- package/tests/statements-combiner/singlestore-statements-combiner.test.ts +882 -0
- package/tests/statements-combiner/sqlite-statements-combiner.test.ts +1211 -0
- package/tests/test/sqlite.test.ts +39 -0
- package/tests/testsinglestore.ts +29 -0
- package/tests/validations.test.ts +869 -0
- package/tests/wrap-param.test.ts +16 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.cli-types.json +9 -0
- package/tsconfig.json +28 -0
- package/vitest.config.ts +34 -0
|
@@ -0,0 +1,1435 @@
|
|
|
1
|
+
import { getTableName, is } from 'drizzle-orm';
|
|
2
|
+
import { AnyPgTable } from 'drizzle-orm/pg-core';
|
|
3
|
+
import {
|
|
4
|
+
createTableRelationsHelpers,
|
|
5
|
+
extractTablesRelationalConfig,
|
|
6
|
+
Many,
|
|
7
|
+
One,
|
|
8
|
+
Relation,
|
|
9
|
+
Relations,
|
|
10
|
+
} from 'drizzle-orm/relations';
|
|
11
|
+
import './@types/utils';
|
|
12
|
+
import { toCamelCase } from 'drizzle-orm/casing';
|
|
13
|
+
import { Casing } from './cli/validations/common';
|
|
14
|
+
import { assertUnreachable } from './global';
|
|
15
|
+
import {
|
|
16
|
+
CheckConstraint,
|
|
17
|
+
Column,
|
|
18
|
+
ForeignKey,
|
|
19
|
+
Index,
|
|
20
|
+
PgKitInternals,
|
|
21
|
+
PgSchemaInternal,
|
|
22
|
+
Policy,
|
|
23
|
+
PrimaryKey,
|
|
24
|
+
UniqueConstraint,
|
|
25
|
+
} from './serializer/pgSchema';
|
|
26
|
+
import { indexName } from './serializer/pgSerializer';
|
|
27
|
+
import { unescapeSingleQuotes } from './utils';
|
|
28
|
+
|
|
29
|
+
const pgImportsList = new Set([
|
|
30
|
+
'pgTable',
|
|
31
|
+
'pgEnum',
|
|
32
|
+
'smallint',
|
|
33
|
+
'integer',
|
|
34
|
+
'bigint',
|
|
35
|
+
'boolean',
|
|
36
|
+
'text',
|
|
37
|
+
'varchar',
|
|
38
|
+
'char',
|
|
39
|
+
'serial',
|
|
40
|
+
'smallserial',
|
|
41
|
+
'bigserial',
|
|
42
|
+
'decimal',
|
|
43
|
+
'numeric',
|
|
44
|
+
'real',
|
|
45
|
+
'json',
|
|
46
|
+
'jsonb',
|
|
47
|
+
'time',
|
|
48
|
+
'timestamp',
|
|
49
|
+
'date',
|
|
50
|
+
'interval',
|
|
51
|
+
'cidr',
|
|
52
|
+
'inet',
|
|
53
|
+
'macaddr',
|
|
54
|
+
'macaddr8',
|
|
55
|
+
'bigint',
|
|
56
|
+
'doublePrecision',
|
|
57
|
+
'uuid',
|
|
58
|
+
'vector',
|
|
59
|
+
'point',
|
|
60
|
+
'line',
|
|
61
|
+
'geometry',
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
const objToStatement2 = (json: { [s: string]: unknown }) => {
|
|
65
|
+
json = Object.fromEntries(Object.entries(json).filter((it) => it[1]));
|
|
66
|
+
|
|
67
|
+
const keys = Object.keys(json);
|
|
68
|
+
if (keys.length === 0) return;
|
|
69
|
+
|
|
70
|
+
let statement = '{ ';
|
|
71
|
+
statement += keys.map((it) => `${it}: "${json[it]}"`).join(', '); // no "" for keys
|
|
72
|
+
statement += ' }';
|
|
73
|
+
return statement;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const timeConfig = (json: { [s: string]: unknown }) => {
|
|
77
|
+
json = Object.fromEntries(Object.entries(json).filter((it) => it[1]));
|
|
78
|
+
|
|
79
|
+
const keys = Object.keys(json);
|
|
80
|
+
if (keys.length === 0) return;
|
|
81
|
+
|
|
82
|
+
let statement = '{ ';
|
|
83
|
+
statement += keys.map((it) => `${it}: ${json[it]}`).join(', ');
|
|
84
|
+
statement += ' }';
|
|
85
|
+
return statement;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const possibleIntervals = [
|
|
89
|
+
'year',
|
|
90
|
+
'month',
|
|
91
|
+
'day',
|
|
92
|
+
'hour',
|
|
93
|
+
'minute',
|
|
94
|
+
'second',
|
|
95
|
+
'year to month',
|
|
96
|
+
'day to hour',
|
|
97
|
+
'day to minute',
|
|
98
|
+
'day to second',
|
|
99
|
+
'hour to minute',
|
|
100
|
+
'hour to second',
|
|
101
|
+
'minute to second',
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
const intervalStrToObj = (str: string) => {
|
|
105
|
+
if (str.startsWith('interval(')) {
|
|
106
|
+
return {
|
|
107
|
+
precision: Number(str.substring('interval('.length, str.length - 1)),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
const splitted = str.split(' ');
|
|
111
|
+
if (splitted.length === 1) {
|
|
112
|
+
return {};
|
|
113
|
+
}
|
|
114
|
+
const rest = splitted.slice(1, splitted.length).join(' ');
|
|
115
|
+
if (possibleIntervals.includes(rest)) {
|
|
116
|
+
return { fields: `"${rest}"` };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
for (const s of possibleIntervals) {
|
|
120
|
+
if (rest.startsWith(`${s}(`)) {
|
|
121
|
+
return {
|
|
122
|
+
fields: `"${s}"`,
|
|
123
|
+
precision: Number(rest.substring(s.length + 1, rest.length - 1)),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return {};
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const intervalConfig = (str: string) => {
|
|
131
|
+
const json = intervalStrToObj(str);
|
|
132
|
+
// json = Object.fromEntries(Object.entries(json).filter((it) => it[1]));
|
|
133
|
+
|
|
134
|
+
const keys = Object.keys(json);
|
|
135
|
+
if (keys.length === 0) return;
|
|
136
|
+
|
|
137
|
+
let statement = '{ ';
|
|
138
|
+
statement += keys.map((it: keyof typeof json) => `${it}: ${json[it]}`).join(', ');
|
|
139
|
+
statement += ' }';
|
|
140
|
+
return statement;
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const mapColumnDefault = (defaultValue: any, isExpression?: boolean) => {
|
|
144
|
+
if (isExpression) {
|
|
145
|
+
return `sql\`${defaultValue}\``;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return defaultValue;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const importsPatch = {
|
|
152
|
+
'double precision': 'doublePrecision',
|
|
153
|
+
'timestamp without time zone': 'timestamp',
|
|
154
|
+
'timestamp with time zone': 'timestamp',
|
|
155
|
+
'time without time zone': 'time',
|
|
156
|
+
'time with time zone': 'time',
|
|
157
|
+
} as Record<string, string>;
|
|
158
|
+
|
|
159
|
+
const relations = new Set<string>();
|
|
160
|
+
|
|
161
|
+
const escapeColumnKey = (value: string) => {
|
|
162
|
+
if (/^(?![a-zA-Z_$][a-zA-Z0-9_$]*$).+$/.test(value)) {
|
|
163
|
+
return `"${value}"`;
|
|
164
|
+
}
|
|
165
|
+
return value;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const withCasing = (value: string, casing: Casing) => {
|
|
169
|
+
if (casing === 'preserve') {
|
|
170
|
+
return escapeColumnKey(value);
|
|
171
|
+
}
|
|
172
|
+
if (casing === 'camel') {
|
|
173
|
+
return escapeColumnKey(value.camelCase());
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
assertUnreachable(casing);
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const dbColumnName = ({ name, casing, withMode = false }: { name: string; casing: Casing; withMode?: boolean }) => {
|
|
180
|
+
if (casing === 'preserve') {
|
|
181
|
+
return '';
|
|
182
|
+
}
|
|
183
|
+
if (casing === 'camel') {
|
|
184
|
+
return toCamelCase(name) === name ? '' : withMode ? `"${name}", ` : `"${name}"`;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
assertUnreachable(casing);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
export const relationsToTypeScriptForStudio = (
|
|
191
|
+
schema: Record<string, Record<string, AnyPgTable<{}>>>,
|
|
192
|
+
relations: Record<string, Relations<string, Record<string, Relation<string>>>>,
|
|
193
|
+
) => {
|
|
194
|
+
const relationalSchema: Record<string, unknown> = {
|
|
195
|
+
...Object.fromEntries(
|
|
196
|
+
Object.entries(schema)
|
|
197
|
+
.map(([key, val]) => {
|
|
198
|
+
// have unique keys across schemas
|
|
199
|
+
const mappedTableEntries = Object.entries(val).map((tableEntry) => {
|
|
200
|
+
return [`__${key}__.${tableEntry[0]}`, tableEntry[1]];
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
return mappedTableEntries;
|
|
204
|
+
})
|
|
205
|
+
.flat(),
|
|
206
|
+
),
|
|
207
|
+
...relations,
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const relationsConfig = extractTablesRelationalConfig(relationalSchema, createTableRelationsHelpers);
|
|
211
|
+
|
|
212
|
+
let result = '';
|
|
213
|
+
|
|
214
|
+
function findColumnKey(table: AnyPgTable, columnName: string) {
|
|
215
|
+
for (const tableEntry of Object.entries(table)) {
|
|
216
|
+
const key = tableEntry[0];
|
|
217
|
+
const value = tableEntry[1];
|
|
218
|
+
|
|
219
|
+
if (value.name === columnName) {
|
|
220
|
+
return key;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
Object.values(relationsConfig.tables).forEach((table) => {
|
|
226
|
+
const tableName = table.tsName.split('.')[1];
|
|
227
|
+
const relations = table.relations;
|
|
228
|
+
let hasRelations = false;
|
|
229
|
+
let relationsObjAsStr = '';
|
|
230
|
+
let hasOne = false;
|
|
231
|
+
let hasMany = false;
|
|
232
|
+
|
|
233
|
+
Object.values(relations).forEach((relation) => {
|
|
234
|
+
hasRelations = true;
|
|
235
|
+
|
|
236
|
+
if (is(relation, Many)) {
|
|
237
|
+
hasMany = true;
|
|
238
|
+
relationsObjAsStr += `\t\t${relation.fieldName}: many(${
|
|
239
|
+
relationsConfig.tableNamesMap[relation.referencedTableName].split('.')[1]
|
|
240
|
+
}${typeof relation.relationName !== 'undefined' ? `, { relationName: "${relation.relationName}"}` : ''}),`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (is(relation, One)) {
|
|
244
|
+
hasOne = true;
|
|
245
|
+
relationsObjAsStr += `\t\t${relation.fieldName}: one(${
|
|
246
|
+
relationsConfig.tableNamesMap[relation.referencedTableName].split('.')[1]
|
|
247
|
+
}, { fields: [${
|
|
248
|
+
relation.config?.fields.map(
|
|
249
|
+
(c) =>
|
|
250
|
+
`${relationsConfig.tableNamesMap[getTableName(relation.sourceTable)].split('.')[1]}.${
|
|
251
|
+
findColumnKey(relation.sourceTable, c.name)
|
|
252
|
+
}`,
|
|
253
|
+
)
|
|
254
|
+
}], references: [${
|
|
255
|
+
relation.config?.references.map(
|
|
256
|
+
(c) =>
|
|
257
|
+
`${relationsConfig.tableNamesMap[getTableName(relation.referencedTable)].split('.')[1]}.${
|
|
258
|
+
findColumnKey(relation.referencedTable, c.name)
|
|
259
|
+
}`,
|
|
260
|
+
)
|
|
261
|
+
}]${typeof relation.relationName !== 'undefined' ? `, relationName: "${relation.relationName}"` : ''}}),`;
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
if (hasRelations) {
|
|
266
|
+
result += `export const ${tableName}Relation = relations(${tableName}, ({${hasOne ? 'one' : ''}${
|
|
267
|
+
hasOne && hasMany ? ', ' : ''
|
|
268
|
+
}${hasMany ? 'many' : ''}}) => ({
|
|
269
|
+
${relationsObjAsStr}
|
|
270
|
+
}));\n`;
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
return result;
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
function generateIdentityParams(identity: Column['identity']) {
|
|
278
|
+
let paramsObj = `{ name: "${identity!.name}"`;
|
|
279
|
+
if (identity?.startWith) {
|
|
280
|
+
paramsObj += `, startWith: ${identity.startWith}`;
|
|
281
|
+
}
|
|
282
|
+
if (identity?.increment) {
|
|
283
|
+
paramsObj += `, increment: ${identity.increment}`;
|
|
284
|
+
}
|
|
285
|
+
if (identity?.minValue) {
|
|
286
|
+
paramsObj += `, minValue: ${identity.minValue}`;
|
|
287
|
+
}
|
|
288
|
+
if (identity?.maxValue) {
|
|
289
|
+
paramsObj += `, maxValue: ${identity.maxValue}`;
|
|
290
|
+
}
|
|
291
|
+
if (identity?.cache) {
|
|
292
|
+
paramsObj += `, cache: ${identity.cache}`;
|
|
293
|
+
}
|
|
294
|
+
if (identity?.cycle) {
|
|
295
|
+
paramsObj += `, cycle: true`;
|
|
296
|
+
}
|
|
297
|
+
paramsObj += ' }';
|
|
298
|
+
if (identity?.type === 'always') {
|
|
299
|
+
return `.generatedAlwaysAsIdentity(${paramsObj})`;
|
|
300
|
+
}
|
|
301
|
+
return `.generatedByDefaultAsIdentity(${paramsObj})`;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export const paramNameFor = (name: string, schema?: string) => {
|
|
305
|
+
const schemaSuffix = schema && schema !== 'public' ? `In${schema.capitalise()}` : '';
|
|
306
|
+
return `${name}${schemaSuffix}`;
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => {
|
|
310
|
+
// collectFKs
|
|
311
|
+
Object.values(schema.tables).forEach((table) => {
|
|
312
|
+
Object.values(table.foreignKeys).forEach((fk) => {
|
|
313
|
+
const relation = `${fk.tableFrom}-${fk.tableTo}`;
|
|
314
|
+
relations.add(relation);
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
const schemas = Object.fromEntries(
|
|
319
|
+
Object.entries(schema.schemas).map((it) => {
|
|
320
|
+
return [it[0], withCasing(it[1], casing)];
|
|
321
|
+
}),
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
const domainTypes = Object.values(schema.domains).reduce((acc, cur) => {
|
|
325
|
+
acc.add(`${cur.schema}.${cur.name}`);
|
|
326
|
+
return acc;
|
|
327
|
+
}, new Set<string>());
|
|
328
|
+
|
|
329
|
+
const enumTypes = Object.values(schema.enums).reduce((acc, cur) => {
|
|
330
|
+
acc.add(`${cur.schema}.${cur.name}`);
|
|
331
|
+
return acc;
|
|
332
|
+
}, new Set<string>());
|
|
333
|
+
|
|
334
|
+
const imports = Object.values(schema.tables).reduce(
|
|
335
|
+
(res, it) => {
|
|
336
|
+
const idxImports = Object.values(it.indexes).map((idx) => (idx.isUnique ? 'uniqueIndex' : 'index'));
|
|
337
|
+
const fkImpots = Object.values(it.foreignKeys).map((it) => 'foreignKey');
|
|
338
|
+
if (Object.values(it.foreignKeys).some((it) => isCyclic(it) && !isSelf(it))) {
|
|
339
|
+
res.pg.push('type AnyPgColumn');
|
|
340
|
+
}
|
|
341
|
+
const pkImports = Object.values(it.compositePrimaryKeys).map((it) => 'primaryKey');
|
|
342
|
+
const uniqueImports = Object.values(it.uniqueConstraints).map((it) => 'unique');
|
|
343
|
+
|
|
344
|
+
const checkImports = Object.values(it.checkConstraints).map(
|
|
345
|
+
(it) => 'check',
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
const policiesImports = Object.values(it.policies).map(
|
|
349
|
+
(it) => 'pgPolicy',
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
if (it.schema && it.schema !== 'public' && it.schema !== '') {
|
|
353
|
+
res.pg.push('pgSchema');
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
res.pg.push(...idxImports);
|
|
357
|
+
res.pg.push(...fkImpots);
|
|
358
|
+
res.pg.push(...pkImports);
|
|
359
|
+
res.pg.push(...uniqueImports);
|
|
360
|
+
res.pg.push(...policiesImports);
|
|
361
|
+
res.pg.push(...checkImports);
|
|
362
|
+
|
|
363
|
+
const columnImports = Object.values(it.columns)
|
|
364
|
+
.map((col) => {
|
|
365
|
+
let patched: string = (importsPatch[col.type] || col.type).replace('[]', '');
|
|
366
|
+
patched = patched === 'double precision' ? 'doublePrecision' : patched;
|
|
367
|
+
patched = patched.startsWith('varchar(') ? 'varchar' : patched;
|
|
368
|
+
patched = patched.startsWith('char(') ? 'char' : patched;
|
|
369
|
+
patched = patched.startsWith('numeric(') ? 'numeric' : patched;
|
|
370
|
+
patched = patched.startsWith('time(') ? 'time' : patched;
|
|
371
|
+
patched = patched.startsWith('timestamp(') ? 'timestamp' : patched;
|
|
372
|
+
patched = patched.startsWith('vector(') ? 'vector' : patched;
|
|
373
|
+
patched = patched.startsWith('geometry(') ? 'geometry' : patched;
|
|
374
|
+
return patched;
|
|
375
|
+
})
|
|
376
|
+
.filter((type) => {
|
|
377
|
+
return pgImportsList.has(type);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
res.pg.push(...columnImports);
|
|
381
|
+
return res;
|
|
382
|
+
},
|
|
383
|
+
{ pg: [] as string[] },
|
|
384
|
+
);
|
|
385
|
+
|
|
386
|
+
Object.values(schema.views).forEach((it) => {
|
|
387
|
+
if (it.schema && it.schema !== 'public' && it.schema !== '') {
|
|
388
|
+
imports.pg.push('pgSchema');
|
|
389
|
+
} else if (it.schema === 'public') {
|
|
390
|
+
it.materialized ? imports.pg.push('pgMaterializedView') : imports.pg.push('pgView');
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
Object.values(it.columns).forEach(() => {
|
|
394
|
+
const columnImports = Object.values(it.columns)
|
|
395
|
+
.map((col) => {
|
|
396
|
+
let patched: string = (importsPatch[col.type] || col.type).replace('[]', '');
|
|
397
|
+
patched = patched === 'double precision' ? 'doublePrecision' : patched;
|
|
398
|
+
patched = patched.startsWith('varchar(') ? 'varchar' : patched;
|
|
399
|
+
patched = patched.startsWith('char(') ? 'char' : patched;
|
|
400
|
+
patched = patched.startsWith('numeric(') ? 'numeric' : patched;
|
|
401
|
+
patched = patched.startsWith('time(') ? 'time' : patched;
|
|
402
|
+
patched = patched.startsWith('timestamp(') ? 'timestamp' : patched;
|
|
403
|
+
patched = patched.startsWith('vector(') ? 'vector' : patched;
|
|
404
|
+
patched = patched.startsWith('geometry(') ? 'geometry' : patched;
|
|
405
|
+
return patched;
|
|
406
|
+
})
|
|
407
|
+
.filter((type) => {
|
|
408
|
+
return pgImportsList.has(type);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
imports.pg.push(...columnImports);
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
Object.values(schema.sequences).forEach((it) => {
|
|
416
|
+
if (it.schema && it.schema !== 'public' && it.schema !== '') {
|
|
417
|
+
imports.pg.push('pgSchema');
|
|
418
|
+
} else if (it.schema === 'public') {
|
|
419
|
+
imports.pg.push('pgSequence');
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
Object.values(schema.domains).forEach((it) => {
|
|
424
|
+
if (it.schema && it.schema !== 'public' && it.schema !== '') {
|
|
425
|
+
imports.pg.push('pgSchema');
|
|
426
|
+
} else if (it.schema === 'public') {
|
|
427
|
+
imports.pg.push('pgDomain');
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
Object.values(schema.enums).forEach((it) => {
|
|
432
|
+
if (it.schema && it.schema !== 'public' && it.schema !== '') {
|
|
433
|
+
imports.pg.push('pgSchema');
|
|
434
|
+
} else if (it.schema === 'public') {
|
|
435
|
+
imports.pg.push('pgEnum');
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
if (Object.keys(schema.roles).length > 0) {
|
|
440
|
+
imports.pg.push('pgRole');
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const domainStatements = Object.values(schema.domains)
|
|
444
|
+
.map((it) => {
|
|
445
|
+
const domainSchema = schemas[it.schema];
|
|
446
|
+
const paramName = paramNameFor(it.name, domainSchema);
|
|
447
|
+
const func = domainSchema ? `${domainSchema}.domain` : 'pgDomain';
|
|
448
|
+
|
|
449
|
+
// TODO handle all logic by porting from column() function below
|
|
450
|
+
let type = it.baseType;
|
|
451
|
+
if (type.startsWith('varchar(') && type.length > 7) {
|
|
452
|
+
type = `varchar({ length: ${type.substring(8, type.length - 1)}})`;
|
|
453
|
+
} else {
|
|
454
|
+
type += '()';
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Start with base type function
|
|
458
|
+
let domainChain = `${func}("${it.name}", ${type}`;
|
|
459
|
+
|
|
460
|
+
// Apply chained methods based on properties
|
|
461
|
+
if (it.notNull) {
|
|
462
|
+
domainChain += '.notNull()';
|
|
463
|
+
}
|
|
464
|
+
if (it.defaultValue) {
|
|
465
|
+
domainChain += `.default(${it.defaultValue})`;
|
|
466
|
+
}
|
|
467
|
+
if (it.checkConstraints && Object.keys(it.checkConstraints).length > 0) {
|
|
468
|
+
const checkStmts = Object.entries(it.checkConstraints)
|
|
469
|
+
.map(([, check]) => {
|
|
470
|
+
return `\n\t.checkConstraint('${check.name}', sql\`${check.value}\`)`;
|
|
471
|
+
}).join('');
|
|
472
|
+
domainChain += checkStmts;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Close function chain
|
|
476
|
+
domainChain += ')';
|
|
477
|
+
|
|
478
|
+
return `export const ${withCasing(paramName, casing)} = ${domainChain};\n`;
|
|
479
|
+
})
|
|
480
|
+
.join('\n')
|
|
481
|
+
.concat('\n');
|
|
482
|
+
|
|
483
|
+
const enumStatements = Object.values(schema.enums)
|
|
484
|
+
.map((it) => {
|
|
485
|
+
const enumSchema = schemas[it.schema];
|
|
486
|
+
// const func = schema || schema === "public" ? "pgTable" : schema;
|
|
487
|
+
const paramName = paramNameFor(it.name, enumSchema);
|
|
488
|
+
|
|
489
|
+
const func = enumSchema ? `${enumSchema}.enum` : 'pgEnum';
|
|
490
|
+
|
|
491
|
+
const values = Object.values(it.values)
|
|
492
|
+
.map((it) => `'${unescapeSingleQuotes(it, false)}'`)
|
|
493
|
+
.join(', ');
|
|
494
|
+
return `export const ${withCasing(paramName, casing)} = ${func}("${it.name}", [${values}])\n`;
|
|
495
|
+
})
|
|
496
|
+
.join('')
|
|
497
|
+
.concat('\n');
|
|
498
|
+
|
|
499
|
+
const sequencesStatements = Object.values(schema.sequences)
|
|
500
|
+
.map((it) => {
|
|
501
|
+
const seqSchema = schemas[it.schema];
|
|
502
|
+
const paramName = paramNameFor(it.name, seqSchema);
|
|
503
|
+
|
|
504
|
+
const func = seqSchema ? `${seqSchema}.sequence` : 'pgSequence';
|
|
505
|
+
|
|
506
|
+
let params = '';
|
|
507
|
+
|
|
508
|
+
if (it.startWith) {
|
|
509
|
+
params += `, startWith: "${it.startWith}"`;
|
|
510
|
+
}
|
|
511
|
+
if (it.increment) {
|
|
512
|
+
params += `, increment: "${it.increment}"`;
|
|
513
|
+
}
|
|
514
|
+
if (it.minValue) {
|
|
515
|
+
params += `, minValue: "${it.minValue}"`;
|
|
516
|
+
}
|
|
517
|
+
if (it.maxValue) {
|
|
518
|
+
params += `, maxValue: "${it.maxValue}"`;
|
|
519
|
+
}
|
|
520
|
+
if (it.cache) {
|
|
521
|
+
params += `, cache: "${it.cache}"`;
|
|
522
|
+
}
|
|
523
|
+
if (it.cycle) {
|
|
524
|
+
params += `, cycle: true`;
|
|
525
|
+
} else {
|
|
526
|
+
params += `, cycle: false`;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
return `export const ${withCasing(paramName, casing)} = ${func}("${it.name}"${
|
|
530
|
+
params ? `, { ${params.trimChar(',')} }` : ''
|
|
531
|
+
})\n`;
|
|
532
|
+
})
|
|
533
|
+
.join('')
|
|
534
|
+
.concat('');
|
|
535
|
+
|
|
536
|
+
const schemaStatements = Object.entries(schemas)
|
|
537
|
+
// .filter((it) => it[0] !== "public")
|
|
538
|
+
.map((it) => {
|
|
539
|
+
return `export const ${it[1]} = pgSchema("${it[0]}");\n`;
|
|
540
|
+
})
|
|
541
|
+
.join('');
|
|
542
|
+
|
|
543
|
+
const rolesNameToTsKey: Record<string, string> = {};
|
|
544
|
+
|
|
545
|
+
const rolesStatements = Object.entries(schema.roles)
|
|
546
|
+
.map((it) => {
|
|
547
|
+
const fields = it[1];
|
|
548
|
+
rolesNameToTsKey[fields.name] = it[0];
|
|
549
|
+
return `export const ${withCasing(it[0], casing)} = pgRole("${fields.name}", ${
|
|
550
|
+
!fields.createDb && !fields.createRole && fields.inherit
|
|
551
|
+
? ''
|
|
552
|
+
: `${
|
|
553
|
+
`, { ${fields.createDb ? `createDb: true,` : ''}${fields.createRole ? ` createRole: true,` : ''}${
|
|
554
|
+
!fields.inherit ? ` inherit: false ` : ''
|
|
555
|
+
}`.trimChar(',')
|
|
556
|
+
}}`
|
|
557
|
+
} );\n`;
|
|
558
|
+
})
|
|
559
|
+
.join('');
|
|
560
|
+
|
|
561
|
+
const tableStatements = Object.values(schema.tables).map((table) => {
|
|
562
|
+
const tableSchema = schemas[table.schema];
|
|
563
|
+
const paramName = paramNameFor(table.name, tableSchema);
|
|
564
|
+
|
|
565
|
+
const func = tableSchema ? `${tableSchema}.table` : 'pgTable';
|
|
566
|
+
let statement = `export const ${withCasing(paramName, casing)} = ${func}("${table.name}", {\n`;
|
|
567
|
+
statement += createTableColumns(
|
|
568
|
+
table.name,
|
|
569
|
+
Object.values(table.columns),
|
|
570
|
+
Object.values(table.foreignKeys),
|
|
571
|
+
domainTypes,
|
|
572
|
+
enumTypes,
|
|
573
|
+
schemas,
|
|
574
|
+
casing,
|
|
575
|
+
schema.internal,
|
|
576
|
+
);
|
|
577
|
+
statement += '}';
|
|
578
|
+
|
|
579
|
+
// more than 2 fields or self reference or cyclic
|
|
580
|
+
// Andrii: I switched this one off until we will get custom names in .references()
|
|
581
|
+
// const filteredFKs = Object.values(table.foreignKeys).filter((it) => {
|
|
582
|
+
// return it.columnsFrom.length > 1 || isSelf(it);
|
|
583
|
+
// });
|
|
584
|
+
|
|
585
|
+
if (
|
|
586
|
+
Object.keys(table.indexes).length > 0
|
|
587
|
+
|| Object.values(table.foreignKeys).length > 0
|
|
588
|
+
|| Object.values(table.policies).length > 0
|
|
589
|
+
|| Object.keys(table.compositePrimaryKeys).length > 0
|
|
590
|
+
|| Object.keys(table.uniqueConstraints).length > 0
|
|
591
|
+
|| Object.keys(table.checkConstraints).length > 0
|
|
592
|
+
) {
|
|
593
|
+
statement += ', ';
|
|
594
|
+
statement += '(table) => [';
|
|
595
|
+
statement += createTableIndexes(table.name, Object.values(table.indexes), casing);
|
|
596
|
+
statement += createTableFKs(Object.values(table.foreignKeys), schemas, casing);
|
|
597
|
+
statement += createTablePKs(
|
|
598
|
+
Object.values(table.compositePrimaryKeys),
|
|
599
|
+
casing,
|
|
600
|
+
);
|
|
601
|
+
statement += createTableUniques(
|
|
602
|
+
Object.values(table.uniqueConstraints),
|
|
603
|
+
casing,
|
|
604
|
+
);
|
|
605
|
+
statement += createTablePolicies(
|
|
606
|
+
Object.values(table.policies),
|
|
607
|
+
casing,
|
|
608
|
+
rolesNameToTsKey,
|
|
609
|
+
);
|
|
610
|
+
statement += createTableChecks(
|
|
611
|
+
Object.values(table.checkConstraints),
|
|
612
|
+
casing,
|
|
613
|
+
);
|
|
614
|
+
statement += '\n]';
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
statement += ');';
|
|
618
|
+
return statement;
|
|
619
|
+
});
|
|
620
|
+
|
|
621
|
+
const viewsStatements = Object.values(schema.views)
|
|
622
|
+
.map((it) => {
|
|
623
|
+
const viewSchema = schemas[it.schema];
|
|
624
|
+
|
|
625
|
+
const paramName = paramNameFor(it.name, viewSchema);
|
|
626
|
+
|
|
627
|
+
const func = viewSchema
|
|
628
|
+
? (it.materialized ? `${viewSchema}.materializedView` : `${viewSchema}.view`)
|
|
629
|
+
: it.materialized
|
|
630
|
+
? 'pgMaterializedView'
|
|
631
|
+
: 'pgView';
|
|
632
|
+
|
|
633
|
+
const withOption = it.with ?? '';
|
|
634
|
+
|
|
635
|
+
const as = `sql\`${it.definition}\``;
|
|
636
|
+
|
|
637
|
+
const tablespace = it.tablespace ?? '';
|
|
638
|
+
|
|
639
|
+
const columns = createTableColumns(
|
|
640
|
+
'',
|
|
641
|
+
Object.values(it.columns),
|
|
642
|
+
[],
|
|
643
|
+
domainTypes,
|
|
644
|
+
enumTypes,
|
|
645
|
+
schemas,
|
|
646
|
+
casing,
|
|
647
|
+
schema.internal,
|
|
648
|
+
);
|
|
649
|
+
|
|
650
|
+
let statement = `export const ${withCasing(paramName, casing)} = ${func}("${it.name}", {${columns}})`;
|
|
651
|
+
statement += tablespace ? `.tablespace("${tablespace}")` : '';
|
|
652
|
+
statement += withOption ? `.with(${JSON.stringify(withOption)})` : '';
|
|
653
|
+
statement += `.as(${as});`;
|
|
654
|
+
|
|
655
|
+
return statement;
|
|
656
|
+
})
|
|
657
|
+
.join('\n\n');
|
|
658
|
+
|
|
659
|
+
const uniquePgImports = ['pgTable', ...new Set(imports.pg)];
|
|
660
|
+
|
|
661
|
+
const importsTs = `import { ${
|
|
662
|
+
uniquePgImports.join(
|
|
663
|
+
', ',
|
|
664
|
+
)
|
|
665
|
+
} } from "drizzle-orm/pg-core"
|
|
666
|
+
import { sql } from "drizzle-orm"\n\n`;
|
|
667
|
+
|
|
668
|
+
let decalrations = schemaStatements;
|
|
669
|
+
decalrations += rolesStatements;
|
|
670
|
+
decalrations += domainStatements;
|
|
671
|
+
decalrations += enumStatements;
|
|
672
|
+
decalrations += sequencesStatements;
|
|
673
|
+
decalrations += '\n';
|
|
674
|
+
decalrations += tableStatements.join('\n\n');
|
|
675
|
+
decalrations += '\n';
|
|
676
|
+
decalrations += viewsStatements;
|
|
677
|
+
|
|
678
|
+
const file = importsTs + decalrations;
|
|
679
|
+
|
|
680
|
+
// for drizzle studio query runner
|
|
681
|
+
const schemaEntry = `
|
|
682
|
+
{
|
|
683
|
+
${
|
|
684
|
+
Object.values(schema.tables)
|
|
685
|
+
.map((it) => withCasing(it.name, casing))
|
|
686
|
+
.join(',\n')
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
`;
|
|
690
|
+
|
|
691
|
+
return { file, imports: importsTs, decalrations, schemaEntry };
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
const isCyclic = (fk: ForeignKey) => {
|
|
695
|
+
const key = `${fk.tableFrom}-${fk.tableTo}`;
|
|
696
|
+
const reverse = `${fk.tableTo}-${fk.tableFrom}`;
|
|
697
|
+
return relations.has(key) && relations.has(reverse);
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
const isSelf = (fk: ForeignKey) => {
|
|
701
|
+
return fk.tableFrom === fk.tableTo;
|
|
702
|
+
};
|
|
703
|
+
|
|
704
|
+
const buildArrayDefault = (defaultValue: string, typeName: string): string => {
|
|
705
|
+
if (typeof defaultValue === 'string' && !(defaultValue.startsWith('{') || defaultValue.startsWith("'{"))) {
|
|
706
|
+
return `sql\`${defaultValue}\``;
|
|
707
|
+
}
|
|
708
|
+
defaultValue = defaultValue.substring(2, defaultValue.length - 2);
|
|
709
|
+
return `[${
|
|
710
|
+
defaultValue
|
|
711
|
+
.split(/\s*,\s*/g)
|
|
712
|
+
.map((value) => {
|
|
713
|
+
// if (['integer', 'smallint', 'bigint', 'double precision', 'real'].includes(typeName)) {
|
|
714
|
+
// return value;
|
|
715
|
+
// } else if (typeName === 'interval') {
|
|
716
|
+
// return value.replaceAll('"', "'");
|
|
717
|
+
// } else if (typeName === 'boolean') {
|
|
718
|
+
// return value === 't' ? 'true' : 'false';
|
|
719
|
+
if (typeName === 'json' || typeName === 'jsonb') {
|
|
720
|
+
return value.substring(1, value.length - 1).replaceAll('\\', '');
|
|
721
|
+
}
|
|
722
|
+
return value;
|
|
723
|
+
// }
|
|
724
|
+
})
|
|
725
|
+
.join(', ')
|
|
726
|
+
}]`;
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
const mapDefault = (
|
|
730
|
+
tableName: string,
|
|
731
|
+
type: string,
|
|
732
|
+
name: string,
|
|
733
|
+
enumTypes: Set<string>,
|
|
734
|
+
typeSchema: string,
|
|
735
|
+
defaultValue?: any,
|
|
736
|
+
internals?: PgKitInternals,
|
|
737
|
+
) => {
|
|
738
|
+
const isExpression = internals?.tables[tableName]?.columns[name]?.isDefaultAnExpression ?? false;
|
|
739
|
+
const isArray = internals?.tables[tableName]?.columns[name]?.isArray ?? false;
|
|
740
|
+
const lowered = type.toLowerCase().replace('[]', '');
|
|
741
|
+
|
|
742
|
+
if (isArray) {
|
|
743
|
+
return typeof defaultValue !== 'undefined' ? `.default(${buildArrayDefault(defaultValue, lowered)})` : '';
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
if (enumTypes.has(`${typeSchema}.${type.replace('[]', '')}`)) {
|
|
747
|
+
return typeof defaultValue !== 'undefined'
|
|
748
|
+
? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})`
|
|
749
|
+
: '';
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
if (lowered.startsWith('integer')) {
|
|
753
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
if (lowered.startsWith('smallint')) {
|
|
757
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
if (lowered.startsWith('bigint')) {
|
|
761
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
if (lowered.startsWith('boolean')) {
|
|
765
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
if (lowered.startsWith('double precision')) {
|
|
769
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (lowered.startsWith('real')) {
|
|
773
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
if (lowered.startsWith('uuid')) {
|
|
777
|
+
return defaultValue === 'gen_random_uuid()'
|
|
778
|
+
? '.defaultRandom()'
|
|
779
|
+
: defaultValue
|
|
780
|
+
? `.default(sql\`${defaultValue}\`)`
|
|
781
|
+
: '';
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
if (lowered.startsWith('numeric')) {
|
|
785
|
+
defaultValue = defaultValue
|
|
786
|
+
? (defaultValue.startsWith(`'`) && defaultValue.endsWith(`'`)
|
|
787
|
+
? defaultValue.substring(1, defaultValue.length - 1)
|
|
788
|
+
: defaultValue)
|
|
789
|
+
: undefined;
|
|
790
|
+
return defaultValue ? `.default('${mapColumnDefault(defaultValue, isExpression)}')` : '';
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
if (lowered.startsWith('timestamp')) {
|
|
794
|
+
return defaultValue === 'now()'
|
|
795
|
+
? '.defaultNow()'
|
|
796
|
+
: /^'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?([+-]\d{2}(:\d{2})?)?'$/.test(defaultValue) // Matches 'YYYY-MM-DD HH:MI:SS', 'YYYY-MM-DD HH:MI:SS.FFFFFF', 'YYYY-MM-DD HH:MI:SS+TZ', 'YYYY-MM-DD HH:MI:SS.FFFFFF+TZ' and 'YYYY-MM-DD HH:MI:SS+HH:MI'
|
|
797
|
+
? `.default(${mapColumnDefault(defaultValue, isExpression)})`
|
|
798
|
+
: defaultValue
|
|
799
|
+
? `.default(sql\`${defaultValue}\`)`
|
|
800
|
+
: '';
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
if (lowered.startsWith('time')) {
|
|
804
|
+
return defaultValue === 'now()'
|
|
805
|
+
? '.defaultNow()'
|
|
806
|
+
: /^'\d{2}:\d{2}(:\d{2})?(\.\d+)?'$/.test(defaultValue) // Matches 'HH:MI', 'HH:MI:SS' and 'HH:MI:SS.FFFFFF'
|
|
807
|
+
? `.default(${mapColumnDefault(defaultValue, isExpression)})`
|
|
808
|
+
: defaultValue
|
|
809
|
+
? `.default(sql\`${defaultValue}\`)`
|
|
810
|
+
: '';
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
if (lowered.startsWith('interval')) {
|
|
814
|
+
return defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
if (lowered === 'date') {
|
|
818
|
+
return defaultValue === 'now()'
|
|
819
|
+
? '.defaultNow()'
|
|
820
|
+
: /^'\d{4}-\d{2}-\d{2}'$/.test(defaultValue) // Matches 'YYYY-MM-DD'
|
|
821
|
+
? `.default(${defaultValue})`
|
|
822
|
+
: defaultValue
|
|
823
|
+
? `.default(sql\`${defaultValue}\`)`
|
|
824
|
+
: '';
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if (lowered.startsWith('text')) {
|
|
828
|
+
return typeof defaultValue !== 'undefined'
|
|
829
|
+
? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})`
|
|
830
|
+
: '';
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
if (lowered.startsWith('jsonb')) {
|
|
834
|
+
const def = typeof defaultValue !== 'undefined'
|
|
835
|
+
? defaultValue.replace(/::(.*?)(?<![^\w"])(?=$)/, '').slice(1, -1)
|
|
836
|
+
: null;
|
|
837
|
+
|
|
838
|
+
return defaultValue ? `.default(${def})` : '';
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
if (lowered.startsWith('json')) {
|
|
842
|
+
const def = defaultValue ? defaultValue.replace(/::(.*?)(?<![^\w"])(?=$)/, '').slice(1, -1) : null;
|
|
843
|
+
|
|
844
|
+
return typeof defaultValue !== 'undefined' ? `.default(${def})` : '';
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
if (lowered.startsWith('inet')) {
|
|
848
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
if (lowered.startsWith('cidr')) {
|
|
852
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (lowered.startsWith('macaddr8')) {
|
|
856
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
if (lowered.startsWith('macaddr')) {
|
|
860
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
if (lowered.startsWith('varchar')) {
|
|
864
|
+
return typeof defaultValue !== 'undefined'
|
|
865
|
+
? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})`
|
|
866
|
+
: '';
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
if (lowered.startsWith('point')) {
|
|
870
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
if (lowered.startsWith('line')) {
|
|
874
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
if (lowered.startsWith('geometry')) {
|
|
878
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
if (lowered.startsWith('vector')) {
|
|
882
|
+
return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : '';
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
if (lowered.startsWith('char')) {
|
|
886
|
+
return typeof defaultValue !== 'undefined'
|
|
887
|
+
? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})`
|
|
888
|
+
: '';
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
return '';
|
|
892
|
+
};
|
|
893
|
+
|
|
894
|
+
const column = (
|
|
895
|
+
tableName: string,
|
|
896
|
+
type: string,
|
|
897
|
+
name: string,
|
|
898
|
+
domainTypes: Set<string>,
|
|
899
|
+
enumTypes: Set<string>,
|
|
900
|
+
domainTypeSchema: string,
|
|
901
|
+
typeSchema: string,
|
|
902
|
+
casing: Casing,
|
|
903
|
+
defaultValue?: any,
|
|
904
|
+
internals?: PgKitInternals,
|
|
905
|
+
) => {
|
|
906
|
+
const isExpression = internals?.tables[tableName]?.columns[name]?.isDefaultAnExpression ?? false;
|
|
907
|
+
const lowered = type.toLowerCase().replace('[]', '');
|
|
908
|
+
|
|
909
|
+
if (enumTypes.has(`${typeSchema}.${type.replace('[]', '')}`)) {
|
|
910
|
+
let out = `${withCasing(name, casing)}: ${withCasing(paramNameFor(type.replace('[]', ''), typeSchema), casing)}(${
|
|
911
|
+
dbColumnName({ name, casing })
|
|
912
|
+
})`;
|
|
913
|
+
return out;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
if (domainTypes.has(`${domainTypeSchema}.${type}`)) {
|
|
917
|
+
return `${withCasing(name, casing)}: ${withCasing(type, casing)}(${dbColumnName({ name, casing })})`;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
// TODO move all of the below into a function so that it can be used for domain serialization
|
|
921
|
+
if (lowered.startsWith('serial')) {
|
|
922
|
+
return `${withCasing(name, casing)}: serial(${dbColumnName({ name, casing })})`;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
if (lowered.startsWith('smallserial')) {
|
|
926
|
+
return `${withCasing(name, casing)}: smallserial(${dbColumnName({ name, casing })})`;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
if (lowered.startsWith('bigserial')) {
|
|
930
|
+
return `${withCasing(name, casing)}: bigserial(${
|
|
931
|
+
dbColumnName({ name, casing, withMode: true })
|
|
932
|
+
}{ mode: "bigint" })`;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
if (lowered.startsWith('integer')) {
|
|
936
|
+
let out = `${withCasing(name, casing)}: integer(${dbColumnName({ name, casing })})`;
|
|
937
|
+
return out;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
if (lowered.startsWith('smallint')) {
|
|
941
|
+
let out = `${withCasing(name, casing)}: smallint(${dbColumnName({ name, casing })})`;
|
|
942
|
+
return out;
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
if (lowered.startsWith('bigint')) {
|
|
946
|
+
let out = `// You can use { mode: "bigint" } if numbers are exceeding js number limitations\n\t`;
|
|
947
|
+
out += `${withCasing(name, casing)}: bigint(${dbColumnName({ name, casing, withMode: true })}{ mode: "number" })`;
|
|
948
|
+
return out;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
if (lowered.startsWith('boolean')) {
|
|
952
|
+
let out = `${withCasing(name, casing)}: boolean(${dbColumnName({ name, casing })})`;
|
|
953
|
+
return out;
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
if (lowered.startsWith('double precision')) {
|
|
957
|
+
let out = `${withCasing(name, casing)}: doublePrecision(${dbColumnName({ name, casing })})`;
|
|
958
|
+
return out;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
if (lowered.startsWith('real')) {
|
|
962
|
+
let out = `${withCasing(name, casing)}: real(${dbColumnName({ name, casing })})`;
|
|
963
|
+
return out;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
if (lowered.startsWith('uuid')) {
|
|
967
|
+
let out = `${withCasing(name, casing)}: uuid(${dbColumnName({ name, casing })})`;
|
|
968
|
+
|
|
969
|
+
return out;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
if (lowered.startsWith('numeric')) {
|
|
973
|
+
let params: { precision: string | undefined; scale: string | undefined } | undefined;
|
|
974
|
+
|
|
975
|
+
if (lowered.length > 7) {
|
|
976
|
+
const [precision, scale] = lowered.slice(8, lowered.length - 1).split(',');
|
|
977
|
+
params = { precision, scale };
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
let out = params
|
|
981
|
+
? `${withCasing(name, casing)}: numeric(${dbColumnName({ name, casing, withMode: true })}${timeConfig(params)})`
|
|
982
|
+
: `${withCasing(name, casing)}: numeric(${dbColumnName({ name, casing })})`;
|
|
983
|
+
|
|
984
|
+
return out;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
if (lowered.startsWith('timestamp')) {
|
|
988
|
+
const withTimezone = lowered.includes('with time zone');
|
|
989
|
+
// const split = lowered.split(" ");
|
|
990
|
+
let precision = lowered.startsWith('timestamp(')
|
|
991
|
+
? Number(lowered.split(' ')[0].substring('timestamp('.length, lowered.split(' ')[0].length - 1))
|
|
992
|
+
: null;
|
|
993
|
+
precision = precision ? precision : null;
|
|
994
|
+
|
|
995
|
+
const params = timeConfig({
|
|
996
|
+
precision,
|
|
997
|
+
withTimezone,
|
|
998
|
+
mode: "'string'",
|
|
999
|
+
});
|
|
1000
|
+
|
|
1001
|
+
let out = params
|
|
1002
|
+
? `${withCasing(name, casing)}: timestamp(${dbColumnName({ name, casing, withMode: true })}${params})`
|
|
1003
|
+
: `${withCasing(name, casing)}: timestamp(${dbColumnName({ name, casing })})`;
|
|
1004
|
+
|
|
1005
|
+
return out;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
if (lowered.startsWith('time')) {
|
|
1009
|
+
const withTimezone = lowered.includes('with time zone');
|
|
1010
|
+
|
|
1011
|
+
let precision = lowered.startsWith('time(')
|
|
1012
|
+
? Number(lowered.split(' ')[0].substring('time('.length, lowered.split(' ')[0].length - 1))
|
|
1013
|
+
: null;
|
|
1014
|
+
precision = precision ? precision : null;
|
|
1015
|
+
|
|
1016
|
+
const params = timeConfig({ precision, withTimezone });
|
|
1017
|
+
|
|
1018
|
+
let out = params
|
|
1019
|
+
? `${withCasing(name, casing)}: time(${dbColumnName({ name, casing, withMode: true })}${params})`
|
|
1020
|
+
: `${withCasing(name, casing)}: time(${dbColumnName({ name, casing })})`;
|
|
1021
|
+
|
|
1022
|
+
return out;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
if (lowered.startsWith('interval')) {
|
|
1026
|
+
// const withTimezone = lowered.includes("with time zone");
|
|
1027
|
+
// const split = lowered.split(" ");
|
|
1028
|
+
// let precision = split.length >= 2 ? Number(split[1].substring(1, 2)) : null;
|
|
1029
|
+
// precision = precision ? precision : null;
|
|
1030
|
+
|
|
1031
|
+
const params = intervalConfig(lowered);
|
|
1032
|
+
|
|
1033
|
+
let out = params
|
|
1034
|
+
? `${withCasing(name, casing)}: interval(${dbColumnName({ name, casing, withMode: true })}${params})`
|
|
1035
|
+
: `${withCasing(name, casing)}: interval(${dbColumnName({ name, casing })})`;
|
|
1036
|
+
|
|
1037
|
+
return out;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
if (lowered === 'date') {
|
|
1041
|
+
let out = `${withCasing(name, casing)}: date(${dbColumnName({ name, casing })})`;
|
|
1042
|
+
|
|
1043
|
+
return out;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
if (lowered.startsWith('text')) {
|
|
1047
|
+
let out = `${withCasing(name, casing)}: text(${dbColumnName({ name, casing })})`;
|
|
1048
|
+
return out;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
if (lowered.startsWith('jsonb')) {
|
|
1052
|
+
let out = `${withCasing(name, casing)}: jsonb(${dbColumnName({ name, casing })})`;
|
|
1053
|
+
return out;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
if (lowered.startsWith('json')) {
|
|
1057
|
+
let out = `${withCasing(name, casing)}: json(${dbColumnName({ name, casing })})`;
|
|
1058
|
+
return out;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
if (lowered.startsWith('inet')) {
|
|
1062
|
+
let out = `${withCasing(name, casing)}: inet(${dbColumnName({ name, casing })})`;
|
|
1063
|
+
return out;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
if (lowered.startsWith('cidr')) {
|
|
1067
|
+
let out = `${withCasing(name, casing)}: cidr(${dbColumnName({ name, casing })})`;
|
|
1068
|
+
return out;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
if (lowered.startsWith('macaddr8')) {
|
|
1072
|
+
let out = `${withCasing(name, casing)}: macaddr8(${dbColumnName({ name, casing })})`;
|
|
1073
|
+
return out;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
if (lowered.startsWith('macaddr')) {
|
|
1077
|
+
let out = `${withCasing(name, casing)}: macaddr(${dbColumnName({ name, casing })})`;
|
|
1078
|
+
return out;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
if (lowered.startsWith('varchar')) {
|
|
1082
|
+
let out: string;
|
|
1083
|
+
if (lowered.length !== 7) {
|
|
1084
|
+
out = `${withCasing(name, casing)}: varchar(${dbColumnName({ name, casing, withMode: true })}{ length: ${
|
|
1085
|
+
lowered.substring(8, lowered.length - 1)
|
|
1086
|
+
} })`;
|
|
1087
|
+
} else {
|
|
1088
|
+
out = `${withCasing(name, casing)}: varchar(${dbColumnName({ name, casing })})`;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
return out;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
if (lowered.startsWith('point')) {
|
|
1095
|
+
let out: string = `${withCasing(name, casing)}: point(${dbColumnName({ name, casing })})`;
|
|
1096
|
+
return out;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
if (lowered.startsWith('line')) {
|
|
1100
|
+
let out: string = `${withCasing(name, casing)}: point(${dbColumnName({ name, casing })})`;
|
|
1101
|
+
return out;
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
if (lowered.startsWith('geometry')) {
|
|
1105
|
+
let out: string = '';
|
|
1106
|
+
|
|
1107
|
+
let isGeoUnknown = false;
|
|
1108
|
+
|
|
1109
|
+
if (lowered.length !== 8) {
|
|
1110
|
+
const geometryOptions = lowered.slice(9, -1).split(',');
|
|
1111
|
+
if (geometryOptions.length === 1 && geometryOptions[0] !== '') {
|
|
1112
|
+
out = `${withCasing(name, casing)}: geometry(${dbColumnName({ name, casing, withMode: true })}{ type: "${
|
|
1113
|
+
geometryOptions[0]
|
|
1114
|
+
}" })`;
|
|
1115
|
+
} else if (geometryOptions.length === 2) {
|
|
1116
|
+
out = `${withCasing(name, casing)}: geometry(${dbColumnName({ name, casing, withMode: true })}{ type: "${
|
|
1117
|
+
geometryOptions[0]
|
|
1118
|
+
}", srid: ${geometryOptions[1]} })`;
|
|
1119
|
+
} else {
|
|
1120
|
+
isGeoUnknown = true;
|
|
1121
|
+
}
|
|
1122
|
+
} else {
|
|
1123
|
+
out = `${withCasing(name, casing)}: geometry(${dbColumnName({ name, casing })})`;
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
if (isGeoUnknown) {
|
|
1127
|
+
let unknown =
|
|
1128
|
+
`// TODO: failed to parse geometry type because found more than 2 options inside geometry function '${type}'\n// Introspect is currently supporting only type and srid options\n`;
|
|
1129
|
+
unknown += `\t${withCasing(name, casing)}: unknown("${name}")`;
|
|
1130
|
+
return unknown;
|
|
1131
|
+
}
|
|
1132
|
+
return out;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
if (lowered.startsWith('vector')) {
|
|
1136
|
+
let out: string;
|
|
1137
|
+
if (lowered.length !== 6) {
|
|
1138
|
+
out = `${withCasing(name, casing)}: vector(${dbColumnName({ name, casing, withMode: true })}{ dimensions: ${
|
|
1139
|
+
lowered.substring(7, lowered.length - 1)
|
|
1140
|
+
} })`;
|
|
1141
|
+
} else {
|
|
1142
|
+
out = `${withCasing(name, casing)}: vector(${dbColumnName({ name, casing })})`;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
return out;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
if (lowered.startsWith('char')) {
|
|
1149
|
+
let out: string;
|
|
1150
|
+
if (lowered.length !== 4) {
|
|
1151
|
+
out = `${withCasing(name, casing)}: char(${dbColumnName({ name, casing, withMode: true })}{ length: ${
|
|
1152
|
+
lowered.substring(5, lowered.length - 1)
|
|
1153
|
+
} })`;
|
|
1154
|
+
} else {
|
|
1155
|
+
out = `${withCasing(name, casing)}: char(${dbColumnName({ name, casing })})`;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
return out;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
let unknown = `// TODO: failed to parse database type '${type}'\n`;
|
|
1162
|
+
unknown += `\t${withCasing(name, casing)}: unknown("${name}")`;
|
|
1163
|
+
return unknown;
|
|
1164
|
+
};
|
|
1165
|
+
|
|
1166
|
+
const dimensionsInArray = (size?: number): string => {
|
|
1167
|
+
let res = '';
|
|
1168
|
+
if (typeof size === 'undefined') return res;
|
|
1169
|
+
for (let i = 0; i < size; i++) {
|
|
1170
|
+
res += '.array()';
|
|
1171
|
+
}
|
|
1172
|
+
return res;
|
|
1173
|
+
};
|
|
1174
|
+
|
|
1175
|
+
const createTableColumns = (
|
|
1176
|
+
tableName: string,
|
|
1177
|
+
columns: Column[],
|
|
1178
|
+
fks: ForeignKey[],
|
|
1179
|
+
domainTypes: Set<string>,
|
|
1180
|
+
enumTypes: Set<string>,
|
|
1181
|
+
schemas: Record<string, string>,
|
|
1182
|
+
casing: Casing,
|
|
1183
|
+
internals: PgKitInternals,
|
|
1184
|
+
): string => {
|
|
1185
|
+
let statement = '';
|
|
1186
|
+
|
|
1187
|
+
// no self refs and no cyclic
|
|
1188
|
+
const oneColumnsFKs = Object.values(fks)
|
|
1189
|
+
.filter((it) => {
|
|
1190
|
+
return !isSelf(it);
|
|
1191
|
+
})
|
|
1192
|
+
.filter((it) => it.columnsFrom.length === 1);
|
|
1193
|
+
|
|
1194
|
+
const fkByColumnName = oneColumnsFKs.reduce((res, it) => {
|
|
1195
|
+
const arr = res[it.columnsFrom[0]] || [];
|
|
1196
|
+
arr.push(it);
|
|
1197
|
+
res[it.columnsFrom[0]] = arr;
|
|
1198
|
+
return res;
|
|
1199
|
+
}, {} as Record<string, ForeignKey[]>);
|
|
1200
|
+
|
|
1201
|
+
columns.forEach((it) => {
|
|
1202
|
+
const columnStatement = column(
|
|
1203
|
+
tableName,
|
|
1204
|
+
it.type,
|
|
1205
|
+
it.name,
|
|
1206
|
+
domainTypes,
|
|
1207
|
+
enumTypes,
|
|
1208
|
+
it.domainTypeSchema ?? 'public',
|
|
1209
|
+
it.typeSchema ?? 'public',
|
|
1210
|
+
casing,
|
|
1211
|
+
it.default,
|
|
1212
|
+
internals,
|
|
1213
|
+
);
|
|
1214
|
+
statement += '\t';
|
|
1215
|
+
statement += columnStatement;
|
|
1216
|
+
// Provide just this in column function
|
|
1217
|
+
if (internals?.tables[tableName]?.columns[it.name]?.isArray) {
|
|
1218
|
+
statement += dimensionsInArray(internals?.tables[tableName]?.columns[it.name]?.dimensions);
|
|
1219
|
+
}
|
|
1220
|
+
statement += mapDefault(tableName, it.type, it.name, enumTypes, it.typeSchema ?? 'public', it.default, internals);
|
|
1221
|
+
statement += it.primaryKey ? '.primaryKey()' : '';
|
|
1222
|
+
statement += it.notNull && !it.identity ? '.notNull()' : '';
|
|
1223
|
+
|
|
1224
|
+
statement += it.identity ? generateIdentityParams(it.identity) : '';
|
|
1225
|
+
|
|
1226
|
+
statement += it.generated ? `.generatedAlwaysAs(sql\`${it.generated.as}\`)` : '';
|
|
1227
|
+
|
|
1228
|
+
// const fks = fkByColumnName[it.name];
|
|
1229
|
+
// Andrii: I switched it off until we will get a custom naem setting in references
|
|
1230
|
+
// if (fks) {
|
|
1231
|
+
// const fksStatement = fks
|
|
1232
|
+
// .map((it) => {
|
|
1233
|
+
// const onDelete = it.onDelete && it.onDelete !== 'no action' ? it.onDelete : null;
|
|
1234
|
+
// const onUpdate = it.onUpdate && it.onUpdate !== 'no action' ? it.onUpdate : null;
|
|
1235
|
+
// const params = { onDelete, onUpdate };
|
|
1236
|
+
|
|
1237
|
+
// const typeSuffix = isCyclic(it) ? ': AnyPgColumn' : '';
|
|
1238
|
+
|
|
1239
|
+
// const paramsStr = objToStatement2(params);
|
|
1240
|
+
// const tableSchema = schemas[it.schemaTo || ''];
|
|
1241
|
+
// const paramName = paramNameFor(it.tableTo, tableSchema);
|
|
1242
|
+
// if (paramsStr) {
|
|
1243
|
+
// return `.references(()${typeSuffix} => ${
|
|
1244
|
+
// withCasing(
|
|
1245
|
+
// paramName,
|
|
1246
|
+
// casing,
|
|
1247
|
+
// )
|
|
1248
|
+
// }.${withCasing(it.columnsTo[0], casing)}, ${paramsStr} )`;
|
|
1249
|
+
// }
|
|
1250
|
+
// return `.references(()${typeSuffix} => ${
|
|
1251
|
+
// withCasing(
|
|
1252
|
+
// paramName,
|
|
1253
|
+
// casing,
|
|
1254
|
+
// )
|
|
1255
|
+
// }.${withCasing(it.columnsTo[0], casing)})`;
|
|
1256
|
+
// })
|
|
1257
|
+
// .join('');
|
|
1258
|
+
// statement += fksStatement;
|
|
1259
|
+
// }
|
|
1260
|
+
|
|
1261
|
+
statement += ',\n';
|
|
1262
|
+
});
|
|
1263
|
+
|
|
1264
|
+
return statement;
|
|
1265
|
+
};
|
|
1266
|
+
|
|
1267
|
+
const createTableIndexes = (tableName: string, idxs: Index[], casing: Casing): string => {
|
|
1268
|
+
let statement = '';
|
|
1269
|
+
|
|
1270
|
+
idxs.forEach((it) => {
|
|
1271
|
+
// we have issue when index is called as table called
|
|
1272
|
+
let idxKey = it.name.startsWith(tableName) && it.name !== tableName ? it.name.slice(tableName.length + 1) : it.name;
|
|
1273
|
+
idxKey = idxKey.endsWith('_index') ? idxKey.slice(0, -'_index'.length) + '_idx' : idxKey;
|
|
1274
|
+
|
|
1275
|
+
idxKey = withCasing(idxKey, casing);
|
|
1276
|
+
|
|
1277
|
+
const indexGeneratedName = indexName(
|
|
1278
|
+
tableName,
|
|
1279
|
+
it.columns.map((it) => it.expression),
|
|
1280
|
+
);
|
|
1281
|
+
const escapedIndexName = indexGeneratedName === it.name ? '' : `"${it.name}"`;
|
|
1282
|
+
|
|
1283
|
+
statement += `\n\t`;
|
|
1284
|
+
statement += it.isUnique ? 'uniqueIndex(' : 'index(';
|
|
1285
|
+
statement += `${escapedIndexName})`;
|
|
1286
|
+
statement += `${it.concurrently ? `.concurrently()` : ''}`;
|
|
1287
|
+
|
|
1288
|
+
statement += `.using("${it.method}", ${
|
|
1289
|
+
it.columns
|
|
1290
|
+
.map((it) => {
|
|
1291
|
+
if (it.isExpression) {
|
|
1292
|
+
return `sql\`${it.expression}\``;
|
|
1293
|
+
} else {
|
|
1294
|
+
return `table.${withCasing(it.expression, casing)}${it.asc ? '.asc()' : '.desc()'}${
|
|
1295
|
+
it.nulls === 'first' ? '.nullsFirst()' : '.nullsLast()'
|
|
1296
|
+
}${
|
|
1297
|
+
it.opclass
|
|
1298
|
+
? `.op("${it.opclass}")`
|
|
1299
|
+
: ''
|
|
1300
|
+
}`;
|
|
1301
|
+
}
|
|
1302
|
+
})
|
|
1303
|
+
.join(', ')
|
|
1304
|
+
})`;
|
|
1305
|
+
statement += it.where ? `.where(sql\`${it.where}\`)` : '';
|
|
1306
|
+
|
|
1307
|
+
function reverseLogic(mappedWith: Record<string, string>): string {
|
|
1308
|
+
let reversedString = '{';
|
|
1309
|
+
for (const key in mappedWith) {
|
|
1310
|
+
if (mappedWith.hasOwnProperty(key)) {
|
|
1311
|
+
reversedString += `${key}: "${mappedWith[key]}",`;
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1314
|
+
reversedString = reversedString.length > 1 ? reversedString.slice(0, reversedString.length - 1) : reversedString;
|
|
1315
|
+
return `${reversedString}}`;
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
statement += it.with && Object.keys(it.with).length > 0 ? `.with(${reverseLogic(it.with)})` : '';
|
|
1319
|
+
statement += `,`;
|
|
1320
|
+
});
|
|
1321
|
+
|
|
1322
|
+
return statement;
|
|
1323
|
+
};
|
|
1324
|
+
|
|
1325
|
+
const createTablePKs = (pks: PrimaryKey[], casing: Casing): string => {
|
|
1326
|
+
let statement = '';
|
|
1327
|
+
|
|
1328
|
+
pks.forEach((it) => {
|
|
1329
|
+
statement += `\n\t`;
|
|
1330
|
+
statement += 'primaryKey({ columns: [';
|
|
1331
|
+
statement += `${
|
|
1332
|
+
it.columns
|
|
1333
|
+
.map((c) => {
|
|
1334
|
+
return `table.${withCasing(c, casing)}`;
|
|
1335
|
+
})
|
|
1336
|
+
.join(', ')
|
|
1337
|
+
}]${it.name ? `, name: "${it.name}"` : ''}}`;
|
|
1338
|
+
statement += ')';
|
|
1339
|
+
statement += `,`;
|
|
1340
|
+
});
|
|
1341
|
+
|
|
1342
|
+
return statement;
|
|
1343
|
+
};
|
|
1344
|
+
|
|
1345
|
+
// get a map of db role name to ts key
|
|
1346
|
+
// if to by key is in this map - no quotes, otherwise - quotes
|
|
1347
|
+
|
|
1348
|
+
const createTablePolicies = (
|
|
1349
|
+
policies: Policy[],
|
|
1350
|
+
casing: Casing,
|
|
1351
|
+
rolesNameToTsKey: Record<string, string> = {},
|
|
1352
|
+
): string => {
|
|
1353
|
+
let statement = '';
|
|
1354
|
+
|
|
1355
|
+
policies.forEach((it) => {
|
|
1356
|
+
const idxKey = withCasing(it.name, casing);
|
|
1357
|
+
|
|
1358
|
+
const mappedItTo = it.to?.map((v) => {
|
|
1359
|
+
return rolesNameToTsKey[v] ? withCasing(rolesNameToTsKey[v], casing) : `"${v}"`;
|
|
1360
|
+
});
|
|
1361
|
+
|
|
1362
|
+
statement += `\n\t`;
|
|
1363
|
+
statement += 'pgPolicy(';
|
|
1364
|
+
statement += `"${it.name}", { `;
|
|
1365
|
+
statement += `as: "${it.as?.toLowerCase()}", for: "${it.for?.toLowerCase()}", to: [${mappedItTo?.join(', ')}]${
|
|
1366
|
+
it.using ? `, using: sql\`${it.using}\`` : ''
|
|
1367
|
+
}${it.withCheck ? `, withCheck: sql\`${it.withCheck}\` ` : ''}`;
|
|
1368
|
+
statement += ` }),`;
|
|
1369
|
+
});
|
|
1370
|
+
|
|
1371
|
+
return statement;
|
|
1372
|
+
};
|
|
1373
|
+
|
|
1374
|
+
const createTableUniques = (
|
|
1375
|
+
unqs: UniqueConstraint[],
|
|
1376
|
+
casing: Casing,
|
|
1377
|
+
): string => {
|
|
1378
|
+
let statement = '';
|
|
1379
|
+
|
|
1380
|
+
unqs.forEach((it) => {
|
|
1381
|
+
statement += `\n\t`;
|
|
1382
|
+
statement += 'unique(';
|
|
1383
|
+
statement += `"${it.name}")`;
|
|
1384
|
+
statement += `.on(${it.columns.map((it) => `table.${withCasing(it, casing)}`).join(', ')})`;
|
|
1385
|
+
statement += it.nullsNotDistinct ? `.nullsNotDistinct()` : '';
|
|
1386
|
+
statement += `,`;
|
|
1387
|
+
});
|
|
1388
|
+
|
|
1389
|
+
return statement;
|
|
1390
|
+
};
|
|
1391
|
+
|
|
1392
|
+
const createTableChecks = (
|
|
1393
|
+
checkConstraints: CheckConstraint[],
|
|
1394
|
+
casing: Casing,
|
|
1395
|
+
) => {
|
|
1396
|
+
let statement = '';
|
|
1397
|
+
|
|
1398
|
+
checkConstraints.forEach((it) => {
|
|
1399
|
+
statement += `\n\t`;
|
|
1400
|
+
statement += 'check(';
|
|
1401
|
+
statement += `"${it.name}", `;
|
|
1402
|
+
statement += `sql\`${it.value}\`)`;
|
|
1403
|
+
statement += `,`;
|
|
1404
|
+
});
|
|
1405
|
+
|
|
1406
|
+
return statement;
|
|
1407
|
+
};
|
|
1408
|
+
|
|
1409
|
+
const createTableFKs = (fks: ForeignKey[], schemas: Record<string, string>, casing: Casing): string => {
|
|
1410
|
+
let statement = '';
|
|
1411
|
+
|
|
1412
|
+
fks.forEach((it) => {
|
|
1413
|
+
const tableSchema = schemas[it.schemaTo || ''];
|
|
1414
|
+
const paramName = paramNameFor(it.tableTo, tableSchema);
|
|
1415
|
+
|
|
1416
|
+
const isSelf = it.tableTo === it.tableFrom;
|
|
1417
|
+
const tableTo = isSelf ? 'table' : `${withCasing(paramName, casing)}`;
|
|
1418
|
+
statement += `\n\t`;
|
|
1419
|
+
statement += `foreignKey({\n`;
|
|
1420
|
+
statement += `\t\t\tcolumns: [${it.columnsFrom.map((i) => `table.${withCasing(i, casing)}`).join(', ')}],\n`;
|
|
1421
|
+
statement += `\t\t\tforeignColumns: [${
|
|
1422
|
+
it.columnsTo.map((i) => `${tableTo}.${withCasing(i, casing)}`).join(', ')
|
|
1423
|
+
}],\n`;
|
|
1424
|
+
statement += `\t\t\tname: "${it.name}"\n`;
|
|
1425
|
+
statement += `\t\t})`;
|
|
1426
|
+
|
|
1427
|
+
statement += it.onUpdate && it.onUpdate !== 'no action' ? `.onUpdate("${it.onUpdate}")` : '';
|
|
1428
|
+
|
|
1429
|
+
statement += it.onDelete && it.onDelete !== 'no action' ? `.onDelete("${it.onDelete}")` : '';
|
|
1430
|
+
|
|
1431
|
+
statement += `,`;
|
|
1432
|
+
});
|
|
1433
|
+
|
|
1434
|
+
return statement;
|
|
1435
|
+
};
|