@auto-engineer/server-generator-apollo-emmett 1.72.0 → 1.74.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 +54 -0
- package/dist/src/codegen/scaffoldFromSchema.d.ts.map +1 -1
- package/dist/src/codegen/scaffoldFromSchema.js +0 -1
- package/dist/src/codegen/scaffoldFromSchema.js.map +1 -1
- package/dist/src/codegen/templates/query/query.resolver.specs.ts +122 -0
- package/dist/src/codegen/templates/query/query.resolver.ts.ejs +3 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/ketchup-plan.md +3 -5
- package/package.json +4 -4
- package/src/codegen/scaffoldFromSchema.ts +0 -1
- package/src/codegen/templates/query/query.resolver.specs.ts +122 -0
- package/src/codegen/templates/query/query.resolver.ts.ejs +3 -3
package/ketchup-plan.md
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
# Ketchup Plan: Fix
|
|
1
|
+
# Ketchup Plan: Fix query resolver collection name casing mismatch
|
|
2
2
|
|
|
3
3
|
## TODO
|
|
4
4
|
|
|
5
5
|
## DONE
|
|
6
6
|
|
|
7
|
-
- [x] Burst
|
|
8
|
-
|
|
9
|
-
- [x] Burst 1: Fix react.specs.ts.ejs — seed event store with Given state data via appendToStream (0afa65ca)
|
|
10
|
-
- [x] Burst 2: Fix react.ts.ejs — generate aggregateStream pattern when Given states exist (8380e5a2)
|
|
7
|
+
- [x] Burst 1: Add regression test + fix EJS template to use projectionName for collection name (5df3ae89)
|
|
8
|
+
- [x] Burst 2: Remove unused projectionType from scaffoldFromSchema template locals
|
package/package.json
CHANGED
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"uuid": "^11.0.0",
|
|
33
33
|
"web-streams-polyfill": "^4.1.0",
|
|
34
34
|
"zod": "^3.22.4",
|
|
35
|
-
"@auto-engineer/narrative": "1.
|
|
36
|
-
"@auto-engineer/message-bus": "1.
|
|
35
|
+
"@auto-engineer/narrative": "1.74.0",
|
|
36
|
+
"@auto-engineer/message-bus": "1.74.0"
|
|
37
37
|
},
|
|
38
38
|
"publishConfig": {
|
|
39
39
|
"access": "public"
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
"typescript": "^5.8.3",
|
|
45
45
|
"vitest": "^3.2.4",
|
|
46
46
|
"tsx": "^4.19.2",
|
|
47
|
-
"@auto-engineer/cli": "1.
|
|
47
|
+
"@auto-engineer/cli": "1.74.0"
|
|
48
48
|
},
|
|
49
|
-
"version": "1.
|
|
49
|
+
"version": "1.74.0",
|
|
50
50
|
"scripts": {
|
|
51
51
|
"generate:server": "tsx src/cli/index.ts",
|
|
52
52
|
"build": "tsc && tsx ../../scripts/fix-esm-imports.ts && rm -rf dist/src/codegen/templates && mkdir -p dist/src/codegen && cp -r src/codegen/templates dist/src/codegen/templates && cp src/server.ts dist/src && cp -r src/utils dist/src && cp -r src/domain dist/src",
|
|
@@ -608,7 +608,6 @@ async function prepareTemplateData(
|
|
|
608
608
|
projectionIdField,
|
|
609
609
|
projectionSingleton,
|
|
610
610
|
projectionName,
|
|
611
|
-
projectionType: projectionName != null ? pascalCase(projectionName) : undefined,
|
|
612
611
|
parsedRequest: slice.type === 'query' && slice.request != null ? parseGraphQlRequest(slice.request) : undefined,
|
|
613
612
|
messages: allMessages,
|
|
614
613
|
message:
|
|
@@ -957,6 +957,128 @@ describe('query.resolver.ts.ejs', () => {
|
|
|
957
957
|
`);
|
|
958
958
|
});
|
|
959
959
|
|
|
960
|
+
it('should use original-case projection name as collection name, not PascalCase', async () => {
|
|
961
|
+
const spec: SpecsSchema = {
|
|
962
|
+
variant: 'specs',
|
|
963
|
+
narratives: [
|
|
964
|
+
{
|
|
965
|
+
name: 'video-flow',
|
|
966
|
+
slices: [
|
|
967
|
+
{
|
|
968
|
+
type: 'query',
|
|
969
|
+
name: 'browse-videos',
|
|
970
|
+
request: `
|
|
971
|
+
query BrowseVideos($category: String) {
|
|
972
|
+
browseVideos(category: $category) {
|
|
973
|
+
videoId
|
|
974
|
+
title
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
`,
|
|
978
|
+
client: { specs: [] },
|
|
979
|
+
server: {
|
|
980
|
+
description: '',
|
|
981
|
+
data: {
|
|
982
|
+
items: [
|
|
983
|
+
{
|
|
984
|
+
origin: {
|
|
985
|
+
type: 'projection',
|
|
986
|
+
idField: 'videoId',
|
|
987
|
+
name: 'videos',
|
|
988
|
+
},
|
|
989
|
+
target: {
|
|
990
|
+
type: 'State',
|
|
991
|
+
name: 'VideoListing',
|
|
992
|
+
},
|
|
993
|
+
},
|
|
994
|
+
],
|
|
995
|
+
},
|
|
996
|
+
specs: [],
|
|
997
|
+
},
|
|
998
|
+
},
|
|
999
|
+
],
|
|
1000
|
+
},
|
|
1001
|
+
],
|
|
1002
|
+
messages: [
|
|
1003
|
+
{
|
|
1004
|
+
type: 'state',
|
|
1005
|
+
name: 'VideoListing',
|
|
1006
|
+
fields: [
|
|
1007
|
+
{ name: 'videoId', type: 'string', required: true },
|
|
1008
|
+
{ name: 'title', type: 'string', required: true },
|
|
1009
|
+
],
|
|
1010
|
+
},
|
|
1011
|
+
],
|
|
1012
|
+
};
|
|
1013
|
+
|
|
1014
|
+
const { plans } = await generateScaffoldFilePlans(spec.narratives, spec.messages, undefined, 'src/domain/flows');
|
|
1015
|
+
const resolverFile = plans.find((p) => p.outputPath.endsWith('query.resolver.ts'));
|
|
1016
|
+
|
|
1017
|
+
expect(resolverFile?.contents).toContain("new ReadModel<VideoListing>(ctx.database, 'videos')");
|
|
1018
|
+
expect(resolverFile?.contents).not.toContain("'Videos'");
|
|
1019
|
+
});
|
|
1020
|
+
|
|
1021
|
+
it('should use original-case projection name in singleton collection lookup', async () => {
|
|
1022
|
+
const spec: SpecsSchema = {
|
|
1023
|
+
variant: 'specs',
|
|
1024
|
+
narratives: [
|
|
1025
|
+
{
|
|
1026
|
+
name: 'video-flow',
|
|
1027
|
+
slices: [
|
|
1028
|
+
{
|
|
1029
|
+
type: 'query',
|
|
1030
|
+
name: 'views-video-stats',
|
|
1031
|
+
request: `
|
|
1032
|
+
query VideoStats {
|
|
1033
|
+
videoStats {
|
|
1034
|
+
totalViews
|
|
1035
|
+
totalVideos
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
`,
|
|
1039
|
+
client: { specs: [] },
|
|
1040
|
+
server: {
|
|
1041
|
+
description: '',
|
|
1042
|
+
data: {
|
|
1043
|
+
items: [
|
|
1044
|
+
{
|
|
1045
|
+
origin: {
|
|
1046
|
+
type: 'projection',
|
|
1047
|
+
name: 'videoStats',
|
|
1048
|
+
singleton: true,
|
|
1049
|
+
},
|
|
1050
|
+
target: {
|
|
1051
|
+
type: 'State',
|
|
1052
|
+
name: 'VideoStats',
|
|
1053
|
+
},
|
|
1054
|
+
},
|
|
1055
|
+
],
|
|
1056
|
+
},
|
|
1057
|
+
specs: [],
|
|
1058
|
+
},
|
|
1059
|
+
},
|
|
1060
|
+
],
|
|
1061
|
+
},
|
|
1062
|
+
],
|
|
1063
|
+
messages: [
|
|
1064
|
+
{
|
|
1065
|
+
type: 'state',
|
|
1066
|
+
name: 'VideoStats',
|
|
1067
|
+
fields: [
|
|
1068
|
+
{ name: 'totalViews', type: 'number', required: true },
|
|
1069
|
+
{ name: 'totalVideos', type: 'number', required: true },
|
|
1070
|
+
],
|
|
1071
|
+
},
|
|
1072
|
+
],
|
|
1073
|
+
};
|
|
1074
|
+
|
|
1075
|
+
const { plans } = await generateScaffoldFilePlans(spec.narratives, spec.messages, undefined, 'src/domain/flows');
|
|
1076
|
+
const resolverFile = plans.find((p) => p.outputPath.endsWith('query.resolver.ts'));
|
|
1077
|
+
|
|
1078
|
+
expect(resolverFile?.contents).toContain("ctx.database.collection<VideoStats>('videoStats').findOne()");
|
|
1079
|
+
expect(resolverFile?.contents).not.toContain("'VideoStats'");
|
|
1080
|
+
});
|
|
1081
|
+
|
|
960
1082
|
it('should generate @ObjectType classes for referenced message types', async () => {
|
|
961
1083
|
const spec: SpecsSchema = {
|
|
962
1084
|
variant: 'specs',
|
|
@@ -4,7 +4,7 @@ const projection = slice?.server?.data?.items?.[0]?.origin;
|
|
|
4
4
|
const isSingleton = projection?.singleton === true;
|
|
5
5
|
const queryName = parsedRequest?.queryName ?? camelCase(sliceName);
|
|
6
6
|
const viewType = target?.name ? pascalCase(target.name) : 'UnknownView';
|
|
7
|
-
const
|
|
7
|
+
const collectionName = projectionName || 'unknown-collection';
|
|
8
8
|
const message = messages?.find(m => m.name === viewType);
|
|
9
9
|
const resolverClassName = `${pascalCase(slice.name)}QueryResolver`;
|
|
10
10
|
const usesID = parsedRequest?.args?.some(arg => graphqlType(arg.tsType) === 'ID');
|
|
@@ -111,7 +111,7 @@ async <%= queryName %>(
|
|
|
111
111
|
%> @Arg('<%= arg.name %>', () => <%= gqlType %>, { nullable: true }) <%= arg.name %>?: <%= tsType %><%= i < parsedRequest.args.length - 1 ? ',' : '' %>
|
|
112
112
|
<% } } %>
|
|
113
113
|
): Promise<<%= viewType %>> {
|
|
114
|
-
const result = await ctx.database.collection<<%= viewType %>>('<%=
|
|
114
|
+
const result = await ctx.database.collection<<%= viewType %>>('<%= collectionName %>').findOne();
|
|
115
115
|
|
|
116
116
|
if (!result) {
|
|
117
117
|
return {
|
|
@@ -154,7 +154,7 @@ async <%= queryName %>(
|
|
|
154
154
|
%> @Arg('<%= arg.name %>', () => <%= gqlType %>, { nullable: true }) <%= arg.name %>?: <%= tsType %><%= i < parsedRequest.args.length - 1 ? ',' : '' %>
|
|
155
155
|
<% } } %>
|
|
156
156
|
): Promise<<%= viewType %>[]> {
|
|
157
|
-
const model = new ReadModel<<%= viewType %>>(ctx.database, '<%=
|
|
157
|
+
const model = new ReadModel<<%= viewType %>>(ctx.database, '<%= collectionName %>');
|
|
158
158
|
|
|
159
159
|
// ## IMPLEMENTATION INSTRUCTIONS ##
|
|
160
160
|
// You can query the projection using the ReadModel API:
|