Spaces:
Sleeping
Sleeping
| 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; | |
| for (const chunk of queryChunks) { | |
| if (is(chunk, Table)) { | |
| const schemaName = chunk[Table.Symbol.Schema]; | |
| this.usedTables.push( | |
| schemaName === void 0 ? chunk[Table.Symbol.Name] : schemaName + "." + chunk[Table.Symbol.Name] | |
| ); | |
| } | |
| } | |
| } | |
| static [entityKind] = "SQL"; | |
| /** @internal */ | |
| decoder = noopDecoder; | |
| shouldInlineParams = false; | |
| /** @internal */ | |
| usedTables = []; | |
| 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 |