@subsquid/openreader 4.6.0 → 5.0.0-beta.79fbfe

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 (131) hide show
  1. package/lib/context.d.ts +2 -2
  2. package/lib/context.d.ts.map +1 -1
  3. package/lib/db.d.ts +3 -3
  4. package/lib/db.d.ts.map +1 -1
  5. package/lib/db.js +2 -2
  6. package/lib/db.js.map +1 -1
  7. package/lib/dialect/common.d.ts +19 -0
  8. package/lib/dialect/common.d.ts.map +1 -0
  9. package/lib/dialect/common.js +42 -0
  10. package/lib/dialect/common.js.map +1 -0
  11. package/lib/dialect/index.d.ts +6 -0
  12. package/lib/dialect/index.d.ts.map +1 -0
  13. package/lib/dialect/index.js +49 -0
  14. package/lib/dialect/index.js.map +1 -0
  15. package/lib/{opencrud → dialect/opencrud}/orderBy.d.ts +2 -3
  16. package/lib/dialect/opencrud/orderBy.d.ts.map +1 -0
  17. package/lib/{opencrud → dialect/opencrud}/orderBy.js +4 -21
  18. package/lib/dialect/opencrud/orderBy.js.map +1 -0
  19. package/lib/{opencrud → dialect/opencrud}/schema.d.ts +2 -6
  20. package/lib/dialect/opencrud/schema.d.ts.map +1 -0
  21. package/lib/{opencrud → dialect/opencrud}/schema.js +21 -34
  22. package/lib/dialect/opencrud/schema.js.map +1 -0
  23. package/lib/{opencrud → dialect/opencrud}/tree.d.ts +3 -3
  24. package/lib/dialect/opencrud/tree.d.ts.map +1 -0
  25. package/lib/{opencrud → dialect/opencrud}/tree.js +3 -3
  26. package/lib/dialect/opencrud/tree.js.map +1 -0
  27. package/lib/{opencrud → dialect/opencrud}/where.d.ts +1 -1
  28. package/lib/dialect/opencrud/where.d.ts.map +1 -0
  29. package/lib/{opencrud → dialect/opencrud}/where.js +4 -13
  30. package/lib/dialect/opencrud/where.js.map +1 -0
  31. package/lib/dialect/thegraph/locale.d.ts +2 -0
  32. package/lib/dialect/thegraph/locale.d.ts.map +1 -0
  33. package/lib/dialect/thegraph/locale.js +49 -0
  34. package/lib/dialect/thegraph/locale.js.map +1 -0
  35. package/lib/dialect/thegraph/orderBy.d.ts +11 -0
  36. package/lib/dialect/thegraph/orderBy.d.ts.map +1 -0
  37. package/lib/dialect/thegraph/orderBy.js +71 -0
  38. package/lib/dialect/thegraph/orderBy.js.map +1 -0
  39. package/lib/dialect/thegraph/schema.d.ts +25 -0
  40. package/lib/dialect/thegraph/schema.d.ts.map +1 -0
  41. package/lib/dialect/thegraph/schema.js +429 -0
  42. package/lib/dialect/thegraph/schema.js.map +1 -0
  43. package/lib/dialect/thegraph/tree.d.ts +10 -0
  44. package/lib/dialect/thegraph/tree.d.ts.map +1 -0
  45. package/lib/dialect/thegraph/tree.js +148 -0
  46. package/lib/dialect/thegraph/tree.js.map +1 -0
  47. package/lib/dialect/thegraph/where.d.ts +9 -0
  48. package/lib/dialect/thegraph/where.d.ts.map +1 -0
  49. package/lib/dialect/thegraph/where.js +188 -0
  50. package/lib/dialect/thegraph/where.js.map +1 -0
  51. package/lib/ir/args.d.ts +1 -1
  52. package/lib/ir/args.d.ts.map +1 -1
  53. package/lib/main.js +1 -1
  54. package/lib/main.js.map +1 -1
  55. package/lib/model.d.ts +2 -0
  56. package/lib/model.d.ts.map +1 -1
  57. package/lib/model.schema.d.ts.map +1 -1
  58. package/lib/model.schema.js +31 -2
  59. package/lib/model.schema.js.map +1 -1
  60. package/lib/server.d.ts +3 -1
  61. package/lib/server.d.ts.map +1 -1
  62. package/lib/server.js +7 -6
  63. package/lib/server.js.map +1 -1
  64. package/lib/sql/cursor.d.ts +2 -2
  65. package/lib/sql/cursor.d.ts.map +1 -1
  66. package/lib/sql/cursor.js +2 -2
  67. package/lib/sql/cursor.js.map +1 -1
  68. package/lib/sql/printer.d.ts +3 -3
  69. package/lib/sql/printer.d.ts.map +1 -1
  70. package/lib/sql/printer.js +17 -15
  71. package/lib/sql/printer.js.map +1 -1
  72. package/lib/sql/query.d.ts +5 -5
  73. package/lib/sql/query.d.ts.map +1 -1
  74. package/lib/sql/query.js.map +1 -1
  75. package/lib/sql/util.d.ts +2 -2
  76. package/lib/sql/util.d.ts.map +1 -1
  77. package/lib/sql/util.js.map +1 -1
  78. package/lib/test/basic.test.js +471 -229
  79. package/lib/test/basic.test.js.map +1 -1
  80. package/lib/test/isNull.test.js +87 -36
  81. package/lib/test/isNull.test.js.map +1 -1
  82. package/lib/test/limits.test.js +206 -94
  83. package/lib/test/limits.test.js.map +1 -1
  84. package/lib/test/lookup.test.js +184 -81
  85. package/lib/test/lookup.test.js.map +1 -1
  86. package/lib/test/setup.js +2 -2
  87. package/lib/test/setup.js.map +1 -1
  88. package/lib/test/where.test.js +216 -99
  89. package/lib/test/where.test.js.map +1 -1
  90. package/package.json +5 -3
  91. package/src/context.ts +2 -2
  92. package/src/db.ts +4 -2
  93. package/src/dialect/common.ts +49 -0
  94. package/src/dialect/index.ts +20 -0
  95. package/src/{opencrud → dialect/opencrud}/orderBy.ts +4 -21
  96. package/src/{opencrud → dialect/opencrud}/schema.ts +30 -55
  97. package/src/{opencrud → dialect/opencrud}/tree.ts +6 -7
  98. package/src/{opencrud → dialect/opencrud}/where.ts +4 -16
  99. package/src/dialect/thegraph/locale.ts +284 -0
  100. package/src/dialect/thegraph/orderBy.ts +75 -0
  101. package/src/dialect/thegraph/schema.ts +484 -0
  102. package/src/dialect/thegraph/tree.ts +162 -0
  103. package/src/dialect/thegraph/where.ts +184 -0
  104. package/src/ir/args.ts +2 -0
  105. package/src/main.ts +3 -3
  106. package/src/model.schema.ts +37 -4
  107. package/src/model.ts +2 -0
  108. package/src/server.ts +21 -19
  109. package/src/sql/cursor.ts +4 -4
  110. package/src/sql/printer.ts +22 -18
  111. package/src/sql/query.ts +5 -5
  112. package/src/sql/util.ts +2 -2
  113. package/src/test/basic.test.ts +570 -282
  114. package/src/test/isNull.test.ts +95 -38
  115. package/src/test/limits.test.ts +212 -91
  116. package/src/test/lookup.test.ts +190 -83
  117. package/src/test/setup.ts +2 -2
  118. package/src/test/where.test.ts +235 -108
  119. package/lib/dialect.d.ts +0 -2
  120. package/lib/dialect.d.ts.map +0 -1
  121. package/lib/dialect.js +0 -3
  122. package/lib/dialect.js.map +0 -1
  123. package/lib/opencrud/orderBy.d.ts.map +0 -1
  124. package/lib/opencrud/orderBy.js.map +0 -1
  125. package/lib/opencrud/schema.d.ts.map +0 -1
  126. package/lib/opencrud/schema.js.map +0 -1
  127. package/lib/opencrud/tree.d.ts.map +0 -1
  128. package/lib/opencrud/tree.js.map +0 -1
  129. package/lib/opencrud/where.d.ts.map +0 -1
  130. package/lib/opencrud/where.js.map +0 -1
  131. 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 {Dialect} from './dialect'
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: Dialect
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
- dialect: opts.dbType,
59
+ dbType: opts.dbType,
60
60
  connection,
61
61
  port: opts.port,
62
62
  log: LOG,
@@ -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] = {kind, properties, description, interfaces, indexes, ...cardinality}
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
@@ -10,6 +10,8 @@ export interface Entity extends TypeMeta {
10
10
  interfaces?: Name[]
11
11
  indexes?: Index[]
12
12
  cardinality?: number
13
+ queryName?: string
14
+ listQueryName?: string
13
15
  }
14
16
 
15
17
 
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 {Dialect} from './dialect'
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 dialect = options.dialect ?? 'postgres'
50
+ let dbType = options.dbType ?? 'postgres'
50
51
 
51
- let schema = new SchemaBuilder(options).build()
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
- dialect,
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
- port: options.port,
80
- schema,
81
- context,
82
- disposals,
83
- subscriptions: options.subscriptions,
84
- log: options.log,
85
- graphiqlConsole: options.graphiqlConsole,
86
- maxRequestSizeBytes: options.maxRequestSizeBytes,
87
- maxRootFields: options.maxRootFields,
88
- cache: options.cache,
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 {Dialect} from "../dialect"
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: 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 {
@@ -1,6 +1,6 @@
1
1
  import {unexpectedCase} from '@subsquid/util-internal'
2
2
  import assert from 'assert'
3
- import {Dialect} from '../dialect'
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: 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(lower(${this.param(where.value)}) in lower(${cursor.native(where.field)})) > 0`)
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(lower(${this.param(where.value)}) in lower(${cursor.native(where.field)})) = 0`)
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: 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 {Dialect} from '../dialect'
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: 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: 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: 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: 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 {Dialect} from "../dialect"
1
+ import type {DbType} from "../db"
2
2
 
3
3
 
4
- export function escapeIdentifier(dialect: Dialect, name: string): string {
4
+ export function escapeIdentifier(dialect: DbType, name: string): string {
5
5
  return `"${name.replace(/"/g, '""')}"`
6
6
  }
7
7