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