@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,894 @@
1
+ import chalk from 'chalk';
2
+ import Docker from 'dockerode';
3
+ import { getTableConfig, index, int, singlestoreTable, text } from 'drizzle-orm/singlestore-core';
4
+ import fs from 'fs';
5
+ import getPort from 'get-port';
6
+ import { Connection, createConnection } from 'mysql2/promise';
7
+ import { diffTestSchemasPushSingleStore } from 'tests/schemaDiffer';
8
+ import { v4 as uuid } from 'uuid';
9
+ import { afterAll, beforeAll, expect, test } from 'vitest';
10
+
11
+ let client: Connection;
12
+ let singlestoreContainer: Docker.Container;
13
+
14
+ async function createDockerDB(): Promise<string> {
15
+ const docker = new Docker();
16
+ const port = await getPort({ port: 3306 });
17
+ const image = 'ghcr.io/singlestore-labs/singlestoredb-dev:latest';
18
+
19
+ const pullStream = await docker.pull(image);
20
+ await new Promise((resolve, reject) =>
21
+ docker.modem.followProgress(pullStream, (err) => err ? reject(err) : resolve(err))
22
+ );
23
+
24
+ singlestoreContainer = await docker.createContainer({
25
+ Image: image,
26
+ Env: ['ROOT_PASSWORD=singlestore'],
27
+ name: `drizzle-integration-tests-${uuid()}`,
28
+ HostConfig: {
29
+ AutoRemove: true,
30
+ PortBindings: {
31
+ '3306/tcp': [{ HostPort: `${port}` }],
32
+ },
33
+ },
34
+ });
35
+
36
+ await singlestoreContainer.start();
37
+ await new Promise((resolve) => setTimeout(resolve, 4000));
38
+
39
+ return `singlestore://root:singlestore@localhost:${port}/`;
40
+ }
41
+
42
+ beforeAll(async () => {
43
+ const connectionString = process.env.MYSQL_CONNECTION_STRING ?? (await createDockerDB());
44
+
45
+ const sleep = 1000;
46
+ let timeLeft = 20000;
47
+ let connected = false;
48
+ let lastError: unknown | undefined;
49
+ do {
50
+ try {
51
+ client = await createConnection(connectionString);
52
+ await client.connect();
53
+ connected = true;
54
+ break;
55
+ } catch (e) {
56
+ lastError = e;
57
+ await new Promise((resolve) => setTimeout(resolve, sleep));
58
+ timeLeft -= sleep;
59
+ }
60
+ } while (timeLeft > 0);
61
+ if (!connected) {
62
+ console.error('Cannot connect to MySQL');
63
+ await client?.end().catch(console.error);
64
+ await singlestoreContainer?.stop().catch(console.error);
65
+ throw lastError;
66
+ }
67
+
68
+ await client.query('DROP DATABASE IF EXISTS drizzle;');
69
+ await client.query('CREATE DATABASE drizzle;');
70
+ await client.query('USE drizzle;');
71
+ });
72
+
73
+ afterAll(async () => {
74
+ await client?.end().catch(console.error);
75
+ await singlestoreContainer?.stop().catch(console.error);
76
+ });
77
+
78
+ if (!fs.existsSync('tests/push/singlestore')) {
79
+ fs.mkdirSync('tests/push/singlestore');
80
+ }
81
+
82
+ test('db has checks. Push with same names', async () => {
83
+ const schema1 = {
84
+ test: singlestoreTable('test', {
85
+ id: int('id').primaryKey(),
86
+ values: int('values').default(1),
87
+ }),
88
+ };
89
+ const schema2 = {
90
+ test: singlestoreTable('test', {
91
+ id: int('id').primaryKey(),
92
+ values: int('values').default(1),
93
+ }),
94
+ };
95
+
96
+ const { statements, sqlStatements } = await diffTestSchemasPushSingleStore(
97
+ client,
98
+ schema1,
99
+ schema2,
100
+ [],
101
+ 'drizzle',
102
+ );
103
+
104
+ expect(statements).toStrictEqual([]);
105
+ expect(sqlStatements).toStrictEqual([]);
106
+
107
+ await client.query(`DROP TABLE \`test\`;`);
108
+ });
109
+
110
+ // TODO: Unskip this test when views are implemented
111
+ /* test.skip.skip('create view', async () => {
112
+ const table = singlestoreTable('test', {
113
+ id: int('id').primaryKey(),
114
+ });
115
+
116
+ const schema1 = {
117
+ test: table,
118
+ };
119
+
120
+ const schema2 = {
121
+ test: table,
122
+ view: singlestoreView('view').as((qb) => qb.select().from(table)),
123
+ };
124
+
125
+ const { statements, sqlStatements } = await diffTestSchemasPushSingleStore(
126
+ client,
127
+ schema1,
128
+ schema2,
129
+ [],
130
+ 'drizzle',
131
+ false,
132
+ );
133
+
134
+ expect(statements).toStrictEqual([
135
+ {
136
+ definition: 'select `id` from `test`',
137
+ name: 'view',
138
+ type: 'singlestore_create_view',
139
+ replace: false,
140
+ sqlSecurity: 'definer',
141
+ withCheckOption: undefined,
142
+ algorithm: 'undefined',
143
+ },
144
+ ]);
145
+ expect(sqlStatements).toStrictEqual([
146
+ `CREATE ALGORITHM = undefined
147
+ SQL SECURITY definer
148
+ VIEW \`view\` AS (select \`id\` from \`test\`);`,
149
+ ]);
150
+
151
+ await client.query(`DROP TABLE \`test\`;`);
152
+ }); */
153
+
154
+ // TODO: Unskip this test when views are implemented
155
+ /* test.skip('drop view', async () => {
156
+ const table = singlestoreTable('test', {
157
+ id: int('id').primaryKey(),
158
+ });
159
+
160
+ const schema1 = {
161
+ test: table,
162
+ view: singlestoreView('view').as((qb) => qb.select().from(table)),
163
+ };
164
+
165
+ const schema2 = {
166
+ test: table,
167
+ };
168
+
169
+ const { statements, sqlStatements } = await diffTestSchemasPushSingleStore(
170
+ client,
171
+ schema1,
172
+ schema2,
173
+ [],
174
+ 'drizzle',
175
+ false,
176
+ );
177
+
178
+ expect(statements).toStrictEqual([
179
+ {
180
+ name: 'view',
181
+ type: 'drop_view',
182
+ },
183
+ ]);
184
+ expect(sqlStatements).toStrictEqual(['DROP VIEW `view`;']);
185
+ await client.query(`DROP TABLE \`test\`;`);
186
+ await client.query(`DROP VIEW \`view\`;`);
187
+ }); */
188
+
189
+ // TODO: Unskip this test when views are implemented
190
+ /* test.skip('alter view ".as"', async () => {
191
+ const table = singlestoreTable('test', {
192
+ id: int('id').primaryKey(),
193
+ });
194
+
195
+ const schema1 = {
196
+ test: table,
197
+ view: singlestoreView('view').as((qb) =>
198
+ qb
199
+ .select()
200
+ .from(table)
201
+ .where(sql`${table.id} = 1`)
202
+ ),
203
+ };
204
+
205
+ const schema2 = {
206
+ test: table,
207
+ view: singlestoreView('view').as((qb) => qb.select().from(table)),
208
+ };
209
+
210
+ const { statements, sqlStatements } = await diffTestSchemasPushSingleStore(
211
+ client,
212
+ schema1,
213
+ schema2,
214
+ [],
215
+ 'drizzle',
216
+ false,
217
+ );
218
+
219
+ expect(statements.length).toBe(0);
220
+ expect(sqlStatements.length).toBe(0);
221
+
222
+ await client.query(`DROP TABLE \`test\`;`);
223
+ await client.query(`DROP VIEW \`view\`;`);
224
+ }); */
225
+
226
+ // TODO: Unskip this test when views are implemented
227
+ /* test.skip('alter meta options with distinct in definition', async () => {
228
+ const table = singlestoreTable('test', {
229
+ id: int('id').primaryKey(),
230
+ });
231
+
232
+ const schema1 = {
233
+ test: table,
234
+ view: singlestoreView('view')
235
+ .withCheckOption('cascaded')
236
+ .sqlSecurity('definer')
237
+ .algorithm('merge')
238
+ .as((qb) =>
239
+ qb
240
+ .selectDistinct()
241
+ .from(table)
242
+ .where(sql`${table.id} = 1`)
243
+ ),
244
+ };
245
+
246
+ const schema2 = {
247
+ test: table,
248
+ view: singlestoreView('view')
249
+ .withCheckOption('cascaded')
250
+ .sqlSecurity('definer')
251
+ .algorithm('undefined')
252
+ .as((qb) => qb.selectDistinct().from(table)),
253
+ };
254
+
255
+ await expect(
256
+ diffTestSchemasPushSingleStore(
257
+ client,
258
+ schema1,
259
+ schema2,
260
+ [],
261
+ 'drizzle',
262
+ false,
263
+ ),
264
+ ).rejects.toThrowError();
265
+
266
+ await client.query(`DROP TABLE \`test\`;`);
267
+ }); */
268
+
269
+ test('added column not null and without default to table with data', async (t) => {
270
+ const schema1 = {
271
+ companies: singlestoreTable('companies', {
272
+ id: int('id'),
273
+ name: text('name'),
274
+ }),
275
+ };
276
+
277
+ const schema2 = {
278
+ companies: singlestoreTable('companies', {
279
+ id: int('id'),
280
+ name: text('name'),
281
+ age: int('age').notNull(),
282
+ }),
283
+ };
284
+
285
+ const table = getTableConfig(schema1.companies);
286
+
287
+ const seedStatements = [
288
+ `INSERT INTO \`${table.name}\` (\`${schema1.companies.name.name}\`) VALUES ('drizzle');`,
289
+ `INSERT INTO \`${table.name}\` (\`${schema1.companies.name.name}\`) VALUES ('turso');`,
290
+ ];
291
+
292
+ const {
293
+ statements,
294
+ sqlStatements,
295
+ columnsToRemove,
296
+ infoToPrint,
297
+ shouldAskForApprove,
298
+ tablesToRemove,
299
+ tablesToTruncate,
300
+ } = await diffTestSchemasPushSingleStore(
301
+ client,
302
+ schema1,
303
+ schema2,
304
+ [],
305
+ 'drizzle',
306
+ false,
307
+ undefined,
308
+ {
309
+ after: seedStatements,
310
+ },
311
+ );
312
+
313
+ expect(statements.length).toBe(1);
314
+ expect(statements[0]).toStrictEqual({
315
+ type: 'alter_table_add_column',
316
+ tableName: 'companies',
317
+ column: {
318
+ name: 'age',
319
+ type: 'int',
320
+ primaryKey: false,
321
+ notNull: true,
322
+ autoincrement: false,
323
+ },
324
+ schema: '',
325
+ });
326
+
327
+ expect(sqlStatements.length).toBe(2);
328
+ expect(sqlStatements[0]).toBe(`truncate table companies;`);
329
+ expect(sqlStatements[1]).toBe(
330
+ `ALTER TABLE \`companies\` ADD \`age\` int NOT NULL;`,
331
+ );
332
+
333
+ expect(columnsToRemove!.length).toBe(0);
334
+ expect(infoToPrint!.length).toBe(1);
335
+ expect(infoToPrint![0]).toBe(
336
+ `· You're about to add not-null ${
337
+ chalk.underline(
338
+ 'age',
339
+ )
340
+ } column without default value, which contains 2 items`,
341
+ );
342
+ expect(shouldAskForApprove).toBe(true);
343
+ expect(tablesToRemove!.length).toBe(0);
344
+ expect(tablesToTruncate!.length).toBe(1);
345
+ expect(tablesToTruncate![0]).toBe('companies');
346
+
347
+ await client.query(`DROP TABLE \`companies\`;`);
348
+ });
349
+
350
+ test('added column not null and without default to table without data', async (t) => {
351
+ const schema1 = {
352
+ companies: singlestoreTable('companies', {
353
+ id: int('id').primaryKey(),
354
+ name: text('name').notNull(),
355
+ }),
356
+ };
357
+
358
+ const schema2 = {
359
+ companies: singlestoreTable('companies', {
360
+ id: int('id').primaryKey(),
361
+ name: text('name').notNull(),
362
+ age: int('age').notNull(),
363
+ }),
364
+ };
365
+
366
+ const {
367
+ statements,
368
+ sqlStatements,
369
+ columnsToRemove,
370
+ infoToPrint,
371
+ shouldAskForApprove,
372
+ tablesToRemove,
373
+ tablesToTruncate,
374
+ } = await diffTestSchemasPushSingleStore(
375
+ client,
376
+ schema1,
377
+ schema2,
378
+ [],
379
+ 'drizzle',
380
+ false,
381
+ undefined,
382
+ );
383
+
384
+ expect(statements.length).toBe(1);
385
+ expect(statements[0]).toStrictEqual({
386
+ type: 'alter_table_add_column',
387
+ tableName: 'companies',
388
+ column: {
389
+ name: 'age',
390
+ type: 'int',
391
+ primaryKey: false,
392
+ notNull: true,
393
+ autoincrement: false,
394
+ },
395
+ schema: '',
396
+ });
397
+
398
+ expect(sqlStatements.length).toBe(1);
399
+ expect(sqlStatements[0]).toBe(
400
+ `ALTER TABLE \`companies\` ADD \`age\` int NOT NULL;`,
401
+ );
402
+
403
+ expect(infoToPrint!.length).toBe(0);
404
+ expect(columnsToRemove!.length).toBe(0);
405
+ expect(shouldAskForApprove).toBe(false);
406
+ expect(tablesToRemove!.length).toBe(0);
407
+ expect(tablesToTruncate!.length).toBe(0);
408
+
409
+ await client.query(`DROP TABLE \`companies\`;`);
410
+ });
411
+
412
+ test('drop not null, add not null', async (t) => {
413
+ const schema1 = {
414
+ users: singlestoreTable('users', {
415
+ id: int('id').primaryKey(),
416
+ name: text('name').notNull(),
417
+ }),
418
+ posts: singlestoreTable(
419
+ 'posts',
420
+ {
421
+ id: int('id').primaryKey(),
422
+ name: text('name'),
423
+ userId: int('user_id'),
424
+ },
425
+ ),
426
+ };
427
+
428
+ const schema2 = {
429
+ users: singlestoreTable('users', {
430
+ id: int('id').primaryKey(),
431
+ name: text('name'),
432
+ }),
433
+ posts: singlestoreTable(
434
+ 'posts',
435
+ {
436
+ id: int('id').primaryKey(),
437
+ name: text('name').notNull(),
438
+ userId: int('user_id'),
439
+ },
440
+ ),
441
+ };
442
+ const {
443
+ statements,
444
+ sqlStatements,
445
+ columnsToRemove,
446
+ infoToPrint,
447
+ shouldAskForApprove,
448
+ tablesToRemove,
449
+ tablesToTruncate,
450
+ } = await diffTestSchemasPushSingleStore(
451
+ client,
452
+ schema1,
453
+ schema2,
454
+ [],
455
+ 'drizzle',
456
+ false,
457
+ undefined,
458
+ );
459
+
460
+ expect(statements!.length).toBe(2);
461
+ expect(statements![0]).toStrictEqual({
462
+ columns: [
463
+ {
464
+ autoincrement: false,
465
+ generated: undefined,
466
+ name: 'id',
467
+ notNull: true,
468
+ onUpdate: undefined,
469
+ primaryKey: false,
470
+ type: 'int',
471
+ },
472
+ {
473
+ autoincrement: false,
474
+ generated: undefined,
475
+ name: 'name',
476
+ notNull: true,
477
+ onUpdate: undefined,
478
+ primaryKey: false,
479
+ type: 'text',
480
+ },
481
+ {
482
+ autoincrement: false,
483
+ generated: undefined,
484
+ name: 'user_id',
485
+ notNull: false,
486
+ onUpdate: undefined,
487
+ primaryKey: false,
488
+ type: 'int',
489
+ },
490
+ ],
491
+ compositePKs: [
492
+ 'posts_id;id',
493
+ ],
494
+ tableName: 'posts',
495
+ type: 'singlestore_recreate_table',
496
+ uniqueConstraints: [],
497
+ });
498
+ expect(statements![1]).toStrictEqual({
499
+ columns: [
500
+ {
501
+ autoincrement: false,
502
+ generated: undefined,
503
+ name: 'id',
504
+ notNull: true,
505
+ onUpdate: undefined,
506
+ primaryKey: false,
507
+ type: 'int',
508
+ },
509
+ {
510
+ autoincrement: false,
511
+ generated: undefined,
512
+ name: 'name',
513
+ notNull: false,
514
+ onUpdate: undefined,
515
+ primaryKey: false,
516
+ type: 'text',
517
+ },
518
+ ],
519
+ compositePKs: [
520
+ 'users_id;id',
521
+ ],
522
+ tableName: 'users',
523
+ type: 'singlestore_recreate_table',
524
+ uniqueConstraints: [],
525
+ });
526
+ expect(sqlStatements!.length).toBe(8);
527
+ expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_posts\` (
528
+ \t\`id\` int NOT NULL,
529
+ \t\`name\` text NOT NULL,
530
+ \t\`user_id\` int,
531
+ \tCONSTRAINT \`posts_id\` PRIMARY KEY(\`id\`)
532
+ );\n`);
533
+ expect(sqlStatements![1]).toBe(
534
+ `INSERT INTO \`__new_posts\`(\`id\`, \`name\`, \`user_id\`) SELECT \`id\`, \`name\`, \`user_id\` FROM \`posts\`;`,
535
+ );
536
+ expect(sqlStatements![2]).toBe(`DROP TABLE \`posts\`;`);
537
+ expect(sqlStatements![3]).toBe(`ALTER TABLE \`__new_posts\` RENAME TO \`posts\`;`);
538
+ expect(sqlStatements![4]).toBe(`CREATE TABLE \`__new_users\` (
539
+ \t\`id\` int NOT NULL,
540
+ \t\`name\` text,
541
+ \tCONSTRAINT \`users_id\` PRIMARY KEY(\`id\`)
542
+ );\n`);
543
+ expect(sqlStatements![5]).toBe(
544
+ `INSERT INTO \`__new_users\`(\`id\`, \`name\`) SELECT \`id\`, \`name\` FROM \`users\`;`,
545
+ );
546
+ expect(sqlStatements![6]).toBe(
547
+ `DROP TABLE \`users\`;`,
548
+ );
549
+ expect(sqlStatements![7]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`);
550
+ expect(columnsToRemove!.length).toBe(0);
551
+ expect(infoToPrint!.length).toBe(0);
552
+ expect(shouldAskForApprove).toBe(false);
553
+ expect(tablesToRemove!.length).toBe(0);
554
+ expect(tablesToTruncate!.length).toBe(0);
555
+
556
+ await client.query(`DROP TABLE \`users\`;`);
557
+ await client.query(`DROP TABLE \`posts\`;`);
558
+ });
559
+
560
+ test('drop table with data', async (t) => {
561
+ const schema1 = {
562
+ users: singlestoreTable('users', {
563
+ id: int('id').primaryKey(),
564
+ name: text('name').notNull(),
565
+ }),
566
+ posts: singlestoreTable(
567
+ 'posts',
568
+ {
569
+ id: int('id').primaryKey(),
570
+ name: text('name'),
571
+ userId: int('user_id'),
572
+ },
573
+ ),
574
+ };
575
+
576
+ const schema2 = {
577
+ posts: singlestoreTable(
578
+ 'posts',
579
+ {
580
+ id: int('id').primaryKey(),
581
+ name: text('name'),
582
+ userId: int('user_id'),
583
+ },
584
+ ),
585
+ };
586
+
587
+ const seedStatements = [
588
+ `INSERT INTO \`users\` (\`id\`, \`name\`) VALUES (1, 'drizzle')`,
589
+ ];
590
+ const {
591
+ statements,
592
+ sqlStatements,
593
+ columnsToRemove,
594
+ infoToPrint,
595
+ shouldAskForApprove,
596
+ tablesToRemove,
597
+ tablesToTruncate,
598
+ } = await diffTestSchemasPushSingleStore(
599
+ client,
600
+ schema1,
601
+ schema2,
602
+ [],
603
+ 'drizzle',
604
+ false,
605
+ undefined,
606
+ { after: seedStatements },
607
+ );
608
+
609
+ expect(statements!.length).toBe(1);
610
+ expect(statements![0]).toStrictEqual({
611
+ policies: [],
612
+ schema: undefined,
613
+ tableName: 'users',
614
+ type: 'drop_table',
615
+ });
616
+
617
+ expect(sqlStatements!.length).toBe(1);
618
+ expect(sqlStatements![0]).toBe(`DROP TABLE \`users\`;`);
619
+ expect(columnsToRemove!.length).toBe(0);
620
+ expect(infoToPrint!.length).toBe(1);
621
+ expect(infoToPrint![0]).toBe(`· You're about to delete ${chalk.underline('users')} table with 1 items`);
622
+ expect(shouldAskForApprove).toBe(true);
623
+ expect(tablesToRemove!.length).toBe(1);
624
+ expect(tablesToRemove![0]).toBe('users');
625
+ expect(tablesToTruncate!.length).toBe(0);
626
+
627
+ await client.query(`DROP TABLE \`users\`;`);
628
+ await client.query(`DROP TABLE \`posts\`;`);
629
+ });
630
+
631
+ test('change data type. db has indexes. table does not have values', async (t) => {
632
+ const schema1 = {
633
+ users: singlestoreTable('users', {
634
+ id: int('id').primaryKey(),
635
+ name: int('name').notNull(),
636
+ }, (table) => [index('index').on(table.name)]),
637
+ };
638
+
639
+ const schema2 = {
640
+ users: singlestoreTable('users', {
641
+ id: int('id').primaryKey(),
642
+ name: text('name').notNull(),
643
+ }, (table) => [index('index').on(table.name)]),
644
+ };
645
+
646
+ const seedStatements = [`INSERT INTO users VALUES (1, 12)`];
647
+
648
+ const {
649
+ statements,
650
+ sqlStatements,
651
+ columnsToRemove,
652
+ infoToPrint,
653
+ shouldAskForApprove,
654
+ tablesToRemove,
655
+ tablesToTruncate,
656
+ } = await diffTestSchemasPushSingleStore(
657
+ client,
658
+ schema1,
659
+ schema2,
660
+ [],
661
+ 'drizzle',
662
+ false,
663
+ undefined,
664
+ );
665
+
666
+ expect(statements!.length).toBe(2);
667
+ expect(statements![0]).toStrictEqual({
668
+ columns: [
669
+ {
670
+ autoincrement: false,
671
+ generated: undefined,
672
+ name: 'id',
673
+ notNull: true,
674
+ onUpdate: undefined,
675
+ primaryKey: false,
676
+ type: 'int',
677
+ },
678
+ {
679
+ autoincrement: false,
680
+ generated: undefined,
681
+ name: 'name',
682
+ notNull: true,
683
+ onUpdate: undefined,
684
+ primaryKey: false,
685
+ type: 'text',
686
+ },
687
+ ],
688
+ compositePKs: [
689
+ 'users_id;id',
690
+ ],
691
+ tableName: 'users',
692
+ type: 'singlestore_recreate_table',
693
+ uniqueConstraints: [],
694
+ });
695
+ expect(statements![1]).toStrictEqual({
696
+ data: 'index;name;false;;;',
697
+ internal: undefined,
698
+ schema: '',
699
+ tableName: 'users',
700
+ type: 'create_index',
701
+ });
702
+
703
+ expect(sqlStatements!.length).toBe(5);
704
+ expect(sqlStatements![0]).toBe(`CREATE TABLE \`__new_users\` (
705
+ \t\`id\` int NOT NULL,
706
+ \t\`name\` text NOT NULL,
707
+ \tCONSTRAINT \`users_id\` PRIMARY KEY(\`id\`)
708
+ );\n`);
709
+ expect(sqlStatements![1]).toBe(
710
+ `INSERT INTO \`__new_users\`(\`id\`, \`name\`) SELECT \`id\`, \`name\` FROM \`users\`;`,
711
+ );
712
+ expect(sqlStatements![2]).toBe(`DROP TABLE \`users\`;`);
713
+ expect(sqlStatements![3]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`);
714
+ expect(sqlStatements![4]).toBe(`CREATE INDEX \`index\` ON \`users\` (\`name\`);`);
715
+ expect(columnsToRemove!.length).toBe(0);
716
+ expect(infoToPrint!.length).toBe(0);
717
+ expect(shouldAskForApprove).toBe(false);
718
+ expect(tablesToRemove!.length).toBe(0);
719
+ expect(tablesToTruncate!.length).toBe(0);
720
+
721
+ await client.query(`DROP TABLE \`users\`;`);
722
+ });
723
+
724
+ test('change data type. db has indexes. table has values', async (t) => {
725
+ const schema1 = {
726
+ users: singlestoreTable('users', {
727
+ id: int('id').primaryKey(),
728
+ name: int('name'),
729
+ }, (table) => [index('index').on(table.name)]),
730
+ };
731
+
732
+ const schema2 = {
733
+ users: singlestoreTable('users', {
734
+ id: int('id').primaryKey(),
735
+ name: text('name'),
736
+ }, (table) => [index('index').on(table.name)]),
737
+ };
738
+
739
+ const seedStatements = [`INSERT INTO users VALUES (1, 12);`, `INSERT INTO users (id) VALUES (2);`];
740
+
741
+ const {
742
+ statements,
743
+ sqlStatements,
744
+ columnsToRemove,
745
+ infoToPrint,
746
+ shouldAskForApprove,
747
+ tablesToRemove,
748
+ tablesToTruncate,
749
+ } = await diffTestSchemasPushSingleStore(
750
+ client,
751
+ schema1,
752
+ schema2,
753
+ [],
754
+ 'drizzle',
755
+ false,
756
+ undefined,
757
+ { after: seedStatements },
758
+ );
759
+
760
+ expect(statements!.length).toBe(2);
761
+ expect(statements![0]).toStrictEqual({
762
+ columns: [
763
+ {
764
+ autoincrement: false,
765
+ generated: undefined,
766
+ name: 'id',
767
+ notNull: true,
768
+ onUpdate: undefined,
769
+ primaryKey: false,
770
+ type: 'int',
771
+ },
772
+ {
773
+ autoincrement: false,
774
+ generated: undefined,
775
+ name: 'name',
776
+ notNull: false,
777
+ onUpdate: undefined,
778
+ primaryKey: false,
779
+ type: 'text',
780
+ },
781
+ ],
782
+ compositePKs: [
783
+ 'users_id;id',
784
+ ],
785
+ tableName: 'users',
786
+ type: 'singlestore_recreate_table',
787
+ uniqueConstraints: [],
788
+ });
789
+ expect(statements![1]).toStrictEqual({
790
+ data: 'index;name;false;;;',
791
+ internal: undefined,
792
+ schema: '',
793
+ tableName: 'users',
794
+ type: 'create_index',
795
+ });
796
+
797
+ expect(sqlStatements!.length).toBe(6);
798
+ expect(sqlStatements![0]).toBe(`TRUNCATE TABLE \`users\`;`);
799
+ expect(sqlStatements![1]).toBe(`CREATE TABLE \`__new_users\` (
800
+ \t\`id\` int NOT NULL,
801
+ \t\`name\` text,
802
+ \tCONSTRAINT \`users_id\` PRIMARY KEY(\`id\`)
803
+ );\n`);
804
+ expect(sqlStatements![2]).toBe(
805
+ `INSERT INTO \`__new_users\`(\`id\`, \`name\`) SELECT \`id\`, \`name\` FROM \`users\`;`,
806
+ );
807
+ expect(sqlStatements![3]).toBe(`DROP TABLE \`users\`;`);
808
+ expect(sqlStatements![4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`);
809
+ expect(sqlStatements![5]).toBe(`CREATE INDEX \`index\` ON \`users\` (\`name\`);`);
810
+ expect(columnsToRemove!.length).toBe(0);
811
+ expect(infoToPrint!.length).toBe(1);
812
+ expect(infoToPrint![0]).toBe(
813
+ `· You're about recreate ${chalk.underline('users')} table with data type changing for ${
814
+ chalk.underline('name')
815
+ } column, which contains 1 items`,
816
+ );
817
+ expect(shouldAskForApprove).toBe(true);
818
+ expect(tablesToRemove!.length).toBe(0);
819
+ expect(tablesToTruncate!.length).toBe(1);
820
+ expect(tablesToTruncate![0]).toBe(`users`);
821
+
822
+ await client.query(`DROP TABLE \`users\`;`);
823
+ });
824
+
825
+ test('add column. add default to column without not null', async (t) => {
826
+ const schema1 = {
827
+ users: singlestoreTable('users', {
828
+ id: int('id').primaryKey(),
829
+ name: text('name'),
830
+ }),
831
+ };
832
+
833
+ const schema2 = {
834
+ users: singlestoreTable('users', {
835
+ id: int('id').primaryKey(),
836
+ name: text('name').default('drizzle'),
837
+ age: int('age'),
838
+ }),
839
+ };
840
+
841
+ const {
842
+ statements,
843
+ sqlStatements,
844
+ columnsToRemove,
845
+ infoToPrint,
846
+ shouldAskForApprove,
847
+ tablesToRemove,
848
+ tablesToTruncate,
849
+ } = await diffTestSchemasPushSingleStore(
850
+ client,
851
+ schema1,
852
+ schema2,
853
+ [],
854
+ 'drizzle',
855
+ false,
856
+ undefined,
857
+ );
858
+
859
+ expect(statements!.length).toBe(2);
860
+ expect(statements![0]).toStrictEqual({
861
+ columnAutoIncrement: false,
862
+ columnName: 'name',
863
+ columnNotNull: false,
864
+ columnOnUpdate: undefined,
865
+ columnPk: false,
866
+ newDataType: 'text',
867
+ newDefaultValue: "'drizzle'",
868
+ schema: '',
869
+ tableName: 'users',
870
+ type: 'alter_table_alter_column_set_default',
871
+ });
872
+ expect(statements![1]).toStrictEqual({
873
+ type: 'alter_table_add_column',
874
+ tableName: 'users',
875
+ schema: '',
876
+ column: {
877
+ notNull: false,
878
+ primaryKey: false,
879
+ autoincrement: false,
880
+ name: 'age',
881
+ type: 'int',
882
+ },
883
+ });
884
+ expect(sqlStatements!.length).toBe(2);
885
+ expect(sqlStatements![0]).toBe(`ALTER TABLE \`users\` MODIFY COLUMN \`name\` text DEFAULT 'drizzle';`);
886
+ expect(sqlStatements![1]).toBe(`ALTER TABLE \`users\` ADD \`age\` int;`);
887
+ expect(columnsToRemove!.length).toBe(0);
888
+ expect(infoToPrint!.length).toBe(0);
889
+ expect(shouldAskForApprove).toBe(false);
890
+ expect(tablesToRemove!.length).toBe(0);
891
+ expect(tablesToTruncate!.length).toBe(0);
892
+
893
+ await client.query(`DROP TABLE \`users\`;`);
894
+ });