| /** | |
| * Low-level SQL statement and fragment primitives. | |
| * | |
| * `SqlClient` uses this module to build executable, parameterized SQL from | |
| * reusable fragments. A statement can be executed, streamed, run without row | |
| * transformation, or compiled to SQL text and parameters for a specific | |
| * dialect. The module also contains helpers for identifiers, parameters, | |
| * inserts, updates, custom dialect fragments, statement compilation, and row | |
| * transformation. | |
| * | |
| * @since 4.0.0 | |
| */ | |
| import { Clock } from "../../Clock.js"; | |
| import * as Context from "../../Context.js"; | |
| import * as Effect from "../../Effect.js"; | |
| import * as Effectable from "../../Effectable.js"; | |
| import { constUndefined } from "../../Function.js"; | |
| import * as internalEffect from "../../internal/effect.js"; | |
| import { hasProperty } from "../../Predicate.js"; | |
| import { TracerTimingEnabled } from "../../References.js"; | |
| import * as Stream from "../../Stream.js"; | |
| const FragmentTypeId = "~effect/sql/Fragment"; | |
| /** | |
| * Constructs a SQL `Fragment` from low-level statement segments. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const fragment = segments => ({ | |
| [FragmentTypeId]: FragmentTypeId, | |
| segments | |
| }); | |
| /** | |
| * Context reference for an optional current SQL statement transformer applied | |
| * before statement execution. | |
| * | |
| * @category transformer | |
| * @since 4.0.0 | |
| */ | |
| export const CurrentTransformer = /*#__PURE__*/Context.Reference("effect/sql/CurrentTransformer", { | |
| defaultValue: constUndefined | |
| }); | |
| /** | |
| * Returns `true` when a value is a SQL `Fragment`. | |
| * | |
| * @category guards | |
| * @since 4.0.0 | |
| */ | |
| export const isFragment = u => hasProperty(u, FragmentTypeId); | |
| /** | |
| * Creates a type guard for custom SQL segments with the specified custom kind. | |
| * | |
| * @category guards | |
| * @since 4.0.0 | |
| */ | |
| export const isCustom = kind => u => hasProperty(u, "_tag") && u._tag === "Custom" && u.kind === kind; | |
| /** | |
| * Constructs a raw SQL literal segment. The literal text is not escaped, so use | |
| * bound parameters for untrusted values. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const literal = (value, params) => ({ | |
| _tag: "Literal", | |
| value, | |
| params | |
| }); | |
| /** | |
| * Constructs a SQL identifier segment that will be escaped by the active | |
| * compiler. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const identifier = value => ({ | |
| _tag: "Identifier", | |
| value | |
| }); | |
| /** | |
| * Constructs a bound parameter segment for a statement value. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const parameter = value => ({ | |
| _tag: "Parameter", | |
| value | |
| }); | |
| /** | |
| * Constructs an `ArrayHelper` segment for an array of values or fragments. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const arrayHelper = value => ({ | |
| _tag: "ArrayHelper", | |
| value | |
| }); | |
| const RecordInsertHelperProto = { | |
| _tag: "RecordInsertHelper", | |
| returning(sql) { | |
| const self = Object.create(Object.getPrototypeOf(this)); | |
| Object.assign(self, this, { | |
| returningIdentifier: sql | |
| }); | |
| return self; | |
| } | |
| }; | |
| /** | |
| * Constructs a `RecordInsertHelper` from one or more row objects. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const recordInsertHelper = value => Object.assign(Object.create(RecordInsertHelperProto), { | |
| value, | |
| returningIdentifier: undefined | |
| }); | |
| const RecordUpdateHelperProto = { | |
| ...RecordInsertHelperProto, | |
| _tag: "RecordUpdateHelper" | |
| }; | |
| /** | |
| * Constructs a `RecordUpdateHelper` for multi-row update compilation using the | |
| * provided alias. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const recordUpdateHelper = (value, alias) => Object.assign(Object.create(RecordUpdateHelperProto), { | |
| value, | |
| alias, | |
| returningIdentifier: undefined | |
| }); | |
| const RecordUpdateHelperSingleProto = { | |
| ...RecordInsertHelperProto, | |
| _tag: "RecordUpdateHelperSingle" | |
| }; | |
| /** | |
| * Constructs a `RecordUpdateHelperSingle` from a record and a list of columns | |
| * to omit from the update. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const recordUpdateHelperSingle = (value, omit) => Object.assign(Object.create(RecordUpdateHelperSingleProto), { | |
| value, | |
| omit, | |
| returningIdentifier: undefined | |
| }); | |
| /** | |
| * Creates a constructor for custom SQL segments of a specific kind handled by | |
| * the active compiler. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const custom = kind => (paramA, paramB, paramC) => ({ | |
| _tag: "Custom", | |
| kind, | |
| paramA, | |
| paramB, | |
| paramC | |
| }); | |
| /** | |
| * Creates a cached SQL statement constructor from a connection acquirer, | |
| * compiler, tracing attributes, and optional row transformation function. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const make = (acquirer, compiler, spanAttributes, transformRows) => { | |
| const cache = transformRows === undefined ? constructorCache.noTransforms : constructorCache.transforms; | |
| if (cache.has(acquirer)) { | |
| return cache.get(acquirer); | |
| } | |
| const self = Object.assign(function sql(strings, ...args) { | |
| if (typeof strings === "string") { | |
| return identifier(strings); | |
| } else if (Array.isArray(strings) && "raw" in strings) { | |
| return statement(acquirer, compiler, strings, args, spanAttributes, transformRows); | |
| } | |
| throw "absurd"; | |
| }, { | |
| unsafe(sql, params) { | |
| return makeUnsafe([literal(sql, params)], acquirer, compiler, spanAttributes, transformRows); | |
| }, | |
| literal(sql) { | |
| return fragment([literal(sql)]); | |
| }, | |
| in: in_, | |
| insert(value) { | |
| return recordInsertHelper(Array.isArray(value) ? value : [value]); | |
| }, | |
| update(value, omit) { | |
| return recordUpdateHelperSingle(value, omit ?? []); | |
| }, | |
| updateValues(value, alias) { | |
| return recordUpdateHelper(value, alias); | |
| }, | |
| and, | |
| or, | |
| csv, | |
| join, | |
| onDialect(options) { | |
| return options[compiler.dialect](); | |
| }, | |
| onDialectOrElse(options) { | |
| return options[compiler.dialect] !== undefined ? options[compiler.dialect]() : options.orElse(); | |
| } | |
| }); | |
| cache.set(acquirer, self); | |
| return self; | |
| }; | |
| const constructorCache = { | |
| transforms: /*#__PURE__*/new WeakMap(), | |
| noTransforms: /*#__PURE__*/new WeakMap() | |
| }; | |
| /** | |
| * Builds a `Statement` from template strings and arguments, preserving | |
| * fragments and helper segments while converting ordinary interpolated values | |
| * into bound parameters. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const statement = (acquirer, compiler, strings, args, spanAttributes, transformRows) => { | |
| const segments = strings[0].length > 0 ? [literal(strings[0])] : []; | |
| for (let i = 0; i < args.length; i++) { | |
| const arg = args[i]; | |
| if (isFragment(arg)) { | |
| segments.push(...arg.segments); | |
| } else if (isSegment(arg)) { | |
| segments.push(arg); | |
| } else { | |
| segments.push(parameter(arg)); | |
| } | |
| if (strings[i + 1].length > 0) { | |
| segments.push(literal(strings[i + 1])); | |
| } | |
| } | |
| return makeUnsafe(segments, acquirer, compiler, spanAttributes, transformRows); | |
| }; | |
| /** | |
| * Creates a helper that joins SQL clauses with a literal separator, optionally | |
| * wrapping multiple clauses in parentheses and using a fallback for an empty | |
| * list. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export function join(lit, addParens = true, fallback = "") { | |
| const literalStatement = literal(lit); | |
| const fallbackFragment = fragment([literal(fallback)]); | |
| return clauses => { | |
| if (clauses.length === 0) { | |
| return fallbackFragment; | |
| } else if (clauses.length === 1) { | |
| return fragment(convertLiteralOrFragment(clauses[0])); | |
| } | |
| const segments = []; | |
| if (addParens) { | |
| segments.push(literal("(")); | |
| } | |
| segments.push.apply(segments, convertLiteralOrFragment(clauses[0])); | |
| for (let i = 1; i < clauses.length; i++) { | |
| segments.push(literalStatement); | |
| segments.push.apply(segments, convertLiteralOrFragment(clauses[i])); | |
| } | |
| if (addParens) { | |
| segments.push(literal(")")); | |
| } | |
| return fragment(segments); | |
| }; | |
| } | |
| /** | |
| * Combines clauses with `AND`, parenthesizing multiple clauses and returning | |
| * `1=1` when the list is empty. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const and = /*#__PURE__*/join(" AND ", true, "1=1"); | |
| /** | |
| * Combines clauses with `OR`, parenthesizing multiple clauses and returning | |
| * `1=1` when the list is empty. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const or = /*#__PURE__*/join(" OR ", true, "1=1"); | |
| /** | |
| * Creates a comma-separated SQL fragment from values, optionally adding a | |
| * prefix, and returns an empty fragment when no values are provided. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export const csv = function (...args) { | |
| if (args[args.length - 1].length === 0) { | |
| return emptyFragment; | |
| } | |
| if (args.length === 1) { | |
| return csvRaw(args[0]); | |
| } | |
| return fragment([literal(`${args[0]} `), ...csvRaw(args[1]).segments]); | |
| }; | |
| const csvRaw = /*#__PURE__*/join(",", false); | |
| const emptyFragment = /*#__PURE__*/fragment([/*#__PURE__*/literal("")]); | |
| /** | |
| * Creates a dialect-specific SQL `Compiler` from rendering callbacks. | |
| * | |
| * @category compiler | |
| * @since 4.0.0 | |
| */ | |
| export const makeCompiler = options => { | |
| const self = Object.create(CompilerProto); | |
| self.options = options; | |
| self.dialect = options.dialect; | |
| self.disableTransforms = false; | |
| return self; | |
| }; | |
| const statementCacheSymbol = /*#__PURE__*/Symbol.for("effect/unstable/sql/Statement/statementCache"); | |
| const statementCacheNoTransformSymbol = /*#__PURE__*/Symbol.for("effect/unstable/sql/Statement/statementCacheNoTransform"); | |
| const CompilerProto = { | |
| compile(statement, withoutTransform = false, placeholderOverride) { | |
| const opts = this.options; | |
| withoutTransform = withoutTransform || this.disableTransforms; | |
| const cacheSymbol = withoutTransform ? statementCacheNoTransformSymbol : statementCacheSymbol; | |
| if (cacheSymbol in statement) { | |
| return statement[cacheSymbol]; | |
| } | |
| const segments = statement.segments; | |
| const len = segments.length; | |
| let sql = ""; | |
| const binds = []; | |
| let placeholderCount = 0; | |
| const placeholder = placeholderOverride ?? (u => opts.placeholder(++placeholderCount, u)); | |
| const placeholderNoIncrement = u => opts.placeholder(placeholderCount, u); | |
| const placeholders = makePlaceholdersArray(placeholder); | |
| for (let i = 0; i < len; i++) { | |
| const segment = segments[i]; | |
| switch (segment._tag) { | |
| case "Literal": | |
| { | |
| sql += segment.value; | |
| if (segment.params) { | |
| binds.push.apply(binds, segment.params); | |
| } | |
| break; | |
| } | |
| case "Identifier": | |
| { | |
| sql += opts.onIdentifier(segment.value, withoutTransform); | |
| break; | |
| } | |
| case "Parameter": | |
| { | |
| sql += placeholder(segment.value); | |
| binds.push(segment.value); | |
| break; | |
| } | |
| case "ArrayHelper": | |
| { | |
| sql += `(${placeholders(segment.value)})`; | |
| binds.push.apply(binds, segment.value); | |
| break; | |
| } | |
| case "RecordInsertHelper": | |
| { | |
| const keys = Object.keys(segment.value[0]); | |
| if (opts.onInsert) { | |
| const values = new Array(segment.value.length); | |
| let placeholders = ""; | |
| for (let i = 0; i < segment.value.length; i++) { | |
| const row = new Array(keys.length); | |
| values[i] = row; | |
| placeholders += i === 0 ? "(" : ",("; | |
| for (let j = 0; j < keys.length; j++) { | |
| const key = keys[j]; | |
| const value = segment.value[i][key]; | |
| const primitive = extractPrimitive(value, opts.onCustom, placeholderNoIncrement, withoutTransform); | |
| row[j] = primitive; | |
| placeholders += j === 0 ? placeholder(value) : `,${placeholder(value)}`; | |
| } | |
| placeholders += ")"; | |
| } | |
| const [s, b] = opts.onInsert(keys.map(_ => opts.onIdentifier(_, withoutTransform)), placeholders, values, typeof segment.returningIdentifier === "string" ? [segment.returningIdentifier, []] : segment.returningIdentifier ? this.compile(segment.returningIdentifier, withoutTransform, placeholder) : undefined); | |
| sql += s; | |
| binds.push.apply(binds, b); | |
| } else { | |
| let placeholders = ""; | |
| for (let i = 0; i < segment.value.length; i++) { | |
| placeholders += i === 0 ? "(" : ",("; | |
| for (let j = 0; j < keys.length; j++) { | |
| const value = segment.value[i][keys[j]]; | |
| const primitive = extractPrimitive(value, opts.onCustom, placeholderNoIncrement, withoutTransform); | |
| binds.push(primitive); | |
| placeholders += j === 0 ? placeholder(value) : `,${placeholder(value)}`; | |
| } | |
| placeholders += ")"; | |
| } | |
| sql += `${generateColumns(keys, opts.onIdentifier, withoutTransform)} VALUES ${placeholders}`; | |
| if (typeof segment.returningIdentifier === "string") { | |
| sql += ` RETURNING ${segment.returningIdentifier}`; | |
| } else if (segment.returningIdentifier) { | |
| sql += " RETURNING "; | |
| const [s, b] = this.compile(segment.returningIdentifier, withoutTransform, placeholder); | |
| sql += s; | |
| binds.push.apply(binds, b); | |
| } | |
| } | |
| break; | |
| } | |
| case "RecordUpdateHelperSingle": | |
| { | |
| let keys = Object.keys(segment.value); | |
| if (segment.omit.length > 0) { | |
| keys = keys.filter(key => !segment.omit.includes(key)); | |
| } | |
| if (opts.onRecordUpdateSingle) { | |
| const [s, b] = opts.onRecordUpdateSingle(keys.map(_ => opts.onIdentifier(_, withoutTransform)), keys.map(key => extractPrimitive(segment.value[key], opts.onCustom, placeholderNoIncrement, withoutTransform)), typeof segment.returningIdentifier === "string" ? [segment.returningIdentifier, []] : segment.returningIdentifier ? this.compile(segment.returningIdentifier, withoutTransform, placeholder) : undefined); | |
| sql += s; | |
| binds.push.apply(binds, b); | |
| } else { | |
| for (let i = 0, len = keys.length; i < len; i++) { | |
| const column = opts.onIdentifier(keys[i], withoutTransform); | |
| if (i === 0) { | |
| sql += `${column} = ${placeholder(segment.value[keys[i]])}`; | |
| } else { | |
| sql += `, ${column} = ${placeholder(segment.value[keys[i]])}`; | |
| } | |
| binds.push(extractPrimitive(segment.value[keys[i]], opts.onCustom, placeholderNoIncrement, withoutTransform)); | |
| } | |
| if (typeof segment.returningIdentifier === "string") { | |
| if (this.dialect === "mssql") { | |
| sql += ` OUTPUT ${segment.returningIdentifier === "*" ? "INSERTED.*" : segment.returningIdentifier}`; | |
| } else { | |
| sql += ` RETURNING ${segment.returningIdentifier}`; | |
| } | |
| } else if (segment.returningIdentifier) { | |
| sql += this.dialect === "mssql" ? " OUTPUT " : " RETURNING "; | |
| const [s, b] = this.compile(segment.returningIdentifier, withoutTransform, placeholder); | |
| sql += s; | |
| binds.push.apply(binds, b); | |
| } | |
| } | |
| break; | |
| } | |
| case "RecordUpdateHelper": | |
| { | |
| const keys = Object.keys(segment.value[0]); | |
| const values = new Array(segment.value.length); | |
| let placeholders = ""; | |
| for (let i = 0; i < segment.value.length; i++) { | |
| const row = new Array(keys.length); | |
| values[i] = row; | |
| placeholders += i === 0 ? "(" : ",("; | |
| for (let j = 0; j < keys.length; j++) { | |
| const key = keys[j]; | |
| const value = segment.value[i][key]; | |
| row[j] = extractPrimitive(value, opts.onCustom, placeholderNoIncrement, withoutTransform); | |
| placeholders += j === 0 ? placeholder(value) : `,${placeholder(value)}`; | |
| } | |
| placeholders += ")"; | |
| } | |
| const [s, b] = opts.onRecordUpdate(placeholders, segment.alias, generateColumns(keys, opts.onIdentifier, withoutTransform), values, typeof segment.returningIdentifier === "string" ? [segment.returningIdentifier, []] : segment.returningIdentifier ? this.compile(segment.returningIdentifier, withoutTransform, placeholder) : undefined); | |
| sql += s; | |
| binds.push.apply(binds, b); | |
| break; | |
| } | |
| case "Custom": | |
| { | |
| const [s, b] = opts.onCustom(segment, placeholder, withoutTransform); | |
| sql += s; | |
| binds.push.apply(binds, b); | |
| break; | |
| } | |
| } | |
| } | |
| const result = [sql, binds]; | |
| if (placeholderOverride !== undefined) { | |
| return result; | |
| } | |
| return statement[cacheSymbol] = result; | |
| }, | |
| get withoutTransform() { | |
| const self = Object.create(CompilerProto); | |
| Object.assign(self, this, { | |
| disableTransforms: true | |
| }); | |
| return self; | |
| } | |
| }; | |
| /** | |
| * Creates a SQLite compiler that uses `?` placeholders and quoted identifiers, | |
| * optionally transforming identifier names before escaping. | |
| * | |
| * @category compiler | |
| * @since 4.0.0 | |
| */ | |
| export const makeCompilerSqlite = transform => makeCompiler({ | |
| dialect: "sqlite", | |
| placeholder(_) { | |
| return "?"; | |
| }, | |
| onIdentifier: transform ? function (value, withoutTransform) { | |
| return withoutTransform ? escapeSqlite(value) : escapeSqlite(transform(value)); | |
| } : escapeSqlite, | |
| onRecordUpdate() { | |
| return ["", []]; | |
| }, | |
| onCustom() { | |
| return ["", []]; | |
| } | |
| }); | |
| /** | |
| * Creates an identifier escaping function that wraps names in the given | |
| * delimiter, doubles delimiter characters, and escapes dots between identifier | |
| * parts. | |
| * | |
| * @category constructors | |
| * @since 4.0.0 | |
| */ | |
| export function defaultEscape(c) { | |
| const re = new RegExp(c, "g"); | |
| const double = c + c; | |
| const dot = c + "." + c; | |
| return function (str) { | |
| return c + str.replace(re, double).replace(/\./g, dot) + c; | |
| }; | |
| } | |
| /** | |
| * Classifies a JavaScript value as a SQL primitive kind, treating `undefined` | |
| * as `null` and defaulting unrecognized objects to `string`. | |
| * | |
| * @category predicates | |
| * @since 4.0.0 | |
| */ | |
| export const primitiveKind = value => { | |
| switch (typeof value) { | |
| case "string": | |
| return "string"; | |
| case "number": | |
| return "number"; | |
| case "boolean": | |
| return "boolean"; | |
| case "bigint": | |
| return "bigint"; | |
| case "undefined": | |
| return "null"; | |
| } | |
| if (value === null) { | |
| return "null"; | |
| } else if (value instanceof Date) { | |
| return "Date"; | |
| } else if (value instanceof Uint8Array) { | |
| return "Uint8Array"; | |
| } else if (value instanceof Int8Array) { | |
| return "Int8Array"; | |
| } | |
| return "string"; | |
| }; | |
| /** | |
| * Builds value, object, and row-array transformers that rename object keys with | |
| * the supplied function and optionally recurse into nested object arrays. | |
| * | |
| * @category transforming | |
| * @since 4.0.0 | |
| */ | |
| export const defaultTransforms = (transformer, nested = true) => { | |
| const transformValue = value => { | |
| if (Array.isArray(value)) { | |
| if (value.length === 0 || value[0].constructor !== Object) { | |
| return value; | |
| } | |
| return array(value); | |
| } else if (value?.constructor === Object) { | |
| return transformObject(value); | |
| } | |
| return value; | |
| }; | |
| const transformObject = obj => { | |
| const newObj = {}; | |
| for (const key in obj) { | |
| newObj[transformer(key)] = transformValue(obj[key]); | |
| } | |
| return newObj; | |
| }; | |
| const transformArrayNested = rows => { | |
| const newRows = new Array(rows.length); | |
| for (let i = 0, len = rows.length; i < len; i++) { | |
| const row = rows[i]; | |
| if (Array.isArray(row)) { | |
| newRows[i] = transformArrayNested(row); | |
| } else { | |
| const obj = {}; | |
| for (const key in row) { | |
| obj[transformer(key)] = transformValue(row[key]); | |
| } | |
| newRows[i] = obj; | |
| } | |
| } | |
| return newRows; | |
| }; | |
| const transformArray = rows => { | |
| const newRows = new Array(rows.length); | |
| for (let i = 0, len = rows.length; i < len; i++) { | |
| const row = rows[i]; | |
| if (Array.isArray(row)) { | |
| newRows[i] = transformArray(row); | |
| } else { | |
| const obj = {}; | |
| for (const key in row) { | |
| obj[transformer(key)] = row[key]; | |
| } | |
| newRows[i] = obj; | |
| } | |
| } | |
| return newRows; | |
| }; | |
| const array = nested ? transformArrayNested : transformArray; | |
| return { | |
| value: transformValue, | |
| object: transformObject, | |
| array | |
| }; | |
| }; | |
| // internal | |
| const ATTR_DB_OPERATION_NAME = "db.operation.name"; | |
| const ATTR_DB_QUERY_TEXT = "db.query.text"; | |
| const makeUnsafe = (segments, acquirer, compiler, spanAttributes, transformRows) => { | |
| const self = Object.create(StatementProto); | |
| self.segments = segments; | |
| self.acquirer = acquirer; | |
| self.compiler = compiler; | |
| self.spanAttributes = spanAttributes; | |
| self.transformRows = transformRows; | |
| return self; | |
| }; | |
| // TODO: figure out why these diagnostics are emitted | |
| const StatementProto = { | |
| ... /*#__PURE__*/Effectable.Prototype({ | |
| label: "Statement", | |
| evaluate(fiber) { | |
| const span = internalEffect.makeSpanUnsafe(fiber, "sql.execute", { | |
| kind: "client" | |
| }); | |
| const clock = fiber.getRef(Clock); | |
| const timingEnabled = fiber.getRef(TracerTimingEnabled); | |
| return Effect.onExit(this.withConnectionSpan("execute", (connection, sql, params) => connection.execute(sql, params, this.transformRows), false, span), exit => internalEffect.endSpan(span, exit, clock, timingEnabled)); | |
| } | |
| }), | |
| [FragmentTypeId]: FragmentTypeId, | |
| withConnection(operation, f, withoutTransform = false) { | |
| return Effect.useSpan("sql.execute", { | |
| kind: "client" | |
| }, span => this.withConnectionSpan(operation, f, withoutTransform, span)); | |
| }, | |
| withConnectionSpan(operation, f, withoutTransform, span) { | |
| return withStatement(this, span, statement => { | |
| const [sql, params] = statement.compile(withoutTransform); | |
| for (const [key, value] of this.spanAttributes) { | |
| span.attribute(key, value); | |
| } | |
| span.attribute(ATTR_DB_OPERATION_NAME, operation); | |
| span.attribute(ATTR_DB_QUERY_TEXT, sql); | |
| return Effect.scoped(Effect.flatMap(this.acquirer, _ => f(_, sql, params))); | |
| }); | |
| }, | |
| get withoutTransform() { | |
| return this.withConnection("executeWithoutTransform", (connection, sql, params) => connection.execute(sql, params, undefined), true); | |
| }, | |
| get raw() { | |
| return this.withConnection("executeRaw", (connection, sql, params) => connection.executeRaw(sql, params), true); | |
| }, | |
| get stream() { | |
| const self = this; | |
| return Stream.unwrap(Effect.flatMap(Effect.makeSpanScoped("sql.execute", { | |
| kind: "client" | |
| }), span => withStatement(self, span, statement => { | |
| const [sql, params] = statement.compile(); | |
| for (const [key, value] of self.spanAttributes) { | |
| span.attribute(key, value); | |
| } | |
| span.attribute(ATTR_DB_OPERATION_NAME, "executeStream"); | |
| span.attribute(ATTR_DB_QUERY_TEXT, sql); | |
| return Effect.map(self.acquirer, _ => _.executeStream(sql, params, self.transformRows)); | |
| }))); | |
| }, | |
| get values() { | |
| return this.withConnection("executeValues", (connection, sql, params) => connection.executeValues(sql, params)); | |
| }, | |
| get unprepared() { | |
| const self = this; | |
| return self.withConnection("executeUnprepared", (connection, sql, params) => connection.executeUnprepared(sql, params, self.transformRows)); | |
| }, | |
| compile(withoutTransform) { | |
| return this.compiler.compile(this, withoutTransform ?? false); | |
| }, | |
| toJSON() { | |
| const [sql, params] = this.compile(); | |
| return { | |
| _id: "Statement", | |
| segments: this.segments, | |
| sql, | |
| params | |
| }; | |
| } | |
| }; | |
| const withStatement = (self, span, f) => Effect.withFiber(fiber => { | |
| const transform = fiber.getRef(CurrentTransformer); | |
| if (transform === undefined) { | |
| return f(self); | |
| } | |
| return Effect.flatMap(transform(self, make(self.acquirer, self.compiler, self.spanAttributes, self.transformRows), fiber, span), f); | |
| }); | |
| const isSegment = u => { | |
| if (!hasProperty(u, "_tag")) { | |
| return false; | |
| } | |
| switch (u._tag) { | |
| case "Literal": | |
| case "Parameter": | |
| case "ArrayHelper": | |
| case "RecordInsertHelper": | |
| case "RecordUpdateHelper": | |
| case "RecordUpdateHelperSingle": | |
| case "Identifier": | |
| case "Custom": | |
| return true; | |
| default: | |
| return false; | |
| } | |
| }; | |
| function convertLiteralOrFragment(clause) { | |
| if (typeof clause === "string") { | |
| return [literal(clause)]; | |
| } | |
| return clause.segments; | |
| } | |
| const makePlaceholdersArray = evaluate => values => { | |
| if (values.length === 0) { | |
| return ""; | |
| } | |
| let result = evaluate(values[0]); | |
| for (let i = 1; i < values.length; i++) { | |
| result += `,${evaluate(values[i])}`; | |
| } | |
| return result; | |
| }; | |
| const generateColumns = (keys, escape, withoutTransform) => { | |
| if (keys.length === 0) { | |
| return "()"; | |
| } | |
| let str = `(${escape(keys[0], withoutTransform)}`; | |
| for (let i = 1; i < keys.length; i++) { | |
| str += `,${escape(keys[i], withoutTransform)}`; | |
| } | |
| return str + ")"; | |
| }; | |
| const extractPrimitive = (value, onCustom, placeholder, withoutTransform) => { | |
| if (value === undefined) { | |
| return null; | |
| } else if (isFragment(value)) { | |
| const head = value.segments[0]; | |
| if (head._tag === "Custom") { | |
| const compiled = onCustom(head, placeholder, withoutTransform); | |
| return compiled[1][0] ?? null; | |
| } else if (head._tag === "Parameter") { | |
| return head.value; | |
| } | |
| return null; | |
| } | |
| return value; | |
| }; | |
| const escapeSqlite = /*#__PURE__*/defaultEscape("\""); | |
| function in_() { | |
| if (arguments.length === 1) { | |
| return arrayHelper(arguments[0]); | |
| } | |
| const column = arguments[0]; | |
| const values = arguments[1]; | |
| return values.length === 0 ? neverFragment : fragment([identifier(column), literal(" IN "), arrayHelper(values)]); | |
| } | |
| const neverFragment = /*#__PURE__*/fragment([/*#__PURE__*/literal("1=0")]); | |
| //# sourceMappingURL=Statement.js.map |
Xet Storage Details
- Size:
- 26.2 kB
- Xet hash:
- c0547151f3c15e4450695337e6b38e9730b4d0aec1fde0ab0bf47b7b474a92b9
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.