@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,639 @@
1
+ import {def, unexpectedCase} from "@subsquid/util-internal"
2
+ import {toCamelCase, toPlural} from "@subsquid/util-naming"
3
+ import {UserInputError} from "apollo-server-core"
4
+ import assert from "assert"
5
+ import {
6
+ GraphQLBoolean,
7
+ GraphQLEnumType,
8
+ GraphQLFieldConfig,
9
+ GraphQLFloat,
10
+ GraphQLInputObjectType,
11
+ GraphQLInputType,
12
+ GraphQLInt,
13
+ GraphQLInterfaceType,
14
+ GraphQLList,
15
+ GraphQLNonNull,
16
+ GraphQLObjectType,
17
+ GraphQLOutputType,
18
+ GraphQLResolveInfo,
19
+ GraphQLScalarType,
20
+ GraphQLSchema,
21
+ GraphQLString,
22
+ GraphQLUnionType
23
+ } from "graphql"
24
+ import {
25
+ GraphQLEnumValueConfigMap,
26
+ GraphQLFieldConfigArgumentMap,
27
+ GraphQLFieldConfigMap,
28
+ GraphQLInputFieldConfigMap
29
+ } from "graphql/type/definition"
30
+ import {Context} from "../context"
31
+ import {decodeRelayConnectionCursor, RelayConnectionRequest} from "../ir/connection"
32
+ import {getEntityListSize, getRelaySize, getSize} from '../limit.size'
33
+ import {Entity, Interface, JsonObject, Model, Prop} from "../model"
34
+ import {getObject, getUnionProps} from "../model.tools"
35
+ import {customScalars} from "../scalars"
36
+ import {EntityByIdQuery, EntityConnectionQuery, EntityCountQuery, EntityListQuery, Query} from "../sql/query"
37
+ import {Subscription} from "../subscription"
38
+ import {Limit} from '../util/limit'
39
+ import {getResolveTree, getTreeRequest, hasTreeRequest, simplifyResolveTree} from "../util/resolve-tree"
40
+ import {ensureArray, identity} from "../util/util"
41
+ import {getOrderByMapping, parseOrderBy} from "./orderBy"
42
+ import {parseEntityListArguments, parseResolveTree} from "./tree"
43
+ import {parseWhere} from "./where"
44
+
45
+
46
+ type GqlFieldMap = GraphQLFieldConfigMap<unknown, Context>
47
+
48
+
49
+ export interface SchemaOptions {
50
+ model: Model
51
+ subscriptions?: boolean
52
+ }
53
+
54
+
55
+ export class SchemaBuilder {
56
+ private model: Model
57
+ private types = new Map<string, GraphQLOutputType>()
58
+ private where = new Map<string, GraphQLInputType>()
59
+ private orderBy = new Map<string, GraphQLInputType>()
60
+
61
+ constructor(private options: SchemaOptions) {
62
+ this.model = options.model
63
+ }
64
+
65
+ private get(name: string): GraphQLOutputType
66
+ private get<T extends GraphQLOutputType>(name: string, kind: Type<T>): T
67
+ private get(name: string, kind?: Type<any>): GraphQLOutputType {
68
+ switch(name) {
69
+ case 'ID':
70
+ case 'String':
71
+ return GraphQLString
72
+ case 'Int':
73
+ return GraphQLInt
74
+ case 'Boolean':
75
+ return GraphQLBoolean
76
+ case 'Float':
77
+ return GraphQLFloat
78
+ case 'DateTime':
79
+ return customScalars.DateTime
80
+ case 'BigInt':
81
+ return customScalars.BigInt
82
+ case 'Bytes':
83
+ return customScalars.Bytes
84
+ case 'JSON':
85
+ return customScalars.JSON
86
+ }
87
+
88
+ let type = this.types.get(name)
89
+ if (type == null) {
90
+ type = this.buildType(name)
91
+ this.types.set(name, type)
92
+ }
93
+ if (kind) {
94
+ assert(type instanceof kind)
95
+ }
96
+ return type
97
+ }
98
+
99
+ private buildType(name: string): GraphQLOutputType {
100
+ const item = this.model[name]
101
+ switch(item.kind) {
102
+ case "entity":
103
+ case "object":
104
+ return new GraphQLObjectType({
105
+ name,
106
+ description: item.description,
107
+ interfaces: () => item.interfaces?.map(name => this.get(name, GraphQLInterfaceType)),
108
+ fields: () => this.buildObjectFields(item)
109
+ })
110
+ case "interface":
111
+ return new GraphQLInterfaceType({
112
+ name,
113
+ description: item.description,
114
+ fields: () => this.buildObjectFields(item)
115
+ })
116
+ case "enum":
117
+ return new GraphQLEnumType({
118
+ name,
119
+ description: item.description,
120
+ values: Object.keys(item.values).reduce((values, variant) => {
121
+ values[variant] = {}
122
+ return values
123
+ }, {} as GraphQLEnumValueConfigMap)
124
+ })
125
+ case "union":
126
+ return new GraphQLUnionType({
127
+ name,
128
+ description: item.description,
129
+ types: () => item.variants.map(variant => this.get(variant, GraphQLObjectType)),
130
+ resolveType(value: any) {
131
+ return value.isTypeOf
132
+ }
133
+ })
134
+ default:
135
+ throw unexpectedCase()
136
+ }
137
+ }
138
+
139
+ private buildObjectFields(object: Entity | JsonObject | Interface): GraphQLFieldConfigMap<any, any> {
140
+ let fields: GraphQLFieldConfigMap<any, any> = {}
141
+ for (let key in object.properties) {
142
+ let prop = object.properties[key]
143
+ let field: GraphQLFieldConfig<any, any> = {
144
+ description: prop.description,
145
+ type: this.getPropType(prop)
146
+ }
147
+ if (prop.type.kind == 'list-lookup') {
148
+ field.args = this.entityListArguments(prop.type.entity)
149
+ }
150
+ if (object.kind == 'entity' || object.kind == 'object') {
151
+ switch(prop.type.kind) {
152
+ case 'object':
153
+ case 'union':
154
+ case 'fk':
155
+ case 'lookup':
156
+ case 'list-lookup':
157
+ field.resolve = (source, args, context, info) => source[info.path.key]
158
+ break
159
+ }
160
+ }
161
+ fields[key] = field
162
+ }
163
+ return fields
164
+ }
165
+
166
+ private getPropType(prop: Prop): GraphQLOutputType {
167
+ let type: GraphQLOutputType
168
+ switch(prop.type.kind) {
169
+ case "list":
170
+ type = new GraphQLList(this.getPropType(prop.type.item))
171
+ break
172
+ case "fk":
173
+ type = this.get(prop.type.foreignEntity)
174
+ break
175
+ case "lookup":
176
+ return this.get(prop.type.entity)
177
+ case "list-lookup":
178
+ return new GraphQLNonNull(
179
+ new GraphQLList(
180
+ new GraphQLNonNull(
181
+ this.get(prop.type.entity)
182
+ )
183
+ )
184
+ )
185
+ default:
186
+ type = this.get(prop.type.name)
187
+ }
188
+ if (!prop.nullable) {
189
+ type = new GraphQLNonNull(type)
190
+ }
191
+ return type
192
+ }
193
+
194
+ private entityListArguments(entityName: string): GraphQLFieldConfigArgumentMap {
195
+ return {
196
+ where: {type: this.getWhere(entityName)},
197
+ orderBy: {type: this.getOrderBy(entityName)},
198
+ offset: {type: GraphQLInt},
199
+ limit: {type: GraphQLInt}
200
+ }
201
+ }
202
+
203
+ private getWhere(name: string): GraphQLInputType {
204
+ let where = this.where.get(name)
205
+ if (where) return where
206
+
207
+ const object = this.model[name]
208
+ switch(object.kind) {
209
+ case "entity":
210
+ case "object":
211
+ case "union":
212
+ break
213
+ default:
214
+ throw unexpectedCase(object.kind)
215
+ }
216
+
217
+ where = new GraphQLInputObjectType({
218
+ name: `${name}WhereInput`,
219
+ fields: () => {
220
+ let fields: GraphQLInputFieldConfigMap = {}
221
+ let properties
222
+ if (object.kind == 'union') {
223
+ properties = getUnionProps(this.model, name).properties
224
+ } else {
225
+ properties = object.properties
226
+ }
227
+
228
+ for (let key in properties) {
229
+ this.buildPropWhereFilters(key, properties[key], fields)
230
+ }
231
+
232
+ if (object.kind == 'entity') {
233
+ let whereList = new GraphQLList(new GraphQLNonNull(this.getWhere(name)))
234
+ fields['AND'] = {
235
+ type: whereList
236
+ }
237
+ fields['OR'] = {
238
+ type: whereList
239
+ }
240
+ }
241
+
242
+ return fields
243
+ }
244
+ })
245
+ this.where.set(name, where)
246
+ return where
247
+ }
248
+
249
+ private buildPropWhereFilters(key: string, prop: Prop, fields: GraphQLInputFieldConfigMap): void {
250
+ switch(prop.type.kind) {
251
+ case "scalar":{
252
+ let type = this.get(prop.type.name, GraphQLScalarType)
253
+ let listType = new GraphQLList(new GraphQLNonNull(type))
254
+
255
+ fields[`${key}_isNull`] = {type: GraphQLBoolean}
256
+ fields[`${key}_eq`] = {type}
257
+ fields[`${key}_not_eq`] = {type}
258
+
259
+ switch(prop.type.name) {
260
+ case 'ID':
261
+ case 'String':
262
+ case 'Int':
263
+ case 'Float':
264
+ case 'DateTime':
265
+ case 'BigInt':
266
+ fields[`${key}_gt`] = {type}
267
+ fields[`${key}_gte`] = {type}
268
+ fields[`${key}_lt`] = {type}
269
+ fields[`${key}_lte`] = {type}
270
+ fields[`${key}_in`] = {type: listType}
271
+ fields[`${key}_not_in`] = {type: listType}
272
+ break
273
+ case "JSON":
274
+ fields[`${key}_jsonContains`] = {type}
275
+ fields[`${key}_jsonHasKey`] = {type}
276
+ break
277
+ }
278
+
279
+ if (prop.type.name == 'ID' || prop.type.name == 'String') {
280
+ fields[`${key}_contains`] = {type}
281
+ fields[`${key}_not_contains`] = {type}
282
+ fields[`${key}_containsInsensitive`] = {type}
283
+ fields[`${key}_not_containsInsensitive`] = {type}
284
+ fields[`${key}_startsWith`] = {type}
285
+ fields[`${key}_not_startsWith`] = {type}
286
+ fields[`${key}_endsWith`] = {type}
287
+ fields[`${key}_not_endsWith`] = {type}
288
+ }
289
+
290
+ break
291
+ }
292
+ case "enum": {
293
+ let type = this.get(prop.type.name, GraphQLEnumType)
294
+ let listType = new GraphQLList(new GraphQLNonNull(type))
295
+ fields[`${key}_isNull`] = {type: GraphQLBoolean}
296
+ fields[`${key}_eq`] = {type}
297
+ fields[`${key}_not_eq`] = {type}
298
+ fields[`${key}_in`] = {type: listType}
299
+ fields[`${key}_not_in`] = {type: listType}
300
+ break
301
+ }
302
+ case "list":
303
+ fields[`${key}_isNull`] = {type: GraphQLBoolean}
304
+ if (prop.type.item.type.kind == 'scalar' || prop.type.item.type.kind == 'enum') {
305
+ let item = this.getPropType(prop.type.item)
306
+ let list = new GraphQLList(item)
307
+ fields[`${key}_containsAll`] = {type: list}
308
+ fields[`${key}_containsAny`] = {type: list}
309
+ fields[`${key}_containsNone`] = {type: list}
310
+ }
311
+ break
312
+ case "object":
313
+ fields[`${key}_isNull`] = {type: GraphQLBoolean}
314
+ if (this.hasFilters(getObject(this.model, prop.type.name))) {
315
+ fields[key] = {type: this.getWhere(prop.type.name)}
316
+ }
317
+ break
318
+ case "union":
319
+ fields[`${key}_isNull`] = {type: GraphQLBoolean}
320
+ fields[key] = {type: this.getWhere(prop.type.name)}
321
+ break
322
+ case "fk":
323
+ fields[`${key}_isNull`] = {type: GraphQLBoolean}
324
+ fields[key] = {type: this.getWhere(prop.type.foreignEntity)}
325
+ break
326
+ case "lookup":
327
+ fields[key] = {type: this.getWhere(prop.type.entity)}
328
+ break
329
+ case "list-lookup": {
330
+ let where = this.getWhere(prop.type.entity)
331
+ fields[`${key}_every`] = {type: where}
332
+ fields[`${key}_some`] = {type: where}
333
+ fields[`${key}_none`] = {type: where}
334
+ break
335
+ }
336
+ }
337
+ }
338
+
339
+ private hasFilters(obj: JsonObject): boolean {
340
+ for (let key in obj.properties) {
341
+ let propType = obj.properties[key].type
342
+ switch(propType.kind) {
343
+ case 'scalar':
344
+ case 'enum':
345
+ case 'union':
346
+ return true
347
+ case 'object': {
348
+ let ref = getObject(this.model, propType.name)
349
+ if (ref !== obj && this.hasFilters(ref)) {
350
+ return true
351
+ }
352
+ }
353
+ }
354
+ }
355
+ return false
356
+ }
357
+
358
+ private getOrderBy(entityName: string): GraphQLInputType {
359
+ let orderBy = this.orderBy.get(entityName)
360
+ if (orderBy) return orderBy
361
+
362
+ let values: GraphQLEnumValueConfigMap = {}
363
+ for (let variant of getOrderByMapping(this.model, entityName).keys()) {
364
+ values[variant] = {}
365
+ }
366
+
367
+ orderBy = new GraphQLList(
368
+ new GraphQLNonNull(
369
+ new GraphQLEnumType({
370
+ name: `${entityName}OrderByInput`,
371
+ values
372
+ })
373
+ )
374
+ )
375
+ this.orderBy.set(entityName, orderBy)
376
+ return orderBy
377
+ }
378
+
379
+ @def
380
+ build(): GraphQLSchema {
381
+ let query: GqlFieldMap = {}
382
+ let subscription: GqlFieldMap = {}
383
+
384
+ for (let name in this.model) {
385
+ let item = this.model[name]
386
+ switch(item.kind) {
387
+ case "entity":
388
+ this.installEntityList(name, query, subscription)
389
+ this.installEntityById(name, query, subscription)
390
+ this.installEntityByUniqueInput(name, query)
391
+ this.installRelayConnection(name, query)
392
+ break
393
+ }
394
+ }
395
+
396
+ return new GraphQLSchema({
397
+ query: new GraphQLObjectType({
398
+ name: 'Query',
399
+ fields: query
400
+ }),
401
+ subscription: this.options.subscriptions ? new GraphQLObjectType({
402
+ name: "Subscription",
403
+ fields: subscription
404
+ }) : undefined
405
+ })
406
+ }
407
+
408
+ private installEntityList(entityName: string, query: GqlFieldMap, subscription: GqlFieldMap): void {
409
+ let model = this.model
410
+ let queryName = toPlural(toCamelCase(entityName))
411
+ let outputType = new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(this.get(entityName))))
412
+ let argsType = this.entityListArguments(entityName)
413
+
414
+ function createQuery(context: Context, info: GraphQLResolveInfo, limit?: Limit) {
415
+ let tree = getResolveTree(info)
416
+ let fields = parseResolveTree(model, entityName, info.schema, tree)
417
+ let args = parseEntityListArguments(model, entityName, tree.args)
418
+ limit?.check(() => getEntityListSize(model, entityName, fields, args.limit, args.where) + 1)
419
+ return new EntityListQuery(
420
+ model,
421
+ context.openreader.dialect,
422
+ entityName,
423
+ fields,
424
+ args
425
+ )
426
+ }
427
+
428
+ query[queryName] = {
429
+ type: outputType,
430
+ args: argsType,
431
+ resolve(source, args, context, info) {
432
+ let q = createQuery(context, info, context.openreader.responseSizeLimit)
433
+ return context.openreader.executeQuery(q)
434
+ }
435
+ }
436
+
437
+ subscription[queryName] = {
438
+ type: outputType,
439
+ args: argsType,
440
+ resolve: identity,
441
+ subscribe(source, args, context, info) {
442
+ let q = createQuery(context, info, context.openreader.subscriptionResponseSizeLimit)
443
+ return context.openreader.subscription(q)
444
+ }
445
+ }
446
+ }
447
+
448
+ private installEntityById(entityName: string, query: GqlFieldMap, subscription: GqlFieldMap): void {
449
+ let model = this.model
450
+ let queryName = `${toCamelCase(entityName)}ById`
451
+ let argsType = {
452
+ id: {type: new GraphQLNonNull(GraphQLString)}
453
+ }
454
+
455
+ function createQuery(context: Context, info: GraphQLResolveInfo, limit?: Limit) {
456
+ let tree = getResolveTree(info)
457
+ let fields = parseResolveTree(model, entityName, info.schema, tree)
458
+ limit?.check(() => getSize(model, fields) + 1)
459
+ return new EntityByIdQuery(
460
+ model,
461
+ context.openreader.dialect,
462
+ entityName,
463
+ fields,
464
+ tree.args.id as string
465
+ )
466
+ }
467
+
468
+ query[queryName] = {
469
+ type: this.get(entityName),
470
+ args: argsType,
471
+ async resolve(source, args, context, info) {
472
+ let q = createQuery(context, info, context.openreader.responseSizeLimit)
473
+ return context.openreader.executeQuery(q)
474
+ }
475
+ }
476
+
477
+ subscription[queryName] = {
478
+ type: this.get(entityName),
479
+ args: argsType,
480
+ resolve: identity,
481
+ subscribe(source, args, context, info) {
482
+ let q = createQuery(context, info, context.openreader.subscriptionResponseSizeLimit)
483
+ return context.openreader.subscription(q)
484
+ }
485
+ }
486
+ }
487
+
488
+ private installEntityByUniqueInput(entityName: string, query: GqlFieldMap): void {
489
+ let model = this.model
490
+
491
+ query[`${toCamelCase(entityName)}ByUniqueInput`] = {
492
+ deprecationReason: `Use ${toCamelCase(entityName)}ById`,
493
+ type: this.get(entityName),
494
+ args: {
495
+ where: {type: this.whereIdInput()}
496
+ },
497
+ async resolve(source, args, context, info) {
498
+ let tree = getResolveTree(info)
499
+ let fields = parseResolveTree(model, entityName, info.schema, tree)
500
+ context.openreader.responseSizeLimit?.check(() => getSize(model, fields) + 1)
501
+ let query = new EntityListQuery(
502
+ model,
503
+ context.openreader.dialect,
504
+ entityName,
505
+ fields,
506
+ {where: {op: 'eq', field: 'id', value: args.where.id}}
507
+ )
508
+ let result = await context.openreader.executeQuery(query)
509
+ assert(result.length < 2)
510
+ return result[0]
511
+ }
512
+ }
513
+ }
514
+
515
+ private installRelayConnection(entityName: string, query: GqlFieldMap): void {
516
+ let model = this.model
517
+ let outputType = toPlural(entityName) + 'Connection'
518
+ let edgeType = `${entityName}Edge`
519
+
520
+ query[`${toPlural(toCamelCase(entityName))}Connection`] = {
521
+ type: new GraphQLNonNull(new GraphQLObjectType({
522
+ name: outputType,
523
+ fields: {
524
+ edges: {
525
+ type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(new GraphQLObjectType({
526
+ name: edgeType,
527
+ fields: {
528
+ node: {type: new GraphQLNonNull(this.get(entityName))},
529
+ cursor: {type: new GraphQLNonNull(GraphQLString)}
530
+ }
531
+ }))))
532
+ },
533
+ pageInfo: {type: this.pageInfoType()},
534
+ totalCount: {type: new GraphQLNonNull(GraphQLInt)}
535
+ }
536
+ })),
537
+ args: {
538
+ orderBy: {type: new GraphQLNonNull(this.getOrderBy(entityName))},
539
+ after: {type: GraphQLString},
540
+ first: {type: GraphQLInt},
541
+ where: {type: this.getWhere(entityName)}
542
+ },
543
+ async resolve(source, args, context, info) {
544
+ let orderByArg = ensureArray(args.orderBy)
545
+ if (orderByArg.length == 0) {
546
+ throw new UserInputError('orderBy argument is required for connection')
547
+ }
548
+
549
+ let req: RelayConnectionRequest = {
550
+ orderBy: parseOrderBy(model, entityName, orderByArg),
551
+ where: parseWhere(args.where)
552
+ }
553
+
554
+ if (args.first != null) {
555
+ if (args.first < 0) {
556
+ throw new UserInputError("'first' argument of connection can't be less than 0")
557
+ } else {
558
+ req.first = args.first
559
+ }
560
+ }
561
+
562
+ if (args.after != null) {
563
+ if (decodeRelayConnectionCursor(args.after) == null) {
564
+ throw new UserInputError(`invalid cursor value: ${args.after}`)
565
+ } else {
566
+ req.after = args.after
567
+ }
568
+ }
569
+
570
+ let tree = getResolveTree(info, outputType)
571
+
572
+ req.totalCount = hasTreeRequest(tree.fields, 'totalCount')
573
+ req.pageInfo = hasTreeRequest(tree.fields, 'pageInfo')
574
+
575
+ let edgesTree = getTreeRequest(tree.fields, 'edges')
576
+ if (edgesTree) {
577
+ let edgeFields = simplifyResolveTree(info.schema, edgesTree, edgeType).fields
578
+ req.edgeCursor = hasTreeRequest(edgeFields, 'cursor')
579
+ let nodeTree = getTreeRequest(edgeFields, 'node')
580
+ if (nodeTree) {
581
+ req.edgeNode = parseResolveTree(model, entityName, info.schema, nodeTree)
582
+ }
583
+ }
584
+
585
+ context.openreader.responseSizeLimit?.check(() => getRelaySize(model, entityName, req) + 1)
586
+
587
+ let result = await context.openreader.executeQuery(new EntityConnectionQuery(
588
+ model,
589
+ context.openreader.dialect,
590
+ entityName,
591
+ req
592
+ ))
593
+
594
+ if (req.totalCount && result.totalCount == null) {
595
+ result.totalCount = await context.openreader.executeQuery(new EntityCountQuery(
596
+ model,
597
+ context.openreader.dialect,
598
+ entityName,
599
+ req.where
600
+ ))
601
+ }
602
+
603
+ return result
604
+ }
605
+ }
606
+ }
607
+
608
+ @def
609
+ private whereIdInput(): GraphQLInputType {
610
+ return new GraphQLNonNull(
611
+ new GraphQLInputObjectType({
612
+ name: "WhereIdInput",
613
+ fields: {
614
+ id: {type: new GraphQLNonNull(GraphQLString)}
615
+ }
616
+ })
617
+ )
618
+ }
619
+
620
+ @def
621
+ private pageInfoType(): GraphQLOutputType {
622
+ return new GraphQLNonNull(
623
+ new GraphQLObjectType({
624
+ name: "PageInfo",
625
+ fields: {
626
+ hasNextPage: {type: new GraphQLNonNull(GraphQLBoolean)},
627
+ hasPreviousPage: {type: new GraphQLNonNull(GraphQLBoolean)},
628
+ startCursor: {type: new GraphQLNonNull(GraphQLString)},
629
+ endCursor: {type: new GraphQLNonNull(GraphQLString)}
630
+ }
631
+ })
632
+ )
633
+ }
634
+ }
635
+
636
+
637
+ interface Type<T> {
638
+ new (...args: any[]): T
639
+ }