@smartive/graphql-magic 23.11.0 → 23.12.0-next.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/CHANGELOG.md +3 -2
- package/dist/bin/gqm.cjs +53 -35
- package/dist/cjs/index.cjs +83 -37
- package/dist/esm/db/generate.d.ts +1 -0
- package/dist/esm/db/generate.js +1 -0
- package/dist/esm/db/generate.js.map +1 -1
- package/dist/esm/migrations/generate.js +8 -0
- package/dist/esm/migrations/generate.js.map +1 -1
- package/dist/esm/models/model-definitions.d.ts +5 -0
- package/dist/esm/models/models.d.ts +2 -1
- package/dist/esm/models/models.js +3 -0
- package/dist/esm/models/models.js.map +1 -1
- package/dist/esm/resolvers/resolvers.js +37 -0
- package/dist/esm/resolvers/resolvers.js.map +1 -1
- package/docs/docs/3-fields.md +3 -0
- package/migrations/20230912185644_setup.ts +2 -0
- package/package.json +5 -5
- package/src/bin/gqm/codegen.ts +2 -0
- package/src/db/generate.ts +1 -0
- package/src/migrations/generate.ts +8 -0
- package/src/models/model-definitions.ts +2 -0
- package/src/models/models.ts +6 -0
- package/src/resolvers/resolvers.ts +44 -0
- package/tests/api/__snapshots__/query.spec.ts.snap +19 -0
- package/tests/api/query.spec.ts +17 -0
- package/tests/unit/__snapshots__/resolve.spec.ts.snap +1 -0
- package/tests/utils/database/seed.ts +5 -2
- package/tests/utils/models.ts +6 -0
|
@@ -1,8 +1,39 @@
|
|
|
1
|
+
import { GraphQLScalarType, Kind } from 'graphql';
|
|
1
2
|
import { Models } from '../models/models';
|
|
2
3
|
import { and, isCreatable, isRootModel, isUpdatable, merge, not, typeToField } from '../models/utils';
|
|
3
4
|
import { mutationResolver } from './mutations';
|
|
4
5
|
import { queryResolver } from './resolver';
|
|
5
6
|
|
|
7
|
+
const normalizeTimeToHHmmForSerialize = (value: unknown): string => {
|
|
8
|
+
if (typeof value !== 'string') {
|
|
9
|
+
throw new Error(`Time must be a string in HH:mm format. Received: ${typeof value}`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Postgres `time` columns may serialize to `HH:mm:ss`.
|
|
13
|
+
// Be permissive here and just extract the leading `HH:mm`.
|
|
14
|
+
const match = value.match(/^(\d{2}:\d{2})/);
|
|
15
|
+
if (!match) {
|
|
16
|
+
throw new Error(`Invalid Time value "${value}". Expected HH:mm.`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return match[1];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const normalizeTimeToHHmmForParse = (value: unknown): string => {
|
|
23
|
+
if (typeof value !== 'string') {
|
|
24
|
+
throw new Error(`Time must be a string in HH:mm format. Received: ${typeof value}`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// For input, we only accept time-without-timezone values.
|
|
28
|
+
// Accept `HH:mm` and `HH:mm:ss[.fraction]`, but explicitly reject `Z` and `+/-HH:mm`.
|
|
29
|
+
const match = value.match(/^(\d{2}):(\d{2})(?::\d{2}(?:\.\d+)?)?$/);
|
|
30
|
+
if (!match) {
|
|
31
|
+
throw new Error(`Invalid Time value "${value}". Expected HH:mm.`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return `${match[1]}:${match[2]}`;
|
|
35
|
+
};
|
|
36
|
+
|
|
6
37
|
export const getResolvers = (models: Models) => {
|
|
7
38
|
const resolvers: Record<string, any> = {
|
|
8
39
|
Query: merge([
|
|
@@ -25,6 +56,19 @@ export const getResolvers = (models: Models) => {
|
|
|
25
56
|
[`${model.pluralField}_AGGREGATE`]: queryResolver,
|
|
26
57
|
})),
|
|
27
58
|
]),
|
|
59
|
+
Time: new GraphQLScalarType({
|
|
60
|
+
name: 'Time',
|
|
61
|
+
description: 'Time without date and timezone (HH:mm)',
|
|
62
|
+
serialize: (value) => (value == null ? value : normalizeTimeToHHmmForSerialize(value)),
|
|
63
|
+
parseValue: (value) => normalizeTimeToHHmmForParse(value),
|
|
64
|
+
parseLiteral: (ast) => {
|
|
65
|
+
if (ast.kind !== Kind.STRING) {
|
|
66
|
+
throw new Error(`Invalid literal for Time scalar. Expected STRING, got ${ast.kind}.`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return normalizeTimeToHHmmForParse(ast.value);
|
|
70
|
+
},
|
|
71
|
+
}),
|
|
28
72
|
};
|
|
29
73
|
const mutations = [
|
|
30
74
|
...models.entities.filter(and(not(isRootModel), isCreatable)).map((model) => ({
|
|
@@ -54,6 +54,7 @@ exports[`query can be executed 1`] = `
|
|
|
54
54
|
},
|
|
55
55
|
"field": null,
|
|
56
56
|
"id": "fc4e013e-4cb0-4ef8-9f2e-3d475bdf2b90",
|
|
57
|
+
"time": "09:15",
|
|
57
58
|
"xyz": 2,
|
|
58
59
|
},
|
|
59
60
|
{
|
|
@@ -68,6 +69,7 @@ exports[`query can be executed 1`] = `
|
|
|
68
69
|
},
|
|
69
70
|
"field": "Some value",
|
|
70
71
|
"id": "604ab55d-ec3e-4857-9f27-219158f80e64",
|
|
72
|
+
"time": "14:30",
|
|
71
73
|
"xyz": 1,
|
|
72
74
|
},
|
|
73
75
|
],
|
|
@@ -333,3 +335,20 @@ exports[`query processes reverseFilters correctly 1`] = `
|
|
|
333
335
|
],
|
|
334
336
|
}
|
|
335
337
|
`;
|
|
338
|
+
|
|
339
|
+
exports[`query returns Time values for SomeObject 1`] = `
|
|
340
|
+
{
|
|
341
|
+
"manyObjects": [
|
|
342
|
+
{
|
|
343
|
+
"id": "fc4e013e-4cb0-4ef8-9f2e-3d475bdf2b90",
|
|
344
|
+
"time": "09:15",
|
|
345
|
+
"xyz": 2,
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
"id": "604ab55d-ec3e-4857-9f27-219158f80e64",
|
|
349
|
+
"time": "14:30",
|
|
350
|
+
"xyz": 1,
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
}
|
|
354
|
+
`;
|
package/tests/api/query.spec.ts
CHANGED
|
@@ -12,6 +12,7 @@ describe('query', () => {
|
|
|
12
12
|
id
|
|
13
13
|
field
|
|
14
14
|
xyz
|
|
15
|
+
time
|
|
15
16
|
another {
|
|
16
17
|
id
|
|
17
18
|
manyObjects(where: { id: "${SOME_ID}" }) {
|
|
@@ -26,6 +27,22 @@ describe('query', () => {
|
|
|
26
27
|
});
|
|
27
28
|
});
|
|
28
29
|
|
|
30
|
+
it('returns Time values for SomeObject', async () => {
|
|
31
|
+
await withServer(async (request) => {
|
|
32
|
+
expect(
|
|
33
|
+
await request(gql`
|
|
34
|
+
query GetTimes {
|
|
35
|
+
manyObjects(where: { another: { id: "${ANOTHER_ID}" } }, orderBy: [{ xyz: DESC }]) {
|
|
36
|
+
id
|
|
37
|
+
xyz
|
|
38
|
+
time
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
`),
|
|
42
|
+
).toMatchSnapshot();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
29
46
|
it('processes reverseFilters correctly', async () => {
|
|
30
47
|
await withServer(async (request) => {
|
|
31
48
|
expect(
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Knex } from 'knex';
|
|
2
2
|
import { pick } from 'lodash';
|
|
3
3
|
import { getColumnName, isInTable, modelNeedsTable } from '../../../src';
|
|
4
|
-
import { SeedData } from '../../generated/db';
|
|
5
4
|
import { models } from '../models';
|
|
6
5
|
|
|
7
6
|
export const ADMIN_ID = '04e45b48-04cf-4b38-bb25-b9af5ae0b2c4';
|
|
@@ -16,7 +15,7 @@ export const QUESTION_ID = '3d0f3254-282f-4f1f-95e3-c1f699f3c1e5';
|
|
|
16
15
|
export const ANSWER_ID = 'f2d7b3f1-8ea1-4c2c-91ec-024432da1b0d';
|
|
17
16
|
export const REVIEW_ID = '817c55de-2f77-4159-bd44-9837d868f889';
|
|
18
17
|
|
|
19
|
-
export const seed
|
|
18
|
+
export const seed = {
|
|
20
19
|
User: [
|
|
21
20
|
{
|
|
22
21
|
id: ADMIN_ID,
|
|
@@ -42,6 +41,7 @@ export const seed: SeedData = {
|
|
|
42
41
|
float: 0,
|
|
43
42
|
list: ['A'],
|
|
44
43
|
xyz: 1,
|
|
44
|
+
time: '14:30',
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
id: SOME_ID_2,
|
|
@@ -50,6 +50,7 @@ export const seed: SeedData = {
|
|
|
50
50
|
float: 0.5,
|
|
51
51
|
list: ['B'],
|
|
52
52
|
xyz: 2,
|
|
53
|
+
time: '09:15',
|
|
53
54
|
},
|
|
54
55
|
{
|
|
55
56
|
id: SOME_ID_3,
|
|
@@ -57,6 +58,7 @@ export const seed: SeedData = {
|
|
|
57
58
|
float: 0.5,
|
|
58
59
|
list: ['B'],
|
|
59
60
|
xyz: 2,
|
|
61
|
+
time: '23:45',
|
|
60
62
|
},
|
|
61
63
|
{
|
|
62
64
|
id: SOME_ID_4,
|
|
@@ -64,6 +66,7 @@ export const seed: SeedData = {
|
|
|
64
66
|
float: 0.5,
|
|
65
67
|
list: ['B'],
|
|
66
68
|
xyz: 2,
|
|
69
|
+
time: '00:05',
|
|
67
70
|
},
|
|
68
71
|
],
|
|
69
72
|
Question: [
|
package/tests/utils/models.ts
CHANGED