@storecraft/database-cloudflare-d1
Version:
`Storecraft` database driver for `cloudflare` D1 (cloud sqlite)
187 lines (158 loc) • 4.06 kB
JavaScript
/**
* @import { Driver, Dialect, DatabaseConnection, QueryResult } from 'kysely';
* @import { D1ConfigWorker as Config } from './types.public.js';
*/
import {
CompiledQuery,
Kysely,
SqliteAdapter,
SqliteIntrospector,
SqliteQueryCompiler,
} from 'kysely';
import { D1Introspector } from './kysely.d1.http.introspector.js';
/**
* @description Official Storecraft Cloudflare D1 adapter on Worker
*
* @implements {Dialect}
*/
export class D1_Worker_Dialect {
/** @param {Config} config */
constructor(config) {
this.config = config;
}
createAdapter() { return new SqliteAdapter(); }
createDriver() { return new D1Driver(this.config); }
createQueryCompiler() { return new SqliteQueryCompiler(); }
/**
* @param {Kysely<any>} db
*/
createIntrospector(db){
return new D1Introspector(db);
}
}
/**
* @implements {Driver}
*/
class D1Driver {
/** @param {Config} config */
constructor(config) {
this.config = config;
}
async init() {}
async acquireConnection() {
return new D1Connection(this.config);
}
/**
* @param {D1Connection} conn
*/
beginTransaction(conn) { return conn.beginTransaction(); }
/**
* @param {D1Connection} conn
*/
commitTransaction(conn) {
return conn.commitTransaction();
}
/**
* @param {D1Connection} conn
*/
rollbackTransaction(conn){
return conn.rollbackTransaction();
}
/**
* @param {D1Connection} _conn
*/
async releaseConnection(_conn) {}
async destroy() {}
}
/**
* @implements {DatabaseConnection}
*/
class D1Connection {
isBatch = false;
/** @type {CompiledQuery[]} */
batch = []
/**
* @param {Config} config
*/
constructor(config) {
this.config = config;
}
/**
* @template R result type
*
* @param {CompiledQuery[]} compiledQueries
*
* @returns {Promise<QueryResult<R>>}
*/
async _internal_execute(compiledQueries) {
const db = this.config.db;
// console.log(JSON.stringify(
// {
// sql: compiledQueries.at(0).sql,
// params: compiledQueries.at(0).parameters,
// }, null, 2))
const results = await db.batch(
compiledQueries.map(
cq => db.prepare(cq.sql).bind(...cq.parameters)
)
);
// // console.log('q', JSON.stringify({sql, params}, null, 2))
// console.log('result', JSON.stringify(results, null, 2))
// if (!results?.success) {
// const is_auth_declined_error = params?.at(0)==='_cf_KV';
// console.log('is_auth_declined_error', is_auth_declined_error)
// if(!is_auth_declined_error)
// throw new Error(results?.errors?.join(', '));
// }
const last_result = results?.at(-1);
const meta = last_result?.meta;
const numAffectedRows = meta?.changes > 0 ? BigInt(meta?.changes) : undefined;
return {
insertId:
meta?.last_row_id === undefined || meta?.last_row_id === null
? undefined
: BigInt(meta?.last_row_id),
rows: ( /** @type {R[]} */(last_result?.results)) || [],
numAffectedRows,
};
}
/**
* @template R result type
*
* @param {CompiledQuery} compiledQuery
*
* @returns {Promise<QueryResult<R>>}
*/
async executeQuery(compiledQuery) {
// console.log('this.isBatch', this.isBatch);
if(this.isBatch) {
this.batch.push(compiledQuery);
return Promise.resolve(
{
rows: []
}
)
} else {
return this._internal_execute([compiledQuery]);
}
}
async beginTransaction() {
// console.log('beginTransaction')
// console.trace()
this.isBatch = true;
this.batch = [];
}
async commitTransaction() {
// console.log('commitTransaction')
// console.trace()
this.isBatch = false;
await this._internal_execute(this.batch);
}
async rollbackTransaction() {
return;
}
/** @type {DatabaseConnection["streamQuery"]} */
async *streamQuery(compiledQuery, chunkSize) {
throw new Error('D1 Driver does not support streaming');
}
}