@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.
Files changed (161) hide show
  1. package/.gitignore +25 -0
  2. package/README.md +79 -0
  3. package/build.dev.ts +51 -0
  4. package/build.ts +112 -0
  5. package/imports-checker/analyze.ts +78 -0
  6. package/imports-checker/checker.ts +296 -0
  7. package/imports-checker/grammar/grammar.ohm +121 -0
  8. package/imports-checker/grammar/grammar.ohm-bundle.d.ts +164 -0
  9. package/imports-checker/grammar/grammar.ohm-bundle.js +753 -0
  10. package/imports-checker/index.ts +48 -0
  11. package/package.json +142 -0
  12. package/patches/difflib@0.2.4.patch +31 -0
  13. package/src/@types/utils.ts +58 -0
  14. package/src/api.ts +504 -0
  15. package/src/cli/commands/_es5.ts +2 -0
  16. package/src/cli/commands/check.ts +52 -0
  17. package/src/cli/commands/drop.ts +60 -0
  18. package/src/cli/commands/introspect.ts +772 -0
  19. package/src/cli/commands/libSqlPushUtils.ts +355 -0
  20. package/src/cli/commands/migrate.ts +1526 -0
  21. package/src/cli/commands/mysqlIntrospect.ts +53 -0
  22. package/src/cli/commands/mysqlPushUtils.ts +352 -0
  23. package/src/cli/commands/mysqlUp.ts +102 -0
  24. package/src/cli/commands/pgIntrospect.ts +55 -0
  25. package/src/cli/commands/pgPushUtils.ts +269 -0
  26. package/src/cli/commands/pgUp.ts +217 -0
  27. package/src/cli/commands/push.ts +637 -0
  28. package/src/cli/commands/singlestoreIntrospect.ts +53 -0
  29. package/src/cli/commands/singlestorePushUtils.ts +456 -0
  30. package/src/cli/commands/singlestoreUp.ts +1 -0
  31. package/src/cli/commands/sqliteIntrospect.ts +96 -0
  32. package/src/cli/commands/sqlitePushUtils.ts +322 -0
  33. package/src/cli/commands/sqliteUp.ts +52 -0
  34. package/src/cli/commands/utils.ts +858 -0
  35. package/src/cli/connections.ts +914 -0
  36. package/src/cli/index.ts +48 -0
  37. package/src/cli/schema.ts +794 -0
  38. package/src/cli/selector-ui.ts +38 -0
  39. package/src/cli/utils.ts +112 -0
  40. package/src/cli/validations/cli.ts +79 -0
  41. package/src/cli/validations/common.ts +193 -0
  42. package/src/cli/validations/libsql.ts +27 -0
  43. package/src/cli/validations/mysql.ts +61 -0
  44. package/src/cli/validations/outputs.ts +91 -0
  45. package/src/cli/validations/postgres.ts +83 -0
  46. package/src/cli/validations/singlestore.ts +61 -0
  47. package/src/cli/validations/sqlite.ts +104 -0
  48. package/src/cli/validations/studio.ts +24 -0
  49. package/src/cli/views.ts +658 -0
  50. package/src/extensions/getTablesFilterByExtensions.ts +16 -0
  51. package/src/extensions/vector.ts +10 -0
  52. package/src/global.ts +61 -0
  53. package/src/index.ts +326 -0
  54. package/src/introspect-mysql.ts +1030 -0
  55. package/src/introspect-pg.ts +1435 -0
  56. package/src/introspect-singlestore.ts +913 -0
  57. package/src/introspect-sqlite.ts +533 -0
  58. package/src/jsonDiffer.js +882 -0
  59. package/src/jsonStatements.ts +3590 -0
  60. package/src/loader.mjs +57 -0
  61. package/src/migrationPreparator.ts +217 -0
  62. package/src/schemaValidator.ts +23 -0
  63. package/src/serializer/index.ts +142 -0
  64. package/src/serializer/mysqlImports.ts +38 -0
  65. package/src/serializer/mysqlSchema.ts +423 -0
  66. package/src/serializer/mysqlSerializer.ts +999 -0
  67. package/src/serializer/pgImports.ts +106 -0
  68. package/src/serializer/pgSchema.ts +937 -0
  69. package/src/serializer/pgSerializer.ts +2223 -0
  70. package/src/serializer/singlestoreImports.ts +38 -0
  71. package/src/serializer/singlestoreSchema.ts +257 -0
  72. package/src/serializer/singlestoreSerializer.ts +767 -0
  73. package/src/serializer/sqliteImports.ts +41 -0
  74. package/src/serializer/sqliteSchema.ts +352 -0
  75. package/src/serializer/sqliteSerializer.ts +931 -0
  76. package/src/serializer/studio.ts +694 -0
  77. package/src/serializer/utils.ts +45 -0
  78. package/src/simulator.ts +157 -0
  79. package/src/snapshotsDiffer.ts +4398 -0
  80. package/src/sqlgenerator.ts +4212 -0
  81. package/src/statementCombiner.ts +597 -0
  82. package/src/utils/certs.ts +44 -0
  83. package/src/utils/words.ts +1333 -0
  84. package/src/utils.ts +370 -0
  85. package/tests/bin.test.ts +58 -0
  86. package/tests/cli/d1http.config.ts +12 -0
  87. package/tests/cli/drizzle.config.ts +9 -0
  88. package/tests/cli/durable-sqlite.config.ts +7 -0
  89. package/tests/cli/expo.config.ts +7 -0
  90. package/tests/cli/postgres.config.ts +13 -0
  91. package/tests/cli/postgres2.config.ts +17 -0
  92. package/tests/cli/schema.ts +1 -0
  93. package/tests/cli/turso.config.ts +10 -0
  94. package/tests/cli-export.test.ts +79 -0
  95. package/tests/cli-generate.test.ts +259 -0
  96. package/tests/cli-migrate.test.ts +103 -0
  97. package/tests/cli-push.test.ts +126 -0
  98. package/tests/common.ts +15 -0
  99. package/tests/indexes/common.ts +21 -0
  100. package/tests/indexes/pg.test.ts +245 -0
  101. package/tests/introspect/libsql.test.ts +35 -0
  102. package/tests/introspect/mysql.test.ts +319 -0
  103. package/tests/introspect/pg.test.ts +894 -0
  104. package/tests/introspect/singlestore.test.ts +275 -0
  105. package/tests/introspect/sqlite.test.ts +122 -0
  106. package/tests/libsql-checks.test.ts +308 -0
  107. package/tests/libsql-statements.test.ts +989 -0
  108. package/tests/libsql-views.test.ts +218 -0
  109. package/tests/migrate/libsq-schema.ts +6 -0
  110. package/tests/migrate/libsql-migrate.test.ts +58 -0
  111. package/tests/migrate/migrations/0000_little_blizzard.sql +4 -0
  112. package/tests/migrate/migrations/0001_nebulous_storm.sql +10 -0
  113. package/tests/migrate/migrations/meta/0000_snapshot.json +40 -0
  114. package/tests/migrate/migrations/meta/0001_snapshot.json +40 -0
  115. package/tests/migrate/migrations/meta/_journal.json +20 -0
  116. package/tests/mysql-checks.test.ts +291 -0
  117. package/tests/mysql-generated.test.ts +1290 -0
  118. package/tests/mysql-schemas.test.ts +156 -0
  119. package/tests/mysql-views.test.ts +553 -0
  120. package/tests/mysql.test.ts +863 -0
  121. package/tests/pg-array.test.ts +368 -0
  122. package/tests/pg-checks.test.ts +329 -0
  123. package/tests/pg-columns.test.ts +484 -0
  124. package/tests/pg-domains.test.ts +306 -0
  125. package/tests/pg-enums.test.ts +751 -0
  126. package/tests/pg-generated.test.ts +529 -0
  127. package/tests/pg-identity.test.ts +447 -0
  128. package/tests/pg-schemas.test.ts +105 -0
  129. package/tests/pg-sequences.test.ts +298 -0
  130. package/tests/pg-tables.test.ts +1021 -0
  131. package/tests/pg-views.test.ts +1929 -0
  132. package/tests/push/common.ts +58 -0
  133. package/tests/push/libsql.test.ts +1400 -0
  134. package/tests/push/mysql-push.test.ts +345 -0
  135. package/tests/push/mysql.test.ts +788 -0
  136. package/tests/push/pg.test.ts +4341 -0
  137. package/tests/push/singlestore-push.test.ts +894 -0
  138. package/tests/push/singlestore.test.ts +444 -0
  139. package/tests/push/sqlite.test.ts +1613 -0
  140. package/tests/rls/pg-policy.test.ts +1656 -0
  141. package/tests/rls/pg-role.test.ts +234 -0
  142. package/tests/schemaDiffer.ts +2852 -0
  143. package/tests/singlestore-generated.test.ts +1290 -0
  144. package/tests/singlestore-schemas.test.ts +155 -0
  145. package/tests/singlestore.test.ts +978 -0
  146. package/tests/sqlite-checks.test.ts +308 -0
  147. package/tests/sqlite-columns.test.ts +1049 -0
  148. package/tests/sqlite-generated.test.ts +1726 -0
  149. package/tests/sqlite-tables.test.ts +637 -0
  150. package/tests/sqlite-views.test.ts +218 -0
  151. package/tests/statements-combiner/libsql-statements-combiner.test.ts +1812 -0
  152. package/tests/statements-combiner/singlestore-statements-combiner.test.ts +882 -0
  153. package/tests/statements-combiner/sqlite-statements-combiner.test.ts +1211 -0
  154. package/tests/test/sqlite.test.ts +39 -0
  155. package/tests/testsinglestore.ts +29 -0
  156. package/tests/validations.test.ts +869 -0
  157. package/tests/wrap-param.test.ts +16 -0
  158. package/tsconfig.build.json +4 -0
  159. package/tsconfig.cli-types.json +9 -0
  160. package/tsconfig.json +28 -0
  161. package/vitest.config.ts +34 -0
@@ -0,0 +1,533 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-argument */
2
+ import { toCamelCase } from 'drizzle-orm/casing';
3
+ import './@types/utils';
4
+ import type { Casing } from './cli/validations/common';
5
+ import { assertUnreachable } from './global';
6
+ import { CheckConstraint } from './serializer/mysqlSchema';
7
+ import type {
8
+ Column,
9
+ ForeignKey,
10
+ Index,
11
+ PrimaryKey,
12
+ SQLiteSchema,
13
+ SQLiteSchemaInternal,
14
+ UniqueConstraint,
15
+ } from './serializer/sqliteSchema';
16
+
17
+ const sqliteImportsList = new Set([
18
+ 'sqliteTable',
19
+ 'integer',
20
+ 'real',
21
+ 'text',
22
+ 'numeric',
23
+ 'blob',
24
+ ]);
25
+
26
+ export const indexName = (tableName: string, columns: string[]) => {
27
+ return `${tableName}_${columns.join('_')}_index`;
28
+ };
29
+
30
+ const objToStatement2 = (json: any) => {
31
+ json = Object.fromEntries(Object.entries(json).filter((it) => it[1]));
32
+
33
+ const keys = Object.keys(json);
34
+ if (keys.length === 0) return;
35
+
36
+ let statement = '{ ';
37
+ statement += keys.map((it) => `${it}: "${json[it]}"`).join(', '); // no "" for keys
38
+ statement += ' }';
39
+ return statement;
40
+ };
41
+
42
+ const relations = new Set<string>();
43
+
44
+ const escapeColumnKey = (value: string) => {
45
+ if (/^(?![a-zA-Z_$][a-zA-Z0-9_$]*$).+$/.test(value)) {
46
+ return `"${value}"`;
47
+ }
48
+ return value;
49
+ };
50
+
51
+ const withCasing = (value: string, casing?: Casing) => {
52
+ if (casing === 'preserve') {
53
+ return escapeColumnKey(value);
54
+ }
55
+ if (casing === 'camel') {
56
+ return escapeColumnKey(value.camelCase());
57
+ }
58
+
59
+ return value;
60
+ };
61
+
62
+ const dbColumnName = ({ name, casing, withMode = false }: { name: string; casing: Casing; withMode?: boolean }) => {
63
+ if (casing === 'preserve') {
64
+ return '';
65
+ }
66
+ if (casing === 'camel') {
67
+ return toCamelCase(name) === name ? '' : withMode ? `"${name}", ` : `"${name}"`;
68
+ }
69
+
70
+ assertUnreachable(casing);
71
+ };
72
+
73
+ export const schemaToTypeScript = (
74
+ schema: SQLiteSchemaInternal,
75
+ casing: Casing,
76
+ ) => {
77
+ // collectFKs
78
+ Object.values(schema.tables).forEach((table) => {
79
+ Object.values(table.foreignKeys).forEach((fk) => {
80
+ const relation = `${fk.tableFrom}-${fk.tableTo}`;
81
+ relations.add(relation);
82
+ });
83
+ });
84
+
85
+ const imports = Object.values(schema.tables).reduce(
86
+ (res, it) => {
87
+ const idxImports = Object.values(it.indexes).map((idx) => idx.isUnique ? 'uniqueIndex' : 'index');
88
+ const fkImpots = Object.values(it.foreignKeys).map((it) => 'foreignKey');
89
+ const pkImports = Object.values(it.compositePrimaryKeys).map(
90
+ (it) => 'primaryKey',
91
+ );
92
+ const uniqueImports = Object.values(it.uniqueConstraints).map(
93
+ (it) => 'unique',
94
+ );
95
+ const checkImports = Object.values(it.checkConstraints).map(
96
+ (it) => 'check',
97
+ );
98
+
99
+ res.sqlite.push(...idxImports);
100
+ res.sqlite.push(...fkImpots);
101
+ res.sqlite.push(...pkImports);
102
+ res.sqlite.push(...uniqueImports);
103
+ res.sqlite.push(...checkImports);
104
+
105
+ const columnImports = Object.values(it.columns)
106
+ .map((col) => {
107
+ return col.type;
108
+ })
109
+ .filter((type) => {
110
+ return sqliteImportsList.has(type);
111
+ });
112
+
113
+ res.sqlite.push(...columnImports);
114
+ return res;
115
+ },
116
+ { sqlite: [] as string[] },
117
+ );
118
+
119
+ Object.values(schema.views).forEach((it) => {
120
+ imports.sqlite.push('sqliteView');
121
+
122
+ const columnImports = Object.values(it.columns)
123
+ .map((col) => {
124
+ return col.type;
125
+ })
126
+ .filter((type) => {
127
+ return sqliteImportsList.has(type);
128
+ });
129
+
130
+ imports.sqlite.push(...columnImports);
131
+ });
132
+
133
+ const tableStatements = Object.values(schema.tables).map((table) => {
134
+ const func = 'sqliteTable';
135
+ let statement = '';
136
+ if (imports.sqlite.includes(withCasing(table.name, casing))) {
137
+ statement = `// Table name is in conflict with ${
138
+ withCasing(
139
+ table.name,
140
+ casing,
141
+ )
142
+ } import.\n// Please change to any other name, that is not in imports list\n`;
143
+ }
144
+ statement += `export const ${withCasing(table.name, casing)} = ${func}("${table.name}", {\n`;
145
+ statement += createTableColumns(
146
+ Object.values(table.columns),
147
+ Object.values(table.foreignKeys),
148
+ casing,
149
+ );
150
+ statement += '}';
151
+
152
+ // more than 2 fields or self reference or cyclic
153
+ const filteredFKs = Object.values(table.foreignKeys).filter((it) => {
154
+ return it.columnsFrom.length > 1 || isSelf(it);
155
+ });
156
+
157
+ if (
158
+ Object.keys(table.indexes).length > 0
159
+ || filteredFKs.length > 0
160
+ || Object.keys(table.compositePrimaryKeys).length > 0
161
+ || Object.keys(table.uniqueConstraints).length > 0
162
+ || Object.keys(table.checkConstraints).length > 0
163
+ ) {
164
+ statement += ',\n';
165
+ statement += '(table) => [';
166
+ statement += createTableIndexes(
167
+ table.name,
168
+ Object.values(table.indexes),
169
+ casing,
170
+ );
171
+ statement += createTableFKs(Object.values(filteredFKs), casing);
172
+ statement += createTablePKs(
173
+ Object.values(table.compositePrimaryKeys),
174
+ casing,
175
+ );
176
+ statement += createTableUniques(
177
+ Object.values(table.uniqueConstraints),
178
+ casing,
179
+ );
180
+ statement += createTableChecks(
181
+ Object.values(table.checkConstraints),
182
+ casing,
183
+ );
184
+ statement += '\n]';
185
+ }
186
+
187
+ statement += ');';
188
+ return statement;
189
+ });
190
+
191
+ const viewsStatements = Object.values(schema.views).map((view) => {
192
+ const func = 'sqliteView';
193
+
194
+ let statement = '';
195
+ if (imports.sqlite.includes(withCasing(view.name, casing))) {
196
+ statement = `// Table name is in conflict with ${
197
+ withCasing(
198
+ view.name,
199
+ casing,
200
+ )
201
+ } import.\n// Please change to any other name, that is not in imports list\n`;
202
+ }
203
+ statement += `export const ${withCasing(view.name, casing)} = ${func}("${view.name}", {\n`;
204
+ statement += createTableColumns(
205
+ Object.values(view.columns),
206
+ [],
207
+ casing,
208
+ );
209
+ statement += '})';
210
+ statement += `.as(sql\`${view.definition?.replaceAll('`', '\\`')}\`);`;
211
+
212
+ return statement;
213
+ });
214
+
215
+ const uniqueSqliteImports = [
216
+ 'sqliteTable',
217
+ 'AnySQLiteColumn',
218
+ ...new Set(imports.sqlite),
219
+ ];
220
+
221
+ const importsTs = `import { ${
222
+ uniqueSqliteImports.join(
223
+ ', ',
224
+ )
225
+ } } from "drizzle-orm/sqlite-core"
226
+ import { sql } from "drizzle-orm"\n\n`;
227
+
228
+ let decalrations = tableStatements.join('\n\n');
229
+ decalrations += '\n\n';
230
+ decalrations += viewsStatements.join('\n\n');
231
+
232
+ const file = importsTs + decalrations;
233
+
234
+ // for drizzle studio query runner
235
+ const schemaEntry = `
236
+ {
237
+ ${
238
+ Object.values(schema.tables)
239
+ .map((it) => withCasing(it.name, casing))
240
+ .join(',')
241
+ }
242
+ }
243
+ `;
244
+
245
+ return { file, imports: importsTs, decalrations, schemaEntry };
246
+ };
247
+
248
+ const isCyclic = (fk: ForeignKey) => {
249
+ const key = `${fk.tableFrom}-${fk.tableTo}`;
250
+ const reverse = `${fk.tableTo}-${fk.tableFrom}`;
251
+ return relations.has(key) && relations.has(reverse);
252
+ };
253
+
254
+ const isSelf = (fk: ForeignKey) => {
255
+ return fk.tableFrom === fk.tableTo;
256
+ };
257
+
258
+ const mapColumnDefault = (defaultValue: any) => {
259
+ if (
260
+ typeof defaultValue === 'string'
261
+ && defaultValue.startsWith('(')
262
+ && defaultValue.endsWith(')')
263
+ ) {
264
+ return `sql\`${defaultValue}\``;
265
+ }
266
+ // If default value is NULL as string it will come back from db as "'NULL'" and not just "NULL"
267
+ if (defaultValue === 'NULL') {
268
+ return `sql\`NULL\``;
269
+ }
270
+
271
+ if (
272
+ typeof defaultValue === 'string'
273
+ ) {
274
+ return defaultValue.substring(1, defaultValue.length - 1).replaceAll('"', '\\"').replaceAll("''", "'");
275
+ }
276
+
277
+ return defaultValue;
278
+ };
279
+
280
+ const column = (
281
+ type: string,
282
+ name: string,
283
+ defaultValue?: any,
284
+ autoincrement?: boolean,
285
+ casing?: Casing,
286
+ ) => {
287
+ let lowered = type;
288
+ casing = casing!;
289
+
290
+ if (lowered === 'integer') {
291
+ let out = `${withCasing(name, casing)}: integer(${dbColumnName({ name, casing })})`;
292
+ // out += autoincrement ? `.autoincrement()` : "";
293
+ out += typeof defaultValue !== 'undefined'
294
+ ? `.default(${mapColumnDefault(defaultValue)})`
295
+ : '';
296
+ return out;
297
+ }
298
+
299
+ if (lowered === 'real') {
300
+ let out = `${withCasing(name, casing)}: real(${dbColumnName({ name, casing })})`;
301
+ out += defaultValue ? `.default(${mapColumnDefault(defaultValue)})` : '';
302
+ return out;
303
+ }
304
+
305
+ if (lowered.startsWith('text')) {
306
+ const match = lowered.match(/\d+/);
307
+ let out: string;
308
+
309
+ if (match) {
310
+ out = `${withCasing(name, casing)}: text(${dbColumnName({ name, casing, withMode: true })}{ length: ${
311
+ match[0]
312
+ } })`;
313
+ } else {
314
+ out = `${withCasing(name, casing)}: text(${dbColumnName({ name, casing })})`;
315
+ }
316
+
317
+ out += defaultValue ? `.default("${mapColumnDefault(defaultValue)}")` : '';
318
+ return out;
319
+ }
320
+
321
+ if (lowered === 'blob') {
322
+ let out = `${withCasing(name, casing)}: blob(${dbColumnName({ name, casing })})`;
323
+ out += defaultValue ? `.default(${mapColumnDefault(defaultValue)})` : '';
324
+ return out;
325
+ }
326
+
327
+ if (lowered === 'numeric') {
328
+ let out = `${withCasing(name, casing)}: numeric(${dbColumnName({ name, casing })})`;
329
+ out += defaultValue ? `.default(${mapColumnDefault(defaultValue)})` : '';
330
+ return out;
331
+ }
332
+
333
+ // console.log("uknown", type);
334
+ return `// Warning: Can't parse ${type} from database\n\t// ${type}Type: ${type}("${name}")`;
335
+ };
336
+
337
+ const createTableColumns = (
338
+ columns: Column[],
339
+ fks: ForeignKey[],
340
+ casing: Casing,
341
+ ): string => {
342
+ let statement = '';
343
+
344
+ // no self refs and no cyclic
345
+ const oneColumnsFKs = Object.values(fks)
346
+ .filter((it) => {
347
+ return !isSelf(it);
348
+ })
349
+ .filter((it) => it.columnsFrom.length === 1);
350
+
351
+ const fkByColumnName = oneColumnsFKs.reduce((res, it) => {
352
+ const arr = res[it.columnsFrom[0]] || [];
353
+ arr.push(it);
354
+ res[it.columnsFrom[0]] = arr;
355
+ return res;
356
+ }, {} as Record<string, ForeignKey[]>);
357
+
358
+ columns.forEach((it) => {
359
+ statement += '\t';
360
+ statement += column(it.type, it.name, it.default, it.autoincrement, casing);
361
+ statement += it.primaryKey
362
+ ? `.primaryKey(${it.autoincrement ? '{ autoIncrement: true }' : ''})`
363
+ : '';
364
+ statement += it.notNull ? '.notNull()' : '';
365
+
366
+ statement += it.generated
367
+ ? `.generatedAlwaysAs(sql\`${
368
+ it.generated.as
369
+ .replace(/`/g, '\\`')
370
+ .slice(1, -1)
371
+ }\`, { mode: "${it.generated.type}" })`
372
+ : '';
373
+
374
+ const fks = fkByColumnName[it.name];
375
+ if (fks) {
376
+ const fksStatement = fks
377
+ .map((it) => {
378
+ const onDelete = it.onDelete && it.onDelete !== 'no action' ? it.onDelete : null;
379
+ const onUpdate = it.onUpdate && it.onUpdate !== 'no action' ? it.onUpdate : null;
380
+ const params = { onDelete, onUpdate };
381
+
382
+ const typeSuffix = isCyclic(it) ? ': AnySQLiteColumn' : '';
383
+
384
+ const paramsStr = objToStatement2(params);
385
+ if (paramsStr) {
386
+ return `.references(()${typeSuffix} => ${
387
+ withCasing(
388
+ it.tableTo,
389
+ casing,
390
+ )
391
+ }.${withCasing(it.columnsTo[0], casing)}, ${paramsStr} )`;
392
+ }
393
+ return `.references(()${typeSuffix} => ${
394
+ withCasing(
395
+ it.tableTo,
396
+ casing,
397
+ )
398
+ }.${withCasing(it.columnsTo[0], casing)})`;
399
+ })
400
+ .join('');
401
+ statement += fksStatement;
402
+ }
403
+
404
+ statement += ',\n';
405
+ });
406
+
407
+ return statement;
408
+ };
409
+
410
+ const createTableIndexes = (
411
+ tableName: string,
412
+ idxs: Index[],
413
+ casing: Casing,
414
+ ): string => {
415
+ let statement = '';
416
+
417
+ idxs.forEach((it) => {
418
+ let idxKey = it.name.startsWith(tableName) && it.name !== tableName
419
+ ? it.name.slice(tableName.length + 1)
420
+ : it.name;
421
+ idxKey = idxKey.endsWith('_index')
422
+ ? idxKey.slice(0, -'_index'.length) + '_idx'
423
+ : idxKey;
424
+
425
+ idxKey = withCasing(idxKey, casing);
426
+
427
+ const indexGeneratedName = indexName(tableName, it.columns);
428
+ const escapedIndexName = indexGeneratedName === it.name ? '' : `"${it.name}"`;
429
+
430
+ statement += `\n\t`;
431
+ statement += it.isUnique ? 'uniqueIndex(' : 'index(';
432
+ statement += `${escapedIndexName})`;
433
+ statement += `.on(${
434
+ it.columns
435
+ .map((it) => `table.${withCasing(it, casing)}`)
436
+ .join(', ')
437
+ }),`;
438
+ });
439
+
440
+ return statement;
441
+ };
442
+
443
+ const createTableUniques = (
444
+ unqs: UniqueConstraint[],
445
+ casing: Casing,
446
+ ): string => {
447
+ let statement = '';
448
+
449
+ unqs.forEach((it) => {
450
+ const idxKey = withCasing(it.name, casing);
451
+
452
+ statement += `\n\t`;
453
+ statement += 'unique(';
454
+ statement += `"${it.name}")`;
455
+ statement += `.on(${
456
+ it.columns
457
+ .map((it) => `table.${withCasing(it, casing)}`)
458
+ .join(', ')
459
+ }),`;
460
+ });
461
+
462
+ return statement;
463
+ };
464
+ const createTableChecks = (
465
+ checks: CheckConstraint[],
466
+ casing: Casing,
467
+ ): string => {
468
+ let statement = '';
469
+
470
+ checks.forEach((it) => {
471
+ statement += `\n\t`;
472
+ statement += 'check(';
473
+ statement += `"${it.name}", `;
474
+ statement += `sql\`${it.value}\`)`;
475
+ statement += `,`;
476
+ });
477
+
478
+ return statement;
479
+ };
480
+
481
+ const createTablePKs = (pks: PrimaryKey[], casing: Casing): string => {
482
+ let statement = '';
483
+
484
+ pks.forEach((it, i) => {
485
+ statement += `\n\t`;
486
+ statement += 'primaryKey({ columns: [';
487
+ statement += `${
488
+ it.columns
489
+ .map((c) => {
490
+ return `table.${withCasing(c, casing)}`;
491
+ })
492
+ .join(', ')
493
+ }]${it.name ? `, name: "${it.name}"` : ''}}`;
494
+ statement += ')';
495
+ });
496
+
497
+ return statement;
498
+ };
499
+
500
+ const createTableFKs = (fks: ForeignKey[], casing: Casing): string => {
501
+ let statement = '';
502
+
503
+ fks.forEach((it) => {
504
+ const isSelf = it.tableTo === it.tableFrom;
505
+ const tableTo = isSelf ? 'table' : `${withCasing(it.tableTo, casing)}`;
506
+ statement += `\n\t`;
507
+ statement += `foreignKey(() => ({\n`;
508
+ statement += `\t\t\tcolumns: [${
509
+ it.columnsFrom
510
+ .map((i) => `table.${withCasing(i, casing)}`)
511
+ .join(', ')
512
+ }],\n`;
513
+ statement += `\t\t\tforeignColumns: [${
514
+ it.columnsTo
515
+ .map((i) => `${tableTo}.${withCasing(i, casing)}`)
516
+ .join(', ')
517
+ }],\n`;
518
+ statement += `\t\t\tname: "${it.name}"\n`;
519
+ statement += `\t\t}))`;
520
+
521
+ statement += it.onUpdate && it.onUpdate !== 'no action'
522
+ ? `.onUpdate("${it.onUpdate}")`
523
+ : '';
524
+
525
+ statement += it.onDelete && it.onDelete !== 'no action'
526
+ ? `.onDelete("${it.onDelete}")`
527
+ : '';
528
+
529
+ statement += `,`;
530
+ });
531
+
532
+ return statement;
533
+ };