@auto-engineer/server-generator-apollo-emmett 0.8.4 → 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 +16 -0
- package/dist/src/codegen/extract/commands.d.ts.map +1 -0
- package/dist/src/codegen/extract/commands.js.map +1 -0
- package/dist/src/codegen/extract/data-sink.d.ts.map +1 -0
- package/dist/{codegen → src/codegen}/extract/data-sink.js +33 -10
- package/dist/src/codegen/extract/data-sink.js.map +1 -0
- package/dist/src/codegen/extract/events.d.ts.map +1 -0
- package/dist/src/codegen/extract/events.js.map +1 -0
- package/dist/src/codegen/extract/fields.d.ts.map +1 -0
- package/dist/src/codegen/extract/fields.js.map +1 -0
- package/dist/src/codegen/extract/graphql.d.ts.map +1 -0
- package/dist/src/codegen/extract/graphql.js.map +1 -0
- package/dist/src/codegen/extract/gwt.d.ts.map +1 -0
- package/dist/src/codegen/extract/gwt.js.map +1 -0
- package/dist/src/codegen/extract/index.d.ts.map +1 -0
- package/dist/src/codegen/extract/index.js.map +1 -0
- package/dist/src/codegen/extract/messages.d.ts.map +1 -0
- package/dist/src/codegen/extract/messages.js.map +1 -0
- package/dist/src/codegen/extract/projection.d.ts.map +1 -0
- package/dist/src/codegen/extract/projection.js.map +1 -0
- package/dist/src/codegen/extract/query.d.ts.map +1 -0
- package/dist/src/codegen/extract/query.js.map +1 -0
- package/dist/src/codegen/extract/states.d.ts.map +1 -0
- package/dist/src/codegen/extract/states.js.map +1 -0
- package/dist/src/codegen/scaffoldFromSchema.d.ts +9 -0
- package/dist/src/codegen/scaffoldFromSchema.d.ts.map +1 -0
- package/dist/src/codegen/scaffoldFromSchema.integration.specs.d.ts.map +1 -0
- package/dist/src/codegen/scaffoldFromSchema.integration.specs.js.map +1 -0
- package/dist/{codegen → src/codegen}/scaffoldFromSchema.js +54 -18
- package/dist/src/codegen/scaffoldFromSchema.js.map +1 -0
- 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 +4 -0
- package/dist/src/codegen/test-data/specVariant1.d.ts.map +1 -0
- package/dist/{codegen → src/codegen}/test-data/specVariant1.js +4 -2
- package/dist/src/codegen/test-data/specVariant1.js.map +1 -0
- package/dist/src/codegen/types.d.ts.map +1 -0
- package/dist/{codegen → src/codegen}/types.js.map +1 -1
- package/dist/src/codegen/utils/path.d.ts.map +1 -0
- package/dist/src/codegen/utils/path.js.map +1 -0
- package/dist/src/commands/generate-server.d.ts.map +1 -0
- package/dist/{commands → src/commands}/generate-server.js +34 -24
- package/dist/src/commands/generate-server.js.map +1 -0
- package/dist/src/domain/shared/ReadModel.d.ts.map +1 -0
- package/dist/src/domain/shared/ReadModel.js.map +1 -0
- package/dist/src/domain/shared/index.d.ts.map +1 -0
- package/dist/src/domain/shared/index.js.map +1 -0
- package/dist/src/domain/shared/reactorSpecification.d.ts.map +1 -0
- package/dist/src/domain/shared/reactorSpecification.js.map +1 -0
- package/dist/src/domain/shared/sendCommand.d.ts.map +1 -0
- package/dist/src/domain/shared/sendCommand.js.map +1 -0
- package/dist/src/domain/shared/types.d.ts.map +1 -0
- package/dist/src/domain/shared/types.js.map +1 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/server.d.ts.map +1 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/loadProjections.d.ts.map +1 -0
- package/dist/src/utils/loadProjections.js.map +1 -0
- package/dist/src/utils/loadRegisterFiles.d.ts.map +1 -0
- package/dist/src/utils/loadRegisterFiles.js.map +1 -0
- package/dist/src/utils/loadResolvers.d.ts.map +1 -0
- package/dist/src/utils/loadResolvers.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +10 -10
- package/src/codegen/extract/data-sink.ts +49 -23
- 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.json +3 -2
- package/tsconfig.test.json +9 -0
- package/.turbo/turbo-test.log +0 -14
- package/.turbo/turbo-type-check.log +0 -4
- package/dist/codegen/extract/commands.d.ts.map +0 -1
- package/dist/codegen/extract/commands.js.map +0 -1
- package/dist/codegen/extract/data-sink.d.ts.map +0 -1
- package/dist/codegen/extract/data-sink.js.map +0 -1
- package/dist/codegen/extract/events.d.ts.map +0 -1
- package/dist/codegen/extract/events.js.map +0 -1
- package/dist/codegen/extract/fields.d.ts.map +0 -1
- package/dist/codegen/extract/fields.js.map +0 -1
- package/dist/codegen/extract/graphql.d.ts.map +0 -1
- package/dist/codegen/extract/graphql.js.map +0 -1
- package/dist/codegen/extract/gwt.d.ts.map +0 -1
- package/dist/codegen/extract/gwt.js.map +0 -1
- package/dist/codegen/extract/index.d.ts.map +0 -1
- package/dist/codegen/extract/index.js.map +0 -1
- package/dist/codegen/extract/messages.d.ts.map +0 -1
- package/dist/codegen/extract/messages.js.map +0 -1
- package/dist/codegen/extract/projection.d.ts.map +0 -1
- package/dist/codegen/extract/projection.js.map +0 -1
- package/dist/codegen/extract/query.d.ts.map +0 -1
- package/dist/codegen/extract/query.js.map +0 -1
- package/dist/codegen/extract/states.d.ts.map +0 -1
- package/dist/codegen/extract/states.js.map +0 -1
- package/dist/codegen/scaffoldFromSchema.d.ts +0 -9
- package/dist/codegen/scaffoldFromSchema.d.ts.map +0 -1
- package/dist/codegen/scaffoldFromSchema.integration.specs.d.ts.map +0 -1
- package/dist/codegen/scaffoldFromSchema.integration.specs.js.map +0 -1
- package/dist/codegen/scaffoldFromSchema.js.map +0 -1
- 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/codegen/test-data/specVariant1.d.ts +0 -4
- package/dist/codegen/test-data/specVariant1.d.ts.map +0 -1
- package/dist/codegen/test-data/specVariant1.js.map +0 -1
- package/dist/codegen/types.d.ts.map +0 -1
- package/dist/codegen/utils/path.d.ts.map +0 -1
- package/dist/codegen/utils/path.js.map +0 -1
- package/dist/commands/generate-server.d.ts.map +0 -1
- package/dist/commands/generate-server.js.map +0 -1
- package/dist/domain/shared/ReadModel.d.ts.map +0 -1
- package/dist/domain/shared/ReadModel.js.map +0 -1
- package/dist/domain/shared/index.d.ts.map +0 -1
- package/dist/domain/shared/index.js.map +0 -1
- package/dist/domain/shared/reactorSpecification.d.ts.map +0 -1
- package/dist/domain/shared/reactorSpecification.js.map +0 -1
- package/dist/domain/shared/sendCommand.d.ts.map +0 -1
- package/dist/domain/shared/sendCommand.js.map +0 -1
- package/dist/domain/shared/types.d.ts.map +0 -1
- package/dist/domain/shared/types.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/server.d.ts.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/utils/index.d.ts.map +0 -1
- package/dist/utils/index.js.map +0 -1
- package/dist/utils/loadProjections.d.ts.map +0 -1
- package/dist/utils/loadProjections.js.map +0 -1
- package/dist/utils/loadRegisterFiles.d.ts.map +0 -1
- package/dist/utils/loadRegisterFiles.js.map +0 -1
- package/dist/utils/loadResolvers.d.ts.map +0 -1
- package/dist/utils/loadResolvers.js.map +0 -1
- package/tsconfig.tsbuildinfo +0 -1
- /package/dist/{codegen → src/codegen}/extract/commands.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/extract/commands.js +0 -0
- /package/dist/{codegen → src/codegen}/extract/data-sink.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/extract/events.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/extract/events.js +0 -0
- /package/dist/{codegen → src/codegen}/extract/fields.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/extract/fields.js +0 -0
- /package/dist/{codegen → src/codegen}/extract/graphql.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/extract/graphql.js +0 -0
- /package/dist/{codegen → src/codegen}/extract/gwt.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/extract/gwt.js +0 -0
- /package/dist/{codegen → src/codegen}/extract/index.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/extract/index.js +0 -0
- /package/dist/{codegen → src/codegen}/extract/messages.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/extract/messages.js +0 -0
- /package/dist/{codegen → src/codegen}/extract/projection.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/extract/projection.js +0 -0
- /package/dist/{codegen → src/codegen}/extract/query.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/extract/query.js +0 -0
- /package/dist/{codegen → src/codegen}/extract/states.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/extract/states.js +0 -0
- /package/dist/{codegen → src/codegen}/scaffoldFromSchema.integration.specs.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/scaffoldFromSchema.integration.specs.js +0 -0
- /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/{codegen → src/codegen}/types.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/types.js +0 -0
- /package/dist/{codegen → src/codegen}/utils/path.d.ts +0 -0
- /package/dist/{codegen → src/codegen}/utils/path.js +0 -0
- /package/dist/{commands → src/commands}/generate-server.d.ts +0 -0
- /package/dist/{domain → src/domain}/shared/ReadModel.d.ts +0 -0
- /package/dist/{domain → src/domain}/shared/ReadModel.js +0 -0
- /package/dist/{domain → src/domain}/shared/ReadModel.ts +0 -0
- /package/dist/{domain → src/domain}/shared/index.d.ts +0 -0
- /package/dist/{domain → src/domain}/shared/index.js +0 -0
- /package/dist/{domain → src/domain}/shared/index.ts +0 -0
- /package/dist/{domain → src/domain}/shared/reactorSpecification.d.ts +0 -0
- /package/dist/{domain → src/domain}/shared/reactorSpecification.js +0 -0
- /package/dist/{domain → src/domain}/shared/reactorSpecification.ts +0 -0
- /package/dist/{domain → src/domain}/shared/sendCommand.d.ts +0 -0
- /package/dist/{domain → src/domain}/shared/sendCommand.js +0 -0
- /package/dist/{domain → src/domain}/shared/sendCommand.ts +0 -0
- /package/dist/{domain → src/domain}/shared/types.d.ts +0 -0
- /package/dist/{domain → src/domain}/shared/types.js +0 -0
- /package/dist/{domain → src/domain}/shared/types.ts +0 -0
- /package/dist/{index.d.ts → src/index.d.ts} +0 -0
- /package/dist/{index.js → src/index.js} +0 -0
- /package/dist/{server.d.ts → src/server.d.ts} +0 -0
- /package/dist/{server.js → src/server.js} +0 -0
- /package/dist/{server.ts → src/server.ts} +0 -0
- /package/dist/{utils → src/utils}/index.d.ts +0 -0
- /package/dist/{utils → src/utils}/index.js +0 -0
- /package/dist/{utils → src/utils}/index.ts +0 -0
- /package/dist/{utils → src/utils}/loadProjections.d.ts +0 -0
- /package/dist/{utils → src/utils}/loadProjections.js +0 -0
- /package/dist/{utils → src/utils}/loadProjections.ts +0 -0
- /package/dist/{utils → src/utils}/loadRegisterFiles.d.ts +0 -0
- /package/dist/{utils → src/utils}/loadRegisterFiles.js +0 -0
- /package/dist/{utils → src/utils}/loadRegisterFiles.ts +0 -0
- /package/dist/{utils → src/utils}/loadResolvers.d.ts +0 -0
- /package/dist/{utils → src/utils}/loadResolvers.js +0 -0
- /package/dist/{utils → src/utils}/loadResolvers.ts +0 -0
|
@@ -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('mutation.resolver.ts.ejs', () => {
|
|
6
6
|
it('should generate a valid mutation resolver file', async () => {
|
|
@@ -15,7 +15,6 @@ describe('mutation.resolver.ts.ejs', () => {
|
|
|
15
15
|
name: 'Create listing',
|
|
16
16
|
client: {
|
|
17
17
|
description: 'A form that allows users to add a new listing',
|
|
18
|
-
specs: [],
|
|
19
18
|
},
|
|
20
19
|
server: {
|
|
21
20
|
description: 'Handles listing creation',
|
|
@@ -77,30 +76,40 @@ describe('mutation.resolver.ts.ejs', () => {
|
|
|
77
76
|
const mutationFile = plans.find((p) => p.outputPath.endsWith('mutation.resolver.ts'));
|
|
78
77
|
|
|
79
78
|
expect(mutationFile?.contents).toMatchInlineSnapshot(`
|
|
80
|
-
"import { Mutation, Resolver, Arg, Ctx, Field, InputType } from 'type-graphql';
|
|
79
|
+
"import { Mutation, Resolver, Arg, Ctx, Field, InputType, GraphQLISODateTime } from 'type-graphql';
|
|
80
|
+
import { GraphQLJSON } from 'graphql-type-json';
|
|
81
81
|
import { type GraphQLContext, sendCommand, MutationResponse } from '../../../shared';
|
|
82
82
|
|
|
83
83
|
@InputType()
|
|
84
84
|
export class CreateListingInput {
|
|
85
85
|
@Field(() => String)
|
|
86
86
|
propertyId!: string;
|
|
87
|
+
|
|
87
88
|
@Field(() => String)
|
|
88
89
|
title!: string;
|
|
89
|
-
|
|
90
|
+
|
|
91
|
+
@Field(() => Float)
|
|
90
92
|
pricePerNight!: number;
|
|
91
|
-
|
|
93
|
+
|
|
94
|
+
@Field(() => Float)
|
|
92
95
|
maxGuests!: number;
|
|
96
|
+
|
|
93
97
|
@Field(() => [String])
|
|
94
98
|
amenities!: string[];
|
|
99
|
+
|
|
95
100
|
@Field(() => Boolean)
|
|
96
101
|
available!: boolean;
|
|
102
|
+
|
|
97
103
|
@Field(() => [String])
|
|
98
104
|
tags!: string[];
|
|
99
|
-
|
|
105
|
+
|
|
106
|
+
@Field(() => Float)
|
|
100
107
|
rating!: number;
|
|
101
|
-
|
|
108
|
+
|
|
109
|
+
@Field(() => JSON)
|
|
102
110
|
metadata!: object;
|
|
103
|
-
|
|
111
|
+
|
|
112
|
+
@Field(() => GraphQLISODateTime)
|
|
104
113
|
listedAt!: Date;
|
|
105
114
|
}
|
|
106
115
|
|
|
@@ -121,4 +130,234 @@ describe('mutation.resolver.ts.ejs', () => {
|
|
|
121
130
|
"
|
|
122
131
|
`);
|
|
123
132
|
});
|
|
133
|
+
|
|
134
|
+
it('should generate the mutation resolver for AnswerQuestion', async () => {
|
|
135
|
+
const spec: SpecsSchema = {
|
|
136
|
+
variant: 'specs',
|
|
137
|
+
flows: [
|
|
138
|
+
{
|
|
139
|
+
name: 'Questionnaires',
|
|
140
|
+
slices: [
|
|
141
|
+
{
|
|
142
|
+
name: 'submits a questionnaire answer',
|
|
143
|
+
type: 'command',
|
|
144
|
+
client: {
|
|
145
|
+
description: '',
|
|
146
|
+
specs: {
|
|
147
|
+
name: '',
|
|
148
|
+
rules: [
|
|
149
|
+
'display a success message when the answer is submitted',
|
|
150
|
+
'display an error message when the answer submission is rejected',
|
|
151
|
+
],
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
request:
|
|
155
|
+
'mutation AnswerQuestion($input: AnswerQuestionInput!) {\\n answerQuestion(input: $input) {\\n success\\n }\\n}',
|
|
156
|
+
server: {
|
|
157
|
+
description: '',
|
|
158
|
+
data: [
|
|
159
|
+
{
|
|
160
|
+
target: { type: 'Event', name: 'QuestionAnswered' },
|
|
161
|
+
destination: { type: 'stream', pattern: 'questionnaire-participantId' },
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
target: { type: 'Event', name: 'QuestionnaireEditRejected' },
|
|
165
|
+
destination: { type: 'stream', pattern: 'questionnaire-participantId' },
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
specs: {
|
|
169
|
+
name: '',
|
|
170
|
+
rules: [
|
|
171
|
+
{
|
|
172
|
+
description: 'answers are allowed while the questionnaire has not been submitted',
|
|
173
|
+
examples: [
|
|
174
|
+
{
|
|
175
|
+
description: 'no questions have been answered yet',
|
|
176
|
+
when: {
|
|
177
|
+
commandRef: 'AnswerQuestion',
|
|
178
|
+
exampleData: {
|
|
179
|
+
questionnaireId: 'q-001',
|
|
180
|
+
participantId: 'participant-abc',
|
|
181
|
+
questionId: 'q1',
|
|
182
|
+
answer: 'Yes',
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
then: [
|
|
186
|
+
{
|
|
187
|
+
eventRef: 'QuestionAnswered',
|
|
188
|
+
exampleData: {
|
|
189
|
+
questionnaireId: 'q-001',
|
|
190
|
+
participantId: 'participant-abc',
|
|
191
|
+
questionId: 'q1',
|
|
192
|
+
answer: 'Yes',
|
|
193
|
+
savedAt: '2030-01-01T09:05:00.000Z',
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
],
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
},
|
|
206
|
+
],
|
|
207
|
+
messages: [
|
|
208
|
+
{
|
|
209
|
+
type: 'command',
|
|
210
|
+
name: 'AnswerQuestion',
|
|
211
|
+
fields: [
|
|
212
|
+
{ name: 'questionnaireId', type: 'string', required: true },
|
|
213
|
+
{ name: 'participantId', type: 'string', required: true },
|
|
214
|
+
{ name: 'questionId', type: 'string', required: true },
|
|
215
|
+
{ name: 'answer', type: 'unknown', required: true },
|
|
216
|
+
],
|
|
217
|
+
metadata: { version: 1 },
|
|
218
|
+
},
|
|
219
|
+
],
|
|
220
|
+
integrations: [],
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const plans = await generateScaffoldFilePlans(spec.flows, spec.messages, undefined, 'src/domain/flows');
|
|
224
|
+
const mutationFile = plans.find(
|
|
225
|
+
(p) =>
|
|
226
|
+
p.outputPath.endsWith('mutation.resolver.ts') && p.contents.includes('export class AnswerQuestionResolver'),
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
expect(mutationFile?.contents).toMatchInlineSnapshot(`
|
|
230
|
+
"import { Mutation, Resolver, Arg, Ctx, Field, InputType } from 'type-graphql';
|
|
231
|
+
import { GraphQLJSON } from 'graphql-type-json';
|
|
232
|
+
import { type GraphQLContext, sendCommand, MutationResponse } from '../../../shared';
|
|
233
|
+
|
|
234
|
+
@InputType()
|
|
235
|
+
export class AnswerQuestionInput {
|
|
236
|
+
@Field(() => String)
|
|
237
|
+
questionnaireId!: string;
|
|
238
|
+
|
|
239
|
+
@Field(() => String)
|
|
240
|
+
participantId!: string;
|
|
241
|
+
|
|
242
|
+
@Field(() => String)
|
|
243
|
+
questionId!: string;
|
|
244
|
+
|
|
245
|
+
@Field(() => GraphQLJSON)
|
|
246
|
+
answer!: unknown;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
@Resolver()
|
|
250
|
+
export class AnswerQuestionResolver {
|
|
251
|
+
@Mutation(() => MutationResponse)
|
|
252
|
+
async answerQuestion(
|
|
253
|
+
@Arg('input', () => AnswerQuestionInput) input: AnswerQuestionInput,
|
|
254
|
+
@Ctx() ctx: GraphQLContext,
|
|
255
|
+
): Promise<MutationResponse> {
|
|
256
|
+
return await sendCommand(ctx.messageBus, {
|
|
257
|
+
type: 'AnswerQuestion',
|
|
258
|
+
kind: 'Command',
|
|
259
|
+
data: { ...input },
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
"
|
|
264
|
+
`);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('generates nested input types for inline object arrays in a mutation', async () => {
|
|
268
|
+
const spec: SpecsSchema = {
|
|
269
|
+
variant: 'specs',
|
|
270
|
+
flows: [
|
|
271
|
+
{
|
|
272
|
+
name: 'Cart',
|
|
273
|
+
slices: [
|
|
274
|
+
{
|
|
275
|
+
type: 'command',
|
|
276
|
+
name: 'Add items to cart',
|
|
277
|
+
client: { description: '' },
|
|
278
|
+
server: {
|
|
279
|
+
description: '',
|
|
280
|
+
specs: {
|
|
281
|
+
name: '',
|
|
282
|
+
rules: [
|
|
283
|
+
{
|
|
284
|
+
description: 'add items',
|
|
285
|
+
examples: [
|
|
286
|
+
{
|
|
287
|
+
description: 'happy path',
|
|
288
|
+
when: {
|
|
289
|
+
commandRef: 'AddItemsToCart',
|
|
290
|
+
exampleData: {
|
|
291
|
+
sessionId: 's-1',
|
|
292
|
+
items: [{ productId: 'p1', quantity: 2 }],
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
then: [],
|
|
296
|
+
},
|
|
297
|
+
],
|
|
298
|
+
},
|
|
299
|
+
],
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
],
|
|
304
|
+
},
|
|
305
|
+
],
|
|
306
|
+
messages: [
|
|
307
|
+
{
|
|
308
|
+
type: 'command',
|
|
309
|
+
name: 'AddItemsToCart',
|
|
310
|
+
fields: [
|
|
311
|
+
{ name: 'sessionId', type: 'string', required: true },
|
|
312
|
+
{ name: 'items', type: 'Array<{ productId: string; quantity: number }>', required: true },
|
|
313
|
+
],
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
const plans = await generateScaffoldFilePlans(spec.flows, spec.messages, undefined, 'src/domain/flows');
|
|
319
|
+
const mutationFile = plans.find(
|
|
320
|
+
(p) =>
|
|
321
|
+
p.outputPath.endsWith('mutation.resolver.ts') && p.contents.includes('export class AddItemsToCartResolver'),
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
expect(mutationFile?.contents).toMatchInlineSnapshot(`
|
|
325
|
+
"import { Mutation, Resolver, Arg, Ctx, Field, InputType } from 'type-graphql';
|
|
326
|
+
import { type GraphQLContext, sendCommand, MutationResponse } from '../../../shared';
|
|
327
|
+
|
|
328
|
+
@InputType()
|
|
329
|
+
export class AddItemsToCartItemsInput {
|
|
330
|
+
@Field(() => String)
|
|
331
|
+
productId!: string;
|
|
332
|
+
|
|
333
|
+
@Field(() => Float)
|
|
334
|
+
quantity!: number;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
@InputType()
|
|
338
|
+
export class AddItemsToCartInput {
|
|
339
|
+
@Field(() => String)
|
|
340
|
+
sessionId!: string;
|
|
341
|
+
|
|
342
|
+
@Field(() => [AddItemsToCartItemsInput])
|
|
343
|
+
items!: AddItemsToCartItemsInput[];
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
@Resolver()
|
|
347
|
+
export class AddItemsToCartResolver {
|
|
348
|
+
@Mutation(() => MutationResponse)
|
|
349
|
+
async addItemsToCart(
|
|
350
|
+
@Arg('input', () => AddItemsToCartInput) input: AddItemsToCartInput,
|
|
351
|
+
@Ctx() ctx: GraphQLContext,
|
|
352
|
+
): Promise<MutationResponse> {
|
|
353
|
+
return await sendCommand(ctx.messageBus, {
|
|
354
|
+
type: 'AddItemsToCart',
|
|
355
|
+
kind: 'Command',
|
|
356
|
+
data: { ...input },
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
"
|
|
361
|
+
`);
|
|
362
|
+
});
|
|
124
363
|
});
|
|
@@ -1,23 +1,97 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
<%
|
|
2
|
+
function isInlineObject(ts) {
|
|
3
|
+
return /^\{[\s\S]*\}$/.test((ts ?? '').trim());
|
|
4
|
+
}
|
|
5
|
+
function isInlineObjectArray(ts) {
|
|
6
|
+
const t = (ts ?? '').trim();
|
|
7
|
+
return /^Array<\{[\s\S]*\}>$/.test(t) || /^\{[\s\S]*\}\[\]$/.test(t);
|
|
8
|
+
}
|
|
9
|
+
function baseTs(ts) {
|
|
10
|
+
return (ts ?? 'string').replace(/\s*\|\s*null\b/g, '').trim();
|
|
11
|
+
}
|
|
12
|
+
function fieldUsesDate(ts) {
|
|
13
|
+
const b = baseTs(ts);
|
|
14
|
+
if (b === 'Date') return true;
|
|
15
|
+
if (isInlineObject(b) || isInlineObjectArray(b)) return /:\s*Date\b/.test(b);
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
function fieldUsesJSON(ts) {
|
|
19
|
+
const b = baseTs(ts);
|
|
20
|
+
if (b === 'unknown' || b === 'any' || b === 'object') return true;
|
|
21
|
+
if (isInlineObject(b) || isInlineObjectArray(b)) return /:\s*(unknown|any|object)\b/.test(b);
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const cmd = commands[0];
|
|
25
|
+
const usesDate = cmd.fields.some(f => fieldUsesDate(f.tsType));
|
|
26
|
+
const usesJSON = cmd.fields.some(f => fieldUsesJSON(f.tsType));
|
|
27
|
+
|
|
28
|
+
const embeddedInputs = [];
|
|
29
|
+
for (const f of cmd.fields) {
|
|
30
|
+
const tsType = f.tsType ?? 'string';
|
|
31
|
+
if (isInlineObjectArray(tsType) || isInlineObject(tsType)) {
|
|
32
|
+
embeddedInputs.push({
|
|
33
|
+
typeName: `${pascalCase(cmd.type)}${pascalCase(f.name)}Input`,
|
|
34
|
+
tsType,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
%>
|
|
39
|
+
import { Mutation, Resolver, Arg, Ctx, Field, InputType<% if (usesDate) { %>, GraphQLISODateTime<% } %> } from 'type-graphql';
|
|
40
|
+
<% if (usesJSON) { %>import { GraphQLJSON } from 'graphql-type-json';
|
|
41
|
+
<% } %>import { type GraphQLContext, sendCommand, MutationResponse } from '../../../shared';
|
|
42
|
+
|
|
43
|
+
<% for (const { typeName, tsType } of embeddedInputs) {
|
|
44
|
+
const inner = tsType.trim().startsWith('Array<')
|
|
45
|
+
? tsType.trim().replace(/^Array<\{/, '{').replace(/}>$/, '}')
|
|
46
|
+
: tsType.trim().replace(/\[\]$/, '');
|
|
47
|
+
const match = inner.match(/^\{([\s\S]*)\}$/);
|
|
48
|
+
const body = match ? match[1] : '';
|
|
49
|
+
const rawFields = body.split(/[,;]\s*/).filter(Boolean);
|
|
50
|
+
const parsedFields = rawFields.map(f => {
|
|
51
|
+
const parts = f.split(':');
|
|
52
|
+
const name = parts[0]?.trim();
|
|
53
|
+
const type = parts.slice(1).join(':').trim();
|
|
54
|
+
if (!name || !type) return null;
|
|
55
|
+
return { name, tsType: type, gqlType: graphqlType(type), nullable: isNullable(type) };
|
|
56
|
+
}).filter(Boolean);
|
|
57
|
+
%>
|
|
58
|
+
@InputType()
|
|
59
|
+
export class <%= typeName %> {
|
|
60
|
+
<% for (const f of parsedFields) { %>
|
|
61
|
+
@Field(() => <%= f.gqlType %><%= f.nullable ? ', { nullable: true }' : '' %>)
|
|
62
|
+
<%= f.name %><%= f.nullable ? '?' : '!' %>: <%= toTsFieldType(f.tsType) %>;
|
|
63
|
+
<% } %>
|
|
64
|
+
}
|
|
65
|
+
<% } %>
|
|
3
66
|
|
|
4
67
|
@InputType()
|
|
5
|
-
export class <%= pascalCase(
|
|
6
|
-
<% for (const field of
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
68
|
+
export class <%= pascalCase(cmd.type) %>Input {
|
|
69
|
+
<% for (const field of cmd.fields) {
|
|
70
|
+
const tsType = field.tsType ?? 'string';
|
|
71
|
+
const gqlType = graphqlType(tsType);
|
|
72
|
+
const nestedName = `${pascalCase(cmd.type)}${pascalCase(field.name)}Input`;
|
|
73
|
+
|
|
74
|
+
if (isInlineObjectArray(tsType)) { %>
|
|
75
|
+
@Field(() => [<%= nestedName %>]<%= (field.required === false || isNullable(tsType)) ? ', { nullable: true }' : '' %>)
|
|
76
|
+
<%= field.name %><%= field.required === false ? '?' : '!' %>: <%= nestedName %>[];
|
|
77
|
+
<% } else if (isInlineObject(tsType)) { %>
|
|
78
|
+
@Field(() => <%= nestedName %><%= (field.required === false || isNullable(tsType)) ? ', { nullable: true }' : '' %>)
|
|
79
|
+
<%= field.name %><%= field.required === false ? '?' : '!' %>: <%= nestedName %>;
|
|
80
|
+
<% } else { %>
|
|
81
|
+
@Field(() => <%= gqlType %><%= (field.required === false || isNullable(tsType)) ? ', { nullable: true }' : '' %>)
|
|
82
|
+
<%= field.name %><%= field.required === false ? '?' : '!' %>: <%= toTsFieldType(tsType) %>;
|
|
83
|
+
<% } } %>
|
|
10
84
|
}
|
|
11
85
|
|
|
12
86
|
@Resolver()
|
|
13
|
-
export class <%= pascalCase(
|
|
87
|
+
export class <%= pascalCase(cmd.type) %>Resolver {
|
|
14
88
|
@Mutation(() => MutationResponse)
|
|
15
|
-
async <%= camelCase(
|
|
16
|
-
@Arg('input', () => <%= pascalCase(
|
|
17
|
-
@Ctx() ctx: GraphQLContext
|
|
89
|
+
async <%= camelCase(cmd.type) %>(
|
|
90
|
+
@Arg('input', () => <%= pascalCase(cmd.type) %>Input) input: <%= pascalCase(cmd.type) %>Input,
|
|
91
|
+
@Ctx() ctx: GraphQLContext,
|
|
18
92
|
): Promise<MutationResponse> {
|
|
19
93
|
return await sendCommand(ctx.messageBus, {
|
|
20
|
-
type: '<%=
|
|
94
|
+
type: '<%= cmd.type %>',
|
|
21
95
|
kind: 'Command',
|
|
22
96
|
data: { ...input },
|
|
23
97
|
});
|
|
@@ -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('generateScaffoldFilePlans', () => {
|
|
6
6
|
it('should generate a valid register file', async () => {
|
|
@@ -16,7 +16,6 @@ describe('generateScaffoldFilePlans', () => {
|
|
|
16
16
|
stream: 'listings-${propertyId}',
|
|
17
17
|
client: {
|
|
18
18
|
description: 'test',
|
|
19
|
-
specs: [],
|
|
20
19
|
},
|
|
21
20
|
server: {
|
|
22
21
|
description: 'test',
|
|
@@ -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 an initial state', async () => {
|
|
@@ -15,7 +15,6 @@ describe('state.ts.ejs', () => {
|
|
|
15
15
|
name: 'Create listing',
|
|
16
16
|
client: {
|
|
17
17
|
description: 'test',
|
|
18
|
-
specs: [],
|
|
19
18
|
},
|
|
20
19
|
server: {
|
|
21
20
|
description: 'test',
|
|
@@ -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('projection.specs.ts.ejs', () => {
|
|
6
6
|
it('should generate a valid test spec for a query slice projection', async () => {
|
|
@@ -14,7 +14,7 @@ describe('projection.specs.ts.ejs', () => {
|
|
|
14
14
|
type: 'command',
|
|
15
15
|
name: 'CreateListing',
|
|
16
16
|
stream: 'listing-${propertyId}',
|
|
17
|
-
client: { description: ''
|
|
17
|
+
client: { description: '' },
|
|
18
18
|
server: {
|
|
19
19
|
description: '',
|
|
20
20
|
specs: {
|
|
@@ -73,7 +73,7 @@ describe('projection.specs.ts.ejs', () => {
|
|
|
73
73
|
type: 'query',
|
|
74
74
|
name: 'search-listings',
|
|
75
75
|
stream: 'listings',
|
|
76
|
-
client: { description: ''
|
|
76
|
+
client: { description: '' },
|
|
77
77
|
server: {
|
|
78
78
|
description: '',
|
|
79
79
|
data: [
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { generateScaffoldFilePlans } from '../../scaffoldFromSchema';
|
|
3
|
-
import {
|
|
3
|
+
import { Model } from '@auto-engineer/flow';
|
|
4
4
|
|
|
5
5
|
describe('projection.ts.ejs', () => {
|
|
6
6
|
it('should generate a valid projection file with correct relative event import path from producing slice', async () => {
|
|
7
|
-
const
|
|
7
|
+
const flows: Model = {
|
|
8
8
|
variant: 'specs',
|
|
9
9
|
flows: [
|
|
10
10
|
{
|
|
@@ -16,7 +16,6 @@ describe('projection.ts.ejs', () => {
|
|
|
16
16
|
stream: 'listing-${propertyId}',
|
|
17
17
|
client: {
|
|
18
18
|
description: 'create listing UI',
|
|
19
|
-
specs: [],
|
|
20
19
|
},
|
|
21
20
|
server: {
|
|
22
21
|
description: 'handles create/remove listing',
|
|
@@ -78,7 +77,6 @@ describe('projection.ts.ejs', () => {
|
|
|
78
77
|
stream: 'listings',
|
|
79
78
|
client: {
|
|
80
79
|
description: 'search listings UI',
|
|
81
|
-
specs: [],
|
|
82
80
|
},
|
|
83
81
|
server: {
|
|
84
82
|
description: 'projection for available listings',
|
|
@@ -203,7 +201,7 @@ describe('projection.ts.ejs', () => {
|
|
|
203
201
|
],
|
|
204
202
|
};
|
|
205
203
|
|
|
206
|
-
const plans = await generateScaffoldFilePlans(
|
|
204
|
+
const plans = await generateScaffoldFilePlans(flows.flows, flows.messages, undefined, 'src/domain/flows');
|
|
207
205
|
const projectionFile = plans.find((p) => p.outputPath.endsWith('projection.ts'));
|
|
208
206
|
|
|
209
207
|
expect(projectionFile?.contents).toMatchInlineSnapshot(`
|
|
@@ -263,7 +261,7 @@ describe('projection.ts.ejs', () => {
|
|
|
263
261
|
`);
|
|
264
262
|
});
|
|
265
263
|
it('should generate a valid query resolver using ID type', async () => {
|
|
266
|
-
const spec:
|
|
264
|
+
const spec: Model = {
|
|
267
265
|
variant: 'specs',
|
|
268
266
|
flows: [
|
|
269
267
|
{
|
|
@@ -282,7 +280,6 @@ describe('projection.ts.ejs', () => {
|
|
|
282
280
|
`,
|
|
283
281
|
client: {
|
|
284
282
|
description: '',
|
|
285
|
-
specs: [],
|
|
286
283
|
},
|
|
287
284
|
server: {
|
|
288
285
|
description: '',
|
|
@@ -346,13 +343,12 @@ describe('projection.ts.ejs', () => {
|
|
|
346
343
|
|
|
347
344
|
// ## IMPLEMENTATION INSTRUCTIONS ##
|
|
348
345
|
// You can query the projection using the ReadModel API:
|
|
349
|
-
//
|
|
350
346
|
// - model.getAll() — fetch all documents
|
|
351
347
|
// - model.getById(id) — fetch a single document by ID (default key: 'id')
|
|
352
348
|
// - model.find(filterFn) — filter documents using a predicate
|
|
353
349
|
// - model.first(filterFn) — fetch the first document matching a predicate
|
|
354
350
|
//
|
|
355
|
-
// Example below uses
|
|
351
|
+
// Example below uses \\\`.find()\\\` to filter
|
|
356
352
|
// change the logic for the query as needed to meet the requirements for the current slice.
|
|
357
353
|
|
|
358
354
|
return model.find((item) => {
|