@prisma/adapter-d1 6.11.0-dev.38 → 6.11.0-dev.4
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/dist/index.d.mts +16 -8
- package/dist/index.d.ts +16 -8
- package/dist/index.js +167 -190
- package/dist/index.mjs +165 -189
- package/package.json +3 -7
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { D1Database as D1Database_2 } from '@cloudflare/workers-types';
|
|
1
|
+
import type { D1Database as D1Database_2 } from '@cloudflare/workers-types';
|
|
2
2
|
import { SqlDriverAdapter } from '@prisma/driver-adapter-utils';
|
|
3
3
|
import { SqlDriverAdapterFactory } from '@prisma/driver-adapter-utils';
|
|
4
|
+
import { SqlMigrationAwareDriverAdapterFactory } from '@prisma/driver-adapter-utils';
|
|
4
5
|
|
|
5
6
|
declare type D1HTTPParams = {
|
|
6
7
|
CLOUDFLARE_D1_TOKEN: string;
|
|
@@ -9,16 +10,23 @@ declare type D1HTTPParams = {
|
|
|
9
10
|
CLOUDFLARE_SHADOW_DATABASE_ID?: string;
|
|
10
11
|
};
|
|
11
12
|
|
|
12
|
-
export declare class PrismaD1
|
|
13
|
+
export declare class PrismaD1 implements SqlDriverAdapterFactory {
|
|
14
|
+
private client;
|
|
13
15
|
readonly provider = "sqlite";
|
|
14
16
|
readonly adapterName: string;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
constructor(params: Args);
|
|
17
|
+
constructor(client: StdClient);
|
|
18
|
+
connect(): Promise<SqlDriverAdapter>;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
declare
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
export declare class PrismaD1HTTP implements SqlMigrationAwareDriverAdapterFactory {
|
|
22
|
+
private params;
|
|
23
|
+
readonly provider = "sqlite";
|
|
24
|
+
readonly adapterName: string;
|
|
25
|
+
constructor(params: D1HTTPParams);
|
|
26
|
+
connect(): Promise<SqlDriverAdapter>;
|
|
27
|
+
connectToShadowDb(): Promise<SqlDriverAdapter>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare type StdClient = D1Database_2;
|
|
23
31
|
|
|
24
32
|
export { }
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { D1Database as D1Database_2 } from '@cloudflare/workers-types';
|
|
1
|
+
import type { D1Database as D1Database_2 } from '@cloudflare/workers-types';
|
|
2
2
|
import { SqlDriverAdapter } from '@prisma/driver-adapter-utils';
|
|
3
3
|
import { SqlDriverAdapterFactory } from '@prisma/driver-adapter-utils';
|
|
4
|
+
import { SqlMigrationAwareDriverAdapterFactory } from '@prisma/driver-adapter-utils';
|
|
4
5
|
|
|
5
6
|
declare type D1HTTPParams = {
|
|
6
7
|
CLOUDFLARE_D1_TOKEN: string;
|
|
@@ -9,16 +10,23 @@ declare type D1HTTPParams = {
|
|
|
9
10
|
CLOUDFLARE_SHADOW_DATABASE_ID?: string;
|
|
10
11
|
};
|
|
11
12
|
|
|
12
|
-
export declare class PrismaD1
|
|
13
|
+
export declare class PrismaD1 implements SqlDriverAdapterFactory {
|
|
14
|
+
private client;
|
|
13
15
|
readonly provider = "sqlite";
|
|
14
16
|
readonly adapterName: string;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
constructor(params: Args);
|
|
17
|
+
constructor(client: StdClient);
|
|
18
|
+
connect(): Promise<SqlDriverAdapter>;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
declare
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
export declare class PrismaD1HTTP implements SqlMigrationAwareDriverAdapterFactory {
|
|
22
|
+
private params;
|
|
23
|
+
readonly provider = "sqlite";
|
|
24
|
+
readonly adapterName: string;
|
|
25
|
+
constructor(params: D1HTTPParams);
|
|
26
|
+
connect(): Promise<SqlDriverAdapter>;
|
|
27
|
+
connectToShadowDb(): Promise<SqlDriverAdapter>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
declare type StdClient = D1Database_2;
|
|
23
31
|
|
|
24
32
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -30,14 +30,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
-
PrismaD1: () =>
|
|
33
|
+
PrismaD1: () => PrismaD1AdapterFactory,
|
|
34
|
+
PrismaD1HTTP: () => PrismaD1HTTPAdapterFactory
|
|
34
35
|
});
|
|
35
36
|
module.exports = __toCommonJS(index_exports);
|
|
36
37
|
|
|
37
|
-
//
|
|
38
|
-
var name = "@prisma/adapter-d1";
|
|
39
|
-
|
|
40
|
-
// src/d1-http.ts
|
|
38
|
+
// src/d1.ts
|
|
41
39
|
var import_driver_adapter_utils2 = require("@prisma/driver-adapter-utils");
|
|
42
40
|
|
|
43
41
|
// ../../node_modules/.pnpm/kleur@4.1.5/node_modules/kleur/colors.mjs
|
|
@@ -88,8 +86,8 @@ var bgMagenta = init(45, 49);
|
|
|
88
86
|
var bgCyan = init(46, 49);
|
|
89
87
|
var bgWhite = init(47, 49);
|
|
90
88
|
|
|
91
|
-
//
|
|
92
|
-
var
|
|
89
|
+
// package.json
|
|
90
|
+
var name = "@prisma/adapter-d1";
|
|
93
91
|
|
|
94
92
|
// src/constants.ts
|
|
95
93
|
var MAX_BIND_VALUES = 98;
|
|
@@ -265,48 +263,14 @@ function cleanArg(arg, argType) {
|
|
|
265
263
|
return arg;
|
|
266
264
|
}
|
|
267
265
|
|
|
268
|
-
// src/d1
|
|
269
|
-
var debug = (0, import_driver_adapter_utils2.Debug)("prisma:driver-adapter:d1
|
|
270
|
-
|
|
271
|
-
debug("D1 HTTP Errors: %O", errors);
|
|
272
|
-
const error = errors.at(0) ?? { message: "Unknown error", code: GENERIC_SQLITE_ERROR };
|
|
273
|
-
throw new import_driver_adapter_utils2.DriverAdapterError(convertDriverError(error));
|
|
274
|
-
}
|
|
275
|
-
function onGenericD1HTTPError(error) {
|
|
276
|
-
debug("HTTP Error: %O", error);
|
|
277
|
-
throw new import_driver_adapter_utils2.DriverAdapterError(convertDriverError(error));
|
|
278
|
-
}
|
|
279
|
-
function onError(error) {
|
|
280
|
-
console.error("Error in performIO: %O", error);
|
|
281
|
-
throw new import_driver_adapter_utils2.DriverAdapterError(convertDriverError(error));
|
|
282
|
-
}
|
|
283
|
-
async function performRawQuery(client, options) {
|
|
284
|
-
try {
|
|
285
|
-
const response = await client.post("raw", options).json();
|
|
286
|
-
const tag = "[js::performRawQuery]";
|
|
287
|
-
debug(`${tag} %O`, {
|
|
288
|
-
success: response.success,
|
|
289
|
-
errors: response.errors,
|
|
290
|
-
messages: response.messages,
|
|
291
|
-
result: response.result
|
|
292
|
-
});
|
|
293
|
-
if (!response.success) {
|
|
294
|
-
onUnsuccessfulD1HTTPResponse(response);
|
|
295
|
-
}
|
|
296
|
-
return response.result;
|
|
297
|
-
} catch (e) {
|
|
298
|
-
onGenericD1HTTPError(e);
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
function isD1HTTPParams(params) {
|
|
302
|
-
return typeof params === "object" && params !== null && "CLOUDFLARE_D1_TOKEN" in params && "CLOUDFLARE_ACCOUNT_ID" in params && "CLOUDFLARE_DATABASE_ID" in params;
|
|
303
|
-
}
|
|
304
|
-
var D1HTTPQueryable = class {
|
|
266
|
+
// src/d1.ts
|
|
267
|
+
var debug = (0, import_driver_adapter_utils2.Debug)("prisma:driver-adapter:d1");
|
|
268
|
+
var D1Queryable = class {
|
|
305
269
|
constructor(client) {
|
|
306
270
|
this.client = client;
|
|
307
271
|
}
|
|
308
272
|
provider = "sqlite";
|
|
309
|
-
adapterName =
|
|
273
|
+
adapterName = name;
|
|
310
274
|
/**
|
|
311
275
|
* Execute a query given as SQL, interpolating the given parameters.
|
|
312
276
|
*/
|
|
@@ -317,7 +281,9 @@ var D1HTTPQueryable = class {
|
|
|
317
281
|
const convertedData = this.convertData(data);
|
|
318
282
|
return convertedData;
|
|
319
283
|
}
|
|
320
|
-
convertData(
|
|
284
|
+
convertData(ioResult) {
|
|
285
|
+
const columnNames = ioResult[0];
|
|
286
|
+
const results = ioResult[1];
|
|
321
287
|
if (results.length === 0) {
|
|
322
288
|
return {
|
|
323
289
|
columnNames: [],
|
|
@@ -325,10 +291,14 @@ var D1HTTPQueryable = class {
|
|
|
325
291
|
rows: []
|
|
326
292
|
};
|
|
327
293
|
}
|
|
328
|
-
const columnTypes = getColumnTypes(columnNames, results);
|
|
294
|
+
const columnTypes = Object.values(getColumnTypes(columnNames, results));
|
|
329
295
|
const rows = results.map((value) => mapRow(value, columnTypes));
|
|
330
296
|
return {
|
|
331
297
|
columnNames,
|
|
298
|
+
// * Note: without Object.values the array looks like
|
|
299
|
+
// * columnTypes: [ id: 128 ],
|
|
300
|
+
// * and errors with:
|
|
301
|
+
// * ✘ [ERROR] A hanging Promise was canceled. This happens when the worker runtime is waiting for a Promise from JavaScript to resolve, but has detected that the Promise cannot possibly ever resolve because all code and events related to the Promise's I/O context have already finished.
|
|
332
302
|
columnTypes,
|
|
333
303
|
rows
|
|
334
304
|
};
|
|
@@ -341,34 +311,25 @@ var D1HTTPQueryable = class {
|
|
|
341
311
|
async executeRaw(query) {
|
|
342
312
|
const tag = "[js::execute_raw]";
|
|
343
313
|
debug(`${tag} %O`, query);
|
|
344
|
-
const result = await this.performIO(query);
|
|
345
|
-
return result.
|
|
314
|
+
const result = await this.performIO(query, true);
|
|
315
|
+
return result.meta.changes ?? 0;
|
|
346
316
|
}
|
|
347
|
-
async performIO(query) {
|
|
317
|
+
async performIO(query, executeRaw = false) {
|
|
348
318
|
try {
|
|
349
319
|
query.args = query.args.map((arg, i) => cleanArg(arg, query.argTypes[i]));
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
const tag = "[js::perform_io]";
|
|
357
|
-
debug(`${tag} %O`, body);
|
|
358
|
-
const results = await performRawQuery(this.client, body);
|
|
359
|
-
if (results.length !== 1) {
|
|
360
|
-
throw new Error("Expected exactly one result");
|
|
320
|
+
const stmt = this.client.prepare(query.sql).bind(...query.args);
|
|
321
|
+
if (executeRaw) {
|
|
322
|
+
return await stmt.run();
|
|
323
|
+
} else {
|
|
324
|
+
const [columnNames, ...rows] = await stmt.raw({ columnNames: true });
|
|
325
|
+
return [columnNames, rows];
|
|
361
326
|
}
|
|
362
|
-
const result = results[0];
|
|
363
|
-
const { columns: columnNames = [], rows = [] } = result.results ?? {};
|
|
364
|
-
const affectedRows = result.meta?.changes;
|
|
365
|
-
return { rows, columnNames, affectedRows };
|
|
366
327
|
} catch (e) {
|
|
367
328
|
onError(e);
|
|
368
329
|
}
|
|
369
330
|
}
|
|
370
331
|
};
|
|
371
|
-
var
|
|
332
|
+
var D1Transaction = class extends D1Queryable {
|
|
372
333
|
constructor(client, options) {
|
|
373
334
|
super(client);
|
|
374
335
|
this.options = options;
|
|
@@ -380,17 +341,8 @@ var D1HTTPTransaction = class extends D1HTTPQueryable {
|
|
|
380
341
|
debug(`[js::rollback]`);
|
|
381
342
|
}
|
|
382
343
|
};
|
|
383
|
-
var
|
|
384
|
-
constructor(
|
|
385
|
-
const D1_API_BASE_URL = `https://api.cloudflare.com/client/v4/accounts/${params.CLOUDFLARE_ACCOUNT_ID}/d1/database/${params.CLOUDFLARE_DATABASE_ID}`;
|
|
386
|
-
const client = import_ky.default.create({
|
|
387
|
-
prefixUrl: D1_API_BASE_URL,
|
|
388
|
-
headers: {
|
|
389
|
-
Authorization: `Bearer ${params.CLOUDFLARE_D1_TOKEN}`
|
|
390
|
-
},
|
|
391
|
-
// Don't automatically throw on non-2xx status codes
|
|
392
|
-
throwHttpErrors: false
|
|
393
|
-
});
|
|
344
|
+
var PrismaD1Adapter = class extends D1Queryable {
|
|
345
|
+
constructor(client, release) {
|
|
394
346
|
super(client);
|
|
395
347
|
this.release = release;
|
|
396
348
|
}
|
|
@@ -419,11 +371,7 @@ var PrismaD1HTTPAdapter = class extends D1HTTPQueryable {
|
|
|
419
371
|
};
|
|
420
372
|
async executeScript(script) {
|
|
421
373
|
try {
|
|
422
|
-
await
|
|
423
|
-
json: {
|
|
424
|
-
sql: script
|
|
425
|
-
}
|
|
426
|
-
});
|
|
374
|
+
await this.client.exec(script);
|
|
427
375
|
} catch (error) {
|
|
428
376
|
onError(error);
|
|
429
377
|
}
|
|
@@ -450,80 +398,69 @@ var PrismaD1HTTPAdapter = class extends D1HTTPQueryable {
|
|
|
450
398
|
};
|
|
451
399
|
const tag = "[js::startTransaction]";
|
|
452
400
|
debug("%s options: %O", tag, options);
|
|
453
|
-
return new
|
|
401
|
+
return new D1Transaction(this.client, options);
|
|
454
402
|
}
|
|
455
403
|
async dispose() {
|
|
456
404
|
await this.release?.();
|
|
457
405
|
}
|
|
458
406
|
};
|
|
459
|
-
var
|
|
460
|
-
constructor(
|
|
461
|
-
this.
|
|
407
|
+
var PrismaD1AdapterFactory = class {
|
|
408
|
+
constructor(client) {
|
|
409
|
+
this.client = client;
|
|
462
410
|
}
|
|
463
411
|
provider = "sqlite";
|
|
464
|
-
adapterName =
|
|
412
|
+
adapterName = name;
|
|
465
413
|
async connect() {
|
|
466
|
-
return new
|
|
414
|
+
return new PrismaD1Adapter(this.client, async () => {
|
|
467
415
|
});
|
|
468
416
|
}
|
|
469
|
-
async connectToShadowDb() {
|
|
470
|
-
const D1_API_BASE_URL = `https://api.cloudflare.com/client/v4/accounts/${this.params.CLOUDFLARE_ACCOUNT_ID}/d1/database`;
|
|
471
|
-
const client = import_ky.default.create({
|
|
472
|
-
headers: {
|
|
473
|
-
Authorization: `Bearer ${this.params.CLOUDFLARE_D1_TOKEN}`
|
|
474
|
-
},
|
|
475
|
-
// Don't throw on non-2xx status codes
|
|
476
|
-
throwHttpErrors: false
|
|
477
|
-
});
|
|
478
|
-
const createShadowDatabase = async () => {
|
|
479
|
-
const tag = "[js::connectToShadowDb::createShadowDatabase]";
|
|
480
|
-
const SHADOW_DATABASE_PREFIX = "_prisma_shadow_";
|
|
481
|
-
const CLOUDFLARE_SHADOW_DATABASE_NAME = `${SHADOW_DATABASE_PREFIX}${globalThis.crypto.randomUUID()}`;
|
|
482
|
-
debug(`${tag} creating database %s`, CLOUDFLARE_SHADOW_DATABASE_NAME);
|
|
483
|
-
try {
|
|
484
|
-
const response = await client.post(D1_API_BASE_URL, {
|
|
485
|
-
json: {
|
|
486
|
-
name: CLOUDFLARE_SHADOW_DATABASE_NAME
|
|
487
|
-
}
|
|
488
|
-
}).json();
|
|
489
|
-
debug(`${tag} %O`, response);
|
|
490
|
-
if (!response.success) {
|
|
491
|
-
onUnsuccessfulD1HTTPResponse(response);
|
|
492
|
-
}
|
|
493
|
-
const { uuid: CLOUDFLARE_SHADOW_DATABASE_ID2 } = response.result;
|
|
494
|
-
debug(`${tag} created database %s with ID %s`, CLOUDFLARE_SHADOW_DATABASE_NAME, CLOUDFLARE_SHADOW_DATABASE_ID2);
|
|
495
|
-
return CLOUDFLARE_SHADOW_DATABASE_ID2;
|
|
496
|
-
} catch (e) {
|
|
497
|
-
onGenericD1HTTPError(e);
|
|
498
|
-
}
|
|
499
|
-
};
|
|
500
|
-
const CLOUDFLARE_SHADOW_DATABASE_ID = this.params.CLOUDFLARE_SHADOW_DATABASE_ID ?? await createShadowDatabase();
|
|
501
|
-
const dispose = async () => {
|
|
502
|
-
const tag = "[js::connectToShadowDb::dispose]";
|
|
503
|
-
try {
|
|
504
|
-
debug(`${tag} deleting database %s`, CLOUDFLARE_SHADOW_DATABASE_ID);
|
|
505
|
-
const response = await client.delete(`${D1_API_BASE_URL}/${CLOUDFLARE_SHADOW_DATABASE_ID}`).json();
|
|
506
|
-
debug(`${tag} %O`, response);
|
|
507
|
-
if (!response.success) {
|
|
508
|
-
onUnsuccessfulD1HTTPResponse(response);
|
|
509
|
-
}
|
|
510
|
-
} catch (e) {
|
|
511
|
-
onGenericD1HTTPError(e);
|
|
512
|
-
}
|
|
513
|
-
};
|
|
514
|
-
return new PrismaD1HTTPAdapter(this.params, dispose);
|
|
515
|
-
}
|
|
516
417
|
};
|
|
418
|
+
function onError(error) {
|
|
419
|
+
console.error("Error in performIO: %O", error);
|
|
420
|
+
throw new import_driver_adapter_utils2.DriverAdapterError(convertDriverError(error));
|
|
421
|
+
}
|
|
517
422
|
|
|
518
|
-
// src/d1-
|
|
423
|
+
// src/d1-http.ts
|
|
519
424
|
var import_driver_adapter_utils3 = require("@prisma/driver-adapter-utils");
|
|
520
|
-
var
|
|
521
|
-
var
|
|
425
|
+
var import_ky = __toESM(require("ky"));
|
|
426
|
+
var debug2 = (0, import_driver_adapter_utils3.Debug)("prisma:driver-adapter:d1-http");
|
|
427
|
+
function onUnsuccessfulD1HTTPResponse({ errors }) {
|
|
428
|
+
debug2("D1 HTTP Errors: %O", errors);
|
|
429
|
+
const error = errors.at(0) ?? { message: "Unknown error", code: GENERIC_SQLITE_ERROR };
|
|
430
|
+
throw new import_driver_adapter_utils3.DriverAdapterError(convertDriverError(error));
|
|
431
|
+
}
|
|
432
|
+
function onGenericD1HTTPError(error) {
|
|
433
|
+
debug2("HTTP Error: %O", error);
|
|
434
|
+
throw new import_driver_adapter_utils3.DriverAdapterError(convertDriverError(error));
|
|
435
|
+
}
|
|
436
|
+
function onError2(error) {
|
|
437
|
+
console.error("Error in performIO: %O", error);
|
|
438
|
+
throw new import_driver_adapter_utils3.DriverAdapterError(convertDriverError(error));
|
|
439
|
+
}
|
|
440
|
+
async function performRawQuery(client, options) {
|
|
441
|
+
try {
|
|
442
|
+
const response = await client.post("raw", options).json();
|
|
443
|
+
const tag = "[js::performRawQuery]";
|
|
444
|
+
debug2(`${tag} %O`, {
|
|
445
|
+
success: response.success,
|
|
446
|
+
errors: response.errors,
|
|
447
|
+
messages: response.messages,
|
|
448
|
+
result: response.result
|
|
449
|
+
});
|
|
450
|
+
if (!response.success) {
|
|
451
|
+
onUnsuccessfulD1HTTPResponse(response);
|
|
452
|
+
}
|
|
453
|
+
return response.result;
|
|
454
|
+
} catch (e) {
|
|
455
|
+
onGenericD1HTTPError(e);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
var D1HTTPQueryable = class {
|
|
522
459
|
constructor(client) {
|
|
523
460
|
this.client = client;
|
|
524
461
|
}
|
|
525
462
|
provider = "sqlite";
|
|
526
|
-
adapterName = name
|
|
463
|
+
adapterName = `${name}-http`;
|
|
527
464
|
/**
|
|
528
465
|
* Execute a query given as SQL, interpolating the given parameters.
|
|
529
466
|
*/
|
|
@@ -534,9 +471,7 @@ var D1WorkerQueryable = class {
|
|
|
534
471
|
const convertedData = this.convertData(data);
|
|
535
472
|
return convertedData;
|
|
536
473
|
}
|
|
537
|
-
convertData(
|
|
538
|
-
const columnNames = ioResult[0];
|
|
539
|
-
const results = ioResult[1];
|
|
474
|
+
convertData({ columnNames, rows: results }) {
|
|
540
475
|
if (results.length === 0) {
|
|
541
476
|
return {
|
|
542
477
|
columnNames: [],
|
|
@@ -544,14 +479,10 @@ var D1WorkerQueryable = class {
|
|
|
544
479
|
rows: []
|
|
545
480
|
};
|
|
546
481
|
}
|
|
547
|
-
const columnTypes =
|
|
482
|
+
const columnTypes = getColumnTypes(columnNames, results);
|
|
548
483
|
const rows = results.map((value) => mapRow(value, columnTypes));
|
|
549
484
|
return {
|
|
550
485
|
columnNames,
|
|
551
|
-
// * Note: without Object.values the array looks like
|
|
552
|
-
// * columnTypes: [ id: 128 ],
|
|
553
|
-
// * and errors with:
|
|
554
|
-
// * ✘ [ERROR] A hanging Promise was canceled. This happens when the worker runtime is waiting for a Promise from JavaScript to resolve, but has detected that the Promise cannot possibly ever resolve because all code and events related to the Promise's I/O context have already finished.
|
|
555
486
|
columnTypes,
|
|
556
487
|
rows
|
|
557
488
|
};
|
|
@@ -564,25 +495,34 @@ var D1WorkerQueryable = class {
|
|
|
564
495
|
async executeRaw(query) {
|
|
565
496
|
const tag = "[js::execute_raw]";
|
|
566
497
|
debug2(`${tag} %O`, query);
|
|
567
|
-
const result = await this.performIO(query
|
|
568
|
-
return result.
|
|
498
|
+
const result = await this.performIO(query);
|
|
499
|
+
return result.affectedRows ?? 0;
|
|
569
500
|
}
|
|
570
|
-
async performIO(query
|
|
501
|
+
async performIO(query) {
|
|
571
502
|
try {
|
|
572
503
|
query.args = query.args.map((arg, i) => cleanArg(arg, query.argTypes[i]));
|
|
573
|
-
const
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
504
|
+
const body = {
|
|
505
|
+
json: {
|
|
506
|
+
sql: query.sql,
|
|
507
|
+
params: query.args
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
const tag = "[js::perform_io]";
|
|
511
|
+
debug2(`${tag} %O`, body);
|
|
512
|
+
const results = await performRawQuery(this.client, body);
|
|
513
|
+
if (results.length !== 1) {
|
|
514
|
+
throw new Error("Expected exactly one result");
|
|
579
515
|
}
|
|
516
|
+
const result = results[0];
|
|
517
|
+
const { columns: columnNames = [], rows = [] } = result.results ?? {};
|
|
518
|
+
const affectedRows = result.meta?.changes;
|
|
519
|
+
return { rows, columnNames, affectedRows };
|
|
580
520
|
} catch (e) {
|
|
581
521
|
onError2(e);
|
|
582
522
|
}
|
|
583
523
|
}
|
|
584
524
|
};
|
|
585
|
-
var
|
|
525
|
+
var D1HTTPTransaction = class extends D1HTTPQueryable {
|
|
586
526
|
constructor(client, options) {
|
|
587
527
|
super(client);
|
|
588
528
|
this.options = options;
|
|
@@ -594,8 +534,17 @@ var D1WorkerTransaction = class extends D1WorkerQueryable {
|
|
|
594
534
|
debug2(`[js::rollback]`);
|
|
595
535
|
}
|
|
596
536
|
};
|
|
597
|
-
var
|
|
598
|
-
constructor(
|
|
537
|
+
var PrismaD1HTTPAdapter = class extends D1HTTPQueryable {
|
|
538
|
+
constructor(params, release) {
|
|
539
|
+
const D1_API_BASE_URL = `https://api.cloudflare.com/client/v4/accounts/${params.CLOUDFLARE_ACCOUNT_ID}/d1/database/${params.CLOUDFLARE_DATABASE_ID}`;
|
|
540
|
+
const client = import_ky.default.create({
|
|
541
|
+
prefixUrl: D1_API_BASE_URL,
|
|
542
|
+
headers: {
|
|
543
|
+
Authorization: `Bearer ${params.CLOUDFLARE_D1_TOKEN}`
|
|
544
|
+
},
|
|
545
|
+
// Don't automatically throw on non-2xx status codes
|
|
546
|
+
throwHttpErrors: false
|
|
547
|
+
});
|
|
599
548
|
super(client);
|
|
600
549
|
this.release = release;
|
|
601
550
|
}
|
|
@@ -624,7 +573,11 @@ var PrismaD1WorkerAdapter = class extends D1WorkerQueryable {
|
|
|
624
573
|
};
|
|
625
574
|
async executeScript(script) {
|
|
626
575
|
try {
|
|
627
|
-
await this.client
|
|
576
|
+
await performRawQuery(this.client, {
|
|
577
|
+
json: {
|
|
578
|
+
sql: script
|
|
579
|
+
}
|
|
580
|
+
});
|
|
628
581
|
} catch (error) {
|
|
629
582
|
onError2(error);
|
|
630
583
|
}
|
|
@@ -651,48 +604,72 @@ var PrismaD1WorkerAdapter = class extends D1WorkerQueryable {
|
|
|
651
604
|
};
|
|
652
605
|
const tag = "[js::startTransaction]";
|
|
653
606
|
debug2("%s options: %O", tag, options);
|
|
654
|
-
return new
|
|
607
|
+
return new D1HTTPTransaction(this.client, options);
|
|
655
608
|
}
|
|
656
609
|
async dispose() {
|
|
657
610
|
await this.release?.();
|
|
658
611
|
}
|
|
659
612
|
};
|
|
660
|
-
var
|
|
661
|
-
constructor(
|
|
662
|
-
this.
|
|
613
|
+
var PrismaD1HTTPAdapterFactory = class {
|
|
614
|
+
constructor(params) {
|
|
615
|
+
this.params = params;
|
|
663
616
|
}
|
|
664
617
|
provider = "sqlite";
|
|
665
|
-
adapterName = name
|
|
618
|
+
adapterName = `${name}-http`;
|
|
666
619
|
async connect() {
|
|
667
|
-
return new
|
|
620
|
+
return new PrismaD1HTTPAdapter(this.params, async () => {
|
|
668
621
|
});
|
|
669
622
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
//
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
623
|
+
async connectToShadowDb() {
|
|
624
|
+
const D1_API_BASE_URL = `https://api.cloudflare.com/client/v4/accounts/${this.params.CLOUDFLARE_ACCOUNT_ID}/d1/database`;
|
|
625
|
+
const client = import_ky.default.create({
|
|
626
|
+
headers: {
|
|
627
|
+
Authorization: `Bearer ${this.params.CLOUDFLARE_D1_TOKEN}`
|
|
628
|
+
},
|
|
629
|
+
// Don't throw on non-2xx status codes
|
|
630
|
+
throwHttpErrors: false
|
|
631
|
+
});
|
|
632
|
+
const createShadowDatabase = async () => {
|
|
633
|
+
const tag = "[js::connectToShadowDb::createShadowDatabase]";
|
|
634
|
+
const SHADOW_DATABASE_PREFIX = "_prisma_shadow_";
|
|
635
|
+
const CLOUDFLARE_SHADOW_DATABASE_NAME = `${SHADOW_DATABASE_PREFIX}${globalThis.crypto.randomUUID()}`;
|
|
636
|
+
debug2(`${tag} creating database %s`, CLOUDFLARE_SHADOW_DATABASE_NAME);
|
|
637
|
+
try {
|
|
638
|
+
const response = await client.post(D1_API_BASE_URL, {
|
|
639
|
+
json: {
|
|
640
|
+
name: CLOUDFLARE_SHADOW_DATABASE_NAME
|
|
641
|
+
}
|
|
642
|
+
}).json();
|
|
643
|
+
debug2(`${tag} %O`, response);
|
|
644
|
+
if (!response.success) {
|
|
645
|
+
onUnsuccessfulD1HTTPResponse(response);
|
|
646
|
+
}
|
|
647
|
+
const { uuid: CLOUDFLARE_SHADOW_DATABASE_ID2 } = response.result;
|
|
648
|
+
debug2(`${tag} created database %s with ID %s`, CLOUDFLARE_SHADOW_DATABASE_NAME, CLOUDFLARE_SHADOW_DATABASE_ID2);
|
|
649
|
+
return CLOUDFLARE_SHADOW_DATABASE_ID2;
|
|
650
|
+
} catch (e) {
|
|
651
|
+
onGenericD1HTTPError(e);
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
const CLOUDFLARE_SHADOW_DATABASE_ID = this.params.CLOUDFLARE_SHADOW_DATABASE_ID ?? await createShadowDatabase();
|
|
655
|
+
const dispose = async () => {
|
|
656
|
+
const tag = "[js::connectToShadowDb::dispose]";
|
|
657
|
+
try {
|
|
658
|
+
debug2(`${tag} deleting database %s`, CLOUDFLARE_SHADOW_DATABASE_ID);
|
|
659
|
+
const response = await client.delete(`${D1_API_BASE_URL}/${CLOUDFLARE_SHADOW_DATABASE_ID}`).json();
|
|
660
|
+
debug2(`${tag} %O`, response);
|
|
661
|
+
if (!response.success) {
|
|
662
|
+
onUnsuccessfulD1HTTPResponse(response);
|
|
663
|
+
}
|
|
664
|
+
} catch (e) {
|
|
665
|
+
onGenericD1HTTPError(e);
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
return new PrismaD1HTTPAdapter(this.params, dispose);
|
|
693
669
|
}
|
|
694
670
|
};
|
|
695
671
|
// Annotate the CommonJS export names for ESM import in node:
|
|
696
672
|
0 && (module.exports = {
|
|
697
|
-
PrismaD1
|
|
673
|
+
PrismaD1,
|
|
674
|
+
PrismaD1HTTP
|
|
698
675
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
//
|
|
2
|
-
var name = "@prisma/adapter-d1";
|
|
3
|
-
|
|
4
|
-
// src/d1-http.ts
|
|
1
|
+
// src/d1.ts
|
|
5
2
|
import {
|
|
6
3
|
Debug,
|
|
7
4
|
DriverAdapterError
|
|
@@ -55,8 +52,8 @@ var bgMagenta = init(45, 49);
|
|
|
55
52
|
var bgCyan = init(46, 49);
|
|
56
53
|
var bgWhite = init(47, 49);
|
|
57
54
|
|
|
58
|
-
//
|
|
59
|
-
|
|
55
|
+
// package.json
|
|
56
|
+
var name = "@prisma/adapter-d1";
|
|
60
57
|
|
|
61
58
|
// src/constants.ts
|
|
62
59
|
var MAX_BIND_VALUES = 98;
|
|
@@ -232,48 +229,14 @@ function cleanArg(arg, argType) {
|
|
|
232
229
|
return arg;
|
|
233
230
|
}
|
|
234
231
|
|
|
235
|
-
// src/d1
|
|
236
|
-
var debug = Debug("prisma:driver-adapter:d1
|
|
237
|
-
|
|
238
|
-
debug("D1 HTTP Errors: %O", errors);
|
|
239
|
-
const error = errors.at(0) ?? { message: "Unknown error", code: GENERIC_SQLITE_ERROR };
|
|
240
|
-
throw new DriverAdapterError(convertDriverError(error));
|
|
241
|
-
}
|
|
242
|
-
function onGenericD1HTTPError(error) {
|
|
243
|
-
debug("HTTP Error: %O", error);
|
|
244
|
-
throw new DriverAdapterError(convertDriverError(error));
|
|
245
|
-
}
|
|
246
|
-
function onError(error) {
|
|
247
|
-
console.error("Error in performIO: %O", error);
|
|
248
|
-
throw new DriverAdapterError(convertDriverError(error));
|
|
249
|
-
}
|
|
250
|
-
async function performRawQuery(client, options) {
|
|
251
|
-
try {
|
|
252
|
-
const response = await client.post("raw", options).json();
|
|
253
|
-
const tag = "[js::performRawQuery]";
|
|
254
|
-
debug(`${tag} %O`, {
|
|
255
|
-
success: response.success,
|
|
256
|
-
errors: response.errors,
|
|
257
|
-
messages: response.messages,
|
|
258
|
-
result: response.result
|
|
259
|
-
});
|
|
260
|
-
if (!response.success) {
|
|
261
|
-
onUnsuccessfulD1HTTPResponse(response);
|
|
262
|
-
}
|
|
263
|
-
return response.result;
|
|
264
|
-
} catch (e) {
|
|
265
|
-
onGenericD1HTTPError(e);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
function isD1HTTPParams(params) {
|
|
269
|
-
return typeof params === "object" && params !== null && "CLOUDFLARE_D1_TOKEN" in params && "CLOUDFLARE_ACCOUNT_ID" in params && "CLOUDFLARE_DATABASE_ID" in params;
|
|
270
|
-
}
|
|
271
|
-
var D1HTTPQueryable = class {
|
|
232
|
+
// src/d1.ts
|
|
233
|
+
var debug = Debug("prisma:driver-adapter:d1");
|
|
234
|
+
var D1Queryable = class {
|
|
272
235
|
constructor(client) {
|
|
273
236
|
this.client = client;
|
|
274
237
|
}
|
|
275
238
|
provider = "sqlite";
|
|
276
|
-
adapterName =
|
|
239
|
+
adapterName = name;
|
|
277
240
|
/**
|
|
278
241
|
* Execute a query given as SQL, interpolating the given parameters.
|
|
279
242
|
*/
|
|
@@ -284,7 +247,9 @@ var D1HTTPQueryable = class {
|
|
|
284
247
|
const convertedData = this.convertData(data);
|
|
285
248
|
return convertedData;
|
|
286
249
|
}
|
|
287
|
-
convertData(
|
|
250
|
+
convertData(ioResult) {
|
|
251
|
+
const columnNames = ioResult[0];
|
|
252
|
+
const results = ioResult[1];
|
|
288
253
|
if (results.length === 0) {
|
|
289
254
|
return {
|
|
290
255
|
columnNames: [],
|
|
@@ -292,10 +257,14 @@ var D1HTTPQueryable = class {
|
|
|
292
257
|
rows: []
|
|
293
258
|
};
|
|
294
259
|
}
|
|
295
|
-
const columnTypes = getColumnTypes(columnNames, results);
|
|
260
|
+
const columnTypes = Object.values(getColumnTypes(columnNames, results));
|
|
296
261
|
const rows = results.map((value) => mapRow(value, columnTypes));
|
|
297
262
|
return {
|
|
298
263
|
columnNames,
|
|
264
|
+
// * Note: without Object.values the array looks like
|
|
265
|
+
// * columnTypes: [ id: 128 ],
|
|
266
|
+
// * and errors with:
|
|
267
|
+
// * ✘ [ERROR] A hanging Promise was canceled. This happens when the worker runtime is waiting for a Promise from JavaScript to resolve, but has detected that the Promise cannot possibly ever resolve because all code and events related to the Promise's I/O context have already finished.
|
|
299
268
|
columnTypes,
|
|
300
269
|
rows
|
|
301
270
|
};
|
|
@@ -308,34 +277,25 @@ var D1HTTPQueryable = class {
|
|
|
308
277
|
async executeRaw(query) {
|
|
309
278
|
const tag = "[js::execute_raw]";
|
|
310
279
|
debug(`${tag} %O`, query);
|
|
311
|
-
const result = await this.performIO(query);
|
|
312
|
-
return result.
|
|
280
|
+
const result = await this.performIO(query, true);
|
|
281
|
+
return result.meta.changes ?? 0;
|
|
313
282
|
}
|
|
314
|
-
async performIO(query) {
|
|
283
|
+
async performIO(query, executeRaw = false) {
|
|
315
284
|
try {
|
|
316
285
|
query.args = query.args.map((arg, i) => cleanArg(arg, query.argTypes[i]));
|
|
317
|
-
const
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
const tag = "[js::perform_io]";
|
|
324
|
-
debug(`${tag} %O`, body);
|
|
325
|
-
const results = await performRawQuery(this.client, body);
|
|
326
|
-
if (results.length !== 1) {
|
|
327
|
-
throw new Error("Expected exactly one result");
|
|
286
|
+
const stmt = this.client.prepare(query.sql).bind(...query.args);
|
|
287
|
+
if (executeRaw) {
|
|
288
|
+
return await stmt.run();
|
|
289
|
+
} else {
|
|
290
|
+
const [columnNames, ...rows] = await stmt.raw({ columnNames: true });
|
|
291
|
+
return [columnNames, rows];
|
|
328
292
|
}
|
|
329
|
-
const result = results[0];
|
|
330
|
-
const { columns: columnNames = [], rows = [] } = result.results ?? {};
|
|
331
|
-
const affectedRows = result.meta?.changes;
|
|
332
|
-
return { rows, columnNames, affectedRows };
|
|
333
293
|
} catch (e) {
|
|
334
294
|
onError(e);
|
|
335
295
|
}
|
|
336
296
|
}
|
|
337
297
|
};
|
|
338
|
-
var
|
|
298
|
+
var D1Transaction = class extends D1Queryable {
|
|
339
299
|
constructor(client, options) {
|
|
340
300
|
super(client);
|
|
341
301
|
this.options = options;
|
|
@@ -347,17 +307,8 @@ var D1HTTPTransaction = class extends D1HTTPQueryable {
|
|
|
347
307
|
debug(`[js::rollback]`);
|
|
348
308
|
}
|
|
349
309
|
};
|
|
350
|
-
var
|
|
351
|
-
constructor(
|
|
352
|
-
const D1_API_BASE_URL = `https://api.cloudflare.com/client/v4/accounts/${params.CLOUDFLARE_ACCOUNT_ID}/d1/database/${params.CLOUDFLARE_DATABASE_ID}`;
|
|
353
|
-
const client = ky.create({
|
|
354
|
-
prefixUrl: D1_API_BASE_URL,
|
|
355
|
-
headers: {
|
|
356
|
-
Authorization: `Bearer ${params.CLOUDFLARE_D1_TOKEN}`
|
|
357
|
-
},
|
|
358
|
-
// Don't automatically throw on non-2xx status codes
|
|
359
|
-
throwHttpErrors: false
|
|
360
|
-
});
|
|
310
|
+
var PrismaD1Adapter = class extends D1Queryable {
|
|
311
|
+
constructor(client, release) {
|
|
361
312
|
super(client);
|
|
362
313
|
this.release = release;
|
|
363
314
|
}
|
|
@@ -386,11 +337,7 @@ var PrismaD1HTTPAdapter = class extends D1HTTPQueryable {
|
|
|
386
337
|
};
|
|
387
338
|
async executeScript(script) {
|
|
388
339
|
try {
|
|
389
|
-
await
|
|
390
|
-
json: {
|
|
391
|
-
sql: script
|
|
392
|
-
}
|
|
393
|
-
});
|
|
340
|
+
await this.client.exec(script);
|
|
394
341
|
} catch (error) {
|
|
395
342
|
onError(error);
|
|
396
343
|
}
|
|
@@ -417,83 +364,72 @@ var PrismaD1HTTPAdapter = class extends D1HTTPQueryable {
|
|
|
417
364
|
};
|
|
418
365
|
const tag = "[js::startTransaction]";
|
|
419
366
|
debug("%s options: %O", tag, options);
|
|
420
|
-
return new
|
|
367
|
+
return new D1Transaction(this.client, options);
|
|
421
368
|
}
|
|
422
369
|
async dispose() {
|
|
423
370
|
await this.release?.();
|
|
424
371
|
}
|
|
425
372
|
};
|
|
426
|
-
var
|
|
427
|
-
constructor(
|
|
428
|
-
this.
|
|
373
|
+
var PrismaD1AdapterFactory = class {
|
|
374
|
+
constructor(client) {
|
|
375
|
+
this.client = client;
|
|
429
376
|
}
|
|
430
377
|
provider = "sqlite";
|
|
431
|
-
adapterName =
|
|
378
|
+
adapterName = name;
|
|
432
379
|
async connect() {
|
|
433
|
-
return new
|
|
380
|
+
return new PrismaD1Adapter(this.client, async () => {
|
|
434
381
|
});
|
|
435
382
|
}
|
|
436
|
-
async connectToShadowDb() {
|
|
437
|
-
const D1_API_BASE_URL = `https://api.cloudflare.com/client/v4/accounts/${this.params.CLOUDFLARE_ACCOUNT_ID}/d1/database`;
|
|
438
|
-
const client = ky.create({
|
|
439
|
-
headers: {
|
|
440
|
-
Authorization: `Bearer ${this.params.CLOUDFLARE_D1_TOKEN}`
|
|
441
|
-
},
|
|
442
|
-
// Don't throw on non-2xx status codes
|
|
443
|
-
throwHttpErrors: false
|
|
444
|
-
});
|
|
445
|
-
const createShadowDatabase = async () => {
|
|
446
|
-
const tag = "[js::connectToShadowDb::createShadowDatabase]";
|
|
447
|
-
const SHADOW_DATABASE_PREFIX = "_prisma_shadow_";
|
|
448
|
-
const CLOUDFLARE_SHADOW_DATABASE_NAME = `${SHADOW_DATABASE_PREFIX}${globalThis.crypto.randomUUID()}`;
|
|
449
|
-
debug(`${tag} creating database %s`, CLOUDFLARE_SHADOW_DATABASE_NAME);
|
|
450
|
-
try {
|
|
451
|
-
const response = await client.post(D1_API_BASE_URL, {
|
|
452
|
-
json: {
|
|
453
|
-
name: CLOUDFLARE_SHADOW_DATABASE_NAME
|
|
454
|
-
}
|
|
455
|
-
}).json();
|
|
456
|
-
debug(`${tag} %O`, response);
|
|
457
|
-
if (!response.success) {
|
|
458
|
-
onUnsuccessfulD1HTTPResponse(response);
|
|
459
|
-
}
|
|
460
|
-
const { uuid: CLOUDFLARE_SHADOW_DATABASE_ID2 } = response.result;
|
|
461
|
-
debug(`${tag} created database %s with ID %s`, CLOUDFLARE_SHADOW_DATABASE_NAME, CLOUDFLARE_SHADOW_DATABASE_ID2);
|
|
462
|
-
return CLOUDFLARE_SHADOW_DATABASE_ID2;
|
|
463
|
-
} catch (e) {
|
|
464
|
-
onGenericD1HTTPError(e);
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
const CLOUDFLARE_SHADOW_DATABASE_ID = this.params.CLOUDFLARE_SHADOW_DATABASE_ID ?? await createShadowDatabase();
|
|
468
|
-
const dispose = async () => {
|
|
469
|
-
const tag = "[js::connectToShadowDb::dispose]";
|
|
470
|
-
try {
|
|
471
|
-
debug(`${tag} deleting database %s`, CLOUDFLARE_SHADOW_DATABASE_ID);
|
|
472
|
-
const response = await client.delete(`${D1_API_BASE_URL}/${CLOUDFLARE_SHADOW_DATABASE_ID}`).json();
|
|
473
|
-
debug(`${tag} %O`, response);
|
|
474
|
-
if (!response.success) {
|
|
475
|
-
onUnsuccessfulD1HTTPResponse(response);
|
|
476
|
-
}
|
|
477
|
-
} catch (e) {
|
|
478
|
-
onGenericD1HTTPError(e);
|
|
479
|
-
}
|
|
480
|
-
};
|
|
481
|
-
return new PrismaD1HTTPAdapter(this.params, dispose);
|
|
482
|
-
}
|
|
483
383
|
};
|
|
384
|
+
function onError(error) {
|
|
385
|
+
console.error("Error in performIO: %O", error);
|
|
386
|
+
throw new DriverAdapterError(convertDriverError(error));
|
|
387
|
+
}
|
|
484
388
|
|
|
485
|
-
// src/d1-
|
|
389
|
+
// src/d1-http.ts
|
|
486
390
|
import {
|
|
487
391
|
Debug as Debug2,
|
|
488
392
|
DriverAdapterError as DriverAdapterError2
|
|
489
393
|
} from "@prisma/driver-adapter-utils";
|
|
490
|
-
|
|
491
|
-
var
|
|
394
|
+
import ky from "ky";
|
|
395
|
+
var debug2 = Debug2("prisma:driver-adapter:d1-http");
|
|
396
|
+
function onUnsuccessfulD1HTTPResponse({ errors }) {
|
|
397
|
+
debug2("D1 HTTP Errors: %O", errors);
|
|
398
|
+
const error = errors.at(0) ?? { message: "Unknown error", code: GENERIC_SQLITE_ERROR };
|
|
399
|
+
throw new DriverAdapterError2(convertDriverError(error));
|
|
400
|
+
}
|
|
401
|
+
function onGenericD1HTTPError(error) {
|
|
402
|
+
debug2("HTTP Error: %O", error);
|
|
403
|
+
throw new DriverAdapterError2(convertDriverError(error));
|
|
404
|
+
}
|
|
405
|
+
function onError2(error) {
|
|
406
|
+
console.error("Error in performIO: %O", error);
|
|
407
|
+
throw new DriverAdapterError2(convertDriverError(error));
|
|
408
|
+
}
|
|
409
|
+
async function performRawQuery(client, options) {
|
|
410
|
+
try {
|
|
411
|
+
const response = await client.post("raw", options).json();
|
|
412
|
+
const tag = "[js::performRawQuery]";
|
|
413
|
+
debug2(`${tag} %O`, {
|
|
414
|
+
success: response.success,
|
|
415
|
+
errors: response.errors,
|
|
416
|
+
messages: response.messages,
|
|
417
|
+
result: response.result
|
|
418
|
+
});
|
|
419
|
+
if (!response.success) {
|
|
420
|
+
onUnsuccessfulD1HTTPResponse(response);
|
|
421
|
+
}
|
|
422
|
+
return response.result;
|
|
423
|
+
} catch (e) {
|
|
424
|
+
onGenericD1HTTPError(e);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
var D1HTTPQueryable = class {
|
|
492
428
|
constructor(client) {
|
|
493
429
|
this.client = client;
|
|
494
430
|
}
|
|
495
431
|
provider = "sqlite";
|
|
496
|
-
adapterName = name
|
|
432
|
+
adapterName = `${name}-http`;
|
|
497
433
|
/**
|
|
498
434
|
* Execute a query given as SQL, interpolating the given parameters.
|
|
499
435
|
*/
|
|
@@ -504,9 +440,7 @@ var D1WorkerQueryable = class {
|
|
|
504
440
|
const convertedData = this.convertData(data);
|
|
505
441
|
return convertedData;
|
|
506
442
|
}
|
|
507
|
-
convertData(
|
|
508
|
-
const columnNames = ioResult[0];
|
|
509
|
-
const results = ioResult[1];
|
|
443
|
+
convertData({ columnNames, rows: results }) {
|
|
510
444
|
if (results.length === 0) {
|
|
511
445
|
return {
|
|
512
446
|
columnNames: [],
|
|
@@ -514,14 +448,10 @@ var D1WorkerQueryable = class {
|
|
|
514
448
|
rows: []
|
|
515
449
|
};
|
|
516
450
|
}
|
|
517
|
-
const columnTypes =
|
|
451
|
+
const columnTypes = getColumnTypes(columnNames, results);
|
|
518
452
|
const rows = results.map((value) => mapRow(value, columnTypes));
|
|
519
453
|
return {
|
|
520
454
|
columnNames,
|
|
521
|
-
// * Note: without Object.values the array looks like
|
|
522
|
-
// * columnTypes: [ id: 128 ],
|
|
523
|
-
// * and errors with:
|
|
524
|
-
// * ✘ [ERROR] A hanging Promise was canceled. This happens when the worker runtime is waiting for a Promise from JavaScript to resolve, but has detected that the Promise cannot possibly ever resolve because all code and events related to the Promise's I/O context have already finished.
|
|
525
455
|
columnTypes,
|
|
526
456
|
rows
|
|
527
457
|
};
|
|
@@ -534,25 +464,34 @@ var D1WorkerQueryable = class {
|
|
|
534
464
|
async executeRaw(query) {
|
|
535
465
|
const tag = "[js::execute_raw]";
|
|
536
466
|
debug2(`${tag} %O`, query);
|
|
537
|
-
const result = await this.performIO(query
|
|
538
|
-
return result.
|
|
467
|
+
const result = await this.performIO(query);
|
|
468
|
+
return result.affectedRows ?? 0;
|
|
539
469
|
}
|
|
540
|
-
async performIO(query
|
|
470
|
+
async performIO(query) {
|
|
541
471
|
try {
|
|
542
472
|
query.args = query.args.map((arg, i) => cleanArg(arg, query.argTypes[i]));
|
|
543
|
-
const
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
473
|
+
const body = {
|
|
474
|
+
json: {
|
|
475
|
+
sql: query.sql,
|
|
476
|
+
params: query.args
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
const tag = "[js::perform_io]";
|
|
480
|
+
debug2(`${tag} %O`, body);
|
|
481
|
+
const results = await performRawQuery(this.client, body);
|
|
482
|
+
if (results.length !== 1) {
|
|
483
|
+
throw new Error("Expected exactly one result");
|
|
549
484
|
}
|
|
485
|
+
const result = results[0];
|
|
486
|
+
const { columns: columnNames = [], rows = [] } = result.results ?? {};
|
|
487
|
+
const affectedRows = result.meta?.changes;
|
|
488
|
+
return { rows, columnNames, affectedRows };
|
|
550
489
|
} catch (e) {
|
|
551
490
|
onError2(e);
|
|
552
491
|
}
|
|
553
492
|
}
|
|
554
493
|
};
|
|
555
|
-
var
|
|
494
|
+
var D1HTTPTransaction = class extends D1HTTPQueryable {
|
|
556
495
|
constructor(client, options) {
|
|
557
496
|
super(client);
|
|
558
497
|
this.options = options;
|
|
@@ -564,8 +503,17 @@ var D1WorkerTransaction = class extends D1WorkerQueryable {
|
|
|
564
503
|
debug2(`[js::rollback]`);
|
|
565
504
|
}
|
|
566
505
|
};
|
|
567
|
-
var
|
|
568
|
-
constructor(
|
|
506
|
+
var PrismaD1HTTPAdapter = class extends D1HTTPQueryable {
|
|
507
|
+
constructor(params, release) {
|
|
508
|
+
const D1_API_BASE_URL = `https://api.cloudflare.com/client/v4/accounts/${params.CLOUDFLARE_ACCOUNT_ID}/d1/database/${params.CLOUDFLARE_DATABASE_ID}`;
|
|
509
|
+
const client = ky.create({
|
|
510
|
+
prefixUrl: D1_API_BASE_URL,
|
|
511
|
+
headers: {
|
|
512
|
+
Authorization: `Bearer ${params.CLOUDFLARE_D1_TOKEN}`
|
|
513
|
+
},
|
|
514
|
+
// Don't automatically throw on non-2xx status codes
|
|
515
|
+
throwHttpErrors: false
|
|
516
|
+
});
|
|
569
517
|
super(client);
|
|
570
518
|
this.release = release;
|
|
571
519
|
}
|
|
@@ -594,7 +542,11 @@ var PrismaD1WorkerAdapter = class extends D1WorkerQueryable {
|
|
|
594
542
|
};
|
|
595
543
|
async executeScript(script) {
|
|
596
544
|
try {
|
|
597
|
-
await this.client
|
|
545
|
+
await performRawQuery(this.client, {
|
|
546
|
+
json: {
|
|
547
|
+
sql: script
|
|
548
|
+
}
|
|
549
|
+
});
|
|
598
550
|
} catch (error) {
|
|
599
551
|
onError2(error);
|
|
600
552
|
}
|
|
@@ -621,47 +573,71 @@ var PrismaD1WorkerAdapter = class extends D1WorkerQueryable {
|
|
|
621
573
|
};
|
|
622
574
|
const tag = "[js::startTransaction]";
|
|
623
575
|
debug2("%s options: %O", tag, options);
|
|
624
|
-
return new
|
|
576
|
+
return new D1HTTPTransaction(this.client, options);
|
|
625
577
|
}
|
|
626
578
|
async dispose() {
|
|
627
579
|
await this.release?.();
|
|
628
580
|
}
|
|
629
581
|
};
|
|
630
|
-
var
|
|
631
|
-
constructor(
|
|
632
|
-
this.
|
|
582
|
+
var PrismaD1HTTPAdapterFactory = class {
|
|
583
|
+
constructor(params) {
|
|
584
|
+
this.params = params;
|
|
633
585
|
}
|
|
634
586
|
provider = "sqlite";
|
|
635
|
-
adapterName = name
|
|
587
|
+
adapterName = `${name}-http`;
|
|
636
588
|
async connect() {
|
|
637
|
-
return new
|
|
589
|
+
return new PrismaD1HTTPAdapter(this.params, async () => {
|
|
638
590
|
});
|
|
639
591
|
}
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
//
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
592
|
+
async connectToShadowDb() {
|
|
593
|
+
const D1_API_BASE_URL = `https://api.cloudflare.com/client/v4/accounts/${this.params.CLOUDFLARE_ACCOUNT_ID}/d1/database`;
|
|
594
|
+
const client = ky.create({
|
|
595
|
+
headers: {
|
|
596
|
+
Authorization: `Bearer ${this.params.CLOUDFLARE_D1_TOKEN}`
|
|
597
|
+
},
|
|
598
|
+
// Don't throw on non-2xx status codes
|
|
599
|
+
throwHttpErrors: false
|
|
600
|
+
});
|
|
601
|
+
const createShadowDatabase = async () => {
|
|
602
|
+
const tag = "[js::connectToShadowDb::createShadowDatabase]";
|
|
603
|
+
const SHADOW_DATABASE_PREFIX = "_prisma_shadow_";
|
|
604
|
+
const CLOUDFLARE_SHADOW_DATABASE_NAME = `${SHADOW_DATABASE_PREFIX}${globalThis.crypto.randomUUID()}`;
|
|
605
|
+
debug2(`${tag} creating database %s`, CLOUDFLARE_SHADOW_DATABASE_NAME);
|
|
606
|
+
try {
|
|
607
|
+
const response = await client.post(D1_API_BASE_URL, {
|
|
608
|
+
json: {
|
|
609
|
+
name: CLOUDFLARE_SHADOW_DATABASE_NAME
|
|
610
|
+
}
|
|
611
|
+
}).json();
|
|
612
|
+
debug2(`${tag} %O`, response);
|
|
613
|
+
if (!response.success) {
|
|
614
|
+
onUnsuccessfulD1HTTPResponse(response);
|
|
615
|
+
}
|
|
616
|
+
const { uuid: CLOUDFLARE_SHADOW_DATABASE_ID2 } = response.result;
|
|
617
|
+
debug2(`${tag} created database %s with ID %s`, CLOUDFLARE_SHADOW_DATABASE_NAME, CLOUDFLARE_SHADOW_DATABASE_ID2);
|
|
618
|
+
return CLOUDFLARE_SHADOW_DATABASE_ID2;
|
|
619
|
+
} catch (e) {
|
|
620
|
+
onGenericD1HTTPError(e);
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
const CLOUDFLARE_SHADOW_DATABASE_ID = this.params.CLOUDFLARE_SHADOW_DATABASE_ID ?? await createShadowDatabase();
|
|
624
|
+
const dispose = async () => {
|
|
625
|
+
const tag = "[js::connectToShadowDb::dispose]";
|
|
626
|
+
try {
|
|
627
|
+
debug2(`${tag} deleting database %s`, CLOUDFLARE_SHADOW_DATABASE_ID);
|
|
628
|
+
const response = await client.delete(`${D1_API_BASE_URL}/${CLOUDFLARE_SHADOW_DATABASE_ID}`).json();
|
|
629
|
+
debug2(`${tag} %O`, response);
|
|
630
|
+
if (!response.success) {
|
|
631
|
+
onUnsuccessfulD1HTTPResponse(response);
|
|
632
|
+
}
|
|
633
|
+
} catch (e) {
|
|
634
|
+
onGenericD1HTTPError(e);
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
return new PrismaD1HTTPAdapter(this.params, dispose);
|
|
663
638
|
}
|
|
664
639
|
};
|
|
665
640
|
export {
|
|
666
|
-
PrismaD1
|
|
641
|
+
PrismaD1AdapterFactory as PrismaD1,
|
|
642
|
+
PrismaD1HTTPAdapterFactory as PrismaD1HTTP
|
|
667
643
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma/adapter-d1",
|
|
3
|
-
"version": "6.11.0-dev.
|
|
3
|
+
"version": "6.11.0-dev.4",
|
|
4
4
|
"description": "Prisma's driver adapter for Cloudflare D1",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -37,14 +37,10 @@
|
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"@cloudflare/workers-types": "4.20250214.0",
|
|
39
39
|
"ky": "1.7.5",
|
|
40
|
-
"@prisma/driver-adapter-utils": "6.11.0-dev.
|
|
41
|
-
},
|
|
42
|
-
"devDependencies": {
|
|
43
|
-
"vitest": "3.0.9"
|
|
40
|
+
"@prisma/driver-adapter-utils": "6.11.0-dev.4"
|
|
44
41
|
},
|
|
45
42
|
"scripts": {
|
|
46
43
|
"dev": "DEV=true tsx helpers/build.ts",
|
|
47
|
-
"build": "tsx helpers/build.ts"
|
|
48
|
-
"test": "vitest run"
|
|
44
|
+
"build": "tsx helpers/build.ts"
|
|
49
45
|
}
|
|
50
46
|
}
|