select.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. import { entityKind, is } from "../../entity.js";
  2. import { TypedQueryBuilder } from "../../query-builders/query-builder.js";
  3. import { QueryPromise } from "../../query-promise.js";
  4. import { SelectionProxyHandler } from "../../selection-proxy.js";
  5. import { SQL, View } from "../../sql/sql.js";
  6. import { Subquery } from "../../subquery.js";
  7. import { Table } from "../../table.js";
  8. import {
  9. applyMixins,
  10. getTableColumns,
  11. getTableLikeName,
  12. haveSameKeys,
  13. orderSelectedFields
  14. } from "../../utils.js";
  15. import { ViewBaseConfig } from "../../view-common.js";
  16. import { extractUsedTable } from "../utils.js";
  17. import { SQLiteViewBase } from "../view-base.js";
  18. class SQLiteSelectBuilder {
  19. static [entityKind] = "SQLiteSelectBuilder";
  20. fields;
  21. session;
  22. dialect;
  23. withList;
  24. distinct;
  25. constructor(config) {
  26. this.fields = config.fields;
  27. this.session = config.session;
  28. this.dialect = config.dialect;
  29. this.withList = config.withList;
  30. this.distinct = config.distinct;
  31. }
  32. from(source) {
  33. const isPartialSelect = !!this.fields;
  34. let fields;
  35. if (this.fields) {
  36. fields = this.fields;
  37. } else if (is(source, Subquery)) {
  38. fields = Object.fromEntries(
  39. Object.keys(source._.selectedFields).map((key) => [key, source[key]])
  40. );
  41. } else if (is(source, SQLiteViewBase)) {
  42. fields = source[ViewBaseConfig].selectedFields;
  43. } else if (is(source, SQL)) {
  44. fields = {};
  45. } else {
  46. fields = getTableColumns(source);
  47. }
  48. return new SQLiteSelectBase({
  49. table: source,
  50. fields,
  51. isPartialSelect,
  52. session: this.session,
  53. dialect: this.dialect,
  54. withList: this.withList,
  55. distinct: this.distinct
  56. });
  57. }
  58. }
  59. class SQLiteSelectQueryBuilderBase extends TypedQueryBuilder {
  60. static [entityKind] = "SQLiteSelectQueryBuilder";
  61. _;
  62. /** @internal */
  63. config;
  64. joinsNotNullableMap;
  65. tableName;
  66. isPartialSelect;
  67. session;
  68. dialect;
  69. cacheConfig = void 0;
  70. usedTables = /* @__PURE__ */ new Set();
  71. constructor({ table, fields, isPartialSelect, session, dialect, withList, distinct }) {
  72. super();
  73. this.config = {
  74. withList,
  75. table,
  76. fields: { ...fields },
  77. distinct,
  78. setOperators: []
  79. };
  80. this.isPartialSelect = isPartialSelect;
  81. this.session = session;
  82. this.dialect = dialect;
  83. this._ = {
  84. selectedFields: fields,
  85. config: this.config
  86. };
  87. this.tableName = getTableLikeName(table);
  88. this.joinsNotNullableMap = typeof this.tableName === "string" ? { [this.tableName]: true } : {};
  89. for (const item of extractUsedTable(table)) this.usedTables.add(item);
  90. }
  91. /** @internal */
  92. getUsedTables() {
  93. return [...this.usedTables];
  94. }
  95. createJoin(joinType) {
  96. return (table, on) => {
  97. const baseTableName = this.tableName;
  98. const tableName = getTableLikeName(table);
  99. for (const item of extractUsedTable(table)) this.usedTables.add(item);
  100. if (typeof tableName === "string" && this.config.joins?.some((join) => join.alias === tableName)) {
  101. throw new Error(`Alias "${tableName}" is already used in this query`);
  102. }
  103. if (!this.isPartialSelect) {
  104. if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === "string") {
  105. this.config.fields = {
  106. [baseTableName]: this.config.fields
  107. };
  108. }
  109. if (typeof tableName === "string" && !is(table, SQL)) {
  110. const selection = is(table, Subquery) ? table._.selectedFields : is(table, View) ? table[ViewBaseConfig].selectedFields : table[Table.Symbol.Columns];
  111. this.config.fields[tableName] = selection;
  112. }
  113. }
  114. if (typeof on === "function") {
  115. on = on(
  116. new Proxy(
  117. this.config.fields,
  118. new SelectionProxyHandler({ sqlAliasedBehavior: "sql", sqlBehavior: "sql" })
  119. )
  120. );
  121. }
  122. if (!this.config.joins) {
  123. this.config.joins = [];
  124. }
  125. this.config.joins.push({ on, table, joinType, alias: tableName });
  126. if (typeof tableName === "string") {
  127. switch (joinType) {
  128. case "left": {
  129. this.joinsNotNullableMap[tableName] = false;
  130. break;
  131. }
  132. case "right": {
  133. this.joinsNotNullableMap = Object.fromEntries(
  134. Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false])
  135. );
  136. this.joinsNotNullableMap[tableName] = true;
  137. break;
  138. }
  139. case "cross":
  140. case "inner": {
  141. this.joinsNotNullableMap[tableName] = true;
  142. break;
  143. }
  144. case "full": {
  145. this.joinsNotNullableMap = Object.fromEntries(
  146. Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false])
  147. );
  148. this.joinsNotNullableMap[tableName] = false;
  149. break;
  150. }
  151. }
  152. }
  153. return this;
  154. };
  155. }
  156. /**
  157. * Executes a `left join` operation by adding another table to the current query.
  158. *
  159. * Calling this method associates each row of the table with the corresponding row from the joined table, if a match is found. If no matching row exists, it sets all columns of the joined table to null.
  160. *
  161. * See docs: {@link https://orm.drizzle.team/docs/joins#left-join}
  162. *
  163. * @param table the table to join.
  164. * @param on the `on` clause.
  165. *
  166. * @example
  167. *
  168. * ```ts
  169. * // Select all users and their pets
  170. * const usersWithPets: { user: User; pets: Pet | null; }[] = await db.select()
  171. * .from(users)
  172. * .leftJoin(pets, eq(users.id, pets.ownerId))
  173. *
  174. * // Select userId and petId
  175. * const usersIdsAndPetIds: { userId: number; petId: number | null; }[] = await db.select({
  176. * userId: users.id,
  177. * petId: pets.id,
  178. * })
  179. * .from(users)
  180. * .leftJoin(pets, eq(users.id, pets.ownerId))
  181. * ```
  182. */
  183. leftJoin = this.createJoin("left");
  184. /**
  185. * Executes a `right join` operation by adding another table to the current query.
  186. *
  187. * Calling this method associates each row of the joined table with the corresponding row from the main table, if a match is found. If no matching row exists, it sets all columns of the main table to null.
  188. *
  189. * See docs: {@link https://orm.drizzle.team/docs/joins#right-join}
  190. *
  191. * @param table the table to join.
  192. * @param on the `on` clause.
  193. *
  194. * @example
  195. *
  196. * ```ts
  197. * // Select all users and their pets
  198. * const usersWithPets: { user: User | null; pets: Pet; }[] = await db.select()
  199. * .from(users)
  200. * .rightJoin(pets, eq(users.id, pets.ownerId))
  201. *
  202. * // Select userId and petId
  203. * const usersIdsAndPetIds: { userId: number | null; petId: number; }[] = await db.select({
  204. * userId: users.id,
  205. * petId: pets.id,
  206. * })
  207. * .from(users)
  208. * .rightJoin(pets, eq(users.id, pets.ownerId))
  209. * ```
  210. */
  211. rightJoin = this.createJoin("right");
  212. /**
  213. * Executes an `inner join` operation, creating a new table by combining rows from two tables that have matching values.
  214. *
  215. * Calling this method retrieves rows that have corresponding entries in both joined tables. Rows without matching entries in either table are excluded, resulting in a table that includes only matching pairs.
  216. *
  217. * See docs: {@link https://orm.drizzle.team/docs/joins#inner-join}
  218. *
  219. * @param table the table to join.
  220. * @param on the `on` clause.
  221. *
  222. * @example
  223. *
  224. * ```ts
  225. * // Select all users and their pets
  226. * const usersWithPets: { user: User; pets: Pet; }[] = await db.select()
  227. * .from(users)
  228. * .innerJoin(pets, eq(users.id, pets.ownerId))
  229. *
  230. * // Select userId and petId
  231. * const usersIdsAndPetIds: { userId: number; petId: number; }[] = await db.select({
  232. * userId: users.id,
  233. * petId: pets.id,
  234. * })
  235. * .from(users)
  236. * .innerJoin(pets, eq(users.id, pets.ownerId))
  237. * ```
  238. */
  239. innerJoin = this.createJoin("inner");
  240. /**
  241. * Executes a `full join` operation by combining rows from two tables into a new table.
  242. *
  243. * Calling this method retrieves all rows from both main and joined tables, merging rows with matching values and filling in `null` for non-matching columns.
  244. *
  245. * See docs: {@link https://orm.drizzle.team/docs/joins#full-join}
  246. *
  247. * @param table the table to join.
  248. * @param on the `on` clause.
  249. *
  250. * @example
  251. *
  252. * ```ts
  253. * // Select all users and their pets
  254. * const usersWithPets: { user: User | null; pets: Pet | null; }[] = await db.select()
  255. * .from(users)
  256. * .fullJoin(pets, eq(users.id, pets.ownerId))
  257. *
  258. * // Select userId and petId
  259. * const usersIdsAndPetIds: { userId: number | null; petId: number | null; }[] = await db.select({
  260. * userId: users.id,
  261. * petId: pets.id,
  262. * })
  263. * .from(users)
  264. * .fullJoin(pets, eq(users.id, pets.ownerId))
  265. * ```
  266. */
  267. fullJoin = this.createJoin("full");
  268. /**
  269. * Executes a `cross join` operation by combining rows from two tables into a new table.
  270. *
  271. * Calling this method retrieves all rows from both main and joined tables, merging all rows from each table.
  272. *
  273. * See docs: {@link https://orm.drizzle.team/docs/joins#cross-join}
  274. *
  275. * @param table the table to join.
  276. *
  277. * @example
  278. *
  279. * ```ts
  280. * // Select all users, each user with every pet
  281. * const usersWithPets: { user: User; pets: Pet; }[] = await db.select()
  282. * .from(users)
  283. * .crossJoin(pets)
  284. *
  285. * // Select userId and petId
  286. * const usersIdsAndPetIds: { userId: number; petId: number; }[] = await db.select({
  287. * userId: users.id,
  288. * petId: pets.id,
  289. * })
  290. * .from(users)
  291. * .crossJoin(pets)
  292. * ```
  293. */
  294. crossJoin = this.createJoin("cross");
  295. createSetOperator(type, isAll) {
  296. return (rightSelection) => {
  297. const rightSelect = typeof rightSelection === "function" ? rightSelection(getSQLiteSetOperators()) : rightSelection;
  298. if (!haveSameKeys(this.getSelectedFields(), rightSelect.getSelectedFields())) {
  299. throw new Error(
  300. "Set operator error (union / intersect / except): selected fields are not the same or are in a different order"
  301. );
  302. }
  303. this.config.setOperators.push({ type, isAll, rightSelect });
  304. return this;
  305. };
  306. }
  307. /**
  308. * Adds `union` set operator to the query.
  309. *
  310. * Calling this method will combine the result sets of the `select` statements and remove any duplicate rows that appear across them.
  311. *
  312. * See docs: {@link https://orm.drizzle.team/docs/set-operations#union}
  313. *
  314. * @example
  315. *
  316. * ```ts
  317. * // Select all unique names from customers and users tables
  318. * await db.select({ name: users.name })
  319. * .from(users)
  320. * .union(
  321. * db.select({ name: customers.name }).from(customers)
  322. * );
  323. * // or
  324. * import { union } from 'drizzle-orm/sqlite-core'
  325. *
  326. * await union(
  327. * db.select({ name: users.name }).from(users),
  328. * db.select({ name: customers.name }).from(customers)
  329. * );
  330. * ```
  331. */
  332. union = this.createSetOperator("union", false);
  333. /**
  334. * Adds `union all` set operator to the query.
  335. *
  336. * Calling this method will combine the result-set of the `select` statements and keep all duplicate rows that appear across them.
  337. *
  338. * See docs: {@link https://orm.drizzle.team/docs/set-operations#union-all}
  339. *
  340. * @example
  341. *
  342. * ```ts
  343. * // Select all transaction ids from both online and in-store sales
  344. * await db.select({ transaction: onlineSales.transactionId })
  345. * .from(onlineSales)
  346. * .unionAll(
  347. * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales)
  348. * );
  349. * // or
  350. * import { unionAll } from 'drizzle-orm/sqlite-core'
  351. *
  352. * await unionAll(
  353. * db.select({ transaction: onlineSales.transactionId }).from(onlineSales),
  354. * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales)
  355. * );
  356. * ```
  357. */
  358. unionAll = this.createSetOperator("union", true);
  359. /**
  360. * Adds `intersect` set operator to the query.
  361. *
  362. * Calling this method will retain only the rows that are present in both result sets and eliminate duplicates.
  363. *
  364. * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect}
  365. *
  366. * @example
  367. *
  368. * ```ts
  369. * // Select course names that are offered in both departments A and B
  370. * await db.select({ courseName: depA.courseName })
  371. * .from(depA)
  372. * .intersect(
  373. * db.select({ courseName: depB.courseName }).from(depB)
  374. * );
  375. * // or
  376. * import { intersect } from 'drizzle-orm/sqlite-core'
  377. *
  378. * await intersect(
  379. * db.select({ courseName: depA.courseName }).from(depA),
  380. * db.select({ courseName: depB.courseName }).from(depB)
  381. * );
  382. * ```
  383. */
  384. intersect = this.createSetOperator("intersect", false);
  385. /**
  386. * Adds `except` set operator to the query.
  387. *
  388. * Calling this method will retrieve all unique rows from the left query, except for the rows that are present in the result set of the right query.
  389. *
  390. * See docs: {@link https://orm.drizzle.team/docs/set-operations#except}
  391. *
  392. * @example
  393. *
  394. * ```ts
  395. * // Select all courses offered in department A but not in department B
  396. * await db.select({ courseName: depA.courseName })
  397. * .from(depA)
  398. * .except(
  399. * db.select({ courseName: depB.courseName }).from(depB)
  400. * );
  401. * // or
  402. * import { except } from 'drizzle-orm/sqlite-core'
  403. *
  404. * await except(
  405. * db.select({ courseName: depA.courseName }).from(depA),
  406. * db.select({ courseName: depB.courseName }).from(depB)
  407. * );
  408. * ```
  409. */
  410. except = this.createSetOperator("except", false);
  411. /** @internal */
  412. addSetOperators(setOperators) {
  413. this.config.setOperators.push(...setOperators);
  414. return this;
  415. }
  416. /**
  417. * Adds a `where` clause to the query.
  418. *
  419. * Calling this method will select only those rows that fulfill a specified condition.
  420. *
  421. * See docs: {@link https://orm.drizzle.team/docs/select#filtering}
  422. *
  423. * @param where the `where` clause.
  424. *
  425. * @example
  426. * You can use conditional operators and `sql function` to filter the rows to be selected.
  427. *
  428. * ```ts
  429. * // Select all cars with green color
  430. * await db.select().from(cars).where(eq(cars.color, 'green'));
  431. * // or
  432. * await db.select().from(cars).where(sql`${cars.color} = 'green'`)
  433. * ```
  434. *
  435. * You can logically combine conditional operators with `and()` and `or()` operators:
  436. *
  437. * ```ts
  438. * // Select all BMW cars with a green color
  439. * await db.select().from(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW')));
  440. *
  441. * // Select all cars with the green or blue color
  442. * await db.select().from(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue')));
  443. * ```
  444. */
  445. where(where) {
  446. if (typeof where === "function") {
  447. where = where(
  448. new Proxy(
  449. this.config.fields,
  450. new SelectionProxyHandler({ sqlAliasedBehavior: "sql", sqlBehavior: "sql" })
  451. )
  452. );
  453. }
  454. this.config.where = where;
  455. return this;
  456. }
  457. /**
  458. * Adds a `having` clause to the query.
  459. *
  460. * Calling this method will select only those rows that fulfill a specified condition. It is typically used with aggregate functions to filter the aggregated data based on a specified condition.
  461. *
  462. * See docs: {@link https://orm.drizzle.team/docs/select#aggregations}
  463. *
  464. * @param having the `having` clause.
  465. *
  466. * @example
  467. *
  468. * ```ts
  469. * // Select all brands with more than one car
  470. * await db.select({
  471. * brand: cars.brand,
  472. * count: sql<number>`cast(count(${cars.id}) as int)`,
  473. * })
  474. * .from(cars)
  475. * .groupBy(cars.brand)
  476. * .having(({ count }) => gt(count, 1));
  477. * ```
  478. */
  479. having(having) {
  480. if (typeof having === "function") {
  481. having = having(
  482. new Proxy(
  483. this.config.fields,
  484. new SelectionProxyHandler({ sqlAliasedBehavior: "sql", sqlBehavior: "sql" })
  485. )
  486. );
  487. }
  488. this.config.having = having;
  489. return this;
  490. }
  491. groupBy(...columns) {
  492. if (typeof columns[0] === "function") {
  493. const groupBy = columns[0](
  494. new Proxy(
  495. this.config.fields,
  496. new SelectionProxyHandler({ sqlAliasedBehavior: "alias", sqlBehavior: "sql" })
  497. )
  498. );
  499. this.config.groupBy = Array.isArray(groupBy) ? groupBy : [groupBy];
  500. } else {
  501. this.config.groupBy = columns;
  502. }
  503. return this;
  504. }
  505. orderBy(...columns) {
  506. if (typeof columns[0] === "function") {
  507. const orderBy = columns[0](
  508. new Proxy(
  509. this.config.fields,
  510. new SelectionProxyHandler({ sqlAliasedBehavior: "alias", sqlBehavior: "sql" })
  511. )
  512. );
  513. const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy];
  514. if (this.config.setOperators.length > 0) {
  515. this.config.setOperators.at(-1).orderBy = orderByArray;
  516. } else {
  517. this.config.orderBy = orderByArray;
  518. }
  519. } else {
  520. const orderByArray = columns;
  521. if (this.config.setOperators.length > 0) {
  522. this.config.setOperators.at(-1).orderBy = orderByArray;
  523. } else {
  524. this.config.orderBy = orderByArray;
  525. }
  526. }
  527. return this;
  528. }
  529. /**
  530. * Adds a `limit` clause to the query.
  531. *
  532. * Calling this method will set the maximum number of rows that will be returned by this query.
  533. *
  534. * See docs: {@link https://orm.drizzle.team/docs/select#limit--offset}
  535. *
  536. * @param limit the `limit` clause.
  537. *
  538. * @example
  539. *
  540. * ```ts
  541. * // Get the first 10 people from this query.
  542. * await db.select().from(people).limit(10);
  543. * ```
  544. */
  545. limit(limit) {
  546. if (this.config.setOperators.length > 0) {
  547. this.config.setOperators.at(-1).limit = limit;
  548. } else {
  549. this.config.limit = limit;
  550. }
  551. return this;
  552. }
  553. /**
  554. * Adds an `offset` clause to the query.
  555. *
  556. * Calling this method will skip a number of rows when returning results from this query.
  557. *
  558. * See docs: {@link https://orm.drizzle.team/docs/select#limit--offset}
  559. *
  560. * @param offset the `offset` clause.
  561. *
  562. * @example
  563. *
  564. * ```ts
  565. * // Get the 10th-20th people from this query.
  566. * await db.select().from(people).offset(10).limit(10);
  567. * ```
  568. */
  569. offset(offset) {
  570. if (this.config.setOperators.length > 0) {
  571. this.config.setOperators.at(-1).offset = offset;
  572. } else {
  573. this.config.offset = offset;
  574. }
  575. return this;
  576. }
  577. /** @internal */
  578. getSQL() {
  579. return this.dialect.buildSelectQuery(this.config);
  580. }
  581. toSQL() {
  582. const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL());
  583. return rest;
  584. }
  585. as(alias) {
  586. const usedTables = [];
  587. usedTables.push(...extractUsedTable(this.config.table));
  588. if (this.config.joins) {
  589. for (const it of this.config.joins) usedTables.push(...extractUsedTable(it.table));
  590. }
  591. return new Proxy(
  592. new Subquery(this.getSQL(), this.config.fields, alias, false, [...new Set(usedTables)]),
  593. new SelectionProxyHandler({ alias, sqlAliasedBehavior: "alias", sqlBehavior: "error" })
  594. );
  595. }
  596. /** @internal */
  597. getSelectedFields() {
  598. return new Proxy(
  599. this.config.fields,
  600. new SelectionProxyHandler({ alias: this.tableName, sqlAliasedBehavior: "alias", sqlBehavior: "error" })
  601. );
  602. }
  603. $dynamic() {
  604. return this;
  605. }
  606. }
  607. class SQLiteSelectBase extends SQLiteSelectQueryBuilderBase {
  608. static [entityKind] = "SQLiteSelect";
  609. /** @internal */
  610. _prepare(isOneTimeQuery = true) {
  611. if (!this.session) {
  612. throw new Error("Cannot execute a query on a query builder. Please use a database instance instead.");
  613. }
  614. const fieldsList = orderSelectedFields(this.config.fields);
  615. const query = this.session[isOneTimeQuery ? "prepareOneTimeQuery" : "prepareQuery"](
  616. this.dialect.sqlToQuery(this.getSQL()),
  617. fieldsList,
  618. "all",
  619. true,
  620. void 0,
  621. {
  622. type: "select",
  623. tables: [...this.usedTables]
  624. },
  625. this.cacheConfig
  626. );
  627. query.joinsNotNullableMap = this.joinsNotNullableMap;
  628. return query;
  629. }
  630. $withCache(config) {
  631. this.cacheConfig = config === void 0 ? { config: {}, enable: true, autoInvalidate: true } : config === false ? { enable: false } : { enable: true, autoInvalidate: true, ...config };
  632. return this;
  633. }
  634. prepare() {
  635. return this._prepare(false);
  636. }
  637. run = (placeholderValues) => {
  638. return this._prepare().run(placeholderValues);
  639. };
  640. all = (placeholderValues) => {
  641. return this._prepare().all(placeholderValues);
  642. };
  643. get = (placeholderValues) => {
  644. return this._prepare().get(placeholderValues);
  645. };
  646. values = (placeholderValues) => {
  647. return this._prepare().values(placeholderValues);
  648. };
  649. async execute() {
  650. return this.all();
  651. }
  652. }
  653. applyMixins(SQLiteSelectBase, [QueryPromise]);
  654. function createSetOperator(type, isAll) {
  655. return (leftSelect, rightSelect, ...restSelects) => {
  656. const setOperators = [rightSelect, ...restSelects].map((select) => ({
  657. type,
  658. isAll,
  659. rightSelect: select
  660. }));
  661. for (const setOperator of setOperators) {
  662. if (!haveSameKeys(leftSelect.getSelectedFields(), setOperator.rightSelect.getSelectedFields())) {
  663. throw new Error(
  664. "Set operator error (union / intersect / except): selected fields are not the same or are in a different order"
  665. );
  666. }
  667. }
  668. return leftSelect.addSetOperators(setOperators);
  669. };
  670. }
  671. const getSQLiteSetOperators = () => ({
  672. union,
  673. unionAll,
  674. intersect,
  675. except
  676. });
  677. const union = createSetOperator("union", false);
  678. const unionAll = createSetOperator("union", true);
  679. const intersect = createSetOperator("intersect", false);
  680. const except = createSetOperator("except", false);
  681. export {
  682. SQLiteSelectBase,
  683. SQLiteSelectBuilder,
  684. SQLiteSelectQueryBuilderBase,
  685. except,
  686. intersect,
  687. union,
  688. unionAll
  689. };
  690. //# sourceMappingURL=select.js.map