@subsquid/openreader 1.0.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. package/bin/main.js +2 -1
  2. package/lib/context.d.ts +11 -0
  3. package/lib/context.d.ts.map +1 -0
  4. package/lib/context.js +3 -0
  5. package/lib/context.js.map +1 -0
  6. package/lib/db.d.ts +23 -0
  7. package/lib/db.d.ts.map +1 -0
  8. package/lib/db.js +57 -0
  9. package/lib/db.js.map +1 -0
  10. package/{dist → lib}/dialect.d.ts +0 -0
  11. package/{dist → lib}/dialect.d.ts.map +0 -0
  12. package/{dist → lib}/dialect.js +0 -0
  13. package/{dist → lib}/dialect.js.map +0 -0
  14. package/lib/ir/args.d.ts +47 -0
  15. package/lib/ir/args.d.ts.map +1 -0
  16. package/lib/ir/args.js +3 -0
  17. package/lib/ir/args.js.map +1 -0
  18. package/lib/ir/connection.d.ts +30 -0
  19. package/lib/ir/connection.d.ts.map +1 -0
  20. package/lib/ir/connection.js +17 -0
  21. package/lib/ir/connection.js.map +1 -0
  22. package/lib/ir/fields.d.ts +22 -0
  23. package/lib/ir/fields.d.ts.map +1 -0
  24. package/lib/ir/fields.js +3 -0
  25. package/lib/ir/fields.js.map +1 -0
  26. package/lib/limit.size.d.ts +3 -0
  27. package/lib/limit.size.d.ts.map +1 -0
  28. package/lib/limit.size.js +44 -0
  29. package/lib/limit.size.js.map +1 -0
  30. package/{dist → lib}/main.d.ts +0 -0
  31. package/{dist → lib}/main.d.ts.map +0 -0
  32. package/lib/main.js +53 -0
  33. package/lib/main.js.map +1 -0
  34. package/{dist → lib}/model.d.ts +10 -1
  35. package/lib/model.d.ts.map +1 -0
  36. package/{dist → lib}/model.js +0 -0
  37. package/{dist → lib}/model.js.map +0 -0
  38. package/{dist/gql/schema.d.ts → lib/model.schema.d.ts} +2 -2
  39. package/lib/model.schema.d.ts.map +1 -0
  40. package/{dist/gql/schema.js → lib/model.schema.js} +44 -7
  41. package/lib/model.schema.js.map +1 -0
  42. package/{dist → lib}/model.tools.d.ts +0 -0
  43. package/{dist → lib}/model.tools.d.ts.map +0 -0
  44. package/{dist → lib}/model.tools.js +0 -0
  45. package/{dist → lib}/model.tools.js.map +0 -0
  46. package/{dist → lib/opencrud}/orderBy.d.ts +2 -5
  47. package/lib/opencrud/orderBy.d.ts.map +1 -0
  48. package/{dist → lib/opencrud}/orderBy.js +1 -1
  49. package/lib/opencrud/orderBy.js.map +1 -0
  50. package/lib/opencrud/schema.d.ts +31 -0
  51. package/lib/opencrud/schema.d.ts.map +1 -0
  52. package/lib/opencrud/schema.js +522 -0
  53. package/lib/opencrud/schema.js.map +1 -0
  54. package/lib/opencrud/tree.d.ts +8 -0
  55. package/lib/opencrud/tree.d.ts.map +1 -0
  56. package/lib/opencrud/tree.js +131 -0
  57. package/lib/opencrud/tree.js.map +1 -0
  58. package/lib/opencrud/where.d.ts +7 -0
  59. package/lib/opencrud/where.d.ts.map +1 -0
  60. package/lib/opencrud/where.js +141 -0
  61. package/lib/opencrud/where.js.map +1 -0
  62. package/{dist/gql → lib}/scalars/BigInt.d.ts +0 -0
  63. package/lib/scalars/BigInt.d.ts.map +1 -0
  64. package/{dist/gql → lib}/scalars/BigInt.js +1 -1
  65. package/lib/scalars/BigInt.js.map +1 -0
  66. package/{dist/gql → lib}/scalars/Bytes.d.ts +0 -0
  67. package/lib/scalars/Bytes.d.ts.map +1 -0
  68. package/{dist/gql → lib}/scalars/Bytes.js +2 -2
  69. package/lib/scalars/Bytes.js.map +1 -0
  70. package/{dist/gql → lib}/scalars/DateTime.d.ts +0 -0
  71. package/lib/scalars/DateTime.d.ts.map +1 -0
  72. package/{dist/gql → lib}/scalars/DateTime.js +1 -1
  73. package/lib/scalars/DateTime.js.map +1 -0
  74. package/{dist/gql → lib}/scalars/JSON.d.ts +0 -0
  75. package/lib/scalars/JSON.d.ts.map +1 -0
  76. package/{dist/gql → lib}/scalars/JSON.js +0 -0
  77. package/lib/scalars/JSON.js.map +1 -0
  78. package/{dist/gql → lib}/scalars/index.d.ts +0 -0
  79. package/lib/scalars/index.d.ts.map +1 -0
  80. package/{dist/gql → lib}/scalars/index.js +0 -0
  81. package/lib/scalars/index.js.map +1 -0
  82. package/lib/server.d.ts +38 -0
  83. package/lib/server.d.ts.map +1 -0
  84. package/lib/server.js +146 -0
  85. package/lib/server.js.map +1 -0
  86. package/lib/sql/cursor.d.ts +52 -0
  87. package/lib/sql/cursor.d.ts.map +1 -0
  88. package/lib/sql/cursor.js +234 -0
  89. package/lib/sql/cursor.js.map +1 -0
  90. package/lib/sql/mapping.d.ts +4 -0
  91. package/lib/sql/mapping.d.ts.map +1 -0
  92. package/lib/sql/mapping.js +71 -0
  93. package/lib/sql/mapping.js.map +1 -0
  94. package/lib/sql/printer.d.ts +37 -0
  95. package/lib/sql/printer.d.ts.map +1 -0
  96. package/lib/sql/printer.js +311 -0
  97. package/lib/sql/printer.js.map +1 -0
  98. package/lib/sql/query.d.ts +46 -0
  99. package/lib/sql/query.d.ts.map +1 -0
  100. package/lib/sql/query.js +134 -0
  101. package/lib/sql/query.js.map +1 -0
  102. package/lib/sql/util.d.ts +30 -0
  103. package/lib/sql/util.d.ts.map +1 -0
  104. package/lib/sql/util.js +75 -0
  105. package/lib/sql/util.js.map +1 -0
  106. package/lib/subscription.d.ts +18 -0
  107. package/lib/subscription.d.ts.map +1 -0
  108. package/lib/subscription.js +47 -0
  109. package/lib/subscription.js.map +1 -0
  110. package/{dist → lib}/test/basic.test.d.ts +0 -0
  111. package/{dist → lib}/test/basic.test.d.ts.map +0 -0
  112. package/{dist → lib}/test/basic.test.js +0 -0
  113. package/{dist → lib}/test/basic.test.js.map +0 -0
  114. package/{dist → lib}/test/connection.test.d.ts +0 -0
  115. package/{dist → lib}/test/connection.test.d.ts.map +0 -0
  116. package/{dist → lib}/test/connection.test.js +0 -0
  117. package/{dist → lib}/test/connection.test.js.map +0 -0
  118. package/{dist → lib}/test/fts.test.d.ts +0 -0
  119. package/{dist → lib}/test/fts.test.d.ts.map +0 -0
  120. package/{dist → lib}/test/fts.test.js +1 -1
  121. package/lib/test/fts.test.js.map +1 -0
  122. package/{dist → lib}/test/isNull.test.d.ts +0 -0
  123. package/{dist → lib}/test/isNull.test.d.ts.map +0 -0
  124. package/{dist → lib}/test/isNull.test.js +0 -0
  125. package/{dist → lib}/test/isNull.test.js.map +0 -0
  126. package/{dist → lib}/test/lists.test.d.ts +0 -0
  127. package/{dist → lib}/test/lists.test.d.ts.map +0 -0
  128. package/{dist → lib}/test/lists.test.js +0 -0
  129. package/{dist → lib}/test/lists.test.js.map +0 -0
  130. package/{dist → lib}/test/lookup.test.d.ts +0 -0
  131. package/{dist → lib}/test/lookup.test.d.ts.map +0 -0
  132. package/{dist → lib}/test/lookup.test.js +0 -0
  133. package/{dist → lib}/test/lookup.test.js.map +0 -0
  134. package/{dist → lib}/test/regressions.test.d.ts +0 -0
  135. package/{dist → lib}/test/regressions.test.d.ts.map +0 -0
  136. package/{dist → lib}/test/regressions.test.js +0 -0
  137. package/{dist → lib}/test/regressions.test.js.map +0 -0
  138. package/{dist → lib}/test/scalars.test.d.ts +0 -0
  139. package/{dist → lib}/test/scalars.test.d.ts.map +0 -0
  140. package/{dist → lib}/test/scalars.test.js +0 -0
  141. package/{dist → lib}/test/scalars.test.js.map +0 -0
  142. package/{dist → lib}/test/setup.d.ts +3 -1
  143. package/lib/test/setup.d.ts.map +1 -0
  144. package/{dist → lib}/test/setup.js +14 -12
  145. package/lib/test/setup.js.map +1 -0
  146. package/lib/test/subscription.test.d.ts +2 -0
  147. package/lib/test/subscription.test.d.ts.map +1 -0
  148. package/lib/test/subscription.test.js +99 -0
  149. package/lib/test/subscription.test.js.map +1 -0
  150. package/{dist → lib}/test/tools.test.d.ts +0 -0
  151. package/{dist → lib}/test/tools.test.d.ts.map +0 -0
  152. package/{dist → lib}/test/tools.test.js +0 -0
  153. package/{dist → lib}/test/tools.test.js.map +0 -0
  154. package/{dist → lib}/test/typed-json.test.d.ts +0 -0
  155. package/{dist → lib}/test/typed-json.test.d.ts.map +0 -0
  156. package/{dist → lib}/test/typed-json.test.js +0 -0
  157. package/{dist → lib}/test/typed-json.test.js.map +0 -0
  158. package/{dist → lib}/test/unions.test.d.ts +0 -0
  159. package/{dist → lib}/test/unions.test.d.ts.map +0 -0
  160. package/{dist → lib}/test/unions.test.js +0 -0
  161. package/{dist → lib}/test/unions.test.js.map +0 -0
  162. package/{dist → lib}/test/where.test.d.ts +0 -0
  163. package/{dist → lib}/test/where.test.d.ts.map +0 -0
  164. package/{dist → lib}/test/where.test.js +0 -0
  165. package/{dist → lib}/test/where.test.js.map +0 -0
  166. package/{dist → lib}/tools.d.ts +0 -0
  167. package/{dist → lib}/tools.d.ts.map +0 -0
  168. package/{dist → lib}/tools.js +3 -3
  169. package/{dist → lib}/tools.js.map +1 -1
  170. package/lib/util/error-handling.d.ts +11 -0
  171. package/lib/util/error-handling.d.ts.map +1 -0
  172. package/lib/util/error-handling.js +42 -0
  173. package/lib/util/error-handling.js.map +1 -0
  174. package/lib/util/lazy-transaction.d.ts +10 -0
  175. package/lib/util/lazy-transaction.d.ts.map +1 -0
  176. package/lib/util/lazy-transaction.js +43 -0
  177. package/lib/util/lazy-transaction.js.map +1 -0
  178. package/lib/util/resolve-tree.d.ts +14 -0
  179. package/lib/util/resolve-tree.d.ts.map +1 -0
  180. package/lib/util/resolve-tree.js +52 -0
  181. package/lib/util/resolve-tree.js.map +1 -0
  182. package/{dist → lib/util}/util.d.ts +2 -3
  183. package/lib/util/util.d.ts.map +1 -0
  184. package/{dist → lib/util}/util.js +9 -13
  185. package/lib/util/util.js.map +1 -0
  186. package/package.json +17 -9
  187. package/src/context.ts +14 -0
  188. package/src/db.ts +46 -57
  189. package/src/ir/args.ts +85 -0
  190. package/src/ir/connection.ts +48 -0
  191. package/src/ir/fields.ts +40 -0
  192. package/src/limit.size.ts +46 -0
  193. package/src/main.ts +62 -37
  194. package/src/{gql/schema.ts → model.schema.ts} +51 -8
  195. package/src/model.ts +12 -1
  196. package/src/{orderBy.ts → opencrud/orderBy.ts} +3 -10
  197. package/src/opencrud/schema.ts +632 -0
  198. package/src/opencrud/tree.ts +144 -0
  199. package/src/opencrud/where.ts +141 -0
  200. package/src/{gql/scalars → scalars}/BigInt.ts +1 -1
  201. package/src/{gql/scalars → scalars}/Bytes.ts +4 -4
  202. package/src/{gql/scalars → scalars}/DateTime.ts +1 -1
  203. package/src/{gql/scalars → scalars}/JSON.ts +0 -0
  204. package/src/{gql/scalars → scalars}/index.ts +0 -0
  205. package/src/server.ts +128 -48
  206. package/src/sql/cursor.ts +291 -0
  207. package/src/sql/mapping.ts +66 -0
  208. package/src/sql/printer.ts +328 -0
  209. package/src/sql/query.ts +194 -0
  210. package/src/sql/util.ts +89 -0
  211. package/src/subscription.ts +46 -0
  212. package/src/test/fts.test.ts +1 -1
  213. package/src/test/setup.ts +12 -10
  214. package/src/test/subscription.test.ts +98 -0
  215. package/src/tools.ts +1 -1
  216. package/src/util/error-handling.ts +40 -0
  217. package/src/util/lazy-transaction.ts +49 -0
  218. package/src/util/resolve-tree.ts +65 -0
  219. package/src/{util.ts → util/util.ts} +9 -14
  220. package/dist/db.d.ts +0 -28
  221. package/dist/db.d.ts.map +0 -1
  222. package/dist/db.js +0 -69
  223. package/dist/db.js.map +0 -1
  224. package/dist/gql/opencrud.d.ts +0 -6
  225. package/dist/gql/opencrud.d.ts.map +0 -1
  226. package/dist/gql/opencrud.js +0 -326
  227. package/dist/gql/opencrud.js.map +0 -1
  228. package/dist/gql/scalars/BigInt.d.ts.map +0 -1
  229. package/dist/gql/scalars/BigInt.js.map +0 -1
  230. package/dist/gql/scalars/Bytes.d.ts.map +0 -1
  231. package/dist/gql/scalars/Bytes.js.map +0 -1
  232. package/dist/gql/scalars/DateTime.d.ts.map +0 -1
  233. package/dist/gql/scalars/DateTime.js.map +0 -1
  234. package/dist/gql/scalars/JSON.d.ts.map +0 -1
  235. package/dist/gql/scalars/JSON.js.map +0 -1
  236. package/dist/gql/scalars/index.d.ts.map +0 -1
  237. package/dist/gql/scalars/index.js.map +0 -1
  238. package/dist/gql/schema.d.ts.map +0 -1
  239. package/dist/gql/schema.js.map +0 -1
  240. package/dist/main.js +0 -43
  241. package/dist/main.js.map +0 -1
  242. package/dist/model.d.ts.map +0 -1
  243. package/dist/orderBy.d.ts.map +0 -1
  244. package/dist/orderBy.js.map +0 -1
  245. package/dist/queryBuilder.d.ts +0 -56
  246. package/dist/queryBuilder.d.ts.map +0 -1
  247. package/dist/queryBuilder.js +0 -733
  248. package/dist/queryBuilder.js.map +0 -1
  249. package/dist/relayConnection.d.ts +0 -37
  250. package/dist/relayConnection.d.ts.map +0 -1
  251. package/dist/relayConnection.js +0 -43
  252. package/dist/relayConnection.js.map +0 -1
  253. package/dist/requestedFields.d.ts +0 -33
  254. package/dist/requestedFields.d.ts.map +0 -1
  255. package/dist/requestedFields.js +0 -179
  256. package/dist/requestedFields.js.map +0 -1
  257. package/dist/resolver.d.ts +0 -9
  258. package/dist/resolver.d.ts.map +0 -1
  259. package/dist/resolver.js +0 -158
  260. package/dist/resolver.js.map +0 -1
  261. package/dist/server.d.ts +0 -22
  262. package/dist/server.d.ts.map +0 -1
  263. package/dist/server.js +0 -96
  264. package/dist/server.js.map +0 -1
  265. package/dist/test/fts.test.js.map +0 -1
  266. package/dist/test/setup.d.ts.map +0 -1
  267. package/dist/test/setup.js.map +0 -1
  268. package/dist/util.d.ts.map +0 -1
  269. package/dist/util.js.map +0 -1
  270. package/dist/where.d.ts +0 -9
  271. package/dist/where.d.ts.map +0 -1
  272. package/dist/where.js +0 -101
  273. package/dist/where.js.map +0 -1
  274. package/src/gql/opencrud.ts +0 -350
  275. package/src/queryBuilder.ts +0 -891
  276. package/src/relayConnection.ts +0 -80
  277. package/src/requestedFields.ts +0 -246
  278. package/src/resolver.ts +0 -201
  279. package/src/where.ts +0 -119
@@ -0,0 +1,144 @@
1
+ import {unexpectedCase} from "@subsquid/util-internal"
2
+ import assert from "assert"
3
+ import {GraphQLSchema} from "graphql"
4
+ import {ResolveTree} from "graphql-parse-resolve-info"
5
+ import {EntityListArguments} from "../ir/args"
6
+ import {FieldRequest, OpaqueRequest} from "../ir/fields"
7
+ import {Model} from "../model"
8
+ import {simplifyResolveTree} from "../util/resolve-tree"
9
+ import {ensureArray} from "../util/util"
10
+ import {parseOrderBy} from "./orderBy"
11
+ import {parseWhere} from "./where"
12
+
13
+
14
+ export function parseResolveTree(
15
+ model: Model,
16
+ objectName: string,
17
+ schema: GraphQLSchema,
18
+ tree: ResolveTree
19
+ ): FieldRequest[] {
20
+
21
+ let requests: FieldRequest[] = []
22
+ let requestedScalars: Record<string, true> = {}
23
+ let object = model[objectName]
24
+ assert(object.kind == "entity" || object.kind == "object")
25
+
26
+ let fields = simplifyResolveTree(schema, tree, objectName).fields
27
+ for (let alias in fields) {
28
+ let f = fields[alias]
29
+ let prop = object.properties[f.name]
30
+ switch(prop.type.kind) {
31
+ case "scalar":
32
+ case "enum":
33
+ case "list":
34
+ if (requestedScalars[f.name] == null) {
35
+ requestedScalars[f.name] = true
36
+ requests.push({
37
+ field: f.name,
38
+ aliases: [f.name],
39
+ kind: prop.type.kind,
40
+ type: prop.type,
41
+ prop,
42
+ index: 0
43
+ } as OpaqueRequest)
44
+ }
45
+ break
46
+ case "object":
47
+ requests.push({
48
+ field: f.name,
49
+ aliases: [f.alias],
50
+ kind: prop.type.kind,
51
+ type: prop.type,
52
+ prop,
53
+ index: 0,
54
+ children: parseResolveTree(model, prop.type.name, schema, f)
55
+ })
56
+ break
57
+ case "union": {
58
+ let union = model[prop.type.name]
59
+ assert(union.kind == "union")
60
+ let children: FieldRequest[] = []
61
+ for (let variant of union.variants) {
62
+ for (let req of parseResolveTree(model, variant, schema, f)) {
63
+ req.ifType = variant
64
+ children.push(req)
65
+ }
66
+ }
67
+ requests.push({
68
+ field: f.name,
69
+ aliases: [f.alias],
70
+ kind: prop.type.kind,
71
+ type: prop.type,
72
+ prop,
73
+ index: 0,
74
+ children
75
+ })
76
+ break
77
+ }
78
+ case "fk":
79
+ requests.push({
80
+ field: f.name,
81
+ aliases: [f.alias],
82
+ kind: prop.type.kind,
83
+ type: prop.type,
84
+ prop,
85
+ index: 0,
86
+ children: parseResolveTree(model, prop.type.foreignEntity, schema, f)
87
+ })
88
+ break
89
+ case "lookup":
90
+ requests.push({
91
+ field: f.name,
92
+ aliases: [f.alias],
93
+ kind: prop.type.kind,
94
+ type: prop.type,
95
+ prop,
96
+ index: 0,
97
+ children: parseResolveTree(model, prop.type.entity, schema, f)
98
+ })
99
+ break
100
+ case "list-lookup":
101
+ requests.push({
102
+ field: f.name,
103
+ aliases: [f.alias],
104
+ kind: prop.type.kind,
105
+ type: prop.type,
106
+ prop,
107
+ index: 0,
108
+ args: parseEntityListArguments(model, prop.type.entity, f.args),
109
+ children: parseResolveTree(model, prop.type.entity, schema, f)
110
+ })
111
+ break
112
+ default:
113
+ throw unexpectedCase()
114
+ }
115
+ }
116
+
117
+ return requests
118
+ }
119
+
120
+
121
+ export function parseEntityListArguments(model: Model, entityName: string, gqlArgs: any): EntityListArguments {
122
+ let args: EntityListArguments = {}
123
+
124
+ let where = parseWhere(gqlArgs.where)
125
+ if (where) {
126
+ args.where = where
127
+ }
128
+
129
+ if (gqlArgs.orderBy) {
130
+ args.orderBy = parseOrderBy(model, entityName, ensureArray(gqlArgs.orderBy))
131
+ }
132
+
133
+ if (gqlArgs.offset) {
134
+ assert(typeof gqlArgs.offset == "number")
135
+ args.offset = gqlArgs.offset
136
+ }
137
+
138
+ if (gqlArgs.limit != null) {
139
+ assert(typeof gqlArgs.limit == "number")
140
+ args.limit = gqlArgs.limit
141
+ }
142
+
143
+ return args
144
+ }
@@ -0,0 +1,141 @@
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
+
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 "REF":
17
+ case "every": {
18
+ let where = parseWhere(arg)
19
+ where && conj.push({op, field, where})
20
+ break
21
+ }
22
+ case "some":
23
+ case "none":
24
+ conj.push({op, field, where: parseWhere(arg)})
25
+ break
26
+ case "in":
27
+ case "not_in":
28
+ conj.push({op, field, values: ensureArray(arg)})
29
+ break
30
+ case "eq":
31
+ case "not_eq":
32
+ case "gt":
33
+ case "gte":
34
+ case "lt":
35
+ case "lte":
36
+ case "contains":
37
+ case "not_contains":
38
+ case "containsInsensitive":
39
+ case "not_containsInsensitive":
40
+ case "startsWith":
41
+ case "not_startsWith":
42
+ case "endsWith":
43
+ case "not_endsWith":
44
+ case "jsonHasKey":
45
+ case "jsonContains":
46
+ conj.push({op, field, value: arg})
47
+ break
48
+ case "containsNone":
49
+ case "containsAll":
50
+ case "containsAny":
51
+ conj.push({op, field, value: ensureArray(arg)})
52
+ break
53
+ case "isNull":
54
+ assert(typeof arg == 'boolean')
55
+ conj.push({op, field, yes: arg})
56
+ break
57
+ default:
58
+ throw unexpectedCase(op)
59
+ }
60
+ }
61
+
62
+ if (AND) {
63
+ for (let arg of ensureArray(AND)) {
64
+ let where = parseWhere(arg)
65
+ if (where) {
66
+ conj.push(where)
67
+ }
68
+ }
69
+ }
70
+
71
+ let conjunction = toCondition('AND', conj)
72
+ if (OR) {
73
+ let disjunctions: Where[] = []
74
+ if (conjunction) {
75
+ disjunctions.push(conjunction)
76
+ }
77
+ for (let arg of ensureArray(OR)) {
78
+ let where = parseWhere(arg)
79
+ if (where) {
80
+ disjunctions.push(where)
81
+ }
82
+ }
83
+ return toCondition('OR', disjunctions)
84
+ } else {
85
+ return conjunction
86
+ }
87
+ }
88
+
89
+
90
+ function toCondition(op: 'AND' | 'OR', operands: Where[]): Where | undefined {
91
+ switch(operands.length) {
92
+ case 0:
93
+ return undefined
94
+ case 1:
95
+ return operands[0]
96
+ default:
97
+ return {op, args: operands}
98
+ }
99
+ }
100
+
101
+
102
+ export function parseWhereKey(key: string): {op: Where['op'], field: string} {
103
+ let m = WHERE_KEY_REGEX.exec(key)
104
+ if (m) {
105
+ return {op: m[2] as Where['op'], field: m[1]}
106
+ } else {
107
+ return {op: 'REF', field: key}
108
+ }
109
+ }
110
+
111
+
112
+ const WHERE_KEY_REGEX = (() => {
113
+ let ops: Where['op'][] = [
114
+ "eq",
115
+ "not_eq",
116
+ "gt",
117
+ "gte",
118
+ "lt",
119
+ "lte",
120
+ "contains",
121
+ "not_contains",
122
+ "containsInsensitive",
123
+ "not_containsInsensitive",
124
+ "startsWith",
125
+ "not_startsWith",
126
+ "endsWith",
127
+ "not_endsWith",
128
+ "containsAll",
129
+ "containsAny",
130
+ "containsNone",
131
+ "jsonContains",
132
+ "jsonHasKey",
133
+ "isNull",
134
+ "some",
135
+ "every",
136
+ "none",
137
+ "in",
138
+ "not_in",
139
+ ]
140
+ return new RegExp(`^([^_]*)_(${ops.join('|')})$`)
141
+ })()
@@ -1,5 +1,5 @@
1
1
  import {GraphQLScalarType} from "graphql"
2
- import {invalidFormat} from "../../util"
2
+ import {invalidFormat} from "../util/util"
3
3
 
4
4
 
5
5
  export const BigIntScalar = new GraphQLScalarType({
@@ -1,17 +1,17 @@
1
- import {decodeHex, isHex} from "@subsquid/util-internal-hex"
1
+ import {decodeHex, isHex, toHex} from "@subsquid/util-internal-hex"
2
2
  import {GraphQLScalarType} from "graphql"
3
- import {invalidFormat} from "../../util"
3
+ import {invalidFormat} from "../util/util"
4
4
 
5
5
 
6
6
  export const BytesScalar = new GraphQLScalarType({
7
7
  name: 'Bytes',
8
8
  description: 'Binary data encoded as a hex string always prefixed with 0x',
9
- serialize(value: string | Buffer) {
9
+ serialize(value: string | Uint8Array) {
10
10
  if (typeof value == 'string') {
11
11
  if (!isHex(value)) throw invalidFormat('Bytes', value)
12
12
  return value.toLowerCase()
13
13
  } else {
14
- return '0x' + value.toString('hex')
14
+ return toHex(value)
15
15
  }
16
16
  },
17
17
  parseValue(value: string) {
@@ -1,5 +1,5 @@
1
1
  import {GraphQLScalarType} from "graphql"
2
- import {invalidFormat} from "../../util"
2
+ import {invalidFormat} from "../util/util"
3
3
 
4
4
 
5
5
  export const DateTimeScalar = new GraphQLScalarType({
File without changes
File without changes
package/src/server.ts CHANGED
@@ -1,56 +1,134 @@
1
- import {ApolloServerPluginDrainHttpServer} from "apollo-server-core"
1
+ import type {Logger} from "@subsquid/logger"
2
+ import {listen, ListeningServer} from "@subsquid/util-internal-http-server"
3
+ import {PluginDefinition} from "apollo-server-core"
2
4
  import {ApolloServer} from "apollo-server-express"
3
- import assert from "assert"
4
5
  import express from "express"
5
6
  import fs from "fs"
7
+ import {GraphQLSchema} from "graphql"
8
+ import {useServer as useWsServer} from "graphql-ws/lib/use/ws"
6
9
  import http from "http"
7
10
  import path from "path"
8
11
  import type {Pool} from "pg"
9
- import {PoolTransaction} from "./db"
10
- import {Dialect} from "./dialect"
11
- import {buildServerSchema} from "./gql/opencrud"
12
+ import {WebSocketServer} from "ws"
13
+ import {Context} from "./context"
14
+ import {PoolOpenreaderContext} from "./db"
15
+ import type {Dialect} from "./dialect"
12
16
  import type {Model} from "./model"
13
- import {buildResolvers} from "./resolver"
14
-
15
-
16
- export interface ListeningServer {
17
- readonly port: number
18
- stop(): Promise<void>
19
- }
17
+ import {SchemaBuilder} from "./opencrud/schema"
18
+ import {logGraphQLError} from "./util/error-handling"
20
19
 
21
20
 
22
21
  export interface ServerOptions {
23
- model: Model
24
- db: Pool
25
22
  port: number | string
23
+ model: Model
24
+ connection: Pool
26
25
  dialect?: Dialect
26
+ subscriptions?: boolean
27
+ subscriptionPollInterval?: number
28
+ subscriptionConnection?: Pool
27
29
  graphiqlConsole?: boolean
30
+ log?: Logger
31
+ maxRequestSizeBytes?: number
28
32
  }
29
33
 
30
34
 
31
35
  export async function serve(options: ServerOptions): Promise<ListeningServer> {
32
- let {model, db} = options
36
+ let {connection, subscriptionConnection, subscriptionPollInterval} = options
33
37
  let dialect = options.dialect ?? 'postgres'
34
- let resolvers = buildResolvers(model, dialect)
35
- let typeDefs = buildServerSchema(model, dialect)
38
+
39
+ let schema = new SchemaBuilder(options).build()
40
+ let context = () => {
41
+ return {
42
+ openreader: new PoolOpenreaderContext(dialect, connection, subscriptionConnection, subscriptionPollInterval)
43
+ }
44
+ }
45
+ let disposals: Dispose[] = []
46
+
47
+ return addServerCleanup(disposals, runApollo({
48
+ port: options.port,
49
+ schema,
50
+ context,
51
+ disposals,
52
+ subscriptions: options.subscriptions,
53
+ log: options.log,
54
+ graphiqlConsole: options.graphiqlConsole,
55
+ maxRequestSizeBytes: options.maxRequestSizeBytes
56
+ }), options.log)
57
+ }
58
+
59
+
60
+ export type Dispose = () => Promise<void>
61
+
62
+
63
+ export interface ApolloOptions {
64
+ port: number | string
65
+ disposals: Dispose[]
66
+ context: () => Context
67
+ schema: GraphQLSchema
68
+ plugins?: PluginDefinition[]
69
+ subscriptions?: boolean
70
+ graphiqlConsole?: boolean
71
+ log?: Logger
72
+ maxRequestSizeBytes?: number
73
+ }
74
+
75
+
76
+ export async function runApollo(options: ApolloOptions): Promise<ListeningServer> {
77
+ let {disposals, context, schema, log} = options
78
+ let maxRequestSizeBytes = options.maxRequestSizeBytes ?? 256 * 1024
36
79
  let app = express()
37
80
  let server = http.createServer(app)
38
81
 
82
+ if (options.subscriptions) {
83
+ let wsServer = new WebSocketServer({
84
+ server,
85
+ path: '/graphql',
86
+ maxPayload: maxRequestSizeBytes
87
+ })
88
+ let wsServerCleanup = useWsServer(
89
+ {
90
+ schema,
91
+ context,
92
+ onError(ctx, message, errors) {
93
+ if (log) {
94
+ // FIXME: we don't want to log client errors
95
+ for (let err of errors) {
96
+ logGraphQLError(log, err)
97
+ }
98
+ }
99
+ },
100
+ onNext(_ctx, _message, args, result) {
101
+ args.contextValue.openreader.close()
102
+ return result
103
+ }
104
+ },
105
+ wsServer
106
+ )
107
+ disposals.push(async () => wsServerCleanup.dispose())
108
+ }
109
+
39
110
  let apollo = new ApolloServer({
40
- typeDefs,
41
- resolvers,
42
- context: () => ({openReaderTransaction: new PoolTransaction(db)}),
111
+ schema,
112
+ context,
113
+ stopOnTerminationSignals: false,
43
114
  plugins: [
115
+ ...options.plugins || [],
44
116
  {
45
117
  async requestDidStart() {
46
118
  return {
47
119
  willSendResponse(req: any) {
48
- return req.context.openReaderTransaction.close()
120
+ return req.context.openreader.close()
121
+ },
122
+ async didEncounterErrors(req) {
123
+ if (req.operation && log) {
124
+ for (let err of req.errors) {
125
+ logGraphQLError(log, err)
126
+ }
127
+ }
49
128
  }
50
129
  }
51
130
  }
52
- },
53
- ApolloServerPluginDrainHttpServer({httpServer: server})
131
+ }
54
132
  ]
55
133
  })
56
134
 
@@ -58,38 +136,40 @@ export async function serve(options: ServerOptions): Promise<ListeningServer> {
58
136
  setupGraphiqlConsole(app)
59
137
  }
60
138
 
61
- await apollo.start()
62
- apollo.applyMiddleware({app})
63
- return listen(apollo, server, options.port)
64
- }
65
139
 
140
+ await apollo.start()
141
+ disposals.push(() => apollo.stop())
66
142
 
67
- export function listen(apollo: ApolloServer, server: http.Server, port: number | string): Promise<ListeningServer> {
68
- return new Promise((resolve, reject) => {
69
- function onerror(err: Error) {
70
- cleanup()
71
- reject(err)
143
+ apollo.applyMiddleware({
144
+ app,
145
+ bodyParserConfig: {
146
+ limit: maxRequestSizeBytes
72
147
  }
148
+ })
149
+
150
+ return listen(server, options.port)
151
+ }
73
152
 
74
- function onlistening() {
75
- cleanup()
76
- let address = server.address()
77
- assert(address != null && typeof address == 'object')
78
- resolve({
79
- port: address.port,
80
- stop: () => apollo.stop()
81
- })
82
- }
83
153
 
84
- function cleanup() {
85
- server.removeListener('error', onerror)
86
- server.removeListener('listening', onlistening)
154
+ export function addServerCleanup(disposals: Dispose[], server: Promise<ListeningServer>, log?: Logger): Promise<ListeningServer> {
155
+ async function cleanup() {
156
+ for (let i = disposals.length - 1; i >= 0; i--) {
157
+ await disposals[i]().catch(err => log?.error(err))
87
158
  }
159
+ }
88
160
 
89
- server.on('error', onerror)
90
- server.on('listening', onlistening)
91
- server.listen(port)
92
- })
161
+ return server.then(
162
+ s => {
163
+ return {
164
+ port: s.port,
165
+ close: () => s.close().finally(cleanup)
166
+ }
167
+ },
168
+ async err => {
169
+ await cleanup()
170
+ throw err
171
+ }
172
+ )
93
173
  }
94
174
 
95
175