@subsquid/openreader 0.6.0 → 1.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.
- package/README.md +1 -1
- package/dist/gql/opencrud.d.ts.map +1 -1
- package/dist/gql/opencrud.js +13 -8
- package/dist/gql/opencrud.js.map +1 -1
- package/dist/gql/scalars/Bytes.js +6 -6
- package/dist/gql/scalars/Bytes.js.map +1 -1
- package/dist/gql/scalars/JSON.d.ts +3 -0
- package/dist/gql/scalars/JSON.d.ts.map +1 -0
- package/dist/gql/scalars/JSON.js +9 -0
- package/dist/gql/scalars/JSON.js.map +1 -0
- package/dist/gql/scalars/index.d.ts +1 -0
- package/dist/gql/scalars/index.d.ts.map +1 -1
- package/dist/gql/scalars/index.js +3 -1
- package/dist/gql/scalars/index.js.map +1 -1
- package/dist/gql/schema.js +3 -3
- package/dist/gql/schema.js.map +1 -1
- package/dist/orderBy.d.ts.map +1 -1
- package/dist/orderBy.js +4 -2
- package/dist/orderBy.js.map +1 -1
- package/dist/queryBuilder.d.ts.map +1 -1
- package/dist/queryBuilder.js +38 -23
- package/dist/queryBuilder.js.map +1 -1
- package/dist/requestedFields.js +2 -2
- package/dist/requestedFields.js.map +1 -1
- package/dist/resolver.js +8 -8
- package/dist/resolver.js.map +1 -1
- package/dist/test/regressions.test.d.ts +2 -0
- package/dist/test/regressions.test.d.ts.map +1 -0
- package/dist/test/regressions.test.js +39 -0
- package/dist/test/regressions.test.js.map +1 -0
- package/dist/test/scalars.test.js +35 -1
- package/dist/test/scalars.test.js.map +1 -1
- package/dist/test/setup.js +2 -2
- package/dist/test/setup.js.map +1 -1
- package/dist/test/typed-json.test.js +15 -1
- package/dist/test/typed-json.test.js.map +1 -1
- package/dist/tools.d.ts +1 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +20 -1
- package/dist/tools.js.map +1 -1
- package/dist/util.js +5 -5
- package/dist/util.js.map +1 -1
- package/dist/where.d.ts +1 -1
- package/dist/where.d.ts.map +1 -1
- package/dist/where.js +3 -1
- package/dist/where.js.map +1 -1
- package/package.json +12 -9
- package/src/gql/opencrud.ts +7 -1
- package/src/gql/scalars/Bytes.ts +1 -1
- package/src/gql/scalars/JSON.ts +7 -0
- package/src/gql/scalars/index.ts +3 -1
- package/src/gql/schema.ts +1 -1
- package/src/orderBy.ts +4 -2
- package/src/queryBuilder.ts +17 -3
- package/src/requestedFields.ts +1 -1
- package/src/resolver.ts +1 -1
- package/src/test/regressions.test.ts +39 -0
- package/src/test/scalars.test.ts +37 -1
- package/src/test/setup.ts +1 -1
- package/src/test/typed-json.test.ts +16 -1
- package/src/tools.ts +15 -0
- package/src/util.ts +1 -1
- package/src/where.ts +6 -2
package/dist/where.js
CHANGED
package/dist/where.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"where.js","sourceRoot":"","sources":["../src/where.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"where.js","sourceRoot":"","sources":["../src/where.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@subsquid/openreader",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "GraphQL server for squid framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"graphql",
|
|
@@ -23,28 +23,31 @@
|
|
|
23
23
|
"@graphql-tools/merge": "^8",
|
|
24
24
|
"@graphql-tools/utils": "^8",
|
|
25
25
|
"@subsquid/graphiql-console": "^0.2.0",
|
|
26
|
-
"@subsquid/util": "^0.0.
|
|
26
|
+
"@subsquid/util-internal": "^0.0.0",
|
|
27
|
+
"@subsquid/util-internal-code-printer": "^0.0.0",
|
|
28
|
+
"@subsquid/util-naming": "^0.0.0",
|
|
29
|
+
"@subsquid/util-internal-hex": "^0.0.0",
|
|
27
30
|
"apollo-server-core": "^3.6.2",
|
|
28
31
|
"apollo-server-express": "^3.6.2",
|
|
29
|
-
"express": "^4.
|
|
32
|
+
"express": "^4.18.1",
|
|
30
33
|
"graphql": "^15.8.0",
|
|
31
34
|
"graphql-parse-resolve-info": "^4.12.0",
|
|
32
35
|
"pg": "^8.7.3"
|
|
33
36
|
},
|
|
34
37
|
"devDependencies": {
|
|
35
38
|
"@types/express": "^4.17.13",
|
|
36
|
-
"@types/mocha": "^9.1.
|
|
39
|
+
"@types/mocha": "^9.1.1",
|
|
37
40
|
"@types/node": "^16.11.22",
|
|
38
|
-
"@types/pg": "
|
|
41
|
+
"@types/pg": "8.6.4",
|
|
39
42
|
"dotenv": "^10.0.0",
|
|
40
|
-
"expect": "^27.
|
|
43
|
+
"expect": "^27.5.1",
|
|
41
44
|
"gql-test-client": "^0.0.0",
|
|
42
|
-
"mocha": "^9.2.
|
|
45
|
+
"mocha": "^9.2.2",
|
|
43
46
|
"typescript": "~4.5.5"
|
|
44
47
|
},
|
|
45
48
|
"scripts": {
|
|
46
49
|
"build": "rm -rf dist && tsc",
|
|
47
|
-
"test": "make up && sleep
|
|
50
|
+
"test": "make up && sleep 2 && make test test-cockroach && make down || (make down && exit 1)"
|
|
48
51
|
},
|
|
49
|
-
"readme": "# OpenReader\n\nGraphQL server for squid framework. Given [data schema](https://docs.subsquid.io/schema
|
|
52
|
+
"readme": "# OpenReader\n\nGraphQL server for squid framework. Given [data schema](https://docs.subsquid.io/reference/openreader-schema) \nand compatible Postgres database it serves \"read part\" of [OpenCRUD spec](https://www.opencrud.org).\n\n## Usage\n\n```bash\nopenreader schema.graphql\n```\n\nDatabase connection and server port are configured via environment variables:\n\n```\nDB_NAME\nDB_USER\nDB_PASS\nDB_HOST\nDB_PORT\nGRAPHQL_SERVER_PORT\n```\n"
|
|
50
53
|
}
|
package/src/gql/opencrud.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {Output
|
|
1
|
+
import {Output} from "@subsquid/util-internal-code-printer"
|
|
2
|
+
import {toCamelCase, toPlural} from "@subsquid/util-naming"
|
|
2
3
|
import assert from "assert"
|
|
3
4
|
import {DocumentNode, parse, print} from "graphql"
|
|
4
5
|
import type {Dialect} from "../dialect"
|
|
@@ -264,6 +265,11 @@ export function generateOpenCrudQueries(model: Model, dialect: Dialect): string
|
|
|
264
265
|
out.line(`${fieldName}_in: [${graphqlType}!]`)
|
|
265
266
|
out.line(`${fieldName}_not_in: [${graphqlType}!]`)
|
|
266
267
|
}
|
|
268
|
+
|
|
269
|
+
if (graphqlType == 'JSON') {
|
|
270
|
+
out.line(`${fieldName}_jsonContains: ${graphqlType}`)
|
|
271
|
+
out.line(`${fieldName}_jsonHasKey: ${graphqlType}`)
|
|
272
|
+
}
|
|
267
273
|
}
|
|
268
274
|
|
|
269
275
|
function generateUnionType(name: string, union: Union) {
|
package/src/gql/scalars/Bytes.ts
CHANGED
package/src/gql/scalars/index.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import {BigIntScalar} from "./BigInt"
|
|
2
2
|
import {BytesScalar} from "./Bytes"
|
|
3
3
|
import {DateTimeScalar} from "./DateTime"
|
|
4
|
+
import {JSONScalar} from "./JSON"
|
|
4
5
|
|
|
5
6
|
|
|
6
7
|
export const customScalars = {
|
|
7
8
|
BigInt: BigIntScalar,
|
|
8
9
|
Bytes: BytesScalar,
|
|
9
|
-
DateTime: DateTimeScalar
|
|
10
|
+
DateTime: DateTimeScalar,
|
|
11
|
+
JSON: JSONScalar,
|
|
10
12
|
}
|
package/src/gql/schema.ts
CHANGED
package/src/orderBy.ts
CHANGED
|
@@ -50,8 +50,10 @@ function buildOrderByMapping(model: Model, typeName: string, depth: number): Ope
|
|
|
50
50
|
switch(propType.kind) {
|
|
51
51
|
case 'scalar':
|
|
52
52
|
case 'enum':
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
if (propType.name != 'JSON') {
|
|
54
|
+
m.set(key + '_ASC', {[key]: 'ASC'})
|
|
55
|
+
m.set(key + '_DESC', {[key]: 'DESC'})
|
|
56
|
+
}
|
|
55
57
|
break
|
|
56
58
|
case 'object':
|
|
57
59
|
case 'union':
|
package/src/queryBuilder.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {toSnakeCase} from "@subsquid/util"
|
|
1
|
+
import {toSnakeCase} from "@subsquid/util-naming"
|
|
2
2
|
import assert from "assert"
|
|
3
3
|
import {Database} from "./db"
|
|
4
4
|
import type {Dialect} from "./dialect"
|
|
@@ -369,6 +369,12 @@ export class QueryBuilder {
|
|
|
369
369
|
case 'not_containsInsensitive':
|
|
370
370
|
exps.push(`position(lower(${this.param(arg)}) in lower(${lhs})) = 0`)
|
|
371
371
|
break
|
|
372
|
+
case 'jsonContains':
|
|
373
|
+
exps.push(`${lhs} @> ${this.param(arg)}`)
|
|
374
|
+
break
|
|
375
|
+
case 'jsonHasKey':
|
|
376
|
+
exps.push(`${lhs} ? ${this.param(arg)}`)
|
|
377
|
+
break
|
|
372
378
|
default: {
|
|
373
379
|
exps.push(`${lhs} ${whereOpToSqlOperator(op)} ${this.param(arg)}`)
|
|
374
380
|
}
|
|
@@ -465,9 +471,15 @@ export class QueryBuilder {
|
|
|
465
471
|
}
|
|
466
472
|
break
|
|
467
473
|
}
|
|
468
|
-
case 'list-lookup':
|
|
469
|
-
|
|
474
|
+
case 'list-lookup': {
|
|
475
|
+
let rows = row[req.index]
|
|
476
|
+
if (rows == null) {
|
|
477
|
+
rec[req.alias] = []
|
|
478
|
+
} else {
|
|
479
|
+
rec[req.alias] = this.toResult(row[req.index], req.children)
|
|
480
|
+
}
|
|
470
481
|
break
|
|
482
|
+
}
|
|
471
483
|
default:
|
|
472
484
|
throw unsupportedCase((f as any).propType.kind)
|
|
473
485
|
}
|
|
@@ -624,6 +636,8 @@ class Cursor {
|
|
|
624
636
|
return `(${this.prefix}->'${propName}')::numeric`
|
|
625
637
|
case 'Boolean':
|
|
626
638
|
return `(${this.prefix}->>'${propName}')::bool`
|
|
639
|
+
case 'JSON':
|
|
640
|
+
return `${this.prefix}->'${propName}'`
|
|
627
641
|
default:
|
|
628
642
|
return `${this.prefix}->>'${propName}'`
|
|
629
643
|
}
|
package/src/requestedFields.ts
CHANGED
package/src/resolver.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {IFieldResolver, IResolvers} from "@graphql-tools/utils"
|
|
2
|
-
import {toCamelCase} from "@subsquid/util"
|
|
2
|
+
import {toCamelCase} from "@subsquid/util-naming"
|
|
3
3
|
import {UserInputError} from "apollo-server-core"
|
|
4
4
|
import assert from "assert"
|
|
5
5
|
import type {GraphQLResolveInfo} from "graphql"
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {useDatabase, useServer} from "./setup"
|
|
2
|
+
|
|
3
|
+
describe('regressions', function () {
|
|
4
|
+
describe('empty lookup lists', function () {
|
|
5
|
+
useDatabase([
|
|
6
|
+
`create table "order" (id text primary key)`,
|
|
7
|
+
`create table item (id text primary key, order_id text)`,
|
|
8
|
+
`insert into "order" (id) values ('1')`
|
|
9
|
+
])
|
|
10
|
+
|
|
11
|
+
const client = useServer(`
|
|
12
|
+
type Order @entity {
|
|
13
|
+
id: ID!
|
|
14
|
+
items: [Item!]! @derivedFrom(field: "order")
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type Item @entity {
|
|
18
|
+
id: ID!
|
|
19
|
+
order: Order
|
|
20
|
+
}
|
|
21
|
+
`)
|
|
22
|
+
|
|
23
|
+
it('should return empty array for empty lookup list', async function () {
|
|
24
|
+
return client.test(`
|
|
25
|
+
query {
|
|
26
|
+
orders {
|
|
27
|
+
id
|
|
28
|
+
items { id }
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
`, {
|
|
32
|
+
orders: [{
|
|
33
|
+
id: '1',
|
|
34
|
+
items: []
|
|
35
|
+
}]
|
|
36
|
+
})
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
})
|
package/src/test/scalars.test.ts
CHANGED
|
@@ -2,7 +2,7 @@ import {useDatabase, useServer} from "./setup"
|
|
|
2
2
|
|
|
3
3
|
describe('scalars', function() {
|
|
4
4
|
useDatabase([
|
|
5
|
-
`create table scalar (id text primary key, "boolean" bool, "bigint" numeric, "string" text, enum text, date_time timestamptz, "bytes" bytea, deep jsonb)`,
|
|
5
|
+
`create table scalar (id text primary key, "boolean" bool, "bigint" numeric, "string" text, enum text, date_time timestamptz, "bytes" bytea, "json" jsonb, deep jsonb)`,
|
|
6
6
|
`insert into scalar (id, "boolean") values ('1', true)`,
|
|
7
7
|
`insert into scalar (id, "boolean", deep) values ('2', false, '{"boolean": true}'::jsonb)`,
|
|
8
8
|
`insert into scalar (id, "bigint", deep) values ('3', 1000000000000000000000000000000000000, '{"bigint": "1000000000000000000000000000000000000"}'::jsonb)`,
|
|
@@ -21,6 +21,8 @@ describe('scalars', function() {
|
|
|
21
21
|
`insert into scalar (id, "enum") values ('15', 'A')`,
|
|
22
22
|
`insert into scalar (id, "enum") values ('16', 'B')`,
|
|
23
23
|
`insert into scalar (id, "enum") values ('17', 'C')`,
|
|
24
|
+
`insert into scalar (id, "json") values ('18', '{"key1": "value1"}'::jsonb)`,
|
|
25
|
+
`insert into scalar (id, "json") values ('19', '{"key2": "value2"}'::jsonb)`,
|
|
24
26
|
])
|
|
25
27
|
|
|
26
28
|
const client = useServer(`
|
|
@@ -32,6 +34,7 @@ describe('scalars', function() {
|
|
|
32
34
|
bigint: BigInt
|
|
33
35
|
dateTime: DateTime
|
|
34
36
|
bytes: Bytes
|
|
37
|
+
json: JSON,
|
|
35
38
|
deep: DeepScalar
|
|
36
39
|
}
|
|
37
40
|
|
|
@@ -316,4 +319,37 @@ describe('scalars', function() {
|
|
|
316
319
|
})
|
|
317
320
|
})
|
|
318
321
|
})
|
|
322
|
+
|
|
323
|
+
describe('JSON', function () {
|
|
324
|
+
it('outputs correctly', function() {
|
|
325
|
+
return client.test(`
|
|
326
|
+
query {
|
|
327
|
+
scalars(where: {id_in: ["18"]}, orderBy: id_ASC) {
|
|
328
|
+
id
|
|
329
|
+
json
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
`, {
|
|
333
|
+
scalars: [
|
|
334
|
+
{id: '18', json: {'key1': 'value1'}},
|
|
335
|
+
]
|
|
336
|
+
})
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
it('supports where conditions', function () {
|
|
340
|
+
return client.test(`
|
|
341
|
+
query {
|
|
342
|
+
eq: scalars(where: {json_eq: {key1: "value1"}}) { id }
|
|
343
|
+
jsonHasKey: scalars(where: {json_jsonHasKey: "key1"}) { id }
|
|
344
|
+
jsonContains: scalars(where: {json_jsonContains: {key2: "value2"}}) { id }
|
|
345
|
+
missingKey: scalars(where: {json_jsonHasKey: {foo: 1}}) { id }
|
|
346
|
+
}
|
|
347
|
+
`, {
|
|
348
|
+
eq: [{id: '18'}],
|
|
349
|
+
jsonHasKey: [{id: '18'}],
|
|
350
|
+
jsonContains: [{id: '19'}],
|
|
351
|
+
missingKey: []
|
|
352
|
+
})
|
|
353
|
+
})
|
|
354
|
+
})
|
|
319
355
|
})
|
package/src/test/setup.ts
CHANGED
|
@@ -3,7 +3,7 @@ import {useDatabase, useServer} from "./setup"
|
|
|
3
3
|
describe('typed json fields', function () {
|
|
4
4
|
useDatabase([
|
|
5
5
|
`create table entity (id text primary key, a jsonb)`,
|
|
6
|
-
`insert into entity (id, a) values ('1', '{"a": "a", "b": {"b": "b", "e": "1"}}'::jsonb)`,
|
|
6
|
+
`insert into entity (id, a) values ('1', '{"a": "a", "b": {"b": "b", "e": "1"}, "c": [1, 2, 3]}'::jsonb)`,
|
|
7
7
|
`insert into entity (id, a) values ('2', '{"a": "A", "b": {"b": "B", "e": "1"}}'::jsonb)`,
|
|
8
8
|
`insert into entity (id, a) values ('3', '{}'::jsonb)`,
|
|
9
9
|
`insert into entity (id) values ('4')`,
|
|
@@ -17,6 +17,7 @@ describe('typed json fields', function () {
|
|
|
17
17
|
type A {
|
|
18
18
|
a: String
|
|
19
19
|
b: B
|
|
20
|
+
c: JSON
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
type B {
|
|
@@ -44,6 +45,20 @@ describe('typed json fields', function () {
|
|
|
44
45
|
})
|
|
45
46
|
})
|
|
46
47
|
|
|
48
|
+
it('nested JSON scalar', function () {
|
|
49
|
+
return client.test(`
|
|
50
|
+
query {
|
|
51
|
+
entities(where: {id_eq: "1"}) {
|
|
52
|
+
a { c }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
`, {
|
|
56
|
+
entities: [{
|
|
57
|
+
a: {c: [1, 2, 3]}
|
|
58
|
+
}]
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
|
|
47
62
|
it('can fetch deep entities', function () {
|
|
48
63
|
return client.test(`
|
|
49
64
|
query {
|
package/src/tools.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {mergeTypeDefs} from "@graphql-tools/merge"
|
|
|
2
2
|
import * as fs from "fs"
|
|
3
3
|
import * as path from "path"
|
|
4
4
|
import {parse, Source} from "graphql"
|
|
5
|
+
import process from "process"
|
|
5
6
|
import {buildModel, buildSchema} from "./gql/schema"
|
|
6
7
|
import type {Model} from "./model"
|
|
7
8
|
|
|
@@ -31,3 +32,17 @@ export function loadModel(schemaFile: string): Model {
|
|
|
31
32
|
let schema = buildSchema(doc)
|
|
32
33
|
return buildModel(schema)
|
|
33
34
|
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
export function resolveGraphqlSchema(projectDir?: string): string {
|
|
38
|
+
let dir = projectDir || process.cwd()
|
|
39
|
+
let loc = path.resolve(dir, 'schema.graphql')
|
|
40
|
+
if (fs.existsSync(loc)) return loc
|
|
41
|
+
loc = path.resolve(dir, 'schema')
|
|
42
|
+
let stat = fs.statSync(loc, {throwIfNoEntry: false})
|
|
43
|
+
if (stat?.isDirectory()) {
|
|
44
|
+
let hasGraphql = fs.readdirSync(loc).some(item => item.endsWith('.graphql') || item.endsWith('.gql'))
|
|
45
|
+
if (hasGraphql) return loc
|
|
46
|
+
}
|
|
47
|
+
throw new Error(`Failed to locate schema.graphql at ${dir}`)
|
|
48
|
+
}
|
package/src/util.ts
CHANGED
package/src/where.ts
CHANGED
|
@@ -17,7 +17,9 @@ export type WhereOp =
|
|
|
17
17
|
'containsNone' |
|
|
18
18
|
'some' |
|
|
19
19
|
'every' |
|
|
20
|
-
'none'
|
|
20
|
+
'none' |
|
|
21
|
+
'jsonContains' |
|
|
22
|
+
'jsonHasKey'
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
const ENDINGS = [
|
|
@@ -43,7 +45,9 @@ const ENDINGS = [
|
|
|
43
45
|
'containsNone',
|
|
44
46
|
'some',
|
|
45
47
|
'every',
|
|
46
|
-
'none'
|
|
48
|
+
'none',
|
|
49
|
+
'jsonContains',
|
|
50
|
+
'jsonHasKey',
|
|
47
51
|
].sort((a, b) => b.length - a.length).map(e => '_' + e)
|
|
48
52
|
|
|
49
53
|
|