| /** | |
| * 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.