EdgeAIG's picture
download
raw
6.46 kB
/**
* Main SQL client service for tagged-template queries.
*
* `SqlClient` combines the tagged-template statement constructor with
* connection acquisition, dialect compilation, transactions, row transforms,
* tracing, and reactive query helpers. Driver integrations build this service
* from their connection and compiler pieces.
*
* @since 4.0.0
*/
import { Clock } from "../../Clock.js";
import * as Context from "../../Context.js";
import * as Effect from "../../Effect.js";
import * as Exit from "../../Exit.js";
import * as Option from "../../Option.js";
import * as Scope from "../../Scope.js";
import * as Stream from "../../Stream.js";
import * as Tracer from "../../Tracer.js";
import { Reactivity } from "../reactivity/Reactivity.js";
import * as Statement from "./Statement.js";
const TypeId = "~effect/sql/SqlClient";
/**
* Service tag for the active SQL client service.
*
* **When to use**
*
* Use to access or provide the SQL client used to build statements, stream
* rows, reserve connections, and run transactions.
*
* @category services
* @since 4.0.0
*/
export const SqlClient = /*#__PURE__*/Context.Service("effect/sql/SqlClient");
let clientIdCounter = 0;
/**
* Constructs a `SqlClient` from connection acquirers, a compiler, transaction
* commands, tracing attributes, optional row transforms, and reactive query
* integration.
*
* @category constructors
* @since 4.0.0
*/
export const make = /*#__PURE__*/Effect.fnUntraced(function* (options) {
const transactionService = options.transactionService ?? TransactionConnection(clientIdCounter++);
const getConnection = Effect.flatMap(Effect.serviceOption(transactionService), Option.match({
onNone: () => options.acquirer,
onSome: ([conn]) => Effect.succeed(conn)
}));
const beginTransaction = options.beginTransaction ?? "BEGIN";
const commit = options.commit ?? "COMMIT";
const savepoint = options.savepoint ?? (name => `SAVEPOINT ${name}`);
const rollback = options.rollback ?? "ROLLBACK";
const rollbackSavepoint = options.rollbackSavepoint ?? (name => `ROLLBACK TO SAVEPOINT ${name}`);
const transactionAcquirer = options.transactionAcquirer ?? options.acquirer;
const withTransaction = makeWithTransaction({
transactionService,
spanAttributes: options.spanAttributes,
acquireConnection: Effect.flatMap(Scope.make(), scope => Effect.map(Scope.provide(transactionAcquirer, scope), conn => [scope, conn])),
begin: conn => conn.executeUnprepared(beginTransaction, [], undefined),
savepoint: (conn, id) => conn.executeUnprepared(savepoint(`effect_sql_${id}`), [], undefined),
commit: conn => conn.executeUnprepared(commit, [], undefined),
rollback: conn => conn.executeUnprepared(rollback, [], undefined),
rollbackSavepoint: (conn, id) => conn.executeUnprepared(rollbackSavepoint(`effect_sql_${id}`), [], undefined)
});
const reactivity = yield* Reactivity;
const client = Object.assign(Statement.make(getConnection, options.compiler, options.spanAttributes, options.transformRows), {
[TypeId]: TypeId,
safe: undefined,
withTransaction,
transactionService,
reserve: transactionAcquirer,
withoutTransforms() {
if (options.transformRows === undefined) {
return this;
}
const statement = Statement.make(getConnection, options.compiler.withoutTransform, options.spanAttributes, undefined);
const client = Object.assign(statement, {
...this,
...statement
});
client.safe = client;
client.withoutTransforms = () => client;
return client;
},
reactive: options.reactiveQueue ? (keys, effect) => options.reactiveQueue(keys, effect).pipe(Effect.map(Stream.fromQueue), Stream.unwrap) : reactivity.stream,
reactiveMailbox: options.reactiveQueue ?? reactivity.query
});
client.safe = client;
return client;
});
/**
* Builds a transaction wrapper that begins top-level transactions, uses
* savepoints for nested transactions, commits on success, and rolls back on
* failure or interruption.
*
* @category transactions
* @since 4.0.0
*/
export const makeWithTransaction = options => effect => {
return Effect.uninterruptibleMask(restore => Effect.useSpan("sql.transaction", {
kind: "client"
}, span => Effect.withFiber(fiber => {
for (const [key, value] of options.spanAttributes) {
span.attribute(key, value);
}
const services = fiber.context;
const clock = fiber.getRef(Clock);
const connOption = Context.getOption(services, options.transactionService);
const conn = connOption._tag === "Some" ? Effect.succeed([undefined, connOption.value[0]]) : options.acquireConnection;
const id = connOption._tag === "Some" ? connOption.value[1] + 1 : 0;
return Effect.flatMap(conn, ([scope, conn]) => (id === 0 ? options.begin(conn) : options.savepoint(conn, id)).pipe(Effect.flatMap(() => Effect.provideContext(restore(effect), Context.mutate(services, services => services.pipe(Context.add(options.transactionService, [conn, id]), Context.add(Tracer.ParentSpan, span))))), Effect.exit, Effect.flatMap(exit => {
let effect;
if (Exit.isSuccess(exit)) {
if (id === 0) {
span.event("db.transaction.commit", clock.currentTimeNanosUnsafe());
effect = Effect.orDie(options.commit(conn));
} else {
span.event("db.transaction.savepoint", clock.currentTimeNanosUnsafe());
effect = Effect.void;
}
} else {
span.event("db.transaction.rollback", clock.currentTimeNanosUnsafe());
effect = Effect.orDie(id > 0 ? options.rollbackSavepoint(conn, id) : options.rollback(conn));
}
const withScope = scope !== undefined ? Effect.ensuring(effect, Scope.close(scope, exit)) : effect;
return Effect.flatMap(withScope, () => exit);
})));
})));
};
/**
* Creates a unique context service tag for the active transaction connection of
* a specific SQL client.
*
* @category services
* @since 4.0.0
*/
export const TransactionConnection = clientId => Context.Service(`effect/sql/SqlClient/TransactionConnection/${clientId}`);
/**
* Context reference used by SQL integrations to opt in to safe integer
* handling; defaults to `false`.
*
* @category references
* @since 4.0.0
*/
export const SafeIntegers = /*#__PURE__*/Context.Reference("effect/sql/SqlClient/SafeIntegers", {
defaultValue: () => false
});
//# sourceMappingURL=SqlClient.js.map

Xet Storage Details

Size:
6.46 kB
·
Xet hash:
47128e9310f7e1aaed744095920720b93a139ece2721353b823de7dc9886e182

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.