@remix-run/data-table 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +549 -2
  3. package/dist/index.d.ts +15 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +7 -0
  6. package/dist/lib/adapter.d.ts +550 -0
  7. package/dist/lib/adapter.d.ts.map +1 -0
  8. package/dist/lib/adapter.js +1 -0
  9. package/dist/lib/column.d.ts +193 -0
  10. package/dist/lib/column.d.ts.map +1 -0
  11. package/dist/lib/column.js +302 -0
  12. package/dist/lib/database/execution-context.d.ts +10 -0
  13. package/dist/lib/database/execution-context.d.ts.map +1 -0
  14. package/dist/lib/database/execution-context.js +1 -0
  15. package/dist/lib/database/helpers.d.ts +26 -0
  16. package/dist/lib/database/helpers.d.ts.map +1 -0
  17. package/dist/lib/database/helpers.js +116 -0
  18. package/dist/lib/database/query-execution.d.ts +7 -0
  19. package/dist/lib/database/query-execution.d.ts.map +1 -0
  20. package/dist/lib/database/query-execution.js +401 -0
  21. package/dist/lib/database/relations.d.ts +4 -0
  22. package/dist/lib/database/relations.d.ts.map +1 -0
  23. package/dist/lib/database/relations.js +207 -0
  24. package/dist/lib/database/write-lifecycle.d.ts +13 -0
  25. package/dist/lib/database/write-lifecycle.d.ts.map +1 -0
  26. package/dist/lib/database/write-lifecycle.js +279 -0
  27. package/dist/lib/database.d.ts +264 -0
  28. package/dist/lib/database.d.ts.map +1 -0
  29. package/dist/lib/database.js +319 -0
  30. package/dist/lib/errors.d.ts +59 -0
  31. package/dist/lib/errors.d.ts.map +1 -0
  32. package/dist/lib/errors.js +76 -0
  33. package/dist/lib/inflection.d.ts +3 -0
  34. package/dist/lib/inflection.d.ts.map +1 -0
  35. package/dist/lib/inflection.js +56 -0
  36. package/dist/lib/migrations/filename.d.ts +12 -0
  37. package/dist/lib/migrations/filename.d.ts.map +1 -0
  38. package/dist/lib/migrations/filename.js +20 -0
  39. package/dist/lib/migrations/helpers.d.ts +11 -0
  40. package/dist/lib/migrations/helpers.d.ts.map +1 -0
  41. package/dist/lib/migrations/helpers.js +77 -0
  42. package/dist/lib/migrations/journal-store.d.ts +15 -0
  43. package/dist/lib/migrations/journal-store.d.ts.map +1 -0
  44. package/dist/lib/migrations/journal-store.js +83 -0
  45. package/dist/lib/migrations/registry.d.ts +27 -0
  46. package/dist/lib/migrations/registry.d.ts.map +1 -0
  47. package/dist/lib/migrations/registry.js +51 -0
  48. package/dist/lib/migrations/runner.d.ts +20 -0
  49. package/dist/lib/migrations/runner.d.ts.map +1 -0
  50. package/dist/lib/migrations/runner.js +273 -0
  51. package/dist/lib/migrations/schema-api.d.ts +7 -0
  52. package/dist/lib/migrations/schema-api.d.ts.map +1 -0
  53. package/dist/lib/migrations/schema-api.js +326 -0
  54. package/dist/lib/migrations-node.d.ts +17 -0
  55. package/dist/lib/migrations-node.d.ts.map +1 -0
  56. package/dist/lib/migrations-node.js +65 -0
  57. package/dist/lib/migrations.d.ts +292 -0
  58. package/dist/lib/migrations.d.ts.map +1 -0
  59. package/dist/lib/migrations.js +38 -0
  60. package/dist/lib/operators.d.ts +154 -0
  61. package/dist/lib/operators.d.ts.map +1 -0
  62. package/dist/lib/operators.js +218 -0
  63. package/dist/lib/query.d.ts +159 -0
  64. package/dist/lib/query.d.ts.map +1 -0
  65. package/dist/lib/query.js +401 -0
  66. package/dist/lib/references.d.ts +41 -0
  67. package/dist/lib/references.d.ts.map +1 -0
  68. package/dist/lib/references.js +33 -0
  69. package/dist/lib/sql-helpers.d.ts +50 -0
  70. package/dist/lib/sql-helpers.d.ts.map +1 -0
  71. package/dist/lib/sql-helpers.js +111 -0
  72. package/dist/lib/sql.d.ts +45 -0
  73. package/dist/lib/sql.d.ts.map +1 -0
  74. package/dist/lib/sql.js +65 -0
  75. package/dist/lib/table.d.ts +569 -0
  76. package/dist/lib/table.d.ts.map +1 -0
  77. package/dist/lib/table.js +519 -0
  78. package/dist/lib/types.d.ts +4 -0
  79. package/dist/lib/types.d.ts.map +1 -0
  80. package/dist/lib/types.js +1 -0
  81. package/dist/migrations/node.d.ts +2 -0
  82. package/dist/migrations/node.d.ts.map +1 -0
  83. package/dist/migrations/node.js +1 -0
  84. package/dist/migrations.d.ts +8 -0
  85. package/dist/migrations.d.ts.map +1 -0
  86. package/dist/migrations.js +5 -0
  87. package/dist/operators.d.ts +3 -0
  88. package/dist/operators.d.ts.map +1 -0
  89. package/dist/operators.js +1 -0
  90. package/dist/sql-helpers.d.ts +3 -0
  91. package/dist/sql-helpers.d.ts.map +1 -0
  92. package/dist/sql-helpers.js +1 -0
  93. package/package.json +56 -7
  94. package/src/index.ts +198 -0
  95. package/src/lib/adapter.ts +653 -0
  96. package/src/lib/column.ts +384 -0
  97. package/src/lib/database/execution-context.ts +15 -0
  98. package/src/lib/database/helpers.ts +216 -0
  99. package/src/lib/database/query-execution.ts +638 -0
  100. package/src/lib/database/relations.ts +332 -0
  101. package/src/lib/database/write-lifecycle.ts +487 -0
  102. package/src/lib/database.ts +856 -0
  103. package/src/lib/errors.ts +119 -0
  104. package/src/lib/inflection.ts +69 -0
  105. package/src/lib/migrations/filename.ts +25 -0
  106. package/src/lib/migrations/helpers.ts +108 -0
  107. package/src/lib/migrations/journal-store.ts +122 -0
  108. package/src/lib/migrations/registry.ts +62 -0
  109. package/src/lib/migrations/runner.ts +374 -0
  110. package/src/lib/migrations/schema-api.ts +417 -0
  111. package/src/lib/migrations-node.ts +71 -0
  112. package/src/lib/migrations.ts +328 -0
  113. package/src/lib/operators.ts +436 -0
  114. package/src/lib/query.ts +958 -0
  115. package/src/lib/references.ts +78 -0
  116. package/src/lib/sql-helpers.ts +146 -0
  117. package/src/lib/sql.ts +84 -0
  118. package/src/lib/table.ts +1309 -0
  119. package/src/lib/types.ts +3 -0
  120. package/src/migrations/node.ts +1 -0
  121. package/src/migrations.ts +26 -0
  122. package/src/operators.ts +18 -0
  123. package/src/sql-helpers.ts +9 -0
@@ -0,0 +1,384 @@
1
+ import type { ColumnDefinition, ForeignKeyAction, IdentityOptions } from './adapter.ts'
2
+ import { toTableRef } from './migrations/helpers.ts'
3
+
4
+ /**
5
+ * Chainable builder used to describe physical column definitions.
6
+ */
7
+ export class ColumnBuilder<output = unknown> {
8
+ #definition: ColumnDefinition
9
+
10
+ constructor(definition: ColumnDefinition) {
11
+ this.#definition = definition
12
+ }
13
+
14
+ /**
15
+ * Marks the column as nullable.
16
+ * @returns The column builder with `null` added to its output type.
17
+ */
18
+ nullable(): ColumnBuilder<output | null> {
19
+ this.#definition.nullable = true
20
+ return this as unknown as ColumnBuilder<output | null>
21
+ }
22
+
23
+ /**
24
+ * Marks the column as non-nullable.
25
+ * @returns The column builder with `null` removed from its output type.
26
+ */
27
+ notNull(): ColumnBuilder<Exclude<output, null>> {
28
+ this.#definition.nullable = false
29
+ return this as unknown as ColumnBuilder<Exclude<output, null>>
30
+ }
31
+
32
+ /**
33
+ * Sets a literal default value for the column.
34
+ * @param value Default value to apply when the column is omitted.
35
+ * @returns The column builder.
36
+ */
37
+ default(value: unknown): ColumnBuilder<output> {
38
+ this.#definition.default = {
39
+ kind: 'literal',
40
+ value,
41
+ }
42
+ return this
43
+ }
44
+
45
+ /**
46
+ * Sets the column default to the current timestamp at write time.
47
+ * @returns The column builder.
48
+ */
49
+ defaultNow(): ColumnBuilder<output> {
50
+ this.#definition.default = {
51
+ kind: 'now',
52
+ }
53
+ return this
54
+ }
55
+
56
+ /**
57
+ * Sets a raw SQL expression as the column default.
58
+ * @param expression SQL expression used as the default value.
59
+ * @returns The column builder.
60
+ */
61
+ defaultSql(expression: string): ColumnBuilder<output> {
62
+ this.#definition.default = {
63
+ kind: 'sql',
64
+ expression,
65
+ }
66
+ return this
67
+ }
68
+
69
+ /**
70
+ * Marks the column as part of the primary key.
71
+ * @returns The column builder.
72
+ */
73
+ primaryKey(): ColumnBuilder<output> {
74
+ this.#definition.primaryKey = true
75
+ return this
76
+ }
77
+
78
+ /**
79
+ * Marks the column as unique.
80
+ * @param name Optional constraint name.
81
+ * @returns The column builder.
82
+ */
83
+ unique(name?: string): ColumnBuilder<output> {
84
+ this.#definition.unique = name ? { name } : true
85
+ return this
86
+ }
87
+
88
+ /**
89
+ * Adds a foreign-key reference for the column.
90
+ * @param table Referenced table name.
91
+ * @param name Constraint name.
92
+ * @returns The column builder.
93
+ */
94
+ references(table: string, name: string): ColumnBuilder<output>
95
+ /**
96
+ * Adds a foreign-key reference for the column.
97
+ * @param table Referenced table name.
98
+ * @param columns Referenced column list.
99
+ * @param name Constraint name.
100
+ * @returns The column builder.
101
+ */
102
+ references(table: string, columns: string | string[], name: string): ColumnBuilder<output>
103
+ references(
104
+ table: string,
105
+ columnsOrName: string | string[],
106
+ maybeName?: string,
107
+ ): ColumnBuilder<output> {
108
+ let columns = maybeName === undefined ? 'id' : columnsOrName
109
+ let name = maybeName === undefined ? String(columnsOrName) : maybeName
110
+
111
+ this.#definition.references = {
112
+ table: toTableRef(table),
113
+ columns: Array.isArray(columns) ? [...columns] : [columns],
114
+ onDelete: this.#definition.references?.onDelete,
115
+ onUpdate: this.#definition.references?.onUpdate,
116
+ name,
117
+ }
118
+ return this
119
+ }
120
+
121
+ /**
122
+ * Sets the foreign-key action used when the referenced row is deleted.
123
+ * @param action Delete action to apply.
124
+ * @returns The column builder.
125
+ */
126
+ onDelete(action: ForeignKeyAction): ColumnBuilder<output> {
127
+ if (!this.#definition.references) {
128
+ throw new Error('onDelete() requires references() to be set first')
129
+ }
130
+
131
+ this.#definition.references.onDelete = action
132
+ return this
133
+ }
134
+
135
+ /**
136
+ * Sets the foreign-key action used when the referenced row is updated.
137
+ * @param action Update action to apply.
138
+ * @returns The column builder.
139
+ */
140
+ onUpdate(action: ForeignKeyAction): ColumnBuilder<output> {
141
+ if (!this.#definition.references) {
142
+ throw new Error('onUpdate() requires references() to be set first')
143
+ }
144
+
145
+ this.#definition.references.onUpdate = action
146
+ return this
147
+ }
148
+
149
+ /**
150
+ * Adds a check constraint for the column.
151
+ * @param expression SQL check expression.
152
+ * @param name Constraint name.
153
+ * @returns The column builder.
154
+ */
155
+ check(expression: string, name: string): ColumnBuilder<output> {
156
+ let checks = this.#definition.checks ?? []
157
+ checks.push({ expression, name })
158
+ this.#definition.checks = checks
159
+ return this
160
+ }
161
+
162
+ /**
163
+ * Adds a database comment for the column.
164
+ * @param text Comment text.
165
+ * @returns The column builder.
166
+ */
167
+ comment(text: string): ColumnBuilder<output> {
168
+ this.#definition.comment = text
169
+ return this
170
+ }
171
+
172
+ /**
173
+ * Marks the column as computed from a SQL expression.
174
+ * @param expression SQL expression for the computed value.
175
+ * @param options Computed-column options.
176
+ * @param options.stored Whether the computed column should be stored instead of virtual.
177
+ * @returns The column builder.
178
+ */
179
+ computed(expression: string, options?: { stored?: boolean }): ColumnBuilder<output> {
180
+ this.#definition.computed = {
181
+ expression,
182
+ stored: options?.stored ?? true,
183
+ }
184
+ return this
185
+ }
186
+
187
+ /**
188
+ * Marks the column as unsigned when the dialect supports it.
189
+ * @returns The column builder.
190
+ */
191
+ unsigned(): ColumnBuilder<output> {
192
+ this.#definition.unsigned = true
193
+ return this
194
+ }
195
+
196
+ /**
197
+ * Marks the column as auto-incrementing when the dialect supports it.
198
+ * @returns The column builder.
199
+ */
200
+ autoIncrement(): ColumnBuilder<output> {
201
+ this.#definition.autoIncrement = true
202
+ return this
203
+ }
204
+
205
+ /**
206
+ * Configures an identity column strategy when the dialect supports it.
207
+ * @param options Identity sequence options.
208
+ * @returns The column builder.
209
+ */
210
+ identity(options?: IdentityOptions): ColumnBuilder<output> {
211
+ this.#definition.identity = options ?? {}
212
+ return this
213
+ }
214
+
215
+ /**
216
+ * Sets the collation for the column.
217
+ * @param name Collation name.
218
+ * @returns The column builder.
219
+ */
220
+ collate(name: string): ColumnBuilder<output> {
221
+ this.#definition.collate = name
222
+ return this
223
+ }
224
+
225
+ /**
226
+ * Sets the character set for the column.
227
+ * @param name Character set name.
228
+ * @returns The column builder.
229
+ */
230
+ charset(name: string): ColumnBuilder<output> {
231
+ this.#definition.charset = name
232
+ return this
233
+ }
234
+
235
+ /**
236
+ * Sets the column length.
237
+ * @param value Maximum length value.
238
+ * @returns The column builder.
239
+ */
240
+ length(value: number): ColumnBuilder<output> {
241
+ this.#definition.length = value
242
+ return this
243
+ }
244
+
245
+ /**
246
+ * Sets numeric precision and optional scale for the column.
247
+ * @param value Precision value.
248
+ * @param scale Optional scale value.
249
+ * @returns The column builder.
250
+ */
251
+ precision(value: number, scale?: number): ColumnBuilder<output> {
252
+ this.#definition.precision = value
253
+
254
+ if (scale !== undefined) {
255
+ this.#definition.scale = scale
256
+ }
257
+
258
+ return this
259
+ }
260
+
261
+ /**
262
+ * Sets numeric scale for the column.
263
+ * @param value Scale value.
264
+ * @returns The column builder.
265
+ */
266
+ scale(value: number): ColumnBuilder<output> {
267
+ this.#definition.scale = value
268
+ return this
269
+ }
270
+
271
+ /**
272
+ * Enables or disables timezone support for time-based columns.
273
+ * @param enabled Whether timezone support should be enabled.
274
+ * @returns The column builder.
275
+ */
276
+ timezone(enabled = true): ColumnBuilder<output> {
277
+ this.#definition.withTimezone = enabled
278
+ return this
279
+ }
280
+
281
+ /**
282
+ * Builds the immutable column definition.
283
+ * @returns A normalized column definition.
284
+ */
285
+ build(): ColumnDefinition {
286
+ return {
287
+ ...this.#definition,
288
+ checks: this.#definition.checks ? [...this.#definition.checks] : undefined,
289
+ }
290
+ }
291
+ }
292
+
293
+ /** Resolves the runtime output type from a column builder. */
294
+ export type ColumnOutput<column extends ColumnBuilder<any>> =
295
+ column extends ColumnBuilder<infer output> ? output : never
296
+
297
+ /** Input type accepted when writing values for a column builder. */
298
+ export type ColumnInput<column extends ColumnBuilder<any>> = ColumnOutput<column>
299
+
300
+ /**
301
+ * Public constructor namespace for column builders.
302
+ */
303
+ export type ColumnNamespace = {
304
+ varchar(length: number): ColumnBuilder<string>
305
+ text(): ColumnBuilder<string>
306
+ integer(): ColumnBuilder<number>
307
+ bigint(): ColumnBuilder
308
+ decimal(precision: number, scale: number): ColumnBuilder<number>
309
+ boolean(): ColumnBuilder<boolean>
310
+ uuid(): ColumnBuilder<string>
311
+ date(): ColumnBuilder
312
+ time(options?: { precision?: number; withTimezone?: boolean }): ColumnBuilder
313
+ timestamp(options?: { precision?: number; withTimezone?: boolean }): ColumnBuilder
314
+ json(): ColumnBuilder
315
+ binary(length?: number): ColumnBuilder
316
+ enum<values extends readonly string[]>(values: values): ColumnBuilder<values[number]>
317
+ }
318
+
319
+ function createColumnBuilder<output = unknown>(
320
+ type: ColumnDefinition['type'],
321
+ ): ColumnBuilder<output> {
322
+ return new ColumnBuilder({ type })
323
+ }
324
+
325
+ /**
326
+ * Chainable column builder namespace.
327
+ * @example
328
+ * ```ts
329
+ * import { column as c } from 'remix/data-table'
330
+ *
331
+ * let email = c.varchar(255).notNull().unique('users_email_uq')
332
+ * ```
333
+ */
334
+ export const column: ColumnNamespace = {
335
+ varchar(length: number) {
336
+ return new ColumnBuilder({ type: 'varchar', length })
337
+ },
338
+ text() {
339
+ return createColumnBuilder<string>('text')
340
+ },
341
+ integer() {
342
+ return createColumnBuilder<number>('integer')
343
+ },
344
+ bigint() {
345
+ return createColumnBuilder('bigint')
346
+ },
347
+ decimal(precision: number, scale: number) {
348
+ return new ColumnBuilder({ type: 'decimal', precision, scale })
349
+ },
350
+ boolean() {
351
+ return createColumnBuilder<boolean>('boolean')
352
+ },
353
+ uuid() {
354
+ return createColumnBuilder<string>('uuid')
355
+ },
356
+ date() {
357
+ return createColumnBuilder('date')
358
+ },
359
+ time(options?: { precision?: number; withTimezone?: boolean }) {
360
+ return new ColumnBuilder({
361
+ type: 'time',
362
+ precision: options?.precision,
363
+ withTimezone: options?.withTimezone,
364
+ })
365
+ },
366
+ timestamp(options?: { precision?: number; withTimezone?: boolean }) {
367
+ return new ColumnBuilder({
368
+ type: 'timestamp',
369
+ precision: options?.precision,
370
+ withTimezone: options?.withTimezone,
371
+ })
372
+ },
373
+ json() {
374
+ return createColumnBuilder('json')
375
+ },
376
+ binary(length?: number) {
377
+ return new ColumnBuilder({ type: 'binary', length })
378
+ },
379
+ enum<values extends readonly string[]>(values: values) {
380
+ return new ColumnBuilder({ type: 'enum', enumValues: [...values] }) as ColumnBuilder<
381
+ values[number]
382
+ >
383
+ },
384
+ }
@@ -0,0 +1,15 @@
1
+ import type {
2
+ DataManipulationOperation,
3
+ DataManipulationResult,
4
+ DatabaseAdapter,
5
+ } from '../adapter.ts'
6
+ import type { Database } from '../database.ts'
7
+
8
+ export const executeOperation = Symbol('executeOperation')
9
+
10
+ export type QueryExecutionContext = {
11
+ adapter: DatabaseAdapter
12
+ now(): unknown
13
+ transaction<result>(callback: (database: Database) => Promise<result>): Promise<result>
14
+ [executeOperation](operation: DataManipulationOperation): Promise<DataManipulationResult>
15
+ }
@@ -0,0 +1,216 @@
1
+ import { DataTableQueryError } from '../errors.ts'
2
+ import type {
3
+ OrderByInput,
4
+ OrderByTuple,
5
+ QueryColumnName,
6
+ QueryColumns,
7
+ QueryColumnTypeMap,
8
+ QueryTableInput,
9
+ SingleTableWhere,
10
+ TableColumnName,
11
+ WriteResult,
12
+ WriteRowsResult,
13
+ } from '../database.ts'
14
+ import type { Predicate } from '../operators.ts'
15
+ import { and, eq, inList, or } from '../operators.ts'
16
+ import { query as createQuery } from '../query.ts'
17
+ import type { AnyTable, PrimaryKeyInput, TableName, TablePrimaryKey, TableRow } from '../table.ts'
18
+ import { getPrimaryKeyObject, getTableName, getTablePrimaryKey } from '../table.ts'
19
+
20
+ import type { QueryExecutionContext } from './execution-context.ts'
21
+ import { loadRowsWithRelationsForQuery } from './query-execution.ts'
22
+
23
+ export function asQueryTableInput<table extends AnyTable>(
24
+ table: table,
25
+ ): QueryTableInput<TableName<table>, TableRow<table>, TablePrimaryKey<table>> {
26
+ return table as unknown as QueryTableInput<
27
+ TableName<table>,
28
+ TableRow<table>,
29
+ TablePrimaryKey<table>
30
+ >
31
+ }
32
+
33
+ export function getPrimaryKeyWhere<table extends AnyTable>(
34
+ table: table,
35
+ value: PrimaryKeyInput<table>,
36
+ ): SingleTableWhere<table> {
37
+ return getPrimaryKeyObject(table, value as any) as SingleTableWhere<table>
38
+ }
39
+
40
+ export function getPrimaryKeyWhereFromRow<table extends AnyTable>(
41
+ table: table,
42
+ row: Record<string, unknown>,
43
+ ): SingleTableWhere<table> {
44
+ let where: Record<string, unknown> = {}
45
+
46
+ for (let key of getTablePrimaryKey(table) as string[]) {
47
+ where[key] = row[key]
48
+ }
49
+
50
+ return where as SingleTableWhere<table>
51
+ }
52
+
53
+ export function resolveCreateRowWhere<table extends AnyTable>(
54
+ table: table,
55
+ values: Partial<TableRow<table>>,
56
+ insertId: unknown,
57
+ ): SingleTableWhere<table> {
58
+ let primaryKey = getTablePrimaryKey(table) as string[]
59
+
60
+ if (primaryKey.length === 1) {
61
+ let key = primaryKey[0]
62
+
63
+ if (Object.prototype.hasOwnProperty.call(values, key)) {
64
+ return {
65
+ [key]: (values as Record<string, unknown>)[key],
66
+ } as SingleTableWhere<table>
67
+ }
68
+
69
+ if (insertId !== undefined) {
70
+ return {
71
+ [key]: insertId,
72
+ } as SingleTableWhere<table>
73
+ }
74
+ }
75
+
76
+ let where: Record<string, unknown> = {}
77
+
78
+ for (let key of primaryKey) {
79
+ if (!Object.prototype.hasOwnProperty.call(values, key)) {
80
+ throw new DataTableQueryError(
81
+ 'create({ returnRow: true }) requires primary key values for table "' +
82
+ getTableName(table) +
83
+ '" when adapter does not support RETURNING',
84
+ )
85
+ }
86
+
87
+ where[key] = (values as Record<string, unknown>)[key]
88
+ }
89
+
90
+ return where as SingleTableWhere<table>
91
+ }
92
+
93
+ export function normalizeOrderByInput<table extends AnyTable>(
94
+ input: OrderByInput<table> | undefined,
95
+ ): OrderByTuple<table>[] {
96
+ if (!input) {
97
+ return []
98
+ }
99
+
100
+ if (input.length === 0) {
101
+ return []
102
+ }
103
+
104
+ if (Array.isArray(input[0])) {
105
+ return input as OrderByTuple<table>[]
106
+ }
107
+
108
+ return [input as OrderByTuple<table>]
109
+ }
110
+
111
+ export function toWriteResult(result: WriteResult | WriteRowsResult<unknown>): WriteResult {
112
+ return {
113
+ affectedRows: result.affectedRows,
114
+ insertId: result.insertId,
115
+ }
116
+ }
117
+
118
+ export function hasScopedWriteModifiers(state: {
119
+ orderBy: unknown[]
120
+ limit?: number
121
+ offset?: number
122
+ }): boolean {
123
+ return state.orderBy.length > 0 || state.limit !== undefined || state.offset !== undefined
124
+ }
125
+
126
+ export async function loadPrimaryKeyRowsForScope<table extends AnyTable>(
127
+ database: QueryExecutionContext,
128
+ table: table,
129
+ state: {
130
+ where: Predicate<string>[]
131
+ orderBy: Array<{ column: string; direction: 'asc' | 'desc' }>
132
+ limit?: number
133
+ offset?: number
134
+ },
135
+ ): Promise<Record<string, unknown>[]> {
136
+ let query = createQuery(
137
+ table as unknown as QueryTableInput<TableName<table>, TableRow<table>, TablePrimaryKey<table>>,
138
+ )
139
+
140
+ for (let predicate of state.where) {
141
+ query = query.where(predicate as Predicate<QueryColumnName<table>>)
142
+ }
143
+
144
+ for (let clause of state.orderBy) {
145
+ query = query.orderBy(
146
+ clause.column as QueryColumns<QueryColumnTypeMap<table>>,
147
+ clause.direction,
148
+ )
149
+ }
150
+
151
+ if (state.limit !== undefined) {
152
+ query = query.limit(state.limit)
153
+ }
154
+
155
+ if (state.offset !== undefined) {
156
+ query = query.offset(state.offset)
157
+ }
158
+
159
+ let rows = await loadRowsWithRelationsForQuery(
160
+ database,
161
+ query.select(...(getTablePrimaryKey(table) as (keyof TableRow<table> & string)[])),
162
+ )
163
+ let primaryKeys = getTablePrimaryKey(table) as string[]
164
+
165
+ return rows.map((row) => {
166
+ let keyObject: Record<string, unknown> = {}
167
+
168
+ for (let key of rowKeys(row as Record<string, unknown>, primaryKeys)) {
169
+ keyObject[key] = (row as Record<string, unknown>)[key]
170
+ }
171
+
172
+ return keyObject
173
+ })
174
+ }
175
+
176
+ export function buildPrimaryKeyPredicate<table extends AnyTable>(
177
+ table: table,
178
+ keyObjects: Record<string, unknown>[],
179
+ ): Predicate<TableColumnName<table>> | undefined {
180
+ let primaryKey = getTablePrimaryKey(table)
181
+
182
+ if (keyObjects.length === 0) {
183
+ return undefined
184
+ }
185
+
186
+ if (primaryKey.length === 1) {
187
+ let key = primaryKey[0] as TableColumnName<table>
188
+ return inList(
189
+ key,
190
+ keyObjects.map((objectValue) => objectValue[key]),
191
+ )
192
+ }
193
+
194
+ let predicates = keyObjects.map((objectValue) => {
195
+ let comparisons = primaryKey.map((key) => {
196
+ let typedKey = key as TableColumnName<table>
197
+ return eq(typedKey, objectValue[typedKey])
198
+ })
199
+
200
+ return and(...comparisons)
201
+ })
202
+
203
+ return or(...predicates)
204
+ }
205
+
206
+ function rowKeys(row: Record<string, unknown>, keys: string[]): string[] {
207
+ let output: string[] = []
208
+
209
+ for (let key of keys) {
210
+ if (Object.prototype.hasOwnProperty.call(row, key)) {
211
+ output.push(key)
212
+ }
213
+ }
214
+
215
+ return output
216
+ }