@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,914 @@
1
+ import type { AwsDataApiPgQueryResult, AwsDataApiSessionOptions } from 'drizzle-orm/aws-data-api/pg';
2
+ import type { MigrationConfig } from 'drizzle-orm/migrator';
3
+ import type { PreparedQueryConfig } from 'drizzle-orm/pg-core';
4
+ import fetch from 'node-fetch';
5
+ import ws from 'ws';
6
+ import { assertUnreachable } from '../global';
7
+ import type { ProxyParams } from '../serializer/studio';
8
+ import {
9
+ type DB,
10
+ LibSQLDB,
11
+ normalisePGliteUrl,
12
+ normaliseSQLiteUrl,
13
+ type Proxy,
14
+ type SQLiteDB,
15
+ type SqliteProxy,
16
+ } from '../utils';
17
+ import { assertPackages, checkPackage } from './utils';
18
+ import { LibSQLCredentials } from './validations/libsql';
19
+ import type { MysqlCredentials } from './validations/mysql';
20
+ import { withStyle } from './validations/outputs';
21
+ import type { PostgresCredentials } from './validations/postgres';
22
+ import { SingleStoreCredentials } from './validations/singlestore';
23
+ import type { SqliteCredentials } from './validations/sqlite';
24
+
25
+ export const preparePostgresDB = async (
26
+ credentials: PostgresCredentials,
27
+ ): Promise<
28
+ DB & {
29
+ proxy: Proxy;
30
+ migrate: (config: string | MigrationConfig) => Promise<void>;
31
+ }
32
+ > => {
33
+ if ('driver' in credentials) {
34
+ const { driver } = credentials;
35
+ if (driver === 'aws-data-api') {
36
+ assertPackages('@aws-sdk/client-rds-data');
37
+ const { RDSDataClient, ExecuteStatementCommand, TypeHint } = await import(
38
+ '@aws-sdk/client-rds-data'
39
+ );
40
+ const { AwsDataApiSession, drizzle } = await import(
41
+ 'drizzle-orm/aws-data-api/pg'
42
+ );
43
+ const { migrate } = await import('drizzle-orm/aws-data-api/pg/migrator');
44
+ const { PgDialect } = await import('drizzle-orm/pg-core');
45
+
46
+ const config: AwsDataApiSessionOptions = {
47
+ database: credentials.database,
48
+ resourceArn: credentials.resourceArn,
49
+ secretArn: credentials.secretArn,
50
+ };
51
+ const rdsClient = new RDSDataClient();
52
+ const session = new AwsDataApiSession(
53
+ rdsClient,
54
+ new PgDialect(),
55
+ undefined,
56
+ config,
57
+ undefined,
58
+ );
59
+
60
+ const db = drizzle(rdsClient, config);
61
+ const migrateFn = async (config: MigrationConfig) => {
62
+ return migrate(db, config);
63
+ };
64
+
65
+ const query = async (sql: string, params: any[]) => {
66
+ const prepared = session.prepareQuery(
67
+ { sql, params: params ?? [] },
68
+ undefined,
69
+ undefined,
70
+ false,
71
+ );
72
+ const result = await prepared.all();
73
+ return result as any[];
74
+ };
75
+ const proxy = async (params: ProxyParams) => {
76
+ const prepared = session.prepareQuery<
77
+ PreparedQueryConfig & {
78
+ execute: AwsDataApiPgQueryResult<unknown>;
79
+ values: AwsDataApiPgQueryResult<unknown[]>;
80
+ }
81
+ >(
82
+ {
83
+ sql: params.sql,
84
+ params: params.params ?? [],
85
+ typings: params.typings,
86
+ },
87
+ undefined,
88
+ undefined,
89
+ params.mode === 'array',
90
+ );
91
+ if (params.mode === 'array') {
92
+ const result = await prepared.values();
93
+ return result.rows;
94
+ }
95
+ const result = await prepared.execute();
96
+ return result.rows;
97
+ };
98
+
99
+ return {
100
+ query,
101
+ proxy,
102
+ migrate: migrateFn,
103
+ };
104
+ }
105
+
106
+ if (driver === 'pglite') {
107
+ assertPackages('@electric-sql/pglite');
108
+ const { PGlite, types } = await import('@electric-sql/pglite');
109
+ const { drizzle } = await import('drizzle-orm/pglite');
110
+ const { migrate } = await import('drizzle-orm/pglite/migrator');
111
+
112
+ const pglite = new PGlite(normalisePGliteUrl(credentials.url));
113
+ await pglite.waitReady;
114
+ const drzl = drizzle(pglite);
115
+ const migrateFn = async (config: MigrationConfig) => {
116
+ return migrate(drzl, config);
117
+ };
118
+
119
+ const parsers = {
120
+ [types.TIMESTAMP]: (value: any) => value,
121
+ [types.TIMESTAMPTZ]: (value: any) => value,
122
+ [types.INTERVAL]: (value: any) => value,
123
+ [types.DATE]: (value: any) => value,
124
+ };
125
+
126
+ const query = async <T>(sql: string, params: any[] = []) => {
127
+ const result = await pglite.query(sql, params, {
128
+ parsers,
129
+ });
130
+ return result.rows as T[];
131
+ };
132
+
133
+ const proxy = async (params: ProxyParams) => {
134
+ const preparedParams = preparePGliteParams(params.params);
135
+ const result = await pglite.query(params.sql, preparedParams, {
136
+ rowMode: params.mode,
137
+ parsers,
138
+ });
139
+ return result.rows;
140
+ };
141
+
142
+ return { query, proxy, migrate: migrateFn };
143
+ }
144
+
145
+ assertUnreachable(driver);
146
+ }
147
+
148
+ if (await checkPackage('pg')) {
149
+ console.log(withStyle.info(`Using 'pg' driver for database querying`));
150
+ const { default: pg } = await import('pg');
151
+ const { drizzle } = await import('drizzle-orm/node-postgres');
152
+ const { migrate } = await import('drizzle-orm/node-postgres/migrator');
153
+
154
+ const ssl = 'ssl' in credentials
155
+ ? credentials.ssl === 'prefer'
156
+ || credentials.ssl === 'require'
157
+ || credentials.ssl === 'allow'
158
+ ? { rejectUnauthorized: false }
159
+ : credentials.ssl === 'verify-full'
160
+ ? {}
161
+ : credentials.ssl
162
+ : {};
163
+
164
+ // Override pg default date parsers
165
+ const types: { getTypeParser: typeof pg.types.getTypeParser } = {
166
+ // @ts-ignore
167
+ getTypeParser: (typeId, format) => {
168
+ if (typeId === pg.types.builtins.TIMESTAMPTZ) {
169
+ return (val) => val;
170
+ }
171
+ if (typeId === pg.types.builtins.TIMESTAMP) {
172
+ return (val) => val;
173
+ }
174
+ if (typeId === pg.types.builtins.DATE) {
175
+ return (val) => val;
176
+ }
177
+ if (typeId === pg.types.builtins.INTERVAL) {
178
+ return (val) => val;
179
+ }
180
+ // @ts-ignore
181
+ return pg.types.getTypeParser(typeId, format);
182
+ },
183
+ };
184
+
185
+ const client = 'url' in credentials
186
+ ? new pg.Pool({ connectionString: credentials.url, max: 1 })
187
+ : new pg.Pool({ ...credentials, ssl, max: 1 });
188
+
189
+ const db = drizzle(client);
190
+ const migrateFn = async (config: MigrationConfig) => {
191
+ return migrate(db, config);
192
+ };
193
+
194
+ const query = async (sql: string, params?: any[]) => {
195
+ const result = await client.query({
196
+ text: sql,
197
+ values: params ?? [],
198
+ types,
199
+ });
200
+ return result.rows;
201
+ };
202
+
203
+ const proxy: Proxy = async (params: ProxyParams) => {
204
+ const result = await client.query({
205
+ text: params.sql,
206
+ values: params.params,
207
+ ...(params.mode === 'array' && { rowMode: 'array' }),
208
+ types,
209
+ });
210
+ return result.rows;
211
+ };
212
+
213
+ return { query, proxy, migrate: migrateFn };
214
+ }
215
+
216
+ if (await checkPackage('postgres')) {
217
+ console.log(
218
+ withStyle.info(`Using 'postgres' driver for database querying`),
219
+ );
220
+ const postgres = await import('postgres');
221
+
222
+ const { drizzle } = await import('drizzle-orm/postgres-js');
223
+ const { migrate } = await import('drizzle-orm/postgres-js/migrator');
224
+
225
+ const client = 'url' in credentials
226
+ ? postgres.default(credentials.url, { max: 1 })
227
+ : postgres.default({ ...credentials, max: 1 });
228
+
229
+ const transparentParser = (val: any) => val;
230
+
231
+ // Override postgres.js default date parsers: https://github.com/porsager/postgres/discussions/761
232
+ for (const type of ['1184', '1082', '1083', '1114']) {
233
+ client.options.parsers[type as any] = transparentParser;
234
+ client.options.serializers[type as any] = transparentParser;
235
+ }
236
+ client.options.serializers['114'] = transparentParser;
237
+ client.options.serializers['3802'] = transparentParser;
238
+
239
+ const db = drizzle(client);
240
+ const migrateFn = async (config: MigrationConfig) => {
241
+ return migrate(db, config);
242
+ };
243
+
244
+ const query = async (sql: string, params?: any[]) => {
245
+ const result = await client.unsafe(sql, params ?? []);
246
+ return result as any[];
247
+ };
248
+
249
+ const proxy = async (params: ProxyParams) => {
250
+ if (params.mode === 'object') {
251
+ return await client.unsafe(params.sql, params.params);
252
+ }
253
+ return await client.unsafe(params.sql, params.params).values();
254
+ };
255
+
256
+ return { query, proxy, migrate: migrateFn };
257
+ }
258
+
259
+ if (await checkPackage('@vercel/postgres')) {
260
+ console.log(
261
+ withStyle.info(`Using '@vercel/postgres' driver for database querying`),
262
+ );
263
+ console.log(
264
+ withStyle.fullWarning(
265
+ "'@vercel/postgres' can only connect to remote Neon/Vercel Postgres/Supabase instances through a websocket",
266
+ ),
267
+ );
268
+ const { VercelPool, types: pgTypes } = await import('@vercel/postgres');
269
+ const { drizzle } = await import('drizzle-orm/vercel-postgres');
270
+ const { migrate } = await import('drizzle-orm/vercel-postgres/migrator');
271
+ const ssl = 'ssl' in credentials
272
+ ? credentials.ssl === 'prefer'
273
+ || credentials.ssl === 'require'
274
+ || credentials.ssl === 'allow'
275
+ ? { rejectUnauthorized: false }
276
+ : credentials.ssl === 'verify-full'
277
+ ? {}
278
+ : credentials.ssl
279
+ : {};
280
+
281
+ // Override @vercel/postgres default date parsers
282
+ const types: { getTypeParser: typeof pgTypes.getTypeParser } = {
283
+ // @ts-ignore
284
+ getTypeParser: (typeId, format) => {
285
+ if (typeId === pgTypes.builtins.TIMESTAMPTZ) {
286
+ return (val: any) => val;
287
+ }
288
+ if (typeId === pgTypes.builtins.TIMESTAMP) {
289
+ return (val: any) => val;
290
+ }
291
+ if (typeId === pgTypes.builtins.DATE) {
292
+ return (val: any) => val;
293
+ }
294
+ if (typeId === pgTypes.builtins.INTERVAL) {
295
+ return (val: any) => val;
296
+ }
297
+ // @ts-ignore
298
+ return pgTypes.getTypeParser(typeId, format);
299
+ },
300
+ };
301
+
302
+ const client = 'url' in credentials
303
+ ? new VercelPool({ connectionString: credentials.url })
304
+ : new VercelPool({ ...credentials, ssl });
305
+
306
+ await client.connect();
307
+
308
+ const db = drizzle(client);
309
+ const migrateFn = async (config: MigrationConfig) => {
310
+ return migrate(db, config);
311
+ };
312
+
313
+ const query = async (sql: string, params?: any[]) => {
314
+ const result = await client.query({
315
+ text: sql,
316
+ values: params ?? [],
317
+ types,
318
+ });
319
+ return result.rows;
320
+ };
321
+
322
+ const proxy: Proxy = async (params: ProxyParams) => {
323
+ const result = await client.query({
324
+ text: params.sql,
325
+ values: params.params,
326
+ ...(params.mode === 'array' && { rowMode: 'array' }),
327
+ types,
328
+ });
329
+ return result.rows;
330
+ };
331
+
332
+ return { query, proxy, migrate: migrateFn };
333
+ }
334
+
335
+ if (await checkPackage('@neondatabase/serverless')) {
336
+ console.log(
337
+ withStyle.info(
338
+ `Using '@neondatabase/serverless' driver for database querying`,
339
+ ),
340
+ );
341
+ console.log(
342
+ withStyle.fullWarning(
343
+ "'@neondatabase/serverless' can only connect to remote Neon/Vercel Postgres/Supabase instances through a websocket",
344
+ ),
345
+ );
346
+ const { Pool, neonConfig, types: pgTypes } = await import('@neondatabase/serverless');
347
+ const { drizzle } = await import('drizzle-orm/neon-serverless');
348
+ const { migrate } = await import('drizzle-orm/neon-serverless/migrator');
349
+
350
+ const ssl = 'ssl' in credentials
351
+ ? credentials.ssl === 'prefer'
352
+ || credentials.ssl === 'require'
353
+ || credentials.ssl === 'allow'
354
+ ? { rejectUnauthorized: false }
355
+ : credentials.ssl === 'verify-full'
356
+ ? {}
357
+ : credentials.ssl
358
+ : {};
359
+
360
+ // Override @neondatabase/serverless default date parsers
361
+ const types: { getTypeParser: typeof pgTypes.getTypeParser } = {
362
+ // @ts-ignore
363
+ getTypeParser: (typeId, format) => {
364
+ if (typeId === pgTypes.builtins.TIMESTAMPTZ) {
365
+ return (val: any) => val;
366
+ }
367
+ if (typeId === pgTypes.builtins.TIMESTAMP) {
368
+ return (val: any) => val;
369
+ }
370
+ if (typeId === pgTypes.builtins.DATE) {
371
+ return (val: any) => val;
372
+ }
373
+ if (typeId === pgTypes.builtins.INTERVAL) {
374
+ return (val: any) => val;
375
+ }
376
+ // @ts-ignore
377
+ return pgTypes.getTypeParser(typeId, format);
378
+ },
379
+ };
380
+
381
+ const client = 'url' in credentials
382
+ ? new Pool({ connectionString: credentials.url, max: 1 })
383
+ : new Pool({ ...credentials, max: 1, ssl });
384
+ neonConfig.webSocketConstructor = ws;
385
+
386
+ const db = drizzle(client);
387
+ const migrateFn = async (config: MigrationConfig) => {
388
+ return migrate(db, config);
389
+ };
390
+
391
+ const query = async (sql: string, params?: any[]) => {
392
+ const result = await client.query({
393
+ text: sql,
394
+ values: params ?? [],
395
+ types,
396
+ });
397
+ return result.rows;
398
+ };
399
+
400
+ const proxy: Proxy = async (params: ProxyParams) => {
401
+ const result = await client.query({
402
+ text: params.sql,
403
+ values: params.params,
404
+ ...(params.mode === 'array' && { rowMode: 'array' }),
405
+ types,
406
+ });
407
+ return result.rows;
408
+ };
409
+
410
+ return { query, proxy, migrate: migrateFn };
411
+ }
412
+
413
+ console.error(
414
+ "To connect to Postgres database - please install either of 'pg', 'postgres', '@neondatabase/serverless' or '@vercel/postgres' drivers",
415
+ );
416
+ process.exit(1);
417
+ };
418
+
419
+ const parseSingleStoreCredentials = (credentials: SingleStoreCredentials) => {
420
+ if ('url' in credentials) {
421
+ const url = credentials.url;
422
+
423
+ const connectionUrl = new URL(url);
424
+ const pathname = connectionUrl.pathname;
425
+
426
+ const database = pathname.split('/')[pathname.split('/').length - 1];
427
+ if (!database) {
428
+ console.error(
429
+ 'You should specify a database name in connection string (singlestore://USER:PASSWORD@HOST:PORT/DATABASE)',
430
+ );
431
+ process.exit(1);
432
+ }
433
+ return { database, url };
434
+ } else {
435
+ return {
436
+ database: credentials.database,
437
+ credentials,
438
+ };
439
+ }
440
+ };
441
+
442
+ export const connectToSingleStore = async (
443
+ it: SingleStoreCredentials,
444
+ ): Promise<{
445
+ db: DB;
446
+ proxy: Proxy;
447
+ database: string;
448
+ migrate: (config: MigrationConfig) => Promise<void>;
449
+ }> => {
450
+ const result = parseSingleStoreCredentials(it);
451
+
452
+ if (await checkPackage('mysql2')) {
453
+ const { createConnection } = await import('mysql2/promise');
454
+ const { drizzle } = await import('drizzle-orm/singlestore');
455
+ const { migrate } = await import('drizzle-orm/singlestore/migrator');
456
+
457
+ const connection = result.url
458
+ ? await createConnection(result.url)
459
+ : await createConnection(result.credentials!); // needed for some reason!
460
+
461
+ const db = drizzle(connection);
462
+ const migrateFn = async (config: MigrationConfig) => {
463
+ return migrate(db, config);
464
+ };
465
+
466
+ await connection.connect();
467
+ const query: DB['query'] = async <T>(
468
+ sql: string,
469
+ params?: any[],
470
+ ): Promise<T[]> => {
471
+ const res = await connection.execute(sql, params);
472
+ return res[0] as any;
473
+ };
474
+
475
+ const proxy: Proxy = async (params: ProxyParams) => {
476
+ const result = await connection.query({
477
+ sql: params.sql,
478
+ values: params.params,
479
+ rowsAsArray: params.mode === 'array',
480
+ });
481
+ return result[0] as any[];
482
+ };
483
+
484
+ return {
485
+ db: { query },
486
+ proxy,
487
+ database: result.database,
488
+ migrate: migrateFn,
489
+ };
490
+ }
491
+
492
+ console.error(
493
+ "To connect to SingleStore database - please install 'singlestore' driver",
494
+ );
495
+ process.exit(1);
496
+ };
497
+
498
+ const parseMysqlCredentials = (credentials: MysqlCredentials) => {
499
+ if ('url' in credentials) {
500
+ const url = credentials.url;
501
+
502
+ const connectionUrl = new URL(url);
503
+ const pathname = connectionUrl.pathname;
504
+
505
+ const database = pathname.split('/')[pathname.split('/').length - 1];
506
+ if (!database) {
507
+ console.error(
508
+ 'You should specify a database name in connection string (mysql://USER:PASSWORD@HOST:PORT/DATABASE)',
509
+ );
510
+ process.exit(1);
511
+ }
512
+ return { database, url };
513
+ } else {
514
+ return {
515
+ database: credentials.database,
516
+ credentials,
517
+ };
518
+ }
519
+ };
520
+
521
+ export const connectToMySQL = async (
522
+ it: MysqlCredentials,
523
+ ): Promise<{
524
+ db: DB;
525
+ proxy: Proxy;
526
+ database: string;
527
+ migrate: (config: MigrationConfig) => Promise<void>;
528
+ }> => {
529
+ const result = parseMysqlCredentials(it);
530
+
531
+ if (await checkPackage('mysql2')) {
532
+ const { createConnection } = await import('mysql2/promise');
533
+ const { drizzle } = await import('drizzle-orm/mysql2');
534
+ const { migrate } = await import('drizzle-orm/mysql2/migrator');
535
+
536
+ const connection = result.url
537
+ ? await createConnection(result.url)
538
+ : await createConnection(result.credentials!); // needed for some reason!
539
+
540
+ const db = drizzle(connection);
541
+ const migrateFn = async (config: MigrationConfig) => {
542
+ return migrate(db, config);
543
+ };
544
+
545
+ const typeCast = (field: any, next: any) => {
546
+ if (field.type === 'TIMESTAMP' || field.type === 'DATETIME' || field.type === 'DATE') {
547
+ return field.string();
548
+ }
549
+ return next();
550
+ };
551
+
552
+ await connection.connect();
553
+ const query: DB['query'] = async <T>(
554
+ sql: string,
555
+ params?: any[],
556
+ ): Promise<T[]> => {
557
+ const res = await connection.execute({
558
+ sql,
559
+ values: params,
560
+ typeCast,
561
+ });
562
+ return res[0] as any;
563
+ };
564
+
565
+ const proxy: Proxy = async (params: ProxyParams) => {
566
+ const result = await connection.query({
567
+ sql: params.sql,
568
+ values: params.params,
569
+ rowsAsArray: params.mode === 'array',
570
+ typeCast,
571
+ });
572
+ return result[0] as any[];
573
+ };
574
+
575
+ return {
576
+ db: { query },
577
+ proxy,
578
+ database: result.database,
579
+ migrate: migrateFn,
580
+ };
581
+ }
582
+
583
+ if (await checkPackage('@planetscale/database')) {
584
+ const { Client } = await import('@planetscale/database');
585
+ const { drizzle } = await import('drizzle-orm/planetscale-serverless');
586
+ const { migrate } = await import(
587
+ 'drizzle-orm/planetscale-serverless/migrator'
588
+ );
589
+
590
+ const connection = new Client(result);
591
+
592
+ const db = drizzle(connection);
593
+ const migrateFn = async (config: MigrationConfig) => {
594
+ return migrate(db, config);
595
+ };
596
+
597
+ const query = async <T>(sql: string, params?: any[]): Promise<T[]> => {
598
+ const res = await connection.execute(sql, params);
599
+ return res.rows as T[];
600
+ };
601
+ const proxy: Proxy = async (params: ProxyParams) => {
602
+ const result = params.mode === 'object'
603
+ ? await connection.execute(params.sql, params.params)
604
+ : await connection.execute(params.sql, params.params, {
605
+ as: 'array',
606
+ });
607
+ return result.rows;
608
+ };
609
+
610
+ return {
611
+ db: { query },
612
+ proxy,
613
+ database: result.database,
614
+ migrate: migrateFn,
615
+ };
616
+ }
617
+
618
+ console.error(
619
+ "To connect to MySQL database - please install either of 'mysql2' or '@planetscale/database' drivers",
620
+ );
621
+ process.exit(1);
622
+ };
623
+
624
+ const prepareSqliteParams = (params: any[], driver?: string) => {
625
+ return params.map((param) => {
626
+ if (
627
+ param
628
+ && typeof param === 'object'
629
+ && 'type' in param
630
+ && 'value' in param
631
+ && param.type === 'binary'
632
+ ) {
633
+ const value = typeof param.value === 'object'
634
+ ? JSON.stringify(param.value)
635
+ : (param.value as string);
636
+
637
+ if (driver === 'd1-http') {
638
+ return value;
639
+ }
640
+
641
+ return Buffer.from(value);
642
+ }
643
+ return param;
644
+ });
645
+ };
646
+
647
+ const preparePGliteParams = (params: any[]) => {
648
+ return params.map((param) => {
649
+ if (
650
+ param
651
+ && typeof param === 'object'
652
+ && 'type' in param
653
+ && 'value' in param
654
+ && param.type === 'binary'
655
+ ) {
656
+ const value = typeof param.value === 'object'
657
+ ? JSON.stringify(param.value)
658
+ : (param.value as string);
659
+
660
+ return value;
661
+ }
662
+ return param;
663
+ });
664
+ };
665
+
666
+ export const connectToSQLite = async (
667
+ credentials: SqliteCredentials,
668
+ ): Promise<
669
+ & SQLiteDB
670
+ & SqliteProxy
671
+ & { migrate: (config: MigrationConfig) => Promise<void> }
672
+ > => {
673
+ if ('driver' in credentials) {
674
+ const { driver } = credentials;
675
+ if (driver === 'd1-http') {
676
+ const { drizzle } = await import('drizzle-orm/sqlite-proxy');
677
+ const { migrate } = await import('drizzle-orm/sqlite-proxy/migrator');
678
+
679
+ const remoteCallback: Parameters<typeof drizzle>[0] = async (
680
+ sql,
681
+ params,
682
+ method,
683
+ ) => {
684
+ const res = await fetch(
685
+ `https://api.cloudflare.com/client/v4/accounts/${credentials.accountId}/d1/database/${credentials.databaseId}/${
686
+ method === 'values' ? 'raw' : 'query'
687
+ }`,
688
+ {
689
+ method: 'POST',
690
+ body: JSON.stringify({ sql, params }),
691
+ headers: {
692
+ 'Content-Type': 'application/json',
693
+ Authorization: `Bearer ${credentials.token}`,
694
+ },
695
+ },
696
+ );
697
+
698
+ const data = (await res.json()) as
699
+ | {
700
+ success: true;
701
+ result: {
702
+ results:
703
+ | any[]
704
+ | {
705
+ columns: string[];
706
+ rows: any[][];
707
+ };
708
+ }[];
709
+ }
710
+ | {
711
+ success: false;
712
+ errors: { code: number; message: string }[];
713
+ };
714
+
715
+ if (!data.success) {
716
+ throw new Error(
717
+ data.errors.map((it) => `${it.code}: ${it.message}`).join('\n'),
718
+ );
719
+ }
720
+
721
+ const result = data.result[0].results;
722
+ const rows = Array.isArray(result) ? result : result.rows;
723
+
724
+ return {
725
+ rows,
726
+ };
727
+ };
728
+
729
+ const drzl = drizzle(remoteCallback);
730
+ const migrateFn = async (config: MigrationConfig) => {
731
+ return migrate(
732
+ drzl,
733
+ async (queries) => {
734
+ for (const query of queries) {
735
+ await remoteCallback(query, [], 'run');
736
+ }
737
+ },
738
+ config,
739
+ );
740
+ };
741
+
742
+ const db: SQLiteDB = {
743
+ query: async <T>(sql: string, params?: any[]) => {
744
+ const res = await remoteCallback(sql, params || [], 'all');
745
+ return res.rows as T[];
746
+ },
747
+ run: async (query: string) => {
748
+ await remoteCallback(query, [], 'run');
749
+ },
750
+ };
751
+ const proxy: SqliteProxy = {
752
+ proxy: async (params: ProxyParams) => {
753
+ const preparedParams = prepareSqliteParams(params.params, 'd1-http');
754
+ const result = await remoteCallback(
755
+ params.sql,
756
+ preparedParams,
757
+ params.mode === 'array' ? 'values' : 'all',
758
+ );
759
+
760
+ return result.rows;
761
+ },
762
+ };
763
+ return { ...db, ...proxy, migrate: migrateFn };
764
+ } else {
765
+ assertUnreachable(driver);
766
+ }
767
+ }
768
+
769
+ if (await checkPackage('@libsql/client')) {
770
+ const { createClient } = await import('@libsql/client');
771
+ const { drizzle } = await import('drizzle-orm/libsql');
772
+ const { migrate } = await import('drizzle-orm/libsql/migrator');
773
+
774
+ const client = createClient({
775
+ url: normaliseSQLiteUrl(credentials.url, 'libsql'),
776
+ });
777
+ const drzl = drizzle(client);
778
+ const migrateFn = async (config: MigrationConfig) => {
779
+ return migrate(drzl, config);
780
+ };
781
+
782
+ const db: SQLiteDB = {
783
+ query: async <T>(sql: string, params?: any[]) => {
784
+ const res = await client.execute({ sql, args: params || [] });
785
+ return res.rows as T[];
786
+ },
787
+ run: async (query: string) => {
788
+ await client.execute(query);
789
+ },
790
+ };
791
+
792
+ const proxy: SqliteProxy = {
793
+ proxy: async (params: ProxyParams) => {
794
+ const preparedParams = prepareSqliteParams(params.params);
795
+ const result = await client.execute({
796
+ sql: params.sql,
797
+ args: preparedParams,
798
+ });
799
+
800
+ if (params.mode === 'array') {
801
+ return result.rows.map((row) => Object.values(row));
802
+ } else {
803
+ return result.rows;
804
+ }
805
+ },
806
+ };
807
+
808
+ return { ...db, ...proxy, migrate: migrateFn };
809
+ }
810
+
811
+ if (await checkPackage('better-sqlite3')) {
812
+ const { default: Database } = await import('better-sqlite3');
813
+ const { drizzle } = await import('drizzle-orm/better-sqlite3');
814
+ const { migrate } = await import('drizzle-orm/better-sqlite3/migrator');
815
+
816
+ const sqlite = new Database(
817
+ normaliseSQLiteUrl(credentials.url, 'better-sqlite'),
818
+ );
819
+ const drzl = drizzle(sqlite);
820
+ const migrateFn = async (config: MigrationConfig) => {
821
+ return migrate(drzl, config);
822
+ };
823
+
824
+ const db: SQLiteDB = {
825
+ query: async <T>(sql: string, params: any[] = []) => {
826
+ return sqlite.prepare(sql).bind(params).all() as T[];
827
+ },
828
+ run: async (query: string) => {
829
+ sqlite.prepare(query).run();
830
+ },
831
+ };
832
+
833
+ const proxy: SqliteProxy = {
834
+ proxy: async (params: ProxyParams) => {
835
+ const preparedParams = prepareSqliteParams(params.params);
836
+ if (
837
+ params.method === 'values'
838
+ || params.method === 'get'
839
+ || params.method === 'all'
840
+ ) {
841
+ return sqlite
842
+ .prepare(params.sql)
843
+ .raw(params.mode === 'array')
844
+ .all(preparedParams);
845
+ }
846
+
847
+ return sqlite.prepare(params.sql).run(preparedParams);
848
+ },
849
+ };
850
+ return { ...db, ...proxy, migrate: migrateFn };
851
+ }
852
+
853
+ console.log(
854
+ "Please install either 'better-sqlite3' or '@libsql/client' for Drizzle Kit to connect to SQLite databases",
855
+ );
856
+ process.exit(1);
857
+ };
858
+
859
+ export const connectToLibSQL = async (credentials: LibSQLCredentials): Promise<
860
+ & LibSQLDB
861
+ & SqliteProxy
862
+ & { migrate: (config: MigrationConfig) => Promise<void> }
863
+ > => {
864
+ if (await checkPackage('@libsql/client')) {
865
+ const { createClient } = await import('@libsql/client');
866
+ const { drizzle } = await import('drizzle-orm/libsql');
867
+ const { migrate } = await import('drizzle-orm/libsql/migrator');
868
+
869
+ const client = createClient({
870
+ url: normaliseSQLiteUrl(credentials.url, 'libsql'),
871
+ authToken: credentials.authToken,
872
+ });
873
+ const drzl = drizzle(client);
874
+ const migrateFn = async (config: MigrationConfig) => {
875
+ return migrate(drzl, config);
876
+ };
877
+
878
+ const db: LibSQLDB = {
879
+ query: async <T>(sql: string, params?: any[]) => {
880
+ const res = await client.execute({ sql, args: params || [] });
881
+ return res.rows as T[];
882
+ },
883
+ run: async (query: string) => {
884
+ await client.execute(query);
885
+ },
886
+ batchWithPragma: async (queries: string[]) => {
887
+ await client.migrate(queries);
888
+ },
889
+ };
890
+
891
+ const proxy: SqliteProxy = {
892
+ proxy: async (params: ProxyParams) => {
893
+ const preparedParams = prepareSqliteParams(params.params);
894
+ const result = await client.execute({
895
+ sql: params.sql,
896
+ args: preparedParams,
897
+ });
898
+
899
+ if (params.mode === 'array') {
900
+ return result.rows.map((row) => Object.values(row));
901
+ } else {
902
+ return result.rows;
903
+ }
904
+ },
905
+ };
906
+
907
+ return { ...db, ...proxy, migrate: migrateFn };
908
+ }
909
+
910
+ console.log(
911
+ "Please install '@libsql/client' for Drizzle Kit to connect to LibSQL databases",
912
+ );
913
+ process.exit(1);
914
+ };