@subsquid/openreader 0.3.1 → 0.4.1
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/dist/db.d.ts +1 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/gql/opencrud.d.ts +1 -0
- package/dist/gql/opencrud.d.ts.map +1 -0
- package/dist/gql/schema.d.ts +1 -0
- package/dist/gql/schema.d.ts.map +1 -0
- package/dist/gql/schema.js +116 -17
- package/dist/gql/schema.js.map +1 -1
- package/dist/main.d.ts +1 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/model.d.ts +9 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.tools.d.ts +2 -0
- package/dist/model.tools.d.ts.map +1 -0
- package/dist/model.tools.js +27 -1
- package/dist/model.tools.js.map +1 -1
- package/dist/orderBy.d.ts +1 -0
- package/dist/orderBy.d.ts.map +1 -0
- package/dist/queryBuilder.d.ts +1 -0
- package/dist/queryBuilder.d.ts.map +1 -0
- package/dist/relayConnection.d.ts +1 -0
- package/dist/relayConnection.d.ts.map +1 -0
- package/dist/requestedFields.d.ts +1 -0
- package/dist/requestedFields.d.ts.map +1 -0
- package/dist/resolver.d.ts +1 -0
- package/dist/resolver.d.ts.map +1 -0
- package/dist/scalars.d.ts +1 -0
- package/dist/scalars.d.ts.map +1 -0
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/test/basic.test.d.ts +2 -0
- package/dist/test/basic.test.d.ts.map +1 -0
- package/dist/test/basic.test.js +286 -0
- package/dist/test/basic.test.js.map +1 -0
- package/dist/test/connection.test.d.ts +2 -0
- package/dist/test/connection.test.d.ts.map +1 -0
- package/dist/test/connection.test.js +193 -0
- package/dist/test/connection.test.js.map +1 -0
- package/dist/test/fts.test.d.ts +2 -0
- package/dist/test/fts.test.d.ts.map +1 -0
- package/dist/test/fts.test.js +110 -0
- package/dist/test/fts.test.js.map +1 -0
- package/dist/test/lists.test.d.ts +2 -0
- package/dist/test/lists.test.d.ts.map +1 -0
- package/dist/test/lists.test.js +266 -0
- package/dist/test/lists.test.js.map +1 -0
- package/dist/test/lookup.test.d.ts +2 -0
- package/dist/test/lookup.test.d.ts.map +1 -0
- package/dist/test/lookup.test.js +109 -0
- package/dist/test/lookup.test.js.map +1 -0
- package/dist/test/scalars.test.d.ts +2 -0
- package/dist/test/scalars.test.d.ts.map +1 -0
- package/dist/test/scalars.test.js +303 -0
- package/dist/test/scalars.test.js.map +1 -0
- package/dist/test/tools.test.d.ts +2 -0
- package/dist/test/tools.test.d.ts.map +1 -0
- package/dist/test/tools.test.js +49 -0
- package/dist/test/tools.test.js.map +1 -0
- package/dist/test/typed-json.test.d.ts +2 -0
- package/dist/test/typed-json.test.d.ts.map +1 -0
- package/dist/test/typed-json.test.js +75 -0
- package/dist/test/typed-json.test.js.map +1 -0
- package/dist/test/unions.test.d.ts +2 -0
- package/dist/test/unions.test.d.ts.map +1 -0
- package/dist/test/unions.test.js +84 -0
- package/dist/test/unions.test.js.map +1 -0
- package/dist/test/util/setup.d.ts +7 -0
- package/dist/test/util/setup.d.ts.map +1 -0
- package/dist/test/util/setup.js +60 -0
- package/dist/test/util/setup.js.map +1 -0
- package/dist/test/where.test.d.ts +2 -0
- package/dist/test/where.test.d.ts.map +1 -0
- package/dist/test/where.test.js +127 -0
- package/dist/test/where.test.js.map +1 -0
- package/dist/tools.d.ts +1 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/util.d.ts +1 -0
- package/dist/util.d.ts.map +1 -0
- package/dist/where.d.ts +1 -0
- package/dist/where.d.ts.map +1 -0
- package/package.json +15 -13
- package/src/db.ts +83 -0
- package/src/gql/opencrud.ts +328 -0
- package/src/gql/schema.ts +463 -0
- package/src/main.ts +51 -0
- package/src/model.tools.ts +201 -0
- package/src/model.ts +137 -0
- package/src/orderBy.ts +105 -0
- package/src/queryBuilder.ts +785 -0
- package/src/relayConnection.ts +80 -0
- package/src/requestedFields.ts +246 -0
- package/src/resolver.ts +199 -0
- package/src/scalars.ts +247 -0
- package/src/server.ts +115 -0
- package/src/test/basic.test.ts +339 -0
- package/src/test/connection.test.ts +195 -0
- package/src/test/fts.test.ts +114 -0
- package/src/test/lists.test.ts +278 -0
- package/src/test/lookup.test.ts +111 -0
- package/src/test/scalars.test.ts +316 -0
- package/src/test/tools.test.ts +27 -0
- package/src/test/typed-json.test.ts +76 -0
- package/src/test/unions.test.ts +85 -0
- package/src/test/util/setup.ts +63 -0
- package/src/test/where.test.ts +135 -0
- package/src/tools.ts +33 -0
- package/src/util.ts +39 -0
- package/src/where.ts +110 -0
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import {useDatabase, useServer} from "./util/setup"
|
|
2
|
+
|
|
3
|
+
describe('AND, OR on entity filters', function () {
|
|
4
|
+
useDatabase([
|
|
5
|
+
`create table item (id text primary key, a int, b int)`,
|
|
6
|
+
`insert into item (id, a, b) values ('1', 1, 1)`,
|
|
7
|
+
`insert into item (id, a, b) values ('2', 2, 2)`,
|
|
8
|
+
`insert into item (id, a, b) values ('3', 3, 2)`,
|
|
9
|
+
`insert into item (id, a, b) values ('4', 4, 4)`,
|
|
10
|
+
`insert into item (id, a, b) values ('5', 5, 4)`,
|
|
11
|
+
`insert into item (id, a, b) values ('6', 5, 6)`,
|
|
12
|
+
])
|
|
13
|
+
|
|
14
|
+
const client = useServer(`
|
|
15
|
+
type Item @entity {
|
|
16
|
+
id: ID!
|
|
17
|
+
a: Int
|
|
18
|
+
b: Int
|
|
19
|
+
}
|
|
20
|
+
`)
|
|
21
|
+
|
|
22
|
+
it('{c, and: {c}}', function () {
|
|
23
|
+
return client.test(`
|
|
24
|
+
query {
|
|
25
|
+
items(where: {a_eq: 1, AND: {b_eq: 1}} orderBy: id_ASC) { id }
|
|
26
|
+
}
|
|
27
|
+
`, {
|
|
28
|
+
items: [
|
|
29
|
+
{id: '1'}
|
|
30
|
+
]
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('{and: {and: {c}, c}}', function () {
|
|
35
|
+
return client.test(`
|
|
36
|
+
query {
|
|
37
|
+
items(where: {AND: {b_eq: 2, AND: {a_eq: 3}}} orderBy: id_ASC) { id }
|
|
38
|
+
}
|
|
39
|
+
`, {
|
|
40
|
+
items: [
|
|
41
|
+
{id: '3'}
|
|
42
|
+
]
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it('{and: [{c}, {c}]}', function () {
|
|
47
|
+
return client.test(`
|
|
48
|
+
query {
|
|
49
|
+
items(where: {AND: [{a_eq: 2}, {b_eq: 2}]} orderBy: id_ASC) { id }
|
|
50
|
+
}
|
|
51
|
+
`, {
|
|
52
|
+
items: [
|
|
53
|
+
{id: '2'}
|
|
54
|
+
]
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
it('{c, {or: {c}}}', function () {
|
|
59
|
+
return client.test(`
|
|
60
|
+
query {
|
|
61
|
+
items(where: {a_eq: 1, OR: {a_eq: 2}} orderBy: id_ASC) { id }
|
|
62
|
+
}
|
|
63
|
+
`, {
|
|
64
|
+
items: [
|
|
65
|
+
{id: '1'},
|
|
66
|
+
{id: '2'}
|
|
67
|
+
]
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
it('{or: [{c}, {c}]}', function () {
|
|
72
|
+
return client.test(`
|
|
73
|
+
query {
|
|
74
|
+
items(where: {OR: [{a_eq: 2}, {a_eq: 3}]} orderBy: id_ASC) { id }
|
|
75
|
+
}
|
|
76
|
+
`, {
|
|
77
|
+
items: [
|
|
78
|
+
{id: '2'},
|
|
79
|
+
{id: '3'}
|
|
80
|
+
]
|
|
81
|
+
})
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('{or: {or: {c}, c}}', function () {
|
|
85
|
+
return client.test(`
|
|
86
|
+
query {
|
|
87
|
+
items(where: {OR: {a_eq: 1, OR: {b_eq: 2}}} orderBy: id_ASC) { id }
|
|
88
|
+
}
|
|
89
|
+
`, {
|
|
90
|
+
items: [
|
|
91
|
+
{id: '1'},
|
|
92
|
+
{id: '2'},
|
|
93
|
+
{id: '3'}
|
|
94
|
+
]
|
|
95
|
+
})
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
it('{and: [{or: {c}, c}, {or: {c}, c}]}', function () {
|
|
99
|
+
return client.test(`
|
|
100
|
+
query {
|
|
101
|
+
items(where: {AND: [{OR: {a_eq: 5}, a_eq: 4}, {OR: {b_eq: 2}, b_eq: 4}]} orderBy: id_ASC) { id }
|
|
102
|
+
}
|
|
103
|
+
`, {
|
|
104
|
+
items: [
|
|
105
|
+
{id: '4'},
|
|
106
|
+
{id: '5'}
|
|
107
|
+
]
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
it('{c, and: {c}, or: {c}}', function () {
|
|
112
|
+
return client.test(`
|
|
113
|
+
query {
|
|
114
|
+
items(where: { a_eq: 4, AND: {b_eq: 4}, OR: {b_eq: 6} } orderBy: id_ASC) { id }
|
|
115
|
+
}
|
|
116
|
+
`, {
|
|
117
|
+
items: [
|
|
118
|
+
{id: '4'},
|
|
119
|
+
{id: '6'}
|
|
120
|
+
]
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('handles empty wheres', function () {
|
|
125
|
+
return client.test(`
|
|
126
|
+
query {
|
|
127
|
+
items(where: { a_eq: 4, AND: { OR: {}, AND: {} }, OR: { OR: {AND: {} } } } orderBy: id_ASC) { id }
|
|
128
|
+
}
|
|
129
|
+
`, {
|
|
130
|
+
items: [
|
|
131
|
+
{id: '4'}
|
|
132
|
+
]
|
|
133
|
+
})
|
|
134
|
+
})
|
|
135
|
+
})
|
package/src/tools.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {mergeTypeDefs} from "@graphql-tools/merge"
|
|
2
|
+
import * as fs from "fs"
|
|
3
|
+
import * as path from "path"
|
|
4
|
+
import {parse, Source} from "graphql"
|
|
5
|
+
import {buildModel, buildSchema} from "./gql/schema"
|
|
6
|
+
import type {Model} from "./model"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export function loadModel(schemaFile: string): Model {
|
|
10
|
+
let files: string[] = []
|
|
11
|
+
if (fs.statSync(schemaFile).isDirectory()) {
|
|
12
|
+
fs.readdirSync(schemaFile, {withFileTypes: true}).forEach(item => {
|
|
13
|
+
if (item.isFile() && (item.name.endsWith('.graphql') || item.name.endsWith('.gql'))) {
|
|
14
|
+
files.push(path.join(schemaFile, item.name))
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
} else {
|
|
18
|
+
files.push(schemaFile)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let docs = files.map(f => {
|
|
22
|
+
let src = new Source(
|
|
23
|
+
fs.readFileSync(f, 'utf-8'),
|
|
24
|
+
f
|
|
25
|
+
)
|
|
26
|
+
return parse(src)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
if (docs.length == 0) return {}
|
|
30
|
+
let doc = docs.length == 1 ? docs[0] : mergeTypeDefs(docs)
|
|
31
|
+
let schema = buildSchema(doc)
|
|
32
|
+
return buildModel(schema)
|
|
33
|
+
}
|
package/src/util.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {toCamelCase, toPlural, toSnakeCase} from "@subsquid/util"
|
|
2
|
+
import assert from "assert"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export function toQueryListField(entityName: string): string {
|
|
6
|
+
return toPlural(toCamelCase(entityName))
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export function toColumn(gqlFieldName: string): string {
|
|
11
|
+
return toSnakeCase(gqlFieldName)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export function toFkColumn(gqlFieldName: string): string {
|
|
16
|
+
return toSnakeCase(gqlFieldName) + '_id'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
export function toTable(entityName: string): string {
|
|
21
|
+
return toSnakeCase(entityName)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
export function ensureArray<T>(item: T | T[]): T[] {
|
|
26
|
+
return Array.isArray(item) ? item : [item]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
export function unsupportedCase(value: string): Error {
|
|
31
|
+
return new Error(`Unsupported case: ${value}`)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
export function toInt(val: number | string): number {
|
|
36
|
+
let i = parseInt(val as string)
|
|
37
|
+
assert(!isNaN(i) && isFinite(i))
|
|
38
|
+
return i
|
|
39
|
+
}
|
package/src/where.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
|
|
2
|
+
export type WhereOp =
|
|
3
|
+
'-' | // no operator
|
|
4
|
+
'eq' | 'not_eq' |
|
|
5
|
+
'gt' |
|
|
6
|
+
'gte' |
|
|
7
|
+
'lt' |
|
|
8
|
+
'lte' |
|
|
9
|
+
'in' | 'not_in' |
|
|
10
|
+
'contains' | 'not_contains' |
|
|
11
|
+
'startsWith' | 'not_startsWith' |
|
|
12
|
+
'endsWith' | 'not_endsWith' |
|
|
13
|
+
'containsAll' |
|
|
14
|
+
'containsAny' |
|
|
15
|
+
'containsNone' |
|
|
16
|
+
'some' |
|
|
17
|
+
'every' |
|
|
18
|
+
'none'
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
const ENDINGS = [
|
|
22
|
+
'eq',
|
|
23
|
+
'not_eq',
|
|
24
|
+
'gt',
|
|
25
|
+
'gte',
|
|
26
|
+
'lt',
|
|
27
|
+
'lte',
|
|
28
|
+
'in',
|
|
29
|
+
'not_in',
|
|
30
|
+
'contains',
|
|
31
|
+
'not_contains',
|
|
32
|
+
'startsWith',
|
|
33
|
+
'not_startsWith',
|
|
34
|
+
'endsWith',
|
|
35
|
+
'not_endsWith',
|
|
36
|
+
'containsAll',
|
|
37
|
+
'containsAny',
|
|
38
|
+
'containsNone',
|
|
39
|
+
'some',
|
|
40
|
+
'every',
|
|
41
|
+
'none'
|
|
42
|
+
].sort((a, b) => b.length - a.length).map(e => '_' + e)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
function parseEnding(field: string): string {
|
|
46
|
+
for (let i = 0; i < ENDINGS.length; i++) {
|
|
47
|
+
if (field.endsWith(ENDINGS[i])) return ENDINGS[i].slice(1)
|
|
48
|
+
}
|
|
49
|
+
return ''
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
export function parseWhereField(field: string): {op: WhereOp, field: string} {
|
|
54
|
+
let ending = parseEnding(field)
|
|
55
|
+
if (!ending) return {op: '-', field}
|
|
56
|
+
let fieldName = field.slice(0, -(ending.length + 1))
|
|
57
|
+
return {
|
|
58
|
+
op: ending as WhereOp,
|
|
59
|
+
field: fieldName
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
export function hasConditions(where?: any): where is any {
|
|
65
|
+
if (where == null) return false
|
|
66
|
+
for (let key in where) {
|
|
67
|
+
switch(key) {
|
|
68
|
+
case 'AND':
|
|
69
|
+
case 'OR':
|
|
70
|
+
break
|
|
71
|
+
default:
|
|
72
|
+
return true
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (Array.isArray(where.AND)) {
|
|
76
|
+
if (where.AND.some(hasConditions)) return true
|
|
77
|
+
} else if (where.AND && hasConditions(where.AND)) {
|
|
78
|
+
return true
|
|
79
|
+
}
|
|
80
|
+
if (Array.isArray(where.OR)) {
|
|
81
|
+
if (where.OR.some(hasConditions)) return true
|
|
82
|
+
} else if (where.OR && hasConditions(where.OR)) {
|
|
83
|
+
return true
|
|
84
|
+
}
|
|
85
|
+
return false
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
export function whereOpToSqlOperator(op: WhereOp): string {
|
|
90
|
+
switch(op) {
|
|
91
|
+
case 'eq':
|
|
92
|
+
return '='
|
|
93
|
+
case 'not_eq':
|
|
94
|
+
return '!='
|
|
95
|
+
case 'gt':
|
|
96
|
+
return '>'
|
|
97
|
+
case 'gte':
|
|
98
|
+
return '>='
|
|
99
|
+
case 'lt':
|
|
100
|
+
return '<'
|
|
101
|
+
case 'lte':
|
|
102
|
+
return '<='
|
|
103
|
+
case 'in':
|
|
104
|
+
return 'IN'
|
|
105
|
+
case 'not_in':
|
|
106
|
+
return 'NOT IN'
|
|
107
|
+
default:
|
|
108
|
+
throw new Error(`Operator ${op} doesn't have SQL analog`)
|
|
109
|
+
}
|
|
110
|
+
}
|