cloudflare-d1-http-knex
Version:
An npm package that query [Cloudflare's D1](https://developers.cloudflare.com/d1/) through [Query D1 Database API](https://developers.cloudflare.com/api/operations/cloudflare-d1-query-database-query) and [Knex](https://knexjs.org/).
152 lines (144 loc) • 4.59 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
require('knex');
var Client = require('knex/lib/dialects/sqlite3/index.js');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var Client__default = /*#__PURE__*/_interopDefault(Client);
// src/client.ts
var CloudflareD1HttpClient = class extends Client__default.default {
constructor(config) {
config.connection.filename = ":memory:";
config.useNullAsDefault = false;
super(config);
if (!config.connection.mockedFetch) {
if (!config.connection?.account_id) {
throw Error("Missing required account_id");
}
if (!config.connection?.database_id) {
throw Error("Missing required database_id");
}
if (!config.connection?.key) {
throw Error("Missing required key");
}
}
this.config = config;
}
_driver() {
return this;
}
acquireRawConnection() {
return Promise.resolve(this);
}
async _query(_, obj) {
if (!obj.sql) return Promise.reject(Error("The query is empty"));
if (["BEGIN;", "COMMIT;", "ROLLBACK;"].includes(obj.sql)) {
console.warn(
"[WARN] D1 doesn't support transactions, see https://blog.cloudflare.com/whats-new-with-d1/"
);
return Promise.resolve();
}
if (this.config.connection.mockedFetch)
return this.config.connection.mockedFetch(
`https://api.cloudflare.com/client/v4/accounts/${this.config.connection.account_id}/d1/database/${this.config.connection.database_id}/query`,
{
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
sql: obj.sql,
params: obj.bindings
})
}
).then((res) => this._processResponse(res, obj));
return fetch(
`https://api.cloudflare.com/client/v4/accounts/${this.config.connection.account_id}/d1/database/${this.config.connection.database_id}/query`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${this.config.connection.key}`
},
body: JSON.stringify({
sql: obj.sql,
params: obj.bindings
})
}
).then((res) => this._processResponse(res, obj));
}
async _processResponse(res, obj) {
return res.json().then((body) => {
if (body.success) {
if (obj.output) return obj.output.call(null, body.result[0].results);
switch (obj.method) {
case "first":
return body.result[0].results[0];
case "insert":
if (obj.returning) {
return body.result[0].results;
}
return [body.result[0].meta.changes];
case "update":
if (obj.returning) {
return body.result[0].results;
}
return body.result[0].meta.changes;
case "del":
case "counter":
return body.result[0].meta.changes;
case "pluck":
return body.result[0].results.map((row) => row[obj.pluck]);
default:
return body.result[0].results;
}
}
throw Error(body.errors[0].message);
});
}
async processResponse(res) {
return res;
}
};
// src/mock.ts
var db;
var mockedFetch = (_, options) => {
return Promise.resolve({
json: async () => {
if (!db) {
const Sqlite3 = globalThis.require === undefined ? (await import('better-sqlite3')).default : globalThis.require("better-sqlite3");
db = new Sqlite3(":memory:");
}
const req = JSON.parse(options.body);
const prepare = db.prepare(req.sql);
let results;
let meta;
try {
results = prepare.all(req.params || []);
} catch (error) {
if (error.message.includes("Use run() instead")) {
meta = prepare.run(req.params || []);
} else return Promise.reject(Error(error.message));
}
return Promise.resolve({
success: true,
result: [
{
results,
meta
}
]
});
}
});
};
var MockedCloudflareD1HttpClient = class extends CloudflareD1HttpClient {
constructor() {
super({
connection: { account_id: "", database_id: "", key: "", mockedFetch }
});
}
};
var mock_default = MockedCloudflareD1HttpClient;
exports.MockedCloudflareD1HttpClient = MockedCloudflareD1HttpClient;
exports.default = mock_default;
exports.mockedFetch = mockedFetch;