@auto-engineer/server-generator-apollo-emmett 0.8.5 → 0.8.6
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 +2 -2
- package/CHANGELOG.md +8 -0
- package/dist/src/codegen/scaffoldFromSchema.d.ts +3 -3
- package/dist/src/codegen/scaffoldFromSchema.d.ts.map +1 -1
- package/dist/src/codegen/scaffoldFromSchema.js +54 -18
- package/dist/src/codegen/scaffoldFromSchema.js.map +1 -1
- package/dist/{codegen → src/codegen}/templates/command/commands.specs.ts +1 -2
- package/dist/{codegen → src/codegen}/templates/command/decide.specs.specs.ts +3 -3
- package/dist/{codegen → src/codegen}/templates/command/decide.specs.ts +1 -5
- package/dist/{codegen → src/codegen}/templates/command/events.specs.ts +1 -2
- package/dist/{codegen → src/codegen}/templates/command/evolve.specs.ts +1 -2
- package/dist/{codegen → src/codegen}/templates/command/handle.specs.ts +1 -3
- package/dist/src/codegen/templates/command/mutation.resolver.specs.ts +363 -0
- package/dist/src/codegen/templates/command/mutation.resolver.ts.ejs +99 -0
- package/dist/{codegen → src/codegen}/templates/command/register.specs.ts +1 -2
- package/dist/{codegen → src/codegen}/templates/command/state.specs.ts +1 -2
- package/dist/{codegen → src/codegen}/templates/query/projection.specs.specs..ts +3 -3
- package/dist/{codegen → src/codegen}/templates/query/projection.specs.ts +5 -9
- package/dist/{codegen → src/codegen}/templates/query/query.resolver.specs.ts +194 -23
- package/dist/src/codegen/templates/query/query.resolver.ts.ejs +137 -0
- package/dist/{codegen → src/codegen}/templates/query/state.specs.ts +1 -2
- package/dist/{codegen → src/codegen}/templates/react/react.specs.specs.ts +2 -2
- package/dist/{codegen → src/codegen}/templates/react/react.specs.ts +3 -3
- package/dist/{codegen → src/codegen}/templates/react/register.specs.ts +3 -3
- package/dist/src/codegen/test-data/specVariant1.d.ts +1 -1
- package/dist/src/codegen/test-data/specVariant1.d.ts.map +1 -1
- package/dist/src/codegen/test-data/specVariant1.js +4 -2
- package/dist/src/codegen/test-data/specVariant1.js.map +1 -1
- package/dist/src/commands/generate-server.d.ts.map +1 -1
- package/dist/src/commands/generate-server.js +34 -24
- package/dist/src/commands/generate-server.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -7
- package/src/codegen/scaffoldFromSchema.ts +52 -20
- package/src/codegen/templates/command/commands.specs.ts +1 -2
- package/src/codegen/templates/command/decide.specs.specs.ts +3 -3
- package/src/codegen/templates/command/decide.specs.ts +1 -5
- package/src/codegen/templates/command/events.specs.ts +1 -2
- package/src/codegen/templates/command/evolve.specs.ts +1 -2
- package/src/codegen/templates/command/handle.specs.ts +1 -3
- package/src/codegen/templates/command/mutation.resolver.specs.ts +247 -8
- package/src/codegen/templates/command/mutation.resolver.ts.ejs +86 -12
- package/src/codegen/templates/command/register.specs.ts +1 -2
- package/src/codegen/templates/command/state.specs.ts +1 -2
- package/src/codegen/templates/query/projection.specs.specs..ts +3 -3
- package/src/codegen/templates/query/projection.specs.ts +5 -9
- package/src/codegen/templates/query/query.resolver.specs.ts +194 -23
- package/src/codegen/templates/query/query.resolver.ts.ejs +84 -45
- package/src/codegen/templates/query/state.specs.ts +1 -2
- package/src/codegen/templates/react/react.specs.specs.ts +2 -2
- package/src/codegen/templates/react/react.specs.ts +3 -3
- package/src/codegen/templates/react/register.specs.ts +3 -3
- package/src/codegen/test-data/specVariant1.ts +5 -3
- package/src/commands/generate-server.ts +38 -30
- package/tsconfig.test.json +9 -0
- package/.turbo/turbo-test.log +0 -14
- package/.turbo/turbo-type-check.log +0 -4
- package/dist/codegen/templates/command/mutation.resolver.specs.ts +0 -124
- package/dist/codegen/templates/command/mutation.resolver.ts.ejs +0 -25
- package/dist/codegen/templates/query/query.resolver.ts.ejs +0 -98
- package/dist/src/codegen/templates/command/commands.specs.d.ts +0 -2
- package/dist/src/codegen/templates/command/commands.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/command/commands.specs.js +0 -96
- package/dist/src/codegen/templates/command/commands.specs.js.map +0 -1
- package/dist/src/codegen/templates/command/decide.specs.d.ts +0 -2
- package/dist/src/codegen/templates/command/decide.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/command/decide.specs.js +0 -567
- package/dist/src/codegen/templates/command/decide.specs.js.map +0 -1
- package/dist/src/codegen/templates/command/decide.specs.specs.d.ts +0 -2
- package/dist/src/codegen/templates/command/decide.specs.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/command/decide.specs.specs.js +0 -278
- package/dist/src/codegen/templates/command/decide.specs.specs.js.map +0 -1
- package/dist/src/codegen/templates/command/events.specs.d.ts +0 -2
- package/dist/src/codegen/templates/command/events.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/command/events.specs.js +0 -112
- package/dist/src/codegen/templates/command/events.specs.js.map +0 -1
- package/dist/src/codegen/templates/command/evolve.specs.d.ts +0 -2
- package/dist/src/codegen/templates/command/evolve.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/command/evolve.specs.js +0 -108
- package/dist/src/codegen/templates/command/evolve.specs.js.map +0 -1
- package/dist/src/codegen/templates/command/handle.specs.d.ts +0 -2
- package/dist/src/codegen/templates/command/handle.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/command/handle.specs.js +0 -326
- package/dist/src/codegen/templates/command/handle.specs.js.map +0 -1
- package/dist/src/codegen/templates/command/mutation.resolver.specs.d.ts +0 -2
- package/dist/src/codegen/templates/command/mutation.resolver.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/command/mutation.resolver.specs.js +0 -121
- package/dist/src/codegen/templates/command/mutation.resolver.specs.js.map +0 -1
- package/dist/src/codegen/templates/command/register.specs.d.ts +0 -2
- package/dist/src/codegen/templates/command/register.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/command/register.specs.js +0 -113
- package/dist/src/codegen/templates/command/register.specs.js.map +0 -1
- package/dist/src/codegen/templates/command/state.specs.d.ts +0 -2
- package/dist/src/codegen/templates/command/state.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/command/state.specs.js +0 -133
- package/dist/src/codegen/templates/command/state.specs.js.map +0 -1
- package/dist/src/codegen/templates/query/projection.specs.d.ts +0 -2
- package/dist/src/codegen/templates/query/projection.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/query/projection.specs.js +0 -363
- package/dist/src/codegen/templates/query/projection.specs.js.map +0 -1
- package/dist/src/codegen/templates/query/projection.specs.specs..d.ts +0 -2
- package/dist/src/codegen/templates/query/projection.specs.specs..d.ts.map +0 -1
- package/dist/src/codegen/templates/query/projection.specs.specs..js +0 -293
- package/dist/src/codegen/templates/query/projection.specs.specs..js.map +0 -1
- package/dist/src/codegen/templates/query/query.resolver.specs.d.ts +0 -2
- package/dist/src/codegen/templates/query/query.resolver.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/query/query.resolver.specs.js +0 -249
- package/dist/src/codegen/templates/query/query.resolver.specs.js.map +0 -1
- package/dist/src/codegen/templates/query/state.specs.d.ts +0 -2
- package/dist/src/codegen/templates/query/state.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/query/state.specs.js +0 -67
- package/dist/src/codegen/templates/query/state.specs.js.map +0 -1
- package/dist/src/codegen/templates/react/react.specs.d.ts +0 -2
- package/dist/src/codegen/templates/react/react.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/react/react.specs.js +0 -265
- package/dist/src/codegen/templates/react/react.specs.js.map +0 -1
- package/dist/src/codegen/templates/react/react.specs.specs.d.ts +0 -2
- package/dist/src/codegen/templates/react/react.specs.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/react/react.specs.specs.js +0 -229
- package/dist/src/codegen/templates/react/react.specs.specs.js.map +0 -1
- package/dist/src/codegen/templates/react/register.specs.d.ts +0 -2
- package/dist/src/codegen/templates/react/register.specs.d.ts.map +0 -1
- package/dist/src/codegen/templates/react/register.specs.js +0 -246
- package/dist/src/codegen/templates/react/register.specs.js.map +0 -1
- /package/dist/{codegen → src/codegen}/templates/command/commands.ts.ejs +0 -0
- /package/dist/{codegen → src/codegen}/templates/command/decide.specs.ts.ejs +0 -0
- /package/dist/{codegen → src/codegen}/templates/command/decide.ts.ejs +0 -0
- /package/dist/{codegen → src/codegen}/templates/command/events.ts.ejs +0 -0
- /package/dist/{codegen → src/codegen}/templates/command/evolve.ts.ejs +0 -0
- /package/dist/{codegen → src/codegen}/templates/command/handle.ts.ejs +0 -0
- /package/dist/{codegen → src/codegen}/templates/command/register.ts.ejs +0 -0
- /package/dist/{codegen → src/codegen}/templates/command/state.ts.ejs +0 -0
- /package/dist/{codegen → src/codegen}/templates/query/projection.specs.ts.ejs +0 -0
- /package/dist/{codegen → src/codegen}/templates/query/projection.ts.ejs +0 -0
- /package/dist/{codegen → src/codegen}/templates/query/state.ts.ejs +0 -0
- /package/dist/{codegen → src/codegen}/templates/react/react.specs.ts.ejs +0 -0
- /package/dist/{codegen → src/codegen}/templates/react/react.ts.ejs +0 -0
- /package/dist/{codegen → src/codegen}/templates/react/register.ts.ejs +0 -0
- /package/dist/{domain → src/domain}/shared/ReadModel.ts +0 -0
- /package/dist/{domain → src/domain}/shared/index.ts +0 -0
- /package/dist/{domain → src/domain}/shared/reactorSpecification.ts +0 -0
- /package/dist/{domain → src/domain}/shared/sendCommand.ts +0 -0
- /package/dist/{domain → src/domain}/shared/types.ts +0 -0
- /package/dist/{server.ts → src/server.ts} +0 -0
- /package/dist/{utils → src/utils}/index.ts +0 -0
- /package/dist/{utils → src/utils}/loadProjections.ts +0 -0
- /package/dist/{utils → src/utils}/loadRegisterFiles.ts +0 -0
- /package/dist/{utils → src/utils}/loadResolvers.ts +0 -0
|
@@ -8,90 +8,129 @@ const message = messages?.find(m => m.name === viewType);
|
|
|
8
8
|
const resolverClassName = `${pascalCase(slice.name)}QueryResolver`;
|
|
9
9
|
const usesID = parsedRequest?.args?.some(arg => graphqlType(arg.tsType) === 'ID');
|
|
10
10
|
|
|
11
|
+
function isInlineObject(ts) {
|
|
12
|
+
return /^\{[\s\S]*\}$/.test((ts ?? '').trim());
|
|
13
|
+
}
|
|
14
|
+
function isInlineObjectArray(ts) {
|
|
15
|
+
const t = (ts ?? '').trim();
|
|
16
|
+
return /^Array<\{[\s\S]*\}>$/.test(t) || /^\{[\s\S]*\}\[\]$/.test(t);
|
|
17
|
+
}
|
|
18
|
+
function baseTs(ts) {
|
|
19
|
+
return (ts ?? 'string').replace(/\s*\|\s*null\b/g, '').trim();
|
|
20
|
+
}
|
|
21
|
+
function fieldUsesDate(ts) {
|
|
22
|
+
const b = baseTs(ts);
|
|
23
|
+
if (b === 'Date') return true;
|
|
24
|
+
if (isInlineObject(b) || isInlineObjectArray(b)) return /:\s*Date\b/.test(b);
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
function fieldUsesJSON(ts) {
|
|
28
|
+
const b = baseTs(ts);
|
|
29
|
+
if (b === 'unknown' || b === 'any' || b === 'object') return true;
|
|
30
|
+
if (isInlineObject(b) || isInlineObjectArray(b)) return /:\s*(unknown|any|object)\b/.test(b);
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const messageFields = message?.fields ?? [];
|
|
35
|
+
const usesDate = messageFields.some(f => fieldUsesDate(f.type)) ||
|
|
36
|
+
(parsedRequest?.args ?? []).some(a => baseTs(a.tsType) === 'Date');
|
|
37
|
+
const usesJSON = messageFields.some(f => fieldUsesJSON(f.type));
|
|
38
|
+
|
|
39
|
+
// Collect embedded types up-front so we can emit them before the parent
|
|
11
40
|
const embeddedTypes = [];
|
|
12
|
-
|
|
13
|
-
|
|
41
|
+
for (const field of messageFields) {
|
|
42
|
+
const tsType = field.type ?? 'string';
|
|
43
|
+
if (isInlineObjectArray(tsType) || isInlineObject(tsType)) {
|
|
44
|
+
embeddedTypes.push({
|
|
45
|
+
typeName: `${viewType}${pascalCase(field.name)}`,
|
|
46
|
+
tsType,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
14
49
|
}
|
|
15
50
|
%>
|
|
16
|
-
import { Query, Resolver, Arg, Ctx, ObjectType, Field<% if (usesID) { %>, ID<% } %> } from 'type-graphql';
|
|
17
|
-
|
|
51
|
+
import { Query, Resolver, Arg, Ctx, ObjectType, Field<% if (usesID) { %>, ID<% } %><% if (usesDate) { %>, GraphQLISODateTime<% } %> } from 'type-graphql';
|
|
52
|
+
<% if (usesJSON) { %>import { GraphQLJSON } from 'graphql-type-json';
|
|
53
|
+
<% } %>import { type GraphQLContext, ReadModel } from '../../../shared';
|
|
54
|
+
|
|
55
|
+
<% // Emit embedded types FIRST — this matches your snapshot order
|
|
56
|
+
for (const { typeName, tsType } of embeddedTypes) {
|
|
57
|
+
// Extract inner "{ ... }" whether Array<{...}> or "{...}[]"
|
|
58
|
+
const inner = tsType.trim().startsWith('Array<')
|
|
59
|
+
? tsType.trim().replace(/^Array<\{/, '{').replace(/}>$/, '}')
|
|
60
|
+
: tsType.trim().replace(/\[\]$/, '');
|
|
61
|
+
const match = inner.match(/^\{([\s\S]*)\}$/);
|
|
62
|
+
const body = match ? match[1] : '';
|
|
63
|
+
const rawFields = body.split(/[,;]\s*/).filter(Boolean);
|
|
64
|
+
const parsedFields = rawFields.map(f => {
|
|
65
|
+
const parts = f.split(':');
|
|
66
|
+
const name = parts[0]?.trim();
|
|
67
|
+
const type = parts.slice(1).join(':').trim();
|
|
68
|
+
if (!name || !type) return null;
|
|
69
|
+
return { name, tsType: type, gqlType: graphqlType(type), nullable: isNullable(type) };
|
|
70
|
+
}).filter(Boolean);
|
|
71
|
+
%>
|
|
72
|
+
@ObjectType()
|
|
73
|
+
export class <%= typeName %> {
|
|
74
|
+
<% for (const f of parsedFields) { %>
|
|
75
|
+
@Field(() => <%= f.gqlType %><%= f.nullable ? ', { nullable: true }' : '' %>)
|
|
76
|
+
<%= f.name %><%= f.nullable ? '?' : '!' %>: <%= toTsFieldType(f.tsType) %>;
|
|
77
|
+
<% } %>
|
|
78
|
+
}
|
|
79
|
+
<% } %>
|
|
18
80
|
|
|
19
81
|
@ObjectType()
|
|
20
82
|
export class <%= viewType %> {
|
|
21
|
-
<% if (
|
|
22
|
-
for (const field of
|
|
23
|
-
const gqlType = graphqlType(field.type ?? 'string');
|
|
83
|
+
<% if (messageFields.length) {
|
|
84
|
+
for (const field of messageFields) {
|
|
24
85
|
const tsType = field.type ?? 'string';
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
if (isInlineArray) {
|
|
29
|
-
embeddedTypes.push({ parentName: viewType, fieldName: field.name, typeName: fieldTypeName, tsType });
|
|
86
|
+
const gqlType = graphqlType(tsType);
|
|
87
|
+
const typeName = `${viewType}${pascalCase(field.name)}`;
|
|
30
88
|
%>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
} %>
|
|
89
|
+
<% if (isInlineObjectArray(tsType)) { %>
|
|
90
|
+
@Field(() => [<%= typeName %>])
|
|
91
|
+
<%= field.name %>!: <%= typeName %>[];
|
|
92
|
+
<% } else if (isInlineObject(tsType)) { %>
|
|
93
|
+
@Field(() => <%= typeName %>)
|
|
94
|
+
<%= field.name %>!: <%= typeName %>;
|
|
95
|
+
<% } else { %>
|
|
96
|
+
@Field(() => <%= gqlType %><%= isNullable(tsType) ? ', { nullable: true }' : '' %>)
|
|
97
|
+
<%= field.name %><%= isNullable(tsType) ? '?' : '!' %>: <%= toTsFieldType(tsType) %>;
|
|
98
|
+
<% } } %>
|
|
38
99
|
[key: string]: unknown;
|
|
39
100
|
<% } else { %>
|
|
40
101
|
[key: string]: unknown;
|
|
41
102
|
<% } %>
|
|
42
103
|
}
|
|
43
104
|
|
|
44
|
-
<% for (const { typeName, tsType } of embeddedTypes) {
|
|
45
|
-
const match = tsType.match(/Array<\{([^}]*)\}>/);
|
|
46
|
-
const rawFields = match?.[1]?.split(/[,;]/) ?? [];
|
|
47
|
-
const parsedFields = rawFields
|
|
48
|
-
.map(f => {
|
|
49
|
-
const [name, type] = f.trim().split(':').map(x => x.trim());
|
|
50
|
-
if (!name || !type) return null;
|
|
51
|
-
return { name, tsType: type, gqlType: graphqlType(type) };
|
|
52
|
-
})
|
|
53
|
-
.filter(Boolean);
|
|
54
|
-
%>
|
|
55
|
-
|
|
56
|
-
@ObjectType()
|
|
57
|
-
export class <%= typeName %> {
|
|
58
|
-
<% for (const f of parsedFields) { %>
|
|
59
|
-
@Field(() => <%= f.gqlType %>)
|
|
60
|
-
<%= f.name %>!: <%= f.tsType %>;
|
|
61
|
-
<% } %>
|
|
62
|
-
}
|
|
63
|
-
<% } %>
|
|
64
|
-
|
|
65
105
|
@Resolver()
|
|
66
106
|
export class <%= resolverClassName %> {
|
|
67
107
|
@Query(() => [<%= viewType %>])
|
|
68
108
|
async <%= queryName %>(
|
|
69
109
|
@Ctx() ctx: GraphQLContext<% if (parsedRequest?.args?.length) { %>,
|
|
70
|
-
<%
|
|
110
|
+
<% for (let i = 0; i < parsedRequest.args.length; i++) {
|
|
71
111
|
const arg = parsedRequest.args[i];
|
|
72
112
|
const gqlType = graphqlType(arg.tsType);
|
|
73
113
|
const tsType = arg.tsType === 'ID' ? 'string' : arg.tsType;
|
|
74
114
|
%> @Arg('<%= arg.name %>', () => <%= gqlType %>, { nullable: true }) <%= arg.name %>?: <%= tsType %><%= i < parsedRequest.args.length - 1 ? ',' : '' %>
|
|
75
|
-
<%
|
|
115
|
+
<% } } %>
|
|
76
116
|
): Promise<<%= viewType %>[]> {
|
|
77
117
|
const model = new ReadModel<<%= viewType %>>(ctx.eventStore, '<%= projectionType %>');
|
|
78
118
|
|
|
79
119
|
// ## IMPLEMENTATION INSTRUCTIONS ##
|
|
80
120
|
// You can query the projection using the ReadModel API:
|
|
81
|
-
//
|
|
82
121
|
// - model.getAll() — fetch all documents
|
|
83
122
|
// - model.getById(id) — fetch a single document by ID (default key: 'id')
|
|
84
123
|
// - model.find(filterFn) — filter documents using a predicate
|
|
85
124
|
// - model.first(filterFn) — fetch the first document matching a predicate
|
|
86
125
|
//
|
|
87
|
-
// Example below uses
|
|
126
|
+
// Example below uses \`.find()\` to filter
|
|
88
127
|
// change the logic for the query as needed to meet the requirements for the current slice.
|
|
89
128
|
|
|
90
129
|
return model.find((item) => {
|
|
91
130
|
<% if (parsedRequest?.args?.length) {
|
|
92
131
|
for (const arg of parsedRequest.args) { %>
|
|
93
132
|
if (<%= arg.name %> !== undefined && item.<%= arg.name %> !== <%= arg.name %>) return false;
|
|
94
|
-
<%
|
|
133
|
+
<% } } %>
|
|
95
134
|
return true;
|
|
96
135
|
});
|
|
97
136
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { generateScaffoldFilePlans } from '../../scaffoldFromSchema';
|
|
3
|
-
import {
|
|
3
|
+
import { Model as SpecsSchema } from '@auto-engineer/flow';
|
|
4
4
|
|
|
5
5
|
describe('state.ts.ejs', () => {
|
|
6
6
|
it('should generate a valid state definition file for a query slice with a state message', async () => {
|
|
@@ -15,7 +15,6 @@ describe('state.ts.ejs', () => {
|
|
|
15
15
|
name: 'Get available items',
|
|
16
16
|
client: {
|
|
17
17
|
description: 'Client view of available items',
|
|
18
|
-
specs: [],
|
|
19
18
|
},
|
|
20
19
|
server: {
|
|
21
20
|
description: 'Projects available items',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
2
|
+
import { Model as SpecsSchema } from '@auto-engineer/flow';
|
|
3
3
|
import { generateScaffoldFilePlans } from '../../scaffoldFromSchema';
|
|
4
4
|
|
|
5
5
|
describe('react.specs.ts.ejs (react slice)', () => {
|
|
@@ -13,7 +13,7 @@ describe('react.specs.ts.ejs (react slice)', () => {
|
|
|
13
13
|
{
|
|
14
14
|
type: 'command',
|
|
15
15
|
name: 'guest submits booking request',
|
|
16
|
-
client: { description: ''
|
|
16
|
+
client: { description: '' },
|
|
17
17
|
server: {
|
|
18
18
|
description: '',
|
|
19
19
|
specs: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
2
|
+
import { Model as SpecsSchema } from '@auto-engineer/flow';
|
|
3
3
|
import { generateScaffoldFilePlans } from '../../scaffoldFromSchema';
|
|
4
4
|
|
|
5
5
|
describe('handle.ts.ejs (react slice)', () => {
|
|
@@ -13,7 +13,7 @@ describe('handle.ts.ejs (react slice)', () => {
|
|
|
13
13
|
{
|
|
14
14
|
type: 'command',
|
|
15
15
|
name: 'guest submits booking request',
|
|
16
|
-
client: { description: ''
|
|
16
|
+
client: { description: '' },
|
|
17
17
|
server: {
|
|
18
18
|
description: '',
|
|
19
19
|
specs: {
|
|
@@ -116,7 +116,7 @@ describe('handle.ts.ejs (react slice)', () => {
|
|
|
116
116
|
{
|
|
117
117
|
type: 'command',
|
|
118
118
|
name: 'notify host',
|
|
119
|
-
client: { description: ''
|
|
119
|
+
client: { description: '' },
|
|
120
120
|
server: {
|
|
121
121
|
description: '',
|
|
122
122
|
specs: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import {
|
|
2
|
+
import { Model as SpecsSchema } from '@auto-engineer/flow';
|
|
3
3
|
import { generateScaffoldFilePlans } from '../../scaffoldFromSchema';
|
|
4
4
|
|
|
5
5
|
describe('register.ts.ejs (react slice)', () => {
|
|
@@ -13,7 +13,7 @@ describe('register.ts.ejs (react slice)', () => {
|
|
|
13
13
|
{
|
|
14
14
|
type: 'command',
|
|
15
15
|
name: 'guest submits booking request',
|
|
16
|
-
client: { description: ''
|
|
16
|
+
client: { description: '' },
|
|
17
17
|
server: {
|
|
18
18
|
description: '',
|
|
19
19
|
specs: {
|
|
@@ -116,7 +116,7 @@ describe('register.ts.ejs (react slice)', () => {
|
|
|
116
116
|
{
|
|
117
117
|
type: 'command',
|
|
118
118
|
name: 'notify host',
|
|
119
|
-
client: { description: ''
|
|
119
|
+
client: { description: '' },
|
|
120
120
|
server: {
|
|
121
121
|
description: '',
|
|
122
122
|
specs: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Model as SpecsSchema } from '@auto-engineer/flow';
|
|
2
2
|
|
|
3
3
|
const specVariant1: SpecsSchema = {
|
|
4
4
|
variant: 'specs',
|
|
@@ -14,7 +14,10 @@ const specVariant1: SpecsSchema = {
|
|
|
14
14
|
description: 'Handles item creation',
|
|
15
15
|
client: {
|
|
16
16
|
description: 'A form that allows users to add items',
|
|
17
|
-
specs:
|
|
17
|
+
specs: {
|
|
18
|
+
name: 'A form that allows users to add items',
|
|
19
|
+
rules: ['have fields for id and description'],
|
|
20
|
+
},
|
|
18
21
|
},
|
|
19
22
|
|
|
20
23
|
server: {
|
|
@@ -57,7 +60,6 @@ const specVariant1: SpecsSchema = {
|
|
|
57
60
|
description: 'Projection of available items',
|
|
58
61
|
client: {
|
|
59
62
|
description: 'Show available items',
|
|
60
|
-
specs: [],
|
|
61
63
|
},
|
|
62
64
|
server: {
|
|
63
65
|
description: 'Project items based on ItemCreated',
|
|
@@ -6,18 +6,18 @@ import { resolve, join } from 'path';
|
|
|
6
6
|
import { existsSync } from 'fs';
|
|
7
7
|
import { generateScaffoldFilePlans, writeScaffoldFilePlans } from '../codegen/scaffoldFromSchema';
|
|
8
8
|
import { ensureDirExists } from '../codegen/utils/path';
|
|
9
|
-
import {
|
|
9
|
+
import { Model } from '@auto-engineer/flow';
|
|
10
10
|
import { fileURLToPath } from 'url';
|
|
11
11
|
import { dirname } from 'path';
|
|
12
12
|
import { execa } from 'execa';
|
|
13
13
|
import createDebug from 'debug';
|
|
14
14
|
import { defineCommandHandler } from '@auto-engineer/message-bus';
|
|
15
15
|
|
|
16
|
-
const debug = createDebug('
|
|
17
|
-
const debugSchema = createDebug('
|
|
18
|
-
const debugFiles = createDebug('
|
|
19
|
-
const debugDeps = createDebug('
|
|
20
|
-
const debugScaffold = createDebug('
|
|
16
|
+
const debug = createDebug('auto:generate-server');
|
|
17
|
+
const debugSchema = createDebug('auto:generate-server:schema');
|
|
18
|
+
const debugFiles = createDebug('auto:generate-server:files');
|
|
19
|
+
const debugDeps = createDebug('auto:generate-server:deps');
|
|
20
|
+
const debugScaffold = createDebug('auto:generate-server:scaffold');
|
|
21
21
|
|
|
22
22
|
type DefaultRecord = Record<string, unknown>;
|
|
23
23
|
export type Command<CommandType extends string = string, CommandData extends DefaultRecord = DefaultRecord> = Readonly<{
|
|
@@ -117,12 +117,12 @@ async function validateSchemaFile(
|
|
|
117
117
|
return null;
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
async function readAndParseSchema(absSchema: string): Promise<
|
|
120
|
+
async function readAndParseSchema(absSchema: string): Promise<Model> {
|
|
121
121
|
debugSchema('Reading schema file from %s', absSchema);
|
|
122
122
|
const content = await readFile(absSchema, 'utf8');
|
|
123
123
|
|
|
124
124
|
debugSchema('Schema content length: %d bytes', content.length);
|
|
125
|
-
const spec = JSON.parse(content) as
|
|
125
|
+
const spec = JSON.parse(content) as Model;
|
|
126
126
|
|
|
127
127
|
debugSchema('Parsed schema:');
|
|
128
128
|
debugSchema(' Flows: %d', spec.flows?.length || 0);
|
|
@@ -133,7 +133,7 @@ async function readAndParseSchema(absSchema: string): Promise<SpecsSchemaType> {
|
|
|
133
133
|
return spec;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
function logFlowDetails(spec:
|
|
136
|
+
function logFlowDetails(spec: Model): void {
|
|
137
137
|
if (spec.flows !== undefined && spec.flows.length > 0) {
|
|
138
138
|
debugSchema(
|
|
139
139
|
'Flow names: %o',
|
|
@@ -148,7 +148,7 @@ function logFlowDetails(spec: SpecsSchemaType): void {
|
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
-
async function generateAndWriteScaffold(spec:
|
|
151
|
+
async function generateAndWriteScaffold(spec: Model, serverDir: string): Promise<void> {
|
|
152
152
|
const domainFlowsPath = join(serverDir, 'src', 'domain', 'flows');
|
|
153
153
|
debugScaffold('Generating scaffold file plans');
|
|
154
154
|
debugScaffold(' Domain flows path: %s', domainFlowsPath);
|
|
@@ -169,7 +169,7 @@ async function generateAndWriteScaffold(spec: SpecsSchemaType, serverDir: string
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
async function copyAllFiles(serverDir: string): Promise<void> {
|
|
172
|
-
const packageRoot = path.resolve(__dirname, '
|
|
172
|
+
const packageRoot = path.resolve(__dirname, '../../../src');
|
|
173
173
|
debugFiles('Package root: %s', packageRoot);
|
|
174
174
|
|
|
175
175
|
debugFiles('Copying utility files...');
|
|
@@ -183,16 +183,16 @@ async function copyAllFiles(serverDir: string): Promise<void> {
|
|
|
183
183
|
}
|
|
184
184
|
|
|
185
185
|
async function writeConfigurationFiles(serverDir: string, absDest: string): Promise<void> {
|
|
186
|
-
debugFiles(
|
|
186
|
+
debugFiles(`Writing package.json... to ${serverDir}`);
|
|
187
187
|
await writePackage(serverDir);
|
|
188
188
|
|
|
189
|
-
debugFiles(
|
|
189
|
+
debugFiles(`Writing tsconfig.json... to ${serverDir}`);
|
|
190
190
|
await writeTsconfig(serverDir);
|
|
191
191
|
|
|
192
|
-
debugFiles(
|
|
192
|
+
debugFiles(`Writing vitest config... to ${serverDir}`);
|
|
193
193
|
await writeVitestConfig(serverDir);
|
|
194
194
|
|
|
195
|
-
debugFiles(
|
|
195
|
+
debugFiles(`Generating GraphQL schema script... ${serverDir} to ${absDest}`);
|
|
196
196
|
await generateSchemaScript(serverDir, absDest);
|
|
197
197
|
}
|
|
198
198
|
|
|
@@ -338,19 +338,20 @@ async function copySharedAndRootFiles(from: string, to: string): Promise<void> {
|
|
|
338
338
|
async function writePackage(dest: string): Promise<void> {
|
|
339
339
|
debugFiles('Writing package.json to %s', dest);
|
|
340
340
|
|
|
341
|
-
const packageRoot = path.resolve(__dirname, '
|
|
341
|
+
const packageRoot = path.resolve(__dirname, '../../..');
|
|
342
342
|
const localPkgPath = path.resolve(packageRoot, 'package.json');
|
|
343
343
|
const rootPkgPath = path.resolve(packageRoot, '../../package.json');
|
|
344
344
|
|
|
345
|
+
debugFiles(' package root: %s', packageRoot);
|
|
345
346
|
debugFiles(' Local package path: %s', localPkgPath);
|
|
346
347
|
debugFiles(' Root package path: %s', rootPkgPath);
|
|
347
348
|
|
|
348
|
-
const localPkg = (await fs.readJson(localPkgPath)
|
|
349
|
+
const localPkg = (await fs.readJson(localPkgPath)) as {
|
|
349
350
|
dependencies?: Record<string, string>;
|
|
350
351
|
devDependencies?: Record<string, string>;
|
|
351
352
|
};
|
|
352
353
|
|
|
353
|
-
const rootPkg = (await fs.readJson(rootPkgPath)
|
|
354
|
+
const rootPkg = (await fs.readJson(rootPkgPath)) as {
|
|
354
355
|
dependencies?: Record<string, string>;
|
|
355
356
|
devDependencies?: Record<string, string>;
|
|
356
357
|
};
|
|
@@ -392,6 +393,7 @@ async function writePackage(dest: string): Promise<void> {
|
|
|
392
393
|
dependencies: resolveDeps([
|
|
393
394
|
'@event-driven-io/emmett',
|
|
394
395
|
'type-graphql',
|
|
396
|
+
'graphql-type-json',
|
|
395
397
|
'graphql',
|
|
396
398
|
'fast-glob',
|
|
397
399
|
'reflect-metadata',
|
|
@@ -402,7 +404,12 @@ async function writePackage(dest: string): Promise<void> {
|
|
|
402
404
|
devDependencies: resolveDeps(['typescript', 'vitest', 'tsx']),
|
|
403
405
|
} as const;
|
|
404
406
|
|
|
405
|
-
|
|
407
|
+
debugFiles('Loading package.json from', path.join(dest, 'package.json'));
|
|
408
|
+
const existingPkg = (await fs.readJson(path.join(dest, 'package.json')).catch(() => {
|
|
409
|
+
debugFiles('Failed to load package.json, using empty object');
|
|
410
|
+
return {};
|
|
411
|
+
})) as Record<string, unknown>;
|
|
412
|
+
debugFiles('Existing package.json:', existingPkg);
|
|
406
413
|
const mergedDeps = {
|
|
407
414
|
...(existingPkg.dependencies as Record<string, string>),
|
|
408
415
|
...packageJson.dependencies,
|
|
@@ -417,6 +424,7 @@ async function writeTsconfig(dest: string): Promise<void> {
|
|
|
417
424
|
module: 'ESNext',
|
|
418
425
|
moduleResolution: 'bundler',
|
|
419
426
|
strict: true,
|
|
427
|
+
outDir: './dist',
|
|
420
428
|
skipLibCheck: true,
|
|
421
429
|
emitDecoratorMetadata: true,
|
|
422
430
|
experimentalDecorators: true,
|
|
@@ -488,29 +496,29 @@ main().catch((err) => {
|
|
|
488
496
|
}
|
|
489
497
|
|
|
490
498
|
async function installDependenciesAndGenerateSchema(serverDir: string, workingDir: string): Promise<void> {
|
|
491
|
-
debugDeps('
|
|
499
|
+
debugDeps('Installing dependencies...');
|
|
492
500
|
debugDeps('Starting dependency installation in %s', serverDir);
|
|
501
|
+
debugDeps('Hint: You can debug by manually running: cd server && pnpm install && npx tsx scripts/generate-schema.ts');
|
|
493
502
|
|
|
494
503
|
try {
|
|
495
|
-
debugDeps('Running
|
|
496
|
-
await execa('pnpm', ['install'], { cwd: serverDir });
|
|
497
|
-
debugDeps('✅ Dependencies installed successfully');
|
|
504
|
+
debugDeps('Running pnpm install');
|
|
505
|
+
await execa('pnpm', ['install', '--ignore-workspace'], { cwd: serverDir });
|
|
498
506
|
debugDeps('Dependencies installed successfully');
|
|
507
|
+
} catch (error) {
|
|
508
|
+
debugDeps('Failed to pnpm install: %s', error instanceof Error ? error.message : 'Unknown error');
|
|
509
|
+
}
|
|
499
510
|
|
|
500
|
-
|
|
501
|
-
debugDeps('
|
|
511
|
+
try {
|
|
512
|
+
debugDeps('Generating GraphQL schema...');
|
|
513
|
+
debugDeps('Running: tsx scripts/generate-schema.ts', serverDir + '/scripts/generate-schema.ts');
|
|
502
514
|
await execa('tsx', ['scripts/generate-schema.ts'], { cwd: serverDir });
|
|
503
|
-
|
|
504
515
|
const schemaPath = join(workingDir, '.context', 'schema.graphql');
|
|
505
|
-
debugDeps('✅ GraphQL schema generated at: %s', schemaPath);
|
|
506
516
|
debugDeps('GraphQL schema generated at: %s', schemaPath);
|
|
507
517
|
} catch (error) {
|
|
508
|
-
debugDeps('Failed to install dependencies or generate schema: %O', error);
|
|
509
518
|
debugDeps(
|
|
510
|
-
'
|
|
519
|
+
'Failed to run tsx scripts/generate-schema.ts: %s',
|
|
511
520
|
error instanceof Error ? error.message : 'Unknown error',
|
|
512
521
|
);
|
|
513
|
-
debugDeps('You can manually run: cd server && pnpm install && npx tsx scripts/generate-schema.ts');
|
|
514
522
|
}
|
|
515
523
|
}
|
|
516
524
|
|
package/.turbo/turbo-test.log
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> @auto-engineer/server-generator-apollo-emmett@0.8.5 test /home/runner/work/auto-engineer/auto-engineer/packages/server-generator-apollo-emmett
|
|
3
|
-
> vitest run --reporter=dot
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
[1m[46m RUN [49m[22m [36mv3.2.4 [39m[90m/home/runner/work/auto-engineer/auto-engineer/packages/server-generator-apollo-emmett[39m
|
|
7
|
-
|
|
8
|
-
[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[2m[90m-[39m[22m[33m[39m[32m·[39m[33m[39m[32m·[39m[33m[39m[32m·[39m
|
|
9
|
-
|
|
10
|
-
[2m Test Files [22m [1m[32m15 passed[39m[22m[2m | [22m[33m1 skipped[39m[90m (16)[39m
|
|
11
|
-
[2m Tests [22m [1m[32m22 passed[39m[22m[2m | [22m[33m1 skipped[39m[90m (23)[39m
|
|
12
|
-
[2m Start at [22m 14:02:58
|
|
13
|
-
[2m Duration [22m 6.14s[2m (transform 770ms, setup 0ms, collect 5.05s, tests 5.57s, environment 4ms, prepare 2.21s)[22m
|
|
14
|
-
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { generateScaffoldFilePlans } from '../../scaffoldFromSchema';
|
|
3
|
-
import { SpecsSchemaType as SpecsSchema } from '@auto-engineer/flow';
|
|
4
|
-
|
|
5
|
-
describe('mutation.resolver.ts.ejs', () => {
|
|
6
|
-
it('should generate a valid mutation resolver file', async () => {
|
|
7
|
-
const spec: SpecsSchema = {
|
|
8
|
-
variant: 'specs',
|
|
9
|
-
flows: [
|
|
10
|
-
{
|
|
11
|
-
name: 'Host creates a listing',
|
|
12
|
-
slices: [
|
|
13
|
-
{
|
|
14
|
-
type: 'command',
|
|
15
|
-
name: 'Create listing',
|
|
16
|
-
client: {
|
|
17
|
-
description: 'A form that allows users to add a new listing',
|
|
18
|
-
specs: [],
|
|
19
|
-
},
|
|
20
|
-
server: {
|
|
21
|
-
description: 'Handles listing creation',
|
|
22
|
-
specs: {
|
|
23
|
-
name: 'Create listing command',
|
|
24
|
-
rules: [
|
|
25
|
-
{
|
|
26
|
-
description: 'Should create listing successfully',
|
|
27
|
-
examples: [
|
|
28
|
-
{
|
|
29
|
-
description: 'User creates listing with valid data',
|
|
30
|
-
when: {
|
|
31
|
-
commandRef: 'CreateListing',
|
|
32
|
-
exampleData: {
|
|
33
|
-
propertyId: 'listing_123',
|
|
34
|
-
title: 'Modern Downtown Apartment',
|
|
35
|
-
pricePerNight: 250,
|
|
36
|
-
maxGuests: 4,
|
|
37
|
-
amenities: ['wifi', 'kitchen'],
|
|
38
|
-
available: true,
|
|
39
|
-
tags: ['sea view', 'balcony'],
|
|
40
|
-
rating: 4.8,
|
|
41
|
-
metadata: { petsAllowed: true },
|
|
42
|
-
listedAt: '2024-01-15T10:00:00Z',
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
then: [],
|
|
46
|
-
},
|
|
47
|
-
],
|
|
48
|
-
},
|
|
49
|
-
],
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
],
|
|
54
|
-
},
|
|
55
|
-
],
|
|
56
|
-
messages: [
|
|
57
|
-
{
|
|
58
|
-
type: 'command',
|
|
59
|
-
name: 'CreateListing',
|
|
60
|
-
fields: [
|
|
61
|
-
{ name: 'propertyId', type: 'string', required: true },
|
|
62
|
-
{ name: 'title', type: 'string', required: true },
|
|
63
|
-
{ name: 'pricePerNight', type: 'number', required: true },
|
|
64
|
-
{ name: 'maxGuests', type: 'number', required: true },
|
|
65
|
-
{ name: 'amenities', type: 'string[]', required: true },
|
|
66
|
-
{ name: 'available', type: 'boolean', required: true },
|
|
67
|
-
{ name: 'tags', type: 'string[]', required: true },
|
|
68
|
-
{ name: 'rating', type: 'number', required: true },
|
|
69
|
-
{ name: 'metadata', type: 'object', required: true },
|
|
70
|
-
{ name: 'listedAt', type: 'Date', required: true },
|
|
71
|
-
],
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
const plans = await generateScaffoldFilePlans(spec.flows, spec.messages, undefined, 'src/domain/flows');
|
|
77
|
-
const mutationFile = plans.find((p) => p.outputPath.endsWith('mutation.resolver.ts'));
|
|
78
|
-
|
|
79
|
-
expect(mutationFile?.contents).toMatchInlineSnapshot(`
|
|
80
|
-
"import { Mutation, Resolver, Arg, Ctx, Field, InputType } from 'type-graphql';
|
|
81
|
-
import { type GraphQLContext, sendCommand, MutationResponse } from '../../../shared';
|
|
82
|
-
|
|
83
|
-
@InputType()
|
|
84
|
-
export class CreateListingInput {
|
|
85
|
-
@Field(() => String)
|
|
86
|
-
propertyId!: string;
|
|
87
|
-
@Field(() => String)
|
|
88
|
-
title!: string;
|
|
89
|
-
@Field(() => Number)
|
|
90
|
-
pricePerNight!: number;
|
|
91
|
-
@Field(() => Number)
|
|
92
|
-
maxGuests!: number;
|
|
93
|
-
@Field(() => [String])
|
|
94
|
-
amenities!: string[];
|
|
95
|
-
@Field(() => Boolean)
|
|
96
|
-
available!: boolean;
|
|
97
|
-
@Field(() => [String])
|
|
98
|
-
tags!: string[];
|
|
99
|
-
@Field(() => Number)
|
|
100
|
-
rating!: number;
|
|
101
|
-
@Field(() => Object)
|
|
102
|
-
metadata!: object;
|
|
103
|
-
@Field(() => Date)
|
|
104
|
-
listedAt!: Date;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
@Resolver()
|
|
108
|
-
export class CreateListingResolver {
|
|
109
|
-
@Mutation(() => MutationResponse)
|
|
110
|
-
async createListing(
|
|
111
|
-
@Arg('input', () => CreateListingInput) input: CreateListingInput,
|
|
112
|
-
@Ctx() ctx: GraphQLContext,
|
|
113
|
-
): Promise<MutationResponse> {
|
|
114
|
-
return await sendCommand(ctx.messageBus, {
|
|
115
|
-
type: 'CreateListing',
|
|
116
|
-
kind: 'Command',
|
|
117
|
-
data: { ...input },
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
"
|
|
122
|
-
`);
|
|
123
|
-
});
|
|
124
|
-
});
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { Mutation, Resolver, Arg, Ctx, Field, InputType } from 'type-graphql';
|
|
2
|
-
import { type GraphQLContext, sendCommand, MutationResponse } from '../../../shared';
|
|
3
|
-
|
|
4
|
-
@InputType()
|
|
5
|
-
export class <%= pascalCase(commands[0].type) %>Input {
|
|
6
|
-
<% for (const field of commands[0].fields) { -%>
|
|
7
|
-
@Field(() => <%= graphqlType(field.tsType) %><%= field.required === false ? ', { nullable: true }' : '' %>)
|
|
8
|
-
<%= field.name %><%= field.required === false ? '?' : '' %><%= field.required !== false ? '!' : '' %>: <%- field.tsType %>;
|
|
9
|
-
<% } -%>
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
@Resolver()
|
|
13
|
-
export class <%= pascalCase(commands[0].type) %>Resolver {
|
|
14
|
-
@Mutation(() => MutationResponse)
|
|
15
|
-
async <%= camelCase(commands[0].type) %>(
|
|
16
|
-
@Arg('input', () => <%= pascalCase(commands[0].type) %>Input) input: <%= pascalCase(commands[0].type) %>Input,
|
|
17
|
-
@Ctx() ctx: GraphQLContext
|
|
18
|
-
): Promise<MutationResponse> {
|
|
19
|
-
return await sendCommand(ctx.messageBus, {
|
|
20
|
-
type: '<%= commands[0].type %>',
|
|
21
|
-
kind: 'Command',
|
|
22
|
-
data: { ...input },
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
}
|