@anthonyalayo/drizzle-kit 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitignore +25 -0
- package/README.md +79 -0
- package/build.dev.ts +51 -0
- package/build.ts +112 -0
- package/imports-checker/analyze.ts +78 -0
- package/imports-checker/checker.ts +296 -0
- package/imports-checker/grammar/grammar.ohm +121 -0
- package/imports-checker/grammar/grammar.ohm-bundle.d.ts +164 -0
- package/imports-checker/grammar/grammar.ohm-bundle.js +753 -0
- package/imports-checker/index.ts +48 -0
- package/package.json +142 -0
- package/patches/difflib@0.2.4.patch +31 -0
- package/src/@types/utils.ts +58 -0
- package/src/api.ts +504 -0
- package/src/cli/commands/_es5.ts +2 -0
- package/src/cli/commands/check.ts +52 -0
- package/src/cli/commands/drop.ts +60 -0
- package/src/cli/commands/introspect.ts +772 -0
- package/src/cli/commands/libSqlPushUtils.ts +355 -0
- package/src/cli/commands/migrate.ts +1526 -0
- package/src/cli/commands/mysqlIntrospect.ts +53 -0
- package/src/cli/commands/mysqlPushUtils.ts +352 -0
- package/src/cli/commands/mysqlUp.ts +102 -0
- package/src/cli/commands/pgIntrospect.ts +55 -0
- package/src/cli/commands/pgPushUtils.ts +269 -0
- package/src/cli/commands/pgUp.ts +217 -0
- package/src/cli/commands/push.ts +637 -0
- package/src/cli/commands/singlestoreIntrospect.ts +53 -0
- package/src/cli/commands/singlestorePushUtils.ts +456 -0
- package/src/cli/commands/singlestoreUp.ts +1 -0
- package/src/cli/commands/sqliteIntrospect.ts +96 -0
- package/src/cli/commands/sqlitePushUtils.ts +322 -0
- package/src/cli/commands/sqliteUp.ts +52 -0
- package/src/cli/commands/utils.ts +858 -0
- package/src/cli/connections.ts +914 -0
- package/src/cli/index.ts +48 -0
- package/src/cli/schema.ts +794 -0
- package/src/cli/selector-ui.ts +38 -0
- package/src/cli/utils.ts +112 -0
- package/src/cli/validations/cli.ts +79 -0
- package/src/cli/validations/common.ts +193 -0
- package/src/cli/validations/libsql.ts +27 -0
- package/src/cli/validations/mysql.ts +61 -0
- package/src/cli/validations/outputs.ts +91 -0
- package/src/cli/validations/postgres.ts +83 -0
- package/src/cli/validations/singlestore.ts +61 -0
- package/src/cli/validations/sqlite.ts +104 -0
- package/src/cli/validations/studio.ts +24 -0
- package/src/cli/views.ts +658 -0
- package/src/extensions/getTablesFilterByExtensions.ts +16 -0
- package/src/extensions/vector.ts +10 -0
- package/src/global.ts +61 -0
- package/src/index.ts +326 -0
- package/src/introspect-mysql.ts +1030 -0
- package/src/introspect-pg.ts +1435 -0
- package/src/introspect-singlestore.ts +913 -0
- package/src/introspect-sqlite.ts +533 -0
- package/src/jsonDiffer.js +882 -0
- package/src/jsonStatements.ts +3590 -0
- package/src/loader.mjs +57 -0
- package/src/migrationPreparator.ts +217 -0
- package/src/schemaValidator.ts +23 -0
- package/src/serializer/index.ts +142 -0
- package/src/serializer/mysqlImports.ts +38 -0
- package/src/serializer/mysqlSchema.ts +423 -0
- package/src/serializer/mysqlSerializer.ts +999 -0
- package/src/serializer/pgImports.ts +106 -0
- package/src/serializer/pgSchema.ts +937 -0
- package/src/serializer/pgSerializer.ts +2223 -0
- package/src/serializer/singlestoreImports.ts +38 -0
- package/src/serializer/singlestoreSchema.ts +257 -0
- package/src/serializer/singlestoreSerializer.ts +767 -0
- package/src/serializer/sqliteImports.ts +41 -0
- package/src/serializer/sqliteSchema.ts +352 -0
- package/src/serializer/sqliteSerializer.ts +931 -0
- package/src/serializer/studio.ts +694 -0
- package/src/serializer/utils.ts +45 -0
- package/src/simulator.ts +157 -0
- package/src/snapshotsDiffer.ts +4398 -0
- package/src/sqlgenerator.ts +4212 -0
- package/src/statementCombiner.ts +597 -0
- package/src/utils/certs.ts +44 -0
- package/src/utils/words.ts +1333 -0
- package/src/utils.ts +370 -0
- package/tests/bin.test.ts +58 -0
- package/tests/cli/d1http.config.ts +12 -0
- package/tests/cli/drizzle.config.ts +9 -0
- package/tests/cli/durable-sqlite.config.ts +7 -0
- package/tests/cli/expo.config.ts +7 -0
- package/tests/cli/postgres.config.ts +13 -0
- package/tests/cli/postgres2.config.ts +17 -0
- package/tests/cli/schema.ts +1 -0
- package/tests/cli/turso.config.ts +10 -0
- package/tests/cli-export.test.ts +79 -0
- package/tests/cli-generate.test.ts +259 -0
- package/tests/cli-migrate.test.ts +103 -0
- package/tests/cli-push.test.ts +126 -0
- package/tests/common.ts +15 -0
- package/tests/indexes/common.ts +21 -0
- package/tests/indexes/pg.test.ts +245 -0
- package/tests/introspect/libsql.test.ts +35 -0
- package/tests/introspect/mysql.test.ts +319 -0
- package/tests/introspect/pg.test.ts +894 -0
- package/tests/introspect/singlestore.test.ts +275 -0
- package/tests/introspect/sqlite.test.ts +122 -0
- package/tests/libsql-checks.test.ts +308 -0
- package/tests/libsql-statements.test.ts +989 -0
- package/tests/libsql-views.test.ts +218 -0
- package/tests/migrate/libsq-schema.ts +6 -0
- package/tests/migrate/libsql-migrate.test.ts +58 -0
- package/tests/migrate/migrations/0000_little_blizzard.sql +4 -0
- package/tests/migrate/migrations/0001_nebulous_storm.sql +10 -0
- package/tests/migrate/migrations/meta/0000_snapshot.json +40 -0
- package/tests/migrate/migrations/meta/0001_snapshot.json +40 -0
- package/tests/migrate/migrations/meta/_journal.json +20 -0
- package/tests/mysql-checks.test.ts +291 -0
- package/tests/mysql-generated.test.ts +1290 -0
- package/tests/mysql-schemas.test.ts +156 -0
- package/tests/mysql-views.test.ts +553 -0
- package/tests/mysql.test.ts +863 -0
- package/tests/pg-array.test.ts +368 -0
- package/tests/pg-checks.test.ts +329 -0
- package/tests/pg-columns.test.ts +484 -0
- package/tests/pg-domains.test.ts +306 -0
- package/tests/pg-enums.test.ts +751 -0
- package/tests/pg-generated.test.ts +529 -0
- package/tests/pg-identity.test.ts +447 -0
- package/tests/pg-schemas.test.ts +105 -0
- package/tests/pg-sequences.test.ts +298 -0
- package/tests/pg-tables.test.ts +1021 -0
- package/tests/pg-views.test.ts +1929 -0
- package/tests/push/common.ts +58 -0
- package/tests/push/libsql.test.ts +1400 -0
- package/tests/push/mysql-push.test.ts +345 -0
- package/tests/push/mysql.test.ts +788 -0
- package/tests/push/pg.test.ts +4341 -0
- package/tests/push/singlestore-push.test.ts +894 -0
- package/tests/push/singlestore.test.ts +444 -0
- package/tests/push/sqlite.test.ts +1613 -0
- package/tests/rls/pg-policy.test.ts +1656 -0
- package/tests/rls/pg-role.test.ts +234 -0
- package/tests/schemaDiffer.ts +2852 -0
- package/tests/singlestore-generated.test.ts +1290 -0
- package/tests/singlestore-schemas.test.ts +155 -0
- package/tests/singlestore.test.ts +978 -0
- package/tests/sqlite-checks.test.ts +308 -0
- package/tests/sqlite-columns.test.ts +1049 -0
- package/tests/sqlite-generated.test.ts +1726 -0
- package/tests/sqlite-tables.test.ts +637 -0
- package/tests/sqlite-views.test.ts +218 -0
- package/tests/statements-combiner/libsql-statements-combiner.test.ts +1812 -0
- package/tests/statements-combiner/singlestore-statements-combiner.test.ts +882 -0
- package/tests/statements-combiner/sqlite-statements-combiner.test.ts +1211 -0
- package/tests/test/sqlite.test.ts +39 -0
- package/tests/testsinglestore.ts +29 -0
- package/tests/validations.test.ts +869 -0
- package/tests/wrap-param.test.ts +16 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.cli-types.json +9 -0
- package/tsconfig.json +28 -0
- package/vitest.config.ts +34 -0
|
@@ -0,0 +1,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
|
+
};
|