@subsquid/openreader 2.1.0 → 3.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.
- package/lib/ir/args.d.ts +1 -1
- package/lib/ir/args.d.ts.map +1 -1
- package/lib/ir/connection.d.ts +3 -4
- package/lib/ir/connection.d.ts.map +1 -1
- package/lib/ir/connection.js.map +1 -1
- package/lib/ir/fields.d.ts +6 -2
- package/lib/ir/fields.d.ts.map +1 -1
- package/lib/ir/fields.js +15 -0
- package/lib/ir/fields.js.map +1 -1
- package/lib/limit.size.d.ts +4 -4
- package/lib/limit.size.d.ts.map +1 -1
- package/lib/limit.size.js +51 -20
- package/lib/limit.size.js.map +1 -1
- package/lib/main.js +0 -9
- package/lib/main.js.map +1 -1
- package/lib/model.d.ts +3 -2
- package/lib/model.d.ts.map +1 -1
- package/lib/model.schema.d.ts +2 -2
- package/lib/model.schema.d.ts.map +1 -1
- package/lib/model.schema.js +8 -3
- package/lib/model.schema.js.map +1 -1
- package/lib/model.tools.d.ts +6 -1
- package/lib/model.tools.d.ts.map +1 -1
- package/lib/model.tools.js +111 -8
- package/lib/model.tools.js.map +1 -1
- package/lib/opencrud/orderBy.d.ts +2 -2
- package/lib/opencrud/orderBy.d.ts.map +1 -1
- package/lib/opencrud/orderBy.js +13 -17
- package/lib/opencrud/orderBy.js.map +1 -1
- package/lib/opencrud/schema.d.ts +4 -4
- package/lib/opencrud/schema.d.ts.map +1 -1
- package/lib/opencrud/schema.js +56 -62
- package/lib/opencrud/schema.js.map +1 -1
- package/lib/opencrud/tree.d.ts +9 -7
- package/lib/opencrud/tree.d.ts.map +1 -1
- package/lib/opencrud/tree.js +32 -14
- package/lib/opencrud/tree.js.map +1 -1
- package/lib/scalars/BigDecimal.d.ts +3 -0
- package/lib/scalars/BigDecimal.d.ts.map +1 -0
- package/lib/scalars/BigDecimal.js +38 -0
- package/lib/scalars/BigDecimal.js.map +1 -0
- package/lib/scalars/index.d.ts +1 -0
- package/lib/scalars/index.d.ts.map +1 -1
- package/lib/scalars/index.js +2 -0
- package/lib/scalars/index.js.map +1 -1
- package/lib/server.d.ts +4 -2
- package/lib/server.d.ts.map +1 -1
- package/lib/server.js +4 -2
- package/lib/server.js.map +1 -1
- package/lib/sql/cursor.d.ts.map +1 -1
- package/lib/sql/cursor.js +4 -2
- package/lib/sql/cursor.js.map +1 -1
- package/lib/sql/mapping.d.ts +3 -1
- package/lib/sql/mapping.d.ts.map +1 -1
- package/lib/sql/mapping.js +16 -1
- package/lib/sql/mapping.js.map +1 -1
- package/lib/sql/printer.d.ts +29 -11
- package/lib/sql/printer.d.ts.map +1 -1
- package/lib/sql/printer.js +112 -11
- package/lib/sql/printer.js.map +1 -1
- package/lib/sql/query.d.ts +11 -11
- package/lib/sql/query.d.ts.map +1 -1
- package/lib/sql/query.js +41 -19
- package/lib/sql/query.js.map +1 -1
- package/lib/test/queryable.test.d.ts +2 -0
- package/lib/test/queryable.test.d.ts.map +1 -0
- package/lib/test/queryable.test.js +255 -0
- package/lib/test/queryable.test.js.map +1 -0
- package/lib/test/scalars.test.js +75 -1
- package/lib/test/scalars.test.js.map +1 -1
- package/lib/util/big-decimal.d.ts +5 -0
- package/lib/util/big-decimal.d.ts.map +1 -0
- package/lib/util/big-decimal.js +15 -0
- package/lib/util/big-decimal.js.map +1 -0
- package/package.json +10 -2
- package/src/ir/args.ts +1 -1
- package/src/ir/connection.ts +3 -4
- package/src/ir/fields.ts +22 -2
- package/src/limit.size.ts +55 -30
- package/src/main.ts +0 -11
- package/src/model.schema.ts +16 -9
- package/src/model.tools.ts +121 -8
- package/src/model.ts +3 -2
- package/src/opencrud/orderBy.ts +13 -17
- package/src/opencrud/schema.ts +81 -84
- package/src/opencrud/tree.ts +55 -26
- package/src/scalars/BigDecimal.ts +37 -0
- package/src/scalars/index.ts +2 -0
- package/src/server.ts +10 -7
- package/src/sql/cursor.ts +4 -2
- package/src/sql/mapping.ts +18 -1
- package/src/sql/printer.ts +142 -22
- package/src/sql/query.ts +50 -30
- package/src/test/queryable.test.ts +258 -0
- package/src/test/scalars.test.ts +78 -1
- package/src/util/big-decimal.ts +15 -0
package/src/main.ts
CHANGED
|
@@ -31,7 +31,6 @@ GraphQL server for postgres-compatible databases
|
|
|
31
31
|
program.option('--sql-statement-timeout <ms>', 'sql statement timeout in ms', nat)
|
|
32
32
|
program.option('--subscriptions', 'enable gql subscriptions')
|
|
33
33
|
program.option('--subscription-poll-interval <ms>', 'subscription poll interval in ms', nat, 1000)
|
|
34
|
-
program.option('--subscription-sql-statement-timeout <ms>', 'sql statement timeout for polling queries', nat)
|
|
35
34
|
program.option('--subscription-max-response-size <nodes>', 'max response size measured in nodes', nat)
|
|
36
35
|
|
|
37
36
|
let opts = program.parse().opts() as {
|
|
@@ -45,7 +44,6 @@ GraphQL server for postgres-compatible databases
|
|
|
45
44
|
sqlStatementTimeout?: number
|
|
46
45
|
subscriptions?: boolean
|
|
47
46
|
subscriptionPollInterval: number
|
|
48
|
-
subscriptionSqlStatementTimeout?: number
|
|
49
47
|
subscriptionMaxResponseSize?: number
|
|
50
48
|
}
|
|
51
49
|
|
|
@@ -56,14 +54,6 @@ GraphQL server for postgres-compatible databases
|
|
|
56
54
|
statement_timeout: opts.sqlStatementTimeout || undefined
|
|
57
55
|
})
|
|
58
56
|
|
|
59
|
-
let subscriptionConnection: Pool | undefined
|
|
60
|
-
if (opts.subscriptions) {
|
|
61
|
-
subscriptionConnection = new Pool({
|
|
62
|
-
connectionString: opts.dbUrl,
|
|
63
|
-
statement_timeout: opts.subscriptionSqlStatementTimeout || opts.sqlStatementTimeout || undefined
|
|
64
|
-
})
|
|
65
|
-
}
|
|
66
|
-
|
|
67
57
|
let server = await serve({
|
|
68
58
|
model,
|
|
69
59
|
dialect: opts.dbType,
|
|
@@ -75,7 +65,6 @@ GraphQL server for postgres-compatible databases
|
|
|
75
65
|
maxResponseNodes: opts.maxResponseSize,
|
|
76
66
|
subscriptions: opts.subscriptions,
|
|
77
67
|
subscriptionPollInterval: opts.subscriptionPollInterval,
|
|
78
|
-
subscriptionConnection,
|
|
79
68
|
subscriptionMaxResponseNodes: opts.subscriptionMaxResponseSize
|
|
80
69
|
})
|
|
81
70
|
|
package/src/model.schema.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {assertNotNull, unexpectedCase} from
|
|
2
|
-
import assert from
|
|
1
|
+
import {assertNotNull, unexpectedCase} from '@subsquid/util-internal'
|
|
2
|
+
import assert from 'assert'
|
|
3
3
|
import {
|
|
4
4
|
buildASTSchema,
|
|
5
5
|
DocumentNode,
|
|
@@ -17,14 +17,15 @@ import {
|
|
|
17
17
|
GraphQLUnionType,
|
|
18
18
|
parse,
|
|
19
19
|
validateSchema
|
|
20
|
-
} from
|
|
21
|
-
import {Index, Model, Prop, PropType, Scalar} from
|
|
22
|
-
import {validateModel} from
|
|
23
|
-
import {customScalars} from
|
|
20
|
+
} from 'graphql'
|
|
21
|
+
import {Index, Model, Prop, PropType, Scalar} from './model'
|
|
22
|
+
import {validateModel} from './model.tools'
|
|
23
|
+
import {customScalars} from './scalars'
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
const baseSchema = buildASTSchema(parse(`
|
|
27
27
|
directive @entity on OBJECT
|
|
28
|
+
directive @query on INTERFACE
|
|
28
29
|
directive @derivedFrom(field: String!) on FIELD_DEFINITION
|
|
29
30
|
directive @unique on FIELD_DEFINITION
|
|
30
31
|
directive @index(fields: [String!] unique: Boolean) on OBJECT | FIELD_DEFINITION
|
|
@@ -88,7 +89,7 @@ function addEntityOrJsonObjectOrInterface(model: Model, type: GraphQLObjectType
|
|
|
88
89
|
model[type.name] = {kind, properties, description, interfaces}
|
|
89
90
|
break
|
|
90
91
|
case 'interface':
|
|
91
|
-
model[type.name] = {kind, properties, description}
|
|
92
|
+
model[type.name] = {kind, properties, description, queryable: isQueryableInterface(type)}
|
|
92
93
|
break
|
|
93
94
|
default:
|
|
94
95
|
throw unexpectedCase(kind)
|
|
@@ -173,7 +174,7 @@ function addEntityOrJsonObjectOrInterface(model: Model, type: GraphQLObjectType
|
|
|
173
174
|
...limits
|
|
174
175
|
}
|
|
175
176
|
} else if (fieldType instanceof GraphQLObjectType) {
|
|
176
|
-
if (isEntityType(fieldType)) {
|
|
177
|
+
if (isEntityType(fieldType) && kind != 'interface') {
|
|
177
178
|
switch(list.nulls.length) {
|
|
178
179
|
case 0:
|
|
179
180
|
if (derivedFrom) {
|
|
@@ -196,7 +197,7 @@ function addEntityOrJsonObjectOrInterface(model: Model, type: GraphQLObjectType
|
|
|
196
197
|
properties[key] = {
|
|
197
198
|
type: {
|
|
198
199
|
kind: 'fk',
|
|
199
|
-
|
|
200
|
+
entity: fieldType.name
|
|
200
201
|
},
|
|
201
202
|
nullable,
|
|
202
203
|
unique,
|
|
@@ -519,6 +520,12 @@ function checkByteWeightDirective(type: GraphQLNamedType, f: GraphQLField<any, a
|
|
|
519
520
|
}
|
|
520
521
|
|
|
521
522
|
|
|
523
|
+
function isQueryableInterface(type: GraphQLOutputType): boolean {
|
|
524
|
+
return type instanceof GraphQLInterfaceType
|
|
525
|
+
&& !!type.astNode?.directives?.find(d => d.name.value == 'query')
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
|
|
522
529
|
function unsupportedFieldTypeError(propName: string): Error {
|
|
523
530
|
return new SchemaError(`Property ${propName} has unsupported type`)
|
|
524
531
|
}
|
package/src/model.tools.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import {unexpectedCase} from '@subsquid/util-internal'
|
|
2
|
+
import assert from 'assert'
|
|
3
|
+
import {Entity, FTS_Query, Interface, JsonObject, Model, Prop, PropType} from './model'
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
const UNION_MAPS = new WeakMap<Model, Record<string, JsonObject>>()
|
|
@@ -20,8 +21,7 @@ export function buildUnionProps(model: Model, unionName: string): JsonObject {
|
|
|
20
21
|
let union = model[unionName]
|
|
21
22
|
assert(union.kind == 'union')
|
|
22
23
|
let properties: Record<string, Prop> = {}
|
|
23
|
-
for (let
|
|
24
|
-
let objectName = union.variants[i]
|
|
24
|
+
for (let objectName of union.variants) {
|
|
25
25
|
let object = model[objectName]
|
|
26
26
|
assert(object.kind == 'object')
|
|
27
27
|
Object.assign(properties, object.properties)
|
|
@@ -34,12 +34,106 @@ export function buildUnionProps(model: Model, unionName: string): JsonObject {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
const QUERYABLE_ENTITIES = new WeakMap<Model, Record<string, string[]>>()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
export function getQueryableEntities(model: Model, queryableName: string): string[] {
|
|
41
|
+
let cache = QUERYABLE_ENTITIES.get(model)
|
|
42
|
+
if (cache == null) {
|
|
43
|
+
cache = {}
|
|
44
|
+
QUERYABLE_ENTITIES.set(model, cache)
|
|
45
|
+
}
|
|
46
|
+
let entities = cache[queryableName]
|
|
47
|
+
if (entities) return entities
|
|
48
|
+
entities = cache[queryableName] = []
|
|
49
|
+
for (let name in model) {
|
|
50
|
+
let item = model[name]
|
|
51
|
+
if (item.kind == 'entity' && item.interfaces?.includes(queryableName)) {
|
|
52
|
+
entities.push(name)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return entities
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
export function getQueryableProperties(model: Model, queryableName: string): Record<string, Prop> {
|
|
60
|
+
let queryable = getInterface(model, queryableName)
|
|
61
|
+
let props: Record<string, Prop> = {}
|
|
62
|
+
for (let entityName of getQueryableEntities(model, queryableName)) {
|
|
63
|
+
let entity = getEntity(model, entityName)
|
|
64
|
+
for (let key in queryable.properties) {
|
|
65
|
+
let ep = entity.properties[key]
|
|
66
|
+
if (ep == null) throw new Error(
|
|
67
|
+
`Entity ${entityName} doesn't implement ${queryableName} properly: .${key} property is missing`
|
|
68
|
+
)
|
|
69
|
+
let prop = matchWithQueryableProp(queryable.properties[key], ep)
|
|
70
|
+
if (prop == null) throw new Error(
|
|
71
|
+
`Entity ${entityName} doesn't implement ${queryableName} properly: .${key} property types are incompatible`
|
|
72
|
+
)
|
|
73
|
+
props[key] = prop
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return props
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
function matchWithQueryableProp(queryableProp: Prop, entityProp: Prop): Prop | undefined {
|
|
81
|
+
if (!queryableProp.nullable && entityProp.nullable) return undefined
|
|
82
|
+
let qt = queryableProp.type
|
|
83
|
+
let et = entityProp.type
|
|
84
|
+
switch(et.kind) {
|
|
85
|
+
case 'fk':
|
|
86
|
+
case 'lookup':
|
|
87
|
+
if (qt.kind == 'object' && qt.name == et.entity) {
|
|
88
|
+
return {
|
|
89
|
+
type: et,
|
|
90
|
+
nullable: queryableProp.nullable,
|
|
91
|
+
description: queryableProp.description
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return undefined
|
|
95
|
+
case 'list-lookup':
|
|
96
|
+
if (qt.kind == 'list' && qt.item.type.kind == 'object' && qt.item.type.name == et.entity) {
|
|
97
|
+
return {
|
|
98
|
+
type: et,
|
|
99
|
+
nullable: false,
|
|
100
|
+
description: queryableProp.description
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return undefined
|
|
104
|
+
default:
|
|
105
|
+
if (propTypeEquals(et, qt)) {
|
|
106
|
+
return queryableProp
|
|
107
|
+
}
|
|
108
|
+
return undefined
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
export function getUniversalProperties(model: Model, typeName: string): Record<string, Prop> {
|
|
114
|
+
let item = model[typeName]
|
|
115
|
+
switch(item.kind) {
|
|
116
|
+
case 'entity':
|
|
117
|
+
case 'object':
|
|
118
|
+
return item.properties
|
|
119
|
+
case 'union':
|
|
120
|
+
return getUnionProps(model, typeName).properties
|
|
121
|
+
case 'interface':
|
|
122
|
+
assert(item.queryable)
|
|
123
|
+
return getQueryableProperties(model, typeName)
|
|
124
|
+
default:
|
|
125
|
+
throw unexpectedCase(item.kind)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
37
130
|
export function validateModel(model: Model) {
|
|
38
131
|
// TODO: check all invariants we assume
|
|
39
132
|
validateNames(model)
|
|
40
133
|
validateUnionTypes(model)
|
|
41
134
|
validateLookups(model)
|
|
42
135
|
validateIndexes(model)
|
|
136
|
+
validateQueryableInterfaces(model)
|
|
43
137
|
}
|
|
44
138
|
|
|
45
139
|
|
|
@@ -119,7 +213,7 @@ export function validateLookups(model: Model): void {
|
|
|
119
213
|
if (prop.type.kind == 'lookup' || prop.type.kind == 'list-lookup') {
|
|
120
214
|
let lookupEntity = getEntity(model, prop.type.entity)
|
|
121
215
|
let lookupProperty = lookupEntity.properties[prop.type.field]
|
|
122
|
-
if (lookupProperty?.type.kind != 'fk' || lookupProperty.type.
|
|
216
|
+
if (lookupProperty?.type.kind != 'fk' || lookupProperty.type.entity != name) {
|
|
123
217
|
throw invalidProperty(name, key, `${prop.type.entity}.${prop.type.field} is not a foreign key pointing to ${name}`)
|
|
124
218
|
}
|
|
125
219
|
if (prop.type.kind == 'lookup' && !lookupProperty.unique) {
|
|
@@ -142,7 +236,7 @@ export function validateIndexes(model: Model): void {
|
|
|
142
236
|
index.fields.forEach(f => {
|
|
143
237
|
let prop = item.properties[f.name]
|
|
144
238
|
if (prop == null) throw new Error(
|
|
145
|
-
`Entity ${name} doesn't have a property ${f.name}, but is a part of index`
|
|
239
|
+
`Entity ${name} doesn't have a property ${f.name}, but it is a part of index`
|
|
146
240
|
)
|
|
147
241
|
switch(prop.type.kind) {
|
|
148
242
|
case "scalar":
|
|
@@ -160,6 +254,16 @@ export function validateIndexes(model: Model): void {
|
|
|
160
254
|
}
|
|
161
255
|
|
|
162
256
|
|
|
257
|
+
export function validateQueryableInterfaces(model: Model): void {
|
|
258
|
+
for (let name in model) {
|
|
259
|
+
let item = model[name]
|
|
260
|
+
if (item.kind == 'interface' && item.queryable) {
|
|
261
|
+
getQueryableProperties(model, name)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
|
|
163
267
|
function invalidProperty(item: string, key: string, msg: string): Error {
|
|
164
268
|
return new Error(`Invalid property ${item}.${key}: ${msg}`)
|
|
165
269
|
}
|
|
@@ -167,10 +271,12 @@ function invalidProperty(item: string, key: string, msg: string): Error {
|
|
|
167
271
|
|
|
168
272
|
export function propTypeEquals(a: PropType, b: PropType): boolean {
|
|
169
273
|
if (a.kind != b.kind) return false
|
|
170
|
-
if (a.kind == 'list') return propTypeEquals(a.item.type, (b as typeof a).item.type)
|
|
171
274
|
switch(a.kind) {
|
|
275
|
+
case 'list':
|
|
276
|
+
return a.item.nullable == (b as typeof a).item.nullable
|
|
277
|
+
&& propTypeEquals(a.item.type, (b as typeof a).item.type)
|
|
172
278
|
case 'fk':
|
|
173
|
-
return a.
|
|
279
|
+
return a.entity == (b as typeof a).entity
|
|
174
280
|
case 'lookup':
|
|
175
281
|
case 'list-lookup':
|
|
176
282
|
return a.entity == (b as typeof a).entity && a.field == (b as typeof a).field
|
|
@@ -194,6 +300,13 @@ export function getObject(model: Model, name: string): JsonObject {
|
|
|
194
300
|
}
|
|
195
301
|
|
|
196
302
|
|
|
303
|
+
export function getInterface(model: Model, name: string): Interface {
|
|
304
|
+
let i = model[name]
|
|
305
|
+
assert(i.kind == 'interface', `${name} expected to be an interface`)
|
|
306
|
+
return i
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
|
|
197
310
|
export function getFtsQuery(model: Model, name: string): FTS_Query {
|
|
198
311
|
let query = model[name]
|
|
199
312
|
assert(query.kind == 'fts', `${name} expected to be FTS query`)
|
package/src/model.ts
CHANGED
|
@@ -23,6 +23,7 @@ export interface JsonObject extends TypeMeta {
|
|
|
23
23
|
export interface Interface extends TypeMeta {
|
|
24
24
|
kind: 'interface'
|
|
25
25
|
properties: Record<Name, Prop>
|
|
26
|
+
queryable?: boolean
|
|
26
27
|
}
|
|
27
28
|
|
|
28
29
|
|
|
@@ -79,7 +80,7 @@ export interface ScalarPropType {
|
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
|
|
82
|
-
export type Scalar = 'ID' | 'String' | 'Int' | 'Float' | 'Boolean' | 'DateTime' | 'BigInt' | 'JSON' | 'Bytes'
|
|
83
|
+
export type Scalar = 'ID' | 'String' | 'Int' | 'Float' | 'Boolean' | 'DateTime' | 'BigInt' | 'JSON' | 'Bytes' | 'BigDecimal'
|
|
83
84
|
|
|
84
85
|
|
|
85
86
|
export interface EnumPropType {
|
|
@@ -108,7 +109,7 @@ export interface ListPropType {
|
|
|
108
109
|
|
|
109
110
|
export interface FkPropType {
|
|
110
111
|
kind: 'fk'
|
|
111
|
-
|
|
112
|
+
entity: Name
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
|
package/src/opencrud/orderBy.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import assert from "assert"
|
|
2
2
|
import type {Model} from "../model"
|
|
3
|
-
import {getUnionProps} from
|
|
3
|
+
import {getUnionProps, getUniversalProperties} from '../model.tools'
|
|
4
4
|
import {OrderBy} from "../ir/args"
|
|
5
5
|
|
|
6
6
|
|
|
@@ -19,27 +19,23 @@ export type OpenCrud_OrderBy_Mapping = ReadonlyMap<OpenCrudOrderByValue, OrderBy
|
|
|
19
19
|
const MAPPING_CACHE = new WeakMap<Model, Record<string, OpenCrud_OrderBy_Mapping>>()
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
export function getOrderByMapping(model: Model,
|
|
22
|
+
export function getOrderByMapping(model: Model, typeName: string): OpenCrud_OrderBy_Mapping {
|
|
23
23
|
let cache = MAPPING_CACHE.get(model)
|
|
24
24
|
if (cache == null) {
|
|
25
25
|
cache = {}
|
|
26
26
|
MAPPING_CACHE.set(model, cache)
|
|
27
27
|
}
|
|
28
|
-
if (cache[
|
|
29
|
-
return cache[
|
|
28
|
+
if (cache[typeName]) return cache[typeName]
|
|
29
|
+
return cache[typeName] = buildOrderByMapping(model, typeName, 2)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
function buildOrderByMapping(model: Model, typeName: string, depth: number): OpenCrud_OrderBy_Mapping {
|
|
34
34
|
if (depth <= 0) return new Map()
|
|
35
|
-
let
|
|
36
|
-
if (object.kind == 'union') {
|
|
37
|
-
object = getUnionProps(model, typeName)
|
|
38
|
-
}
|
|
39
|
-
assert(object.kind == 'entity' || object.kind == 'object')
|
|
35
|
+
let properties = getUniversalProperties(model, typeName)
|
|
40
36
|
let m = new Map<string, OrderBy>()
|
|
41
|
-
for (let key in
|
|
42
|
-
let propType =
|
|
37
|
+
for (let key in properties) {
|
|
38
|
+
let propType = properties[key].type
|
|
43
39
|
switch(propType.kind) {
|
|
44
40
|
case 'scalar':
|
|
45
41
|
case 'enum':
|
|
@@ -55,10 +51,6 @@ function buildOrderByMapping(model: Model, typeName: string, depth: number): Ope
|
|
|
55
51
|
}
|
|
56
52
|
break
|
|
57
53
|
case 'fk':
|
|
58
|
-
for (let [name, spec] of buildOrderByMapping(model, propType.foreignEntity, depth - 1)) {
|
|
59
|
-
m.set(key + '_' + name, {[key]: spec})
|
|
60
|
-
}
|
|
61
|
-
break
|
|
62
54
|
case 'lookup':
|
|
63
55
|
for (let [name, spec] of buildOrderByMapping(model, propType.entity, depth - 1)) {
|
|
64
56
|
m.set(key + '_' + name, {[key]: spec})
|
|
@@ -66,12 +58,16 @@ function buildOrderByMapping(model: Model, typeName: string, depth: number): Ope
|
|
|
66
58
|
break
|
|
67
59
|
}
|
|
68
60
|
}
|
|
61
|
+
if (model[typeName].kind == 'interface') {
|
|
62
|
+
m.set('_type_ASC', {_type: 'ASC'})
|
|
63
|
+
m.set('_type_DESC', {_type: 'DESC'})
|
|
64
|
+
}
|
|
69
65
|
return m
|
|
70
66
|
}
|
|
71
67
|
|
|
72
68
|
|
|
73
|
-
export function parseOrderBy(model: Model,
|
|
74
|
-
let mapping = getOrderByMapping(model,
|
|
69
|
+
export function parseOrderBy(model: Model, typeName: string, input: OpenCrudOrderByValue[]): OrderBy {
|
|
70
|
+
let mapping = getOrderByMapping(model, typeName)
|
|
75
71
|
return mergeOrderBy(
|
|
76
72
|
input.map(value => {
|
|
77
73
|
let spec = mapping.get(value)
|