@remix-run/data-table 0.1.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.
- package/README.md +306 -55
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/lib/adapter.d.ts +386 -16
- package/dist/lib/adapter.d.ts.map +1 -1
- package/dist/lib/column.d.ts +193 -0
- package/dist/lib/column.d.ts.map +1 -0
- package/dist/lib/column.js +302 -0
- package/dist/lib/database/execution-context.d.ts +10 -0
- package/dist/lib/database/execution-context.d.ts.map +1 -0
- package/dist/lib/database/execution-context.js +1 -0
- package/dist/lib/database/helpers.d.ts +26 -0
- package/dist/lib/database/helpers.d.ts.map +1 -0
- package/dist/lib/database/helpers.js +116 -0
- package/dist/lib/database/query-execution.d.ts +7 -0
- package/dist/lib/database/query-execution.d.ts.map +1 -0
- package/dist/lib/database/query-execution.js +401 -0
- package/dist/lib/database/relations.d.ts +4 -0
- package/dist/lib/database/relations.d.ts.map +1 -0
- package/dist/lib/database/relations.js +207 -0
- package/dist/lib/database/write-lifecycle.d.ts +13 -0
- package/dist/lib/database/write-lifecycle.d.ts.map +1 -0
- package/dist/lib/database/write-lifecycle.js +279 -0
- package/dist/lib/database.d.ts +141 -238
- package/dist/lib/database.d.ts.map +1 -1
- package/dist/lib/database.js +73 -1122
- package/dist/lib/errors.d.ts +9 -0
- package/dist/lib/errors.d.ts.map +1 -1
- package/dist/lib/errors.js +9 -0
- package/dist/lib/migrations/filename.d.ts +12 -0
- package/dist/lib/migrations/filename.d.ts.map +1 -0
- package/dist/lib/migrations/filename.js +20 -0
- package/dist/lib/migrations/helpers.d.ts +11 -0
- package/dist/lib/migrations/helpers.d.ts.map +1 -0
- package/dist/lib/migrations/helpers.js +77 -0
- package/dist/lib/migrations/journal-store.d.ts +15 -0
- package/dist/lib/migrations/journal-store.d.ts.map +1 -0
- package/dist/lib/migrations/journal-store.js +83 -0
- package/dist/lib/migrations/registry.d.ts +27 -0
- package/dist/lib/migrations/registry.d.ts.map +1 -0
- package/dist/lib/migrations/registry.js +51 -0
- package/dist/lib/migrations/runner.d.ts +20 -0
- package/dist/lib/migrations/runner.d.ts.map +1 -0
- package/dist/lib/migrations/runner.js +273 -0
- package/dist/lib/migrations/schema-api.d.ts +7 -0
- package/dist/lib/migrations/schema-api.d.ts.map +1 -0
- package/dist/lib/migrations/schema-api.js +326 -0
- package/dist/lib/migrations-node.d.ts +17 -0
- package/dist/lib/migrations-node.d.ts.map +1 -0
- package/dist/lib/migrations-node.js +65 -0
- package/dist/lib/migrations.d.ts +292 -0
- package/dist/lib/migrations.d.ts.map +1 -0
- package/dist/lib/migrations.js +38 -0
- package/dist/lib/operators.d.ts +3 -0
- package/dist/lib/operators.d.ts.map +1 -1
- package/dist/lib/query.d.ts +159 -0
- package/dist/lib/query.d.ts.map +1 -0
- package/dist/lib/query.js +401 -0
- package/dist/lib/references.d.ts +0 -1
- package/dist/lib/references.d.ts.map +1 -1
- package/dist/lib/sql-helpers.d.ts +50 -0
- package/dist/lib/sql-helpers.d.ts.map +1 -0
- package/dist/lib/sql-helpers.js +111 -0
- package/dist/lib/sql.d.ts +23 -6
- package/dist/lib/sql.d.ts.map +1 -1
- package/dist/lib/sql.js +19 -5
- package/dist/lib/table.d.ts +355 -40
- package/dist/lib/table.d.ts.map +1 -1
- package/dist/lib/table.js +113 -90
- package/dist/migrations/node.d.ts +2 -0
- package/dist/migrations/node.d.ts.map +1 -0
- package/dist/migrations/node.js +1 -0
- package/dist/migrations.d.ts +8 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +5 -0
- package/dist/operators.d.ts +3 -0
- package/dist/operators.d.ts.map +1 -0
- package/dist/operators.js +1 -0
- package/dist/sql-helpers.d.ts +3 -0
- package/dist/sql-helpers.d.ts.map +1 -0
- package/dist/sql-helpers.js +1 -0
- package/package.json +23 -8
- package/src/index.ts +93 -10
- package/src/lib/adapter.ts +469 -25
- package/src/lib/column.ts +384 -0
- package/src/lib/database/execution-context.ts +15 -0
- package/src/lib/database/helpers.ts +216 -0
- package/src/lib/database/query-execution.ts +638 -0
- package/src/lib/database/relations.ts +332 -0
- package/src/lib/database/write-lifecycle.ts +487 -0
- package/src/lib/database.ts +246 -1848
- package/src/lib/errors.ts +10 -0
- package/src/lib/migrations/filename.ts +25 -0
- package/src/lib/migrations/helpers.ts +108 -0
- package/src/lib/migrations/journal-store.ts +122 -0
- package/src/lib/migrations/registry.ts +62 -0
- package/src/lib/migrations/runner.ts +374 -0
- package/src/lib/migrations/schema-api.ts +417 -0
- package/src/lib/migrations-node.ts +71 -0
- package/src/lib/migrations.ts +328 -0
- package/src/lib/operators.ts +3 -0
- package/src/lib/query.ts +958 -0
- package/src/lib/references.ts +0 -1
- package/src/lib/sql-helpers.ts +146 -0
- package/src/lib/sql.ts +23 -6
- package/src/lib/table.ts +484 -156
- package/src/migrations/node.ts +1 -0
- package/src/migrations.ts +26 -0
- package/src/operators.ts +18 -0
- package/src/sql-helpers.ts +9 -0
package/src/lib/table.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import type { ColumnDefinition } from './adapter.ts'
|
|
2
|
+
import { ColumnBuilder } from './column.ts'
|
|
3
|
+
import type { ColumnInput as ColumnBuilderInput, ColumnOutput } from './column.ts'
|
|
3
4
|
import type { Predicate, WhereInput } from './operators.ts'
|
|
4
5
|
import { inferForeignKey } from './inflection.ts'
|
|
5
6
|
import { normalizeWhereInput } from './operators.ts'
|
|
@@ -13,19 +14,174 @@ import type { Pretty } from './types.ts'
|
|
|
13
14
|
export { columnMetadataKey, tableMetadataKey } from './references.ts'
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
|
-
*
|
|
17
|
+
* Column builder map used when declaring a table.
|
|
17
18
|
*/
|
|
18
|
-
export type
|
|
19
|
+
export type TableColumnsDefinition = Record<string, ColumnBuilder<any>>
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Validation lifecycle operations.
|
|
23
|
+
*/
|
|
24
|
+
export type TableValidationOperation = 'create' | 'update'
|
|
25
|
+
/**
|
|
26
|
+
* Write lifecycle operations.
|
|
27
|
+
*/
|
|
28
|
+
export type TableWriteOperation = TableValidationOperation
|
|
29
|
+
/**
|
|
30
|
+
* All lifecycle operations exposed by table hooks.
|
|
31
|
+
*/
|
|
32
|
+
export type TableLifecycleOperation = TableWriteOperation | 'delete' | 'read'
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Single validation issue reported by table hooks.
|
|
36
|
+
*/
|
|
37
|
+
export type ValidationIssue = {
|
|
38
|
+
message: string
|
|
39
|
+
path?: Array<string | number>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Validation failure returned from table hooks.
|
|
44
|
+
*/
|
|
45
|
+
export type ValidationFailure = {
|
|
46
|
+
issues: ReadonlyArray<ValidationIssue>
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Context passed to the `validate` hook.
|
|
51
|
+
*/
|
|
52
|
+
export type TableValidationContext<row extends Record<string, unknown>> = {
|
|
53
|
+
operation: TableValidationOperation
|
|
54
|
+
tableName: string
|
|
55
|
+
value: Partial<row>
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Result returned from the `validate` hook.
|
|
60
|
+
*/
|
|
61
|
+
export type TableValidationResult<row extends Record<string, unknown>> =
|
|
62
|
+
| { value: Partial<row> }
|
|
63
|
+
| ValidationFailure
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Validation hook that runs before writes.
|
|
67
|
+
*/
|
|
68
|
+
export type TableValidate<row extends Record<string, unknown>> = (
|
|
69
|
+
context: TableValidationContext<row>,
|
|
70
|
+
) => TableValidationResult<row>
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Context passed to the `beforeWrite` hook.
|
|
74
|
+
*/
|
|
75
|
+
export type TableBeforeWriteContext<row extends Record<string, unknown>> = {
|
|
76
|
+
operation: TableWriteOperation
|
|
77
|
+
tableName: string
|
|
78
|
+
value: Partial<row>
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Result returned from the `beforeWrite` hook.
|
|
83
|
+
*/
|
|
84
|
+
export type TableBeforeWriteResult<row extends Record<string, unknown>> =
|
|
85
|
+
| { value: Partial<row> }
|
|
86
|
+
| ValidationFailure
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Hook invoked before a row write executes.
|
|
90
|
+
*/
|
|
91
|
+
export type TableBeforeWrite<row extends Record<string, unknown>> = (
|
|
92
|
+
context: TableBeforeWriteContext<row>,
|
|
93
|
+
) => TableBeforeWriteResult<row>
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Context passed to the `afterWrite` hook.
|
|
97
|
+
*/
|
|
98
|
+
export type TableAfterWriteContext<row extends Record<string, unknown>> = {
|
|
99
|
+
operation: TableWriteOperation
|
|
100
|
+
tableName: string
|
|
101
|
+
values: ReadonlyArray<Partial<row>>
|
|
102
|
+
affectedRows: number
|
|
103
|
+
insertId?: unknown
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Hook invoked after a row write completes.
|
|
108
|
+
*/
|
|
109
|
+
export type TableAfterWrite<row extends Record<string, unknown>> = (
|
|
110
|
+
context: TableAfterWriteContext<row>,
|
|
111
|
+
) => void
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Context passed to the `beforeDelete` hook.
|
|
115
|
+
*/
|
|
116
|
+
export type TableBeforeDeleteContext = {
|
|
117
|
+
tableName: string
|
|
118
|
+
where: ReadonlyArray<Predicate<string>>
|
|
119
|
+
orderBy: ReadonlyArray<OrderByClause>
|
|
120
|
+
limit?: number
|
|
121
|
+
offset?: number
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Result returned from the `beforeDelete` hook.
|
|
126
|
+
*/
|
|
127
|
+
export type TableBeforeDeleteResult = void | ValidationFailure
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Hook invoked before a delete operation executes.
|
|
131
|
+
*/
|
|
132
|
+
export type TableBeforeDelete = (context: TableBeforeDeleteContext) => TableBeforeDeleteResult
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Context passed to the `afterDelete` hook.
|
|
136
|
+
*/
|
|
137
|
+
export type TableAfterDeleteContext = {
|
|
138
|
+
tableName: string
|
|
139
|
+
where: ReadonlyArray<Predicate<string>>
|
|
140
|
+
orderBy: ReadonlyArray<OrderByClause>
|
|
141
|
+
limit?: number
|
|
142
|
+
offset?: number
|
|
143
|
+
affectedRows: number
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Hook invoked after a delete operation completes.
|
|
148
|
+
*/
|
|
149
|
+
export type TableAfterDelete = (context: TableAfterDeleteContext) => void
|
|
21
150
|
|
|
22
|
-
|
|
151
|
+
/**
|
|
152
|
+
* Context passed to the `afterRead` hook.
|
|
153
|
+
*/
|
|
154
|
+
export type TableAfterReadContext<row extends Record<string, unknown>> = {
|
|
155
|
+
tableName: string
|
|
156
|
+
/**
|
|
157
|
+
* The current row shape being returned. This may be a projection/partial row.
|
|
158
|
+
*/
|
|
159
|
+
value: Partial<row>
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Result returned from the `afterRead` hook.
|
|
164
|
+
*/
|
|
165
|
+
export type TableAfterReadResult<row extends Record<string, unknown>> =
|
|
166
|
+
| { value: Partial<row> }
|
|
167
|
+
| ValidationFailure
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Hook invoked after a row is read.
|
|
171
|
+
*/
|
|
172
|
+
export type TableAfterRead<row extends Record<string, unknown>> = (
|
|
173
|
+
context: TableAfterReadContext<row>,
|
|
174
|
+
) => TableAfterReadResult<row>
|
|
175
|
+
|
|
176
|
+
type ColumnNameFromColumns<columns extends TableColumnsDefinition> = keyof columns & string
|
|
177
|
+
|
|
178
|
+
type DefaultPrimaryKey<columns extends TableColumnsDefinition> =
|
|
23
179
|
'id' extends ColumnNameFromColumns<columns>
|
|
24
180
|
? readonly ['id']
|
|
25
181
|
: readonly ColumnNameFromColumns<columns>[]
|
|
26
182
|
|
|
27
183
|
type NormalizePrimaryKey<
|
|
28
|
-
columns extends
|
|
184
|
+
columns extends TableColumnsDefinition,
|
|
29
185
|
primaryKey extends
|
|
30
186
|
| ColumnNameFromColumns<columns>
|
|
31
187
|
| readonly ColumnNameFromColumns<columns>[]
|
|
@@ -36,8 +192,14 @@ type NormalizePrimaryKey<
|
|
|
36
192
|
? readonly [primaryKey]
|
|
37
193
|
: DefaultPrimaryKey<columns>
|
|
38
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Timestamp configuration accepted by {@link table}.
|
|
197
|
+
*/
|
|
39
198
|
export type TimestampOptions = boolean | { createdAt?: string; updatedAt?: string }
|
|
40
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Resolved timestamp column names for a table.
|
|
202
|
+
*/
|
|
41
203
|
export type TimestampConfig = {
|
|
42
204
|
createdAt: string
|
|
43
205
|
updatedAt: string
|
|
@@ -45,94 +207,143 @@ export type TimestampConfig = {
|
|
|
45
207
|
|
|
46
208
|
type TableMetadata<
|
|
47
209
|
name extends string,
|
|
48
|
-
columns extends
|
|
210
|
+
columns extends TableColumnsDefinition,
|
|
49
211
|
primaryKey extends readonly ColumnNameFromColumns<columns>[],
|
|
50
212
|
> = {
|
|
51
213
|
name: name
|
|
52
214
|
columns: columns
|
|
53
215
|
primaryKey: primaryKey
|
|
54
216
|
timestamps: TimestampConfig | null
|
|
217
|
+
columnDefinitions: {
|
|
218
|
+
[column in keyof columns & string]: ColumnDefinition
|
|
219
|
+
}
|
|
220
|
+
beforeWrite?: TableBeforeWrite<TableRowFromColumns<columns>>
|
|
221
|
+
afterWrite?: TableAfterWrite<TableRowFromColumns<columns>>
|
|
222
|
+
beforeDelete?: TableBeforeDelete
|
|
223
|
+
afterDelete?: TableAfterDelete
|
|
224
|
+
afterRead?: TableAfterRead<TableRowFromColumns<columns>>
|
|
225
|
+
validate?: TableValidate<TableRowFromColumns<columns>>
|
|
55
226
|
}
|
|
56
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Typed reference to a table column.
|
|
230
|
+
*/
|
|
57
231
|
export type ColumnReference<
|
|
58
232
|
tableName extends string,
|
|
59
233
|
columnName extends string,
|
|
60
|
-
schema extends Schema<any, any>,
|
|
61
234
|
> = ColumnReferenceLike<`${tableName}.${columnName}`> & {
|
|
62
235
|
[columnMetadataKey]: {
|
|
63
236
|
tableName: tableName
|
|
64
237
|
columnName: columnName
|
|
65
238
|
qualifiedName: `${tableName}.${columnName}`
|
|
66
|
-
schema: schema
|
|
67
239
|
}
|
|
68
240
|
}
|
|
69
241
|
|
|
70
|
-
|
|
242
|
+
/**
|
|
243
|
+
* Any column reference.
|
|
244
|
+
*/
|
|
245
|
+
export type AnyColumn = ColumnReference<string, string>
|
|
71
246
|
|
|
247
|
+
/**
|
|
248
|
+
* Column reference narrowed by a qualified column name string.
|
|
249
|
+
*/
|
|
72
250
|
export type ColumnReferenceForQualifiedName<qualifiedName extends string> = AnyColumn & {
|
|
73
251
|
[columnMetadataKey]: {
|
|
74
252
|
qualifiedName: qualifiedName
|
|
75
253
|
}
|
|
76
254
|
}
|
|
77
255
|
|
|
78
|
-
type TableColumnReferences<name extends string, columns extends
|
|
79
|
-
[column in keyof columns & string]: ColumnReference<name, column
|
|
256
|
+
type TableColumnReferences<name extends string, columns extends TableColumnsDefinition> = {
|
|
257
|
+
[column in keyof columns & string]: ColumnReference<name, column>
|
|
80
258
|
}
|
|
81
259
|
|
|
82
|
-
type
|
|
83
|
-
[column in keyof columns & string]:
|
|
260
|
+
type TableRowFromColumns<columns extends TableColumnsDefinition> = Pretty<{
|
|
261
|
+
[column in keyof columns & string]: ColumnOutput<columns[column]>
|
|
84
262
|
}>
|
|
85
263
|
|
|
264
|
+
/**
|
|
265
|
+
* Fully-typed table object returned by {@link table}.
|
|
266
|
+
*/
|
|
86
267
|
export type Table<
|
|
87
268
|
name extends string,
|
|
88
|
-
columns extends
|
|
269
|
+
columns extends TableColumnsDefinition,
|
|
89
270
|
primaryKey extends readonly ColumnNameFromColumns<columns>[],
|
|
90
271
|
> = TableMetadataLike<name, columns, primaryKey, TimestampConfig | null> & {
|
|
91
272
|
[tableMetadataKey]: TableMetadata<name, columns, primaryKey>
|
|
92
|
-
'~standard': Schema<unknown, TableParseOutput<columns>>['~standard']
|
|
93
273
|
} & TableColumnReferences<name, columns>
|
|
94
274
|
|
|
275
|
+
/**
|
|
276
|
+
* Table-like object with erased concrete column types.
|
|
277
|
+
*/
|
|
95
278
|
export type AnyTable = TableMetadataLike<
|
|
96
279
|
string,
|
|
97
|
-
|
|
280
|
+
TableColumnsDefinition,
|
|
98
281
|
readonly string[],
|
|
99
282
|
TimestampConfig | null
|
|
100
283
|
> & {
|
|
101
284
|
[tableMetadataKey]: {
|
|
102
285
|
name: string
|
|
103
|
-
columns:
|
|
286
|
+
columns: TableColumnsDefinition
|
|
104
287
|
primaryKey: readonly string[]
|
|
105
288
|
timestamps: TimestampConfig | null
|
|
289
|
+
columnDefinitions: Record<string, ColumnDefinition>
|
|
290
|
+
beforeWrite?: unknown
|
|
291
|
+
afterWrite?: unknown
|
|
292
|
+
beforeDelete?: unknown
|
|
293
|
+
afterDelete?: unknown
|
|
294
|
+
afterRead?: unknown
|
|
295
|
+
validate?: TableValidate<Record<string, unknown>>
|
|
106
296
|
}
|
|
107
|
-
'~standard': Schema<unknown, Partial<Record<string, unknown>>>['~standard']
|
|
108
297
|
} & Record<string, unknown>
|
|
109
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Name of a concrete table.
|
|
301
|
+
*/
|
|
110
302
|
export type TableName<table extends AnyTable> = table[typeof tableMetadataKey]['name']
|
|
111
303
|
|
|
304
|
+
/**
|
|
305
|
+
* Column builder map for a concrete table.
|
|
306
|
+
*/
|
|
112
307
|
export type TableColumns<table extends AnyTable> = table[typeof tableMetadataKey]['columns']
|
|
113
308
|
|
|
309
|
+
/**
|
|
310
|
+
* Primary-key column list for a concrete table.
|
|
311
|
+
*/
|
|
114
312
|
export type TablePrimaryKey<table extends AnyTable> = table[typeof tableMetadataKey]['primaryKey']
|
|
115
313
|
|
|
116
314
|
export type TableTimestamps<table extends AnyTable> = table[typeof tableMetadataKey]['timestamps']
|
|
117
315
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
316
|
+
/**
|
|
317
|
+
* Row shape produced by a concrete table.
|
|
318
|
+
*/
|
|
319
|
+
export type TableRow<table extends AnyTable> = TableRowFromColumns<TableColumns<table>>
|
|
121
320
|
|
|
321
|
+
/**
|
|
322
|
+
* Row shape with loaded relations merged in.
|
|
323
|
+
*/
|
|
122
324
|
export type TableRowWith<
|
|
123
325
|
table extends AnyTable,
|
|
124
326
|
loaded extends Record<string, unknown> = {},
|
|
125
327
|
> = Pretty<TableRow<table> & loaded>
|
|
126
328
|
|
|
329
|
+
/**
|
|
330
|
+
* Unqualified column names for a concrete table.
|
|
331
|
+
*/
|
|
127
332
|
export type TableColumnName<table extends AnyTable> = keyof TableColumns<table> & string
|
|
128
333
|
|
|
129
334
|
export type QualifiedTableColumnName<table extends AnyTable> =
|
|
130
335
|
`${TableName<table>}.${TableColumnName<table>}`
|
|
131
336
|
|
|
337
|
+
/**
|
|
338
|
+
* Column input accepted for a concrete table.
|
|
339
|
+
*/
|
|
132
340
|
export type TableColumnInput<table extends AnyTable> = ColumnInput<
|
|
133
341
|
TableColumnName<table> | QualifiedTableColumnName<table>
|
|
134
342
|
>
|
|
135
343
|
|
|
344
|
+
/**
|
|
345
|
+
* Plain metadata snapshot of a table.
|
|
346
|
+
*/
|
|
136
347
|
export type TableReference<table extends AnyTable = AnyTable> = {
|
|
137
348
|
kind: 'table'
|
|
138
349
|
name: TableName<table>
|
|
@@ -168,14 +379,96 @@ export function getTableName<table extends AnyTable>(table: table): TableName<ta
|
|
|
168
379
|
}
|
|
169
380
|
|
|
170
381
|
/**
|
|
171
|
-
* Returns a table's
|
|
382
|
+
* Returns a table's column builder map.
|
|
172
383
|
* @param table Source table instance.
|
|
173
|
-
* @returns Table
|
|
384
|
+
* @returns Table column builder map.
|
|
174
385
|
*/
|
|
175
386
|
export function getTableColumns<table extends AnyTable>(table: table): TableColumns<table> {
|
|
176
387
|
return table[tableMetadataKey].columns as TableColumns<table>
|
|
177
388
|
}
|
|
178
389
|
|
|
390
|
+
/**
|
|
391
|
+
* Returns a table's resolved physical column definitions.
|
|
392
|
+
* @param table Source table instance.
|
|
393
|
+
* @returns Column definition map.
|
|
394
|
+
*/
|
|
395
|
+
export function getTableColumnDefinitions<table extends AnyTable>(
|
|
396
|
+
table: table,
|
|
397
|
+
): {
|
|
398
|
+
[column in keyof TableColumns<table> & string]: ColumnDefinition
|
|
399
|
+
} {
|
|
400
|
+
return table[tableMetadataKey].columnDefinitions as {
|
|
401
|
+
[column in keyof TableColumns<table> & string]: ColumnDefinition
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Returns a table's optional write validator.
|
|
407
|
+
* @param table Source table instance.
|
|
408
|
+
* @returns Validation function or `undefined`.
|
|
409
|
+
*/
|
|
410
|
+
export function getTableValidator<table extends AnyTable>(
|
|
411
|
+
table: table,
|
|
412
|
+
): TableValidate<TableRow<table>> | undefined {
|
|
413
|
+
return table[tableMetadataKey].validate as TableValidate<TableRow<table>> | undefined
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Returns a table's optional before-write lifecycle callback.
|
|
418
|
+
* @param table Source table instance.
|
|
419
|
+
* @returns Before-write callback or `undefined`.
|
|
420
|
+
*/
|
|
421
|
+
export function getTableBeforeWrite<table extends AnyTable>(
|
|
422
|
+
table: table,
|
|
423
|
+
): TableBeforeWrite<TableRow<table>> | undefined {
|
|
424
|
+
return table[tableMetadataKey].beforeWrite as TableBeforeWrite<TableRow<table>> | undefined
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Returns a table's optional after-write lifecycle callback.
|
|
429
|
+
* @param table Source table instance.
|
|
430
|
+
* @returns After-write callback or `undefined`.
|
|
431
|
+
*/
|
|
432
|
+
export function getTableAfterWrite<table extends AnyTable>(
|
|
433
|
+
table: table,
|
|
434
|
+
): TableAfterWrite<TableRow<table>> | undefined {
|
|
435
|
+
return table[tableMetadataKey].afterWrite as TableAfterWrite<TableRow<table>> | undefined
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Returns a table's optional before-delete lifecycle callback.
|
|
440
|
+
* @param table Source table instance.
|
|
441
|
+
* @returns Before-delete callback or `undefined`.
|
|
442
|
+
*/
|
|
443
|
+
export function getTableBeforeDelete<table extends AnyTable>(
|
|
444
|
+
table: table,
|
|
445
|
+
): TableBeforeDelete | undefined {
|
|
446
|
+
return table[tableMetadataKey].beforeDelete as TableBeforeDelete | undefined
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Returns a table's optional after-delete lifecycle callback.
|
|
451
|
+
* @param table Source table instance.
|
|
452
|
+
* @returns After-delete callback or `undefined`.
|
|
453
|
+
*/
|
|
454
|
+
export function getTableAfterDelete<table extends AnyTable>(
|
|
455
|
+
table: table,
|
|
456
|
+
): TableAfterDelete | undefined {
|
|
457
|
+
return table[tableMetadataKey].afterDelete as TableAfterDelete | undefined
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Returns a table's optional after-read lifecycle callback.
|
|
462
|
+
* The callback receives the current read shape, which may be a projected partial row.
|
|
463
|
+
* @param table Source table instance.
|
|
464
|
+
* @returns After-read callback or `undefined`.
|
|
465
|
+
*/
|
|
466
|
+
export function getTableAfterRead<table extends AnyTable>(
|
|
467
|
+
table: table,
|
|
468
|
+
): TableAfterRead<TableRow<table>> | undefined {
|
|
469
|
+
return table[tableMetadataKey].afterRead as TableAfterRead<TableRow<table>> | undefined
|
|
470
|
+
}
|
|
471
|
+
|
|
179
472
|
/**
|
|
180
473
|
* Returns a table's primary key columns.
|
|
181
474
|
* @param table Source table instance.
|
|
@@ -194,15 +487,27 @@ export function getTableTimestamps<table extends AnyTable>(table: table): TableT
|
|
|
194
487
|
return table[tableMetadataKey].timestamps as TableTimestamps<table>
|
|
195
488
|
}
|
|
196
489
|
|
|
490
|
+
/**
|
|
491
|
+
* Sort direction accepted by `orderBy`.
|
|
492
|
+
*/
|
|
197
493
|
export type OrderDirection = 'asc' | 'desc'
|
|
198
494
|
|
|
495
|
+
/**
|
|
496
|
+
* Normalized `orderBy` clause.
|
|
497
|
+
*/
|
|
199
498
|
export type OrderByClause = {
|
|
200
499
|
column: string
|
|
201
500
|
direction: OrderDirection
|
|
202
501
|
}
|
|
203
502
|
|
|
503
|
+
/**
|
|
504
|
+
* Cardinality of a relation.
|
|
505
|
+
*/
|
|
204
506
|
export type RelationCardinality = 'one' | 'many'
|
|
205
507
|
|
|
508
|
+
/**
|
|
509
|
+
* Supported relation kinds.
|
|
510
|
+
*/
|
|
206
511
|
export type RelationKind = 'hasMany' | 'hasOne' | 'belongsTo' | 'hasManyThrough'
|
|
207
512
|
|
|
208
513
|
export type RelationResult<relation extends AnyRelation> =
|
|
@@ -212,6 +517,9 @@ export type RelationResult<relation extends AnyRelation> =
|
|
|
212
517
|
: TableRowWith<target, loaded> | null
|
|
213
518
|
: never
|
|
214
519
|
|
|
520
|
+
/**
|
|
521
|
+
* Named relation map for a source table.
|
|
522
|
+
*/
|
|
215
523
|
export type RelationMapForTable<table extends AnyTable> = Record<
|
|
216
524
|
string,
|
|
217
525
|
Relation<table, AnyTable, RelationCardinality, any>
|
|
@@ -221,25 +529,40 @@ export type LoadedRelationMap<relations extends RelationMapForTable<any>> = Pret
|
|
|
221
529
|
[name in keyof relations]: RelationResult<relations[name]>
|
|
222
530
|
}>
|
|
223
531
|
|
|
532
|
+
/**
|
|
533
|
+
* Column or column list used to join relations.
|
|
534
|
+
*/
|
|
224
535
|
export type KeySelector<table extends AnyTable> =
|
|
225
536
|
| (keyof TableRow<table> & string)
|
|
226
537
|
| readonly (keyof TableRow<table> & string)[]
|
|
227
538
|
|
|
539
|
+
/**
|
|
540
|
+
* Options for defining a {@link hasMany} relation.
|
|
541
|
+
*/
|
|
228
542
|
export type HasManyOptions<source extends AnyTable, target extends AnyTable> = {
|
|
229
543
|
foreignKey?: KeySelector<target>
|
|
230
544
|
targetKey?: KeySelector<source>
|
|
231
545
|
}
|
|
232
546
|
|
|
547
|
+
/**
|
|
548
|
+
* Options for defining a {@link hasOne} relation.
|
|
549
|
+
*/
|
|
233
550
|
export type HasOneOptions<source extends AnyTable, target extends AnyTable> = {
|
|
234
551
|
foreignKey?: KeySelector<target>
|
|
235
552
|
targetKey?: KeySelector<source>
|
|
236
553
|
}
|
|
237
554
|
|
|
555
|
+
/**
|
|
556
|
+
* Options for defining a {@link belongsTo} relation.
|
|
557
|
+
*/
|
|
238
558
|
export type BelongsToOptions<source extends AnyTable, target extends AnyTable> = {
|
|
239
559
|
foreignKey?: KeySelector<source>
|
|
240
560
|
targetKey?: KeySelector<target>
|
|
241
561
|
}
|
|
242
562
|
|
|
563
|
+
/**
|
|
564
|
+
* Options for defining a {@link hasManyThrough} relation.
|
|
565
|
+
*/
|
|
243
566
|
export type HasManyThroughOptions<source extends AnyTable, target extends AnyTable> = {
|
|
244
567
|
through: Relation<source, AnyTable, RelationCardinality, any>
|
|
245
568
|
throughForeignKey?: KeySelector<target>
|
|
@@ -260,6 +583,9 @@ export type ThroughRelationMetadata = {
|
|
|
260
583
|
throughTargetKey: string[]
|
|
261
584
|
}
|
|
262
585
|
|
|
586
|
+
/**
|
|
587
|
+
* Relation descriptor used by query loading.
|
|
588
|
+
*/
|
|
263
589
|
export type Relation<
|
|
264
590
|
source extends AnyTable,
|
|
265
591
|
target extends AnyTable,
|
|
@@ -289,11 +615,14 @@ export type Relation<
|
|
|
289
615
|
): Relation<source, target, cardinality, loaded & LoadedRelationMap<relations>>
|
|
290
616
|
}
|
|
291
617
|
|
|
618
|
+
/**
|
|
619
|
+
* Relation descriptor with erased table types.
|
|
620
|
+
*/
|
|
292
621
|
export type AnyRelation = Relation<AnyTable, AnyTable, RelationCardinality, any>
|
|
293
622
|
|
|
294
623
|
export type CreateTableOptions<
|
|
295
624
|
name extends string,
|
|
296
|
-
columns extends
|
|
625
|
+
columns extends TableColumnsDefinition,
|
|
297
626
|
primaryKey extends
|
|
298
627
|
| ColumnNameFromColumns<columns>
|
|
299
628
|
| readonly ColumnNameFromColumns<columns>[]
|
|
@@ -303,80 +632,68 @@ export type CreateTableOptions<
|
|
|
303
632
|
columns: columns
|
|
304
633
|
primaryKey?: primaryKey
|
|
305
634
|
timestamps?: TimestampOptions
|
|
635
|
+
beforeWrite?: TableBeforeWrite<TableRowFromColumns<columns>>
|
|
636
|
+
afterWrite?: TableAfterWrite<TableRowFromColumns<columns>>
|
|
637
|
+
beforeDelete?: TableBeforeDelete
|
|
638
|
+
afterDelete?: TableAfterDelete
|
|
639
|
+
afterRead?: TableAfterRead<TableRowFromColumns<columns>>
|
|
640
|
+
validate?: TableValidate<TableRowFromColumns<columns>>
|
|
306
641
|
}
|
|
307
642
|
|
|
308
|
-
|
|
643
|
+
const defaultTimestampConfig: TimestampConfig = {
|
|
309
644
|
createdAt: 'created_at',
|
|
310
645
|
updatedAt: 'updated_at',
|
|
311
646
|
}
|
|
312
647
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
648
|
+
/**
|
|
649
|
+
* Creates a lifecycle/validation failure result with one or more issues.
|
|
650
|
+
* @param message A single issue message.
|
|
651
|
+
* @param path Optional issue path.
|
|
652
|
+
* @returns A {@link ValidationFailure} result object for `validate` and lifecycle callbacks.
|
|
653
|
+
* @example
|
|
654
|
+
* ```ts
|
|
655
|
+
* import { column as c, fail, table } from 'remix/data-table'
|
|
656
|
+
*
|
|
657
|
+
* let users = table({
|
|
658
|
+
* name: 'users',
|
|
659
|
+
* columns: {
|
|
660
|
+
* id: c.integer(),
|
|
661
|
+
* email: c.varchar(255),
|
|
662
|
+
* },
|
|
663
|
+
* validate({ value }) {
|
|
664
|
+
* if (!value.email) {
|
|
665
|
+
* // Fail with a single issue message and optional path
|
|
666
|
+
* return fail('Email is required', ['email'])
|
|
667
|
+
*
|
|
668
|
+
* // Or fail with multiple issues at once
|
|
669
|
+
* return fail([
|
|
670
|
+
* { message: 'Id is required', path: ['id'] },
|
|
671
|
+
* { message: 'Email is required', path: ['email'] },
|
|
672
|
+
* ])
|
|
673
|
+
* }
|
|
674
|
+
*
|
|
675
|
+
* return { value }
|
|
676
|
+
* },
|
|
677
|
+
* })
|
|
678
|
+
* ```
|
|
679
|
+
*/
|
|
680
|
+
export function fail(message: string, path?: Array<string | number>): ValidationFailure
|
|
681
|
+
/**
|
|
682
|
+
* @param issues An array of issues.
|
|
683
|
+
*/
|
|
684
|
+
export function fail(issues: ReadonlyArray<ValidationIssue>): ValidationFailure
|
|
685
|
+
export function fail(
|
|
686
|
+
messageOrIssues: string | ReadonlyArray<ValidationIssue>,
|
|
687
|
+
path?: Array<string | number>,
|
|
688
|
+
): ValidationFailure {
|
|
689
|
+
if (typeof messageOrIssues === 'string') {
|
|
328
690
|
return {
|
|
329
|
-
issues: [{ message:
|
|
691
|
+
issues: [{ message: messageOrIssues, path }],
|
|
330
692
|
}
|
|
331
693
|
}
|
|
332
694
|
|
|
333
|
-
let input = value as Record<string, unknown>
|
|
334
|
-
let output: Record<string, unknown> = {}
|
|
335
|
-
let issues: Issue[] = []
|
|
336
|
-
|
|
337
|
-
for (let key in input) {
|
|
338
|
-
if (!Object.prototype.hasOwnProperty.call(input, key)) {
|
|
339
|
-
continue
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
if (!Object.prototype.hasOwnProperty.call(columns, key)) {
|
|
343
|
-
issues.push({
|
|
344
|
-
message: 'Unknown column "' + key + '" for table "' + tableName + '"',
|
|
345
|
-
path: [key],
|
|
346
|
-
})
|
|
347
|
-
continue
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
let result = parseSafe(columns[key], input[key], options)
|
|
351
|
-
|
|
352
|
-
if (!result.success) {
|
|
353
|
-
issues.push(...result.issues.map((issue) => prefixIssuePath(issue, key)))
|
|
354
|
-
continue
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
output[key] = result.value
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
if (issues.length > 0) {
|
|
361
|
-
return { issues }
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
return { value: output as TableParseOutput<columns> }
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
export function validatePartialRow<table extends AnyTable>(
|
|
368
|
-
table: table,
|
|
369
|
-
value: unknown,
|
|
370
|
-
options?: ParseOptions,
|
|
371
|
-
): { value: Partial<TableRow<table>> } | { issues: ReadonlyArray<Issue> } {
|
|
372
|
-
let result = validatePartialRowInput(getTableName(table), getTableColumns(table), value, options)
|
|
373
|
-
|
|
374
|
-
if ('issues' in result) {
|
|
375
|
-
return result
|
|
376
|
-
}
|
|
377
|
-
|
|
378
695
|
return {
|
|
379
|
-
|
|
696
|
+
issues: [...messageOrIssues],
|
|
380
697
|
}
|
|
381
698
|
}
|
|
382
699
|
|
|
@@ -384,10 +701,23 @@ export function validatePartialRow<table extends AnyTable>(
|
|
|
384
701
|
* Creates a table object with symbol-backed metadata and direct column references.
|
|
385
702
|
* @param options Table declaration options.
|
|
386
703
|
* @returns A frozen table object.
|
|
704
|
+
* @example
|
|
705
|
+
* ```ts
|
|
706
|
+
* import { column as c, table } from 'remix/data-table'
|
|
707
|
+
*
|
|
708
|
+
* let users = table({
|
|
709
|
+
* name: 'users',
|
|
710
|
+
* columns: {
|
|
711
|
+
* id: c.integer(),
|
|
712
|
+
* email: c.varchar(255),
|
|
713
|
+
* },
|
|
714
|
+
* primaryKey: 'id',
|
|
715
|
+
* })
|
|
716
|
+
* ```
|
|
387
717
|
*/
|
|
388
|
-
export function
|
|
718
|
+
export function table<
|
|
389
719
|
name extends string,
|
|
390
|
-
columns extends
|
|
720
|
+
columns extends TableColumnsDefinition,
|
|
391
721
|
primaryKey extends
|
|
392
722
|
| ColumnNameFromColumns<columns>
|
|
393
723
|
| readonly ColumnNameFromColumns<columns>[]
|
|
@@ -398,14 +728,9 @@ export function createTable<
|
|
|
398
728
|
let tableName = options.name
|
|
399
729
|
let columns = options.columns
|
|
400
730
|
|
|
401
|
-
if (Object.prototype.hasOwnProperty.call(columns, '~standard')) {
|
|
402
|
-
throw new Error(
|
|
403
|
-
'Column name "~standard" is reserved for table validation on "' + tableName + '"',
|
|
404
|
-
)
|
|
405
|
-
}
|
|
406
|
-
|
|
407
731
|
let resolvedPrimaryKey = normalizePrimaryKey(tableName, columns, options.primaryKey)
|
|
408
732
|
let timestampConfig = normalizeTimestampConfig(options.timestamps)
|
|
733
|
+
let columnDefinitions = resolveTableColumns(tableName, columns)
|
|
409
734
|
let table = Object.create(null) as Table<name, columns, NormalizePrimaryKey<columns, primaryKey>>
|
|
410
735
|
|
|
411
736
|
Object.defineProperty(table, tableMetadataKey, {
|
|
@@ -414,19 +739,15 @@ export function createTable<
|
|
|
414
739
|
columns,
|
|
415
740
|
primaryKey: resolvedPrimaryKey,
|
|
416
741
|
timestamps: timestampConfig,
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
vendor: 'data-table',
|
|
427
|
-
validate(value: unknown, parseOptions?: ParseOptions) {
|
|
428
|
-
return validatePartialRowInput(tableName, columns, value, parseOptions)
|
|
429
|
-
},
|
|
742
|
+
columnDefinitions,
|
|
743
|
+
beforeWrite: options.beforeWrite as
|
|
744
|
+
| TableBeforeWrite<TableRowFromColumns<columns>>
|
|
745
|
+
| undefined,
|
|
746
|
+
afterWrite: options.afterWrite as TableAfterWrite<TableRowFromColumns<columns>> | undefined,
|
|
747
|
+
beforeDelete: options.beforeDelete as TableBeforeDelete | undefined,
|
|
748
|
+
afterDelete: options.afterDelete as TableAfterDelete | undefined,
|
|
749
|
+
afterRead: options.afterRead as TableAfterRead<TableRowFromColumns<columns>> | undefined,
|
|
750
|
+
validate: options.validate as TableValidate<TableRowFromColumns<columns>> | undefined,
|
|
430
751
|
}),
|
|
431
752
|
enumerable: false,
|
|
432
753
|
writable: false,
|
|
@@ -438,8 +759,7 @@ export function createTable<
|
|
|
438
759
|
continue
|
|
439
760
|
}
|
|
440
761
|
|
|
441
|
-
let
|
|
442
|
-
let column = createColumnReference(tableName, columnName, schema)
|
|
762
|
+
let column = createColumnReference(tableName, columnName)
|
|
443
763
|
|
|
444
764
|
Object.defineProperty(table, columnName, {
|
|
445
765
|
value: column,
|
|
@@ -452,24 +772,49 @@ export function createTable<
|
|
|
452
772
|
return Object.freeze(table) as Table<name, columns, NormalizePrimaryKey<columns, primaryKey>>
|
|
453
773
|
}
|
|
454
774
|
|
|
455
|
-
function createColumnReference<
|
|
456
|
-
tableName extends string,
|
|
457
|
-
columnName extends string,
|
|
458
|
-
schema extends Schema<any, any>,
|
|
459
|
-
>(
|
|
775
|
+
function createColumnReference<tableName extends string, columnName extends string>(
|
|
460
776
|
tableName: tableName,
|
|
461
777
|
columnName: columnName,
|
|
462
|
-
|
|
463
|
-
): ColumnReference<tableName, columnName, schema> {
|
|
778
|
+
): ColumnReference<tableName, columnName> {
|
|
464
779
|
return Object.freeze({
|
|
465
780
|
kind: 'column',
|
|
466
781
|
[columnMetadataKey]: Object.freeze({
|
|
467
782
|
tableName,
|
|
468
783
|
columnName,
|
|
469
784
|
qualifiedName: tableName + '.' + columnName,
|
|
470
|
-
schema,
|
|
471
785
|
}),
|
|
472
|
-
}) as ColumnReference<tableName, columnName
|
|
786
|
+
}) as ColumnReference<tableName, columnName>
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
function resolveTableColumns<columns extends TableColumnsDefinition>(
|
|
790
|
+
tableName: string,
|
|
791
|
+
columns: columns,
|
|
792
|
+
): { [column in keyof columns & string]: ColumnDefinition } {
|
|
793
|
+
let columnDefinitions: Record<string, ColumnDefinition> = {}
|
|
794
|
+
|
|
795
|
+
for (let columnName in columns) {
|
|
796
|
+
if (!Object.prototype.hasOwnProperty.call(columns, columnName)) {
|
|
797
|
+
continue
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
let column = columns[columnName]
|
|
801
|
+
|
|
802
|
+
if (!(column instanceof ColumnBuilder)) {
|
|
803
|
+
throw new Error(
|
|
804
|
+
'Invalid column "' +
|
|
805
|
+
columnName +
|
|
806
|
+
'" for table "' +
|
|
807
|
+
tableName +
|
|
808
|
+
'". Expected a column(...) builder',
|
|
809
|
+
)
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
columnDefinitions[columnName] = column.build()
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
return Object.freeze(columnDefinitions) as {
|
|
816
|
+
[column in keyof columns & string]: ColumnDefinition
|
|
817
|
+
}
|
|
473
818
|
}
|
|
474
819
|
|
|
475
820
|
/**
|
|
@@ -630,51 +975,34 @@ export function hasManyThrough<source extends AnyTable, target extends AnyTable>
|
|
|
630
975
|
})
|
|
631
976
|
}
|
|
632
977
|
|
|
633
|
-
/**
|
|
634
|
-
* Creates a schema that accepts `Date`, string, and numeric timestamp inputs.
|
|
635
|
-
* @returns Timestamp schema for generated timestamp helpers.
|
|
636
|
-
*/
|
|
637
|
-
export function timestampSchema(): Schema<unknown, Date | string | number> {
|
|
638
|
-
return createSchema<unknown, Date | string | number>((value) => {
|
|
639
|
-
if (value instanceof Date) {
|
|
640
|
-
return { value }
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
if (typeof value === 'string' || typeof value === 'number') {
|
|
644
|
-
return { value }
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
return {
|
|
648
|
-
issues: [{ message: 'Expected Date, string, or number' }],
|
|
649
|
-
}
|
|
650
|
-
})
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
let defaultTimestampSchema = timestampSchema()
|
|
654
|
-
|
|
655
978
|
/**
|
|
656
979
|
* Convenience helper for standard snake_case timestamp columns.
|
|
657
|
-
* @
|
|
658
|
-
* @returns Column schema map for `created_at`/`updated_at`.
|
|
980
|
+
* @returns Column-builder map for `created_at`/`updated_at`.
|
|
659
981
|
*/
|
|
660
|
-
export function timestamps(
|
|
661
|
-
|
|
662
|
-
|
|
982
|
+
export function timestamps(): Record<
|
|
983
|
+
'created_at' | 'updated_at',
|
|
984
|
+
ColumnBuilder<Date | string | number>
|
|
985
|
+
> {
|
|
986
|
+
let timestampColumn = () => new ColumnBuilder<Date | string | number>({ type: 'timestamp' })
|
|
987
|
+
|
|
663
988
|
return {
|
|
664
|
-
created_at:
|
|
665
|
-
updated_at:
|
|
989
|
+
created_at: timestampColumn(),
|
|
990
|
+
updated_at: timestampColumn(),
|
|
666
991
|
}
|
|
667
992
|
}
|
|
668
993
|
|
|
994
|
+
/**
|
|
995
|
+
* Primary-key input accepted by `find()`, `update()`, and similar helpers.
|
|
996
|
+
*/
|
|
669
997
|
export type PrimaryKeyInput<table extends AnyTable> =
|
|
670
998
|
TablePrimaryKey<table> extends readonly [infer column extends string]
|
|
671
999
|
? column extends keyof TableColumns<table> & string
|
|
672
|
-
?
|
|
1000
|
+
? ColumnBuilderInput<TableColumns<table>[column]>
|
|
673
1001
|
: never
|
|
674
1002
|
: Pretty<{
|
|
675
|
-
[column in TablePrimaryKey<table>[number] &
|
|
676
|
-
TableColumns<table>
|
|
677
|
-
|
|
1003
|
+
[column in TablePrimaryKey<table>[number] &
|
|
1004
|
+
keyof TableColumns<table> &
|
|
1005
|
+
string]: ColumnBuilderInput<TableColumns<table>[column]>
|
|
678
1006
|
}>
|
|
679
1007
|
|
|
680
1008
|
/**
|
|
@@ -757,13 +1085,13 @@ export function stableSerialize(value: unknown): string {
|
|
|
757
1085
|
|
|
758
1086
|
function normalizePrimaryKey(
|
|
759
1087
|
tableName: string,
|
|
760
|
-
columns:
|
|
1088
|
+
columns: TableColumnsDefinition,
|
|
761
1089
|
primaryKey?: string | readonly string[],
|
|
762
1090
|
): string[] {
|
|
763
1091
|
if (primaryKey === undefined) {
|
|
764
1092
|
if (!Object.prototype.hasOwnProperty.call(columns, 'id')) {
|
|
765
1093
|
throw new Error(
|
|
766
|
-
'Table "' + tableName + '" must
|
|
1094
|
+
'Table "' + tableName + '" must include an "id" column or an explicit primaryKey',
|
|
767
1095
|
)
|
|
768
1096
|
}
|
|
769
1097
|
|