| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123 |
- import { aliasedTable, aliasedTableColumn, mapColumnsInAliasedSQLToAlias, mapColumnsInSQLToAlias } from "../alias.js";
- import { CasingCache } from "../casing.js";
- import { Column } from "../column.js";
- import { entityKind, is } from "../entity.js";
- import { DrizzleError } from "../errors.js";
- import { GelColumn, GelDecimal, GelJson, GelUUID } from "./columns/index.js";
- import { GelTable } from "./table.js";
- import {
- getOperators,
- getOrderByOperators,
- Many,
- normalizeRelation,
- One
- } from "../relations.js";
- import { and, eq, View } from "../sql/index.js";
- import {
- Param,
- SQL,
- sql
- } from "../sql/sql.js";
- import { Subquery } from "../subquery.js";
- import { getTableName, getTableUniqueName, Table } from "../table.js";
- import { orderSelectedFields } from "../utils.js";
- import { ViewBaseConfig } from "../view-common.js";
- import { GelTimestamp } from "./columns/timestamp.js";
- import { GelViewBase } from "./view-base.js";
- class GelDialect {
- static [entityKind] = "GelDialect";
- /** @internal */
- casing;
- constructor(config) {
- this.casing = new CasingCache(config?.casing);
- }
- // TODO can not migrate gel with drizzle
- // async migrate(migrations: MigrationMeta[], session: GelSession, config: string | MigrationConfig): Promise<void> {
- // const migrationsTable = typeof config === 'string'
- // ? '__drizzle_migrations'
- // : config.migrationsTable ?? '__drizzle_migrations';
- // const migrationsSchema = typeof config === 'string' ? 'drizzle' : config.migrationsSchema ?? 'drizzle';
- // const migrationTableCreate = sql`
- // CREATE TABLE IF NOT EXISTS ${sql.identifier(migrationsSchema)}.${sql.identifier(migrationsTable)} (
- // id SERIAL PRIMARY KEY,
- // hash text NOT NULL,
- // created_at bigint
- // )
- // `;
- // await session.execute(sql`CREATE SCHEMA IF NOT EXISTS ${sql.identifier(migrationsSchema)}`);
- // await session.execute(migrationTableCreate);
- // const dbMigrations = await session.all<{ id: number; hash: string; created_at: string }>(
- // sql`select id, hash, created_at from ${sql.identifier(migrationsSchema)}.${
- // sql.identifier(migrationsTable)
- // } order by created_at desc limit 1`,
- // );
- // const lastDbMigration = dbMigrations[0];
- // await session.transaction(async (tx) => {
- // for await (const migration of migrations) {
- // if (
- // !lastDbMigration
- // || Number(lastDbMigration.created_at) < migration.folderMillis
- // ) {
- // for (const stmt of migration.sql) {
- // await tx.execute(sql.raw(stmt));
- // }
- // await tx.execute(
- // sql`insert into ${sql.identifier(migrationsSchema)}.${
- // sql.identifier(migrationsTable)
- // } ("hash", "created_at") values(${migration.hash}, ${migration.folderMillis})`,
- // );
- // }
- // }
- // });
- // }
- escapeName(name) {
- return `"${name}"`;
- }
- escapeParam(num) {
- return `$${num + 1}`;
- }
- escapeString(str) {
- return `'${str.replace(/'/g, "''")}'`;
- }
- buildWithCTE(queries) {
- if (!queries?.length) return void 0;
- const withSqlChunks = [sql`with `];
- for (const [i, w] of queries.entries()) {
- withSqlChunks.push(sql`${sql.identifier(w._.alias)} as (${w._.sql})`);
- if (i < queries.length - 1) {
- withSqlChunks.push(sql`, `);
- }
- }
- withSqlChunks.push(sql` `);
- return sql.join(withSqlChunks);
- }
- buildDeleteQuery({ table, where, returning, withList }) {
- const withSql = this.buildWithCTE(withList);
- const returningSql = returning ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` : void 0;
- const whereSql = where ? sql` where ${where}` : void 0;
- return sql`${withSql}delete from ${table}${whereSql}${returningSql}`;
- }
- buildUpdateSet(table, set) {
- const tableColumns = table[Table.Symbol.Columns];
- const columnNames = Object.keys(tableColumns).filter(
- (colName) => set[colName] !== void 0 || tableColumns[colName]?.onUpdateFn !== void 0
- );
- const setSize = columnNames.length;
- return sql.join(columnNames.flatMap((colName, i) => {
- const col = tableColumns[colName];
- const onUpdateFnResult = col.onUpdateFn?.();
- const value = set[colName] ?? (is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col));
- const res = sql`${sql.identifier(this.casing.getColumnCasing(col))} = ${value}`;
- if (i < setSize - 1) {
- return [res, sql.raw(", ")];
- }
- return [res];
- }));
- }
- buildUpdateQuery({ table, set, where, returning, withList, from, joins }) {
- const withSql = this.buildWithCTE(withList);
- const tableName = table[GelTable.Symbol.Name];
- const tableSchema = table[GelTable.Symbol.Schema];
- const origTableName = table[GelTable.Symbol.OriginalName];
- const alias = tableName === origTableName ? void 0 : tableName;
- const tableSql = sql`${tableSchema ? sql`${sql.identifier(tableSchema)}.` : void 0}${sql.identifier(origTableName)}${alias && sql` ${sql.identifier(alias)}`}`;
- const setSql = this.buildUpdateSet(table, set);
- const fromSql = from && sql.join([sql.raw(" from "), this.buildFromTable(from)]);
- const joinsSql = this.buildJoins(joins);
- const returningSql = returning ? sql` returning ${this.buildSelection(returning, { isSingleTable: !from })}` : void 0;
- const whereSql = where ? sql` where ${where}` : void 0;
- return sql`${withSql}update ${tableSql} set ${setSql}${fromSql}${joinsSql}${whereSql}${returningSql}`;
- }
- /**
- * Builds selection SQL with provided fields/expressions
- *
- * Examples:
- *
- * `select <selection> from`
- *
- * `insert ... returning <selection>`
- *
- * If `isSingleTable` is true, then columns won't be prefixed with table name
- * ^ Temporarily disabled behaviour, see comments within method for a reasoning
- */
- buildSelection(fields, { isSingleTable = false } = {}) {
- const columnsLen = fields.length;
- const chunks = fields.flatMap(({ field }, i) => {
- const chunk = [];
- if (is(field, SQL.Aliased) && field.isSelectionField) {
- chunk.push(sql.identifier(field.fieldAlias));
- } else if (is(field, SQL.Aliased) || is(field, SQL)) {
- const query = is(field, SQL.Aliased) ? field.sql : field;
- chunk.push(query);
- if (is(field, SQL.Aliased)) {
- chunk.push(sql` as ${sql.identifier(field.fieldAlias)}`);
- }
- } else if (is(field, Column)) {
- chunk.push(field);
- } else if (is(field, Subquery)) {
- const entries = Object.entries(field._.selectedFields);
- if (entries.length === 1) {
- const entry = entries[0][1];
- const fieldDecoder = is(entry, SQL) ? entry.decoder : is(entry, Column) ? { mapFromDriverValue: (v) => entry.mapFromDriverValue(v) } : entry.sql.decoder;
- if (fieldDecoder) {
- field._.sql.decoder = fieldDecoder;
- }
- }
- chunk.push(field);
- }
- if (i < columnsLen - 1) {
- chunk.push(sql`, `);
- }
- return chunk;
- });
- return sql.join(chunks);
- }
- buildJoins(joins) {
- if (!joins || joins.length === 0) {
- return void 0;
- }
- const joinsArray = [];
- for (const [index, joinMeta] of joins.entries()) {
- if (index === 0) {
- joinsArray.push(sql` `);
- }
- const table = joinMeta.table;
- const lateralSql = joinMeta.lateral ? sql` lateral` : void 0;
- const onSql = joinMeta.on ? sql` on ${joinMeta.on}` : void 0;
- if (is(table, GelTable)) {
- const tableName = table[GelTable.Symbol.Name];
- const tableSchema = table[GelTable.Symbol.Schema];
- const origTableName = table[GelTable.Symbol.OriginalName];
- const alias = tableName === origTableName ? void 0 : joinMeta.alias;
- joinsArray.push(
- sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${tableSchema ? sql`${sql.identifier(tableSchema)}.` : void 0}${sql.identifier(origTableName)}${alias && sql` ${sql.identifier(alias)}`}${onSql}`
- );
- } else if (is(table, View)) {
- const viewName = table[ViewBaseConfig].name;
- const viewSchema = table[ViewBaseConfig].schema;
- const origViewName = table[ViewBaseConfig].originalName;
- const alias = viewName === origViewName ? void 0 : joinMeta.alias;
- joinsArray.push(
- sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${viewSchema ? sql`${sql.identifier(viewSchema)}.` : void 0}${sql.identifier(origViewName)}${alias && sql` ${sql.identifier(alias)}`}${onSql}`
- );
- } else {
- joinsArray.push(
- sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${table}${onSql}`
- );
- }
- if (index < joins.length - 1) {
- joinsArray.push(sql` `);
- }
- }
- return sql.join(joinsArray);
- }
- buildFromTable(table) {
- if (is(table, Table) && table[Table.Symbol.OriginalName] !== table[Table.Symbol.Name]) {
- let fullName = sql`${sql.identifier(table[Table.Symbol.OriginalName])}`;
- if (table[Table.Symbol.Schema]) {
- fullName = sql`${sql.identifier(table[Table.Symbol.Schema])}.${fullName}`;
- }
- return sql`${fullName} ${sql.identifier(table[Table.Symbol.Name])}`;
- }
- return table;
- }
- buildSelectQuery({
- withList,
- fields,
- fieldsFlat,
- where,
- having,
- table,
- joins,
- orderBy,
- groupBy,
- limit,
- offset,
- lockingClause,
- distinct,
- setOperators
- }) {
- const fieldsList = fieldsFlat ?? orderSelectedFields(fields);
- for (const f of fieldsList) {
- if (is(f.field, Column) && getTableName(f.field.table) !== (is(table, Subquery) ? table._.alias : is(table, GelViewBase) ? table[ViewBaseConfig].name : is(table, SQL) ? void 0 : getTableName(table)) && !((table2) => joins?.some(
- ({ alias }) => alias === (table2[Table.Symbol.IsAlias] ? getTableName(table2) : table2[Table.Symbol.BaseName])
- ))(f.field.table)) {
- const tableName = getTableName(f.field.table);
- throw new Error(
- `Your "${f.path.join("->")}" field references a column "${tableName}"."${f.field.name}", but the table "${tableName}" is not part of the query! Did you forget to join it?`
- );
- }
- }
- const isSingleTable = !joins || joins.length === 0;
- const withSql = this.buildWithCTE(withList);
- let distinctSql;
- if (distinct) {
- distinctSql = distinct === true ? sql` distinct` : sql` distinct on (${sql.join(distinct.on, sql`, `)})`;
- }
- const selection = this.buildSelection(fieldsList, { isSingleTable });
- const tableSql = this.buildFromTable(table);
- const joinsSql = this.buildJoins(joins);
- const whereSql = where ? sql` where ${where}` : void 0;
- const havingSql = having ? sql` having ${having}` : void 0;
- let orderBySql;
- if (orderBy && orderBy.length > 0) {
- orderBySql = sql` order by ${sql.join(orderBy, sql`, `)}`;
- }
- let groupBySql;
- if (groupBy && groupBy.length > 0) {
- groupBySql = sql` group by ${sql.join(groupBy, sql`, `)}`;
- }
- const limitSql = typeof limit === "object" || typeof limit === "number" && limit >= 0 ? sql` limit ${limit}` : void 0;
- const offsetSql = offset ? sql` offset ${offset}` : void 0;
- const lockingClauseSql = sql.empty();
- if (lockingClause) {
- const clauseSql = sql` for ${sql.raw(lockingClause.strength)}`;
- if (lockingClause.config.of) {
- clauseSql.append(
- sql` of ${sql.join(
- Array.isArray(lockingClause.config.of) ? lockingClause.config.of : [lockingClause.config.of],
- sql`, `
- )}`
- );
- }
- if (lockingClause.config.noWait) {
- clauseSql.append(sql` nowait`);
- } else if (lockingClause.config.skipLocked) {
- clauseSql.append(sql` skip locked`);
- }
- lockingClauseSql.append(clauseSql);
- }
- const finalQuery = sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClauseSql}`;
- if (setOperators.length > 0) {
- return this.buildSetOperations(finalQuery, setOperators);
- }
- return finalQuery;
- }
- buildSetOperations(leftSelect, setOperators) {
- const [setOperator, ...rest] = setOperators;
- if (!setOperator) {
- throw new Error("Cannot pass undefined values to any set operator");
- }
- if (rest.length === 0) {
- return this.buildSetOperationQuery({ leftSelect, setOperator });
- }
- return this.buildSetOperations(
- this.buildSetOperationQuery({ leftSelect, setOperator }),
- rest
- );
- }
- buildSetOperationQuery({
- leftSelect,
- setOperator: { type, isAll, rightSelect, limit, orderBy, offset }
- }) {
- const leftChunk = sql`(${leftSelect.getSQL()}) `;
- const rightChunk = sql`(${rightSelect.getSQL()})`;
- let orderBySql;
- if (orderBy && orderBy.length > 0) {
- const orderByValues = [];
- for (const singleOrderBy of orderBy) {
- if (is(singleOrderBy, GelColumn)) {
- orderByValues.push(sql.identifier(singleOrderBy.name));
- } else if (is(singleOrderBy, SQL)) {
- for (let i = 0; i < singleOrderBy.queryChunks.length; i++) {
- const chunk = singleOrderBy.queryChunks[i];
- if (is(chunk, GelColumn)) {
- singleOrderBy.queryChunks[i] = sql.identifier(chunk.name);
- }
- }
- orderByValues.push(sql`${singleOrderBy}`);
- } else {
- orderByValues.push(sql`${singleOrderBy}`);
- }
- }
- orderBySql = sql` order by ${sql.join(orderByValues, sql`, `)} `;
- }
- const limitSql = typeof limit === "object" || typeof limit === "number" && limit >= 0 ? sql` limit ${limit}` : void 0;
- const operatorChunk = sql.raw(`${type} ${isAll ? "all " : ""}`);
- const offsetSql = offset ? sql` offset ${offset}` : void 0;
- return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`;
- }
- buildInsertQuery({ table, values: valuesOrSelect, onConflict, returning, withList, select, overridingSystemValue_ }) {
- const valuesSqlList = [];
- const columns = table[Table.Symbol.Columns];
- const colEntries = Object.entries(columns).filter(([_, col]) => !col.shouldDisableInsert());
- const insertOrder = colEntries.map(
- ([, column]) => sql.identifier(this.casing.getColumnCasing(column))
- );
- if (select) {
- const select2 = valuesOrSelect;
- if (is(select2, SQL)) {
- valuesSqlList.push(select2);
- } else {
- valuesSqlList.push(select2.getSQL());
- }
- } else {
- const values = valuesOrSelect;
- valuesSqlList.push(sql.raw("values "));
- for (const [valueIndex, value] of values.entries()) {
- const valueList = [];
- for (const [fieldName, col] of colEntries) {
- const colValue = value[fieldName];
- if (colValue === void 0 || is(colValue, Param) && colValue.value === void 0) {
- if (col.defaultFn !== void 0) {
- const defaultFnResult = col.defaultFn();
- const defaultValue = is(defaultFnResult, SQL) ? defaultFnResult : sql.param(defaultFnResult, col);
- valueList.push(defaultValue);
- } else if (!col.default && col.onUpdateFn !== void 0) {
- const onUpdateFnResult = col.onUpdateFn();
- const newValue = is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col);
- valueList.push(newValue);
- } else {
- valueList.push(sql`default`);
- }
- } else {
- valueList.push(colValue);
- }
- }
- valuesSqlList.push(valueList);
- if (valueIndex < values.length - 1) {
- valuesSqlList.push(sql`, `);
- }
- }
- }
- const withSql = this.buildWithCTE(withList);
- const valuesSql = sql.join(valuesSqlList);
- const returningSql = returning ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` : void 0;
- const onConflictSql = onConflict ? sql` on conflict ${onConflict}` : void 0;
- const overridingSql = overridingSystemValue_ === true ? sql`overriding system value ` : void 0;
- return sql`${withSql}insert into ${table} ${insertOrder} ${overridingSql}${valuesSql}${onConflictSql}${returningSql}`;
- }
- buildRefreshMaterializedViewQuery({ view, concurrently, withNoData }) {
- const concurrentlySql = concurrently ? sql` concurrently` : void 0;
- const withNoDataSql = withNoData ? sql` with no data` : void 0;
- return sql`refresh materialized view${concurrentlySql} ${view}${withNoDataSql}`;
- }
- prepareTyping(encoder) {
- if (is(encoder, GelJson)) {
- return "json";
- } else if (is(encoder, GelDecimal)) {
- return "decimal";
- } else if (is(encoder, GelTimestamp)) {
- return "timestamp";
- } else if (is(encoder, GelUUID)) {
- return "uuid";
- } else {
- return "none";
- }
- }
- sqlToQuery(sql2, invokeSource) {
- return sql2.toQuery({
- casing: this.casing,
- escapeName: this.escapeName,
- escapeParam: this.escapeParam,
- escapeString: this.escapeString,
- prepareTyping: this.prepareTyping,
- invokeSource
- });
- }
- // buildRelationalQueryWithPK({
- // fullSchema,
- // schema,
- // tableNamesMap,
- // table,
- // tableConfig,
- // queryConfig: config,
- // tableAlias,
- // isRoot = false,
- // joinOn,
- // }: {
- // fullSchema: Record<string, unknown>;
- // schema: TablesRelationalConfig;
- // tableNamesMap: Record<string, string>;
- // table: GelTable;
- // tableConfig: TableRelationalConfig;
- // queryConfig: true | DBQueryConfig<'many', true>;
- // tableAlias: string;
- // isRoot?: boolean;
- // joinOn?: SQL;
- // }): BuildRelationalQueryResult<GelTable, GelColumn> {
- // // For { "<relation>": true }, return a table with selection of all columns
- // if (config === true) {
- // const selectionEntries = Object.entries(tableConfig.columns);
- // const selection: BuildRelationalQueryResult<GelTable, GelColumn>['selection'] = selectionEntries.map((
- // [key, value],
- // ) => ({
- // dbKey: value.name,
- // tsKey: key,
- // field: value as GelColumn,
- // relationTableTsKey: undefined,
- // isJson: false,
- // selection: [],
- // }));
- // return {
- // tableTsKey: tableConfig.tsName,
- // sql: table,
- // selection,
- // };
- // }
- // // let selection: BuildRelationalQueryResult<GelTable, GelColumn>['selection'] = [];
- // // let selectionForBuild = selection;
- // const aliasedColumns = Object.fromEntries(
- // Object.entries(tableConfig.columns).map(([key, value]) => [key, aliasedTableColumn(value, tableAlias)]),
- // );
- // const aliasedRelations = Object.fromEntries(
- // Object.entries(tableConfig.relations).map(([key, value]) => [key, aliasedRelation(value, tableAlias)]),
- // );
- // const aliasedFields = Object.assign({}, aliasedColumns, aliasedRelations);
- // let where, hasUserDefinedWhere;
- // if (config.where) {
- // const whereSql = typeof config.where === 'function' ? config.where(aliasedFields, operators) : config.where;
- // where = whereSql && mapColumnsInSQLToAlias(whereSql, tableAlias);
- // hasUserDefinedWhere = !!where;
- // }
- // where = and(joinOn, where);
- // // const fieldsSelection: { tsKey: string; value: GelColumn | SQL.Aliased; isExtra?: boolean }[] = [];
- // let joins: Join[] = [];
- // let selectedColumns: string[] = [];
- // // Figure out which columns to select
- // if (config.columns) {
- // let isIncludeMode = false;
- // for (const [field, value] of Object.entries(config.columns)) {
- // if (value === undefined) {
- // continue;
- // }
- // if (field in tableConfig.columns) {
- // if (!isIncludeMode && value === true) {
- // isIncludeMode = true;
- // }
- // selectedColumns.push(field);
- // }
- // }
- // if (selectedColumns.length > 0) {
- // selectedColumns = isIncludeMode
- // ? selectedColumns.filter((c) => config.columns?.[c] === true)
- // : Object.keys(tableConfig.columns).filter((key) => !selectedColumns.includes(key));
- // }
- // } else {
- // // Select all columns if selection is not specified
- // selectedColumns = Object.keys(tableConfig.columns);
- // }
- // // for (const field of selectedColumns) {
- // // const column = tableConfig.columns[field]! as GelColumn;
- // // fieldsSelection.push({ tsKey: field, value: column });
- // // }
- // let initiallySelectedRelations: {
- // tsKey: string;
- // queryConfig: true | DBQueryConfig<'many', false>;
- // relation: Relation;
- // }[] = [];
- // // let selectedRelations: BuildRelationalQueryResult<GelTable, GelColumn>['selection'] = [];
- // // Figure out which relations to select
- // if (config.with) {
- // initiallySelectedRelations = Object.entries(config.with)
- // .filter((entry): entry is [typeof entry[0], NonNullable<typeof entry[1]>] => !!entry[1])
- // .map(([tsKey, queryConfig]) => ({ tsKey, queryConfig, relation: tableConfig.relations[tsKey]! }));
- // }
- // const manyRelations = initiallySelectedRelations.filter((r) =>
- // is(r.relation, Many)
- // && (schema[tableNamesMap[r.relation.referencedTable[Table.Symbol.Name]]!]?.primaryKey.length ?? 0) > 0
- // );
- // // If this is the last Many relation (or there are no Many relations), we are on the innermost subquery level
- // const isInnermostQuery = manyRelations.length < 2;
- // const selectedExtras: {
- // tsKey: string;
- // value: SQL.Aliased;
- // }[] = [];
- // // Figure out which extras to select
- // if (isInnermostQuery && config.extras) {
- // const extras = typeof config.extras === 'function'
- // ? config.extras(aliasedFields, { sql })
- // : config.extras;
- // for (const [tsKey, value] of Object.entries(extras)) {
- // selectedExtras.push({
- // tsKey,
- // value: mapColumnsInAliasedSQLToAlias(value, tableAlias),
- // });
- // }
- // }
- // // Transform `fieldsSelection` into `selection`
- // // `fieldsSelection` shouldn't be used after this point
- // // for (const { tsKey, value, isExtra } of fieldsSelection) {
- // // selection.push({
- // // dbKey: is(value, SQL.Aliased) ? value.fieldAlias : tableConfig.columns[tsKey]!.name,
- // // tsKey,
- // // field: is(value, Column) ? aliasedTableColumn(value, tableAlias) : value,
- // // relationTableTsKey: undefined,
- // // isJson: false,
- // // isExtra,
- // // selection: [],
- // // });
- // // }
- // let orderByOrig = typeof config.orderBy === 'function'
- // ? config.orderBy(aliasedFields, orderByOperators)
- // : config.orderBy ?? [];
- // if (!Array.isArray(orderByOrig)) {
- // orderByOrig = [orderByOrig];
- // }
- // const orderBy = orderByOrig.map((orderByValue) => {
- // if (is(orderByValue, Column)) {
- // return aliasedTableColumn(orderByValue, tableAlias) as GelColumn;
- // }
- // return mapColumnsInSQLToAlias(orderByValue, tableAlias);
- // });
- // const limit = isInnermostQuery ? config.limit : undefined;
- // const offset = isInnermostQuery ? config.offset : undefined;
- // // For non-root queries without additional config except columns, return a table with selection
- // if (
- // !isRoot
- // && initiallySelectedRelations.length === 0
- // && selectedExtras.length === 0
- // && !where
- // && orderBy.length === 0
- // && limit === undefined
- // && offset === undefined
- // ) {
- // return {
- // tableTsKey: tableConfig.tsName,
- // sql: table,
- // selection: selectedColumns.map((key) => ({
- // dbKey: tableConfig.columns[key]!.name,
- // tsKey: key,
- // field: tableConfig.columns[key] as GelColumn,
- // relationTableTsKey: undefined,
- // isJson: false,
- // selection: [],
- // })),
- // };
- // }
- // const selectedRelationsWithoutPK:
- // // Process all relations without primary keys, because they need to be joined differently and will all be on the same query level
- // for (
- // const {
- // tsKey: selectedRelationTsKey,
- // queryConfig: selectedRelationConfigValue,
- // relation,
- // } of initiallySelectedRelations
- // ) {
- // const normalizedRelation = normalizeRelation(schema, tableNamesMap, relation);
- // const relationTableName = relation.referencedTable[Table.Symbol.Name];
- // const relationTableTsName = tableNamesMap[relationTableName]!;
- // const relationTable = schema[relationTableTsName]!;
- // if (relationTable.primaryKey.length > 0) {
- // continue;
- // }
- // const relationTableAlias = `${tableAlias}_${selectedRelationTsKey}`;
- // const joinOn = and(
- // ...normalizedRelation.fields.map((field, i) =>
- // eq(
- // aliasedTableColumn(normalizedRelation.references[i]!, relationTableAlias),
- // aliasedTableColumn(field, tableAlias),
- // )
- // ),
- // );
- // const builtRelation = this.buildRelationalQueryWithoutPK({
- // fullSchema,
- // schema,
- // tableNamesMap,
- // table: fullSchema[relationTableTsName] as GelTable,
- // tableConfig: schema[relationTableTsName]!,
- // queryConfig: selectedRelationConfigValue,
- // tableAlias: relationTableAlias,
- // joinOn,
- // nestedQueryRelation: relation,
- // });
- // const field = sql`${sql.identifier(relationTableAlias)}.${sql.identifier('data')}`.as(selectedRelationTsKey);
- // joins.push({
- // on: sql`true`,
- // table: new Subquery(builtRelation.sql as SQL, {}, relationTableAlias),
- // alias: relationTableAlias,
- // joinType: 'left',
- // lateral: true,
- // });
- // selectedRelations.push({
- // dbKey: selectedRelationTsKey,
- // tsKey: selectedRelationTsKey,
- // field,
- // relationTableTsKey: relationTableTsName,
- // isJson: true,
- // selection: builtRelation.selection,
- // });
- // }
- // const oneRelations = initiallySelectedRelations.filter((r): r is typeof r & { relation: One } =>
- // is(r.relation, One)
- // );
- // // Process all One relations with PKs, because they can all be joined on the same level
- // for (
- // const {
- // tsKey: selectedRelationTsKey,
- // queryConfig: selectedRelationConfigValue,
- // relation,
- // } of oneRelations
- // ) {
- // const normalizedRelation = normalizeRelation(schema, tableNamesMap, relation);
- // const relationTableName = relation.referencedTable[Table.Symbol.Name];
- // const relationTableTsName = tableNamesMap[relationTableName]!;
- // const relationTableAlias = `${tableAlias}_${selectedRelationTsKey}`;
- // const relationTable = schema[relationTableTsName]!;
- // if (relationTable.primaryKey.length === 0) {
- // continue;
- // }
- // const joinOn = and(
- // ...normalizedRelation.fields.map((field, i) =>
- // eq(
- // aliasedTableColumn(normalizedRelation.references[i]!, relationTableAlias),
- // aliasedTableColumn(field, tableAlias),
- // )
- // ),
- // );
- // const builtRelation = this.buildRelationalQueryWithPK({
- // fullSchema,
- // schema,
- // tableNamesMap,
- // table: fullSchema[relationTableTsName] as GelTable,
- // tableConfig: schema[relationTableTsName]!,
- // queryConfig: selectedRelationConfigValue,
- // tableAlias: relationTableAlias,
- // joinOn,
- // });
- // const field = sql`case when ${sql.identifier(relationTableAlias)} is null then null else json_build_array(${
- // sql.join(
- // builtRelation.selection.map(({ field }) =>
- // is(field, SQL.Aliased)
- // ? sql`${sql.identifier(relationTableAlias)}.${sql.identifier(field.fieldAlias)}`
- // : is(field, Column)
- // ? aliasedTableColumn(field, relationTableAlias)
- // : field
- // ),
- // sql`, `,
- // )
- // }) end`.as(selectedRelationTsKey);
- // const isLateralJoin = is(builtRelation.sql, SQL);
- // joins.push({
- // on: isLateralJoin ? sql`true` : joinOn,
- // table: is(builtRelation.sql, SQL)
- // ? new Subquery(builtRelation.sql, {}, relationTableAlias)
- // : aliasedTable(builtRelation.sql, relationTableAlias),
- // alias: relationTableAlias,
- // joinType: 'left',
- // lateral: is(builtRelation.sql, SQL),
- // });
- // selectedRelations.push({
- // dbKey: selectedRelationTsKey,
- // tsKey: selectedRelationTsKey,
- // field,
- // relationTableTsKey: relationTableTsName,
- // isJson: true,
- // selection: builtRelation.selection,
- // });
- // }
- // let distinct: GelSelectConfig['distinct'];
- // let tableFrom: GelTable | Subquery = table;
- // // Process first Many relation - each one requires a nested subquery
- // const manyRelation = manyRelations[0];
- // if (manyRelation) {
- // const {
- // tsKey: selectedRelationTsKey,
- // queryConfig: selectedRelationQueryConfig,
- // relation,
- // } = manyRelation;
- // distinct = {
- // on: tableConfig.primaryKey.map((c) => aliasedTableColumn(c as GelColumn, tableAlias)),
- // };
- // const normalizedRelation = normalizeRelation(schema, tableNamesMap, relation);
- // const relationTableName = relation.referencedTable[Table.Symbol.Name];
- // const relationTableTsName = tableNamesMap[relationTableName]!;
- // const relationTableAlias = `${tableAlias}_${selectedRelationTsKey}`;
- // const joinOn = and(
- // ...normalizedRelation.fields.map((field, i) =>
- // eq(
- // aliasedTableColumn(normalizedRelation.references[i]!, relationTableAlias),
- // aliasedTableColumn(field, tableAlias),
- // )
- // ),
- // );
- // const builtRelationJoin = this.buildRelationalQueryWithPK({
- // fullSchema,
- // schema,
- // tableNamesMap,
- // table: fullSchema[relationTableTsName] as GelTable,
- // tableConfig: schema[relationTableTsName]!,
- // queryConfig: selectedRelationQueryConfig,
- // tableAlias: relationTableAlias,
- // joinOn,
- // });
- // const builtRelationSelectionField = sql`case when ${
- // sql.identifier(relationTableAlias)
- // } is null then '[]' else json_agg(json_build_array(${
- // sql.join(
- // builtRelationJoin.selection.map(({ field }) =>
- // is(field, SQL.Aliased)
- // ? sql`${sql.identifier(relationTableAlias)}.${sql.identifier(field.fieldAlias)}`
- // : is(field, Column)
- // ? aliasedTableColumn(field, relationTableAlias)
- // : field
- // ),
- // sql`, `,
- // )
- // })) over (partition by ${sql.join(distinct.on, sql`, `)}) end`.as(selectedRelationTsKey);
- // const isLateralJoin = is(builtRelationJoin.sql, SQL);
- // joins.push({
- // on: isLateralJoin ? sql`true` : joinOn,
- // table: isLateralJoin
- // ? new Subquery(builtRelationJoin.sql as SQL, {}, relationTableAlias)
- // : aliasedTable(builtRelationJoin.sql as GelTable, relationTableAlias),
- // alias: relationTableAlias,
- // joinType: 'left',
- // lateral: isLateralJoin,
- // });
- // // Build the "from" subquery with the remaining Many relations
- // const builtTableFrom = this.buildRelationalQueryWithPK({
- // fullSchema,
- // schema,
- // tableNamesMap,
- // table,
- // tableConfig,
- // queryConfig: {
- // ...config,
- // where: undefined,
- // orderBy: undefined,
- // limit: undefined,
- // offset: undefined,
- // with: manyRelations.slice(1).reduce<NonNullable<typeof config['with']>>(
- // (result, { tsKey, queryConfig: configValue }) => {
- // result[tsKey] = configValue;
- // return result;
- // },
- // {},
- // ),
- // },
- // tableAlias,
- // });
- // selectedRelations.push({
- // dbKey: selectedRelationTsKey,
- // tsKey: selectedRelationTsKey,
- // field: builtRelationSelectionField,
- // relationTableTsKey: relationTableTsName,
- // isJson: true,
- // selection: builtRelationJoin.selection,
- // });
- // // selection = builtTableFrom.selection.map((item) =>
- // // is(item.field, SQL.Aliased)
- // // ? { ...item, field: sql`${sql.identifier(tableAlias)}.${sql.identifier(item.field.fieldAlias)}` }
- // // : item
- // // );
- // // selectionForBuild = [{
- // // dbKey: '*',
- // // tsKey: '*',
- // // field: sql`${sql.identifier(tableAlias)}.*`,
- // // selection: [],
- // // isJson: false,
- // // relationTableTsKey: undefined,
- // // }];
- // // const newSelectionItem: (typeof selection)[number] = {
- // // dbKey: selectedRelationTsKey,
- // // tsKey: selectedRelationTsKey,
- // // field,
- // // relationTableTsKey: relationTableTsName,
- // // isJson: true,
- // // selection: builtRelationJoin.selection,
- // // };
- // // selection.push(newSelectionItem);
- // // selectionForBuild.push(newSelectionItem);
- // tableFrom = is(builtTableFrom.sql, GelTable)
- // ? builtTableFrom.sql
- // : new Subquery(builtTableFrom.sql, {}, tableAlias);
- // }
- // if (selectedColumns.length === 0 && selectedRelations.length === 0 && selectedExtras.length === 0) {
- // throw new DrizzleError(`No fields selected for table "${tableConfig.tsName}" ("${tableAlias}")`);
- // }
- // let selection: BuildRelationalQueryResult<GelTable, GelColumn>['selection'];
- // function prepareSelectedColumns() {
- // return selectedColumns.map((key) => ({
- // dbKey: tableConfig.columns[key]!.name,
- // tsKey: key,
- // field: tableConfig.columns[key] as GelColumn,
- // relationTableTsKey: undefined,
- // isJson: false,
- // selection: [],
- // }));
- // }
- // function prepareSelectedExtras() {
- // return selectedExtras.map((item) => ({
- // dbKey: item.value.fieldAlias,
- // tsKey: item.tsKey,
- // field: item.value,
- // relationTableTsKey: undefined,
- // isJson: false,
- // selection: [],
- // }));
- // }
- // if (isRoot) {
- // selection = [
- // ...prepareSelectedColumns(),
- // ...prepareSelectedExtras(),
- // ];
- // }
- // if (hasUserDefinedWhere || orderBy.length > 0) {
- // tableFrom = new Subquery(
- // this.buildSelectQuery({
- // table: is(tableFrom, GelTable) ? aliasedTable(tableFrom, tableAlias) : tableFrom,
- // fields: {},
- // fieldsFlat: selectionForBuild.map(({ field }) => ({
- // path: [],
- // field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field,
- // })),
- // joins,
- // distinct,
- // }),
- // {},
- // tableAlias,
- // );
- // selectionForBuild = selection.map((item) =>
- // is(item.field, SQL.Aliased)
- // ? { ...item, field: sql`${sql.identifier(tableAlias)}.${sql.identifier(item.field.fieldAlias)}` }
- // : item
- // );
- // joins = [];
- // distinct = undefined;
- // }
- // const result = this.buildSelectQuery({
- // table: is(tableFrom, GelTable) ? aliasedTable(tableFrom, tableAlias) : tableFrom,
- // fields: {},
- // fieldsFlat: selectionForBuild.map(({ field }) => ({
- // path: [],
- // field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field,
- // })),
- // where,
- // limit,
- // offset,
- // joins,
- // orderBy,
- // distinct,
- // });
- // return {
- // tableTsKey: tableConfig.tsName,
- // sql: result,
- // selection,
- // };
- // }
- buildRelationalQueryWithoutPK({
- fullSchema,
- schema,
- tableNamesMap,
- table,
- tableConfig,
- queryConfig: config,
- tableAlias,
- nestedQueryRelation,
- joinOn
- }) {
- let selection = [];
- let limit, offset, orderBy = [], where;
- const joins = [];
- if (config === true) {
- const selectionEntries = Object.entries(tableConfig.columns);
- selection = selectionEntries.map(([key, value]) => ({
- dbKey: value.name,
- tsKey: key,
- field: aliasedTableColumn(value, tableAlias),
- relationTableTsKey: void 0,
- isJson: false,
- selection: []
- }));
- } else {
- const aliasedColumns = Object.fromEntries(
- Object.entries(tableConfig.columns).map(([key, value]) => [key, aliasedTableColumn(value, tableAlias)])
- );
- if (config.where) {
- const whereSql = typeof config.where === "function" ? config.where(aliasedColumns, getOperators()) : config.where;
- where = whereSql && mapColumnsInSQLToAlias(whereSql, tableAlias);
- }
- const fieldsSelection = [];
- let selectedColumns = [];
- if (config.columns) {
- let isIncludeMode = false;
- for (const [field, value] of Object.entries(config.columns)) {
- if (value === void 0) {
- continue;
- }
- if (field in tableConfig.columns) {
- if (!isIncludeMode && value === true) {
- isIncludeMode = true;
- }
- selectedColumns.push(field);
- }
- }
- if (selectedColumns.length > 0) {
- selectedColumns = isIncludeMode ? selectedColumns.filter((c) => config.columns?.[c] === true) : Object.keys(tableConfig.columns).filter((key) => !selectedColumns.includes(key));
- }
- } else {
- selectedColumns = Object.keys(tableConfig.columns);
- }
- for (const field of selectedColumns) {
- const column = tableConfig.columns[field];
- fieldsSelection.push({ tsKey: field, value: column });
- }
- let selectedRelations = [];
- if (config.with) {
- selectedRelations = Object.entries(config.with).filter((entry) => !!entry[1]).map(([tsKey, queryConfig]) => ({ tsKey, queryConfig, relation: tableConfig.relations[tsKey] }));
- }
- let extras;
- if (config.extras) {
- extras = typeof config.extras === "function" ? config.extras(aliasedColumns, { sql }) : config.extras;
- for (const [tsKey, value] of Object.entries(extras)) {
- fieldsSelection.push({
- tsKey,
- value: mapColumnsInAliasedSQLToAlias(value, tableAlias)
- });
- }
- }
- for (const { tsKey, value } of fieldsSelection) {
- selection.push({
- dbKey: is(value, SQL.Aliased) ? value.fieldAlias : tableConfig.columns[tsKey].name,
- tsKey,
- field: is(value, Column) ? aliasedTableColumn(value, tableAlias) : value,
- relationTableTsKey: void 0,
- isJson: false,
- selection: []
- });
- }
- let orderByOrig = typeof config.orderBy === "function" ? config.orderBy(aliasedColumns, getOrderByOperators()) : config.orderBy ?? [];
- if (!Array.isArray(orderByOrig)) {
- orderByOrig = [orderByOrig];
- }
- orderBy = orderByOrig.map((orderByValue) => {
- if (is(orderByValue, Column)) {
- return aliasedTableColumn(orderByValue, tableAlias);
- }
- return mapColumnsInSQLToAlias(orderByValue, tableAlias);
- });
- limit = config.limit;
- offset = config.offset;
- for (const {
- tsKey: selectedRelationTsKey,
- queryConfig: selectedRelationConfigValue,
- relation
- } of selectedRelations) {
- const normalizedRelation = normalizeRelation(schema, tableNamesMap, relation);
- const relationTableName = getTableUniqueName(relation.referencedTable);
- const relationTableTsName = tableNamesMap[relationTableName];
- const relationTableAlias = `${tableAlias}_${selectedRelationTsKey}`;
- const joinOn2 = and(
- ...normalizedRelation.fields.map(
- (field2, i) => eq(
- aliasedTableColumn(normalizedRelation.references[i], relationTableAlias),
- aliasedTableColumn(field2, tableAlias)
- )
- )
- );
- const builtRelation = this.buildRelationalQueryWithoutPK({
- fullSchema,
- schema,
- tableNamesMap,
- table: fullSchema[relationTableTsName],
- tableConfig: schema[relationTableTsName],
- queryConfig: is(relation, One) ? selectedRelationConfigValue === true ? { limit: 1 } : { ...selectedRelationConfigValue, limit: 1 } : selectedRelationConfigValue,
- tableAlias: relationTableAlias,
- joinOn: joinOn2,
- nestedQueryRelation: relation
- });
- const field = sql`${sql.identifier(relationTableAlias)}.${sql.identifier("data")}`.as(selectedRelationTsKey);
- joins.push({
- on: sql`true`,
- table: new Subquery(builtRelation.sql, {}, relationTableAlias),
- alias: relationTableAlias,
- joinType: "left",
- lateral: true
- });
- selection.push({
- dbKey: selectedRelationTsKey,
- tsKey: selectedRelationTsKey,
- field,
- relationTableTsKey: relationTableTsName,
- isJson: true,
- selection: builtRelation.selection
- });
- }
- }
- if (selection.length === 0) {
- throw new DrizzleError({ message: `No fields selected for table "${tableConfig.tsName}" ("${tableAlias}")` });
- }
- let result;
- where = and(joinOn, where);
- if (nestedQueryRelation) {
- let field = sql`json_build_array(${sql.join(
- selection.map(
- ({ field: field2, tsKey, isJson }) => isJson ? sql`${sql.identifier(`${tableAlias}_${tsKey}`)}.${sql.identifier("data")}` : is(field2, SQL.Aliased) ? field2.sql : field2
- ),
- sql`, `
- )})`;
- if (is(nestedQueryRelation, Many)) {
- field = sql`coalesce(json_agg(${field}${orderBy.length > 0 ? sql` order by ${sql.join(orderBy, sql`, `)}` : void 0}), '[]'::json)`;
- }
- const nestedSelection = [{
- dbKey: "data",
- tsKey: "data",
- field: field.as("data"),
- isJson: true,
- relationTableTsKey: tableConfig.tsName,
- selection
- }];
- const needsSubquery = limit !== void 0 || offset !== void 0 || orderBy.length > 0;
- if (needsSubquery) {
- result = this.buildSelectQuery({
- table: aliasedTable(table, tableAlias),
- fields: {},
- fieldsFlat: [{
- path: [],
- field: sql.raw("*")
- }],
- where,
- limit,
- offset,
- orderBy,
- setOperators: []
- });
- where = void 0;
- limit = void 0;
- offset = void 0;
- orderBy = [];
- } else {
- result = aliasedTable(table, tableAlias);
- }
- result = this.buildSelectQuery({
- table: is(result, GelTable) ? result : new Subquery(result, {}, tableAlias),
- fields: {},
- fieldsFlat: nestedSelection.map(({ field: field2 }) => ({
- path: [],
- field: is(field2, Column) ? aliasedTableColumn(field2, tableAlias) : field2
- })),
- joins,
- where,
- limit,
- offset,
- orderBy,
- setOperators: []
- });
- } else {
- result = this.buildSelectQuery({
- table: aliasedTable(table, tableAlias),
- fields: {},
- fieldsFlat: selection.map(({ field }) => ({
- path: [],
- field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field
- })),
- joins,
- where,
- limit,
- offset,
- orderBy,
- setOperators: []
- });
- }
- return {
- tableTsKey: tableConfig.tsName,
- sql: result,
- selection
- };
- }
- }
- export {
- GelDialect
- };
- //# sourceMappingURL=dialect.js.map
|