insert.ts 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /* oxlint-disable */
  2. import type * as Effect from "effect/Effect"
  3. import { applyEffectWrapper, type QueryEffectHKTBase } from "drizzle-orm/effect-core/query-effect"
  4. import { entityKind, is } from "drizzle-orm/entity"
  5. import type { SelectResultFields } from "drizzle-orm/query-builders/select.types"
  6. import type { RunnableQuery } from "drizzle-orm/runnable-query"
  7. import type { Query, SQLWrapper } from "drizzle-orm/sql/sql"
  8. import { Param, SQL, sql } from "drizzle-orm/sql/sql"
  9. import type { SQLiteDialect } from "drizzle-orm/sqlite-core/dialect"
  10. import type { IndexColumn } from "drizzle-orm/sqlite-core/indexes"
  11. import type {
  12. SQLiteInsertConfig,
  13. SQLiteInsertSelectQueryBuilder,
  14. SQLiteInsertValue,
  15. } from "drizzle-orm/sqlite-core/query-builders/insert"
  16. import type { SelectedFieldsFlat } from "drizzle-orm/sqlite-core/query-builders/select.types"
  17. import type { PreparedQueryConfig } from "drizzle-orm/sqlite-core/session"
  18. import { SQLiteTable } from "drizzle-orm/sqlite-core/table"
  19. import { extractUsedTable } from "drizzle-orm/sqlite-core/utils"
  20. import type { Subquery } from "drizzle-orm/subquery"
  21. import { type DrizzleTypeError, haveSameKeys } from "drizzle-orm/utils"
  22. import type { SQLiteColumn } from "drizzle-orm/sqlite-core/columns/common"
  23. import { QueryBuilder } from "drizzle-orm/sqlite-core/query-builders/query-builder"
  24. import type { SQLiteUpdateSetSource } from "drizzle-orm/sqlite-core/query-builders/update"
  25. import { getTableColumnsRuntime, mapUpdateSet, orderSelectedFields } from "../../internal/drizzle-utils"
  26. import type { SQLiteEffectPreparedQuery, SQLiteEffectSession } from "./session"
  27. export type SQLiteEffectInsertWithout<
  28. T extends AnySQLiteEffectInsert,
  29. TDynamic extends boolean,
  30. K extends keyof T & string,
  31. > = TDynamic extends true
  32. ? T
  33. : Omit<
  34. SQLiteEffectInsertBase<
  35. T["_"]["table"],
  36. T["_"]["runResult"],
  37. T["_"]["returning"],
  38. TDynamic,
  39. T["_"]["excludedMethods"] | K,
  40. T["_"]["effectHKT"]
  41. >,
  42. T["_"]["excludedMethods"] | K
  43. >
  44. export type SQLiteEffectInsertReturning<
  45. T extends AnySQLiteEffectInsert,
  46. TDynamic extends boolean,
  47. TSelectedFields extends SelectedFieldsFlat,
  48. > = SQLiteEffectInsertWithout<
  49. SQLiteEffectInsertBase<
  50. T["_"]["table"],
  51. T["_"]["runResult"],
  52. SelectResultFields<TSelectedFields>,
  53. TDynamic,
  54. T["_"]["excludedMethods"],
  55. T["_"]["effectHKT"]
  56. >,
  57. TDynamic,
  58. "returning"
  59. >
  60. export type SQLiteEffectInsertReturningAll<
  61. T extends AnySQLiteEffectInsert,
  62. TDynamic extends boolean,
  63. > = SQLiteEffectInsertWithout<
  64. SQLiteEffectInsertBase<
  65. T["_"]["table"],
  66. T["_"]["runResult"],
  67. T["_"]["table"]["$inferSelect"],
  68. TDynamic,
  69. T["_"]["excludedMethods"],
  70. T["_"]["effectHKT"]
  71. >,
  72. TDynamic,
  73. "returning"
  74. >
  75. export type SQLiteEffectInsertDynamic<T extends AnySQLiteEffectInsert> = SQLiteEffectInsert<
  76. T["_"]["table"],
  77. T["_"]["runResult"],
  78. T["_"]["returning"],
  79. T["_"]["effectHKT"]
  80. >
  81. export type SQLiteEffectInsertOnConflictDoUpdateConfig<T extends AnySQLiteEffectInsert> = {
  82. target: IndexColumn | IndexColumn[]
  83. /** @deprecated - use either `targetWhere` or `setWhere` */
  84. where?: SQL
  85. targetWhere?: SQL
  86. setWhere?: SQL
  87. set: SQLiteUpdateSetSource<T["_"]["table"]>
  88. }
  89. export type SQLiteEffectInsertExecute<T extends AnySQLiteEffectInsert> = T["_"]["returning"] extends undefined
  90. ? T["_"]["runResult"]
  91. : T["_"]["returning"][]
  92. export type SQLiteEffectInsertPrepare<
  93. T extends AnySQLiteEffectInsert,
  94. TEffectHKT extends QueryEffectHKTBase = T["_"]["effectHKT"],
  95. > = SQLiteEffectPreparedQuery<
  96. PreparedQueryConfig & {
  97. run: T["_"]["runResult"]
  98. all: T["_"]["returning"] extends undefined
  99. ? DrizzleTypeError<".all() cannot be used without .returning()">
  100. : T["_"]["returning"][]
  101. get: T["_"]["returning"] extends undefined
  102. ? DrizzleTypeError<".get() cannot be used without .returning()">
  103. : T["_"]["returning"]
  104. values: T["_"]["returning"] extends undefined
  105. ? DrizzleTypeError<".values() cannot be used without .returning()">
  106. : any[][]
  107. execute: SQLiteEffectInsertExecute<T>
  108. },
  109. TEffectHKT
  110. >
  111. export type SQLiteEffectInsert<
  112. TTable extends SQLiteTable = SQLiteTable,
  113. TRunResult = unknown,
  114. TReturning = any,
  115. TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase,
  116. > = SQLiteEffectInsertBase<TTable, TRunResult, TReturning, true, never, TEffectHKT>
  117. export type AnySQLiteEffectInsert = SQLiteEffectInsertBase<any, any, any, any, any, any>
  118. export class SQLiteEffectInsertBuilder<
  119. TTable extends SQLiteTable,
  120. TRunResult,
  121. TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase,
  122. > {
  123. static readonly [entityKind]: string = "SQLiteEffectInsertBuilder"
  124. constructor(
  125. protected table: TTable,
  126. protected session: SQLiteEffectSession<TEffectHKT, TRunResult, any>,
  127. protected dialect: SQLiteDialect,
  128. private withList?: Subquery[],
  129. ) {}
  130. values(
  131. value: SQLiteInsertValue<TTable>,
  132. ): SQLiteEffectInsertBase<TTable, TRunResult, undefined, false, never, TEffectHKT>
  133. values(
  134. values: SQLiteInsertValue<TTable>[],
  135. ): SQLiteEffectInsertBase<TTable, TRunResult, undefined, false, never, TEffectHKT>
  136. values(
  137. values: SQLiteInsertValue<TTable> | SQLiteInsertValue<TTable>[],
  138. ): SQLiteEffectInsertBase<TTable, TRunResult, undefined, false, never, TEffectHKT> {
  139. values = Array.isArray(values) ? values : [values]
  140. if (values.length === 0) {
  141. throw new Error("values() must be called with at least one value")
  142. }
  143. const mappedValues = values.map((entry) => {
  144. const result: Record<string, Param | SQL> = {}
  145. const cols = getTableColumnsRuntime(this.table)
  146. for (const colKey of Object.keys(entry)) {
  147. const colValue = entry[colKey as keyof typeof entry]
  148. result[colKey] = is(colValue, SQL) ? colValue : new Param(colValue, cols[colKey])
  149. }
  150. return result
  151. })
  152. return new SQLiteEffectInsertBase(this.table, mappedValues, this.session, this.dialect, this.withList)
  153. }
  154. select(
  155. selectQuery: (qb: QueryBuilder) => SQLiteInsertSelectQueryBuilder<TTable>,
  156. ): SQLiteEffectInsertBase<TTable, TRunResult, undefined, false, never, TEffectHKT>
  157. select(
  158. selectQuery: (qb: QueryBuilder) => SQL,
  159. ): SQLiteEffectInsertBase<TTable, TRunResult, undefined, false, never, TEffectHKT>
  160. select(selectQuery: SQL): SQLiteEffectInsertBase<TTable, TRunResult, undefined, false, never, TEffectHKT>
  161. select(
  162. selectQuery: SQLiteInsertSelectQueryBuilder<TTable>,
  163. ): SQLiteEffectInsertBase<TTable, TRunResult, undefined, false, never, TEffectHKT>
  164. select(
  165. selectQuery:
  166. | SQL
  167. | SQLiteInsertSelectQueryBuilder<TTable>
  168. | ((qb: QueryBuilder) => SQLiteInsertSelectQueryBuilder<TTable> | SQL),
  169. ): SQLiteEffectInsertBase<TTable, TRunResult, undefined, false, never, TEffectHKT> {
  170. const select = typeof selectQuery === "function" ? selectQuery(new QueryBuilder()) : selectQuery
  171. if (!is(select, SQL) && !haveSameKeys(getTableColumnsRuntime(this.table), select._.selectedFields)) {
  172. throw new Error(
  173. "Insert select error: selected fields are not the same or are in a different order compared to the table definition",
  174. )
  175. }
  176. return new SQLiteEffectInsertBase(this.table, select, this.session, this.dialect, this.withList, true)
  177. }
  178. }
  179. export interface SQLiteEffectInsertBase<
  180. TTable extends SQLiteTable,
  181. TRunResult,
  182. TReturning = undefined,
  183. TDynamic extends boolean = false,
  184. _TExcludedMethods extends string = never,
  185. TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase,
  186. > extends SQLWrapper,
  187. RunnableQuery<TReturning extends undefined ? TRunResult : TReturning[], "sqlite">,
  188. Effect.Effect<
  189. TReturning extends undefined ? TRunResult : TReturning[],
  190. TEffectHKT["error"],
  191. TEffectHKT["context"]
  192. > {
  193. readonly _: {
  194. readonly dialect: "sqlite"
  195. readonly table: TTable
  196. readonly resultType: "async"
  197. readonly runResult: TRunResult
  198. readonly returning: TReturning
  199. readonly dynamic: TDynamic
  200. readonly excludedMethods: _TExcludedMethods
  201. readonly result: TReturning extends undefined ? TRunResult : TReturning[]
  202. readonly effectHKT: TEffectHKT
  203. }
  204. }
  205. export class SQLiteEffectInsertBase<
  206. TTable extends SQLiteTable,
  207. TRunResult,
  208. TReturning = undefined,
  209. TDynamic extends boolean = false,
  210. _TExcludedMethods extends string = never,
  211. TEffectHKT extends QueryEffectHKTBase = QueryEffectHKTBase,
  212. >
  213. implements RunnableQuery<TReturning extends undefined ? TRunResult : TReturning[], "sqlite">, SQLWrapper
  214. {
  215. static readonly [entityKind]: string = "SQLiteEffectInsert"
  216. /** @internal */
  217. config: SQLiteInsertConfig<TTable>
  218. constructor(
  219. private table: TTable,
  220. values: SQLiteInsertConfig["values"],
  221. private effectSession: SQLiteEffectSession<TEffectHKT, TRunResult, any>,
  222. private effectDialect: SQLiteDialect,
  223. withList?: Subquery[],
  224. select?: boolean,
  225. ) {
  226. this.config = { table, values: values as any, withList, select }
  227. }
  228. returning(): SQLiteEffectInsertReturningAll<this, TDynamic>
  229. returning<TSelectedFields extends SelectedFieldsFlat>(
  230. fields: TSelectedFields,
  231. ): SQLiteEffectInsertReturning<this, TDynamic, TSelectedFields>
  232. returning(
  233. fields: SelectedFieldsFlat = getTableColumnsRuntime(this.config.table),
  234. ): SQLiteEffectInsertWithout<AnySQLiteEffectInsert, TDynamic, "returning"> {
  235. this.config.returning = orderSelectedFields<SQLiteColumn>(fields)
  236. return this as any
  237. }
  238. onConflictDoNothing(config: { target?: IndexColumn | IndexColumn[]; where?: SQL } = {}): this {
  239. if (!this.config.onConflict) this.config.onConflict = []
  240. if (config.target === undefined) {
  241. this.config.onConflict.push(sql` on conflict do nothing`)
  242. return this
  243. }
  244. const targetSql = Array.isArray(config.target) ? sql`${config.target}` : sql`${[config.target]}`
  245. const whereSql = config.where ? sql` where ${config.where}` : sql``
  246. this.config.onConflict.push(sql` on conflict ${targetSql} do nothing${whereSql}`)
  247. return this
  248. }
  249. onConflictDoUpdate(config: SQLiteEffectInsertOnConflictDoUpdateConfig<this>): this {
  250. if (config.where && (config.targetWhere || config.setWhere)) {
  251. throw new Error(
  252. 'You cannot use both "where" and "targetWhere"/"setWhere" at the same time - "where" is deprecated, use "targetWhere" or "setWhere" instead.',
  253. )
  254. }
  255. if (!this.config.onConflict) this.config.onConflict = []
  256. const whereSql = config.where ? sql` where ${config.where}` : undefined
  257. const targetWhereSql = config.targetWhere ? sql` where ${config.targetWhere}` : undefined
  258. const setWhereSql = config.setWhere ? sql` where ${config.setWhere}` : undefined
  259. const targetSql = Array.isArray(config.target) ? sql`${config.target}` : sql`${[config.target]}`
  260. const setSql = this.effectDialect.buildUpdateSet(
  261. this.config.table,
  262. mapUpdateSet(this.config.table, config.set as SQLiteUpdateSetSource<TTable>),
  263. )
  264. this.config.onConflict.push(
  265. sql` on conflict ${targetSql}${targetWhereSql} do update set ${setSql}${whereSql}${setWhereSql}`,
  266. )
  267. return this
  268. }
  269. /** @internal */
  270. getSQL(): SQL {
  271. return this.effectDialect.buildInsertQuery(this.config)
  272. }
  273. toSQL(): Query {
  274. return this.effectDialect.sqlToQuery(this.getSQL())
  275. }
  276. /** @internal */
  277. _prepare(isOneTimeQuery = true): SQLiteEffectInsertPrepare<this, TEffectHKT> {
  278. return this.effectSession[isOneTimeQuery ? "prepareOneTimeQuery" : "prepareQuery"](
  279. this.effectDialect.sqlToQuery(this.getSQL()),
  280. this.config.returning,
  281. this.config.returning ? "all" : "run",
  282. undefined,
  283. {
  284. type: "insert",
  285. tables: extractUsedTable(this.config.table),
  286. },
  287. ) as SQLiteEffectInsertPrepare<this, TEffectHKT>
  288. }
  289. prepare(): SQLiteEffectInsertPrepare<this, TEffectHKT> {
  290. return this._prepare(false)
  291. }
  292. run: ReturnType<this["prepare"]>["run"] = (placeholderValues) => {
  293. return this._prepare().run(placeholderValues)
  294. }
  295. all: ReturnType<this["prepare"]>["all"] = (placeholderValues) => {
  296. return this._prepare().all(placeholderValues)
  297. }
  298. get: ReturnType<this["prepare"]>["get"] = (placeholderValues) => {
  299. return this._prepare().get(placeholderValues)
  300. }
  301. values: ReturnType<this["prepare"]>["values"] = (placeholderValues) => {
  302. return this._prepare().values(placeholderValues)
  303. }
  304. execute: ReturnType<this["prepare"]>["execute"] = (placeholderValues) => {
  305. return this._prepare().execute(placeholderValues)
  306. }
  307. $dynamic(): SQLiteEffectInsertDynamic<this> {
  308. return this as any
  309. }
  310. }
  311. applyEffectWrapper(SQLiteEffectInsertBase)