@projectcaluma/ember-testing 9.1.0 → 10.2.0-beta.2
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 +994 -0
- package/addon/mirage-graphql/filters/answer.js +13 -0
- package/addon/mirage-graphql/filters/base.js +47 -20
- package/addon/mirage-graphql/filters/question.js +1 -3
- package/addon/mirage-graphql/filters/work-item.js +22 -2
- package/addon/mirage-graphql/handler.js +25 -7
- package/addon/mirage-graphql/index.js +24 -3
- package/addon/mirage-graphql/mocks/answer.js +8 -33
- package/addon/mirage-graphql/mocks/base.js +105 -42
- package/addon/mirage-graphql/mocks/form.js +25 -100
- package/addon/mirage-graphql/mocks/question.js +17 -119
- package/addon/mirage-graphql/mocks/work-item.js +105 -0
- package/addon/mirage-graphql/schema.graphql +0 -16
- package/addon/scenarios/distribution.js +315 -0
- package/addon-mirage-support/factories/answer.js +4 -2
- package/addon-mirage-support/factories/case.js +3 -2
- package/addon-mirage-support/factories/document.js +5 -2
- package/addon-mirage-support/factories/file.js +3 -2
- package/addon-mirage-support/factories/form.js +5 -2
- package/addon-mirage-support/factories/format-validator.js +5 -2
- package/addon-mirage-support/factories/option.js +4 -1
- package/addon-mirage-support/factories/question.js +6 -2
- package/addon-mirage-support/factories/task.js +6 -5
- package/addon-mirage-support/factories/work-item.js +3 -2
- package/addon-mirage-support/factories/workflow.js +9 -0
- package/addon-mirage-support/models/answer.js +3 -2
- package/addon-mirage-support/models/case.js +2 -1
- package/addon-mirage-support/models/document.js +1 -1
- package/addon-mirage-support/models/file.js +1 -1
- package/addon-mirage-support/models/form.js +2 -2
- package/addon-mirage-support/models/format-validator.js +1 -1
- package/addon-mirage-support/models/option.js +1 -1
- package/addon-mirage-support/models/question.js +5 -3
- package/addon-mirage-support/models/task.js +1 -1
- package/addon-mirage-support/models/work-item.js +3 -1
- package/addon-mirage-support/models/workflow.js +1 -1
- package/index.js +1 -1
- package/package.json +15 -13
- package/addon/mirage-graphql/mocks/case.js +0 -9
- package/addon/mirage-graphql/mocks/task.js +0 -55
- package/addon/mirage-graphql/resolvers/index.js +0 -16
- package/addon/mirage-graphql/serializers/answer.js +0 -14
- package/addon/mirage-graphql/serializers/base.js +0 -13
- package/addon/mirage-graphql/serializers/case.js +0 -11
- package/addon/mirage-graphql/serializers/document.js +0 -11
- package/addon/mirage-graphql/serializers/file.js +0 -12
- package/addon/mirage-graphql/serializers/form.js +0 -11
- package/addon/mirage-graphql/serializers/question.js +0 -14
- package/addon/mirage-graphql/serializers/task.js +0 -16
- package/addon/mirage-graphql/serializers/work-item.js +0 -11
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import BaseFilter from "@projectcaluma/ember-testing/mirage-graphql/filters/base";
|
|
2
|
+
|
|
3
|
+
export default class extends BaseFilter {
|
|
4
|
+
questions(records, value, { invert = false }) {
|
|
5
|
+
return records.filter(
|
|
6
|
+
(record) => invert !== value.includes(record.questionId)
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
question(records, value, { invert = false }) {
|
|
11
|
+
return this.questions(records, [value], { invert });
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -1,39 +1,66 @@
|
|
|
1
|
+
import { camelize } from "@ember/string";
|
|
2
|
+
|
|
1
3
|
export default class {
|
|
2
|
-
constructor(type
|
|
4
|
+
constructor(type) {
|
|
3
5
|
this.type = type;
|
|
4
|
-
this.collection = collection;
|
|
5
|
-
this.db = db;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
_getFilterFns(
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
_getFilterFns(rawFilters) {
|
|
9
|
+
const filters = Array.isArray(rawFilters)
|
|
10
|
+
? // new format
|
|
11
|
+
rawFilters
|
|
12
|
+
.filter((filter) => Object.keys(filter).length !== 0) // filter out empty filters
|
|
13
|
+
.map((filter) => {
|
|
14
|
+
const entries = Object.entries(filter);
|
|
15
|
+
const key = entries[0][0];
|
|
16
|
+
const value = entries[0][1];
|
|
17
|
+
const options = entries
|
|
18
|
+
.slice(1)
|
|
19
|
+
.reduce((opts, [k, v]) => ({ ...opts, [k]: v }), {});
|
|
20
|
+
|
|
21
|
+
return { key, value, options };
|
|
22
|
+
})
|
|
23
|
+
: // old format
|
|
24
|
+
Object.entries(rawFilters).map(([key, value]) => ({
|
|
25
|
+
key,
|
|
26
|
+
value,
|
|
27
|
+
}));
|
|
28
|
+
|
|
29
|
+
return filters.map(({ key, value, options = {} }) => {
|
|
30
|
+
const fn = this[key];
|
|
11
31
|
|
|
12
32
|
return typeof fn === "function"
|
|
13
|
-
? (records) => fn.call(this, records, value)
|
|
33
|
+
? (records) => fn.call(this, records, value, options)
|
|
14
34
|
: (records) => records;
|
|
15
35
|
});
|
|
16
36
|
}
|
|
17
37
|
|
|
38
|
+
sort(records, order) {
|
|
39
|
+
if (!order) return records;
|
|
40
|
+
|
|
41
|
+
return records.sort((a, b) => {
|
|
42
|
+
return (
|
|
43
|
+
order
|
|
44
|
+
.map((o) => {
|
|
45
|
+
const attr = camelize(o.attribute.toLowerCase());
|
|
46
|
+
const direction = o.direction === "ASC" ? -1 : 1;
|
|
47
|
+
|
|
48
|
+
return (b[attr] - a[attr]) * direction;
|
|
49
|
+
})
|
|
50
|
+
.find((result) => result !== 0) ?? 0
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
18
55
|
filter(records, filters) {
|
|
19
|
-
|
|
20
|
-
const filterObj = Array.isArray(filters)
|
|
21
|
-
? filters.length
|
|
22
|
-
? Object.assign(...filters)
|
|
23
|
-
: {}
|
|
24
|
-
: filters;
|
|
25
|
-
|
|
26
|
-
return this._getFilterFns(filterObj).reduce(
|
|
56
|
+
return this._getFilterFns(filters.filter ?? filters).reduce(
|
|
27
57
|
(recs, fn) => fn(recs),
|
|
28
|
-
records
|
|
58
|
+
this.sort(records, filters?.order)
|
|
29
59
|
);
|
|
30
60
|
}
|
|
31
61
|
|
|
32
62
|
find(records, filters) {
|
|
33
|
-
return (
|
|
34
|
-
this._getFilterFns(filters).reduce((recs, fn) => fn(recs), records)[0] ||
|
|
35
|
-
null
|
|
36
|
-
);
|
|
63
|
+
return this.filter(records, filters)[0] || null;
|
|
37
64
|
}
|
|
38
65
|
|
|
39
66
|
slug(records, value) {
|
|
@@ -12,10 +12,8 @@ export default class extends BaseFilter {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
excludeForms(records, value) {
|
|
15
|
-
const forms = this.db.forms.filter(({ slug }) => value.includes(slug));
|
|
16
|
-
|
|
17
15
|
return records.filter(
|
|
18
|
-
({ formIds }) => !
|
|
16
|
+
({ formIds }) => !value.some((id) => (formIds || []).includes(id))
|
|
19
17
|
);
|
|
20
18
|
}
|
|
21
19
|
}
|
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
import BaseFilter from "@projectcaluma/ember-testing/mirage-graphql/filters/base";
|
|
2
2
|
|
|
3
3
|
export default class extends BaseFilter {
|
|
4
|
-
status(records, value) {
|
|
5
|
-
return records.filter(({ status }) => status === value);
|
|
4
|
+
status(records, value, { invert = false }) {
|
|
5
|
+
return records.filter(({ status }) => invert !== (status === value));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
tasks(records, value, { invert = false }) {
|
|
9
|
+
return records.filter((record) => invert !== value.includes(record.taskId));
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
task(records, value, { invert = false }) {
|
|
13
|
+
return this.tasks(records, [value], { invert });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
controllingGroups(records, value, { invert = false }) {
|
|
17
|
+
return records.filter((record) =>
|
|
18
|
+
value.every((g) => invert !== record.controllingGroups?.includes(g))
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
addressedGroups(records, value, { invert = false }) {
|
|
23
|
+
return records.filter((record) =>
|
|
24
|
+
value.every((g) => invert !== record.addressedGroups?.includes(g))
|
|
25
|
+
);
|
|
6
26
|
}
|
|
7
27
|
}
|
|
@@ -1,25 +1,35 @@
|
|
|
1
1
|
import { classify } from "@ember/string";
|
|
2
2
|
import { singularize } from "ember-inflector";
|
|
3
3
|
import { graphql } from "graphql";
|
|
4
|
+
import {
|
|
5
|
+
GraphQLDate as Date,
|
|
6
|
+
GraphQLDateTime as DateTime,
|
|
7
|
+
} from "graphql-iso-date";
|
|
4
8
|
import { addMockFunctionsToSchema, makeExecutableSchema } from "graphql-tools";
|
|
5
|
-
import moment from "moment";
|
|
6
9
|
|
|
7
10
|
import { Mock } from "@projectcaluma/ember-testing/mirage-graphql";
|
|
8
|
-
import
|
|
9
|
-
import rawSchema from "@projectcaluma/ember-testing/mirage-graphql/schema.graphql";
|
|
11
|
+
import typeDefs from "@projectcaluma/ember-testing/mirage-graphql/schema.graphql";
|
|
10
12
|
|
|
11
13
|
export default function (server) {
|
|
12
14
|
return function ({ db }, request) {
|
|
13
15
|
const mocks = db._collections.reduce((m, { name }) => {
|
|
14
16
|
const cls = classify(singularize(name));
|
|
15
|
-
const mock = new Mock(cls,
|
|
17
|
+
const mock = new Mock(cls, server);
|
|
16
18
|
|
|
17
19
|
return { ...m, ...mock.getHandlers() };
|
|
18
20
|
}, {});
|
|
19
21
|
|
|
20
22
|
const schema = makeExecutableSchema({
|
|
21
|
-
typeDefs
|
|
22
|
-
resolvers
|
|
23
|
+
typeDefs,
|
|
24
|
+
resolvers: {
|
|
25
|
+
Date,
|
|
26
|
+
DateTime,
|
|
27
|
+
GenericScalar: {
|
|
28
|
+
serialize(value) {
|
|
29
|
+
return typeof value === "string" ? JSON.parse(value) : value;
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
23
33
|
resolverValidationOptions: { requireResolversForResolveType: false },
|
|
24
34
|
});
|
|
25
35
|
|
|
@@ -29,10 +39,18 @@ export default function (server) {
|
|
|
29
39
|
schema,
|
|
30
40
|
mocks: {
|
|
31
41
|
...mocks,
|
|
32
|
-
Date: () => moment().format(moment.HTML5_FMT.DATE),
|
|
33
42
|
JSONString: () => JSON.stringify({}),
|
|
34
43
|
GenericScalar: () => ({}),
|
|
35
44
|
Node: (_, { id }) => ({ __typename: atob(id).split(":")[0] }),
|
|
45
|
+
SelectedOption: ({ value }) => {
|
|
46
|
+
const option = server.schema.options.findBy({ slug: value });
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
slug: value,
|
|
50
|
+
label: option.label,
|
|
51
|
+
__typename: "SelectedOption",
|
|
52
|
+
};
|
|
53
|
+
},
|
|
36
54
|
},
|
|
37
55
|
preserveResolvers: false,
|
|
38
56
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { dasherize } from "@ember/string";
|
|
1
|
+
import { dasherize, classify } from "@ember/string";
|
|
2
2
|
import require from "require";
|
|
3
3
|
|
|
4
4
|
const importTypeOrBase = (path, type) => {
|
|
@@ -28,8 +28,29 @@ export const register = (tpl) => (target, name, descriptor) => {
|
|
|
28
28
|
return descriptor;
|
|
29
29
|
};
|
|
30
30
|
|
|
31
|
-
export const
|
|
32
|
-
|
|
31
|
+
export const serialize = (deserialized = {}, type) => {
|
|
32
|
+
const __typename = [deserialized.type?.toLowerCase(), type]
|
|
33
|
+
.filter(Boolean)
|
|
34
|
+
.map(classify)
|
|
35
|
+
.join("");
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
...deserialized,
|
|
39
|
+
id: btoa(`${__typename}:${deserialized.id}`),
|
|
40
|
+
__typename,
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const deserialize = (serialized) => {
|
|
45
|
+
let decodedId = serialized.id;
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
decodedId = atob(serialized.id).split(":")[1] || serialized.id;
|
|
49
|
+
} catch (e) {
|
|
50
|
+
// this is expected most times
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return { ...serialized, ...(decodedId ? { id: decodedId } : {}) };
|
|
33
54
|
};
|
|
34
55
|
|
|
35
56
|
export const Filter = function (type, ...args) {
|
|
@@ -4,46 +4,21 @@ import { register } from "@projectcaluma/ember-testing/mirage-graphql";
|
|
|
4
4
|
import BaseMock from "@projectcaluma/ember-testing/mirage-graphql/mocks/base";
|
|
5
5
|
|
|
6
6
|
export default class extends BaseMock {
|
|
7
|
-
@register("Answer")
|
|
8
|
-
handleAnswer({ __typename }) {
|
|
9
|
-
return { __typename };
|
|
10
|
-
}
|
|
11
|
-
|
|
12
7
|
_handleSaveDocumentAnswer(
|
|
13
8
|
_,
|
|
14
|
-
{
|
|
15
|
-
question: questionSlug,
|
|
16
|
-
document: documentId,
|
|
17
|
-
clientMutationId,
|
|
18
|
-
value,
|
|
19
|
-
type,
|
|
20
|
-
}
|
|
9
|
+
{ question: questionId, document: documentId, value, type }
|
|
21
10
|
) {
|
|
22
|
-
const questionId = this.db.questions.findBy({ slug: questionSlug }).id;
|
|
23
|
-
|
|
24
11
|
const answer = this.collection.findBy({ questionId, documentId });
|
|
25
12
|
|
|
26
|
-
|
|
13
|
+
return this.handleSavePayload.fn.call(this, _, {
|
|
27
14
|
input: {
|
|
28
|
-
id: answer
|
|
15
|
+
id: answer?.id,
|
|
29
16
|
type,
|
|
30
17
|
value,
|
|
31
18
|
documentId,
|
|
32
19
|
questionId,
|
|
33
|
-
clientMutationId,
|
|
34
20
|
},
|
|
35
21
|
});
|
|
36
|
-
|
|
37
|
-
// Default answers don't have a document.
|
|
38
|
-
if (res.answer.documentId) {
|
|
39
|
-
const doc = this.db.documents.findBy({ id: res.answer.documentId });
|
|
40
|
-
|
|
41
|
-
this.db.documents.update(doc.id, {
|
|
42
|
-
answerIds: [...new Set([...(doc.answerIds || []), res.answer.id])],
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return res;
|
|
47
22
|
}
|
|
48
23
|
|
|
49
24
|
@register("SaveDocumentStringAnswerPayload")
|
|
@@ -51,7 +26,7 @@ export default class extends BaseMock {
|
|
|
51
26
|
handleSaveDocumentStringAnswer(_, { input }) {
|
|
52
27
|
return this._handleSaveDocumentAnswer(_, {
|
|
53
28
|
...input,
|
|
54
|
-
value: String(input.value),
|
|
29
|
+
value: input.value ? String(input.value) : null,
|
|
55
30
|
type: "STRING",
|
|
56
31
|
});
|
|
57
32
|
}
|
|
@@ -61,7 +36,7 @@ export default class extends BaseMock {
|
|
|
61
36
|
handleSaveIntegerAnswer(_, { input }) {
|
|
62
37
|
return this._handleSaveDocumentAnswer(_, {
|
|
63
38
|
...input,
|
|
64
|
-
value: parseInt(input.value),
|
|
39
|
+
value: input.value ? parseInt(input.value) : null,
|
|
65
40
|
type: "INTEGER",
|
|
66
41
|
});
|
|
67
42
|
}
|
|
@@ -71,7 +46,7 @@ export default class extends BaseMock {
|
|
|
71
46
|
handleSaveFloatAnswer(_, { input }) {
|
|
72
47
|
return this._handleSaveDocumentAnswer(_, {
|
|
73
48
|
...input,
|
|
74
|
-
value: parseFloat(input.value),
|
|
49
|
+
value: input.value ? parseFloat(input.value) : null,
|
|
75
50
|
type: "FLOAT",
|
|
76
51
|
});
|
|
77
52
|
}
|
|
@@ -81,7 +56,7 @@ export default class extends BaseMock {
|
|
|
81
56
|
handleSaveListAnswer(_, { input }) {
|
|
82
57
|
return this._handleSaveDocumentAnswer(_, {
|
|
83
58
|
...input,
|
|
84
|
-
value: [...input.value].map(String),
|
|
59
|
+
value: input.value ? [...input.value].map(String) : null,
|
|
85
60
|
type: "LIST",
|
|
86
61
|
});
|
|
87
62
|
}
|
|
@@ -90,7 +65,7 @@ export default class extends BaseMock {
|
|
|
90
65
|
handleSaveFileAnswer(_, { input }) {
|
|
91
66
|
return this._handleSaveDocumentAnswer(_, {
|
|
92
67
|
...input,
|
|
93
|
-
value: { metadata: { object_name: input.value } },
|
|
68
|
+
value: input.value ? { metadata: { object_name: input.value } } : null,
|
|
94
69
|
type: "FILE",
|
|
95
70
|
});
|
|
96
71
|
}
|
|
@@ -1,24 +1,70 @@
|
|
|
1
|
-
import { camelize, dasherize } from "@ember/string";
|
|
1
|
+
import { camelize, dasherize, classify } from "@ember/string";
|
|
2
|
+
import faker from "@faker-js/faker";
|
|
3
|
+
import { singularize, pluralize } from "ember-inflector";
|
|
2
4
|
import { MockList } from "graphql-tools";
|
|
3
5
|
|
|
4
6
|
import {
|
|
5
7
|
Filter,
|
|
6
|
-
Serializer,
|
|
7
8
|
register,
|
|
9
|
+
serialize,
|
|
10
|
+
deserialize,
|
|
8
11
|
} from "@projectcaluma/ember-testing/mirage-graphql";
|
|
9
12
|
|
|
13
|
+
export const ANSWER_TYPES = [
|
|
14
|
+
"DATE",
|
|
15
|
+
"FILE",
|
|
16
|
+
"FLOAT",
|
|
17
|
+
"INTEGER",
|
|
18
|
+
"LIST",
|
|
19
|
+
"STRING",
|
|
20
|
+
"TABLE",
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
export const QUESTION_TYPES = [
|
|
24
|
+
"ACTION_BUTTON",
|
|
25
|
+
"CALCULATED_FLOAT",
|
|
26
|
+
"CHOICE",
|
|
27
|
+
"DATE",
|
|
28
|
+
"DYNAMIC_CHOICE",
|
|
29
|
+
"DYNAMIC_MULTIPLE_CHOICE",
|
|
30
|
+
"FILE",
|
|
31
|
+
"FLOAT",
|
|
32
|
+
"FORM",
|
|
33
|
+
"INTEGER",
|
|
34
|
+
"MULTIPLE_CHOICE",
|
|
35
|
+
"STATIC",
|
|
36
|
+
"TABLE",
|
|
37
|
+
"TEXT",
|
|
38
|
+
"TEXTAREA",
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
export const TASK_TYPES = [
|
|
42
|
+
"SIMPLE",
|
|
43
|
+
"COMPLETE_WORKFLOW_FORM",
|
|
44
|
+
"COMPLETE_TASK_FORM",
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
export const TYPE_MAPPING = {
|
|
48
|
+
Answer: ANSWER_TYPES,
|
|
49
|
+
Question: QUESTION_TYPES,
|
|
50
|
+
Task: TASK_TYPES,
|
|
51
|
+
};
|
|
52
|
+
|
|
10
53
|
export default class {
|
|
11
|
-
constructor(type,
|
|
54
|
+
constructor(type, server) {
|
|
12
55
|
this.type = type;
|
|
13
|
-
this.collection = collection;
|
|
14
|
-
this.db = db;
|
|
15
56
|
this.server = server;
|
|
57
|
+
this.schema = server.schema;
|
|
58
|
+
|
|
59
|
+
this.filter = new Filter(type);
|
|
60
|
+
}
|
|
16
61
|
|
|
17
|
-
|
|
18
|
-
this.
|
|
62
|
+
get collection() {
|
|
63
|
+
return this.schema[pluralize(camelize(this.type))];
|
|
19
64
|
}
|
|
20
65
|
|
|
21
66
|
getHandlers() {
|
|
67
|
+
const types = TYPE_MAPPING[this.type];
|
|
22
68
|
const handlers = (target) => {
|
|
23
69
|
const proto = Reflect.getPrototypeOf(target);
|
|
24
70
|
const res = Object.values(proto);
|
|
@@ -37,10 +83,26 @@ export default class {
|
|
|
37
83
|
...handlers,
|
|
38
84
|
// Mocks can have multiple handlers per type.
|
|
39
85
|
...handler.__handlerFor.reduce((targets, target) => {
|
|
86
|
+
const handlerName = target.replace(/\{type\}/, this.type);
|
|
87
|
+
const baseHandlerName = handlerName.replace(/\{subtype\}/, "");
|
|
88
|
+
const fn = (...args) => handler.fn.apply(this, args);
|
|
89
|
+
|
|
90
|
+
const newHandlers = types
|
|
91
|
+
? types.reduce(
|
|
92
|
+
(typeHandlers, type) => ({
|
|
93
|
+
...typeHandlers,
|
|
94
|
+
[handlerName.replace(
|
|
95
|
+
/\{subtype\}/,
|
|
96
|
+
classify(type.toLowerCase())
|
|
97
|
+
)]: fn,
|
|
98
|
+
}),
|
|
99
|
+
{}
|
|
100
|
+
)
|
|
101
|
+
: { [baseHandlerName]: fn };
|
|
102
|
+
|
|
40
103
|
return {
|
|
41
104
|
...targets,
|
|
42
|
-
|
|
43
|
-
handler.fn.apply(this, args),
|
|
105
|
+
...newHandlers,
|
|
44
106
|
};
|
|
45
107
|
}, {}),
|
|
46
108
|
};
|
|
@@ -51,21 +113,23 @@ export default class {
|
|
|
51
113
|
}
|
|
52
114
|
|
|
53
115
|
@register("{type}Connection")
|
|
54
|
-
handleConnection(root, vars) {
|
|
116
|
+
handleConnection(root, vars, _, { fieldName }) {
|
|
55
117
|
let records = this.filter.filter(
|
|
56
|
-
this.collection,
|
|
57
|
-
|
|
118
|
+
this.collection.all().models,
|
|
119
|
+
deserialize(vars)
|
|
58
120
|
);
|
|
59
121
|
|
|
60
|
-
const relKey = `${
|
|
122
|
+
const relKey = `${singularize(fieldName)}Ids`;
|
|
61
123
|
if (root && Object.prototype.hasOwnProperty.call(root, relKey)) {
|
|
62
124
|
const ids = root[relKey];
|
|
63
|
-
records = records
|
|
125
|
+
records = records
|
|
126
|
+
.filter(({ id }) => ids && ids.includes(id))
|
|
127
|
+
.sort((a, b) => ids.indexOf(a.id) - ids.indexOf(b.id));
|
|
64
128
|
}
|
|
65
129
|
|
|
66
130
|
// add base64 encoded index as cursor to records
|
|
67
131
|
records = records.map((record, index) => ({
|
|
68
|
-
...record,
|
|
132
|
+
...record.toJSON(),
|
|
69
133
|
_cursor: btoa(index),
|
|
70
134
|
}));
|
|
71
135
|
|
|
@@ -91,46 +155,47 @@ export default class {
|
|
|
91
155
|
edges: () =>
|
|
92
156
|
new MockList(records.length, () => ({
|
|
93
157
|
node: (r, v, _, meta) =>
|
|
94
|
-
|
|
158
|
+
serialize(records[meta.path.prev.key], this.type),
|
|
95
159
|
})),
|
|
96
160
|
};
|
|
97
161
|
}
|
|
98
162
|
|
|
99
|
-
@register("{type}")
|
|
100
|
-
handle(root, vars) {
|
|
163
|
+
@register("{subtype}{type}")
|
|
164
|
+
handle(root, vars, _, { fieldName }) {
|
|
101
165
|
// If the parent node already resolved this branch in the graph, return it
|
|
102
166
|
// directly without mocking it
|
|
103
167
|
if (
|
|
104
168
|
root &&
|
|
105
|
-
|
|
169
|
+
fieldName !== "node" &&
|
|
170
|
+
Object.prototype.hasOwnProperty.call(root, fieldName)
|
|
106
171
|
) {
|
|
107
|
-
return root[
|
|
172
|
+
return root[fieldName];
|
|
108
173
|
}
|
|
109
174
|
|
|
110
175
|
// If the parent node provides an ID for this relation, filter our mock data
|
|
111
176
|
// with that given ID
|
|
177
|
+
const relKey = `${fieldName}Id`;
|
|
112
178
|
if (
|
|
113
179
|
root &&
|
|
114
|
-
|
|
180
|
+
fieldName !== "node" &&
|
|
181
|
+
Object.prototype.hasOwnProperty.call(root, relKey)
|
|
115
182
|
) {
|
|
116
|
-
vars = { id: root[
|
|
183
|
+
vars = { id: root[relKey] };
|
|
117
184
|
}
|
|
118
185
|
|
|
119
|
-
const record = this.
|
|
120
|
-
this.collection,
|
|
121
|
-
this.serializer.deserialize(vars)
|
|
122
|
-
);
|
|
186
|
+
const record = this.collection.findBy(deserialize(vars));
|
|
123
187
|
|
|
124
|
-
return record &&
|
|
188
|
+
return record && serialize(record.toJSON(), this.type);
|
|
125
189
|
}
|
|
126
190
|
|
|
127
|
-
@register("Save{type}Payload")
|
|
128
|
-
handleSavePayload(
|
|
191
|
+
@register("Save{subtype}{type}Payload")
|
|
192
|
+
handleSavePayload(
|
|
193
|
+
_,
|
|
194
|
+
{ input: { clientMutationId = faker.datatype.uuid(), slug, id, ...args } }
|
|
195
|
+
) {
|
|
129
196
|
const identifier = slug ? { slug } : { id };
|
|
130
197
|
|
|
131
|
-
const relKeys = this.
|
|
132
|
-
this.type.toLowerCase()
|
|
133
|
-
).foreignKeys;
|
|
198
|
+
const relKeys = this.schema.modelFor(camelize(this.type)).foreignKeys;
|
|
134
199
|
|
|
135
200
|
const parsedArgs = Object.entries(args).reduce((parsed, [key, value]) => {
|
|
136
201
|
const re = new RegExp(`${camelize(key)}Id(s)?`);
|
|
@@ -138,16 +203,17 @@ export default class {
|
|
|
138
203
|
|
|
139
204
|
return {
|
|
140
205
|
...parsed,
|
|
141
|
-
[relKey ?? key]: value,
|
|
206
|
+
...(value === undefined ? {} : { [relKey ?? key]: value }),
|
|
142
207
|
};
|
|
143
208
|
}, {});
|
|
144
209
|
|
|
145
|
-
const obj = this.
|
|
210
|
+
const obj = this.collection.findBy(identifier);
|
|
146
211
|
const res = obj
|
|
147
|
-
?
|
|
148
|
-
: this.collection.
|
|
149
|
-
this.
|
|
150
|
-
|
|
212
|
+
? obj.update(deserialize(parsedArgs))
|
|
213
|
+
: this.collection.create(
|
|
214
|
+
this.server.build(
|
|
215
|
+
dasherize(this.type),
|
|
216
|
+
deserialize({
|
|
151
217
|
...identifier,
|
|
152
218
|
...parsedArgs,
|
|
153
219
|
})
|
|
@@ -155,10 +221,7 @@ export default class {
|
|
|
155
221
|
);
|
|
156
222
|
|
|
157
223
|
return {
|
|
158
|
-
[camelize(this.type)]: this.
|
|
159
|
-
...relKeys.reduce((rels, key) => ({ ...rels, [key]: null })),
|
|
160
|
-
...res,
|
|
161
|
-
}),
|
|
224
|
+
[camelize(this.type)]: serialize(res.toJSON(), this.type),
|
|
162
225
|
clientMutationId,
|
|
163
226
|
};
|
|
164
227
|
}
|