db.js 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import { entityKind } from "../entity.js";
  2. import { SelectionProxyHandler } from "../selection-proxy.js";
  3. import { sql } from "../sql/sql.js";
  4. import { WithSubquery } from "../subquery.js";
  5. import { SingleStoreCountBuilder } from "./query-builders/count.js";
  6. import {
  7. QueryBuilder,
  8. SingleStoreDeleteBase,
  9. SingleStoreInsertBuilder,
  10. SingleStoreSelectBuilder,
  11. SingleStoreUpdateBuilder
  12. } from "./query-builders/index.js";
  13. class SingleStoreDatabase {
  14. constructor(dialect, session, schema) {
  15. this.dialect = dialect;
  16. this.session = session;
  17. this._ = schema ? {
  18. schema: schema.schema,
  19. fullSchema: schema.fullSchema,
  20. tableNamesMap: schema.tableNamesMap
  21. } : {
  22. schema: void 0,
  23. fullSchema: {},
  24. tableNamesMap: {}
  25. };
  26. this.query = {};
  27. this.$cache = { invalidate: async (_params) => {
  28. } };
  29. }
  30. static [entityKind] = "SingleStoreDatabase";
  31. // We are waiting for SingleStore support for `json_array` function
  32. /**@inrernal */
  33. query;
  34. /**
  35. * Creates a subquery that defines a temporary named result set as a CTE.
  36. *
  37. * It is useful for breaking down complex queries into simpler parts and for reusing the result set in subsequent parts of the query.
  38. *
  39. * See docs: {@link https://orm.drizzle.team/docs/select#with-clause}
  40. *
  41. * @param alias The alias for the subquery.
  42. *
  43. * Failure to provide an alias will result in a DrizzleTypeError, preventing the subquery from being referenced in other queries.
  44. *
  45. * @example
  46. *
  47. * ```ts
  48. * // Create a subquery with alias 'sq' and use it in the select query
  49. * const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));
  50. *
  51. * const result = await db.with(sq).select().from(sq);
  52. * ```
  53. *
  54. * To select arbitrary SQL values as fields in a CTE and reference them in other CTEs or in the main query, you need to add aliases to them:
  55. *
  56. * ```ts
  57. * // Select an arbitrary SQL value as a field in a CTE and reference it in the main query
  58. * const sq = db.$with('sq').as(db.select({
  59. * name: sql<string>`upper(${users.name})`.as('name'),
  60. * })
  61. * .from(users));
  62. *
  63. * const result = await db.with(sq).select({ name: sq.name }).from(sq);
  64. * ```
  65. */
  66. $with = (alias, selection) => {
  67. const self = this;
  68. const as = (qb) => {
  69. if (typeof qb === "function") {
  70. qb = qb(new QueryBuilder(self.dialect));
  71. }
  72. return new Proxy(
  73. new WithSubquery(
  74. qb.getSQL(),
  75. selection ?? ("getSelectedFields" in qb ? qb.getSelectedFields() ?? {} : {}),
  76. alias,
  77. true
  78. ),
  79. new SelectionProxyHandler({ alias, sqlAliasedBehavior: "alias", sqlBehavior: "error" })
  80. );
  81. };
  82. return { as };
  83. };
  84. $count(source, filters) {
  85. return new SingleStoreCountBuilder({ source, filters, session: this.session });
  86. }
  87. /**
  88. * Incorporates a previously defined CTE (using `$with`) into the main query.
  89. *
  90. * This method allows the main query to reference a temporary named result set.
  91. *
  92. * See docs: {@link https://orm.drizzle.team/docs/select#with-clause}
  93. *
  94. * @param queries The CTEs to incorporate into the main query.
  95. *
  96. * @example
  97. *
  98. * ```ts
  99. * // Define a subquery 'sq' as a CTE using $with
  100. * const sq = db.$with('sq').as(db.select().from(users).where(eq(users.id, 42)));
  101. *
  102. * // Incorporate the CTE 'sq' into the main query and select from it
  103. * const result = await db.with(sq).select().from(sq);
  104. * ```
  105. */
  106. with(...queries) {
  107. const self = this;
  108. function select(fields) {
  109. return new SingleStoreSelectBuilder({
  110. fields: fields ?? void 0,
  111. session: self.session,
  112. dialect: self.dialect,
  113. withList: queries
  114. });
  115. }
  116. function selectDistinct(fields) {
  117. return new SingleStoreSelectBuilder({
  118. fields: fields ?? void 0,
  119. session: self.session,
  120. dialect: self.dialect,
  121. withList: queries,
  122. distinct: true
  123. });
  124. }
  125. function update(table) {
  126. return new SingleStoreUpdateBuilder(table, self.session, self.dialect, queries);
  127. }
  128. function delete_(table) {
  129. return new SingleStoreDeleteBase(table, self.session, self.dialect, queries);
  130. }
  131. return { select, selectDistinct, update, delete: delete_ };
  132. }
  133. select(fields) {
  134. return new SingleStoreSelectBuilder({ fields: fields ?? void 0, session: this.session, dialect: this.dialect });
  135. }
  136. selectDistinct(fields) {
  137. return new SingleStoreSelectBuilder({
  138. fields: fields ?? void 0,
  139. session: this.session,
  140. dialect: this.dialect,
  141. distinct: true
  142. });
  143. }
  144. /**
  145. * Creates an update query.
  146. *
  147. * Calling this method without `.where()` clause will update all rows in a table. The `.where()` clause specifies which rows should be updated.
  148. *
  149. * Use `.set()` method to specify which values to update.
  150. *
  151. * See docs: {@link https://orm.drizzle.team/docs/update}
  152. *
  153. * @param table The table to update.
  154. *
  155. * @example
  156. *
  157. * ```ts
  158. * // Update all rows in the 'cars' table
  159. * await db.update(cars).set({ color: 'red' });
  160. *
  161. * // Update rows with filters and conditions
  162. * await db.update(cars).set({ color: 'red' }).where(eq(cars.brand, 'BMW'));
  163. * ```
  164. */
  165. update(table) {
  166. return new SingleStoreUpdateBuilder(table, this.session, this.dialect);
  167. }
  168. /**
  169. * Creates an insert query.
  170. *
  171. * Calling this method will create new rows in a table. Use `.values()` method to specify which values to insert.
  172. *
  173. * See docs: {@link https://orm.drizzle.team/docs/insert}
  174. *
  175. * @param table The table to insert into.
  176. *
  177. * @example
  178. *
  179. * ```ts
  180. * // Insert one row
  181. * await db.insert(cars).values({ brand: 'BMW' });
  182. *
  183. * // Insert multiple rows
  184. * await db.insert(cars).values([{ brand: 'BMW' }, { brand: 'Porsche' }]);
  185. * ```
  186. */
  187. insert(table) {
  188. return new SingleStoreInsertBuilder(table, this.session, this.dialect);
  189. }
  190. /**
  191. * Creates a delete query.
  192. *
  193. * Calling this method without `.where()` clause will delete all rows in a table. The `.where()` clause specifies which rows should be deleted.
  194. *
  195. * See docs: {@link https://orm.drizzle.team/docs/delete}
  196. *
  197. * @param table The table to delete from.
  198. *
  199. * @example
  200. *
  201. * ```ts
  202. * // Delete all rows in the 'cars' table
  203. * await db.delete(cars);
  204. *
  205. * // Delete rows with filters and conditions
  206. * await db.delete(cars).where(eq(cars.color, 'green'));
  207. * ```
  208. */
  209. delete(table) {
  210. return new SingleStoreDeleteBase(table, this.session, this.dialect);
  211. }
  212. execute(query) {
  213. return this.session.execute(typeof query === "string" ? sql.raw(query) : query.getSQL());
  214. }
  215. $cache;
  216. transaction(transaction, config) {
  217. return this.session.transaction(transaction, config);
  218. }
  219. }
  220. const withReplicas = (primary, replicas, getReplica = () => replicas[Math.floor(Math.random() * replicas.length)]) => {
  221. const select = (...args) => getReplica(replicas).select(...args);
  222. const selectDistinct = (...args) => getReplica(replicas).selectDistinct(...args);
  223. const $count = (...args) => getReplica(replicas).$count(...args);
  224. const $with = (...args) => getReplica(replicas).with(...args);
  225. const update = (...args) => primary.update(...args);
  226. const insert = (...args) => primary.insert(...args);
  227. const $delete = (...args) => primary.delete(...args);
  228. const execute = (...args) => primary.execute(...args);
  229. const transaction = (...args) => primary.transaction(...args);
  230. return {
  231. ...primary,
  232. update,
  233. insert,
  234. delete: $delete,
  235. execute,
  236. transaction,
  237. $primary: primary,
  238. $replicas: replicas,
  239. select,
  240. selectDistinct,
  241. $count,
  242. with: $with,
  243. get query() {
  244. return getReplica(replicas).query;
  245. }
  246. };
  247. };
  248. export {
  249. SingleStoreDatabase,
  250. withReplicas
  251. };
  252. //# sourceMappingURL=db.js.map