@subsquid/openreader 0.2.1 → 0.4.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 (131) hide show
  1. package/README.md +2 -15
  2. package/bin/main.js +2 -0
  3. package/dist/db.d.ts +28 -0
  4. package/dist/db.d.ts.map +1 -0
  5. package/dist/db.js +69 -0
  6. package/dist/db.js.map +1 -0
  7. package/dist/gql/opencrud.d.ts +1 -0
  8. package/dist/gql/opencrud.d.ts.map +1 -0
  9. package/dist/gql/opencrud.js +10 -9
  10. package/dist/gql/opencrud.js.map +1 -1
  11. package/dist/gql/schema.d.ts +1 -0
  12. package/dist/gql/schema.d.ts.map +1 -0
  13. package/dist/gql/schema.js +116 -17
  14. package/dist/gql/schema.js.map +1 -1
  15. package/dist/main.d.ts +2 -3
  16. package/dist/main.d.ts.map +1 -0
  17. package/dist/main.js +6 -30
  18. package/dist/main.js.map +1 -1
  19. package/dist/model.d.ts +9 -0
  20. package/dist/model.d.ts.map +1 -0
  21. package/dist/model.tools.d.ts +2 -0
  22. package/dist/model.tools.d.ts.map +1 -0
  23. package/dist/model.tools.js +27 -1
  24. package/dist/model.tools.js.map +1 -1
  25. package/dist/orderBy.d.ts +1 -0
  26. package/dist/orderBy.d.ts.map +1 -0
  27. package/dist/queryBuilder.d.ts +3 -2
  28. package/dist/queryBuilder.d.ts.map +1 -0
  29. package/dist/queryBuilder.js +28 -27
  30. package/dist/queryBuilder.js.map +1 -1
  31. package/dist/relayConnection.d.ts +1 -0
  32. package/dist/relayConnection.d.ts.map +1 -0
  33. package/dist/requestedFields.d.ts +1 -0
  34. package/dist/requestedFields.d.ts.map +1 -0
  35. package/dist/requestedFields.js +3 -3
  36. package/dist/requestedFields.js.map +1 -1
  37. package/dist/resolver.d.ts +3 -2
  38. package/dist/resolver.d.ts.map +1 -0
  39. package/dist/resolver.js +12 -11
  40. package/dist/resolver.js.map +1 -1
  41. package/dist/scalars.d.ts +2 -2
  42. package/dist/scalars.d.ts.map +1 -0
  43. package/dist/scalars.js.map +1 -1
  44. package/dist/server.d.ts +5 -11
  45. package/dist/server.d.ts.map +1 -0
  46. package/dist/server.js +13 -31
  47. package/dist/server.js.map +1 -1
  48. package/dist/test/basic.test.d.ts +2 -0
  49. package/dist/test/basic.test.d.ts.map +1 -0
  50. package/dist/test/basic.test.js +286 -0
  51. package/dist/test/basic.test.js.map +1 -0
  52. package/dist/test/connection.test.d.ts +2 -0
  53. package/dist/test/connection.test.d.ts.map +1 -0
  54. package/dist/test/connection.test.js +193 -0
  55. package/dist/test/connection.test.js.map +1 -0
  56. package/dist/test/fts.test.d.ts +2 -0
  57. package/dist/test/fts.test.d.ts.map +1 -0
  58. package/dist/test/fts.test.js +110 -0
  59. package/dist/test/fts.test.js.map +1 -0
  60. package/dist/test/lists.test.d.ts +2 -0
  61. package/dist/test/lists.test.d.ts.map +1 -0
  62. package/dist/test/lists.test.js +266 -0
  63. package/dist/test/lists.test.js.map +1 -0
  64. package/dist/test/lookup.test.d.ts +2 -0
  65. package/dist/test/lookup.test.d.ts.map +1 -0
  66. package/dist/test/lookup.test.js +109 -0
  67. package/dist/test/lookup.test.js.map +1 -0
  68. package/dist/test/scalars.test.d.ts +2 -0
  69. package/dist/test/scalars.test.d.ts.map +1 -0
  70. package/dist/test/scalars.test.js +303 -0
  71. package/dist/test/scalars.test.js.map +1 -0
  72. package/dist/test/tools.test.d.ts +2 -0
  73. package/dist/test/tools.test.d.ts.map +1 -0
  74. package/dist/test/tools.test.js +49 -0
  75. package/dist/test/tools.test.js.map +1 -0
  76. package/dist/test/typed-json.test.d.ts +2 -0
  77. package/dist/test/typed-json.test.d.ts.map +1 -0
  78. package/dist/test/typed-json.test.js +75 -0
  79. package/dist/test/typed-json.test.js.map +1 -0
  80. package/dist/test/unions.test.d.ts +2 -0
  81. package/dist/test/unions.test.d.ts.map +1 -0
  82. package/dist/test/unions.test.js +84 -0
  83. package/dist/test/unions.test.js.map +1 -0
  84. package/dist/test/util/setup.d.ts +7 -0
  85. package/dist/test/util/setup.d.ts.map +1 -0
  86. package/dist/test/util/setup.js +60 -0
  87. package/dist/test/util/setup.js.map +1 -0
  88. package/dist/test/where.test.d.ts +2 -0
  89. package/dist/test/where.test.d.ts.map +1 -0
  90. package/dist/test/where.test.js +127 -0
  91. package/dist/test/where.test.js.map +1 -0
  92. package/dist/tools.d.ts +1 -0
  93. package/dist/tools.d.ts.map +1 -0
  94. package/dist/util.d.ts +1 -13
  95. package/dist/util.d.ts.map +1 -0
  96. package/dist/util.js +6 -79
  97. package/dist/util.js.map +1 -1
  98. package/dist/where.d.ts +1 -0
  99. package/dist/where.d.ts.map +1 -0
  100. package/package.json +26 -20
  101. package/src/db.ts +83 -0
  102. package/src/gql/opencrud.ts +328 -0
  103. package/src/gql/schema.ts +463 -0
  104. package/src/main.ts +51 -0
  105. package/src/model.tools.ts +201 -0
  106. package/src/model.ts +137 -0
  107. package/src/orderBy.ts +105 -0
  108. package/src/queryBuilder.ts +785 -0
  109. package/src/relayConnection.ts +80 -0
  110. package/src/requestedFields.ts +246 -0
  111. package/src/resolver.ts +199 -0
  112. package/src/scalars.ts +247 -0
  113. package/src/server.ts +115 -0
  114. package/src/test/basic.test.ts +339 -0
  115. package/src/test/connection.test.ts +195 -0
  116. package/src/test/fts.test.ts +114 -0
  117. package/src/test/lists.test.ts +278 -0
  118. package/src/test/lookup.test.ts +111 -0
  119. package/src/test/scalars.test.ts +316 -0
  120. package/src/test/tools.test.ts +27 -0
  121. package/src/test/typed-json.test.ts +76 -0
  122. package/src/test/unions.test.ts +85 -0
  123. package/src/test/util/setup.ts +63 -0
  124. package/src/test/where.test.ts +135 -0
  125. package/src/tools.ts +33 -0
  126. package/src/util.ts +39 -0
  127. package/src/where.ts +110 -0
  128. package/CHANGELOG.md +0 -20
  129. package/dist/transaction.d.ts +0 -10
  130. package/dist/transaction.js +0 -47
  131. package/dist/transaction.js.map +0 -1
@@ -0,0 +1,328 @@
1
+ import {Output, toCamelCase, toPlural} from "@subsquid/util"
2
+ import assert from "assert"
3
+ import {DocumentNode, parse, print} from "graphql"
4
+ import {Entity, Enum, FTS_Query, Interface, JsonObject, Model, Prop, Union} from "../model"
5
+ import {getOrderByMapping} from "../orderBy"
6
+ import {scalars_list} from "../scalars"
7
+ import {toQueryListField} from "../util"
8
+
9
+
10
+ export function generateOpenCrudQueries(model: Model): string {
11
+ let out = new Output()
12
+
13
+ generatePageInfoType()
14
+
15
+ for (let name in model) {
16
+ let item = model[name]
17
+ switch(item.kind) {
18
+ case 'entity':
19
+ generateOrderByInput(name)
20
+ generateWhereUniqueInput(name)
21
+ generateWhereInput(name, item)
22
+ generateObjectType(name, item)
23
+ generateEntityConnection(name)
24
+ break
25
+ case 'object':
26
+ if (hasFilters(item)) {
27
+ generateWhereInput(name, item)
28
+ }
29
+ generateObjectType(name, item)
30
+ break
31
+ case 'interface':
32
+ generateObjectType(name, item)
33
+ break
34
+ case 'union':
35
+ generateUnionWhereInput(name, item)
36
+ generateUnionType(name, item)
37
+ break
38
+ case 'enum':
39
+ generateEnumType(name, item)
40
+ break
41
+ case 'fts':
42
+ generateFtsTypes(name, item)
43
+ break
44
+ }
45
+ }
46
+
47
+ out.block('type Query', () => {
48
+ for (let name in model) {
49
+ let item = model[name]
50
+ if (item.kind == 'entity') {
51
+ out.line(`${toCamelCase(name)}ById(id: ID!): ${name}`)
52
+ out.line(`${toCamelCase(name)}ByUniqueInput(where: ${name}WhereUniqueInput!): ${name} @deprecated(reason: "Use \`${toCamelCase(name)}ById\`")`)
53
+ out.line(`${toQueryListField(name)}${manyArguments(name)}: [${name}!]!`)
54
+ out.line(`${toQueryListField(name)}Connection${connectionArguments(name)}: ${toPlural(name)}Connection!`)
55
+ }
56
+ if (item.kind == 'fts') {
57
+ generateFtsQuery(name, item)
58
+ }
59
+ }
60
+ })
61
+
62
+ function generateObjectType(name: string, object: Entity | JsonObject | Interface): void {
63
+ let head: string
64
+ if (object.kind == 'interface') {
65
+ head = `interface ${name}`
66
+ } else {
67
+ head = `type ${name}`
68
+ if (object.interfaces?.length) {
69
+ head += ` implements ${object.interfaces.join(' & ')}`
70
+ }
71
+ }
72
+ generateDescription(object.description)
73
+ out.block(head, () => {
74
+ for (let key in object.properties) {
75
+ let prop = object.properties[key]
76
+ let gqlType = renderPropType(prop)
77
+ generateDescription(prop.description)
78
+ if (prop.type.kind == 'list-lookup') {
79
+ out.line(`${key}${manyArguments(prop.type.entity)}: ${gqlType}`)
80
+ } else {
81
+ out.line(`${key}: ${gqlType}`)
82
+ }
83
+ }
84
+ })
85
+ out.line()
86
+ }
87
+
88
+ function renderPropType(prop: Prop): string {
89
+ switch(prop.type.kind) {
90
+ case "list":
91
+ return `[${renderPropType(prop.type.item)}]${prop.nullable ? '' : '!'}`
92
+ case 'fk':
93
+ return `${prop.type.foreignEntity}${prop.nullable ? '' : '!'}`
94
+ case 'lookup':
95
+ return prop.type.entity
96
+ case 'list-lookup':
97
+ return `[${prop.type.entity}!]!`
98
+ default:
99
+ return prop.type.name + (prop.nullable ? '' : '!')
100
+ }
101
+ }
102
+
103
+ function manyArguments(entityName: string): string {
104
+ return `(where: ${entityName}WhereInput orderBy: [${entityName}OrderByInput] offset: Int limit: Int)`
105
+ }
106
+
107
+ function connectionArguments(entityName: string): string {
108
+ return `(orderBy: [${entityName}OrderByInput!]! after: String first: Int where: ${entityName}WhereInput)`
109
+ }
110
+
111
+ function generateOrderByInput(entityName: string): void {
112
+ out.block(`enum ${entityName}OrderByInput`, () => {
113
+ let mapping = getOrderByMapping(model, entityName)
114
+ for (let key of mapping.keys()) {
115
+ out.line(key)
116
+ }
117
+ })
118
+ out.line()
119
+ }
120
+
121
+ function generateWhereUniqueInput(entityName: string): void {
122
+ out.block(`input ${entityName}WhereUniqueInput`, () => {
123
+ out.line('id: ID!')
124
+ })
125
+ }
126
+
127
+ function generateWhereInput(name: string, object: Entity | JsonObject): void {
128
+ out.block(`input ${name}WhereInput`, () => {
129
+ generatePropsFilters(object.properties)
130
+ if (object.kind == 'entity') {
131
+ out.line(`AND: [${name}WhereInput!]`)
132
+ out.line(`OR: [${name}WhereInput!]`)
133
+ }
134
+ })
135
+ out.line()
136
+ }
137
+
138
+ function generatePropsFilters(props: Record<string, Prop>): void {
139
+ for (let key in props) {
140
+ let prop = props[key]
141
+ switch(prop.type.kind) {
142
+ case 'scalar':
143
+ case 'enum':
144
+ generateScalarFilters(key, prop.type.name)
145
+ break
146
+ case 'list':
147
+ if (prop.type.item.type.kind == 'scalar' || prop.type.item.type.kind == 'enum') {
148
+ let item = prop.type.item.type.name
149
+ out.line(`${key}_containsAll: [${item}!]`)
150
+ out.line(`${key}_containsAny: [${item}!]`)
151
+ out.line(`${key}_containsNone: [${item}!]`)
152
+ }
153
+ break
154
+ case 'object':
155
+ if (hasFilters(getObject(prop.type.name))) {
156
+ out.line(`${key}: ${prop.type.name}WhereInput`)
157
+ }
158
+ break
159
+ case 'union':
160
+ out.line(`${key}: ${prop.type.name}WhereInput`)
161
+ break
162
+ case 'fk':
163
+ out.line(`${key}: ${prop.type.foreignEntity}WhereInput`)
164
+ break
165
+ case 'lookup':
166
+ out.line(`${key}: ${prop.type.entity}WhereInput`)
167
+ break
168
+ case 'list-lookup':
169
+ out.line(`${key}_every: ${prop.type.entity}WhereInput`)
170
+ out.line(`${key}_some: ${prop.type.entity}WhereInput`)
171
+ out.line(`${key}_none: ${prop.type.entity}WhereInput`)
172
+ break
173
+ }
174
+ }
175
+ }
176
+
177
+ function hasFilters(obj: JsonObject): boolean {
178
+ for (let key in obj.properties) {
179
+ let propType = obj.properties[key].type
180
+ switch(propType.kind) {
181
+ case 'scalar':
182
+ case 'enum':
183
+ case 'union':
184
+ return true
185
+ case 'object':
186
+ if (hasFilters(getObject(propType.name))) {
187
+ return true
188
+ }
189
+ }
190
+ }
191
+ return false
192
+ }
193
+
194
+ function getObject(name: string): JsonObject {
195
+ let obj = model[name]
196
+ assert(obj.kind == 'object')
197
+ return obj
198
+ }
199
+
200
+ function generateUnionWhereInput(name: string, union: Union): void {
201
+ out.block(`input ${name}WhereInput`, () => {
202
+ // TODO: unify and use enum
203
+ out.line('isTypeOf_eq: String')
204
+ out.line('isTypeOf_not_eq: String')
205
+ out.line('isTypeOf_in: [String!]')
206
+ out.line('isTypeOf_not_in: [String!]')
207
+
208
+ let props: Record<string, Prop> = {}
209
+ union.variants.forEach(variant => {
210
+ let obj = getObject(variant)
211
+ Object.assign(props, obj.properties)
212
+ })
213
+
214
+ generatePropsFilters(props)
215
+ })
216
+ }
217
+
218
+ function generateScalarFilters(fieldName: string, graphqlType: string): void {
219
+ out.line(`${fieldName}_eq: ${graphqlType}`)
220
+ out.line(`${fieldName}_not_eq: ${graphqlType}`)
221
+
222
+ switch(graphqlType) {
223
+ case 'ID':
224
+ case 'String':
225
+ case 'Int':
226
+ case 'Float':
227
+ case 'DateTime':
228
+ case 'BigInt':
229
+ out.line(`${fieldName}_gt: ${graphqlType}`)
230
+ out.line(`${fieldName}_gte: ${graphqlType}`)
231
+ out.line(`${fieldName}_lt: ${graphqlType}`)
232
+ out.line(`${fieldName}_lte: ${graphqlType}`)
233
+ out.line(`${fieldName}_in: [${graphqlType}!]`)
234
+ out.line(`${fieldName}_not_in: [${graphqlType}!]`)
235
+ break
236
+ }
237
+
238
+ if (graphqlType == 'String' || graphqlType == 'ID') {
239
+ out.line(`${fieldName}_contains: ${graphqlType}`)
240
+ out.line(`${fieldName}_not_contains: ${graphqlType}`)
241
+ out.line(`${fieldName}_startsWith: ${graphqlType}`)
242
+ out.line(`${fieldName}_not_startsWith: ${graphqlType}`)
243
+ out.line(`${fieldName}_endsWith: ${graphqlType}`)
244
+ out.line(`${fieldName}_not_endsWith: ${graphqlType}`)
245
+ }
246
+
247
+ if (model[graphqlType]?.kind == 'enum') {
248
+ out.line(`${fieldName}_in: [${graphqlType}!]`)
249
+ out.line(`${fieldName}_not_in: [${graphqlType}!]`)
250
+ }
251
+ }
252
+
253
+ function generateUnionType(name: string, union: Union) {
254
+ generateDescription(union.description)
255
+ out.line(`union ${name} = ${union.variants.join(' | ')}`)
256
+ out.line()
257
+ }
258
+
259
+ function generateEnumType(name: string, e: Enum): void {
260
+ generateDescription(e.description)
261
+ out.block(`enum ${name}`, () => {
262
+ for (let key in e.values) {
263
+ out.line(key)
264
+ }
265
+ })
266
+ }
267
+
268
+ function generatePageInfoType(): void {
269
+ out.block(`type PageInfo`, () => {
270
+ out.line('hasNextPage: Boolean!')
271
+ out.line('hasPreviousPage: Boolean!')
272
+ out.line('startCursor: String!')
273
+ out.line('endCursor: String!')
274
+ })
275
+ out.line()
276
+ }
277
+
278
+ function generateEntityConnection(name: string): void {
279
+ out.block(`type ${name}Edge`, () => {
280
+ out.line(`node: ${name}!`)
281
+ out.line(`cursor: String!`)
282
+ })
283
+ out.line()
284
+ out.block(`type ${toPlural(name)}Connection`, () => {
285
+ out.line(`edges: [${name}Edge!]!`)
286
+ out.line(`pageInfo: PageInfo!`)
287
+ out.line(`totalCount: Int!`)
288
+ })
289
+ out.line()
290
+ }
291
+
292
+ function generateFtsTypes(name: string, query: FTS_Query): void {
293
+ let itemType = name + '_Item'
294
+ out.line(`union ${itemType} = ${query.sources.map(s => s.entity).join(' | ')}`)
295
+ out.line()
296
+ out.block(`type ${name}_Output`, () => {
297
+ out.line(`item: ${itemType}!`)
298
+ out.line(`rank: Float!`)
299
+ out.line(`highlight: String!`)
300
+ })
301
+ out.line()
302
+ }
303
+
304
+ function generateFtsQuery(name: string, query: FTS_Query): void {
305
+ let where = query.sources.map(src => {
306
+ return `where${src.entity}: ${src.entity}WhereInput`
307
+ })
308
+ out.line(`${name}(text: String! ${where.join(' ')} limit: Int offset: Int): [${name}_Output!]!`)
309
+ }
310
+
311
+ function generateDescription(description?: string): void {
312
+ if (description) {
313
+ out.line(print({
314
+ kind: 'StringValue',
315
+ value: description
316
+ }))
317
+ }
318
+ }
319
+
320
+ return out.toString()
321
+ }
322
+
323
+
324
+ export function buildServerSchema(model: Model): DocumentNode {
325
+ let scalars = scalars_list.map(name => 'scalar ' + name).join('\n')
326
+ let queries = generateOpenCrudQueries(model)
327
+ return parse(scalars + '\n\n' + queries)
328
+ }