@subsquid/openreader 4.6.0 → 5.0.0-beta.62d187
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/lib/context.d.ts +2 -2
- package/lib/context.d.ts.map +1 -1
- package/lib/db.d.ts +3 -3
- package/lib/db.d.ts.map +1 -1
- package/lib/db.js +2 -2
- package/lib/db.js.map +1 -1
- package/lib/dialect/common.d.ts +19 -0
- package/lib/dialect/common.d.ts.map +1 -0
- package/lib/dialect/common.js +42 -0
- package/lib/dialect/common.js.map +1 -0
- package/lib/dialect/index.d.ts +6 -0
- package/lib/dialect/index.d.ts.map +1 -0
- package/lib/dialect/index.js +49 -0
- package/lib/dialect/index.js.map +1 -0
- package/lib/{opencrud → dialect/opencrud}/orderBy.d.ts +2 -3
- package/lib/dialect/opencrud/orderBy.d.ts.map +1 -0
- package/lib/{opencrud → dialect/opencrud}/orderBy.js +4 -21
- package/lib/dialect/opencrud/orderBy.js.map +1 -0
- package/lib/{opencrud → dialect/opencrud}/schema.d.ts +2 -6
- package/lib/dialect/opencrud/schema.d.ts.map +1 -0
- package/lib/{opencrud → dialect/opencrud}/schema.js +21 -34
- package/lib/dialect/opencrud/schema.js.map +1 -0
- package/lib/{opencrud → dialect/opencrud}/tree.d.ts +3 -3
- package/lib/dialect/opencrud/tree.d.ts.map +1 -0
- package/lib/{opencrud → dialect/opencrud}/tree.js +3 -3
- package/lib/dialect/opencrud/tree.js.map +1 -0
- package/lib/{opencrud → dialect/opencrud}/where.d.ts +1 -1
- package/lib/dialect/opencrud/where.d.ts.map +1 -0
- package/lib/{opencrud → dialect/opencrud}/where.js +4 -13
- package/lib/dialect/opencrud/where.js.map +1 -0
- package/lib/dialect/thegraph/locale.d.ts +2 -0
- package/lib/dialect/thegraph/locale.d.ts.map +1 -0
- package/lib/dialect/thegraph/locale.js +49 -0
- package/lib/dialect/thegraph/locale.js.map +1 -0
- package/lib/dialect/thegraph/orderBy.d.ts +11 -0
- package/lib/dialect/thegraph/orderBy.d.ts.map +1 -0
- package/lib/dialect/thegraph/orderBy.js +71 -0
- package/lib/dialect/thegraph/orderBy.js.map +1 -0
- package/lib/dialect/thegraph/schema.d.ts +25 -0
- package/lib/dialect/thegraph/schema.d.ts.map +1 -0
- package/lib/dialect/thegraph/schema.js +429 -0
- package/lib/dialect/thegraph/schema.js.map +1 -0
- package/lib/dialect/thegraph/tree.d.ts +10 -0
- package/lib/dialect/thegraph/tree.d.ts.map +1 -0
- package/lib/dialect/thegraph/tree.js +148 -0
- package/lib/dialect/thegraph/tree.js.map +1 -0
- package/lib/dialect/thegraph/where.d.ts +9 -0
- package/lib/dialect/thegraph/where.d.ts.map +1 -0
- package/lib/dialect/thegraph/where.js +188 -0
- package/lib/dialect/thegraph/where.js.map +1 -0
- package/lib/ir/args.d.ts +1 -1
- package/lib/ir/args.d.ts.map +1 -1
- package/lib/main.js +1 -1
- package/lib/main.js.map +1 -1
- package/lib/model.d.ts +2 -0
- package/lib/model.d.ts.map +1 -1
- package/lib/model.schema.d.ts.map +1 -1
- package/lib/model.schema.js +31 -2
- package/lib/model.schema.js.map +1 -1
- package/lib/server.d.ts +3 -1
- package/lib/server.d.ts.map +1 -1
- package/lib/server.js +7 -6
- package/lib/server.js.map +1 -1
- package/lib/sql/cursor.d.ts +2 -2
- package/lib/sql/cursor.d.ts.map +1 -1
- package/lib/sql/cursor.js +2 -2
- package/lib/sql/cursor.js.map +1 -1
- package/lib/sql/printer.d.ts +3 -3
- package/lib/sql/printer.d.ts.map +1 -1
- package/lib/sql/printer.js +17 -15
- package/lib/sql/printer.js.map +1 -1
- package/lib/sql/query.d.ts +5 -5
- package/lib/sql/query.d.ts.map +1 -1
- package/lib/sql/query.js.map +1 -1
- package/lib/sql/util.d.ts +2 -2
- package/lib/sql/util.d.ts.map +1 -1
- package/lib/sql/util.js.map +1 -1
- package/lib/test/basic.test.js +471 -229
- package/lib/test/basic.test.js.map +1 -1
- package/lib/test/isNull.test.js +87 -36
- package/lib/test/isNull.test.js.map +1 -1
- package/lib/test/limits.test.js +206 -94
- package/lib/test/limits.test.js.map +1 -1
- package/lib/test/lookup.test.js +184 -81
- package/lib/test/lookup.test.js.map +1 -1
- package/lib/test/setup.js +2 -2
- package/lib/test/setup.js.map +1 -1
- package/lib/test/where.test.js +216 -99
- package/lib/test/where.test.js.map +1 -1
- package/package.json +5 -3
- package/src/context.ts +2 -2
- package/src/db.ts +4 -2
- package/src/dialect/common.ts +49 -0
- package/src/dialect/index.ts +20 -0
- package/src/{opencrud → dialect/opencrud}/orderBy.ts +4 -21
- package/src/{opencrud → dialect/opencrud}/schema.ts +30 -55
- package/src/{opencrud → dialect/opencrud}/tree.ts +6 -7
- package/src/{opencrud → dialect/opencrud}/where.ts +4 -16
- package/src/dialect/thegraph/locale.ts +284 -0
- package/src/dialect/thegraph/orderBy.ts +75 -0
- package/src/dialect/thegraph/schema.ts +484 -0
- package/src/dialect/thegraph/tree.ts +162 -0
- package/src/dialect/thegraph/where.ts +184 -0
- package/src/ir/args.ts +2 -0
- package/src/main.ts +3 -3
- package/src/model.schema.ts +37 -4
- package/src/model.ts +2 -0
- package/src/server.ts +21 -19
- package/src/sql/cursor.ts +4 -4
- package/src/sql/printer.ts +22 -18
- package/src/sql/query.ts +5 -5
- package/src/sql/util.ts +2 -2
- package/src/test/basic.test.ts +570 -282
- package/src/test/isNull.test.ts +95 -38
- package/src/test/limits.test.ts +212 -91
- package/src/test/lookup.test.ts +190 -83
- package/src/test/setup.ts +2 -2
- package/src/test/where.test.ts +235 -108
- package/lib/dialect.d.ts +0 -2
- package/lib/dialect.d.ts.map +0 -1
- package/lib/dialect.js +0 -3
- package/lib/dialect.js.map +0 -1
- package/lib/opencrud/orderBy.d.ts.map +0 -1
- package/lib/opencrud/orderBy.js.map +0 -1
- package/lib/opencrud/schema.d.ts.map +0 -1
- package/lib/opencrud/schema.js.map +0 -1
- package/lib/opencrud/tree.d.ts.map +0 -1
- package/lib/opencrud/tree.js.map +0 -1
- package/lib/opencrud/where.d.ts.map +0 -1
- package/lib/opencrud/where.js.map +0 -1
- package/src/dialect.ts +0 -2
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import {unexpectedCase} from '@subsquid/util-internal'
|
|
2
|
+
import assert from 'assert'
|
|
3
|
+
import {Where} from '../../ir/args'
|
|
4
|
+
import {ensureArray} from '../../util/util'
|
|
5
|
+
import {toCondition} from '../common'
|
|
6
|
+
|
|
7
|
+
export function parseWhere(whereArg?: any): Where | undefined {
|
|
8
|
+
if (whereArg == null) return undefined
|
|
9
|
+
let {and, or, ...fields} = whereArg
|
|
10
|
+
let conj: Where[] = []
|
|
11
|
+
|
|
12
|
+
for (let key in fields) {
|
|
13
|
+
let arg = fields[key]
|
|
14
|
+
let {field, op} = parseWhereKey(key)
|
|
15
|
+
switch (op) {
|
|
16
|
+
case 'SELF':
|
|
17
|
+
conj.push({op: 'eq', field, value: arg})
|
|
18
|
+
break
|
|
19
|
+
case '_': {
|
|
20
|
+
let where = parseWhere(arg)
|
|
21
|
+
where && conj.push({op: 'REF', field, where})
|
|
22
|
+
break
|
|
23
|
+
}
|
|
24
|
+
case '_every': {
|
|
25
|
+
let where = parseWhere(arg)
|
|
26
|
+
where && conj.push({op: 'every', field, where})
|
|
27
|
+
break
|
|
28
|
+
}
|
|
29
|
+
case '_some':
|
|
30
|
+
conj.push({op: 'some', field, where: parseWhere(arg)})
|
|
31
|
+
break
|
|
32
|
+
case '_none':
|
|
33
|
+
conj.push({op: 'none', field, where: parseWhere(arg)})
|
|
34
|
+
break
|
|
35
|
+
case '_in':
|
|
36
|
+
conj.push({op: 'in', field, values: ensureArray(arg)})
|
|
37
|
+
break
|
|
38
|
+
case '_not_in':
|
|
39
|
+
conj.push({op: 'not_in', field, values: ensureArray(arg)})
|
|
40
|
+
break
|
|
41
|
+
case '_not':
|
|
42
|
+
conj.push({op: 'not_eq', field, value: arg})
|
|
43
|
+
break
|
|
44
|
+
case '_gt':
|
|
45
|
+
conj.push({op: 'gt', field, value: arg})
|
|
46
|
+
break
|
|
47
|
+
case '_gte':
|
|
48
|
+
conj.push({op: 'gte', field, value: arg})
|
|
49
|
+
break
|
|
50
|
+
case '_lt':
|
|
51
|
+
conj.push({op: 'lt', field, value: arg})
|
|
52
|
+
break
|
|
53
|
+
case '_lte':
|
|
54
|
+
conj.push({op: 'lte', field, value: arg})
|
|
55
|
+
break
|
|
56
|
+
case '_contains':
|
|
57
|
+
conj.push({op: 'contains', field, value: arg})
|
|
58
|
+
break
|
|
59
|
+
case '_not_contains':
|
|
60
|
+
conj.push({op: 'not_contains', field, value: arg})
|
|
61
|
+
break
|
|
62
|
+
case '_contains_nocase':
|
|
63
|
+
conj.push({op: 'containsInsensitive', field, value: arg})
|
|
64
|
+
break
|
|
65
|
+
case '_not_contains_nocase':
|
|
66
|
+
conj.push({op: 'not_containsInsensitive', field, value: arg})
|
|
67
|
+
break
|
|
68
|
+
case '_starts_with':
|
|
69
|
+
conj.push({op: 'startsWith', field, value: arg})
|
|
70
|
+
break
|
|
71
|
+
case '_starts_with_nocase':
|
|
72
|
+
conj.push({op: 'startsWithInsensitive', field, value: arg})
|
|
73
|
+
break
|
|
74
|
+
case '_not_starts_with':
|
|
75
|
+
conj.push({op: 'not_startsWith', field, value: arg})
|
|
76
|
+
break
|
|
77
|
+
case '_not_starts_with_nocase':
|
|
78
|
+
conj.push({op: 'not_startsWithInsensitive', field, value: arg})
|
|
79
|
+
break
|
|
80
|
+
case '_ends_with':
|
|
81
|
+
conj.push({op: 'endsWith', field, value: arg})
|
|
82
|
+
break
|
|
83
|
+
case '_ends_with_nocase':
|
|
84
|
+
conj.push({op: 'endsWithInsensitive', field, value: arg})
|
|
85
|
+
break
|
|
86
|
+
case '_not_ends_with':
|
|
87
|
+
conj.push({op: 'not_endsWith', field, value: arg})
|
|
88
|
+
break
|
|
89
|
+
case '_not_ends_with_nocase':
|
|
90
|
+
conj.push({op: 'not_endsWithInsensitive', field, value: arg})
|
|
91
|
+
break
|
|
92
|
+
case '_json_has_key':
|
|
93
|
+
conj.push({op: 'jsonHasKey', field, value: arg})
|
|
94
|
+
break
|
|
95
|
+
case '_json_contains':
|
|
96
|
+
conj.push({op: 'jsonContains', field, value: arg})
|
|
97
|
+
break
|
|
98
|
+
case '_contains_none':
|
|
99
|
+
conj.push({op: 'containsNone', field, value: ensureArray(arg)})
|
|
100
|
+
break
|
|
101
|
+
case '_contains_all':
|
|
102
|
+
conj.push({op: 'containsAll', field, value: ensureArray(arg)})
|
|
103
|
+
break
|
|
104
|
+
case '_contains_any':
|
|
105
|
+
conj.push({op: 'containsAny', field, value: ensureArray(arg)})
|
|
106
|
+
break
|
|
107
|
+
case '_is_null':
|
|
108
|
+
assert(typeof arg == 'boolean')
|
|
109
|
+
conj.push({op: 'isNull', field, yes: arg})
|
|
110
|
+
break
|
|
111
|
+
default:
|
|
112
|
+
throw unexpectedCase(op)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (and) {
|
|
117
|
+
for (let arg of ensureArray(and)) {
|
|
118
|
+
let where = parseWhere(arg)
|
|
119
|
+
if (where) {
|
|
120
|
+
conj.push(where)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let conjunction = toCondition('AND', conj)
|
|
126
|
+
if (or) {
|
|
127
|
+
let disjunctions: Where[] = []
|
|
128
|
+
if (conjunction) {
|
|
129
|
+
disjunctions.push(conjunction)
|
|
130
|
+
}
|
|
131
|
+
for (let arg of ensureArray(or)) {
|
|
132
|
+
let where = parseWhere(arg)
|
|
133
|
+
if (where) {
|
|
134
|
+
disjunctions.push(where)
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return toCondition('OR', disjunctions)
|
|
138
|
+
} else {
|
|
139
|
+
return conjunction
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function parseWhereKey(key: string): {op: (typeof WHERE_OPS)[number] | 'SELF'; field: string} {
|
|
144
|
+
let m = WHERE_KEY_REGEX.exec(key)
|
|
145
|
+
if (m) {
|
|
146
|
+
return {op: m[2] as (typeof WHERE_OPS)[number], field: m[1]}
|
|
147
|
+
} else {
|
|
148
|
+
return {op: 'SELF', field: key}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const WHERE_OPS = [
|
|
153
|
+
'_',
|
|
154
|
+
'_not',
|
|
155
|
+
'_gt',
|
|
156
|
+
'_gte',
|
|
157
|
+
'_lt',
|
|
158
|
+
'_lte',
|
|
159
|
+
'_in',
|
|
160
|
+
'_not_in',
|
|
161
|
+
'_contains',
|
|
162
|
+
'_contains_nocase',
|
|
163
|
+
'_not_contains',
|
|
164
|
+
'_not_contains_nocase',
|
|
165
|
+
'_starts_with',
|
|
166
|
+
'_starts_with_nocase',
|
|
167
|
+
'_not_starts_with',
|
|
168
|
+
'_not_starts_with_nocase',
|
|
169
|
+
'_ends_with',
|
|
170
|
+
'_ends_with_nocase',
|
|
171
|
+
'_not_ends_with',
|
|
172
|
+
'_not_ends_with_nocase',
|
|
173
|
+
'_contains_all',
|
|
174
|
+
'_contains_any',
|
|
175
|
+
'_contains_none',
|
|
176
|
+
'_json_contains',
|
|
177
|
+
'_json_has_key',
|
|
178
|
+
'_is_null',
|
|
179
|
+
'_some',
|
|
180
|
+
'_every',
|
|
181
|
+
'_none',
|
|
182
|
+
] as const
|
|
183
|
+
|
|
184
|
+
const WHERE_KEY_REGEX = new RegExp(`^([^_]*)(${WHERE_OPS.join('|')})$`)
|
package/src/ir/args.ts
CHANGED
|
@@ -66,7 +66,9 @@ export type BinaryOp =
|
|
|
66
66
|
'contains' | 'not_contains' |
|
|
67
67
|
'containsInsensitive' | 'not_containsInsensitive' |
|
|
68
68
|
'startsWith' | 'not_startsWith' |
|
|
69
|
+
'startsWithInsensitive' | 'not_startsWithInsensitive' |
|
|
69
70
|
'endsWith' | 'not_endsWith' |
|
|
71
|
+
'endsWithInsensitive' | 'not_endsWithInsensitive' |
|
|
70
72
|
'containsAll' |
|
|
71
73
|
'containsAny' |
|
|
72
74
|
'containsNone' |
|
package/src/main.ts
CHANGED
|
@@ -4,7 +4,7 @@ import {nat, Url} from '@subsquid/util-internal-commander'
|
|
|
4
4
|
import {waitForInterruption} from '@subsquid/util-internal-http-server'
|
|
5
5
|
import {Command, Option} from 'commander'
|
|
6
6
|
import {Pool} from 'pg'
|
|
7
|
-
import {
|
|
7
|
+
import {DbType} from './db'
|
|
8
8
|
import {serve} from './server'
|
|
9
9
|
import {loadModel} from './tools'
|
|
10
10
|
|
|
@@ -36,7 +36,7 @@ GraphQL server for postgres-compatible databases
|
|
|
36
36
|
let opts = program.parse().opts() as {
|
|
37
37
|
schema: string
|
|
38
38
|
dbUrl: string
|
|
39
|
-
dbType:
|
|
39
|
+
dbType: DbType
|
|
40
40
|
port: number
|
|
41
41
|
maxRequestSize: number
|
|
42
42
|
maxRootFields?: number
|
|
@@ -56,7 +56,7 @@ GraphQL server for postgres-compatible databases
|
|
|
56
56
|
|
|
57
57
|
let server = await serve({
|
|
58
58
|
model,
|
|
59
|
-
|
|
59
|
+
dbType: opts.dbType,
|
|
60
60
|
connection,
|
|
61
61
|
port: opts.port,
|
|
62
62
|
log: LOG,
|
package/src/model.schema.ts
CHANGED
|
@@ -24,7 +24,7 @@ import {customScalars} from './scalars'
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
const baseSchema = buildASTSchema(parse(`
|
|
27
|
-
directive @entity on OBJECT
|
|
27
|
+
directive @entity(queryName: String listQueryName: String) on OBJECT
|
|
28
28
|
directive @query on INTERFACE
|
|
29
29
|
directive @derivedFrom(field: String!) on FIELD_DEFINITION
|
|
30
30
|
directive @unique on FIELD_DEFINITION
|
|
@@ -80,10 +80,18 @@ function addEntityOrJsonObjectOrInterface(model: Model, type: GraphQLObjectType
|
|
|
80
80
|
let indexes: Index[] = type instanceof GraphQLObjectType ? checkEntityIndexes(type) : []
|
|
81
81
|
let cardinality = checkEntityCardinality(type)
|
|
82
82
|
let description = type.description || undefined
|
|
83
|
-
|
|
84
|
-
switch(kind) {
|
|
83
|
+
|
|
84
|
+
switch (kind) {
|
|
85
85
|
case 'entity':
|
|
86
|
-
model[type.name] = {
|
|
86
|
+
model[type.name] = {
|
|
87
|
+
kind,
|
|
88
|
+
properties,
|
|
89
|
+
description,
|
|
90
|
+
interfaces,
|
|
91
|
+
indexes,
|
|
92
|
+
...cardinality,
|
|
93
|
+
...handleEntityDirective(model, type),
|
|
94
|
+
}
|
|
87
95
|
break
|
|
88
96
|
case 'object':
|
|
89
97
|
model[type.name] = {kind, properties, description, interfaces}
|
|
@@ -528,4 +536,29 @@ function unsupportedFieldTypeError(propName: string): Error {
|
|
|
528
536
|
}
|
|
529
537
|
|
|
530
538
|
|
|
539
|
+
function handleEntityDirective(model: Model, type: GraphQLObjectType | GraphQLInterfaceType) {
|
|
540
|
+
let directive = type.astNode?.directives?.find(d => d.name.value == 'entity')
|
|
541
|
+
if (directive == null) return
|
|
542
|
+
|
|
543
|
+
let queryNameArg = directive.arguments?.find(d => d.name.value === 'queryName')
|
|
544
|
+
let queryName: string | undefined
|
|
545
|
+
if (queryNameArg != null) {
|
|
546
|
+
assert(queryNameArg?.value.kind == 'StringValue')
|
|
547
|
+
queryName = queryNameArg.value.value
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
let listQueryNameArg = directive.arguments?.find(d => d.name.value === 'listQueryName')
|
|
551
|
+
let listQueryName: string | undefined
|
|
552
|
+
if (listQueryNameArg != null) {
|
|
553
|
+
assert(listQueryNameArg?.value.kind == 'StringValue')
|
|
554
|
+
listQueryName = listQueryNameArg.value.value
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
return {
|
|
558
|
+
queryName,
|
|
559
|
+
listQueryName,
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
|
|
531
564
|
export class SchemaError extends Error {}
|
package/src/model.ts
CHANGED
package/src/server.ts
CHANGED
|
@@ -12,17 +12,18 @@ import type {Pool} from 'pg'
|
|
|
12
12
|
import {WebSocketServer} from 'ws'
|
|
13
13
|
import {Context, OpenreaderContext} from './context'
|
|
14
14
|
import {PoolOpenreaderContext} from './db'
|
|
15
|
-
import type {
|
|
15
|
+
import type {DbType} from './db'
|
|
16
16
|
import type {Model} from './model'
|
|
17
|
-
import {SchemaBuilder} from './opencrud/schema'
|
|
18
17
|
import {openreaderExecute, openreaderSubscribe} from './util/execute'
|
|
19
18
|
import {ResponseSizeLimit} from './util/limit'
|
|
19
|
+
import {Dialect, getSchemaBuilder} from './dialect'
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
export interface ServerOptions {
|
|
23
23
|
port: number | string
|
|
24
24
|
model: Model
|
|
25
25
|
connection: Pool
|
|
26
|
+
dbType?: DbType
|
|
26
27
|
dialect?: Dialect
|
|
27
28
|
graphiqlConsole?: boolean
|
|
28
29
|
log?: Logger
|
|
@@ -32,7 +33,7 @@ export interface ServerOptions {
|
|
|
32
33
|
subscriptions?: boolean
|
|
33
34
|
subscriptionPollInterval?: number
|
|
34
35
|
subscriptionConnection?: Pool
|
|
35
|
-
subscriptionMaxResponseNodes?: number
|
|
36
|
+
subscriptionMaxResponseNodes?: number
|
|
36
37
|
cache?: KeyValueCache
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -43,16 +44,17 @@ export async function serve(options: ServerOptions): Promise<ListeningServer> {
|
|
|
43
44
|
subscriptionPollInterval,
|
|
44
45
|
maxResponseNodes,
|
|
45
46
|
subscriptionMaxResponseNodes,
|
|
46
|
-
log
|
|
47
|
+
log,
|
|
47
48
|
} = options
|
|
48
49
|
|
|
49
|
-
let
|
|
50
|
+
let dbType = options.dbType ?? 'postgres'
|
|
50
51
|
|
|
51
|
-
let
|
|
52
|
+
let schemaBuilder = await getSchemaBuilder(options)
|
|
53
|
+
let schema = schemaBuilder.build()
|
|
52
54
|
|
|
53
55
|
let context = () => {
|
|
54
56
|
let openreader: OpenreaderContext = new PoolOpenreaderContext(
|
|
55
|
-
|
|
57
|
+
dbType,
|
|
56
58
|
connection,
|
|
57
59
|
subscriptionConnection,
|
|
58
60
|
subscriptionPollInterval,
|
|
@@ -69,23 +71,23 @@ export async function serve(options: ServerOptions): Promise<ListeningServer> {
|
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
return {
|
|
72
|
-
openreader
|
|
74
|
+
openreader,
|
|
73
75
|
}
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
let disposals: Dispose[] = []
|
|
77
79
|
|
|
78
80
|
return addServerCleanup(disposals, runApollo({
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
81
|
+
port: options.port,
|
|
82
|
+
schema,
|
|
83
|
+
context,
|
|
84
|
+
disposals,
|
|
85
|
+
subscriptions: options.subscriptions,
|
|
86
|
+
log: options.log,
|
|
87
|
+
graphiqlConsole: options.graphiqlConsole,
|
|
88
|
+
maxRequestSizeBytes: options.maxRequestSizeBytes,
|
|
89
|
+
maxRootFields: options.maxRootFields,
|
|
90
|
+
cache: options.cache,
|
|
89
91
|
}), options.log)
|
|
90
92
|
}
|
|
91
93
|
|
|
@@ -117,7 +119,7 @@ export async function runApollo(options: ApolloOptions): Promise<ListeningServer
|
|
|
117
119
|
|
|
118
120
|
let execute = (args: ExecutionArgs) => openreaderExecute(args, {
|
|
119
121
|
maxRootFields: maxRootFields
|
|
120
|
-
|
|
122
|
+
})
|
|
121
123
|
|
|
122
124
|
if (options.subscriptions) {
|
|
123
125
|
let wsServer = new WebSocketServer({
|
package/src/sql/cursor.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {assertNotNull, unexpectedCase} from "@subsquid/util-internal"
|
|
2
2
|
import {toSnakeCase} from "@subsquid/util-naming"
|
|
3
3
|
import assert from "assert"
|
|
4
|
-
import {
|
|
4
|
+
import {DbType} from "../db"
|
|
5
5
|
import {Entity, JsonObject, Model, ObjectPropType, Prop, UnionPropType} from "../model"
|
|
6
6
|
import {getEntity, getFtsQuery, getObject, getUnionProps} from "../model.tools"
|
|
7
7
|
import {toColumn, toFkColumn, toTable} from "../util/util"
|
|
@@ -10,7 +10,7 @@ import {AliasSet, escapeIdentifier, JoinSet} from "./util"
|
|
|
10
10
|
|
|
11
11
|
export interface CursorCtx {
|
|
12
12
|
model: Model
|
|
13
|
-
dialect:
|
|
13
|
+
dialect: DbType
|
|
14
14
|
aliases: AliasSet
|
|
15
15
|
join: JoinSet
|
|
16
16
|
}
|
|
@@ -62,7 +62,7 @@ export class EntityCursor implements Cursor {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
prop(field: string): Prop {
|
|
65
|
-
return assertNotNull(this.entity.properties[field])
|
|
65
|
+
return assertNotNull(this.entity.properties[field], `property ${field} is missing`)
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
output(field: string): string {
|
|
@@ -209,7 +209,7 @@ export class ObjectCursor implements Cursor {
|
|
|
209
209
|
}
|
|
210
210
|
|
|
211
211
|
prop(field: string): Prop {
|
|
212
|
-
return assertNotNull(this.object.properties[field])
|
|
212
|
+
return assertNotNull(this.object.properties[field], `property ${field} is missing`)
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
output(field: string): string {
|
package/src/sql/printer.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {unexpectedCase} from '@subsquid/util-internal'
|
|
2
2
|
import assert from 'assert'
|
|
3
|
-
import {
|
|
3
|
+
import {DbType} from '../db'
|
|
4
4
|
import {OrderBy, SortOrder, SqlArguments, Where} from '../ir/args'
|
|
5
5
|
import {FieldRequest, FieldsByEntity} from '../ir/fields'
|
|
6
6
|
import {Model} from '../model'
|
|
@@ -19,7 +19,7 @@ export class EntitySqlPrinter {
|
|
|
19
19
|
|
|
20
20
|
constructor(
|
|
21
21
|
private model: Model,
|
|
22
|
-
private dialect:
|
|
22
|
+
private dialect: DbType,
|
|
23
23
|
public readonly entityName: string,
|
|
24
24
|
private params: unknown[],
|
|
25
25
|
private args: SqlArguments = {},
|
|
@@ -92,6 +92,10 @@ export class EntitySqlPrinter {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
private populateWhere(cursor: Cursor, where: Where, exps: string[]): void {
|
|
95
|
+
function printStr(value: string) {
|
|
96
|
+
return !!where.op?.endsWith?.('Insensitive') ? `lower(${value})` : value
|
|
97
|
+
}
|
|
98
|
+
|
|
95
99
|
switch(where.op) {
|
|
96
100
|
case "AND":
|
|
97
101
|
for (let cond of where.args) {
|
|
@@ -178,47 +182,46 @@ export class EntitySqlPrinter {
|
|
|
178
182
|
break
|
|
179
183
|
}
|
|
180
184
|
case "startsWith":
|
|
185
|
+
case "startsWithInsensitive":
|
|
181
186
|
if (this.dialect == "cockroach") {
|
|
182
187
|
let f = cursor.native(where.field)
|
|
183
188
|
let p = this.param(where.value) + "::text"
|
|
184
|
-
exps.push(`${f} >= ${p}`)
|
|
185
|
-
exps.push(`left(${f}, length(${p})) = ${p}`)
|
|
189
|
+
exps.push(`${printStr(f)} >= ${printStr(p)}`)
|
|
190
|
+
exps.push(`left(${printStr(f)}, length(${p})) = ${printStr(p)}`)
|
|
186
191
|
} else {
|
|
187
|
-
exps.push(`starts_with(${cursor.native(where.field)}, ${this.param(where.value)})`)
|
|
192
|
+
exps.push(`starts_with(${printStr(cursor.native(where.field))}, ${printStr(this.param(where.value))})`)
|
|
188
193
|
}
|
|
189
194
|
break
|
|
190
195
|
case "not_startsWith":
|
|
196
|
+
case "not_startsWithInsensitive":
|
|
191
197
|
if (this.dialect == "cockroach") {
|
|
192
198
|
let f = cursor.native(where.field)
|
|
193
199
|
let p = this.param(where.value) + "::text"
|
|
194
|
-
exps.push(`(${f} < ${p} OR left(${f}, length(${p})) != ${p})`)
|
|
200
|
+
exps.push(`(${printStr(f)} < ${printStr(p)} OR left(${printStr(f)}, length(${printStr(p)})) != ${printStr(p)})`)
|
|
195
201
|
} else {
|
|
196
|
-
exps.push(`NOT starts_with(${cursor.native(where.field)}, ${this.param(where.value)})`)
|
|
202
|
+
exps.push(`NOT starts_with(${printStr(cursor.native(where.field))}, ${printStr(this.param(where.value))})`)
|
|
197
203
|
}
|
|
198
204
|
break
|
|
199
|
-
case "endsWith":
|
|
205
|
+
case "endsWith":
|
|
206
|
+
case "not_startsWithInsensitive": {
|
|
200
207
|
let f = cursor.native(where.field)
|
|
201
208
|
let p = this.param(where.value) + "::text"
|
|
202
|
-
exps.push(`right(${f}, length(${p})) = ${p}`)
|
|
209
|
+
exps.push(`right(${printStr(f)}, length(${p})) = ${printStr(p)}`)
|
|
203
210
|
break
|
|
204
211
|
}
|
|
205
212
|
case "not_endsWith": {
|
|
206
213
|
let f = cursor.native(where.field)
|
|
207
214
|
let p = this.param(where.value) + "::text"
|
|
208
|
-
exps.push(`right(${f}, length(${p})) != ${p}`)
|
|
215
|
+
exps.push(`right(${printStr(f)}, length(${p})) != ${printStr(p)}`)
|
|
209
216
|
break
|
|
210
217
|
}
|
|
211
218
|
case "contains":
|
|
212
|
-
exps.push(`position(${this.param(where.value)} in ${cursor.native(where.field)}) > 0`)
|
|
213
|
-
break
|
|
214
|
-
case "not_contains":
|
|
215
|
-
exps.push(`position(${this.param(where.value)} in ${cursor.native(where.field)}) = 0`)
|
|
216
|
-
break
|
|
217
219
|
case "containsInsensitive":
|
|
218
|
-
exps.push(`position(
|
|
220
|
+
exps.push(`position(${printStr(this.param(where.value))} in ${printStr(cursor.native(where.field))}) > 0`)
|
|
219
221
|
break
|
|
222
|
+
case "not_contains":
|
|
220
223
|
case "not_containsInsensitive":
|
|
221
|
-
exps.push(`position(
|
|
224
|
+
exps.push(`position(${printStr(this.param(where.value))} in ${printStr(cursor.native(where.field))}) = 0`)
|
|
222
225
|
break
|
|
223
226
|
case "every": {
|
|
224
227
|
let rel = cursor.prop(where.field)
|
|
@@ -360,7 +363,7 @@ export class QueryableSqlPrinter {
|
|
|
360
363
|
|
|
361
364
|
constructor(
|
|
362
365
|
private model: Model,
|
|
363
|
-
private dialect:
|
|
366
|
+
private dialect: DbType,
|
|
364
367
|
private queryableName: string,
|
|
365
368
|
private params: unknown[],
|
|
366
369
|
private args: SqlArguments = {},
|
|
@@ -446,3 +449,4 @@ export class QueryableSqlPrinter {
|
|
|
446
449
|
return sql
|
|
447
450
|
}
|
|
448
451
|
}
|
|
452
|
+
|
package/src/sql/query.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {assertNotNull} from '@subsquid/util-internal'
|
|
2
2
|
import assert from 'assert'
|
|
3
|
-
import type {
|
|
3
|
+
import type {DbType} from '../db'
|
|
4
4
|
import type {SqlArguments, Where} from '../ir/args'
|
|
5
5
|
import {
|
|
6
6
|
decodeRelayConnectionCursor,
|
|
@@ -30,7 +30,7 @@ export class ListQuery implements Query<any[]> {
|
|
|
30
30
|
|
|
31
31
|
constructor(
|
|
32
32
|
model: Model,
|
|
33
|
-
dialect:
|
|
33
|
+
dialect: DbType,
|
|
34
34
|
typeName: string,
|
|
35
35
|
private fields: AnyFields,
|
|
36
36
|
args: SqlArguments
|
|
@@ -60,7 +60,7 @@ export class EntityByIdQuery {
|
|
|
60
60
|
|
|
61
61
|
constructor(
|
|
62
62
|
model: Model,
|
|
63
|
-
dialect:
|
|
63
|
+
dialect: DbType,
|
|
64
64
|
entityName: string,
|
|
65
65
|
private fields: FieldRequest[],
|
|
66
66
|
id: string
|
|
@@ -88,7 +88,7 @@ export class CountQuery implements Query<number> {
|
|
|
88
88
|
|
|
89
89
|
constructor(
|
|
90
90
|
model: Model,
|
|
91
|
-
dialect:
|
|
91
|
+
dialect: DbType,
|
|
92
92
|
typeName: string,
|
|
93
93
|
where?: Where
|
|
94
94
|
) {
|
|
@@ -114,7 +114,7 @@ export class ConnectionQuery implements Query<RelayConnectionResponse> {
|
|
|
114
114
|
|
|
115
115
|
constructor(
|
|
116
116
|
model: Model,
|
|
117
|
-
dialect:
|
|
117
|
+
dialect: DbType,
|
|
118
118
|
typeName: string,
|
|
119
119
|
req: RelayConnectionRequest<AnyFields>
|
|
120
120
|
) {
|
package/src/sql/util.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {DbType} from "../db"
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
export function escapeIdentifier(dialect:
|
|
4
|
+
export function escapeIdentifier(dialect: DbType, name: string): string {
|
|
5
5
|
return `"${name.replace(/"/g, '""')}"`
|
|
6
6
|
}
|
|
7
7
|
|