dialect.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. import { aliasedTable, aliasedTableColumn, mapColumnsInAliasedSQLToAlias, mapColumnsInSQLToAlias } from "../alias.js";
  2. import { CasingCache } from "../casing.js";
  3. import { Column } from "../column.js";
  4. import { entityKind, is } from "../entity.js";
  5. import { DrizzleError } from "../errors.js";
  6. import {
  7. getOperators,
  8. getOrderByOperators,
  9. Many,
  10. normalizeRelation,
  11. One
  12. } from "../relations.js";
  13. import { and, eq } from "../sql/expressions/index.js";
  14. import { Param, SQL, sql, View } from "../sql/sql.js";
  15. import { Subquery } from "../subquery.js";
  16. import { getTableName, getTableUniqueName, Table } from "../table.js";
  17. import { orderSelectedFields } from "../utils.js";
  18. import { ViewBaseConfig } from "../view-common.js";
  19. import { SingleStoreColumn } from "./columns/common.js";
  20. import { SingleStoreTable } from "./table.js";
  21. class SingleStoreDialect {
  22. static [entityKind] = "SingleStoreDialect";
  23. /** @internal */
  24. casing;
  25. constructor(config) {
  26. this.casing = new CasingCache(config?.casing);
  27. }
  28. async migrate(migrations, session, config) {
  29. const migrationsTable = config.migrationsTable ?? "__drizzle_migrations";
  30. const migrationTableCreate = sql`
  31. create table if not exists ${sql.identifier(migrationsTable)} (
  32. id serial primary key,
  33. hash text not null,
  34. created_at bigint
  35. )
  36. `;
  37. await session.execute(migrationTableCreate);
  38. const dbMigrations = await session.all(
  39. sql`select id, hash, created_at from ${sql.identifier(migrationsTable)} order by created_at desc limit 1`
  40. );
  41. const lastDbMigration = dbMigrations[0];
  42. await session.transaction(async (tx) => {
  43. for (const migration of migrations) {
  44. if (!lastDbMigration || Number(lastDbMigration.created_at) < migration.folderMillis) {
  45. for (const stmt of migration.sql) {
  46. await tx.execute(sql.raw(stmt));
  47. }
  48. await tx.execute(
  49. sql`insert into ${sql.identifier(
  50. migrationsTable
  51. )} (\`hash\`, \`created_at\`) values(${migration.hash}, ${migration.folderMillis})`
  52. );
  53. }
  54. }
  55. });
  56. }
  57. escapeName(name) {
  58. return `\`${name.replace(/`/g, "``")}\``;
  59. }
  60. escapeParam(_num) {
  61. return `?`;
  62. }
  63. escapeString(str) {
  64. return `'${str.replace(/'/g, "''")}'`;
  65. }
  66. buildWithCTE(queries) {
  67. if (!queries?.length) return void 0;
  68. const withSqlChunks = [sql`with `];
  69. for (const [i, w] of queries.entries()) {
  70. withSqlChunks.push(sql`${sql.identifier(w._.alias)} as (${w._.sql})`);
  71. if (i < queries.length - 1) {
  72. withSqlChunks.push(sql`, `);
  73. }
  74. }
  75. withSqlChunks.push(sql` `);
  76. return sql.join(withSqlChunks);
  77. }
  78. buildDeleteQuery({
  79. table,
  80. where,
  81. returning,
  82. withList,
  83. limit,
  84. orderBy
  85. }) {
  86. const withSql = this.buildWithCTE(withList);
  87. const returningSql = returning ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` : void 0;
  88. const whereSql = where ? sql` where ${where}` : void 0;
  89. const orderBySql = this.buildOrderBy(orderBy);
  90. const limitSql = this.buildLimit(limit);
  91. return sql`${withSql}delete from ${table}${whereSql}${orderBySql}${limitSql}${returningSql}`;
  92. }
  93. buildUpdateSet(table, set) {
  94. const tableColumns = table[Table.Symbol.Columns];
  95. const columnNames = Object.keys(tableColumns).filter(
  96. (colName) => set[colName] !== void 0 || tableColumns[colName]?.onUpdateFn !== void 0
  97. );
  98. const setSize = columnNames.length;
  99. return sql.join(
  100. columnNames.flatMap((colName, i) => {
  101. const col = tableColumns[colName];
  102. const onUpdateFnResult = col.onUpdateFn?.();
  103. const value = set[colName] ?? (is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col));
  104. const res = sql`${sql.identifier(this.casing.getColumnCasing(col))} = ${value}`;
  105. if (i < setSize - 1) {
  106. return [res, sql.raw(", ")];
  107. }
  108. return [res];
  109. })
  110. );
  111. }
  112. buildUpdateQuery({
  113. table,
  114. set,
  115. where,
  116. returning,
  117. withList,
  118. limit,
  119. orderBy
  120. }) {
  121. const withSql = this.buildWithCTE(withList);
  122. const setSql = this.buildUpdateSet(table, set);
  123. const returningSql = returning ? sql` returning ${this.buildSelection(returning, { isSingleTable: true })}` : void 0;
  124. const whereSql = where ? sql` where ${where}` : void 0;
  125. const orderBySql = this.buildOrderBy(orderBy);
  126. const limitSql = this.buildLimit(limit);
  127. return sql`${withSql}update ${table} set ${setSql}${whereSql}${orderBySql}${limitSql}${returningSql}`;
  128. }
  129. /**
  130. * Builds selection SQL with provided fields/expressions
  131. *
  132. * Examples:
  133. *
  134. * `select <selection> from`
  135. *
  136. * `insert ... returning <selection>`
  137. *
  138. * If `isSingleTable` is true, then columns won't be prefixed with table name
  139. */
  140. buildSelection(fields, { isSingleTable = false } = {}) {
  141. const columnsLen = fields.length;
  142. const chunks = fields.flatMap(({ field }, i) => {
  143. const chunk = [];
  144. if (is(field, SQL.Aliased) && field.isSelectionField) {
  145. chunk.push(sql.identifier(field.fieldAlias));
  146. } else if (is(field, SQL.Aliased) || is(field, SQL)) {
  147. const query = is(field, SQL.Aliased) ? field.sql : field;
  148. if (isSingleTable) {
  149. chunk.push(
  150. new SQL(
  151. query.queryChunks.map((c) => {
  152. if (is(c, SingleStoreColumn)) {
  153. return sql.identifier(this.casing.getColumnCasing(c));
  154. }
  155. return c;
  156. })
  157. )
  158. );
  159. } else {
  160. chunk.push(query);
  161. }
  162. if (is(field, SQL.Aliased)) {
  163. chunk.push(sql` as ${sql.identifier(field.fieldAlias)}`);
  164. }
  165. } else if (is(field, Column)) {
  166. if (isSingleTable) {
  167. chunk.push(sql.identifier(this.casing.getColumnCasing(field)));
  168. } else {
  169. chunk.push(field);
  170. }
  171. } else if (is(field, Subquery)) {
  172. const entries = Object.entries(field._.selectedFields);
  173. if (entries.length === 1) {
  174. const entry = entries[0][1];
  175. const fieldDecoder = is(entry, SQL) ? entry.decoder : is(entry, Column) ? { mapFromDriverValue: (v) => entry.mapFromDriverValue(v) } : entry.sql.decoder;
  176. if (fieldDecoder) {
  177. field._.sql.decoder = fieldDecoder;
  178. }
  179. }
  180. chunk.push(field);
  181. }
  182. if (i < columnsLen - 1) {
  183. chunk.push(sql`, `);
  184. }
  185. return chunk;
  186. });
  187. return sql.join(chunks);
  188. }
  189. buildLimit(limit) {
  190. return typeof limit === "object" || typeof limit === "number" && limit >= 0 ? sql` limit ${limit}` : void 0;
  191. }
  192. buildOrderBy(orderBy) {
  193. return orderBy && orderBy.length > 0 ? sql` order by ${sql.join(orderBy, sql`, `)}` : void 0;
  194. }
  195. buildSelectQuery({
  196. withList,
  197. fields,
  198. fieldsFlat,
  199. where,
  200. having,
  201. table,
  202. joins,
  203. orderBy,
  204. groupBy,
  205. limit,
  206. offset,
  207. lockingClause,
  208. distinct,
  209. setOperators
  210. }) {
  211. const fieldsList = fieldsFlat ?? orderSelectedFields(fields);
  212. for (const f of fieldsList) {
  213. if (is(f.field, Column) && getTableName(f.field.table) !== (is(table, Subquery) ? table._.alias : is(table, SQL) ? void 0 : getTableName(table)) && !((table2) => joins?.some(
  214. ({ alias }) => alias === (table2[Table.Symbol.IsAlias] ? getTableName(table2) : table2[Table.Symbol.BaseName])
  215. ))(f.field.table)) {
  216. const tableName = getTableName(f.field.table);
  217. throw new Error(
  218. `Your "${f.path.join(
  219. "->"
  220. )}" field references a column "${tableName}"."${f.field.name}", but the table "${tableName}" is not part of the query! Did you forget to join it?`
  221. );
  222. }
  223. }
  224. const isSingleTable = !joins || joins.length === 0;
  225. const withSql = this.buildWithCTE(withList);
  226. const distinctSql = distinct ? sql` distinct` : void 0;
  227. const selection = this.buildSelection(fieldsList, { isSingleTable });
  228. const tableSql = (() => {
  229. if (is(table, Table) && table[Table.Symbol.IsAlias]) {
  230. return sql`${sql`${sql.identifier(table[Table.Symbol.Schema] ?? "")}.`.if(table[Table.Symbol.Schema])}${sql.identifier(
  231. table[Table.Symbol.OriginalName]
  232. )} ${sql.identifier(table[Table.Symbol.Name])}`;
  233. }
  234. return table;
  235. })();
  236. const joinsArray = [];
  237. if (joins) {
  238. for (const [index, joinMeta] of joins.entries()) {
  239. if (index === 0) {
  240. joinsArray.push(sql` `);
  241. }
  242. const table2 = joinMeta.table;
  243. const lateralSql = joinMeta.lateral ? sql` lateral` : void 0;
  244. const onSql = joinMeta.on ? sql` on ${joinMeta.on}` : void 0;
  245. if (is(table2, SingleStoreTable)) {
  246. const tableName = table2[SingleStoreTable.Symbol.Name];
  247. const tableSchema = table2[SingleStoreTable.Symbol.Schema];
  248. const origTableName = table2[SingleStoreTable.Symbol.OriginalName];
  249. const alias = tableName === origTableName ? void 0 : joinMeta.alias;
  250. joinsArray.push(
  251. sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${tableSchema ? sql`${sql.identifier(tableSchema)}.` : void 0}${sql.identifier(origTableName)}${alias && sql` ${sql.identifier(alias)}`}${onSql}`
  252. );
  253. } else if (is(table2, View)) {
  254. const viewName = table2[ViewBaseConfig].name;
  255. const viewSchema = table2[ViewBaseConfig].schema;
  256. const origViewName = table2[ViewBaseConfig].originalName;
  257. const alias = viewName === origViewName ? void 0 : joinMeta.alias;
  258. joinsArray.push(
  259. sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${viewSchema ? sql`${sql.identifier(viewSchema)}.` : void 0}${sql.identifier(origViewName)}${alias && sql` ${sql.identifier(alias)}`}${onSql}`
  260. );
  261. } else {
  262. joinsArray.push(
  263. sql`${sql.raw(joinMeta.joinType)} join${lateralSql} ${table2}${onSql}`
  264. );
  265. }
  266. if (index < joins.length - 1) {
  267. joinsArray.push(sql` `);
  268. }
  269. }
  270. }
  271. const joinsSql = sql.join(joinsArray);
  272. const whereSql = where ? sql` where ${where}` : void 0;
  273. const havingSql = having ? sql` having ${having}` : void 0;
  274. const orderBySql = this.buildOrderBy(orderBy);
  275. const groupBySql = groupBy && groupBy.length > 0 ? sql` group by ${sql.join(groupBy, sql`, `)}` : void 0;
  276. const limitSql = this.buildLimit(limit);
  277. const offsetSql = offset ? sql` offset ${offset}` : void 0;
  278. let lockingClausesSql;
  279. if (lockingClause) {
  280. const { config, strength } = lockingClause;
  281. lockingClausesSql = sql` for ${sql.raw(strength)}`;
  282. if (config.noWait) {
  283. lockingClausesSql.append(sql` nowait`);
  284. } else if (config.skipLocked) {
  285. lockingClausesSql.append(sql` skip locked`);
  286. }
  287. }
  288. const finalQuery = sql`${withSql}select${distinctSql} ${selection} from ${tableSql}${joinsSql}${whereSql}${groupBySql}${havingSql}${orderBySql}${limitSql}${offsetSql}${lockingClausesSql}`;
  289. if (setOperators.length > 0) {
  290. return this.buildSetOperations(finalQuery, setOperators);
  291. }
  292. return finalQuery;
  293. }
  294. buildSetOperations(leftSelect, setOperators) {
  295. const [setOperator, ...rest] = setOperators;
  296. if (!setOperator) {
  297. throw new Error("Cannot pass undefined values to any set operator");
  298. }
  299. if (rest.length === 0) {
  300. return this.buildSetOperationQuery({ leftSelect, setOperator });
  301. }
  302. return this.buildSetOperations(
  303. this.buildSetOperationQuery({ leftSelect, setOperator }),
  304. rest
  305. );
  306. }
  307. buildSetOperationQuery({
  308. leftSelect,
  309. setOperator: { type, isAll, rightSelect, limit, orderBy, offset }
  310. }) {
  311. const leftChunk = sql`(${leftSelect.getSQL()}) `;
  312. const rightChunk = sql`(${rightSelect.getSQL()})`;
  313. let orderBySql;
  314. if (orderBy && orderBy.length > 0) {
  315. const orderByValues = [];
  316. for (const orderByUnit of orderBy) {
  317. if (is(orderByUnit, SingleStoreColumn)) {
  318. orderByValues.push(
  319. sql.identifier(this.casing.getColumnCasing(orderByUnit))
  320. );
  321. } else if (is(orderByUnit, SQL)) {
  322. for (let i = 0; i < orderByUnit.queryChunks.length; i++) {
  323. const chunk = orderByUnit.queryChunks[i];
  324. if (is(chunk, SingleStoreColumn)) {
  325. orderByUnit.queryChunks[i] = sql.identifier(
  326. this.casing.getColumnCasing(chunk)
  327. );
  328. }
  329. }
  330. orderByValues.push(sql`${orderByUnit}`);
  331. } else {
  332. orderByValues.push(sql`${orderByUnit}`);
  333. }
  334. }
  335. orderBySql = sql` order by ${sql.join(orderByValues, sql`, `)} `;
  336. }
  337. const limitSql = typeof limit === "object" || typeof limit === "number" && limit >= 0 ? sql` limit ${limit}` : void 0;
  338. const operatorChunk = sql.raw(`${type} ${isAll ? "all " : ""}`);
  339. const offsetSql = offset ? sql` offset ${offset}` : void 0;
  340. return sql`${leftChunk}${operatorChunk}${rightChunk}${orderBySql}${limitSql}${offsetSql}`;
  341. }
  342. buildInsertQuery({
  343. table,
  344. values,
  345. ignore,
  346. onConflict
  347. }) {
  348. const valuesSqlList = [];
  349. const columns = table[Table.Symbol.Columns];
  350. const colEntries = Object.entries(
  351. columns
  352. ).filter(([_, col]) => !col.shouldDisableInsert());
  353. const insertOrder = colEntries.map(([, column]) => sql.identifier(this.casing.getColumnCasing(column)));
  354. const generatedIdsResponse = [];
  355. for (const [valueIndex, value] of values.entries()) {
  356. const generatedIds = {};
  357. const valueList = [];
  358. for (const [fieldName, col] of colEntries) {
  359. const colValue = value[fieldName];
  360. if (colValue === void 0 || is(colValue, Param) && colValue.value === void 0) {
  361. if (col.defaultFn !== void 0) {
  362. const defaultFnResult = col.defaultFn();
  363. generatedIds[fieldName] = defaultFnResult;
  364. const defaultValue = is(defaultFnResult, SQL) ? defaultFnResult : sql.param(defaultFnResult, col);
  365. valueList.push(defaultValue);
  366. } else if (!col.default && col.onUpdateFn !== void 0) {
  367. const onUpdateFnResult = col.onUpdateFn();
  368. const newValue = is(onUpdateFnResult, SQL) ? onUpdateFnResult : sql.param(onUpdateFnResult, col);
  369. valueList.push(newValue);
  370. } else {
  371. valueList.push(sql`default`);
  372. }
  373. } else {
  374. if (col.defaultFn && is(colValue, Param)) {
  375. generatedIds[fieldName] = colValue.value;
  376. }
  377. valueList.push(colValue);
  378. }
  379. }
  380. generatedIdsResponse.push(generatedIds);
  381. valuesSqlList.push(valueList);
  382. if (valueIndex < values.length - 1) {
  383. valuesSqlList.push(sql`, `);
  384. }
  385. }
  386. const valuesSql = sql.join(valuesSqlList);
  387. const ignoreSql = ignore ? sql` ignore` : void 0;
  388. const onConflictSql = onConflict ? sql` on duplicate key ${onConflict}` : void 0;
  389. return {
  390. sql: sql`insert${ignoreSql} into ${table} ${insertOrder} values ${valuesSql}${onConflictSql}`,
  391. generatedIds: generatedIdsResponse
  392. };
  393. }
  394. sqlToQuery(sql2, invokeSource) {
  395. return sql2.toQuery({
  396. casing: this.casing,
  397. escapeName: this.escapeName,
  398. escapeParam: this.escapeParam,
  399. escapeString: this.escapeString,
  400. invokeSource
  401. });
  402. }
  403. buildRelationalQuery({
  404. fullSchema,
  405. schema,
  406. tableNamesMap,
  407. table,
  408. tableConfig,
  409. queryConfig: config,
  410. tableAlias,
  411. nestedQueryRelation,
  412. joinOn
  413. }) {
  414. let selection = [];
  415. let limit, offset, orderBy, where;
  416. const joins = [];
  417. if (config === true) {
  418. const selectionEntries = Object.entries(tableConfig.columns);
  419. selection = selectionEntries.map(([key, value]) => ({
  420. dbKey: value.name,
  421. tsKey: key,
  422. field: aliasedTableColumn(value, tableAlias),
  423. relationTableTsKey: void 0,
  424. isJson: false,
  425. selection: []
  426. }));
  427. } else {
  428. const aliasedColumns = Object.fromEntries(
  429. Object.entries(tableConfig.columns).map(([key, value]) => [
  430. key,
  431. aliasedTableColumn(value, tableAlias)
  432. ])
  433. );
  434. if (config.where) {
  435. const whereSql = typeof config.where === "function" ? config.where(aliasedColumns, getOperators()) : config.where;
  436. where = whereSql && mapColumnsInSQLToAlias(whereSql, tableAlias);
  437. }
  438. const fieldsSelection = [];
  439. let selectedColumns = [];
  440. if (config.columns) {
  441. let isIncludeMode = false;
  442. for (const [field, value] of Object.entries(config.columns)) {
  443. if (value === void 0) {
  444. continue;
  445. }
  446. if (field in tableConfig.columns) {
  447. if (!isIncludeMode && value === true) {
  448. isIncludeMode = true;
  449. }
  450. selectedColumns.push(field);
  451. }
  452. }
  453. if (selectedColumns.length > 0) {
  454. selectedColumns = isIncludeMode ? selectedColumns.filter((c) => config.columns?.[c] === true) : Object.keys(tableConfig.columns).filter(
  455. (key) => !selectedColumns.includes(key)
  456. );
  457. }
  458. } else {
  459. selectedColumns = Object.keys(tableConfig.columns);
  460. }
  461. for (const field of selectedColumns) {
  462. const column = tableConfig.columns[field];
  463. fieldsSelection.push({ tsKey: field, value: column });
  464. }
  465. let selectedRelations = [];
  466. if (config.with) {
  467. selectedRelations = Object.entries(config.with).filter(
  468. (entry) => !!entry[1]
  469. ).map(([tsKey, queryConfig]) => ({
  470. tsKey,
  471. queryConfig,
  472. relation: tableConfig.relations[tsKey]
  473. }));
  474. }
  475. let extras;
  476. if (config.extras) {
  477. extras = typeof config.extras === "function" ? config.extras(aliasedColumns, { sql }) : config.extras;
  478. for (const [tsKey, value] of Object.entries(extras)) {
  479. fieldsSelection.push({
  480. tsKey,
  481. value: mapColumnsInAliasedSQLToAlias(value, tableAlias)
  482. });
  483. }
  484. }
  485. for (const { tsKey, value } of fieldsSelection) {
  486. selection.push({
  487. dbKey: is(value, SQL.Aliased) ? value.fieldAlias : tableConfig.columns[tsKey].name,
  488. tsKey,
  489. field: is(value, Column) ? aliasedTableColumn(value, tableAlias) : value,
  490. relationTableTsKey: void 0,
  491. isJson: false,
  492. selection: []
  493. });
  494. }
  495. let orderByOrig = typeof config.orderBy === "function" ? config.orderBy(aliasedColumns, getOrderByOperators()) : config.orderBy ?? [];
  496. if (!Array.isArray(orderByOrig)) {
  497. orderByOrig = [orderByOrig];
  498. }
  499. orderBy = orderByOrig.map((orderByValue) => {
  500. if (is(orderByValue, Column)) {
  501. return aliasedTableColumn(
  502. orderByValue,
  503. tableAlias
  504. );
  505. }
  506. return mapColumnsInSQLToAlias(orderByValue, tableAlias);
  507. });
  508. limit = config.limit;
  509. offset = config.offset;
  510. for (const {
  511. tsKey: selectedRelationTsKey,
  512. queryConfig: selectedRelationConfigValue,
  513. relation
  514. } of selectedRelations) {
  515. const normalizedRelation = normalizeRelation(
  516. schema,
  517. tableNamesMap,
  518. relation
  519. );
  520. const relationTableName = getTableUniqueName(relation.referencedTable);
  521. const relationTableTsName = tableNamesMap[relationTableName];
  522. const relationTableAlias = `${tableAlias}_${selectedRelationTsKey}`;
  523. const joinOn2 = and(
  524. ...normalizedRelation.fields.map(
  525. (field2, i) => eq(
  526. aliasedTableColumn(
  527. normalizedRelation.references[i],
  528. relationTableAlias
  529. ),
  530. aliasedTableColumn(field2, tableAlias)
  531. )
  532. )
  533. );
  534. const builtRelation = this.buildRelationalQuery({
  535. fullSchema,
  536. schema,
  537. tableNamesMap,
  538. table: fullSchema[relationTableTsName],
  539. tableConfig: schema[relationTableTsName],
  540. queryConfig: is(relation, One) ? selectedRelationConfigValue === true ? { limit: 1 } : { ...selectedRelationConfigValue, limit: 1 } : selectedRelationConfigValue,
  541. tableAlias: relationTableAlias,
  542. joinOn: joinOn2,
  543. nestedQueryRelation: relation
  544. });
  545. const field = sql`${sql.identifier(relationTableAlias)}.${sql.identifier("data")}`.as(
  546. selectedRelationTsKey
  547. );
  548. joins.push({
  549. on: sql`true`,
  550. table: new Subquery(builtRelation.sql, {}, relationTableAlias),
  551. alias: relationTableAlias,
  552. joinType: "left",
  553. lateral: true
  554. });
  555. selection.push({
  556. dbKey: selectedRelationTsKey,
  557. tsKey: selectedRelationTsKey,
  558. field,
  559. relationTableTsKey: relationTableTsName,
  560. isJson: true,
  561. selection: builtRelation.selection
  562. });
  563. }
  564. }
  565. if (selection.length === 0) {
  566. throw new DrizzleError({
  567. message: `No fields selected for table "${tableConfig.tsName}" ("${tableAlias}")`
  568. });
  569. }
  570. let result;
  571. where = and(joinOn, where);
  572. if (nestedQueryRelation) {
  573. let field = sql`JSON_TO_ARRAY(${sql.join(
  574. selection.map(
  575. ({ field: field2, tsKey, isJson }) => isJson ? sql`${sql.identifier(`${tableAlias}_${tsKey}`)}.${sql.identifier("data")}` : is(field2, SQL.Aliased) ? field2.sql : field2
  576. ),
  577. sql`, `
  578. )})`;
  579. if (is(nestedQueryRelation, Many)) {
  580. field = sql`json_agg(${field})`;
  581. }
  582. const nestedSelection = [
  583. {
  584. dbKey: "data",
  585. tsKey: "data",
  586. field: field.as("data"),
  587. isJson: true,
  588. relationTableTsKey: tableConfig.tsName,
  589. selection
  590. }
  591. ];
  592. const needsSubquery = limit !== void 0 || offset !== void 0 || (orderBy?.length ?? 0) > 0;
  593. if (needsSubquery) {
  594. result = this.buildSelectQuery({
  595. table: aliasedTable(table, tableAlias),
  596. fields: {},
  597. fieldsFlat: [
  598. {
  599. path: [],
  600. field: sql.raw("*")
  601. },
  602. ...((orderBy?.length ?? 0) > 0 ? [
  603. {
  604. path: [],
  605. field: sql`row_number() over (order by ${sql.join(orderBy, sql`, `)})`
  606. }
  607. ] : [])
  608. ],
  609. where,
  610. limit,
  611. offset,
  612. setOperators: []
  613. });
  614. where = void 0;
  615. limit = void 0;
  616. offset = void 0;
  617. orderBy = void 0;
  618. } else {
  619. result = aliasedTable(table, tableAlias);
  620. }
  621. result = this.buildSelectQuery({
  622. table: is(result, SingleStoreTable) ? result : new Subquery(result, {}, tableAlias),
  623. fields: {},
  624. fieldsFlat: nestedSelection.map(({ field: field2 }) => ({
  625. path: [],
  626. field: is(field2, Column) ? aliasedTableColumn(field2, tableAlias) : field2
  627. })),
  628. joins,
  629. where,
  630. limit,
  631. offset,
  632. orderBy,
  633. setOperators: []
  634. });
  635. } else {
  636. result = this.buildSelectQuery({
  637. table: aliasedTable(table, tableAlias),
  638. fields: {},
  639. fieldsFlat: selection.map(({ field }) => ({
  640. path: [],
  641. field: is(field, Column) ? aliasedTableColumn(field, tableAlias) : field
  642. })),
  643. joins,
  644. where,
  645. limit,
  646. offset,
  647. orderBy,
  648. setOperators: []
  649. });
  650. }
  651. return {
  652. tableTsKey: tableConfig.tsName,
  653. sql: result,
  654. selection
  655. };
  656. }
  657. }
  658. export {
  659. SingleStoreDialect
  660. };
  661. //# sourceMappingURL=dialect.js.map