effect-sql-kysely
Version:
A full-featured integration between `@effect/sql` and `Kysely` that provides type-safe database operations with Effect's powerful error handling and resource management.
103 lines (102 loc) • 4.9 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeSqlClient = makeSqlClient;
const Sql = __importStar(require("@effect/sql"));
const effect_1 = require("effect");
const kysely_1 = require("kysely");
const beginConnection_js_1 = require("./beginConnection.js");
const createQueryId_js_1 = require("./createQueryId.js");
function makeSqlClient({ database, compiler, spanAttributes = [], chunkSize = 16, }) {
const transformRows = Sql.Statement.defaultTransforms((s) => s, false).array;
// A Connection is a wrapper around a Kysely database connection, or Transaction, that provides
// the ability to run queries within Effects and captures any errors that may occur.
class ConnectionImpl {
db;
constructor(db) {
this.db = db;
}
executeUnprepared(sql, params) {
return effect_1.Effect.tryPromise({
try: () => this.db
.executeQuery(compileSqlQuery(sql, params))
.then((r) => transformRows(r.rows)),
catch: (cause) => new Sql.SqlError.SqlError({ cause }),
});
}
execute(sql, params) {
return effect_1.Effect.tryPromise({
try: () => this.db
.executeQuery(compileSqlQuery(sql, params))
.then((r) => transformRows(r.rows)),
catch: (cause) => new Sql.SqlError.SqlError({ cause }),
});
}
executeWithoutTransform(sql, params) {
return effect_1.Effect.tryPromise({
try: () => this.db
.executeQuery(compileSqlQuery(sql, params))
.then((r) => r.rows),
catch: (cause) => new Sql.SqlError.SqlError({ cause }),
});
}
executeValues(sql, params) {
return effect_1.Effect.map(this.executeRaw(sql, params), (results) => results.map((x) => Object.values(x)));
}
executeRaw(sql, params) {
return effect_1.Effect.tryPromise({
try: () => this.db
.executeQuery(compileSqlQuery(sql, params))
.then((r) => transformRows(r.rows)),
catch: (cause) => new Sql.SqlError.SqlError({ cause }),
});
}
executeStream(sql, params) {
const query = compileSqlQuery(sql, params);
return effect_1.Stream.suspend(() => effect_1.Stream.mapChunks(effect_1.Stream.fromAsyncIterable(this.db
.getExecutor()
.stream(query, chunkSize, { queryId: (0, createQueryId_js_1.createQueryId)() }), (cause) => new Sql.SqlError.SqlError({ cause })), effect_1.Chunk.flatMap((result) => effect_1.Chunk.unsafeFromArray(result.rows))));
}
}
const acquirer = effect_1.Effect.succeed(new ConnectionImpl(database));
return Sql.SqlClient.make({
// Our default connection is managed by Kysely
acquirer,
// Our SQL statement compiler
compiler,
// We don't utilize db.transaction() because Sql.client.make will handle the actual transaction
// But we do ensure that all queries are run within a single connection
transactionAcquirer: effect_1.Effect.map(effect_1.Effect.acquireRelease(effect_1.Effect.promise(() => (0, beginConnection_js_1.beginConnection)(database)), (conn, exit) => effect_1.Effect.promise(() => effect_1.Exit.match(exit, {
// If the scope fails we rollback the transaction
onFailure: () => conn.fail(),
// If the scope succeeds we commit the transaction
onSuccess: () => conn.success(),
}))), ({ conn }) => new ConnectionImpl(conn)),
spanAttributes,
});
}
function compileSqlQuery(sql, params) {
return kysely_1.CompiledQuery.raw(sql, params);
}