@subsquid/openreader 1.0.2 → 2.1.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 (295) hide show
  1. package/bin/main.js +1 -1
  2. package/lib/context.d.ts +14 -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 +8 -0
  27. package/lib/limit.size.d.ts.map +1 -0
  28. package/lib/limit.size.js +107 -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 +59 -0
  33. package/lib/main.js.map +1 -0
  34. package/{dist → lib}/model.d.ts +11 -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} +62 -8
  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 +527 -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 +42 -0
  83. package/lib/server.d.ts.map +1 -0
  84. package/lib/server.js +171 -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/lib/test/limits.test.d.ts +2 -0
  127. package/lib/test/limits.test.d.ts.map +1 -0
  128. package/lib/test/limits.test.js +159 -0
  129. package/lib/test/limits.test.js.map +1 -0
  130. package/{dist → lib}/test/lists.test.d.ts +0 -0
  131. package/{dist → lib}/test/lists.test.d.ts.map +0 -0
  132. package/{dist → lib}/test/lists.test.js +0 -0
  133. package/{dist → lib}/test/lists.test.js.map +0 -0
  134. package/{dist → lib}/test/lookup.test.d.ts +0 -0
  135. package/{dist → lib}/test/lookup.test.d.ts.map +0 -0
  136. package/{dist → lib}/test/lookup.test.js +0 -0
  137. package/{dist → lib}/test/lookup.test.js.map +0 -0
  138. package/{dist → lib}/test/regressions.test.d.ts +0 -0
  139. package/{dist → lib}/test/regressions.test.d.ts.map +0 -0
  140. package/{dist → lib}/test/regressions.test.js +0 -0
  141. package/{dist → lib}/test/regressions.test.js.map +0 -0
  142. package/{dist → lib}/test/scalars.test.d.ts +0 -0
  143. package/{dist → lib}/test/scalars.test.d.ts.map +0 -0
  144. package/{dist → lib}/test/scalars.test.js +0 -0
  145. package/{dist → lib}/test/scalars.test.js.map +0 -0
  146. package/lib/test/setup.d.ts +17 -0
  147. package/lib/test/setup.d.ts.map +1 -0
  148. package/{dist → lib}/test/setup.js +18 -13
  149. package/lib/test/setup.js.map +1 -0
  150. package/lib/test/subscription.test.d.ts +2 -0
  151. package/lib/test/subscription.test.d.ts.map +1 -0
  152. package/lib/test/subscription.test.js +99 -0
  153. package/lib/test/subscription.test.js.map +1 -0
  154. package/{dist → lib}/test/tools.test.d.ts +0 -0
  155. package/{dist → lib}/test/tools.test.d.ts.map +0 -0
  156. package/{dist → lib}/test/tools.test.js +0 -0
  157. package/{dist → lib}/test/tools.test.js.map +0 -0
  158. package/{dist → lib}/test/typed-json.test.d.ts +0 -0
  159. package/{dist → lib}/test/typed-json.test.d.ts.map +0 -0
  160. package/{dist → lib}/test/typed-json.test.js +0 -0
  161. package/{dist → lib}/test/typed-json.test.js.map +0 -0
  162. package/{dist → lib}/test/unions.test.d.ts +0 -0
  163. package/{dist → lib}/test/unions.test.d.ts.map +0 -0
  164. package/{dist → lib}/test/unions.test.js +0 -0
  165. package/{dist → lib}/test/unions.test.js.map +0 -0
  166. package/{dist → lib}/test/where.test.d.ts +0 -0
  167. package/{dist → lib}/test/where.test.d.ts.map +0 -0
  168. package/{dist → lib}/test/where.test.js +0 -0
  169. package/{dist → lib}/test/where.test.js.map +0 -0
  170. package/{dist → lib}/tools.d.ts +0 -0
  171. package/{dist → lib}/tools.d.ts.map +0 -0
  172. package/{dist → lib}/tools.js +3 -3
  173. package/{dist → lib}/tools.js.map +1 -1
  174. package/lib/util/error-handling.d.ts +11 -0
  175. package/lib/util/error-handling.d.ts.map +1 -0
  176. package/lib/util/error-handling.js +42 -0
  177. package/lib/util/error-handling.js.map +1 -0
  178. package/lib/util/execute.d.ts +5 -0
  179. package/lib/util/execute.d.ts.map +1 -0
  180. package/lib/util/execute.js +28 -0
  181. package/lib/util/execute.js.map +1 -0
  182. package/lib/util/lazy-transaction.d.ts +10 -0
  183. package/lib/util/lazy-transaction.d.ts.map +1 -0
  184. package/lib/util/lazy-transaction.js +43 -0
  185. package/lib/util/lazy-transaction.js.map +1 -0
  186. package/lib/util/limit.d.ts +11 -0
  187. package/lib/util/limit.d.ts.map +1 -0
  188. package/lib/util/limit.js +39 -0
  189. package/lib/util/limit.js.map +1 -0
  190. package/lib/util/resolve-tree.d.ts +14 -0
  191. package/lib/util/resolve-tree.d.ts.map +1 -0
  192. package/lib/util/resolve-tree.js +52 -0
  193. package/lib/util/resolve-tree.js.map +1 -0
  194. package/{dist → lib/util}/util.d.ts +2 -3
  195. package/lib/util/util.d.ts.map +1 -0
  196. package/{dist → lib/util}/util.js +9 -13
  197. package/lib/util/util.js.map +1 -0
  198. package/package.json +18 -10
  199. package/src/context.ts +17 -0
  200. package/src/db.ts +46 -57
  201. package/src/ir/args.ts +85 -0
  202. package/src/ir/connection.ts +48 -0
  203. package/src/ir/fields.ts +40 -0
  204. package/src/limit.size.ts +130 -0
  205. package/src/main.ts +74 -42
  206. package/src/{gql/schema.ts → model.schema.ts} +72 -9
  207. package/src/model.ts +13 -1
  208. package/src/{orderBy.ts → opencrud/orderBy.ts} +3 -10
  209. package/src/opencrud/schema.ts +639 -0
  210. package/src/opencrud/tree.ts +144 -0
  211. package/src/opencrud/where.ts +141 -0
  212. package/src/{gql/scalars → scalars}/BigInt.ts +1 -1
  213. package/src/{gql/scalars → scalars}/Bytes.ts +4 -4
  214. package/src/{gql/scalars → scalars}/DateTime.ts +1 -1
  215. package/src/{gql/scalars → scalars}/JSON.ts +0 -0
  216. package/src/{gql/scalars → scalars}/index.ts +0 -0
  217. package/src/server.ts +175 -55
  218. package/src/sql/cursor.ts +291 -0
  219. package/src/sql/mapping.ts +66 -0
  220. package/src/sql/printer.ts +328 -0
  221. package/src/sql/query.ts +194 -0
  222. package/src/sql/util.ts +89 -0
  223. package/src/subscription.ts +46 -0
  224. package/src/test/fts.test.ts +1 -1
  225. package/src/test/limits.test.ts +163 -0
  226. package/src/test/setup.ts +16 -11
  227. package/src/test/subscription.test.ts +98 -0
  228. package/src/tools.ts +1 -1
  229. package/src/util/error-handling.ts +40 -0
  230. package/src/util/execute.ts +53 -0
  231. package/src/util/lazy-transaction.ts +49 -0
  232. package/src/util/limit.ts +34 -0
  233. package/src/util/resolve-tree.ts +65 -0
  234. package/src/{util.ts → util/util.ts} +9 -14
  235. package/dist/db.d.ts +0 -28
  236. package/dist/db.d.ts.map +0 -1
  237. package/dist/db.js +0 -69
  238. package/dist/db.js.map +0 -1
  239. package/dist/gql/opencrud.d.ts +0 -6
  240. package/dist/gql/opencrud.d.ts.map +0 -1
  241. package/dist/gql/opencrud.js +0 -326
  242. package/dist/gql/opencrud.js.map +0 -1
  243. package/dist/gql/scalars/BigInt.d.ts.map +0 -1
  244. package/dist/gql/scalars/BigInt.js.map +0 -1
  245. package/dist/gql/scalars/Bytes.d.ts.map +0 -1
  246. package/dist/gql/scalars/Bytes.js.map +0 -1
  247. package/dist/gql/scalars/DateTime.d.ts.map +0 -1
  248. package/dist/gql/scalars/DateTime.js.map +0 -1
  249. package/dist/gql/scalars/JSON.d.ts.map +0 -1
  250. package/dist/gql/scalars/JSON.js.map +0 -1
  251. package/dist/gql/scalars/index.d.ts.map +0 -1
  252. package/dist/gql/scalars/index.js.map +0 -1
  253. package/dist/gql/schema.d.ts.map +0 -1
  254. package/dist/gql/schema.js.map +0 -1
  255. package/dist/main.js +0 -44
  256. package/dist/main.js.map +0 -1
  257. package/dist/model.d.ts.map +0 -1
  258. package/dist/orderBy.d.ts.map +0 -1
  259. package/dist/orderBy.js.map +0 -1
  260. package/dist/queryBuilder.d.ts +0 -56
  261. package/dist/queryBuilder.d.ts.map +0 -1
  262. package/dist/queryBuilder.js +0 -733
  263. package/dist/queryBuilder.js.map +0 -1
  264. package/dist/relayConnection.d.ts +0 -37
  265. package/dist/relayConnection.d.ts.map +0 -1
  266. package/dist/relayConnection.js +0 -43
  267. package/dist/relayConnection.js.map +0 -1
  268. package/dist/requestedFields.d.ts +0 -33
  269. package/dist/requestedFields.d.ts.map +0 -1
  270. package/dist/requestedFields.js +0 -179
  271. package/dist/requestedFields.js.map +0 -1
  272. package/dist/resolver.d.ts +0 -9
  273. package/dist/resolver.d.ts.map +0 -1
  274. package/dist/resolver.js +0 -158
  275. package/dist/resolver.js.map +0 -1
  276. package/dist/server.d.ts +0 -22
  277. package/dist/server.d.ts.map +0 -1
  278. package/dist/server.js +0 -96
  279. package/dist/server.js.map +0 -1
  280. package/dist/test/fts.test.js.map +0 -1
  281. package/dist/test/setup.d.ts +0 -14
  282. package/dist/test/setup.d.ts.map +0 -1
  283. package/dist/test/setup.js.map +0 -1
  284. package/dist/util.d.ts.map +0 -1
  285. package/dist/util.js.map +0 -1
  286. package/dist/where.d.ts +0 -9
  287. package/dist/where.d.ts.map +0 -1
  288. package/dist/where.js +0 -101
  289. package/dist/where.js.map +0 -1
  290. package/src/gql/opencrud.ts +0 -350
  291. package/src/queryBuilder.ts +0 -891
  292. package/src/relayConnection.ts +0 -80
  293. package/src/requestedFields.ts +0 -246
  294. package/src/resolver.ts +0 -201
  295. 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,175 @@
1
- import {ApolloServerPluginDrainHttpServer} from "apollo-server-core"
2
- import {ApolloServer} from "apollo-server-express"
3
- import assert from "assert"
4
- import express from "express"
5
- import fs from "fs"
6
- import http from "http"
7
- import path from "path"
8
- import type {Pool} from "pg"
9
- import {PoolTransaction} from "./db"
10
- import {Dialect} from "./dialect"
11
- import {buildServerSchema} from "./gql/opencrud"
12
- 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
- }
1
+ import type {Logger} from '@subsquid/logger'
2
+ import {listen, ListeningServer} from '@subsquid/util-internal-http-server'
3
+ import {PluginDefinition} from 'apollo-server-core'
4
+ import {ApolloServer} from 'apollo-server-express'
5
+ import express from 'express'
6
+ import fs from 'fs'
7
+ import {ExecutionArgs, GraphQLSchema} from 'graphql'
8
+ import {useServer as useWsServer} from 'graphql-ws/lib/use/ws'
9
+ import http from 'http'
10
+ import path from 'path'
11
+ import type {Pool} from 'pg'
12
+ import {WebSocketServer} from 'ws'
13
+ import {Context, OpenreaderContext} from './context'
14
+ import {PoolOpenreaderContext} from './db'
15
+ import type {Dialect} from './dialect'
16
+ import type {Model} from './model'
17
+ import {SchemaBuilder} from './opencrud/schema'
18
+ import {logGraphQLError} from './util/error-handling'
19
+ import {executeWithLimit} from './util/execute'
20
+ import {ResponseSizeLimit} from './util/limit'
20
21
 
21
22
 
22
23
  export interface ServerOptions {
23
- model: Model
24
- db: Pool
25
24
  port: number | string
25
+ model: Model
26
+ connection: Pool
26
27
  dialect?: Dialect
27
28
  graphiqlConsole?: boolean
29
+ log?: Logger
30
+ maxRequestSizeBytes?: number
31
+ maxRootFields?: number
32
+ maxResponseNodes?: number
33
+ subscriptions?: boolean
34
+ subscriptionPollInterval?: number
35
+ subscriptionConnection?: Pool
36
+ subscriptionMaxResponseNodes?: number
28
37
  }
29
38
 
30
39
 
31
40
  export async function serve(options: ServerOptions): Promise<ListeningServer> {
32
- let {model, db} = options
41
+ let {connection, subscriptionConnection, subscriptionPollInterval, maxResponseNodes, subscriptionMaxResponseNodes} = options
33
42
  let dialect = options.dialect ?? 'postgres'
34
- let resolvers = buildResolvers(model, dialect)
35
- let typeDefs = buildServerSchema(model, dialect)
43
+
44
+ let schema = new SchemaBuilder(options).build()
45
+
46
+ let context = () => {
47
+ let openreader: OpenreaderContext = new PoolOpenreaderContext(
48
+ dialect,
49
+ connection,
50
+ subscriptionConnection,
51
+ subscriptionPollInterval
52
+ )
53
+
54
+ if (maxResponseNodes) {
55
+ openreader.responseSizeLimit = new ResponseSizeLimit(maxResponseNodes)
56
+ openreader.subscriptionResponseSizeLimit = new ResponseSizeLimit(maxResponseNodes)
57
+ }
58
+
59
+ if (subscriptionMaxResponseNodes) {
60
+ openreader.subscriptionResponseSizeLimit = new ResponseSizeLimit(subscriptionMaxResponseNodes)
61
+ }
62
+
63
+ return {
64
+ openreader
65
+ }
66
+ }
67
+
68
+ let disposals: Dispose[] = []
69
+
70
+ return addServerCleanup(disposals, runApollo({
71
+ port: options.port,
72
+ schema,
73
+ context,
74
+ disposals,
75
+ subscriptions: options.subscriptions,
76
+ log: options.log,
77
+ graphiqlConsole: options.graphiqlConsole,
78
+ maxRequestSizeBytes: options.maxRequestSizeBytes,
79
+ maxRootFields: options.maxRootFields
80
+ }), options.log)
81
+ }
82
+
83
+
84
+ export type Dispose = () => Promise<void>
85
+
86
+
87
+ export interface ApolloOptions {
88
+ port: number | string
89
+ disposals: Dispose[]
90
+ context: () => Context
91
+ schema: GraphQLSchema
92
+ plugins?: PluginDefinition[]
93
+ subscriptions?: boolean
94
+ graphiqlConsole?: boolean
95
+ log?: Logger
96
+ maxRequestSizeBytes?: number
97
+ maxRootFields?: number
98
+ }
99
+
100
+
101
+ export async function runApollo(options: ApolloOptions): Promise<ListeningServer> {
102
+ const {disposals, context, schema, log, maxRootFields} = options
103
+
104
+ let maxRequestSizeBytes = options.maxRequestSizeBytes ?? 256 * 1024
36
105
  let app = express()
37
106
  let server = http.createServer(app)
38
107
 
108
+ const execute = maxRootFields
109
+ ? (args: ExecutionArgs) => executeWithLimit(maxRootFields, args)
110
+ : undefined
111
+
112
+ if (options.subscriptions) {
113
+ let wsServer = new WebSocketServer({
114
+ server,
115
+ path: '/graphql',
116
+ maxPayload: maxRequestSizeBytes
117
+ })
118
+ let wsServerCleanup = useWsServer(
119
+ {
120
+ schema,
121
+ context,
122
+ execute,
123
+ onError(ctx, message, errors) {
124
+ if (log) {
125
+ // FIXME: we don't want to log client errors
126
+ for (let err of errors) {
127
+ logGraphQLError(log, err)
128
+ }
129
+ }
130
+ },
131
+ onNext(_ctx, _message, args, result) {
132
+ args.contextValue.openreader.close()
133
+ return result
134
+ }
135
+ },
136
+ wsServer
137
+ )
138
+ disposals.push(async () => wsServerCleanup.dispose())
139
+ }
140
+
39
141
  let apollo = new ApolloServer({
40
- typeDefs,
41
- resolvers,
42
- context: () => ({openReaderTransaction: new PoolTransaction(db)}),
142
+ schema,
143
+ context,
144
+ stopOnTerminationSignals: false,
145
+ executor: execute && (async req => {
146
+ return execute({
147
+ schema,
148
+ document: req.document,
149
+ rootValue: {},
150
+ contextValue: req.context,
151
+ variableValues: req.request.variables,
152
+ operationName: req.operationName
153
+ })
154
+ }),
43
155
  plugins: [
156
+ ...options.plugins || [],
44
157
  {
45
158
  async requestDidStart() {
46
159
  return {
47
160
  willSendResponse(req: any) {
48
- return req.context.openReaderTransaction.close()
161
+ return req.context.openreader.close()
162
+ },
163
+ async didEncounterErrors(req) {
164
+ if (req.operation && log) {
165
+ for (let err of req.errors) {
166
+ logGraphQLError(log, err)
167
+ }
168
+ }
49
169
  }
50
170
  }
51
171
  }
52
- },
53
- ApolloServerPluginDrainHttpServer({httpServer: server})
172
+ }
54
173
  ]
55
174
  })
56
175
 
@@ -59,37 +178,38 @@ export async function serve(options: ServerOptions): Promise<ListeningServer> {
59
178
  }
60
179
 
61
180
  await apollo.start()
62
- apollo.applyMiddleware({app})
63
- return listen(apollo, server, options.port)
64
- }
65
-
181
+ disposals.push(() => apollo.stop())
66
182
 
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)
183
+ apollo.applyMiddleware({
184
+ app,
185
+ bodyParserConfig: {
186
+ limit: maxRequestSizeBytes
72
187
  }
188
+ })
73
189
 
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
- }
190
+ return listen(server, options.port)
191
+ }
83
192
 
84
- function cleanup() {
85
- server.removeListener('error', onerror)
86
- server.removeListener('listening', onlistening)
193
+
194
+ export function addServerCleanup(disposals: Dispose[], server: Promise<ListeningServer>, log?: Logger): Promise<ListeningServer> {
195
+ async function cleanup() {
196
+ for (let i = disposals.length - 1; i >= 0; i--) {
197
+ await disposals[i]().catch(err => log?.error(err))
87
198
  }
199
+ }
88
200
 
89
- server.on('error', onerror)
90
- server.on('listening', onlistening)
91
- server.listen(port)
92
- })
201
+ return server.then(
202
+ s => {
203
+ return {
204
+ port: s.port,
205
+ close: () => s.close().finally(cleanup)
206
+ }
207
+ },
208
+ async err => {
209
+ await cleanup()
210
+ throw err
211
+ }
212
+ )
93
213
  }
94
214
 
95
215