insert.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import { entityKind, is } from "../../entity.js";
  2. import { QueryPromise } from "../../query-promise.js";
  3. import { Param, SQL } from "../../sql/sql.js";
  4. import { Columns, Table } from "../../table.js";
  5. import { tracer } from "../../tracing.js";
  6. import { haveSameKeys, orderSelectedFields } from "../../utils.js";
  7. import { extractUsedTable } from "../utils.js";
  8. import { QueryBuilder } from "./query-builder.js";
  9. class GelInsertBuilder {
  10. constructor(table, session, dialect, withList, overridingSystemValue_) {
  11. this.table = table;
  12. this.session = session;
  13. this.dialect = dialect;
  14. this.withList = withList;
  15. this.overridingSystemValue_ = overridingSystemValue_;
  16. }
  17. static [entityKind] = "GelInsertBuilder";
  18. authToken;
  19. /** @internal */
  20. setToken(token) {
  21. this.authToken = token;
  22. return this;
  23. }
  24. overridingSystemValue() {
  25. this.overridingSystemValue_ = true;
  26. return this;
  27. }
  28. values(values) {
  29. values = Array.isArray(values) ? values : [values];
  30. if (values.length === 0) {
  31. throw new Error("values() must be called with at least one value");
  32. }
  33. const mappedValues = values.map((entry) => {
  34. const result = {};
  35. const cols = this.table[Table.Symbol.Columns];
  36. for (const colKey of Object.keys(entry)) {
  37. const colValue = entry[colKey];
  38. result[colKey] = is(colValue, SQL) ? colValue : new Param(colValue, cols[colKey]);
  39. }
  40. return result;
  41. });
  42. return new GelInsertBase(
  43. this.table,
  44. mappedValues,
  45. this.session,
  46. this.dialect,
  47. this.withList,
  48. false,
  49. this.overridingSystemValue_
  50. );
  51. }
  52. select(selectQuery) {
  53. const select = typeof selectQuery === "function" ? selectQuery(new QueryBuilder()) : selectQuery;
  54. if (!is(select, SQL) && !haveSameKeys(this.table[Columns], select._.selectedFields)) {
  55. throw new Error(
  56. "Insert select error: selected fields are not the same or are in a different order compared to the table definition"
  57. );
  58. }
  59. return new GelInsertBase(this.table, select, this.session, this.dialect, this.withList, true);
  60. }
  61. }
  62. class GelInsertBase extends QueryPromise {
  63. constructor(table, values, session, dialect, withList, select, overridingSystemValue_) {
  64. super();
  65. this.session = session;
  66. this.dialect = dialect;
  67. this.config = { table, values, withList, select, overridingSystemValue_ };
  68. }
  69. static [entityKind] = "GelInsert";
  70. config;
  71. returning(fields = this.config.table[Table.Symbol.Columns]) {
  72. this.config.returning = orderSelectedFields(fields);
  73. return this;
  74. }
  75. /**
  76. * Adds an `on conflict do nothing` clause to the query.
  77. *
  78. * Calling this method simply avoids inserting a row as its alternative action.
  79. *
  80. * See docs: {@link https://orm.drizzle.team/docs/insert#on-conflict-do-nothing}
  81. *
  82. * @param config The `target` and `where` clauses.
  83. *
  84. * @example
  85. * ```ts
  86. * // Insert one row and cancel the insert if there's a conflict
  87. * await db.insert(cars)
  88. * .values({ id: 1, brand: 'BMW' })
  89. * .onConflictDoNothing();
  90. *
  91. * // Explicitly specify conflict target
  92. * await db.insert(cars)
  93. * .values({ id: 1, brand: 'BMW' })
  94. * .onConflictDoNothing({ target: cars.id });
  95. * ```
  96. */
  97. // TODO not supported
  98. // onConflictDoNothing(
  99. // config: { target?: IndexColumn | IndexColumn[]; where?: SQL } = {},
  100. // ): GelInsertWithout<this, TDynamic, 'onConflictDoNothing' | 'onConflictDoUpdate'> {
  101. // if (config.target === undefined) {
  102. // this.config.onConflict = sql`do nothing`;
  103. // } else {
  104. // let targetColumn = '';
  105. // targetColumn = Array.isArray(config.target)
  106. // ? config.target.map((it) => this.dialect.escapeName(this.dialect.casing.getColumnCasing(it))).join(',')
  107. // : this.dialect.escapeName(this.dialect.casing.getColumnCasing(config.target));
  108. // const whereSql = config.where ? sql` where ${config.where}` : undefined;
  109. // this.config.onConflict = sql`(${sql.raw(targetColumn)})${whereSql} do nothing`;
  110. // }
  111. // return this as any;
  112. // }
  113. /**
  114. * Adds an `on conflict do update` clause to the query.
  115. *
  116. * Calling this method will update the existing row that conflicts with the row proposed for insertion as its alternative action.
  117. *
  118. * See docs: {@link https://orm.drizzle.team/docs/insert#upserts-and-conflicts}
  119. *
  120. * @param config The `target`, `set` and `where` clauses.
  121. *
  122. * @example
  123. * ```ts
  124. * // Update the row if there's a conflict
  125. * await db.insert(cars)
  126. * .values({ id: 1, brand: 'BMW' })
  127. * .onConflictDoUpdate({
  128. * target: cars.id,
  129. * set: { brand: 'Porsche' }
  130. * });
  131. *
  132. * // Upsert with 'where' clause
  133. * await db.insert(cars)
  134. * .values({ id: 1, brand: 'BMW' })
  135. * .onConflictDoUpdate({
  136. * target: cars.id,
  137. * set: { brand: 'newBMW' },
  138. * targetWhere: sql`${cars.createdAt} > '2023-01-01'::date`,
  139. * });
  140. * ```
  141. */
  142. // TODO not supported
  143. // onConflictDoUpdate(
  144. // config: GelInsertOnConflictDoUpdateConfig<this>,
  145. // ): GelInsertWithout<this, TDynamic, 'onConflictDoNothing' | 'onConflictDoUpdate'> {
  146. // if (config.where && (config.targetWhere || config.setWhere)) {
  147. // throw new Error(
  148. // 'You cannot use both "where" and "targetWhere"/"setWhere" at the same time - "where" is deprecated, use "targetWhere" or "setWhere" instead.',
  149. // );
  150. // }
  151. // const whereSql = config.where ? sql` where ${config.where}` : undefined;
  152. // const targetWhereSql = config.targetWhere ? sql` where ${config.targetWhere}` : undefined;
  153. // const setWhereSql = config.setWhere ? sql` where ${config.setWhere}` : undefined;
  154. // const setSql = this.dialect.buildUpdateSet(this.config.table, mapUpdateSet(this.config.table, config.set));
  155. // let targetColumn = '';
  156. // targetColumn = Array.isArray(config.target)
  157. // ? config.target.map((it) => this.dialect.escapeName(this.dialect.casing.getColumnCasing(it))).join(',')
  158. // : this.dialect.escapeName(this.dialect.casing.getColumnCasing(config.target));
  159. // this.config.onConflict = sql`(${
  160. // sql.raw(targetColumn)
  161. // })${targetWhereSql} do update set ${setSql}${whereSql}${setWhereSql}`;
  162. // return this as any;
  163. // }
  164. /** @internal */
  165. getSQL() {
  166. return this.dialect.buildInsertQuery(this.config);
  167. }
  168. toSQL() {
  169. const { typings: _typings, ...rest } = this.dialect.sqlToQuery(this.getSQL());
  170. return rest;
  171. }
  172. /** @internal */
  173. _prepare(name) {
  174. return tracer.startActiveSpan("drizzle.prepareQuery", () => {
  175. return this.session.prepareQuery(this.dialect.sqlToQuery(this.getSQL()), this.config.returning, name, true, void 0, {
  176. type: "insert",
  177. tables: extractUsedTable(this.config.table)
  178. });
  179. });
  180. }
  181. prepare(name) {
  182. return this._prepare(name);
  183. }
  184. execute = (placeholderValues) => {
  185. return tracer.startActiveSpan("drizzle.operation", () => {
  186. return this._prepare().execute(placeholderValues);
  187. });
  188. };
  189. $dynamic() {
  190. return this;
  191. }
  192. }
  193. export {
  194. GelInsertBase,
  195. GelInsertBuilder
  196. };
  197. //# sourceMappingURL=insert.js.map