@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,2852 @@
1
+ import { PGlite } from '@electric-sql/pglite';
2
+ import { Client } from '@libsql/client/.';
3
+ import { Database } from 'better-sqlite3';
4
+ import { is } from 'drizzle-orm';
5
+ import { MySqlSchema, MySqlTable, MySqlView } from 'drizzle-orm/mysql-core';
6
+ import {
7
+ getMaterializedViewConfig,
8
+ isPgDomain,
9
+ isPgEnum,
10
+ isPgMaterializedView,
11
+ isPgSequence,
12
+ isPgView,
13
+ PgDomain,
14
+ PgEnum,
15
+ PgMaterializedView,
16
+ PgPolicy,
17
+ PgRole,
18
+ PgSchema,
19
+ PgSequence,
20
+ PgTable,
21
+ PgView,
22
+ } from 'drizzle-orm/pg-core';
23
+ import { SingleStoreSchema, SingleStoreTable } from 'drizzle-orm/singlestore-core';
24
+ import { SQLiteTable, SQLiteView } from 'drizzle-orm/sqlite-core';
25
+ import * as fs from 'fs';
26
+ import { Connection } from 'mysql2/promise';
27
+ import { libSqlLogSuggestionsAndReturn } from 'src/cli/commands/libSqlPushUtils';
28
+ import {
29
+ columnsResolver,
30
+ domainsResolver,
31
+ enumsResolver,
32
+ indPolicyResolver,
33
+ mySqlViewsResolver,
34
+ Named,
35
+ policyResolver,
36
+ roleResolver,
37
+ schemasResolver,
38
+ sequencesResolver,
39
+ sqliteViewsResolver,
40
+ tablesResolver,
41
+ viewsResolver,
42
+ } from 'src/cli/commands/migrate';
43
+ import { pgSuggestions } from 'src/cli/commands/pgPushUtils';
44
+ import { logSuggestionsAndReturn as singleStoreLogSuggestionsAndReturn } from 'src/cli/commands/singlestorePushUtils';
45
+ import { logSuggestionsAndReturn } from 'src/cli/commands/sqlitePushUtils';
46
+ import { Entities } from 'src/cli/validations/cli';
47
+ import { CasingType } from 'src/cli/validations/common';
48
+ import { snapshotVersion } from 'src/global';
49
+ import { schemaToTypeScript as schemaToTypeScriptMySQL } from 'src/introspect-mysql';
50
+ import { schemaToTypeScript } from 'src/introspect-pg';
51
+ import { schemaToTypeScript as schemaToTypeScriptSingleStore } from 'src/introspect-singlestore';
52
+ import { schemaToTypeScript as schemaToTypeScriptSQLite } from 'src/introspect-sqlite';
53
+ import { prepareFromMySqlImports } from 'src/serializer/mysqlImports';
54
+ import { mysqlSchema, squashMysqlScheme, ViewSquashed } from 'src/serializer/mysqlSchema';
55
+ import { fromDatabase as fromMySqlDatabase, generateMySqlSnapshot } from 'src/serializer/mysqlSerializer';
56
+ import { prepareFromPgImports } from 'src/serializer/pgImports';
57
+ import { pgSchema, Policy, Role, squashPgScheme, View } from 'src/serializer/pgSchema';
58
+ import { fromDatabase, generatePgSnapshot } from 'src/serializer/pgSerializer';
59
+ import { prepareFromSingleStoreImports } from 'src/serializer/singlestoreImports';
60
+ import { singlestoreSchema, squashSingleStoreScheme } from 'src/serializer/singlestoreSchema';
61
+ import {
62
+ fromDatabase as fromSingleStoreDatabase,
63
+ generateSingleStoreSnapshot,
64
+ } from 'src/serializer/singlestoreSerializer';
65
+ import { prepareFromSqliteImports } from 'src/serializer/sqliteImports';
66
+ import { sqliteSchema, squashSqliteScheme, View as SqliteView } from 'src/serializer/sqliteSchema';
67
+ import { fromDatabase as fromSqliteDatabase, generateSqliteSnapshot } from 'src/serializer/sqliteSerializer';
68
+ import {
69
+ applyLibSQLSnapshotsDiff,
70
+ applyMysqlSnapshotsDiff,
71
+ applyPgSnapshotsDiff,
72
+ applySingleStoreSnapshotsDiff,
73
+ applySqliteSnapshotsDiff,
74
+ Column,
75
+ ColumnsResolverInput,
76
+ ColumnsResolverOutput,
77
+ Domain,
78
+ Enum,
79
+ PolicyResolverInput,
80
+ PolicyResolverOutput,
81
+ ResolverInput,
82
+ ResolverOutput,
83
+ ResolverOutputWithMoved,
84
+ RolesResolverInput,
85
+ RolesResolverOutput,
86
+ Sequence,
87
+ Table,
88
+ TablePolicyResolverInput,
89
+ TablePolicyResolverOutput,
90
+ } from 'src/snapshotsDiffer';
91
+
92
+ export type PostgresSchema = Record<
93
+ string,
94
+ | PgTable<any>
95
+ | PgDomain<any>
96
+ | PgEnum<any>
97
+ | PgSchema
98
+ | PgSequence
99
+ | PgView
100
+ | PgMaterializedView
101
+ | PgRole
102
+ | PgPolicy
103
+ >;
104
+ export type MysqlSchema = Record<
105
+ string,
106
+ MySqlTable<any> | MySqlSchema | MySqlView
107
+ >;
108
+ export type SqliteSchema = Record<string, SQLiteTable<any> | SQLiteView>;
109
+ export type SinglestoreSchema = Record<
110
+ string,
111
+ SingleStoreTable<any> | SingleStoreSchema /* | SingleStoreView */
112
+ >;
113
+
114
+ export const testSchemasResolver =
115
+ (renames: Set<string>) => async (input: ResolverInput<Named>): Promise<ResolverOutput<Named>> => {
116
+ try {
117
+ if (
118
+ input.created.length === 0
119
+ || input.deleted.length === 0
120
+ || renames.size === 0
121
+ ) {
122
+ return {
123
+ created: input.created,
124
+ renamed: [],
125
+ deleted: input.deleted,
126
+ };
127
+ }
128
+
129
+ let createdSchemas = [...input.created];
130
+ let deletedSchemas = [...input.deleted];
131
+
132
+ const result: {
133
+ created: Named[];
134
+ renamed: { from: Named; to: Named }[];
135
+ deleted: Named[];
136
+ } = { created: [], renamed: [], deleted: [] };
137
+
138
+ for (let rename of renames) {
139
+ const [from, to] = rename.split('->');
140
+
141
+ const idxFrom = deletedSchemas.findIndex((it) => {
142
+ return it.name === from;
143
+ });
144
+
145
+ if (idxFrom >= 0) {
146
+ const idxTo = createdSchemas.findIndex((it) => {
147
+ return it.name === to;
148
+ });
149
+
150
+ result.renamed.push({
151
+ from: deletedSchemas[idxFrom],
152
+ to: createdSchemas[idxTo],
153
+ });
154
+
155
+ delete createdSchemas[idxTo];
156
+ delete deletedSchemas[idxFrom];
157
+
158
+ createdSchemas = createdSchemas.filter(Boolean);
159
+ deletedSchemas = deletedSchemas.filter(Boolean);
160
+ }
161
+ }
162
+
163
+ result.created = createdSchemas;
164
+ result.deleted = deletedSchemas;
165
+
166
+ return result;
167
+ } catch (e) {
168
+ console.error(e);
169
+ throw e;
170
+ }
171
+ };
172
+
173
+ export const testSequencesResolver = (renames: Set<string>) =>
174
+ async (
175
+ input: ResolverInput<Sequence>,
176
+ ): Promise<ResolverOutputWithMoved<Sequence>> => {
177
+ try {
178
+ if (
179
+ input.created.length === 0
180
+ || input.deleted.length === 0
181
+ || renames.size === 0
182
+ ) {
183
+ return {
184
+ created: input.created,
185
+ moved: [],
186
+ renamed: [],
187
+ deleted: input.deleted,
188
+ };
189
+ }
190
+
191
+ let createdSequences = [...input.created];
192
+ let deletedSequences = [...input.deleted];
193
+
194
+ const result: {
195
+ created: Sequence[];
196
+ moved: { name: string; schemaFrom: string; schemaTo: string }[];
197
+ renamed: { from: Sequence; to: Sequence }[];
198
+ deleted: Sequence[];
199
+ } = { created: [], renamed: [], deleted: [], moved: [] };
200
+
201
+ for (let rename of renames) {
202
+ const [from, to] = rename.split('->');
203
+
204
+ const idxFrom = deletedSequences.findIndex((it) => {
205
+ return `${it.schema || 'public'}.${it.name}` === from;
206
+ });
207
+
208
+ if (idxFrom >= 0) {
209
+ const idxTo = createdSequences.findIndex((it) => {
210
+ return `${it.schema || 'public'}.${it.name}` === to;
211
+ });
212
+
213
+ const tableFrom = deletedSequences[idxFrom];
214
+ const tableTo = createdSequences[idxFrom];
215
+
216
+ if (tableFrom.schema !== tableTo.schema) {
217
+ result.moved.push({
218
+ name: tableFrom.name,
219
+ schemaFrom: tableFrom.schema,
220
+ schemaTo: tableTo.schema,
221
+ });
222
+ }
223
+
224
+ if (tableFrom.name !== tableTo.name) {
225
+ result.renamed.push({
226
+ from: deletedSequences[idxFrom],
227
+ to: createdSequences[idxTo],
228
+ });
229
+ }
230
+
231
+ delete createdSequences[idxTo];
232
+ delete deletedSequences[idxFrom];
233
+
234
+ createdSequences = createdSequences.filter(Boolean);
235
+ deletedSequences = deletedSequences.filter(Boolean);
236
+ }
237
+ }
238
+
239
+ result.created = createdSequences;
240
+ result.deleted = deletedSequences;
241
+
242
+ return result;
243
+ } catch (e) {
244
+ console.error(e);
245
+ throw e;
246
+ }
247
+ };
248
+
249
+ export const testEnumsResolver = (renames: Set<string>) =>
250
+ async (
251
+ input: ResolverInput<Enum>,
252
+ ): Promise<ResolverOutputWithMoved<Enum>> => {
253
+ try {
254
+ if (
255
+ input.created.length === 0
256
+ || input.deleted.length === 0
257
+ || renames.size === 0
258
+ ) {
259
+ return {
260
+ created: input.created,
261
+ moved: [],
262
+ renamed: [],
263
+ deleted: input.deleted,
264
+ };
265
+ }
266
+
267
+ let createdEnums = [...input.created];
268
+ let deletedEnums = [...input.deleted];
269
+
270
+ const result: {
271
+ created: Enum[];
272
+ moved: { name: string; schemaFrom: string; schemaTo: string }[];
273
+ renamed: { from: Enum; to: Enum }[];
274
+ deleted: Enum[];
275
+ } = { created: [], renamed: [], deleted: [], moved: [] };
276
+
277
+ for (let rename of renames) {
278
+ const [from, to] = rename.split('->');
279
+
280
+ const idxFrom = deletedEnums.findIndex((it) => {
281
+ return `${it.schema || 'public'}.${it.name}` === from;
282
+ });
283
+
284
+ if (idxFrom >= 0) {
285
+ const idxTo = createdEnums.findIndex((it) => {
286
+ return `${it.schema || 'public'}.${it.name}` === to;
287
+ });
288
+
289
+ const tableFrom = deletedEnums[idxFrom];
290
+ const tableTo = createdEnums[idxFrom];
291
+
292
+ if (tableFrom.schema !== tableTo.schema) {
293
+ result.moved.push({
294
+ name: tableFrom.name,
295
+ schemaFrom: tableFrom.schema,
296
+ schemaTo: tableTo.schema,
297
+ });
298
+ }
299
+
300
+ if (tableFrom.name !== tableTo.name) {
301
+ result.renamed.push({
302
+ from: deletedEnums[idxFrom],
303
+ to: createdEnums[idxTo],
304
+ });
305
+ }
306
+
307
+ delete createdEnums[idxTo];
308
+ delete deletedEnums[idxFrom];
309
+
310
+ createdEnums = createdEnums.filter(Boolean);
311
+ deletedEnums = deletedEnums.filter(Boolean);
312
+ }
313
+ }
314
+
315
+ result.created = createdEnums;
316
+ result.deleted = deletedEnums;
317
+
318
+ return result;
319
+ } catch (e) {
320
+ console.error(e);
321
+ throw e;
322
+ }
323
+ };
324
+
325
+ export const testTablesResolver = (renames: Set<string>) =>
326
+ async (
327
+ input: ResolverInput<Table>,
328
+ ): Promise<ResolverOutputWithMoved<Table>> => {
329
+ try {
330
+ if (
331
+ input.created.length === 0
332
+ || input.deleted.length === 0
333
+ || renames.size === 0
334
+ ) {
335
+ return {
336
+ created: input.created,
337
+ moved: [],
338
+ renamed: [],
339
+ deleted: input.deleted,
340
+ };
341
+ }
342
+
343
+ let createdTables = [...input.created];
344
+ let deletedTables = [...input.deleted];
345
+
346
+ const result: {
347
+ created: Table[];
348
+ moved: { name: string; schemaFrom: string; schemaTo: string }[];
349
+ renamed: { from: Table; to: Table }[];
350
+ deleted: Table[];
351
+ } = { created: [], renamed: [], deleted: [], moved: [] };
352
+
353
+ for (let rename of renames) {
354
+ const [from, to] = rename.split('->');
355
+
356
+ const idxFrom = deletedTables.findIndex((it) => {
357
+ return `${it.schema || 'public'}.${it.name}` === from;
358
+ });
359
+
360
+ if (idxFrom >= 0) {
361
+ const idxTo = createdTables.findIndex((it) => {
362
+ return `${it.schema || 'public'}.${it.name}` === to;
363
+ });
364
+
365
+ const tableFrom = deletedTables[idxFrom];
366
+ const tableTo = createdTables[idxFrom];
367
+
368
+ if (tableFrom.schema !== tableTo.schema) {
369
+ result.moved.push({
370
+ name: tableFrom.name,
371
+ schemaFrom: tableFrom.schema,
372
+ schemaTo: tableTo.schema,
373
+ });
374
+ }
375
+
376
+ if (tableFrom.name !== tableTo.name) {
377
+ result.renamed.push({
378
+ from: deletedTables[idxFrom],
379
+ to: createdTables[idxTo],
380
+ });
381
+ }
382
+
383
+ delete createdTables[idxTo];
384
+ delete deletedTables[idxFrom];
385
+
386
+ createdTables = createdTables.filter(Boolean);
387
+ deletedTables = deletedTables.filter(Boolean);
388
+ }
389
+ }
390
+
391
+ result.created = createdTables;
392
+ result.deleted = deletedTables;
393
+
394
+ return result;
395
+ } catch (e) {
396
+ console.error(e);
397
+ throw e;
398
+ }
399
+ };
400
+
401
+ export const testColumnsResolver = (renames: Set<string>) =>
402
+ async (
403
+ input: ColumnsResolverInput<Column>,
404
+ ): Promise<ColumnsResolverOutput<Column>> => {
405
+ try {
406
+ if (
407
+ input.created.length === 0
408
+ || input.deleted.length === 0
409
+ || renames.size === 0
410
+ ) {
411
+ return {
412
+ tableName: input.tableName,
413
+ schema: input.schema,
414
+ created: input.created,
415
+ renamed: [],
416
+ deleted: input.deleted,
417
+ };
418
+ }
419
+
420
+ let createdColumns = [...input.created];
421
+ let deletedColumns = [...input.deleted];
422
+
423
+ const renamed: { from: Column; to: Column }[] = [];
424
+
425
+ const schema = input.schema || 'public';
426
+
427
+ for (let rename of renames) {
428
+ const [from, to] = rename.split('->');
429
+
430
+ const idxFrom = deletedColumns.findIndex((it) => {
431
+ return `${schema}.${input.tableName}.${it.name}` === from;
432
+ });
433
+
434
+ if (idxFrom >= 0) {
435
+ const idxTo = createdColumns.findIndex((it) => {
436
+ return `${schema}.${input.tableName}.${it.name}` === to;
437
+ });
438
+
439
+ renamed.push({
440
+ from: deletedColumns[idxFrom],
441
+ to: createdColumns[idxTo],
442
+ });
443
+
444
+ delete createdColumns[idxTo];
445
+ delete deletedColumns[idxFrom];
446
+
447
+ createdColumns = createdColumns.filter(Boolean);
448
+ deletedColumns = deletedColumns.filter(Boolean);
449
+ }
450
+ }
451
+
452
+ return {
453
+ tableName: input.tableName,
454
+ schema: input.schema,
455
+ created: createdColumns,
456
+ deleted: deletedColumns,
457
+ renamed,
458
+ };
459
+ } catch (e) {
460
+ console.error(e);
461
+ throw e;
462
+ }
463
+ };
464
+
465
+ export const testPolicyResolver = (renames: Set<string>) =>
466
+ async (
467
+ input: TablePolicyResolverInput<Policy>,
468
+ ): Promise<TablePolicyResolverOutput<Policy>> => {
469
+ try {
470
+ if (
471
+ input.created.length === 0
472
+ || input.deleted.length === 0
473
+ || renames.size === 0
474
+ ) {
475
+ return {
476
+ tableName: input.tableName,
477
+ schema: input.schema,
478
+ created: input.created,
479
+ renamed: [],
480
+ deleted: input.deleted,
481
+ };
482
+ }
483
+
484
+ let createdPolicies = [...input.created];
485
+ let deletedPolicies = [...input.deleted];
486
+
487
+ const renamed: { from: Policy; to: Policy }[] = [];
488
+
489
+ const schema = input.schema || 'public';
490
+
491
+ for (let rename of renames) {
492
+ const [from, to] = rename.split('->');
493
+
494
+ const idxFrom = deletedPolicies.findIndex((it) => {
495
+ return `${schema}.${input.tableName}.${it.name}` === from;
496
+ });
497
+
498
+ if (idxFrom >= 0) {
499
+ const idxTo = createdPolicies.findIndex((it) => {
500
+ return `${schema}.${input.tableName}.${it.name}` === to;
501
+ });
502
+
503
+ renamed.push({
504
+ from: deletedPolicies[idxFrom],
505
+ to: createdPolicies[idxTo],
506
+ });
507
+
508
+ delete createdPolicies[idxTo];
509
+ delete deletedPolicies[idxFrom];
510
+
511
+ createdPolicies = createdPolicies.filter(Boolean);
512
+ deletedPolicies = deletedPolicies.filter(Boolean);
513
+ }
514
+ }
515
+
516
+ return {
517
+ tableName: input.tableName,
518
+ schema: input.schema,
519
+ created: createdPolicies,
520
+ deleted: deletedPolicies,
521
+ renamed,
522
+ };
523
+ } catch (e) {
524
+ console.error(e);
525
+ throw e;
526
+ }
527
+ };
528
+
529
+ export const testIndPolicyResolver = (renames: Set<string>) =>
530
+ async (
531
+ input: PolicyResolverInput<Policy>,
532
+ ): Promise<PolicyResolverOutput<Policy>> => {
533
+ try {
534
+ if (
535
+ input.created.length === 0
536
+ || input.deleted.length === 0
537
+ || renames.size === 0
538
+ ) {
539
+ return {
540
+ created: input.created,
541
+ renamed: [],
542
+ deleted: input.deleted,
543
+ };
544
+ }
545
+
546
+ let createdPolicies = [...input.created];
547
+ let deletedPolicies = [...input.deleted];
548
+
549
+ const renamed: { from: Policy; to: Policy }[] = [];
550
+
551
+ for (let rename of renames) {
552
+ const [from, to] = rename.split('->');
553
+
554
+ const idxFrom = deletedPolicies.findIndex((it) => {
555
+ return `${it.on}.${it.name}` === from;
556
+ });
557
+
558
+ if (idxFrom >= 0) {
559
+ const idxTo = createdPolicies.findIndex((it) => {
560
+ return `${it.on}.${it.name}` === to;
561
+ });
562
+
563
+ renamed.push({
564
+ from: deletedPolicies[idxFrom],
565
+ to: createdPolicies[idxTo],
566
+ });
567
+
568
+ delete createdPolicies[idxTo];
569
+ delete deletedPolicies[idxFrom];
570
+
571
+ createdPolicies = createdPolicies.filter(Boolean);
572
+ deletedPolicies = deletedPolicies.filter(Boolean);
573
+ }
574
+ }
575
+
576
+ return {
577
+ created: createdPolicies,
578
+ deleted: deletedPolicies,
579
+ renamed,
580
+ };
581
+ } catch (e) {
582
+ console.error(e);
583
+ throw e;
584
+ }
585
+ };
586
+
587
+ export const testRolesResolver = (renames: Set<string>) =>
588
+ async (
589
+ input: RolesResolverInput<Role>,
590
+ ): Promise<RolesResolverOutput<Role>> => {
591
+ try {
592
+ if (
593
+ input.created.length === 0
594
+ || input.deleted.length === 0
595
+ || renames.size === 0
596
+ ) {
597
+ return {
598
+ created: input.created,
599
+ renamed: [],
600
+ deleted: input.deleted,
601
+ };
602
+ }
603
+
604
+ let createdPolicies = [...input.created];
605
+ let deletedPolicies = [...input.deleted];
606
+
607
+ const renamed: { from: Policy; to: Policy }[] = [];
608
+
609
+ for (let rename of renames) {
610
+ const [from, to] = rename.split('->');
611
+
612
+ const idxFrom = deletedPolicies.findIndex((it) => {
613
+ return `${it.name}` === from;
614
+ });
615
+
616
+ if (idxFrom >= 0) {
617
+ const idxTo = createdPolicies.findIndex((it) => {
618
+ return `${it.name}` === to;
619
+ });
620
+
621
+ renamed.push({
622
+ from: deletedPolicies[idxFrom],
623
+ to: createdPolicies[idxTo],
624
+ });
625
+
626
+ delete createdPolicies[idxTo];
627
+ delete deletedPolicies[idxFrom];
628
+
629
+ createdPolicies = createdPolicies.filter(Boolean);
630
+ deletedPolicies = deletedPolicies.filter(Boolean);
631
+ }
632
+ }
633
+
634
+ return {
635
+ created: createdPolicies,
636
+ deleted: deletedPolicies,
637
+ renamed,
638
+ };
639
+ } catch (e) {
640
+ console.error(e);
641
+ throw e;
642
+ }
643
+ };
644
+
645
+ export const testDomainsResolver = (renames: Set<string>) =>
646
+ async (
647
+ input: ResolverInput<Domain>,
648
+ ): Promise<ResolverOutputWithMoved<Domain>> => {
649
+ try {
650
+ if (
651
+ input.created.length === 0
652
+ || input.deleted.length === 0
653
+ || renames.size === 0
654
+ ) {
655
+ return {
656
+ created: input.created,
657
+ moved: [],
658
+ renamed: [],
659
+ deleted: input.deleted,
660
+ };
661
+ }
662
+
663
+ let createdDomains = [...input.created];
664
+ let deletedDomains = [...input.deleted];
665
+
666
+ const result: {
667
+ created: Domain[];
668
+ moved: { name: string; schemaFrom: string; schemaTo: string }[];
669
+ renamed: { from: Domain; to: Domain }[];
670
+ deleted: Domain[];
671
+ } = { created: [], renamed: [], deleted: [], moved: [] };
672
+
673
+ for (let rename of renames) {
674
+ const [from, to] = rename.split('->');
675
+
676
+ const idxFrom = deletedDomains.findIndex((it) => {
677
+ return `${it.schema || 'public'}.${it.name}` === from;
678
+ });
679
+
680
+ if (idxFrom >= 0) {
681
+ const idxTo = createdDomains.findIndex((it) => {
682
+ return `${it.schema || 'public'}.${it.name}` === to;
683
+ });
684
+
685
+ const domainFrom = deletedDomains[idxFrom];
686
+ const domainTo = createdDomains[idxFrom];
687
+
688
+ if (domainFrom.schema !== domainTo.schema) {
689
+ result.moved.push({
690
+ name: domainFrom.name,
691
+ schemaFrom: domainFrom.schema,
692
+ schemaTo: domainTo.schema,
693
+ });
694
+ }
695
+
696
+ if (domainFrom.name !== domainTo.name) {
697
+ result.renamed.push({
698
+ from: deletedDomains[idxFrom],
699
+ to: createdDomains[idxTo],
700
+ });
701
+ }
702
+
703
+ delete createdDomains[idxTo];
704
+ delete deletedDomains[idxFrom];
705
+
706
+ createdDomains = createdDomains.filter(Boolean);
707
+ deletedDomains = deletedDomains.filter(Boolean);
708
+ }
709
+ }
710
+
711
+ result.created = createdDomains;
712
+ result.deleted = deletedDomains;
713
+
714
+ return result;
715
+ } catch (e) {
716
+ console.error(e);
717
+ throw e;
718
+ }
719
+ };
720
+
721
+ export const testViewsResolver = (renames: Set<string>) =>
722
+ async (
723
+ input: ResolverInput<View>,
724
+ ): Promise<ResolverOutputWithMoved<View>> => {
725
+ try {
726
+ if (
727
+ input.created.length === 0
728
+ || input.deleted.length === 0
729
+ || renames.size === 0
730
+ ) {
731
+ return {
732
+ created: input.created,
733
+ moved: [],
734
+ renamed: [],
735
+ deleted: input.deleted,
736
+ };
737
+ }
738
+
739
+ let createdViews = [...input.created];
740
+ let deletedViews = [...input.deleted];
741
+
742
+ const result: {
743
+ created: View[];
744
+ moved: { name: string; schemaFrom: string; schemaTo: string }[];
745
+ renamed: { from: View; to: View }[];
746
+ deleted: View[];
747
+ } = { created: [], renamed: [], deleted: [], moved: [] };
748
+
749
+ for (let rename of renames) {
750
+ const [from, to] = rename.split('->');
751
+
752
+ const idxFrom = deletedViews.findIndex((it) => {
753
+ return `${it.schema || 'public'}.${it.name}` === from;
754
+ });
755
+
756
+ if (idxFrom >= 0) {
757
+ const idxTo = createdViews.findIndex((it) => {
758
+ return `${it.schema || 'public'}.${it.name}` === to;
759
+ });
760
+
761
+ const viewFrom = deletedViews[idxFrom];
762
+ const viewTo = createdViews[idxFrom];
763
+
764
+ if (viewFrom.schema !== viewTo.schema) {
765
+ result.moved.push({
766
+ name: viewFrom.name,
767
+ schemaFrom: viewFrom.schema,
768
+ schemaTo: viewTo.schema,
769
+ });
770
+ }
771
+
772
+ if (viewFrom.name !== viewTo.name) {
773
+ result.renamed.push({
774
+ from: deletedViews[idxFrom],
775
+ to: createdViews[idxTo],
776
+ });
777
+ }
778
+
779
+ delete createdViews[idxTo];
780
+ delete deletedViews[idxFrom];
781
+
782
+ createdViews = createdViews.filter(Boolean);
783
+ deletedViews = deletedViews.filter(Boolean);
784
+ }
785
+ }
786
+
787
+ result.created = createdViews;
788
+ result.deleted = deletedViews;
789
+
790
+ return result;
791
+ } catch (e) {
792
+ console.error(e);
793
+ throw e;
794
+ }
795
+ };
796
+
797
+ export const testViewsResolverMySql = (renames: Set<string>) =>
798
+ async (
799
+ input: ResolverInput<ViewSquashed & { schema: '' }>,
800
+ ): Promise<ResolverOutputWithMoved<ViewSquashed>> => {
801
+ try {
802
+ if (
803
+ input.created.length === 0
804
+ || input.deleted.length === 0
805
+ || renames.size === 0
806
+ ) {
807
+ return {
808
+ created: input.created,
809
+ moved: [],
810
+ renamed: [],
811
+ deleted: input.deleted,
812
+ };
813
+ }
814
+
815
+ let createdViews = [...input.created];
816
+ let deletedViews = [...input.deleted];
817
+
818
+ const result: {
819
+ created: ViewSquashed[];
820
+ moved: { name: string; schemaFrom: string; schemaTo: string }[];
821
+ renamed: { from: ViewSquashed; to: ViewSquashed }[];
822
+ deleted: ViewSquashed[];
823
+ } = { created: [], renamed: [], deleted: [], moved: [] };
824
+
825
+ for (let rename of renames) {
826
+ const [from, to] = rename.split('->');
827
+
828
+ const idxFrom = deletedViews.findIndex((it) => {
829
+ return `${it.schema || 'public'}.${it.name}` === from;
830
+ });
831
+
832
+ if (idxFrom >= 0) {
833
+ const idxTo = createdViews.findIndex((it) => {
834
+ return `${it.schema || 'public'}.${it.name}` === to;
835
+ });
836
+
837
+ const viewFrom = deletedViews[idxFrom];
838
+ const viewTo = createdViews[idxFrom];
839
+
840
+ if (viewFrom.schema !== viewTo.schema) {
841
+ result.moved.push({
842
+ name: viewFrom.name,
843
+ schemaFrom: viewFrom.schema,
844
+ schemaTo: viewTo.schema,
845
+ });
846
+ }
847
+
848
+ if (viewFrom.name !== viewTo.name) {
849
+ result.renamed.push({
850
+ from: deletedViews[idxFrom],
851
+ to: createdViews[idxTo],
852
+ });
853
+ }
854
+
855
+ delete createdViews[idxTo];
856
+ delete deletedViews[idxFrom];
857
+
858
+ createdViews = createdViews.filter(Boolean);
859
+ deletedViews = deletedViews.filter(Boolean);
860
+ }
861
+ }
862
+
863
+ result.created = createdViews;
864
+ result.deleted = deletedViews;
865
+
866
+ return result;
867
+ } catch (e) {
868
+ console.error(e);
869
+ throw e;
870
+ }
871
+ };
872
+
873
+ export const testViewsResolverSingleStore = (renames: Set<string>) =>
874
+ async (
875
+ input: ResolverInput<ViewSquashed & { schema: '' }>,
876
+ ): Promise<ResolverOutputWithMoved<ViewSquashed>> => {
877
+ try {
878
+ if (
879
+ input.created.length === 0
880
+ || input.deleted.length === 0
881
+ || renames.size === 0
882
+ ) {
883
+ return {
884
+ created: input.created,
885
+ moved: [],
886
+ renamed: [],
887
+ deleted: input.deleted,
888
+ };
889
+ }
890
+
891
+ let createdViews = [...input.created];
892
+ let deletedViews = [...input.deleted];
893
+
894
+ const result: {
895
+ created: ViewSquashed[];
896
+ moved: { name: string; schemaFrom: string; schemaTo: string }[];
897
+ renamed: { from: ViewSquashed; to: ViewSquashed }[];
898
+ deleted: ViewSquashed[];
899
+ } = { created: [], renamed: [], deleted: [], moved: [] };
900
+
901
+ for (let rename of renames) {
902
+ const [from, to] = rename.split('->');
903
+
904
+ const idxFrom = deletedViews.findIndex((it) => {
905
+ return `${it.schema || 'public'}.${it.name}` === from;
906
+ });
907
+
908
+ if (idxFrom >= 0) {
909
+ const idxTo = createdViews.findIndex((it) => {
910
+ return `${it.schema || 'public'}.${it.name}` === to;
911
+ });
912
+
913
+ const viewFrom = deletedViews[idxFrom];
914
+ const viewTo = createdViews[idxFrom];
915
+
916
+ if (viewFrom.schema !== viewTo.schema) {
917
+ result.moved.push({
918
+ name: viewFrom.name,
919
+ schemaFrom: viewFrom.schema,
920
+ schemaTo: viewTo.schema,
921
+ });
922
+ }
923
+
924
+ if (viewFrom.name !== viewTo.name) {
925
+ result.renamed.push({
926
+ from: deletedViews[idxFrom],
927
+ to: createdViews[idxTo],
928
+ });
929
+ }
930
+
931
+ delete createdViews[idxTo];
932
+ delete deletedViews[idxFrom];
933
+
934
+ createdViews = createdViews.filter(Boolean);
935
+ deletedViews = deletedViews.filter(Boolean);
936
+ }
937
+ }
938
+
939
+ result.created = createdViews;
940
+ result.deleted = deletedViews;
941
+
942
+ return result;
943
+ } catch (e) {
944
+ console.error(e);
945
+ throw e;
946
+ }
947
+ };
948
+
949
+ export const testViewsResolverSqlite = (renames: Set<string>) =>
950
+ async (
951
+ input: ResolverInput<SqliteView>,
952
+ ): Promise<ResolverOutputWithMoved<SqliteView>> => {
953
+ try {
954
+ if (
955
+ input.created.length === 0
956
+ || input.deleted.length === 0
957
+ || renames.size === 0
958
+ ) {
959
+ return {
960
+ created: input.created,
961
+ moved: [],
962
+ renamed: [],
963
+ deleted: input.deleted,
964
+ };
965
+ }
966
+
967
+ let createdViews = [...input.created];
968
+ let deletedViews = [...input.deleted];
969
+
970
+ const result: {
971
+ created: SqliteView[];
972
+ moved: { name: string; schemaFrom: string; schemaTo: string }[];
973
+ renamed: { from: SqliteView; to: SqliteView }[];
974
+ deleted: SqliteView[];
975
+ } = { created: [], renamed: [], deleted: [], moved: [] };
976
+
977
+ for (let rename of renames) {
978
+ const [from, to] = rename.split('->');
979
+
980
+ const idxFrom = deletedViews.findIndex((it) => {
981
+ return it.name === from;
982
+ });
983
+
984
+ if (idxFrom >= 0) {
985
+ const idxTo = createdViews.findIndex((it) => {
986
+ return it.name === to;
987
+ });
988
+
989
+ const viewFrom = deletedViews[idxFrom];
990
+ const viewTo = createdViews[idxFrom];
991
+
992
+ if (viewFrom.name !== viewTo.name) {
993
+ result.renamed.push({
994
+ from: deletedViews[idxFrom],
995
+ to: createdViews[idxTo],
996
+ });
997
+ }
998
+
999
+ delete createdViews[idxTo];
1000
+ delete deletedViews[idxFrom];
1001
+
1002
+ createdViews = createdViews.filter(Boolean);
1003
+ deletedViews = deletedViews.filter(Boolean);
1004
+ }
1005
+ }
1006
+
1007
+ result.created = createdViews;
1008
+ result.deleted = deletedViews;
1009
+
1010
+ return result;
1011
+ } catch (e) {
1012
+ console.error(e);
1013
+ throw e;
1014
+ }
1015
+ };
1016
+
1017
+ export const diffTestSchemasPush = async (
1018
+ client: PGlite,
1019
+ left: PostgresSchema,
1020
+ right: PostgresSchema,
1021
+ renamesArr: string[],
1022
+ cli: boolean = false,
1023
+ schemas: string[] = ['public'],
1024
+ casing?: CasingType | undefined,
1025
+ entities?: Entities,
1026
+ sqlStatementsToRun: {
1027
+ before?: string[];
1028
+ after?: string[];
1029
+ runApply?: boolean;
1030
+ } = {
1031
+ before: [],
1032
+ after: [],
1033
+ runApply: true,
1034
+ },
1035
+ ) => {
1036
+ const shouldRunApply = sqlStatementsToRun.runApply === undefined
1037
+ ? true
1038
+ : sqlStatementsToRun.runApply;
1039
+
1040
+ for (const st of sqlStatementsToRun.before ?? []) {
1041
+ await client.query(st);
1042
+ }
1043
+
1044
+ if (shouldRunApply) {
1045
+ const res = await applyPgDiffs(left, casing);
1046
+ for (const st of res.sqlStatements) {
1047
+ await client.query(st);
1048
+ }
1049
+ }
1050
+
1051
+ for (const st of sqlStatementsToRun.after ?? []) {
1052
+ await client.query(st);
1053
+ }
1054
+
1055
+ const materializedViewsForRefresh = Object.values(left).filter((it) =>
1056
+ isPgMaterializedView(it)
1057
+ ) as PgMaterializedView[];
1058
+
1059
+ // refresh all mat views
1060
+ for (const view of materializedViewsForRefresh) {
1061
+ const viewConf = getMaterializedViewConfig(view);
1062
+ if (viewConf.isExisting) continue;
1063
+
1064
+ await client.exec(
1065
+ `REFRESH MATERIALIZED VIEW "${viewConf.schema ?? 'public'}"."${viewConf.name}"${
1066
+ viewConf.withNoData ? ' WITH NO DATA;' : ';'
1067
+ }`,
1068
+ );
1069
+ }
1070
+
1071
+ // do introspect into PgSchemaInternal
1072
+ const introspectedSchema = await fromDatabase(
1073
+ {
1074
+ query: async (query: string, values?: any[] | undefined) => {
1075
+ const res = await client.query(query, values);
1076
+ return res.rows as any[];
1077
+ },
1078
+ },
1079
+ undefined,
1080
+ schemas,
1081
+ entities,
1082
+ );
1083
+
1084
+ const leftTables = Object.values(right).filter((it) => is(it, PgTable)) as PgTable[];
1085
+
1086
+ const leftSchemas = Object.values(right).filter((it) => is(it, PgSchema)) as PgSchema[];
1087
+
1088
+ const leftEnums = Object.values(right).filter((it) => isPgEnum(it)) as PgEnum<any>[];
1089
+
1090
+ const leftSequences = Object.values(right).filter((it) => isPgSequence(it)) as PgSequence[];
1091
+
1092
+ const leftDomains = Object.values(right).filter((it) => isPgDomain(it)) as PgDomain<any>[];
1093
+
1094
+ const leftRoles = Object.values(right).filter((it) => is(it, PgRole)) as PgRole[];
1095
+
1096
+ const leftPolicies = Object.values(right).filter((it) => is(it, PgPolicy)) as PgPolicy[];
1097
+
1098
+ const leftViews = Object.values(right).filter((it) => isPgView(it)) as PgView[];
1099
+
1100
+ const leftMaterializedViews = Object.values(right).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[];
1101
+
1102
+ const serialized2 = generatePgSnapshot(
1103
+ leftTables,
1104
+ leftDomains,
1105
+ leftEnums,
1106
+ leftSchemas,
1107
+ leftSequences,
1108
+ leftRoles,
1109
+ leftPolicies,
1110
+ leftViews,
1111
+ leftMaterializedViews,
1112
+ casing,
1113
+ );
1114
+
1115
+ const { version: v1, dialect: d1, ...rest1 } = introspectedSchema;
1116
+ const { version: v2, dialect: d2, ...rest2 } = serialized2;
1117
+
1118
+ const sch1 = {
1119
+ version: snapshotVersion,
1120
+ dialect: 'postgresql',
1121
+ id: '0',
1122
+ prevId: '0',
1123
+ ...rest1,
1124
+ } as const;
1125
+
1126
+ const sch2 = {
1127
+ version: snapshotVersion,
1128
+ dialect: 'postgresql',
1129
+ id: '0',
1130
+ prevId: '0',
1131
+ ...rest2,
1132
+ } as const;
1133
+
1134
+ const sn1 = squashPgScheme(sch1, 'push');
1135
+ const sn2 = squashPgScheme(sch2, 'push');
1136
+
1137
+ const validatedPrev = pgSchema.parse(sch1);
1138
+ const validatedCur = pgSchema.parse(sch2);
1139
+
1140
+ const renames = new Set(renamesArr);
1141
+
1142
+ if (!cli) {
1143
+ const { sqlStatements, statements } = await applyPgSnapshotsDiff(
1144
+ sn1,
1145
+ sn2,
1146
+ testSchemasResolver(renames),
1147
+ testDomainsResolver(renames),
1148
+ testEnumsResolver(renames),
1149
+ testSequencesResolver(renames),
1150
+ testPolicyResolver(renames),
1151
+ testIndPolicyResolver(renames),
1152
+ testRolesResolver(renames),
1153
+ testTablesResolver(renames),
1154
+ testColumnsResolver(renames),
1155
+ testViewsResolver(renames),
1156
+ validatedPrev,
1157
+ validatedCur,
1158
+ 'push',
1159
+ );
1160
+
1161
+ const {
1162
+ shouldAskForApprove,
1163
+ statementsToExecute,
1164
+ columnsToRemove,
1165
+ tablesToRemove,
1166
+ tablesToTruncate,
1167
+ infoToPrint,
1168
+ schemasToRemove,
1169
+ matViewsToRemove,
1170
+ } = await pgSuggestions(
1171
+ {
1172
+ query: async <T>(sql: string, params: any[] = []) => {
1173
+ return (await client.query(sql, params)).rows as T[];
1174
+ },
1175
+ },
1176
+ statements,
1177
+ );
1178
+
1179
+ return {
1180
+ sqlStatements: statementsToExecute,
1181
+ statements,
1182
+ shouldAskForApprove,
1183
+ columnsToRemove,
1184
+ tablesToRemove,
1185
+ tablesToTruncate,
1186
+ infoToPrint,
1187
+ schemasToRemove,
1188
+ matViewsToRemove,
1189
+ };
1190
+ } else {
1191
+ const { sqlStatements, statements } = await applyPgSnapshotsDiff(
1192
+ sn1,
1193
+ sn2,
1194
+ schemasResolver,
1195
+ domainsResolver,
1196
+ enumsResolver,
1197
+ sequencesResolver,
1198
+ policyResolver,
1199
+ indPolicyResolver,
1200
+ roleResolver,
1201
+ tablesResolver,
1202
+ columnsResolver,
1203
+ viewsResolver,
1204
+ validatedPrev,
1205
+ validatedCur,
1206
+ 'push',
1207
+ );
1208
+ return { sqlStatements, statements };
1209
+ }
1210
+ };
1211
+
1212
+ export const applyPgDiffs = async (
1213
+ sn: PostgresSchema,
1214
+ casing: CasingType | undefined,
1215
+ ) => {
1216
+ const dryRun = {
1217
+ version: snapshotVersion,
1218
+ dialect: 'postgresql',
1219
+ id: '0',
1220
+ prevId: '0',
1221
+ tables: {},
1222
+ domains: {},
1223
+ enums: {},
1224
+ views: {},
1225
+ schemas: {},
1226
+ sequences: {},
1227
+ policies: {},
1228
+ roles: {},
1229
+ _meta: {
1230
+ schemas: {},
1231
+ tables: {},
1232
+ columns: {},
1233
+ },
1234
+ } as const;
1235
+
1236
+ const tables = Object.values(sn).filter((it) => is(it, PgTable)) as PgTable[];
1237
+
1238
+ const schemas = Object.values(sn).filter((it) => is(it, PgSchema)) as PgSchema[];
1239
+
1240
+ const domains = Object.values(sn).filter((it) => isPgDomain(it)) as PgDomain<any>[];
1241
+
1242
+ const enums = Object.values(sn).filter((it) => isPgEnum(it)) as PgEnum<any>[];
1243
+
1244
+ const sequences = Object.values(sn).filter((it) => isPgSequence(it)) as PgSequence[];
1245
+
1246
+ const roles = Object.values(sn).filter((it) => is(it, PgRole)) as PgRole[];
1247
+
1248
+ const views = Object.values(sn).filter((it) => isPgView(it)) as PgView[];
1249
+
1250
+ const policies = Object.values(sn).filter((it) => is(it, PgPolicy)) as PgPolicy[];
1251
+
1252
+ const materializedViews = Object.values(sn).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[];
1253
+
1254
+ const serialized1 = generatePgSnapshot(
1255
+ tables,
1256
+ domains,
1257
+ enums,
1258
+ schemas,
1259
+ sequences,
1260
+ roles,
1261
+ policies,
1262
+ views,
1263
+ materializedViews,
1264
+ casing,
1265
+ );
1266
+
1267
+ const { version: v1, dialect: d1, ...rest1 } = serialized1;
1268
+
1269
+ const sch1 = {
1270
+ version: snapshotVersion,
1271
+ dialect: 'postgresql',
1272
+ id: '0',
1273
+ prevId: '0',
1274
+ ...rest1,
1275
+ } as const;
1276
+
1277
+ const sn1 = squashPgScheme(sch1);
1278
+
1279
+ const validatedPrev = pgSchema.parse(dryRun);
1280
+ const validatedCur = pgSchema.parse(sch1);
1281
+
1282
+ const { sqlStatements, statements } = await applyPgSnapshotsDiff(
1283
+ dryRun,
1284
+ sn1,
1285
+ testSchemasResolver(new Set()),
1286
+ testDomainsResolver(new Set()),
1287
+ testEnumsResolver(new Set()),
1288
+ testSequencesResolver(new Set()),
1289
+ testPolicyResolver(new Set()),
1290
+ testIndPolicyResolver(new Set()),
1291
+ testRolesResolver(new Set()),
1292
+ testTablesResolver(new Set()),
1293
+ testColumnsResolver(new Set()),
1294
+ testViewsResolver(new Set()),
1295
+ validatedPrev,
1296
+ validatedCur,
1297
+ );
1298
+ return { sqlStatements, statements };
1299
+ };
1300
+
1301
+ export const diffTestSchemas = async (
1302
+ left: PostgresSchema,
1303
+ right: PostgresSchema,
1304
+ renamesArr: string[],
1305
+ cli: boolean = false,
1306
+ casing?: CasingType | undefined,
1307
+ ) => {
1308
+ const leftTables = Object.values(left).filter((it) => is(it, PgTable)) as PgTable[];
1309
+
1310
+ const rightTables = Object.values(right).filter((it) => is(it, PgTable)) as PgTable[];
1311
+
1312
+ const leftSchemas = Object.values(left).filter((it) => is(it, PgSchema)) as PgSchema[];
1313
+
1314
+ const rightSchemas = Object.values(right).filter((it) => is(it, PgSchema)) as PgSchema[];
1315
+
1316
+ const leftEnums = Object.values(left).filter((it) => isPgEnum(it)) as PgEnum<any>[];
1317
+
1318
+ const rightEnums = Object.values(right).filter((it) => isPgEnum(it)) as PgEnum<any>[];
1319
+
1320
+ const leftSequences = Object.values(left).filter((it) => isPgSequence(it)) as PgSequence[];
1321
+
1322
+ const rightSequences = Object.values(right).filter((it) => isPgSequence(it)) as PgSequence[];
1323
+
1324
+ const leftDomains = Object.values(left).filter((it) => isPgDomain(it)) as PgDomain<any>[];
1325
+
1326
+ const rightDomains = Object.values(right).filter((it) => isPgDomain(it)) as PgDomain<any>[];
1327
+
1328
+ const leftRoles = Object.values(left).filter((it) => is(it, PgRole)) as PgRole[];
1329
+
1330
+ const rightRoles = Object.values(right).filter((it) => is(it, PgRole)) as PgRole[];
1331
+
1332
+ const leftPolicies = Object.values(left).filter((it) => is(it, PgPolicy)) as PgPolicy[];
1333
+
1334
+ const rightPolicies = Object.values(right).filter((it) => is(it, PgPolicy)) as PgPolicy[];
1335
+
1336
+ const leftViews = Object.values(left).filter((it) => isPgView(it)) as PgView[];
1337
+
1338
+ const rightViews = Object.values(right).filter((it) => isPgView(it)) as PgView[];
1339
+
1340
+ const leftMaterializedViews = Object.values(left).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[];
1341
+
1342
+ const rightMaterializedViews = Object.values(right).filter((it) => isPgMaterializedView(it)) as PgMaterializedView[];
1343
+
1344
+ const serialized1 = generatePgSnapshot(
1345
+ leftTables,
1346
+ leftDomains,
1347
+ leftEnums,
1348
+ leftSchemas,
1349
+ leftSequences,
1350
+ leftRoles,
1351
+ leftPolicies,
1352
+ leftViews,
1353
+ leftMaterializedViews,
1354
+ casing,
1355
+ );
1356
+ const serialized2 = generatePgSnapshot(
1357
+ rightTables,
1358
+ rightDomains,
1359
+ rightEnums,
1360
+ rightSchemas,
1361
+ rightSequences,
1362
+ rightRoles,
1363
+ rightPolicies,
1364
+ rightViews,
1365
+ rightMaterializedViews,
1366
+ casing,
1367
+ );
1368
+
1369
+ const { version: v1, dialect: d1, ...rest1 } = serialized1;
1370
+ const { version: v2, dialect: d2, ...rest2 } = serialized2;
1371
+
1372
+ const sch1 = {
1373
+ version: snapshotVersion,
1374
+ dialect: 'postgresql',
1375
+ id: '0',
1376
+ prevId: '0',
1377
+ ...rest1,
1378
+ } as const;
1379
+
1380
+ const sch2 = {
1381
+ version: snapshotVersion,
1382
+ dialect: 'postgresql',
1383
+ id: '0',
1384
+ prevId: '0',
1385
+ ...rest2,
1386
+ } as const;
1387
+
1388
+ const sn1 = squashPgScheme(sch1);
1389
+ const sn2 = squashPgScheme(sch2);
1390
+
1391
+ const validatedPrev = pgSchema.parse(sch1);
1392
+ const validatedCur = pgSchema.parse(sch2);
1393
+
1394
+ const renames = new Set(renamesArr);
1395
+
1396
+ if (!cli) {
1397
+ const { sqlStatements, statements } = await applyPgSnapshotsDiff(
1398
+ sn1,
1399
+ sn2,
1400
+ testSchemasResolver(renames),
1401
+ testDomainsResolver(renames),
1402
+ testEnumsResolver(renames),
1403
+ testSequencesResolver(renames),
1404
+ testPolicyResolver(renames),
1405
+ testIndPolicyResolver(renames),
1406
+ testRolesResolver(renames),
1407
+ testTablesResolver(renames),
1408
+ testColumnsResolver(renames),
1409
+ testViewsResolver(renames),
1410
+ validatedPrev,
1411
+ validatedCur,
1412
+ );
1413
+ return { sqlStatements, statements };
1414
+ } else {
1415
+ const { sqlStatements, statements } = await applyPgSnapshotsDiff(
1416
+ sn1,
1417
+ sn2,
1418
+ schemasResolver,
1419
+ domainsResolver,
1420
+ enumsResolver,
1421
+ sequencesResolver,
1422
+ policyResolver,
1423
+ indPolicyResolver,
1424
+ roleResolver,
1425
+ tablesResolver,
1426
+ columnsResolver,
1427
+ viewsResolver,
1428
+ validatedPrev,
1429
+ validatedCur,
1430
+ );
1431
+ return { sqlStatements, statements };
1432
+ }
1433
+ };
1434
+
1435
+ export const diffTestSchemasPushMysql = async (
1436
+ client: Connection,
1437
+ left: MysqlSchema,
1438
+ right: MysqlSchema,
1439
+ renamesArr: string[],
1440
+ schema: string,
1441
+ cli: boolean = false,
1442
+ casing?: CasingType | undefined,
1443
+ ) => {
1444
+ const { sqlStatements } = await applyMySqlDiffs(left, casing);
1445
+ for (const st of sqlStatements) {
1446
+ await client.query(st);
1447
+ }
1448
+ // do introspect into PgSchemaInternal
1449
+ const introspectedSchema = await fromMySqlDatabase(
1450
+ {
1451
+ query: async (sql: string, params?: any[]) => {
1452
+ const res = await client.execute(sql, params);
1453
+ return res[0] as any;
1454
+ },
1455
+ },
1456
+ schema,
1457
+ );
1458
+
1459
+ const leftTables = Object.values(right).filter((it) => is(it, MySqlTable)) as MySqlTable[];
1460
+
1461
+ const leftViews = Object.values(right).filter((it) => is(it, MySqlView)) as MySqlView[];
1462
+
1463
+ const serialized2 = generateMySqlSnapshot(leftTables, leftViews, casing);
1464
+
1465
+ const { version: v1, dialect: d1, ...rest1 } = introspectedSchema;
1466
+ const { version: v2, dialect: d2, ...rest2 } = serialized2;
1467
+
1468
+ const sch1 = {
1469
+ version: '5',
1470
+ dialect: 'mysql',
1471
+ id: '0',
1472
+ prevId: '0',
1473
+ ...rest1,
1474
+ } as const;
1475
+
1476
+ const sch2 = {
1477
+ version: '5',
1478
+ dialect: 'mysql',
1479
+ id: '0',
1480
+ prevId: '0',
1481
+ ...rest2,
1482
+ } as const;
1483
+
1484
+ const sn1 = squashMysqlScheme(sch1);
1485
+ const sn2 = squashMysqlScheme(sch2);
1486
+
1487
+ const validatedPrev = mysqlSchema.parse(sch1);
1488
+ const validatedCur = mysqlSchema.parse(sch2);
1489
+
1490
+ const renames = new Set(renamesArr);
1491
+
1492
+ if (!cli) {
1493
+ const { sqlStatements, statements } = await applyMysqlSnapshotsDiff(
1494
+ sn1,
1495
+ sn2,
1496
+ testTablesResolver(renames),
1497
+ testColumnsResolver(renames),
1498
+ testViewsResolverMySql(renames),
1499
+ validatedPrev,
1500
+ validatedCur,
1501
+ 'push',
1502
+ );
1503
+ return { sqlStatements, statements };
1504
+ } else {
1505
+ const { sqlStatements, statements } = await applyMysqlSnapshotsDiff(
1506
+ sn1,
1507
+ sn2,
1508
+ tablesResolver,
1509
+ columnsResolver,
1510
+ mySqlViewsResolver,
1511
+ validatedPrev,
1512
+ validatedCur,
1513
+ 'push',
1514
+ );
1515
+ return { sqlStatements, statements };
1516
+ }
1517
+ };
1518
+
1519
+ export const applyMySqlDiffs = async (
1520
+ sn: MysqlSchema,
1521
+ casing: CasingType | undefined,
1522
+ ) => {
1523
+ const dryRun = {
1524
+ version: '5',
1525
+ dialect: 'mysql',
1526
+ id: '0',
1527
+ prevId: '0',
1528
+ views: {},
1529
+ tables: {},
1530
+ enums: {},
1531
+ schemas: {},
1532
+ _meta: {
1533
+ schemas: {},
1534
+ tables: {},
1535
+ columns: {},
1536
+ },
1537
+ } as const;
1538
+
1539
+ const tables = Object.values(sn).filter((it) => is(it, MySqlTable)) as MySqlTable[];
1540
+
1541
+ const views = Object.values(sn).filter((it) => is(it, MySqlView)) as MySqlView[];
1542
+
1543
+ const serialized1 = generateMySqlSnapshot(tables, views, casing);
1544
+
1545
+ const { version: v1, dialect: d1, ...rest1 } = serialized1;
1546
+
1547
+ const sch1 = {
1548
+ version: '5',
1549
+ dialect: 'mysql',
1550
+ id: '0',
1551
+ prevId: '0',
1552
+ ...rest1,
1553
+ } as const;
1554
+
1555
+ const sn1 = squashMysqlScheme(sch1);
1556
+
1557
+ const validatedPrev = mysqlSchema.parse(dryRun);
1558
+ const validatedCur = mysqlSchema.parse(sch1);
1559
+
1560
+ const { sqlStatements, statements } = await applyMysqlSnapshotsDiff(
1561
+ dryRun,
1562
+ sn1,
1563
+ testTablesResolver(new Set()),
1564
+ testColumnsResolver(new Set()),
1565
+ testViewsResolverMySql(new Set()),
1566
+ validatedPrev,
1567
+ validatedCur,
1568
+ );
1569
+ return { sqlStatements, statements };
1570
+ };
1571
+
1572
+ export const diffTestSchemasMysql = async (
1573
+ left: MysqlSchema,
1574
+ right: MysqlSchema,
1575
+ renamesArr: string[],
1576
+ cli: boolean = false,
1577
+ casing?: CasingType | undefined,
1578
+ ) => {
1579
+ const leftTables = Object.values(left).filter((it) => is(it, MySqlTable)) as MySqlTable[];
1580
+
1581
+ const leftViews = Object.values(left).filter((it) => is(it, MySqlView)) as MySqlView[];
1582
+
1583
+ const rightTables = Object.values(right).filter((it) => is(it, MySqlTable)) as MySqlTable[];
1584
+
1585
+ const rightViews = Object.values(right).filter((it) => is(it, MySqlView)) as MySqlView[];
1586
+
1587
+ const serialized1 = generateMySqlSnapshot(leftTables, leftViews, casing);
1588
+ const serialized2 = generateMySqlSnapshot(rightTables, rightViews, casing);
1589
+
1590
+ const { version: v1, dialect: d1, ...rest1 } = serialized1;
1591
+ const { version: v2, dialect: d2, ...rest2 } = serialized2;
1592
+
1593
+ const sch1 = {
1594
+ version: '5',
1595
+ dialect: 'mysql',
1596
+ id: '0',
1597
+ prevId: '0',
1598
+ ...rest1,
1599
+ } as const;
1600
+
1601
+ const sch2 = {
1602
+ version: '5',
1603
+ dialect: 'mysql',
1604
+ id: '0',
1605
+ prevId: '0',
1606
+ ...rest2,
1607
+ } as const;
1608
+
1609
+ const sn1 = squashMysqlScheme(sch1);
1610
+ const sn2 = squashMysqlScheme(sch2);
1611
+
1612
+ const validatedPrev = mysqlSchema.parse(sch1);
1613
+ const validatedCur = mysqlSchema.parse(sch2);
1614
+
1615
+ const renames = new Set(renamesArr);
1616
+
1617
+ if (!cli) {
1618
+ const { sqlStatements, statements } = await applyMysqlSnapshotsDiff(
1619
+ sn1,
1620
+ sn2,
1621
+ testTablesResolver(renames),
1622
+ testColumnsResolver(renames),
1623
+ testViewsResolverMySql(renames),
1624
+ validatedPrev,
1625
+ validatedCur,
1626
+ );
1627
+ return { sqlStatements, statements };
1628
+ }
1629
+
1630
+ const { sqlStatements, statements } = await applyMysqlSnapshotsDiff(
1631
+ sn1,
1632
+ sn2,
1633
+ tablesResolver,
1634
+ columnsResolver,
1635
+ mySqlViewsResolver,
1636
+ validatedPrev,
1637
+ validatedCur,
1638
+ );
1639
+ return { sqlStatements, statements };
1640
+ };
1641
+
1642
+ export const diffTestSchemasSingleStore = async (
1643
+ left: SinglestoreSchema,
1644
+ right: SinglestoreSchema,
1645
+ renamesArr: string[],
1646
+ cli: boolean = false,
1647
+ casing?: CasingType | undefined,
1648
+ ) => {
1649
+ const leftTables = Object.values(left).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[];
1650
+
1651
+ /* const leftViews = Object.values(left).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; */
1652
+
1653
+ const rightTables = Object.values(right).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[];
1654
+
1655
+ /* const rightViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; */
1656
+
1657
+ const serialized1 = generateSingleStoreSnapshot(
1658
+ leftTables,
1659
+ /* leftViews, */
1660
+ casing,
1661
+ );
1662
+ const serialized2 = generateSingleStoreSnapshot(
1663
+ rightTables,
1664
+ /* rightViews, */
1665
+ casing,
1666
+ );
1667
+
1668
+ const { version: v1, dialect: d1, ...rest1 } = serialized1;
1669
+ const { version: v2, dialect: d2, ...rest2 } = serialized2;
1670
+
1671
+ const sch1 = {
1672
+ version: '1',
1673
+ dialect: 'singlestore',
1674
+ id: '0',
1675
+ prevId: '0',
1676
+ ...rest1,
1677
+ } as const;
1678
+
1679
+ const sch2 = {
1680
+ version: '1',
1681
+ dialect: 'singlestore',
1682
+ id: '0',
1683
+ prevId: '0',
1684
+ ...rest2,
1685
+ } as const;
1686
+
1687
+ const sn1 = squashSingleStoreScheme(sch1);
1688
+ const sn2 = squashSingleStoreScheme(sch2);
1689
+
1690
+ const validatedPrev = singlestoreSchema.parse(sch1);
1691
+ const validatedCur = singlestoreSchema.parse(sch2);
1692
+
1693
+ const renames = new Set(renamesArr);
1694
+
1695
+ if (!cli) {
1696
+ const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff(
1697
+ sn1,
1698
+ sn2,
1699
+ testTablesResolver(renames),
1700
+ testColumnsResolver(renames),
1701
+ /* testViewsResolverSingleStore(renames), */
1702
+ validatedPrev,
1703
+ validatedCur,
1704
+ );
1705
+ return { sqlStatements, statements };
1706
+ }
1707
+
1708
+ const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff(
1709
+ sn1,
1710
+ sn2,
1711
+ tablesResolver,
1712
+ columnsResolver,
1713
+ /* singleStoreViewsResolver, */
1714
+ validatedPrev,
1715
+ validatedCur,
1716
+ );
1717
+ return { sqlStatements, statements };
1718
+ };
1719
+
1720
+ export const diffTestSchemasPushSingleStore = async (
1721
+ client: Connection,
1722
+ left: SinglestoreSchema,
1723
+ right: SinglestoreSchema,
1724
+ renamesArr: string[],
1725
+ schema: string,
1726
+ cli: boolean = false,
1727
+ casing?: CasingType | undefined,
1728
+ sqlStatementsToRun: {
1729
+ before?: string[];
1730
+ after?: string[];
1731
+ runApply?: boolean;
1732
+ } = {
1733
+ before: [],
1734
+ after: [],
1735
+ runApply: true,
1736
+ },
1737
+ ) => {
1738
+ const shouldRunApply = sqlStatementsToRun.runApply === undefined
1739
+ ? true
1740
+ : sqlStatementsToRun.runApply;
1741
+
1742
+ for (const st of sqlStatementsToRun.before ?? []) {
1743
+ await client.query(st);
1744
+ }
1745
+
1746
+ if (shouldRunApply) {
1747
+ const res = await applySingleStoreDiffs(left, casing);
1748
+ for (const st of res.sqlStatements) {
1749
+ await client.query(st);
1750
+ }
1751
+ }
1752
+
1753
+ for (const st of sqlStatementsToRun.after ?? []) {
1754
+ await client.query(st);
1755
+ }
1756
+
1757
+ // do introspect into PgSchemaInternal
1758
+ const introspectedSchema = await fromSingleStoreDatabase(
1759
+ {
1760
+ query: async (sql: string, params?: any[]) => {
1761
+ const res = await client.execute(sql, params);
1762
+ return res[0] as any;
1763
+ },
1764
+ },
1765
+ schema,
1766
+ );
1767
+
1768
+ const leftTables = Object.values(right).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[];
1769
+
1770
+ /* const leftViews = Object.values(right).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; */
1771
+
1772
+ const serialized2 = generateSingleStoreSnapshot(
1773
+ leftTables,
1774
+ /* leftViews, */
1775
+ casing,
1776
+ );
1777
+
1778
+ const { version: v1, dialect: d1, ...rest1 } = introspectedSchema;
1779
+ const { version: v2, dialect: d2, ...rest2 } = serialized2;
1780
+
1781
+ const sch1 = {
1782
+ version: '1',
1783
+ dialect: 'singlestore',
1784
+ id: '0',
1785
+ prevId: '0',
1786
+ ...rest1,
1787
+ } as const;
1788
+
1789
+ const sch2 = {
1790
+ version: '1',
1791
+ dialect: 'singlestore',
1792
+ id: '0',
1793
+ prevId: '0',
1794
+ ...rest2,
1795
+ } as const;
1796
+
1797
+ const sn1 = squashSingleStoreScheme(sch1);
1798
+ const sn2 = squashSingleStoreScheme(sch2);
1799
+
1800
+ const validatedPrev = singlestoreSchema.parse(sch1);
1801
+ const validatedCur = singlestoreSchema.parse(sch2);
1802
+
1803
+ const renames = new Set(renamesArr);
1804
+
1805
+ if (!cli) {
1806
+ const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff(
1807
+ sn1,
1808
+ sn2,
1809
+ testTablesResolver(renames),
1810
+ testColumnsResolver(renames),
1811
+ /* testViewsResolverSingleStore(renames), */
1812
+ validatedPrev,
1813
+ validatedCur,
1814
+ 'push',
1815
+ );
1816
+
1817
+ const {
1818
+ statementsToExecute,
1819
+ columnsToRemove,
1820
+ infoToPrint,
1821
+ shouldAskForApprove,
1822
+ tablesToRemove,
1823
+ tablesToTruncate,
1824
+ } = await singleStoreLogSuggestionsAndReturn(
1825
+ {
1826
+ query: async <T>(sql: string, params?: any[]) => {
1827
+ const res = await client.execute(sql, params);
1828
+ return res[0] as T[];
1829
+ },
1830
+ },
1831
+ statements,
1832
+ sn1,
1833
+ sn2,
1834
+ );
1835
+
1836
+ return {
1837
+ sqlStatements: statementsToExecute,
1838
+ statements,
1839
+ columnsToRemove,
1840
+ infoToPrint,
1841
+ shouldAskForApprove,
1842
+ tablesToRemove,
1843
+ tablesToTruncate,
1844
+ };
1845
+ } else {
1846
+ const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff(
1847
+ sn1,
1848
+ sn2,
1849
+ tablesResolver,
1850
+ columnsResolver,
1851
+ /* singleStoreViewsResolver, */
1852
+ validatedPrev,
1853
+ validatedCur,
1854
+ 'push',
1855
+ );
1856
+ return { sqlStatements, statements };
1857
+ }
1858
+ };
1859
+
1860
+ export const applySingleStoreDiffs = async (
1861
+ sn: SinglestoreSchema,
1862
+ casing: CasingType | undefined,
1863
+ ) => {
1864
+ const dryRun = {
1865
+ version: '1',
1866
+ dialect: 'singlestore',
1867
+ id: '0',
1868
+ prevId: '0',
1869
+ tables: {},
1870
+ views: {},
1871
+ enums: {},
1872
+ schemas: {},
1873
+ _meta: {
1874
+ schemas: {},
1875
+ tables: {},
1876
+ columns: {},
1877
+ },
1878
+ } as const;
1879
+
1880
+ const tables = Object.values(sn).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[];
1881
+
1882
+ /* const views = Object.values(sn).filter((it) => is(it, SingleStoreView)) as SingleStoreView[]; */
1883
+
1884
+ const serialized1 = generateSingleStoreSnapshot(tables, /* views, */ casing);
1885
+
1886
+ const { version: v1, dialect: d1, ...rest1 } = serialized1;
1887
+
1888
+ const sch1 = {
1889
+ version: '1',
1890
+ dialect: 'singlestore',
1891
+ id: '0',
1892
+ prevId: '0',
1893
+ ...rest1,
1894
+ } as const;
1895
+
1896
+ const sn1 = squashSingleStoreScheme(sch1);
1897
+
1898
+ const validatedPrev = singlestoreSchema.parse(dryRun);
1899
+ const validatedCur = singlestoreSchema.parse(sch1);
1900
+
1901
+ const { sqlStatements, statements } = await applySingleStoreSnapshotsDiff(
1902
+ dryRun,
1903
+ sn1,
1904
+ testTablesResolver(new Set()),
1905
+ testColumnsResolver(new Set()),
1906
+ /* testViewsResolverSingleStore(new Set()), */
1907
+ validatedPrev,
1908
+ validatedCur,
1909
+ );
1910
+ return { sqlStatements, statements };
1911
+ };
1912
+
1913
+ export const diffTestSchemasPushSqlite = async (
1914
+ client: Database,
1915
+ left: SqliteSchema,
1916
+ right: SqliteSchema,
1917
+ renamesArr: string[],
1918
+ cli: boolean = false,
1919
+ seedStatements: string[] = [],
1920
+ casing?: CasingType | undefined,
1921
+ ) => {
1922
+ const { sqlStatements } = await applySqliteDiffs(left, 'push');
1923
+
1924
+ for (const st of sqlStatements) {
1925
+ client.exec(st);
1926
+ }
1927
+
1928
+ for (const st of seedStatements) {
1929
+ client.exec(st);
1930
+ }
1931
+
1932
+ // do introspect into PgSchemaInternal
1933
+ const introspectedSchema = await fromSqliteDatabase(
1934
+ {
1935
+ query: async <T>(sql: string, params: any[] = []) => {
1936
+ return client.prepare(sql).bind(params).all() as T[];
1937
+ },
1938
+ run: async (query: string) => {
1939
+ client.prepare(query).run();
1940
+ },
1941
+ },
1942
+ undefined,
1943
+ );
1944
+
1945
+ const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[];
1946
+
1947
+ const rightViews = Object.values(right).filter((it) => is(it, SQLiteView)) as SQLiteView[];
1948
+
1949
+ const serialized2 = generateSqliteSnapshot(rightTables, rightViews, casing);
1950
+
1951
+ const { version: v1, dialect: d1, ...rest1 } = introspectedSchema;
1952
+ const { version: v2, dialect: d2, ...rest2 } = serialized2;
1953
+
1954
+ const sch1 = {
1955
+ version: '6',
1956
+ dialect: 'sqlite',
1957
+ id: '0',
1958
+ prevId: '0',
1959
+ ...rest1,
1960
+ } as const;
1961
+
1962
+ const sch2 = {
1963
+ version: '6',
1964
+ dialect: 'sqlite',
1965
+ id: '0',
1966
+ prevId: '0',
1967
+ ...rest2,
1968
+ } as const;
1969
+
1970
+ const sn1 = squashSqliteScheme(sch1, 'push');
1971
+ const sn2 = squashSqliteScheme(sch2, 'push');
1972
+
1973
+ const renames = new Set(renamesArr);
1974
+
1975
+ if (!cli) {
1976
+ const { sqlStatements, statements, _meta } = await applySqliteSnapshotsDiff(
1977
+ sn1,
1978
+ sn2,
1979
+ testTablesResolver(renames),
1980
+ testColumnsResolver(renames),
1981
+ testViewsResolverSqlite(renames),
1982
+ sch1,
1983
+ sch2,
1984
+ 'push',
1985
+ );
1986
+
1987
+ const {
1988
+ statementsToExecute,
1989
+ columnsToRemove,
1990
+ infoToPrint,
1991
+ schemasToRemove,
1992
+ shouldAskForApprove,
1993
+ tablesToRemove,
1994
+ tablesToTruncate,
1995
+ } = await logSuggestionsAndReturn(
1996
+ {
1997
+ query: async <T>(sql: string, params: any[] = []) => {
1998
+ return client.prepare(sql).bind(params).all() as T[];
1999
+ },
2000
+ run: async (query: string) => {
2001
+ client.prepare(query).run();
2002
+ },
2003
+ },
2004
+ statements,
2005
+ sn1,
2006
+ sn2,
2007
+ _meta!,
2008
+ );
2009
+
2010
+ return {
2011
+ sqlStatements: statementsToExecute,
2012
+ statements,
2013
+ columnsToRemove,
2014
+ infoToPrint,
2015
+ schemasToRemove,
2016
+ shouldAskForApprove,
2017
+ tablesToRemove,
2018
+ tablesToTruncate,
2019
+ };
2020
+ } else {
2021
+ const { sqlStatements, statements } = await applySqliteSnapshotsDiff(
2022
+ sn1,
2023
+ sn2,
2024
+ tablesResolver,
2025
+ columnsResolver,
2026
+ sqliteViewsResolver,
2027
+ sch1,
2028
+ sch2,
2029
+ 'push',
2030
+ );
2031
+ return { sqlStatements, statements };
2032
+ }
2033
+ };
2034
+
2035
+ export async function diffTestSchemasPushLibSQL(
2036
+ client: Client,
2037
+ left: SqliteSchema,
2038
+ right: SqliteSchema,
2039
+ renamesArr: string[],
2040
+ cli: boolean = false,
2041
+ seedStatements: string[] = [],
2042
+ casing?: CasingType | undefined,
2043
+ ) {
2044
+ const { sqlStatements } = await applyLibSQLDiffs(left, 'push');
2045
+
2046
+ for (const st of sqlStatements) {
2047
+ await client.execute(st);
2048
+ }
2049
+
2050
+ for (const st of seedStatements) {
2051
+ await client.execute(st);
2052
+ }
2053
+
2054
+ const introspectedSchema = await fromSqliteDatabase(
2055
+ {
2056
+ query: async <T>(sql: string, params?: any[]) => {
2057
+ const res = await client.execute({ sql, args: params || [] });
2058
+ return res.rows as T[];
2059
+ },
2060
+ run: async (query: string) => {
2061
+ await client.execute(query);
2062
+ },
2063
+ },
2064
+ undefined,
2065
+ );
2066
+
2067
+ const leftTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[];
2068
+
2069
+ const leftViews = Object.values(right).filter((it) => is(it, SQLiteView)) as SQLiteView[];
2070
+
2071
+ const serialized2 = generateSqliteSnapshot(leftTables, leftViews, casing);
2072
+
2073
+ const { version: v1, dialect: d1, ...rest1 } = introspectedSchema;
2074
+ const { version: v2, dialect: d2, ...rest2 } = serialized2;
2075
+
2076
+ const sch1 = {
2077
+ version: '6',
2078
+ dialect: 'sqlite',
2079
+ id: '0',
2080
+ prevId: '0',
2081
+ ...rest1,
2082
+ } as const;
2083
+
2084
+ const sch2 = {
2085
+ version: '6',
2086
+ dialect: 'sqlite',
2087
+ id: '0',
2088
+ prevId: '0',
2089
+ ...rest2,
2090
+ } as const;
2091
+
2092
+ const sn1 = squashSqliteScheme(sch1, 'push');
2093
+ const sn2 = squashSqliteScheme(sch2, 'push');
2094
+
2095
+ const renames = new Set(renamesArr);
2096
+
2097
+ if (!cli) {
2098
+ const { sqlStatements, statements, _meta } = await applyLibSQLSnapshotsDiff(
2099
+ sn1,
2100
+ sn2,
2101
+ testTablesResolver(renames),
2102
+ testColumnsResolver(renames),
2103
+ testViewsResolverSqlite(renames),
2104
+ sch1,
2105
+ sch2,
2106
+ 'push',
2107
+ );
2108
+
2109
+ const {
2110
+ statementsToExecute,
2111
+ columnsToRemove,
2112
+ infoToPrint,
2113
+ shouldAskForApprove,
2114
+ tablesToRemove,
2115
+ tablesToTruncate,
2116
+ } = await libSqlLogSuggestionsAndReturn(
2117
+ {
2118
+ query: async <T>(sql: string, params?: any[]) => {
2119
+ const res = await client.execute({ sql, args: params || [] });
2120
+ return res.rows as T[];
2121
+ },
2122
+ run: async (query: string) => {
2123
+ await client.execute(query);
2124
+ },
2125
+ },
2126
+ statements,
2127
+ sn1,
2128
+ sn2,
2129
+ _meta!,
2130
+ );
2131
+
2132
+ return {
2133
+ sqlStatements: statementsToExecute,
2134
+ statements,
2135
+ columnsToRemove,
2136
+ infoToPrint,
2137
+ shouldAskForApprove,
2138
+ tablesToRemove,
2139
+ tablesToTruncate,
2140
+ };
2141
+ } else {
2142
+ const { sqlStatements, statements } = await applyLibSQLSnapshotsDiff(
2143
+ sn1,
2144
+ sn2,
2145
+ tablesResolver,
2146
+ columnsResolver,
2147
+ sqliteViewsResolver,
2148
+ sch1,
2149
+ sch2,
2150
+ 'push',
2151
+ );
2152
+ return { sqlStatements, statements };
2153
+ }
2154
+ }
2155
+
2156
+ export const applySqliteDiffs = async (
2157
+ sn: SqliteSchema,
2158
+ action?: 'push' | undefined,
2159
+ casing?: CasingType | undefined,
2160
+ ) => {
2161
+ const dryRun = {
2162
+ version: '6',
2163
+ dialect: 'sqlite',
2164
+ id: '0',
2165
+ prevId: '0',
2166
+ tables: {},
2167
+ enums: {},
2168
+ views: {},
2169
+ schemas: {},
2170
+ _meta: {
2171
+ schemas: {},
2172
+ tables: {},
2173
+ columns: {},
2174
+ },
2175
+ } as const;
2176
+
2177
+ const tables = Object.values(sn).filter((it) => is(it, SQLiteTable)) as SQLiteTable[];
2178
+
2179
+ const views = Object.values(sn).filter((it) => is(it, SQLiteView)) as SQLiteView[];
2180
+
2181
+ const serialized1 = generateSqliteSnapshot(tables, views, casing);
2182
+
2183
+ const { version: v1, dialect: d1, ...rest1 } = serialized1;
2184
+
2185
+ const sch1 = {
2186
+ version: '6',
2187
+ dialect: 'sqlite',
2188
+ id: '0',
2189
+ prevId: '0',
2190
+ ...rest1,
2191
+ } as const;
2192
+
2193
+ const sn1 = squashSqliteScheme(sch1, action);
2194
+
2195
+ const { sqlStatements, statements } = await applySqliteSnapshotsDiff(
2196
+ dryRun,
2197
+ sn1,
2198
+ testTablesResolver(new Set()),
2199
+ testColumnsResolver(new Set()),
2200
+ testViewsResolverSqlite(new Set()),
2201
+ dryRun,
2202
+ sch1,
2203
+ action,
2204
+ );
2205
+
2206
+ return { sqlStatements, statements };
2207
+ };
2208
+
2209
+ export const applyLibSQLDiffs = async (
2210
+ sn: SqliteSchema,
2211
+ action?: 'push' | undefined,
2212
+ casing?: CasingType | undefined,
2213
+ ) => {
2214
+ const dryRun = {
2215
+ version: '6',
2216
+ dialect: 'sqlite',
2217
+ id: '0',
2218
+ prevId: '0',
2219
+ tables: {},
2220
+ views: {},
2221
+ enums: {},
2222
+ schemas: {},
2223
+ _meta: {
2224
+ schemas: {},
2225
+ tables: {},
2226
+ columns: {},
2227
+ },
2228
+ } as const;
2229
+
2230
+ const tables = Object.values(sn).filter((it) => is(it, SQLiteTable)) as SQLiteTable[];
2231
+
2232
+ const views = Object.values(sn).filter((it) => is(it, SQLiteView)) as SQLiteView[];
2233
+
2234
+ const serialized1 = generateSqliteSnapshot(tables, views, casing);
2235
+
2236
+ const { version: v1, dialect: d1, ...rest1 } = serialized1;
2237
+
2238
+ const sch1 = {
2239
+ version: '6',
2240
+ dialect: 'sqlite',
2241
+ id: '0',
2242
+ prevId: '0',
2243
+ ...rest1,
2244
+ } as const;
2245
+
2246
+ const sn1 = squashSqliteScheme(sch1, action);
2247
+
2248
+ const { sqlStatements, statements } = await applyLibSQLSnapshotsDiff(
2249
+ dryRun,
2250
+ sn1,
2251
+ testTablesResolver(new Set()),
2252
+ testColumnsResolver(new Set()),
2253
+ testViewsResolverSqlite(new Set()),
2254
+ dryRun,
2255
+ sch1,
2256
+ action,
2257
+ );
2258
+
2259
+ return { sqlStatements, statements };
2260
+ };
2261
+
2262
+ export const diffTestSchemasSqlite = async (
2263
+ left: SqliteSchema,
2264
+ right: SqliteSchema,
2265
+ renamesArr: string[],
2266
+ cli: boolean = false,
2267
+ casing?: CasingType | undefined,
2268
+ ) => {
2269
+ const leftTables = Object.values(left).filter((it) => is(it, SQLiteTable)) as SQLiteTable[];
2270
+
2271
+ const leftViews = Object.values(left).filter((it) => is(it, SQLiteView)) as SQLiteView[];
2272
+
2273
+ const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[];
2274
+
2275
+ const rightViews = Object.values(right).filter((it) => is(it, SQLiteView)) as SQLiteView[];
2276
+
2277
+ const serialized1 = generateSqliteSnapshot(leftTables, leftViews, casing);
2278
+ const serialized2 = generateSqliteSnapshot(rightTables, rightViews, casing);
2279
+
2280
+ const { version: v1, dialect: d1, ...rest1 } = serialized1;
2281
+ const { version: v2, dialect: d2, ...rest2 } = serialized2;
2282
+
2283
+ const sch1 = {
2284
+ version: '6',
2285
+ dialect: 'sqlite',
2286
+ id: '0',
2287
+ prevId: '0',
2288
+ ...rest1,
2289
+ } as const;
2290
+
2291
+ const sch2 = {
2292
+ version: '6',
2293
+ dialect: 'sqlite',
2294
+ id: '0',
2295
+ prevId: '0',
2296
+ ...rest2,
2297
+ } as const;
2298
+
2299
+ const sn1 = squashSqliteScheme(sch1);
2300
+ const sn2 = squashSqliteScheme(sch2);
2301
+
2302
+ const renames = new Set(renamesArr);
2303
+
2304
+ if (!cli) {
2305
+ const { sqlStatements, statements } = await applySqliteSnapshotsDiff(
2306
+ sn1,
2307
+ sn2,
2308
+ testTablesResolver(renames),
2309
+ testColumnsResolver(renames),
2310
+ testViewsResolverSqlite(renames),
2311
+ sch1,
2312
+ sch2,
2313
+ );
2314
+ return { sqlStatements, statements };
2315
+ }
2316
+
2317
+ const { sqlStatements, statements } = await applySqliteSnapshotsDiff(
2318
+ sn1,
2319
+ sn2,
2320
+ tablesResolver,
2321
+ columnsResolver,
2322
+ sqliteViewsResolver,
2323
+ sch1,
2324
+ sch2,
2325
+ );
2326
+ return { sqlStatements, statements };
2327
+ };
2328
+
2329
+ export const diffTestSchemasLibSQL = async (
2330
+ left: SqliteSchema,
2331
+ right: SqliteSchema,
2332
+ renamesArr: string[],
2333
+ cli: boolean = false,
2334
+ casing?: CasingType | undefined,
2335
+ ) => {
2336
+ const leftTables = Object.values(left).filter((it) => is(it, SQLiteTable)) as SQLiteTable[];
2337
+
2338
+ const leftViews = Object.values(left).filter((it) => is(it, SQLiteView)) as SQLiteView[];
2339
+
2340
+ const rightTables = Object.values(right).filter((it) => is(it, SQLiteTable)) as SQLiteTable[];
2341
+
2342
+ const rightViews = Object.values(right).filter((it) => is(it, SQLiteView)) as SQLiteView[];
2343
+
2344
+ const serialized1 = generateSqliteSnapshot(leftTables, leftViews, casing);
2345
+ const serialized2 = generateSqliteSnapshot(rightTables, rightViews, casing);
2346
+
2347
+ const { version: v1, dialect: d1, ...rest1 } = serialized1;
2348
+ const { version: v2, dialect: d2, ...rest2 } = serialized2;
2349
+
2350
+ const sch1 = {
2351
+ version: '6',
2352
+ dialect: 'sqlite',
2353
+ id: '0',
2354
+ prevId: '0',
2355
+ ...rest1,
2356
+ } as const;
2357
+
2358
+ const sch2 = {
2359
+ version: '6',
2360
+ dialect: 'sqlite',
2361
+ id: '0',
2362
+ prevId: '0',
2363
+ ...rest2,
2364
+ } as const;
2365
+
2366
+ const sn1 = squashSqliteScheme(sch1);
2367
+ const sn2 = squashSqliteScheme(sch2);
2368
+
2369
+ const renames = new Set(renamesArr);
2370
+
2371
+ if (!cli) {
2372
+ const { sqlStatements, statements } = await applyLibSQLSnapshotsDiff(
2373
+ sn1,
2374
+ sn2,
2375
+ testTablesResolver(renames),
2376
+ testColumnsResolver(renames),
2377
+ testViewsResolverSqlite(renames),
2378
+ sch1,
2379
+ sch2,
2380
+ );
2381
+ return { sqlStatements, statements };
2382
+ }
2383
+
2384
+ const { sqlStatements, statements } = await applyLibSQLSnapshotsDiff(
2385
+ sn1,
2386
+ sn2,
2387
+ tablesResolver,
2388
+ columnsResolver,
2389
+ sqliteViewsResolver,
2390
+ sch1,
2391
+ sch2,
2392
+ );
2393
+ return { sqlStatements, statements };
2394
+ };
2395
+
2396
+ // --- Introspect to file helpers ---
2397
+
2398
+ export const introspectPgToFile = async (
2399
+ client: PGlite,
2400
+ initSchema: PostgresSchema,
2401
+ testName: string,
2402
+ schemas: string[] = ['public'],
2403
+ entities?: Entities,
2404
+ casing?: CasingType | undefined,
2405
+ ) => {
2406
+ // put in db
2407
+ const { sqlStatements } = await applyPgDiffs(initSchema, casing);
2408
+ for (const st of sqlStatements) {
2409
+ await client.query(st);
2410
+ }
2411
+
2412
+ // introspect to schema
2413
+ const introspectedSchema = await fromDatabase(
2414
+ {
2415
+ query: async (query: string, values?: any[] | undefined) => {
2416
+ const res = await client.query(query, values);
2417
+ return res.rows as any[];
2418
+ },
2419
+ },
2420
+ undefined,
2421
+ schemas,
2422
+ entities,
2423
+ );
2424
+
2425
+ const { version: initV, dialect: initD, ...initRest } = introspectedSchema;
2426
+
2427
+ const initSch = {
2428
+ version: snapshotVersion,
2429
+ dialect: 'postgresql',
2430
+ id: '0',
2431
+ prevId: '0',
2432
+ ...initRest,
2433
+ } as const;
2434
+
2435
+ const initSn = squashPgScheme(initSch);
2436
+ const validatedCur = pgSchema.parse(initSch);
2437
+
2438
+ // write to ts file
2439
+ const file = schemaToTypeScript(introspectedSchema, 'camel');
2440
+
2441
+ fs.writeFileSync(`tests/introspect/postgres/${testName}.ts`, file.file);
2442
+
2443
+ // generate snapshot from ts file
2444
+ const response = await prepareFromPgImports([
2445
+ `tests/introspect/postgres/${testName}.ts`,
2446
+ ]);
2447
+
2448
+ const afterFileImports = generatePgSnapshot(
2449
+ response.tables,
2450
+ response.domains,
2451
+ response.enums,
2452
+ response.schemas,
2453
+ response.sequences,
2454
+ response.roles,
2455
+ response.policies,
2456
+ response.views,
2457
+ response.matViews,
2458
+ casing,
2459
+ );
2460
+
2461
+ const { version: v2, dialect: d2, ...rest2 } = afterFileImports;
2462
+
2463
+ const sch2 = {
2464
+ version: snapshotVersion,
2465
+ dialect: 'postgresql',
2466
+ id: '0',
2467
+ prevId: '0',
2468
+ ...rest2,
2469
+ } as const;
2470
+
2471
+ const sn2AfterIm = squashPgScheme(sch2);
2472
+ const validatedCurAfterImport = pgSchema.parse(sch2);
2473
+
2474
+ const {
2475
+ sqlStatements: afterFileSqlStatements,
2476
+ statements: afterFileStatements,
2477
+ } = await applyPgSnapshotsDiff(
2478
+ initSn,
2479
+ sn2AfterIm,
2480
+ testSchemasResolver(new Set()),
2481
+ testDomainsResolver(new Set()),
2482
+ testEnumsResolver(new Set()),
2483
+ testSequencesResolver(new Set()),
2484
+ testPolicyResolver(new Set()),
2485
+ testIndPolicyResolver(new Set()),
2486
+ testRolesResolver(new Set()),
2487
+ testTablesResolver(new Set()),
2488
+ testColumnsResolver(new Set()),
2489
+ testViewsResolver(new Set()),
2490
+ validatedCur,
2491
+ validatedCurAfterImport,
2492
+ );
2493
+
2494
+ fs.rmSync(`tests/introspect/postgres/${testName}.ts`);
2495
+
2496
+ return {
2497
+ sqlStatements: afterFileSqlStatements,
2498
+ statements: afterFileStatements,
2499
+ };
2500
+ };
2501
+
2502
+ export const introspectMySQLToFile = async (
2503
+ client: Connection,
2504
+ initSchema: MysqlSchema,
2505
+ testName: string,
2506
+ schema: string,
2507
+ casing?: CasingType | undefined,
2508
+ ) => {
2509
+ // put in db
2510
+ const { sqlStatements } = await applyMySqlDiffs(initSchema, casing);
2511
+ for (const st of sqlStatements) {
2512
+ await client.query(st);
2513
+ }
2514
+
2515
+ // introspect to schema
2516
+ const introspectedSchema = await fromMySqlDatabase(
2517
+ {
2518
+ query: async (sql: string, params?: any[] | undefined) => {
2519
+ const res = await client.execute(sql, params);
2520
+ return res[0] as any;
2521
+ },
2522
+ },
2523
+ schema,
2524
+ );
2525
+
2526
+ const { version: initV, dialect: initD, ...initRest } = introspectedSchema;
2527
+
2528
+ const initSch = {
2529
+ version: '5',
2530
+ dialect: 'mysql',
2531
+ id: '0',
2532
+ prevId: '0',
2533
+ ...initRest,
2534
+ } as const;
2535
+
2536
+ const initSn = squashMysqlScheme(initSch);
2537
+ const validatedCur = mysqlSchema.parse(initSch);
2538
+
2539
+ const file = schemaToTypeScriptMySQL(introspectedSchema, 'camel');
2540
+
2541
+ fs.writeFileSync(`tests/introspect/mysql/${testName}.ts`, file.file);
2542
+
2543
+ const response = await prepareFromMySqlImports([
2544
+ `tests/introspect/mysql/${testName}.ts`,
2545
+ ]);
2546
+
2547
+ const afterFileImports = generateMySqlSnapshot(
2548
+ response.tables,
2549
+ response.views,
2550
+ casing,
2551
+ );
2552
+
2553
+ const { version: v2, dialect: d2, ...rest2 } = afterFileImports;
2554
+
2555
+ const sch2 = {
2556
+ version: '5',
2557
+ dialect: 'mysql',
2558
+ id: '0',
2559
+ prevId: '0',
2560
+ ...rest2,
2561
+ } as const;
2562
+
2563
+ const sn2AfterIm = squashMysqlScheme(sch2);
2564
+ const validatedCurAfterImport = mysqlSchema.parse(sch2);
2565
+
2566
+ const {
2567
+ sqlStatements: afterFileSqlStatements,
2568
+ statements: afterFileStatements,
2569
+ } = await applyMysqlSnapshotsDiff(
2570
+ sn2AfterIm,
2571
+ initSn,
2572
+ testTablesResolver(new Set()),
2573
+ testColumnsResolver(new Set()),
2574
+ testViewsResolverMySql(new Set()),
2575
+ validatedCurAfterImport,
2576
+ validatedCur,
2577
+ );
2578
+
2579
+ fs.rmSync(`tests/introspect/mysql/${testName}.ts`);
2580
+
2581
+ return {
2582
+ sqlStatements: afterFileSqlStatements,
2583
+ statements: afterFileStatements,
2584
+ };
2585
+ };
2586
+
2587
+ export const introspectSingleStoreToFile = async (
2588
+ client: Connection,
2589
+ initSchema: SinglestoreSchema,
2590
+ testName: string,
2591
+ schema: string,
2592
+ casing?: CasingType | undefined,
2593
+ ) => {
2594
+ // put in db
2595
+ const { sqlStatements } = await applySingleStoreDiffs(initSchema, casing);
2596
+ for (const st of sqlStatements) {
2597
+ await client.query(st);
2598
+ }
2599
+
2600
+ // introspect to schema
2601
+ const introspectedSchema = await fromSingleStoreDatabase(
2602
+ {
2603
+ query: async (sql: string, params?: any[] | undefined) => {
2604
+ const res = await client.execute(sql, params);
2605
+ return res[0] as any;
2606
+ },
2607
+ },
2608
+ schema,
2609
+ );
2610
+
2611
+ const file = schemaToTypeScriptSingleStore(introspectedSchema, 'camel');
2612
+
2613
+ fs.writeFileSync(`tests/introspect/singlestore/${testName}.ts`, file.file);
2614
+
2615
+ const response = await prepareFromSingleStoreImports([
2616
+ `tests/introspect/singlestore/${testName}.ts`,
2617
+ ]);
2618
+
2619
+ const afterFileImports = generateSingleStoreSnapshot(
2620
+ response.tables,
2621
+ /* response.views, */
2622
+ casing,
2623
+ );
2624
+
2625
+ const { version: v2, dialect: d2, ...rest2 } = afterFileImports;
2626
+
2627
+ const sch2 = {
2628
+ version: '1',
2629
+ dialect: 'singlestore',
2630
+ id: '0',
2631
+ prevId: '0',
2632
+ ...rest2,
2633
+ } as const;
2634
+
2635
+ const sn2AfterIm = squashSingleStoreScheme(sch2);
2636
+ const validatedCurAfterImport = singlestoreSchema.parse(sch2);
2637
+
2638
+ const leftTables = Object.values(initSchema).filter((it) => is(it, SingleStoreTable)) as SingleStoreTable[];
2639
+
2640
+ const initSnapshot = generateSingleStoreSnapshot(
2641
+ leftTables,
2642
+ /* response.views, */
2643
+ casing,
2644
+ );
2645
+
2646
+ const { version: initV, dialect: initD, ...initRest } = initSnapshot;
2647
+
2648
+ const initSch = {
2649
+ version: '1',
2650
+ dialect: 'singlestore',
2651
+ id: '0',
2652
+ prevId: '0',
2653
+ ...initRest,
2654
+ } as const;
2655
+
2656
+ const initSn = squashSingleStoreScheme(initSch);
2657
+ const validatedCur = singlestoreSchema.parse(initSch);
2658
+
2659
+ const {
2660
+ sqlStatements: afterFileSqlStatements,
2661
+ statements: afterFileStatements,
2662
+ } = await applySingleStoreSnapshotsDiff(
2663
+ sn2AfterIm,
2664
+ initSn,
2665
+ testTablesResolver(new Set()),
2666
+ testColumnsResolver(new Set()),
2667
+ /* testViewsResolverSingleStore(new Set()), */
2668
+ validatedCurAfterImport,
2669
+ validatedCur,
2670
+ );
2671
+
2672
+ fs.rmSync(`tests/introspect/singlestore/${testName}.ts`);
2673
+
2674
+ return {
2675
+ sqlStatements: afterFileSqlStatements,
2676
+ statements: afterFileStatements,
2677
+ };
2678
+ };
2679
+
2680
+ export const introspectSQLiteToFile = async (
2681
+ client: Database,
2682
+ initSchema: SqliteSchema,
2683
+ testName: string,
2684
+ casing?: CasingType | undefined,
2685
+ ) => {
2686
+ // put in db
2687
+ const { sqlStatements } = await applySqliteDiffs(initSchema);
2688
+ for (const st of sqlStatements) {
2689
+ client.exec(st);
2690
+ }
2691
+
2692
+ // introspect to schema
2693
+ const introspectedSchema = await fromSqliteDatabase(
2694
+ {
2695
+ query: async <T>(sql: string, params: any[] = []) => {
2696
+ return client.prepare(sql).bind(params).all() as T[];
2697
+ },
2698
+ run: async (query: string) => {
2699
+ client.prepare(query).run();
2700
+ },
2701
+ },
2702
+ undefined,
2703
+ );
2704
+
2705
+ const { version: initV, dialect: initD, ...initRest } = introspectedSchema;
2706
+
2707
+ const initSch = {
2708
+ version: '6',
2709
+ dialect: 'sqlite',
2710
+ id: '0',
2711
+ prevId: '0',
2712
+ ...initRest,
2713
+ } as const;
2714
+
2715
+ const initSn = squashSqliteScheme(initSch);
2716
+
2717
+ const validatedCur = sqliteSchema.parse(initSch);
2718
+
2719
+ const file = schemaToTypeScriptSQLite(introspectedSchema, 'camel');
2720
+
2721
+ fs.writeFileSync(`tests/introspect/sqlite/${testName}.ts`, file.file);
2722
+
2723
+ const response = await prepareFromSqliteImports([
2724
+ `tests/introspect/sqlite/${testName}.ts`,
2725
+ ]);
2726
+
2727
+ const afterFileImports = generateSqliteSnapshot(
2728
+ response.tables,
2729
+ response.views,
2730
+ casing,
2731
+ );
2732
+
2733
+ const { version: v2, dialect: d2, ...rest2 } = afterFileImports;
2734
+
2735
+ const sch2 = {
2736
+ version: '6',
2737
+ dialect: 'sqlite',
2738
+ id: '0',
2739
+ prevId: '0',
2740
+ ...rest2,
2741
+ } as const;
2742
+
2743
+ const sn2AfterIm = squashSqliteScheme(sch2);
2744
+ const validatedCurAfterImport = sqliteSchema.parse(sch2);
2745
+
2746
+ const {
2747
+ sqlStatements: afterFileSqlStatements,
2748
+ statements: afterFileStatements,
2749
+ } = await applySqliteSnapshotsDiff(
2750
+ sn2AfterIm,
2751
+ initSn,
2752
+ testTablesResolver(new Set()),
2753
+ testColumnsResolver(new Set()),
2754
+ testViewsResolverSqlite(new Set()),
2755
+ validatedCurAfterImport,
2756
+ validatedCur,
2757
+ );
2758
+
2759
+ fs.rmSync(`tests/introspect/sqlite/${testName}.ts`);
2760
+
2761
+ return {
2762
+ sqlStatements: afterFileSqlStatements,
2763
+ statements: afterFileStatements,
2764
+ };
2765
+ };
2766
+
2767
+ export const introspectLibSQLToFile = async (
2768
+ client: Client,
2769
+ initSchema: SqliteSchema,
2770
+ testName: string,
2771
+ casing?: CasingType | undefined,
2772
+ ) => {
2773
+ // put in db
2774
+ const { sqlStatements } = await applyLibSQLDiffs(initSchema);
2775
+ for (const st of sqlStatements) {
2776
+ client.execute(st);
2777
+ }
2778
+
2779
+ // introspect to schema
2780
+ const introspectedSchema = await fromSqliteDatabase(
2781
+ {
2782
+ query: async <T>(sql: string, params: any[] = []) => {
2783
+ return (await client.execute({ sql, args: params })).rows as T[];
2784
+ },
2785
+ run: async (query: string) => {
2786
+ client.execute(query);
2787
+ },
2788
+ },
2789
+ undefined,
2790
+ );
2791
+
2792
+ const { version: initV, dialect: initD, ...initRest } = introspectedSchema;
2793
+
2794
+ const initSch = {
2795
+ version: '6',
2796
+ dialect: 'sqlite',
2797
+ id: '0',
2798
+ prevId: '0',
2799
+ ...initRest,
2800
+ } as const;
2801
+
2802
+ const initSn = squashSqliteScheme(initSch);
2803
+
2804
+ const validatedCur = sqliteSchema.parse(initSch);
2805
+
2806
+ const file = schemaToTypeScriptSQLite(introspectedSchema, 'camel');
2807
+
2808
+ fs.writeFileSync(`tests/introspect/libsql/${testName}.ts`, file.file);
2809
+
2810
+ const response = await prepareFromSqliteImports([
2811
+ `tests/introspect/libsql/${testName}.ts`,
2812
+ ]);
2813
+
2814
+ const afterFileImports = generateSqliteSnapshot(
2815
+ response.tables,
2816
+ response.views,
2817
+ casing,
2818
+ );
2819
+
2820
+ const { version: v2, dialect: d2, ...rest2 } = afterFileImports;
2821
+
2822
+ const sch2 = {
2823
+ version: '6',
2824
+ dialect: 'sqlite',
2825
+ id: '0',
2826
+ prevId: '0',
2827
+ ...rest2,
2828
+ } as const;
2829
+
2830
+ const sn2AfterIm = squashSqliteScheme(sch2);
2831
+ const validatedCurAfterImport = sqliteSchema.parse(sch2);
2832
+
2833
+ const {
2834
+ sqlStatements: afterFileSqlStatements,
2835
+ statements: afterFileStatements,
2836
+ } = await applyLibSQLSnapshotsDiff(
2837
+ sn2AfterIm,
2838
+ initSn,
2839
+ testTablesResolver(new Set()),
2840
+ testColumnsResolver(new Set()),
2841
+ testViewsResolverSqlite(new Set()),
2842
+ validatedCurAfterImport,
2843
+ validatedCur,
2844
+ );
2845
+
2846
+ fs.rmSync(`tests/introspect/libsql/${testName}.ts`);
2847
+
2848
+ return {
2849
+ sqlStatements: afterFileSqlStatements,
2850
+ statements: afterFileStatements,
2851
+ };
2852
+ };