select.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  1. import { entityKind, is } from "../../entity.js";
  2. import { PgViewBase } from "../view-base.js";
  3. import { TypedQueryBuilder } from "../../query-builders/query-builder.js";
  4. import { QueryPromise } from "../../query-promise.js";
  5. import { SelectionProxyHandler } from "../../selection-proxy.js";
  6. import { SQL, View } from "../../sql/sql.js";
  7. import { Subquery } from "../../subquery.js";
  8. import { Table } from "../../table.js";
  9. import { tracer } from "../../tracing.js";
  10. import {
  11. applyMixins,
  12. getTableColumns,
  13. getTableLikeName,
  14. haveSameKeys
  15. } from "../../utils.js";
  16. import { orderSelectedFields } from "../../utils.js";
  17. import { ViewBaseConfig } from "../../view-common.js";
  18. import { extractUsedTable } from "../utils.js";
  19. class PgSelectBuilder {
  20. static [entityKind] = "PgSelectBuilder";
  21. fields;
  22. session;
  23. dialect;
  24. withList = [];
  25. distinct;
  26. constructor(config) {
  27. this.fields = config.fields;
  28. this.session = config.session;
  29. this.dialect = config.dialect;
  30. if (config.withList) {
  31. this.withList = config.withList;
  32. }
  33. this.distinct = config.distinct;
  34. }
  35. authToken;
  36. /** @internal */
  37. setToken(token) {
  38. this.authToken = token;
  39. return this;
  40. }
  41. /**
  42. * Specify the table, subquery, or other target that you're
  43. * building a select query against.
  44. *
  45. * {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-FROM | Postgres from documentation}
  46. */
  47. from(source) {
  48. const isPartialSelect = !!this.fields;
  49. const src = source;
  50. let fields;
  51. if (this.fields) {
  52. fields = this.fields;
  53. } else if (is(src, Subquery)) {
  54. fields = Object.fromEntries(
  55. Object.keys(src._.selectedFields).map((key) => [key, src[key]])
  56. );
  57. } else if (is(src, PgViewBase)) {
  58. fields = src[ViewBaseConfig].selectedFields;
  59. } else if (is(src, SQL)) {
  60. fields = {};
  61. } else {
  62. fields = getTableColumns(src);
  63. }
  64. return new PgSelectBase({
  65. table: src,
  66. fields,
  67. isPartialSelect,
  68. session: this.session,
  69. dialect: this.dialect,
  70. withList: this.withList,
  71. distinct: this.distinct
  72. }).setToken(this.authToken);
  73. }
  74. }
  75. class PgSelectQueryBuilderBase extends TypedQueryBuilder {
  76. static [entityKind] = "PgSelectQueryBuilder";
  77. _;
  78. config;
  79. joinsNotNullableMap;
  80. tableName;
  81. isPartialSelect;
  82. session;
  83. dialect;
  84. cacheConfig = void 0;
  85. usedTables = /* @__PURE__ */ new Set();
  86. constructor({ table, fields, isPartialSelect, session, dialect, withList, distinct }) {
  87. super();
  88. this.config = {
  89. withList,
  90. table,
  91. fields: { ...fields },
  92. distinct,
  93. setOperators: []
  94. };
  95. this.isPartialSelect = isPartialSelect;
  96. this.session = session;
  97. this.dialect = dialect;
  98. this._ = {
  99. selectedFields: fields,
  100. config: this.config
  101. };
  102. this.tableName = getTableLikeName(table);
  103. this.joinsNotNullableMap = typeof this.tableName === "string" ? { [this.tableName]: true } : {};
  104. for (const item of extractUsedTable(table)) this.usedTables.add(item);
  105. }
  106. /** @internal */
  107. getUsedTables() {
  108. return [...this.usedTables];
  109. }
  110. createJoin(joinType, lateral) {
  111. return (table, on) => {
  112. const baseTableName = this.tableName;
  113. const tableName = getTableLikeName(table);
  114. for (const item of extractUsedTable(table)) this.usedTables.add(item);
  115. if (typeof tableName === "string" && this.config.joins?.some((join) => join.alias === tableName)) {
  116. throw new Error(`Alias "${tableName}" is already used in this query`);
  117. }
  118. if (!this.isPartialSelect) {
  119. if (Object.keys(this.joinsNotNullableMap).length === 1 && typeof baseTableName === "string") {
  120. this.config.fields = {
  121. [baseTableName]: this.config.fields
  122. };
  123. }
  124. if (typeof tableName === "string" && !is(table, SQL)) {
  125. const selection = is(table, Subquery) ? table._.selectedFields : is(table, View) ? table[ViewBaseConfig].selectedFields : table[Table.Symbol.Columns];
  126. this.config.fields[tableName] = selection;
  127. }
  128. }
  129. if (typeof on === "function") {
  130. on = on(
  131. new Proxy(
  132. this.config.fields,
  133. new SelectionProxyHandler({ sqlAliasedBehavior: "sql", sqlBehavior: "sql" })
  134. )
  135. );
  136. }
  137. if (!this.config.joins) {
  138. this.config.joins = [];
  139. }
  140. this.config.joins.push({ on, table, joinType, alias: tableName, lateral });
  141. if (typeof tableName === "string") {
  142. switch (joinType) {
  143. case "left": {
  144. this.joinsNotNullableMap[tableName] = false;
  145. break;
  146. }
  147. case "right": {
  148. this.joinsNotNullableMap = Object.fromEntries(
  149. Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false])
  150. );
  151. this.joinsNotNullableMap[tableName] = true;
  152. break;
  153. }
  154. case "cross":
  155. case "inner": {
  156. this.joinsNotNullableMap[tableName] = true;
  157. break;
  158. }
  159. case "full": {
  160. this.joinsNotNullableMap = Object.fromEntries(
  161. Object.entries(this.joinsNotNullableMap).map(([key]) => [key, false])
  162. );
  163. this.joinsNotNullableMap[tableName] = false;
  164. break;
  165. }
  166. }
  167. }
  168. return this;
  169. };
  170. }
  171. /**
  172. * Executes a `left join` operation by adding another table to the current query.
  173. *
  174. * 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.
  175. *
  176. * See docs: {@link https://orm.drizzle.team/docs/joins#left-join}
  177. *
  178. * @param table the table to join.
  179. * @param on the `on` clause.
  180. *
  181. * @example
  182. *
  183. * ```ts
  184. * // Select all users and their pets
  185. * const usersWithPets: { user: User; pets: Pet | null; }[] = await db.select()
  186. * .from(users)
  187. * .leftJoin(pets, eq(users.id, pets.ownerId))
  188. *
  189. * // Select userId and petId
  190. * const usersIdsAndPetIds: { userId: number; petId: number | null; }[] = await db.select({
  191. * userId: users.id,
  192. * petId: pets.id,
  193. * })
  194. * .from(users)
  195. * .leftJoin(pets, eq(users.id, pets.ownerId))
  196. * ```
  197. */
  198. leftJoin = this.createJoin("left", false);
  199. /**
  200. * Executes a `left join lateral` operation by adding subquery to the current query.
  201. *
  202. * A `lateral` join allows the right-hand expression to refer to columns from the left-hand side.
  203. *
  204. * 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.
  205. *
  206. * See docs: {@link https://orm.drizzle.team/docs/joins#left-join-lateral}
  207. *
  208. * @param table the subquery to join.
  209. * @param on the `on` clause.
  210. */
  211. leftJoinLateral = this.createJoin("left", true);
  212. /**
  213. * Executes a `right join` operation by adding another table to the current query.
  214. *
  215. * 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.
  216. *
  217. * See docs: {@link https://orm.drizzle.team/docs/joins#right-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 | null; pets: Pet; }[] = await db.select()
  227. * .from(users)
  228. * .rightJoin(pets, eq(users.id, pets.ownerId))
  229. *
  230. * // Select userId and petId
  231. * const usersIdsAndPetIds: { userId: number | null; petId: number; }[] = await db.select({
  232. * userId: users.id,
  233. * petId: pets.id,
  234. * })
  235. * .from(users)
  236. * .rightJoin(pets, eq(users.id, pets.ownerId))
  237. * ```
  238. */
  239. rightJoin = this.createJoin("right", false);
  240. /**
  241. * Executes an `inner join` operation, creating a new table by combining rows from two tables that have matching values.
  242. *
  243. * 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.
  244. *
  245. * See docs: {@link https://orm.drizzle.team/docs/joins#inner-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; pets: Pet; }[] = await db.select()
  255. * .from(users)
  256. * .innerJoin(pets, eq(users.id, pets.ownerId))
  257. *
  258. * // Select userId and petId
  259. * const usersIdsAndPetIds: { userId: number; petId: number; }[] = await db.select({
  260. * userId: users.id,
  261. * petId: pets.id,
  262. * })
  263. * .from(users)
  264. * .innerJoin(pets, eq(users.id, pets.ownerId))
  265. * ```
  266. */
  267. innerJoin = this.createJoin("inner", false);
  268. /**
  269. * Executes an `inner join lateral` operation, creating a new table by combining rows from two queries that have matching values.
  270. *
  271. * A `lateral` join allows the right-hand expression to refer to columns from the left-hand side.
  272. *
  273. * 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.
  274. *
  275. * See docs: {@link https://orm.drizzle.team/docs/joins#inner-join-lateral}
  276. *
  277. * @param table the subquery to join.
  278. * @param on the `on` clause.
  279. */
  280. innerJoinLateral = this.createJoin("inner", true);
  281. /**
  282. * Executes a `full join` operation by combining rows from two tables into a new table.
  283. *
  284. * 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.
  285. *
  286. * See docs: {@link https://orm.drizzle.team/docs/joins#full-join}
  287. *
  288. * @param table the table to join.
  289. * @param on the `on` clause.
  290. *
  291. * @example
  292. *
  293. * ```ts
  294. * // Select all users and their pets
  295. * const usersWithPets: { user: User | null; pets: Pet | null; }[] = await db.select()
  296. * .from(users)
  297. * .fullJoin(pets, eq(users.id, pets.ownerId))
  298. *
  299. * // Select userId and petId
  300. * const usersIdsAndPetIds: { userId: number | null; petId: number | null; }[] = await db.select({
  301. * userId: users.id,
  302. * petId: pets.id,
  303. * })
  304. * .from(users)
  305. * .fullJoin(pets, eq(users.id, pets.ownerId))
  306. * ```
  307. */
  308. fullJoin = this.createJoin("full", false);
  309. /**
  310. * Executes a `cross join` operation by combining rows from two tables into a new table.
  311. *
  312. * Calling this method retrieves all rows from both main and joined tables, merging all rows from each table.
  313. *
  314. * See docs: {@link https://orm.drizzle.team/docs/joins#cross-join}
  315. *
  316. * @param table the table to join.
  317. *
  318. * @example
  319. *
  320. * ```ts
  321. * // Select all users, each user with every pet
  322. * const usersWithPets: { user: User; pets: Pet; }[] = await db.select()
  323. * .from(users)
  324. * .crossJoin(pets)
  325. *
  326. * // Select userId and petId
  327. * const usersIdsAndPetIds: { userId: number; petId: number; }[] = await db.select({
  328. * userId: users.id,
  329. * petId: pets.id,
  330. * })
  331. * .from(users)
  332. * .crossJoin(pets)
  333. * ```
  334. */
  335. crossJoin = this.createJoin("cross", false);
  336. /**
  337. * Executes a `cross join lateral` operation by combining rows from two queries into a new table.
  338. *
  339. * A `lateral` join allows the right-hand expression to refer to columns from the left-hand side.
  340. *
  341. * Calling this method retrieves all rows from both main and joined queries, merging all rows from each query.
  342. *
  343. * See docs: {@link https://orm.drizzle.team/docs/joins#cross-join-lateral}
  344. *
  345. * @param table the query to join.
  346. */
  347. crossJoinLateral = this.createJoin("cross", true);
  348. createSetOperator(type, isAll) {
  349. return (rightSelection) => {
  350. const rightSelect = typeof rightSelection === "function" ? rightSelection(getPgSetOperators()) : rightSelection;
  351. if (!haveSameKeys(this.getSelectedFields(), rightSelect.getSelectedFields())) {
  352. throw new Error(
  353. "Set operator error (union / intersect / except): selected fields are not the same or are in a different order"
  354. );
  355. }
  356. this.config.setOperators.push({ type, isAll, rightSelect });
  357. return this;
  358. };
  359. }
  360. /**
  361. * Adds `union` set operator to the query.
  362. *
  363. * Calling this method will combine the result sets of the `select` statements and remove any duplicate rows that appear across them.
  364. *
  365. * See docs: {@link https://orm.drizzle.team/docs/set-operations#union}
  366. *
  367. * @example
  368. *
  369. * ```ts
  370. * // Select all unique names from customers and users tables
  371. * await db.select({ name: users.name })
  372. * .from(users)
  373. * .union(
  374. * db.select({ name: customers.name }).from(customers)
  375. * );
  376. * // or
  377. * import { union } from 'drizzle-orm/pg-core'
  378. *
  379. * await union(
  380. * db.select({ name: users.name }).from(users),
  381. * db.select({ name: customers.name }).from(customers)
  382. * );
  383. * ```
  384. */
  385. union = this.createSetOperator("union", false);
  386. /**
  387. * Adds `union all` set operator to the query.
  388. *
  389. * Calling this method will combine the result-set of the `select` statements and keep all duplicate rows that appear across them.
  390. *
  391. * See docs: {@link https://orm.drizzle.team/docs/set-operations#union-all}
  392. *
  393. * @example
  394. *
  395. * ```ts
  396. * // Select all transaction ids from both online and in-store sales
  397. * await db.select({ transaction: onlineSales.transactionId })
  398. * .from(onlineSales)
  399. * .unionAll(
  400. * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales)
  401. * );
  402. * // or
  403. * import { unionAll } from 'drizzle-orm/pg-core'
  404. *
  405. * await unionAll(
  406. * db.select({ transaction: onlineSales.transactionId }).from(onlineSales),
  407. * db.select({ transaction: inStoreSales.transactionId }).from(inStoreSales)
  408. * );
  409. * ```
  410. */
  411. unionAll = this.createSetOperator("union", true);
  412. /**
  413. * Adds `intersect` set operator to the query.
  414. *
  415. * Calling this method will retain only the rows that are present in both result sets and eliminate duplicates.
  416. *
  417. * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect}
  418. *
  419. * @example
  420. *
  421. * ```ts
  422. * // Select course names that are offered in both departments A and B
  423. * await db.select({ courseName: depA.courseName })
  424. * .from(depA)
  425. * .intersect(
  426. * db.select({ courseName: depB.courseName }).from(depB)
  427. * );
  428. * // or
  429. * import { intersect } from 'drizzle-orm/pg-core'
  430. *
  431. * await intersect(
  432. * db.select({ courseName: depA.courseName }).from(depA),
  433. * db.select({ courseName: depB.courseName }).from(depB)
  434. * );
  435. * ```
  436. */
  437. intersect = this.createSetOperator("intersect", false);
  438. /**
  439. * Adds `intersect all` set operator to the query.
  440. *
  441. * Calling this method will retain only the rows that are present in both result sets including all duplicates.
  442. *
  443. * See docs: {@link https://orm.drizzle.team/docs/set-operations#intersect-all}
  444. *
  445. * @example
  446. *
  447. * ```ts
  448. * // Select all products and quantities that are ordered by both regular and VIP customers
  449. * await db.select({
  450. * productId: regularCustomerOrders.productId,
  451. * quantityOrdered: regularCustomerOrders.quantityOrdered
  452. * })
  453. * .from(regularCustomerOrders)
  454. * .intersectAll(
  455. * db.select({
  456. * productId: vipCustomerOrders.productId,
  457. * quantityOrdered: vipCustomerOrders.quantityOrdered
  458. * })
  459. * .from(vipCustomerOrders)
  460. * );
  461. * // or
  462. * import { intersectAll } from 'drizzle-orm/pg-core'
  463. *
  464. * await intersectAll(
  465. * db.select({
  466. * productId: regularCustomerOrders.productId,
  467. * quantityOrdered: regularCustomerOrders.quantityOrdered
  468. * })
  469. * .from(regularCustomerOrders),
  470. * db.select({
  471. * productId: vipCustomerOrders.productId,
  472. * quantityOrdered: vipCustomerOrders.quantityOrdered
  473. * })
  474. * .from(vipCustomerOrders)
  475. * );
  476. * ```
  477. */
  478. intersectAll = this.createSetOperator("intersect", true);
  479. /**
  480. * Adds `except` set operator to the query.
  481. *
  482. * 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.
  483. *
  484. * See docs: {@link https://orm.drizzle.team/docs/set-operations#except}
  485. *
  486. * @example
  487. *
  488. * ```ts
  489. * // Select all courses offered in department A but not in department B
  490. * await db.select({ courseName: depA.courseName })
  491. * .from(depA)
  492. * .except(
  493. * db.select({ courseName: depB.courseName }).from(depB)
  494. * );
  495. * // or
  496. * import { except } from 'drizzle-orm/pg-core'
  497. *
  498. * await except(
  499. * db.select({ courseName: depA.courseName }).from(depA),
  500. * db.select({ courseName: depB.courseName }).from(depB)
  501. * );
  502. * ```
  503. */
  504. except = this.createSetOperator("except", false);
  505. /**
  506. * Adds `except all` set operator to the query.
  507. *
  508. * Calling this method will retrieve all rows from the left query, except for the rows that are present in the result set of the right query.
  509. *
  510. * See docs: {@link https://orm.drizzle.team/docs/set-operations#except-all}
  511. *
  512. * @example
  513. *
  514. * ```ts
  515. * // Select all products that are ordered by regular customers but not by VIP customers
  516. * await db.select({
  517. * productId: regularCustomerOrders.productId,
  518. * quantityOrdered: regularCustomerOrders.quantityOrdered,
  519. * })
  520. * .from(regularCustomerOrders)
  521. * .exceptAll(
  522. * db.select({
  523. * productId: vipCustomerOrders.productId,
  524. * quantityOrdered: vipCustomerOrders.quantityOrdered,
  525. * })
  526. * .from(vipCustomerOrders)
  527. * );
  528. * // or
  529. * import { exceptAll } from 'drizzle-orm/pg-core'
  530. *
  531. * await exceptAll(
  532. * db.select({
  533. * productId: regularCustomerOrders.productId,
  534. * quantityOrdered: regularCustomerOrders.quantityOrdered
  535. * })
  536. * .from(regularCustomerOrders),
  537. * db.select({
  538. * productId: vipCustomerOrders.productId,
  539. * quantityOrdered: vipCustomerOrders.quantityOrdered
  540. * })
  541. * .from(vipCustomerOrders)
  542. * );
  543. * ```
  544. */
  545. exceptAll = this.createSetOperator("except", true);
  546. /** @internal */
  547. addSetOperators(setOperators) {
  548. this.config.setOperators.push(...setOperators);
  549. return this;
  550. }
  551. /**
  552. * Adds a `where` clause to the query.
  553. *
  554. * Calling this method will select only those rows that fulfill a specified condition.
  555. *
  556. * See docs: {@link https://orm.drizzle.team/docs/select#filtering}
  557. *
  558. * @param where the `where` clause.
  559. *
  560. * @example
  561. * You can use conditional operators and `sql function` to filter the rows to be selected.
  562. *
  563. * ```ts
  564. * // Select all cars with green color
  565. * await db.select().from(cars).where(eq(cars.color, 'green'));
  566. * // or
  567. * await db.select().from(cars).where(sql`${cars.color} = 'green'`)
  568. * ```
  569. *
  570. * You can logically combine conditional operators with `and()` and `or()` operators:
  571. *
  572. * ```ts
  573. * // Select all BMW cars with a green color
  574. * await db.select().from(cars).where(and(eq(cars.color, 'green'), eq(cars.brand, 'BMW')));
  575. *
  576. * // Select all cars with the green or blue color
  577. * await db.select().from(cars).where(or(eq(cars.color, 'green'), eq(cars.color, 'blue')));
  578. * ```
  579. */
  580. where(where) {
  581. if (typeof where === "function") {
  582. where = where(
  583. new Proxy(
  584. this.config.fields,
  585. new SelectionProxyHandler({ sqlAliasedBehavior: "sql", sqlBehavior: "sql" })
  586. )
  587. );
  588. }
  589. this.config.where = where;
  590. return this;
  591. }
  592. /**
  593. * Adds a `having` clause to the query.
  594. *
  595. * 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.
  596. *
  597. * See docs: {@link https://orm.drizzle.team/docs/select#aggregations}
  598. *
  599. * @param having the `having` clause.
  600. *
  601. * @example
  602. *
  603. * ```ts
  604. * // Select all brands with more than one car
  605. * await db.select({
  606. * brand: cars.brand,
  607. * count: sql<number>`cast(count(${cars.id}) as int)`,
  608. * })
  609. * .from(cars)
  610. * .groupBy(cars.brand)
  611. * .having(({ count }) => gt(count, 1));
  612. * ```
  613. */
  614. having(having) {
  615. if (typeof having === "function") {
  616. having = having(
  617. new Proxy(
  618. this.config.fields,
  619. new SelectionProxyHandler({ sqlAliasedBehavior: "sql", sqlBehavior: "sql" })
  620. )
  621. );
  622. }
  623. this.config.having = having;
  624. return this;
  625. }
  626. groupBy(...columns) {
  627. if (typeof columns[0] === "function") {
  628. const groupBy = columns[0](
  629. new Proxy(
  630. this.config.fields,
  631. new SelectionProxyHandler({ sqlAliasedBehavior: "alias", sqlBehavior: "sql" })
  632. )
  633. );
  634. this.config.groupBy = Array.isArray(groupBy) ? groupBy : [groupBy];
  635. } else {
  636. this.config.groupBy = columns;
  637. }
  638. return this;
  639. }
  640. orderBy(...columns) {
  641. if (typeof columns[0] === "function") {
  642. const orderBy = columns[0](
  643. new Proxy(
  644. this.config.fields,
  645. new SelectionProxyHandler({ sqlAliasedBehavior: "alias", sqlBehavior: "sql" })
  646. )
  647. );
  648. const orderByArray = Array.isArray(orderBy) ? orderBy : [orderBy];
  649. if (this.config.setOperators.length > 0) {
  650. this.config.setOperators.at(-1).orderBy = orderByArray;
  651. } else {
  652. this.config.orderBy = orderByArray;
  653. }
  654. } else {
  655. const orderByArray = columns;
  656. if (this.config.setOperators.length > 0) {
  657. this.config.setOperators.at(-1).orderBy = orderByArray;
  658. } else {
  659. this.config.orderBy = orderByArray;
  660. }
  661. }
  662. return this;
  663. }
  664. /**
  665. * Adds a `limit` clause to the query.
  666. *
  667. * Calling this method will set the maximum number of rows that will be returned by this query.
  668. *
  669. * See docs: {@link https://orm.drizzle.team/docs/select#limit--offset}
  670. *
  671. * @param limit the `limit` clause.
  672. *
  673. * @example
  674. *
  675. * ```ts
  676. * // Get the first 10 people from this query.
  677. * await db.select().from(people).limit(10);
  678. * ```
  679. */
  680. limit(limit) {
  681. if (this.config.setOperators.length > 0) {
  682. this.config.setOperators.at(-1).limit = limit;
  683. } else {
  684. this.config.limit = limit;
  685. }
  686. return this;
  687. }
  688. /**
  689. * Adds an `offset` clause to the query.
  690. *
  691. * Calling this method will skip a number of rows when returning results from this query.
  692. *
  693. * See docs: {@link https://orm.drizzle.team/docs/select#limit--offset}
  694. *
  695. * @param offset the `offset` clause.
  696. *
  697. * @example
  698. *
  699. * ```ts
  700. * // Get the 10th-20th people from this query.
  701. * await db.select().from(people).offset(10).limit(10);
  702. * ```
  703. */
  704. offset(offset) {
  705. if (this.config.setOperators.length > 0) {
  706. this.config.setOperators.at(-1).offset = offset;
  707. } else {
  708. this.config.offset = offset;
  709. }
  710. return this;
  711. }
  712. /**
  713. * Adds a `for` clause to the query.
  714. *
  715. * Calling this method will specify a lock strength for this query that controls how strictly it acquires exclusive access to the rows being queried.
  716. *
  717. * See docs: {@link https://www.postgresql.org/docs/current/sql-select.html#SQL-FOR-UPDATE-SHARE}
  718. *
  719. * @param strength the lock strength.
  720. * @param config the lock configuration.
  721. */
  722. for(strength, config = {}) {
  723. this.config.lockingClause = { strength, config };
  724. return this;
  725. }
  726. /** @internal */
  727. getSQL() {
  728. return this.dialect.buildSelectQuery(this.config);
  729. }
  730. toSQL() {
  731. const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL());
  732. return rest;
  733. }
  734. as(alias) {
  735. const usedTables = [];
  736. usedTables.push(...extractUsedTable(this.config.table));
  737. if (this.config.joins) {
  738. for (const it of this.config.joins) usedTables.push(...extractUsedTable(it.table));
  739. }
  740. return new Proxy(
  741. new Subquery(this.getSQL(), this.config.fields, alias, false, [...new Set(usedTables)]),
  742. new SelectionProxyHandler({ alias, sqlAliasedBehavior: "alias", sqlBehavior: "error" })
  743. );
  744. }
  745. /** @internal */
  746. getSelectedFields() {
  747. return new Proxy(
  748. this.config.fields,
  749. new SelectionProxyHandler({ alias: this.tableName, sqlAliasedBehavior: "alias", sqlBehavior: "error" })
  750. );
  751. }
  752. $dynamic() {
  753. return this;
  754. }
  755. $withCache(config) {
  756. this.cacheConfig = config === void 0 ? { config: {}, enable: true, autoInvalidate: true } : config === false ? { enable: false } : { enable: true, autoInvalidate: true, ...config };
  757. return this;
  758. }
  759. }
  760. class PgSelectBase extends PgSelectQueryBuilderBase {
  761. static [entityKind] = "PgSelect";
  762. /** @internal */
  763. _prepare(name) {
  764. const { session, config, dialect, joinsNotNullableMap, authToken, cacheConfig, usedTables } = this;
  765. if (!session) {
  766. throw new Error("Cannot execute a query on a query builder. Please use a database instance instead.");
  767. }
  768. const { fields } = config;
  769. return tracer.startActiveSpan("drizzle.prepareQuery", () => {
  770. const fieldsList = orderSelectedFields(fields);
  771. const query = session.prepareQuery(dialect.sqlToQuery(this.getSQL()), fieldsList, name, true, void 0, {
  772. type: "select",
  773. tables: [...usedTables]
  774. }, cacheConfig);
  775. query.joinsNotNullableMap = joinsNotNullableMap;
  776. return query.setToken(authToken);
  777. });
  778. }
  779. /**
  780. * Create a prepared statement for this query. This allows
  781. * the database to remember this query for the given session
  782. * and call it by name, rather than specifying the full query.
  783. *
  784. * {@link https://www.postgresql.org/docs/current/sql-prepare.html | Postgres prepare documentation}
  785. */
  786. prepare(name) {
  787. return this._prepare(name);
  788. }
  789. authToken;
  790. /** @internal */
  791. setToken(token) {
  792. this.authToken = token;
  793. return this;
  794. }
  795. execute = (placeholderValues) => {
  796. return tracer.startActiveSpan("drizzle.operation", () => {
  797. return this._prepare().execute(placeholderValues, this.authToken);
  798. });
  799. };
  800. }
  801. applyMixins(PgSelectBase, [QueryPromise]);
  802. function createSetOperator(type, isAll) {
  803. return (leftSelect, rightSelect, ...restSelects) => {
  804. const setOperators = [rightSelect, ...restSelects].map((select) => ({
  805. type,
  806. isAll,
  807. rightSelect: select
  808. }));
  809. for (const setOperator of setOperators) {
  810. if (!haveSameKeys(leftSelect.getSelectedFields(), setOperator.rightSelect.getSelectedFields())) {
  811. throw new Error(
  812. "Set operator error (union / intersect / except): selected fields are not the same or are in a different order"
  813. );
  814. }
  815. }
  816. return leftSelect.addSetOperators(setOperators);
  817. };
  818. }
  819. const getPgSetOperators = () => ({
  820. union,
  821. unionAll,
  822. intersect,
  823. intersectAll,
  824. except,
  825. exceptAll
  826. });
  827. const union = createSetOperator("union", false);
  828. const unionAll = createSetOperator("union", true);
  829. const intersect = createSetOperator("intersect", false);
  830. const intersectAll = createSetOperator("intersect", true);
  831. const except = createSetOperator("except", false);
  832. const exceptAll = createSetOperator("except", true);
  833. export {
  834. PgSelectBase,
  835. PgSelectBuilder,
  836. PgSelectQueryBuilderBase,
  837. except,
  838. exceptAll,
  839. intersect,
  840. intersectAll,
  841. union,
  842. unionAll
  843. };
  844. //# sourceMappingURL=select.js.map