UNPKG

drizzle-orm

Version:

Drizzle ORM package for SQL databases

426 lines • 12.1 kB
import { entityKind, is } from "../entity.js"; import { isPgEnum } from "../pg-core/columns/enum.js"; import { Subquery } from "../subquery.js"; import { tracer } from "../tracing.js"; import { ViewBaseConfig } from "../view-common.js"; import { Column } from "../column.js"; import { IsAlias, Table } from "../table.js"; class FakePrimitiveParam { static [entityKind] = "FakePrimitiveParam"; } function isSQLWrapper(value) { return value !== null && value !== void 0 && typeof value.getSQL === "function"; } function mergeQueries(queries) { const result = { sql: "", params: [] }; for (const query of queries) { result.sql += query.sql; result.params.push(...query.params); if (query.typings?.length) { if (!result.typings) { result.typings = []; } result.typings.push(...query.typings); } } return result; } class StringChunk { static [entityKind] = "StringChunk"; value; constructor(value) { this.value = Array.isArray(value) ? value : [value]; } getSQL() { return new SQL([this]); } } class SQL { constructor(queryChunks) { this.queryChunks = queryChunks; } static [entityKind] = "SQL"; /** @internal */ decoder = noopDecoder; shouldInlineParams = false; append(query) { this.queryChunks.push(...query.queryChunks); return this; } toQuery(config) { return tracer.startActiveSpan("drizzle.buildSQL", (span) => { const query = this.buildQueryFromSourceParams(this.queryChunks, config); span?.setAttributes({ "drizzle.query.text": query.sql, "drizzle.query.params": JSON.stringify(query.params) }); return query; }); } buildQueryFromSourceParams(chunks, _config) { const config = Object.assign({}, _config, { inlineParams: _config.inlineParams || this.shouldInlineParams, paramStartIndex: _config.paramStartIndex || { value: 0 } }); const { casing, escapeName, escapeParam, prepareTyping, inlineParams, paramStartIndex } = config; return mergeQueries(chunks.map((chunk) => { if (is(chunk, StringChunk)) { return { sql: chunk.value.join(""), params: [] }; } if (is(chunk, Name)) { return { sql: escapeName(chunk.value), params: [] }; } if (chunk === void 0) { return { sql: "", params: [] }; } if (Array.isArray(chunk)) { const result = [new StringChunk("(")]; for (const [i, p] of chunk.entries()) { result.push(p); if (i < chunk.length - 1) { result.push(new StringChunk(", ")); } } result.push(new StringChunk(")")); return this.buildQueryFromSourceParams(result, config); } if (is(chunk, SQL)) { return this.buildQueryFromSourceParams(chunk.queryChunks, { ...config, inlineParams: inlineParams || chunk.shouldInlineParams }); } if (is(chunk, Table)) { const schemaName = chunk[Table.Symbol.Schema]; const tableName = chunk[Table.Symbol.Name]; return { sql: schemaName === void 0 || chunk[IsAlias] ? escapeName(tableName) : escapeName(schemaName) + "." + escapeName(tableName), params: [] }; } if (is(chunk, Column)) { const columnName = casing.getColumnCasing(chunk); if (_config.invokeSource === "indexes") { return { sql: escapeName(columnName), params: [] }; } const schemaName = chunk.table[Table.Symbol.Schema]; return { sql: chunk.table[IsAlias] || schemaName === void 0 ? escapeName(chunk.table[Table.Symbol.Name]) + "." + escapeName(columnName) : escapeName(schemaName) + "." + escapeName(chunk.table[Table.Symbol.Name]) + "." + escapeName(columnName), params: [] }; } if (is(chunk, View)) { const schemaName = chunk[ViewBaseConfig].schema; const viewName = chunk[ViewBaseConfig].name; return { sql: schemaName === void 0 || chunk[ViewBaseConfig].isAlias ? escapeName(viewName) : escapeName(schemaName) + "." + escapeName(viewName), params: [] }; } if (is(chunk, Param)) { if (is(chunk.value, Placeholder)) { return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk], typings: ["none"] }; } const mappedValue = chunk.value === null ? null : chunk.encoder.mapToDriverValue(chunk.value); if (is(mappedValue, SQL)) { return this.buildQueryFromSourceParams([mappedValue], config); } if (inlineParams) { return { sql: this.mapInlineParam(mappedValue, config), params: [] }; } let typings = ["none"]; if (prepareTyping) { typings = [prepareTyping(chunk.encoder)]; } return { sql: escapeParam(paramStartIndex.value++, mappedValue), params: [mappedValue], typings }; } if (is(chunk, Placeholder)) { return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk], typings: ["none"] }; } if (is(chunk, SQL.Aliased) && chunk.fieldAlias !== void 0) { return { sql: escapeName(chunk.fieldAlias), params: [] }; } if (is(chunk, Subquery)) { if (chunk._.isWith) { return { sql: escapeName(chunk._.alias), params: [] }; } return this.buildQueryFromSourceParams([ new StringChunk("("), chunk._.sql, new StringChunk(") "), new Name(chunk._.alias) ], config); } if (isPgEnum(chunk)) { if (chunk.schema) { return { sql: escapeName(chunk.schema) + "." + escapeName(chunk.enumName), params: [] }; } return { sql: escapeName(chunk.enumName), params: [] }; } if (isSQLWrapper(chunk)) { if (chunk.shouldOmitSQLParens?.()) { return this.buildQueryFromSourceParams([chunk.getSQL()], config); } return this.buildQueryFromSourceParams([ new StringChunk("("), chunk.getSQL(), new StringChunk(")") ], config); } if (inlineParams) { return { sql: this.mapInlineParam(chunk, config), params: [] }; } return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk], typings: ["none"] }; })); } mapInlineParam(chunk, { escapeString }) { if (chunk === null) { return "null"; } if (typeof chunk === "number" || typeof chunk === "boolean") { return chunk.toString(); } if (typeof chunk === "string") { return escapeString(chunk); } if (typeof chunk === "object") { const mappedValueAsString = chunk.toString(); if (mappedValueAsString === "[object Object]") { return escapeString(JSON.stringify(chunk)); } return escapeString(mappedValueAsString); } throw new Error("Unexpected param value: " + chunk); } getSQL() { return this; } as(alias) { if (alias === void 0) { return this; } return new SQL.Aliased(this, alias); } mapWith(decoder) { this.decoder = typeof decoder === "function" ? { mapFromDriverValue: decoder } : decoder; return this; } inlineParams() { this.shouldInlineParams = true; return this; } /** * This method is used to conditionally include a part of the query. * * @param condition - Condition to check * @returns itself if the condition is `true`, otherwise `undefined` */ if(condition) { return condition ? this : void 0; } } class Name { constructor(value) { this.value = value; } static [entityKind] = "Name"; brand; getSQL() { return new SQL([this]); } } function name(value) { return new Name(value); } function isDriverValueEncoder(value) { return typeof value === "object" && value !== null && "mapToDriverValue" in value && typeof value.mapToDriverValue === "function"; } const noopDecoder = { mapFromDriverValue: (value) => value }; const noopEncoder = { mapToDriverValue: (value) => value }; const noopMapper = { ...noopDecoder, ...noopEncoder }; class Param { /** * @param value - Parameter value * @param encoder - Encoder to convert the value to a driver parameter */ constructor(value, encoder = noopEncoder) { this.value = value; this.encoder = encoder; } static [entityKind] = "Param"; brand; getSQL() { return new SQL([this]); } } function param(value, encoder) { return new Param(value, encoder); } function sql(strings, ...params) { const queryChunks = []; if (params.length > 0 || strings.length > 0 && strings[0] !== "") { queryChunks.push(new StringChunk(strings[0])); } for (const [paramIndex, param2] of params.entries()) { queryChunks.push(param2, new StringChunk(strings[paramIndex + 1])); } return new SQL(queryChunks); } ((sql2) => { function empty() { return new SQL([]); } sql2.empty = empty; function fromList(list) { return new SQL(list); } sql2.fromList = fromList; function raw(str) { return new SQL([new StringChunk(str)]); } sql2.raw = raw; function join(chunks, separator) { const result = []; for (const [i, chunk] of chunks.entries()) { if (i > 0 && separator !== void 0) { result.push(separator); } result.push(chunk); } return new SQL(result); } sql2.join = join; function identifier(value) { return new Name(value); } sql2.identifier = identifier; function placeholder2(name2) { return new Placeholder(name2); } sql2.placeholder = placeholder2; function param2(value, encoder) { return new Param(value, encoder); } sql2.param = param2; })(sql || (sql = {})); ((SQL2) => { class Aliased { constructor(sql2, fieldAlias) { this.sql = sql2; this.fieldAlias = fieldAlias; } static [entityKind] = "SQL.Aliased"; /** @internal */ isSelectionField = false; getSQL() { return this.sql; } /** @internal */ clone() { return new Aliased(this.sql, this.fieldAlias); } } SQL2.Aliased = Aliased; })(SQL || (SQL = {})); class Placeholder { constructor(name2) { this.name = name2; } static [entityKind] = "Placeholder"; getSQL() { return new SQL([this]); } } function placeholder(name2) { return new Placeholder(name2); } function fillPlaceholders(params, values) { return params.map((p) => { if (is(p, Placeholder)) { if (!(p.name in values)) { throw new Error(`No value for placeholder "${p.name}" was provided`); } return values[p.name]; } if (is(p, Param) && is(p.value, Placeholder)) { if (!(p.value.name in values)) { throw new Error(`No value for placeholder "${p.value.name}" was provided`); } return p.encoder.mapToDriverValue(values[p.value.name]); } return p; }); } const IsDrizzleView = Symbol.for("drizzle:IsDrizzleView"); class View { static [entityKind] = "View"; /** @internal */ [ViewBaseConfig]; /** @internal */ [IsDrizzleView] = true; constructor({ name: name2, schema, selectedFields, query }) { this[ViewBaseConfig] = { name: name2, originalName: name2, schema, selectedFields, query, isExisting: !query, isAlias: false }; } getSQL() { return new SQL([this]); } } function isView(view) { return typeof view === "object" && view !== null && IsDrizzleView in view; } function getViewName(view) { return view[ViewBaseConfig].name; } Column.prototype.getSQL = function() { return new SQL([this]); }; Table.prototype.getSQL = function() { return new SQL([this]); }; Subquery.prototype.getSQL = function() { return new SQL([this]); }; export { FakePrimitiveParam, Name, Param, Placeholder, SQL, StringChunk, View, fillPlaceholders, getViewName, isDriverValueEncoder, isSQLWrapper, isView, name, noopDecoder, noopEncoder, noopMapper, param, placeholder, sql }; //# sourceMappingURL=sql.js.map