@remix-run/data-table-postgres 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 +9 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/adapter.d.ts +100 -33
- package/dist/lib/adapter.d.ts.map +1 -1
- package/dist/lib/adapter.js +553 -17
- package/dist/lib/sql-compiler.d.ts +2 -7
- package/dist/lib/sql-compiler.d.ts.map +1 -1
- package/dist/lib/sql-compiler.js +50 -80
- package/package.json +6 -7
- package/src/index.ts +1 -7
- package/src/lib/adapter.ts +675 -69
- package/src/lib/sql-compiler.ts +66 -106
package/src/lib/sql-compiler.ts
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
1
1
|
import { getTableName, getTablePrimaryKey } from '@remix-run/data-table'
|
|
2
|
-
import type {
|
|
2
|
+
import type { DataManipulationOperation, Predicate, SqlStatement } from '@remix-run/data-table'
|
|
3
|
+
import {
|
|
4
|
+
collectColumns as collectColumnsHelper,
|
|
5
|
+
normalizeJoinType as normalizeJoinTypeHelper,
|
|
6
|
+
quotePath as quotePathHelper,
|
|
7
|
+
} from '@remix-run/data-table/sql-helpers'
|
|
3
8
|
|
|
4
|
-
type JoinClause = Extract<
|
|
5
|
-
type
|
|
6
|
-
type
|
|
7
|
-
|
|
8
|
-
type CompiledSql = {
|
|
9
|
-
text: string
|
|
10
|
-
values: unknown[]
|
|
11
|
-
}
|
|
9
|
+
type JoinClause = Extract<DataManipulationOperation, { kind: 'select' }>['joins'][number]
|
|
10
|
+
type UpsertOperation = Extract<DataManipulationOperation, { kind: 'upsert' }>
|
|
11
|
+
type OperationTable = Extract<DataManipulationOperation, { kind: 'select' }>['table']
|
|
12
12
|
|
|
13
13
|
type CompileContext = {
|
|
14
14
|
values: unknown[]
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
export function
|
|
18
|
-
if (
|
|
19
|
-
return
|
|
17
|
+
export function compilePostgresOperation(operation: DataManipulationOperation): SqlStatement {
|
|
18
|
+
if (operation.kind === 'raw') {
|
|
19
|
+
return compileRawOperation(operation.sql)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
let context: CompileContext = { values: [] }
|
|
23
23
|
|
|
24
|
-
if (
|
|
24
|
+
if (operation.kind === 'select') {
|
|
25
25
|
let selection = '*'
|
|
26
26
|
|
|
27
|
-
if (
|
|
28
|
-
selection =
|
|
27
|
+
if (operation.select !== '*') {
|
|
28
|
+
selection = operation.select
|
|
29
29
|
.map((field) => quotePath(field.column) + ' as ' + quoteIdentifier(field.alias))
|
|
30
30
|
.join(', ')
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
let text =
|
|
34
34
|
'select ' +
|
|
35
|
-
(
|
|
35
|
+
(operation.distinct ? 'distinct ' : '') +
|
|
36
36
|
selection +
|
|
37
|
-
compileFromClause(
|
|
38
|
-
compileWhereClause(
|
|
39
|
-
compileGroupByClause(
|
|
40
|
-
compileHavingClause(
|
|
41
|
-
compileOrderByClause(
|
|
42
|
-
compileLimitClause(
|
|
43
|
-
compileOffsetClause(
|
|
37
|
+
compileFromClause(operation.table, operation.joins, context) +
|
|
38
|
+
compileWhereClause(operation.where, context) +
|
|
39
|
+
compileGroupByClause(operation.groupBy) +
|
|
40
|
+
compileHavingClause(operation.having, context) +
|
|
41
|
+
compileOrderByClause(operation.orderBy) +
|
|
42
|
+
compileLimitClause(operation.limit) +
|
|
43
|
+
compileOffsetClause(operation.offset)
|
|
44
44
|
|
|
45
45
|
return {
|
|
46
46
|
text,
|
|
@@ -48,13 +48,13 @@ export function compilePostgresStatement(statement: AdapterStatement): CompiledS
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
if (
|
|
51
|
+
if (operation.kind === 'count' || operation.kind === 'exists') {
|
|
52
52
|
let inner =
|
|
53
53
|
'select 1' +
|
|
54
|
-
compileFromClause(
|
|
55
|
-
compileWhereClause(
|
|
56
|
-
compileGroupByClause(
|
|
57
|
-
compileHavingClause(
|
|
54
|
+
compileFromClause(operation.table, operation.joins, context) +
|
|
55
|
+
compileWhereClause(operation.where, context) +
|
|
56
|
+
compileGroupByClause(operation.groupBy) +
|
|
57
|
+
compileHavingClause(operation.having, context)
|
|
58
58
|
|
|
59
59
|
return {
|
|
60
60
|
text:
|
|
@@ -68,61 +68,61 @@ export function compilePostgresStatement(statement: AdapterStatement): CompiledS
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
if (
|
|
72
|
-
return
|
|
71
|
+
if (operation.kind === 'insert') {
|
|
72
|
+
return compileInsertOperation(operation.table, operation.values, operation.returning, context)
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
if (
|
|
76
|
-
return
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
75
|
+
if (operation.kind === 'insertMany') {
|
|
76
|
+
return compileInsertManyOperation(
|
|
77
|
+
operation.table,
|
|
78
|
+
operation.values,
|
|
79
|
+
operation.returning,
|
|
80
80
|
context,
|
|
81
81
|
)
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
if (
|
|
85
|
-
let changes = Object.keys(
|
|
84
|
+
if (operation.kind === 'update') {
|
|
85
|
+
let changes = Object.keys(operation.changes)
|
|
86
86
|
let assignments = changes
|
|
87
|
-
.map((column) => quotePath(column) + ' = ' + pushValue(context,
|
|
87
|
+
.map((column) => quotePath(column) + ' = ' + pushValue(context, operation.changes[column]))
|
|
88
88
|
.join(', ')
|
|
89
89
|
|
|
90
90
|
return {
|
|
91
91
|
text:
|
|
92
92
|
'update ' +
|
|
93
|
-
quotePath(getTableName(
|
|
93
|
+
quotePath(getTableName(operation.table)) +
|
|
94
94
|
' set ' +
|
|
95
95
|
assignments +
|
|
96
|
-
compileWhereClause(
|
|
97
|
-
compileReturningClause(
|
|
96
|
+
compileWhereClause(operation.where, context) +
|
|
97
|
+
compileReturningClause(operation.returning),
|
|
98
98
|
values: context.values,
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
if (
|
|
102
|
+
if (operation.kind === 'delete') {
|
|
103
103
|
return {
|
|
104
104
|
text:
|
|
105
105
|
'delete from ' +
|
|
106
|
-
quotePath(getTableName(
|
|
107
|
-
compileWhereClause(
|
|
108
|
-
compileReturningClause(
|
|
106
|
+
quotePath(getTableName(operation.table)) +
|
|
107
|
+
compileWhereClause(operation.where, context) +
|
|
108
|
+
compileReturningClause(operation.returning),
|
|
109
109
|
values: context.values,
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
if (
|
|
114
|
-
return
|
|
113
|
+
if (operation.kind === 'upsert') {
|
|
114
|
+
return compileUpsertOperation(operation, context)
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
throw new Error('Unsupported
|
|
117
|
+
throw new Error('Unsupported operation kind')
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
function
|
|
121
|
-
table:
|
|
120
|
+
function compileInsertOperation(
|
|
121
|
+
table: OperationTable,
|
|
122
122
|
values: Record<string, unknown>,
|
|
123
123
|
returning: '*' | string[] | undefined,
|
|
124
124
|
context: CompileContext,
|
|
125
|
-
):
|
|
125
|
+
): SqlStatement {
|
|
126
126
|
let columns = Object.keys(values)
|
|
127
127
|
|
|
128
128
|
if (columns.length === 0) {
|
|
@@ -153,12 +153,12 @@ function compileInsertStatement(
|
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
155
|
|
|
156
|
-
function
|
|
157
|
-
table:
|
|
156
|
+
function compileInsertManyOperation(
|
|
157
|
+
table: OperationTable,
|
|
158
158
|
rows: Record<string, unknown>[],
|
|
159
159
|
returning: '*' | string[] | undefined,
|
|
160
160
|
context: CompileContext,
|
|
161
|
-
):
|
|
161
|
+
): SqlStatement {
|
|
162
162
|
if (rows.length === 0) {
|
|
163
163
|
return {
|
|
164
164
|
text: 'select 0 where 1 = 0',
|
|
@@ -203,9 +203,9 @@ function compileInsertManyStatement(
|
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
function
|
|
207
|
-
let insertColumns = Object.keys(
|
|
208
|
-
let conflictTarget =
|
|
206
|
+
function compileUpsertOperation(operation: UpsertOperation, context: CompileContext): SqlStatement {
|
|
207
|
+
let insertColumns = Object.keys(operation.values)
|
|
208
|
+
let conflictTarget = operation.conflictTarget ?? [...getTablePrimaryKey(operation.table)]
|
|
209
209
|
|
|
210
210
|
if (insertColumns.length === 0) {
|
|
211
211
|
throw new Error('upsert requires at least one value')
|
|
@@ -213,10 +213,10 @@ function compileUpsertStatement(statement: UpsertStatement, context: CompileCont
|
|
|
213
213
|
|
|
214
214
|
let quotedInsertColumns = insertColumns.map((column) => quotePath(column))
|
|
215
215
|
let insertPlaceholders = insertColumns.map((column) =>
|
|
216
|
-
pushValue(context,
|
|
216
|
+
pushValue(context, operation.values[column]),
|
|
217
217
|
)
|
|
218
218
|
|
|
219
|
-
let updateValues =
|
|
219
|
+
let updateValues = operation.update ?? operation.values
|
|
220
220
|
let updateColumns = Object.keys(updateValues)
|
|
221
221
|
let onConflictClause = ''
|
|
222
222
|
|
|
@@ -238,19 +238,19 @@ function compileUpsertStatement(statement: UpsertStatement, context: CompileCont
|
|
|
238
238
|
return {
|
|
239
239
|
text:
|
|
240
240
|
'insert into ' +
|
|
241
|
-
quotePath(getTableName(
|
|
241
|
+
quotePath(getTableName(operation.table)) +
|
|
242
242
|
' (' +
|
|
243
243
|
quotedInsertColumns.join(', ') +
|
|
244
244
|
') values (' +
|
|
245
245
|
insertPlaceholders.join(', ') +
|
|
246
246
|
')' +
|
|
247
247
|
onConflictClause +
|
|
248
|
-
compileReturningClause(
|
|
248
|
+
compileReturningClause(operation.returning),
|
|
249
249
|
values: context.values,
|
|
250
250
|
}
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
function
|
|
253
|
+
function compileRawOperation(statement: SqlStatement): SqlStatement {
|
|
254
254
|
if (!statement.text.includes('?')) {
|
|
255
255
|
return {
|
|
256
256
|
text: statement.text,
|
|
@@ -272,7 +272,7 @@ function compileRawStatement(statement: SqlStatement): CompiledSql {
|
|
|
272
272
|
}
|
|
273
273
|
|
|
274
274
|
function compileFromClause(
|
|
275
|
-
table:
|
|
275
|
+
table: OperationTable,
|
|
276
276
|
joins: JoinClause[],
|
|
277
277
|
context: CompileContext,
|
|
278
278
|
): string {
|
|
@@ -480,15 +480,7 @@ function compileComparisonValue(
|
|
|
480
480
|
}
|
|
481
481
|
|
|
482
482
|
function normalizeJoinType(type: string): string {
|
|
483
|
-
|
|
484
|
-
return 'left'
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
if (type === 'right') {
|
|
488
|
-
return 'right'
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
return 'inner'
|
|
483
|
+
return normalizeJoinTypeHelper(type)
|
|
492
484
|
}
|
|
493
485
|
|
|
494
486
|
function quoteIdentifier(value: string): string {
|
|
@@ -496,21 +488,7 @@ function quoteIdentifier(value: string): string {
|
|
|
496
488
|
}
|
|
497
489
|
|
|
498
490
|
function quotePath(path: string): string {
|
|
499
|
-
|
|
500
|
-
return '*'
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
let segments = path.split('.')
|
|
504
|
-
|
|
505
|
-
return segments
|
|
506
|
-
.map((segment) => {
|
|
507
|
-
if (segment === '*') {
|
|
508
|
-
return '*'
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
return quoteIdentifier(segment)
|
|
512
|
-
})
|
|
513
|
-
.join('.')
|
|
491
|
+
return quotePathHelper(path, quoteIdentifier)
|
|
514
492
|
}
|
|
515
493
|
|
|
516
494
|
function pushValue(context: CompileContext, value: unknown): string {
|
|
@@ -519,23 +497,5 @@ function pushValue(context: CompileContext, value: unknown): string {
|
|
|
519
497
|
}
|
|
520
498
|
|
|
521
499
|
function collectColumns(rows: Record<string, unknown>[]): string[] {
|
|
522
|
-
|
|
523
|
-
let seen = new Set<string>()
|
|
524
|
-
|
|
525
|
-
for (let row of rows) {
|
|
526
|
-
for (let key in row) {
|
|
527
|
-
if (!Object.prototype.hasOwnProperty.call(row, key)) {
|
|
528
|
-
continue
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
if (seen.has(key)) {
|
|
532
|
-
continue
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
seen.add(key)
|
|
536
|
-
columns.push(key)
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
return columns
|
|
500
|
+
return collectColumnsHelper(rows)
|
|
541
501
|
}
|