@auto-engineer/server-generator-apollo-emmett 1.87.0 → 1.89.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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +5 -5
- package/.turbo/turbo-type-check.log +1 -1
- package/CHANGELOG.md +97 -0
- package/dist/src/codegen/extract/messages.d.ts +1 -1
- package/dist/src/codegen/extract/messages.d.ts.map +1 -1
- package/dist/src/codegen/extract/projection.d.ts +1 -1
- package/dist/src/codegen/extract/projection.d.ts.map +1 -1
- package/dist/src/codegen/extract/projection.js +14 -1
- package/dist/src/codegen/extract/projection.js.map +1 -1
- package/dist/src/codegen/extract/slice-normalizer.d.ts.map +1 -1
- package/dist/src/codegen/extract/slice-normalizer.js +14 -0
- package/dist/src/codegen/extract/slice-normalizer.js.map +1 -1
- package/dist/src/codegen/extract/type-helpers.d.ts +10 -0
- package/dist/src/codegen/extract/type-helpers.d.ts.map +1 -1
- package/dist/src/codegen/extract/type-helpers.js +17 -0
- package/dist/src/codegen/extract/type-helpers.js.map +1 -1
- package/dist/src/codegen/scaffoldFromSchema.d.ts.map +1 -1
- package/dist/src/codegen/scaffoldFromSchema.js +6 -4
- package/dist/src/codegen/scaffoldFromSchema.js.map +1 -1
- package/dist/src/codegen/templates/command/decide.specs.specs.ts +599 -34
- package/dist/src/codegen/templates/command/decide.specs.ts +38 -18
- package/dist/src/codegen/templates/command/decide.specs.ts.ejs +65 -6
- package/dist/src/codegen/templates/command/decide.ts.ejs +33 -5
- package/dist/src/codegen/templates/command/mutation.resolver.specs.ts +72 -1
- package/dist/src/codegen/templates/command/mutation.resolver.ts.ejs +1 -1
- package/dist/src/codegen/templates/query/projection.specs.specs.ts +298 -1
- package/dist/src/codegen/templates/query/projection.specs.ts +20 -0
- package/dist/src/codegen/templates/query/projection.specs.ts.ejs +43 -13
- package/dist/src/codegen/templates/query/projection.ts.ejs +5 -0
- package/dist/src/codegen/templates/query/query.resolver.ts.ejs +1 -1
- package/dist/src/codegen/templates/react/react.specs.specs.ts +115 -0
- package/dist/src/codegen/templates/react/react.specs.ts +9 -2
- package/dist/src/codegen/templates/react/react.specs.ts.ejs +1 -3
- package/dist/src/codegen/templates/react/react.ts.ejs +22 -9
- package/dist/src/codegen/templates/react/react.ts.specs.ts +253 -0
- package/dist/src/codegen/templates/react/register.specs.ts +27 -23
- package/dist/src/codegen/templates/react/register.ts.ejs +5 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/ketchup-plan.md +14 -1
- package/package.json +4 -4
- package/src/codegen/extract/messages.ts +1 -1
- package/src/codegen/extract/projection.ts +13 -3
- package/src/codegen/extract/slice-normalizer.specs.ts +83 -0
- package/src/codegen/extract/slice-normalizer.ts +15 -0
- package/src/codegen/extract/type-helpers.specs.ts +77 -1
- package/src/codegen/extract/type-helpers.ts +23 -0
- package/src/codegen/formatTsValueSimple.specs.ts +8 -0
- package/src/codegen/scaffoldFromSchema.ts +8 -4
- package/src/codegen/templates/command/decide.specs.specs.ts +599 -34
- package/src/codegen/templates/command/decide.specs.ts +38 -18
- package/src/codegen/templates/command/decide.specs.ts.ejs +65 -6
- package/src/codegen/templates/command/decide.ts.ejs +33 -5
- package/src/codegen/templates/command/mutation.resolver.specs.ts +72 -1
- package/src/codegen/templates/command/mutation.resolver.ts.ejs +1 -1
- package/src/codegen/templates/query/projection.specs.specs.ts +298 -1
- package/src/codegen/templates/query/projection.specs.ts +20 -0
- package/src/codegen/templates/query/projection.specs.ts.ejs +43 -13
- package/src/codegen/templates/query/projection.ts.ejs +5 -0
- package/src/codegen/templates/query/query.resolver.ts.ejs +1 -1
- package/src/codegen/templates/react/react.specs.specs.ts +115 -0
- package/src/codegen/templates/react/react.specs.ts +9 -2
- package/src/codegen/templates/react/react.specs.ts.ejs +1 -3
- package/src/codegen/templates/react/react.ts.ejs +22 -9
- package/src/codegen/templates/react/react.ts.specs.ts +253 -0
- package/src/codegen/templates/react/register.specs.ts +27 -23
- package/src/codegen/templates/react/register.ts.ejs +5 -1
- package/dist/src/codegen/extract/graphql.d.ts +0 -14
- package/dist/src/codegen/extract/graphql.d.ts.map +0 -1
- package/dist/src/codegen/extract/graphql.js +0 -81
- package/dist/src/codegen/extract/graphql.js.map +0 -1
- package/src/codegen/extract/graphql.ts +0 -103
|
@@ -96,9 +96,9 @@ describe('decide.ts.ejs', () => {
|
|
|
96
96
|
*
|
|
97
97
|
* You should:
|
|
98
98
|
* - Validate the command input fields
|
|
99
|
-
* - Inspect the current domain \`
|
|
100
|
-
* - If invalid, throw one of the following domain errors: \`
|
|
101
|
-
* ⚠️ Error constructors:
|
|
99
|
+
* - Inspect the current domain \`_state\` to determine if the command is allowed
|
|
100
|
+
* - If invalid, throw one of the following domain errors: \`IllegalStateError\`
|
|
101
|
+
* ⚠️ Error constructors: IllegalStateError takes a string message
|
|
102
102
|
* - If valid, return one or more events with the correct structure
|
|
103
103
|
*
|
|
104
104
|
* ⚠️ Only read from inputs — never mutate them. \`evolve.ts\` handles state updates.
|
|
@@ -107,10 +107,12 @@ describe('decide.ts.ejs', () => {
|
|
|
107
107
|
* - Should create listing with valid data
|
|
108
108
|
*/
|
|
109
109
|
|
|
110
|
+
// All event fields come from command input — use ...command.data to pass them through.
|
|
111
|
+
|
|
110
112
|
// return {
|
|
111
113
|
// type: 'ListingCreated',
|
|
112
114
|
// data: { ...command.data },
|
|
113
|
-
// }
|
|
115
|
+
// };
|
|
114
116
|
|
|
115
117
|
throw new IllegalStateError('Not yet implemented: ' + command.type);
|
|
116
118
|
}
|
|
@@ -229,9 +231,9 @@ describe('decide.ts.ejs', () => {
|
|
|
229
231
|
*
|
|
230
232
|
* You should:
|
|
231
233
|
* - Validate the command input fields
|
|
232
|
-
* - Inspect the current domain \`
|
|
233
|
-
* - If invalid, throw one of the following domain errors: \`
|
|
234
|
-
* ⚠️ Error constructors:
|
|
234
|
+
* - Inspect the current domain \`_state\` to determine if the command is allowed
|
|
235
|
+
* - If invalid, throw one of the following domain errors: \`IllegalStateError\`
|
|
236
|
+
* ⚠️ Error constructors: IllegalStateError takes a string message
|
|
235
237
|
* - If valid, return one or more events with the correct structure
|
|
236
238
|
*
|
|
237
239
|
* ⚠️ Only read from inputs — never mutate them. \`evolve.ts\` handles state updates.
|
|
@@ -240,10 +242,18 @@ describe('decide.ts.ejs', () => {
|
|
|
240
242
|
* - Should remove existing listing
|
|
241
243
|
*/
|
|
242
244
|
|
|
245
|
+
// ⚠️ REQUIRED: Your return value MUST include ALL fields defined in the event type.
|
|
246
|
+
// Tests use partial matching and may not check every field — passing tests does NOT mean all fields are present.
|
|
247
|
+
// Do NOT use 'as ListingRemoved' to silence missing fields.
|
|
248
|
+
//
|
|
249
|
+
// Fields from command input → use ...command.data or command.data.<fieldName>
|
|
250
|
+
// Fields NOT in command input → produce dynamically (never hardcode):
|
|
251
|
+
// removedAt: Date — derive from _state, generate at runtime (e.g., crypto.randomUUID()), or compute from command.data
|
|
252
|
+
|
|
243
253
|
// return {
|
|
244
254
|
// type: 'ListingRemoved',
|
|
245
|
-
// data: { ...command.data },
|
|
246
|
-
// }
|
|
255
|
+
// data: { ...command.data, /* + dynamically produce: removedAt */ },
|
|
256
|
+
// };
|
|
247
257
|
|
|
248
258
|
throw new IllegalStateError('Not yet implemented: ' + command.type);
|
|
249
259
|
}
|
|
@@ -382,9 +392,9 @@ describe('decide.ts.ejs', () => {
|
|
|
382
392
|
*
|
|
383
393
|
* You should:
|
|
384
394
|
* - Validate the command input fields
|
|
385
|
-
* - Inspect the current domain \`
|
|
386
|
-
* - If invalid, throw one of the following domain errors: \`
|
|
387
|
-
* ⚠️ Error constructors:
|
|
395
|
+
* - Inspect the current domain \`_state\` to determine if the command is allowed
|
|
396
|
+
* - If invalid, throw one of the following domain errors: \`IllegalStateError\`, \`ValidationError\`
|
|
397
|
+
* ⚠️ Error constructors: IllegalStateError takes a string message, ValidationError takes a string message
|
|
388
398
|
* - If valid, return one or more events with the correct structure
|
|
389
399
|
*
|
|
390
400
|
* ⚠️ Only read from inputs — never mutate them. \`evolve.ts\` handles state updates.
|
|
@@ -397,10 +407,12 @@ describe('decide.ts.ejs', () => {
|
|
|
397
407
|
throw new ValidationError('Title must not be empty');
|
|
398
408
|
}
|
|
399
409
|
|
|
410
|
+
// All event fields come from command input — use ...command.data to pass them through.
|
|
411
|
+
|
|
400
412
|
// return {
|
|
401
413
|
// type: 'ListingCreated',
|
|
402
414
|
// data: { ...command.data },
|
|
403
|
-
// }
|
|
415
|
+
// };
|
|
404
416
|
|
|
405
417
|
throw new IllegalStateError('Not yet implemented: ' + command.type);
|
|
406
418
|
}
|
|
@@ -579,10 +591,10 @@ describe('decide.ts.ejs', () => {
|
|
|
579
591
|
*
|
|
580
592
|
* You should:
|
|
581
593
|
* - Validate the command input fields
|
|
582
|
-
* - Inspect the current domain \`
|
|
594
|
+
* - Inspect the current domain \`_state\` to determine if the command is allowed
|
|
583
595
|
* - Use \`products\` (integration result) to enrich or filter the output
|
|
584
|
-
* - If invalid, throw one of the following domain errors: \`
|
|
585
|
-
* ⚠️ Error constructors:
|
|
596
|
+
* - If invalid, throw one of the following domain errors: \`IllegalStateError\`
|
|
597
|
+
* ⚠️ Error constructors: IllegalStateError takes a string message
|
|
586
598
|
* - If valid, return one or more events with the correct structure
|
|
587
599
|
*
|
|
588
600
|
* ⚠️ Only read from inputs — never mutate them. \`evolve.ts\` handles state updates.
|
|
@@ -599,10 +611,18 @@ describe('decide.ts.ejs', () => {
|
|
|
599
611
|
* - Should suggest items successfully
|
|
600
612
|
*/
|
|
601
613
|
|
|
614
|
+
// ⚠️ REQUIRED: Your return value MUST include ALL fields defined in the event type.
|
|
615
|
+
// Tests use partial matching and may not check every field — passing tests does NOT mean all fields are present.
|
|
616
|
+
// Do NOT use 'as ItemsSuggested' to silence missing fields.
|
|
617
|
+
//
|
|
618
|
+
// Fields from command input → use ...command.data or command.data.<fieldName>
|
|
619
|
+
// Fields NOT in command input → produce dynamically (never hardcode):
|
|
620
|
+
// items: Array<object> — derive from _state, generate at runtime (e.g., crypto.randomUUID()), or compute from command.data
|
|
621
|
+
|
|
602
622
|
// return {
|
|
603
623
|
// type: 'ItemsSuggested',
|
|
604
|
-
// data: { ...command.data },
|
|
605
|
-
// }
|
|
624
|
+
// data: { ...command.data, /* + dynamically produce: items */ },
|
|
625
|
+
// };
|
|
606
626
|
|
|
607
627
|
throw new IllegalStateError('Not yet implemented: ' + command.type);
|
|
608
628
|
}
|
|
@@ -53,6 +53,52 @@ for (const [importPath, eventTypes] of testEventsByPath.entries()) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
const uniqueEventTypes = Array.from(new Set(allEvents.map(e => e?.type).filter(Boolean))).sort();
|
|
56
|
+
|
|
57
|
+
function findDerivedDateInfo(eventResults, commandFieldNames, givenEvents) {
|
|
58
|
+
const givenValues = new Set();
|
|
59
|
+
for (const g of givenEvents || []) {
|
|
60
|
+
for (const val of Object.values(g.exampleData || {})) {
|
|
61
|
+
if (typeof val === 'string') givenValues.add(val);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const fieldsByDate = new Map();
|
|
65
|
+
for (const e of eventResults) {
|
|
66
|
+
for (const [key, val] of Object.entries(e.exampleData || {})) {
|
|
67
|
+
if (
|
|
68
|
+
!commandFieldNames.has(key) &&
|
|
69
|
+
typeof val === 'string' &&
|
|
70
|
+
/^\d{4}-\d{2}-\d{2}$/.test(val) &&
|
|
71
|
+
!givenValues.has(val)
|
|
72
|
+
) {
|
|
73
|
+
if (!fieldsByDate.has(val)) fieldsByDate.set(val, []);
|
|
74
|
+
fieldsByDate.get(val).push(key);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (fieldsByDate.size !== 1) return { date: null, fields: [] };
|
|
79
|
+
const [date, fields] = [...fieldsByDate.entries()][0];
|
|
80
|
+
return { date, fields };
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function isKeyTraceable(key, value, givenEvents) {
|
|
84
|
+
if (value === null || value === undefined || typeof value === 'object') return false;
|
|
85
|
+
for (const g of givenEvents || []) {
|
|
86
|
+
if ((g.exampleData || {})[key] === value) return true;
|
|
87
|
+
}
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function buildKeepFieldNames(eventResults, commandFieldNames, derivedDateFieldNames, givenEvents) {
|
|
92
|
+
const keep = new Set([...commandFieldNames, ...derivedDateFieldNames]);
|
|
93
|
+
for (const e of eventResults) {
|
|
94
|
+
for (const [key, value] of Object.entries(e.exampleData || {})) {
|
|
95
|
+
if (!keep.has(key) && isKeyTraceable(key, value, givenEvents)) {
|
|
96
|
+
keep.add(key);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return keep;
|
|
101
|
+
}
|
|
56
102
|
_%>
|
|
57
103
|
import { describe, it } from 'vitest';
|
|
58
104
|
import { DeciderSpecification } from '@event-driven-io/emmett';
|
|
@@ -74,6 +120,9 @@ describe('<%= ruleDescription %>', () => {
|
|
|
74
120
|
initialState,
|
|
75
121
|
});
|
|
76
122
|
|
|
123
|
+
const expectEvents = (...events: Array<{ type: string; data: unknown }>) =>
|
|
124
|
+
events as Events[];
|
|
125
|
+
|
|
77
126
|
<% for (const { commandName, gwt } of ruleGwts) {
|
|
78
127
|
const schema = commandSchemasByName[commandName];
|
|
79
128
|
const example = gwt.when;
|
|
@@ -97,18 +146,28 @@ describe('<%= ruleDescription %>', () => {
|
|
|
97
146
|
.when({
|
|
98
147
|
type: '<%= example.commandRef %>',
|
|
99
148
|
data: <%- formatDataObject(example.exampleData, schema) %>,
|
|
100
|
-
|
|
149
|
+
<% const commandFieldNames = new Set(schema?.fields?.map(f => f.name) || []);
|
|
150
|
+
const { date: derivedDate, fields: derivedDateFieldNames } = findDerivedDateInfo(eventResults, commandFieldNames, gwt.given);
|
|
151
|
+
const keepFieldNames = buildKeepFieldNames(eventResults, commandFieldNames, derivedDateFieldNames, gwt.given);
|
|
152
|
+
-%>
|
|
153
|
+
metadata: { now: <%= derivedDate ? `new Date('${derivedDate}')` : 'new Date()' %> },
|
|
101
154
|
})
|
|
102
155
|
<% if (errorResult) { %>
|
|
103
156
|
.thenThrows((err) => err instanceof <%= errorResult.errorType %> && err.message === '<%= errorResult.message || '' %>');
|
|
104
157
|
<% } else { %>
|
|
105
158
|
|
|
106
|
-
.then(
|
|
107
|
-
<%- eventResults.map(e =>
|
|
159
|
+
.then(expectEvents(
|
|
160
|
+
<%- eventResults.map(e => {
|
|
161
|
+
const evtSchema = events.find(evt => evt.type === e.eventRef);
|
|
162
|
+
const filteredData = Object.fromEntries(
|
|
163
|
+
Object.entries(e.exampleData || {}).filter(([key]) => keepFieldNames.has(key))
|
|
164
|
+
);
|
|
165
|
+
return `{
|
|
108
166
|
type: '${e.eventRef}',
|
|
109
|
-
data: ${formatDataObject(
|
|
110
|
-
}
|
|
111
|
-
|
|
167
|
+
data: ${formatDataObject(filteredData, evtSchema)}
|
|
168
|
+
}`;
|
|
169
|
+
}).join(',\n ') %>
|
|
170
|
+
));
|
|
112
171
|
<% } %>
|
|
113
172
|
});
|
|
114
173
|
<% } %>
|
|
@@ -60,12 +60,12 @@ case '<%= command %>': {
|
|
|
60
60
|
*
|
|
61
61
|
* You should:
|
|
62
62
|
* - Validate the command input fields
|
|
63
|
-
* - Inspect the current domain `
|
|
63
|
+
* - Inspect the current domain `_state` to determine if the command is allowed
|
|
64
64
|
<% if (integrationReturnType) { -%>
|
|
65
65
|
* - Use `<%= camelCase(integrationReturnType) %>` (integration result) to enrich or filter the output
|
|
66
66
|
<% } -%>
|
|
67
|
-
* - If invalid, throw one of the following domain errors: `
|
|
68
|
-
* ⚠️ Error constructors: NotFoundError takes { id, type, message? }
|
|
67
|
+
* - If invalid, throw one of the following domain errors: `IllegalStateError`<% if (usedErrors.includes('ValidationError')) { %>, `ValidationError`<% } %><% if (usedErrors.includes('NotFoundError')) { %>, `NotFoundError`<% } %>
|
|
68
|
+
* ⚠️ Error constructors: IllegalStateError takes a string message<% if (usedErrors.includes('ValidationError')) { %>, ValidationError takes a string message<% } %><% if (usedErrors.includes('NotFoundError')) { %>, NotFoundError takes { id, type, message? }<% } %>
|
|
69
69
|
* - If valid, return one or more events with the correct structure
|
|
70
70
|
*
|
|
71
71
|
* ⚠️ Only read from inputs — never mutate them. `evolve.ts` handles state updates.
|
|
@@ -95,10 +95,38 @@ throw new <%= error.errorType %>('<%- error.message ?? 'Validation failed' %>');
|
|
|
95
95
|
}
|
|
96
96
|
<% } } -%>
|
|
97
97
|
|
|
98
|
+
<%
|
|
99
|
+
const cmdFieldSet = new Set((commandSchemasByName?.[command]?.fields || []).map(f => f.name));
|
|
100
|
+
const nonCommandFields = [];
|
|
101
|
+
for (const scenario of scenarios) {
|
|
102
|
+
for (const t of scenario.then.filter(t => 'eventRef' in t)) {
|
|
103
|
+
const eventMsg = (messages || []).find(m => m.name === t.eventRef && m.type === 'event');
|
|
104
|
+
for (const f of (eventMsg?.fields || [])) {
|
|
105
|
+
if (!cmdFieldSet.has(f.name) && !nonCommandFields.some(e => e.name === f.name)) {
|
|
106
|
+
nonCommandFields.push(f);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
-%>
|
|
112
|
+
<% if (nonCommandFields.length > 0) { -%>
|
|
113
|
+
// ⚠️ REQUIRED: Your return value MUST include ALL fields defined in the event type.
|
|
114
|
+
// Tests use partial matching and may not check every field — passing tests does NOT mean all fields are present.
|
|
115
|
+
// Do NOT use 'as <%= fallbackEventTypes[0] ? pascalCase(fallbackEventTypes[0]) : 'EventType' %>' to silence missing fields.
|
|
116
|
+
//
|
|
117
|
+
// Fields from command input → use ...command.data or command.data.<fieldName>
|
|
118
|
+
// Fields NOT in command input → produce dynamically (never hardcode):
|
|
119
|
+
<% for (const f of nonCommandFields) { -%>
|
|
120
|
+
// <%= f.name %>: <%= f.type || f.tsType %> — derive from _state, generate at runtime (e.g., crypto.randomUUID()), or compute from command.data
|
|
121
|
+
<% } -%>
|
|
122
|
+
<% } else { -%>
|
|
123
|
+
// All event fields come from command input — use ...command.data to pass them through.
|
|
124
|
+
<% } -%>
|
|
125
|
+
|
|
98
126
|
// return {
|
|
99
127
|
// type: '<%= fallbackEventTypes[0] ?? 'TODO_EVENT_TYPE' %>',
|
|
100
|
-
// data: { ...command.data },
|
|
101
|
-
// }
|
|
128
|
+
// data: { ...command.data<%= nonCommandFields.length > 0 ? `, /* + dynamically produce: ${nonCommandFields.map(f => f.name).join(', ')} */` : '' %> },
|
|
129
|
+
// };
|
|
102
130
|
|
|
103
131
|
throw new IllegalStateError('Not yet implemented: ' + command.type);
|
|
104
132
|
}
|
|
@@ -150,7 +150,7 @@ describe('mutation.resolver.ts.ejs', () => {
|
|
|
150
150
|
specs: [],
|
|
151
151
|
},
|
|
152
152
|
request:
|
|
153
|
-
'mutation AnswerQuestion($input: AnswerQuestionInput!) {
|
|
153
|
+
'mutation AnswerQuestion($input: AnswerQuestionInput!) {\n answerQuestion(input: $input) {\n success\n }\n}',
|
|
154
154
|
server: {
|
|
155
155
|
description: '',
|
|
156
156
|
data: {
|
|
@@ -549,4 +549,75 @@ export class AddItemsToCartResolver {
|
|
|
549
549
|
"
|
|
550
550
|
`);
|
|
551
551
|
});
|
|
552
|
+
|
|
553
|
+
it('uses parsedRequest operationName when it differs from camelCase(cmd.type)', async () => {
|
|
554
|
+
const spec: SpecsSchema = {
|
|
555
|
+
variant: 'specs',
|
|
556
|
+
narratives: [
|
|
557
|
+
{
|
|
558
|
+
name: 'Questionnaires',
|
|
559
|
+
slices: [
|
|
560
|
+
{
|
|
561
|
+
name: 'submit answer',
|
|
562
|
+
type: 'command',
|
|
563
|
+
client: { specs: [] },
|
|
564
|
+
request:
|
|
565
|
+
'mutation SubmitAnswer($input: SubmitAnswerInput!) {\n submitQuestionnaireAnswer(input: $input) {\n success\n }\n}',
|
|
566
|
+
server: {
|
|
567
|
+
description: '',
|
|
568
|
+
data: {
|
|
569
|
+
items: [
|
|
570
|
+
{
|
|
571
|
+
target: { type: 'Event', name: 'AnswerSubmitted' },
|
|
572
|
+
destination: { type: 'stream', pattern: 'questionnaire-participantId' },
|
|
573
|
+
},
|
|
574
|
+
],
|
|
575
|
+
},
|
|
576
|
+
specs: [
|
|
577
|
+
{
|
|
578
|
+
type: 'gherkin',
|
|
579
|
+
feature: '',
|
|
580
|
+
rules: [
|
|
581
|
+
{
|
|
582
|
+
name: 'submit answer',
|
|
583
|
+
examples: [
|
|
584
|
+
{
|
|
585
|
+
name: 'happy path',
|
|
586
|
+
steps: [
|
|
587
|
+
{
|
|
588
|
+
keyword: 'When',
|
|
589
|
+
text: 'SubmitAnswer',
|
|
590
|
+
docString: { participantId: 'p-1', answer: 'Yes' },
|
|
591
|
+
},
|
|
592
|
+
],
|
|
593
|
+
},
|
|
594
|
+
],
|
|
595
|
+
},
|
|
596
|
+
],
|
|
597
|
+
},
|
|
598
|
+
],
|
|
599
|
+
},
|
|
600
|
+
},
|
|
601
|
+
],
|
|
602
|
+
},
|
|
603
|
+
],
|
|
604
|
+
messages: [
|
|
605
|
+
{
|
|
606
|
+
type: 'command',
|
|
607
|
+
name: 'SubmitAnswer',
|
|
608
|
+
fields: [
|
|
609
|
+
{ name: 'participantId', type: 'string', required: true },
|
|
610
|
+
{ name: 'answer', type: 'string', required: true },
|
|
611
|
+
],
|
|
612
|
+
},
|
|
613
|
+
],
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
const { plans } = await generateScaffoldFilePlans(spec.narratives, spec.messages, undefined, 'src/domain/flows');
|
|
617
|
+
const mutationFile = plans.find(
|
|
618
|
+
(p) => p.outputPath.endsWith('mutation.resolver.ts') && p.contents.includes('export class SubmitAnswerResolver'),
|
|
619
|
+
);
|
|
620
|
+
|
|
621
|
+
expect(mutationFile?.contents).toContain('async submitQuestionnaireAnswer(');
|
|
622
|
+
});
|
|
552
623
|
});
|
|
@@ -82,7 +82,7 @@ if (isInlineObjectArray(tsType)) { %>
|
|
|
82
82
|
@Resolver()
|
|
83
83
|
export class <%= pascalCase(cmd.type) %>Resolver {
|
|
84
84
|
@Mutation(() => MutationResponse)
|
|
85
|
-
async <%= camelCase(cmd.type) %>(
|
|
85
|
+
async <%= parsedRequest?.operationName ?? camelCase(cmd.type) %>(
|
|
86
86
|
@Arg('input', () => <%= pascalCase(cmd.type) %>Input) input: <%= pascalCase(cmd.type) %>Input,
|
|
87
87
|
@Ctx() ctx: GraphQLContext,
|
|
88
88
|
): Promise<MutationResponse> {
|