@izara_project/izara-core-generate-service-code 1.0.90 → 1.0.92
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/package.json +7 -10
- package/src/compile/flowValidator.js +6 -0
- package/src/compile/loadSchemas.js +177 -69
- package/src/emit/crud/emitDynamicCrudFlowSchemas.js +2 -2
- package/src/emit/crud/generateCrudApplicationArtifacts.js +15 -17
- package/src/emit/crud/generateDynamicCrudFlowSchemas.js +16 -21
- package/src/emit/crud/loadLocalSchemaArrays.js +4 -8
- package/src/emit/crud/templates/CreateAfterHookCallback_Main.ejs +6 -6
- package/src/emit/crud/templates/CreateBeforeHookCallback_Main.ejs +3 -3
- package/src/emit/crud/templates/CreateComplete_Main.ejs +22 -22
- package/src/emit/crud/templates/CreateEndpoint_Main.ejs +18 -18
- package/src/emit/crud/templates/CreateLogicalLib.ejs +47 -47
- package/src/emit/crud/templates/CreateNodeCallback_Main.ejs +24 -24
- package/src/emit/crud/templates/DeleteAfterHookCallback_Main.ejs +5 -5
- package/src/emit/crud/templates/DeleteBeforeHookCallback_Main.ejs +3 -3
- package/src/emit/crud/templates/DeleteComplete_Main.ejs +23 -23
- package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +15 -15
- package/src/emit/crud/templates/DeleteLogicalLib.ejs +19 -19
- package/src/emit/crud/templates/FlowEndpointRbacCallback_Main.ejs +3 -3
- package/src/emit/crud/templates/UpdateAfterHookCallback_Main.ejs +5 -5
- package/src/emit/crud/templates/UpdateBeforeHookCallback_Main.ejs +3 -3
- package/src/emit/crud/templates/UpdateComplete_Main.ejs +22 -22
- package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +15 -15
- package/src/emit/crud/templates/UpdateLogicalLib.ejs +33 -33
- package/src/emit/custom/customFlowPaths.js +149 -0
- package/src/emit/custom/customFlowS3.js +156 -0
- package/src/emit/custom/customFlowSteps.js +385 -0
- package/src/emit/custom/customFlowTemplates.js +28 -0
- package/src/emit/custom/customFlows.js +48 -19
- package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +57 -692
- package/src/emit/custom/generateCustomFlowApplicationArtifacts.js +27 -25
- package/src/emit/custom/templates/FlowEndpointRbacCallback_Main.ejs +7 -7
- package/src/emit/custom/templates/s3/ConfirmReserved_HdrSqs.ejs +3 -3
- package/src/emit/custom/templates/s3/ConfirmReserved_Main.ejs +3 -3
- package/src/emit/custom/templates/s3/CreatePreSignUrl_HdrSqs.ejs +3 -3
- package/src/emit/custom/templates/s3/CreatePreSignUrl_Main.ejs +4 -4
- package/src/emit/rbac/emitDynamicRbacFlowSchemas.js +26 -6
- package/src/emit/rbac/emitRbacApplicationArtifacts.js +40 -13
- package/src/emit/rbac/generateCreateTargetRoleHandler.js +11 -13
- package/src/emit/rbac/generateDynamicRbacFlowSchemas.js +14 -18
- package/src/emit/rbac/templates/UserRbacFlow_Main.ejs +13 -7
- package/src/emit/relationship/emitDynamicRelationshipFlowSchemas.js +1 -1
- package/src/emit/relationship/generateDynamicRelationshipFlowSchemas.js +16 -19
- package/src/emit/relationship/generateRelationshipApplicationArtifacts.js +19 -19
- package/src/emit/relationship/templates/ChangeRelationshipComplete_HdrSqs.ejs +2 -2
- package/src/emit/relationship/templates/ChangeRelationshipComplete_Main.ejs +6 -6
- package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +17 -17
- package/src/emit/relationship/templates/CreateRelationshipComplete_HdrSqs.ejs +2 -2
- package/src/emit/relationship/templates/CreateRelationshipComplete_Main.ejs +6 -6
- package/src/emit/relationship/templates/CreateRelationship_Main.ejs +14 -14
- package/src/emit/relationship/templates/DeleteRelationshipComplete_HdrSqs.ejs +2 -2
- package/src/emit/relationship/templates/DeleteRelationshipComplete_Main.ejs +6 -6
- package/src/emit/relationship/templates/DeleteRelationship_Main.ejs +10 -10
- package/src/emit/relationship/templates/GetRelationshipComplete_HdrSqs.ejs +2 -2
- package/src/emit/relationship/templates/GetRelationshipComplete_Main.ejs +5 -5
- package/src/emit/relationship/templates/GetRelationship_Main.ejs +9 -9
- package/src/emit/relationship/templates/MoveRelationshipComplete_HdrSqs.ejs +2 -2
- package/src/emit/relationship/templates/MoveRelationshipComplete_Main.ejs +6 -6
- package/src/emit/relationship/templates/MoveRelationship_Main.ejs +15 -15
- package/src/emit/relationship/templates/UpdateRelationshipComplete_HdrSqs.ejs +2 -2
- package/src/emit/relationship/templates/UpdateRelationshipComplete_Main.ejs +6 -6
- package/src/emit/relationship/templates/UpdateRelationship_Main.ejs +11 -11
- package/src/emit/resource/dynamoResourceArtifacts.js +18 -0
- package/src/emit/resource/emitResourceArtifacts.js +13 -1251
- package/src/emit/resource/generateResourceArtifacts.js +20 -20
- package/src/emit/resource/iamResourceArtifacts.js +612 -0
- package/src/emit/resource/resourceState.js +564 -0
- package/src/emit/resource/resourceTemplate.js +30 -0
- package/src/emit/resource/s3ResourceArtifacts.js +14 -0
- package/src/emit/resource/sqsResourceArtifacts.js +113 -0
- package/src/emit/shared/runSubsystemGeneration.js +55 -0
- package/src/emit/shared/templates/FindData_Main.ejs +19 -19
- package/src/emit/shared/templates/PaginateProcessLogical_Main.ejs +3 -3
- package/src/emit/shared/templates/ProcessLogical_Main.ejs +15 -15
- package/src/emit/system/emitSystemWebSocketArtifacts.js +2 -1
- package/test/createTargetRoleHandler.test.js +62 -4
- package/test/crudApplicationArtifacts.test.js +75 -3
- package/test/customFlowApplicationArtifacts.test.js +98 -0
- package/test/dynamicCrudFlowSchemas.test.js +2 -2
- package/test/dynamicRbacFlowSchemas.test.js +32 -4
- package/test/relationshipApplicationArtifacts.test.js +1 -1
- package/test/resourceArtifacts.test.js +99 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { indentYaml, renderResourceTemplate } from './resourceTemplate.js';
|
|
2
|
+
|
|
3
|
+
export async function renderResourceGroup({
|
|
4
|
+
ownTopics = [],
|
|
5
|
+
sqsQueues = [],
|
|
6
|
+
dsqQueues = [],
|
|
7
|
+
webSocketSubscriptions = [],
|
|
8
|
+
s3Subscriptions = []
|
|
9
|
+
}) {
|
|
10
|
+
const hasResources =
|
|
11
|
+
ownTopics.length > 0 ||
|
|
12
|
+
sqsQueues.length > 0 ||
|
|
13
|
+
dsqQueues.length > 0 ||
|
|
14
|
+
webSocketSubscriptions.length > 0 ||
|
|
15
|
+
s3Subscriptions.length > 0;
|
|
16
|
+
if (!hasResources) {
|
|
17
|
+
return '';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const chunks = await Promise.all([
|
|
21
|
+
...ownTopics.map((queueName) =>
|
|
22
|
+
renderResourceTemplate('ResourceYaml.ejs', { queueName })
|
|
23
|
+
),
|
|
24
|
+
...sqsQueues.map((queueName) =>
|
|
25
|
+
renderResourceTemplate('ResourceSqsYaml.ejs', { queueName })
|
|
26
|
+
),
|
|
27
|
+
...dsqQueues.map((queueName) =>
|
|
28
|
+
renderResourceTemplate('ResourceSqsYaml.ejs', { queueName })
|
|
29
|
+
)
|
|
30
|
+
]);
|
|
31
|
+
const wsSubs = await Promise.all(
|
|
32
|
+
webSocketSubscriptions.map((topicName) =>
|
|
33
|
+
renderWebSocketSubscription(topicName)
|
|
34
|
+
)
|
|
35
|
+
);
|
|
36
|
+
const s3Subs = await Promise.all(
|
|
37
|
+
s3Subscriptions.map(({ subscriptionName, topicName, queueName }) =>
|
|
38
|
+
renderResourceTemplate('S3Subscription_Yaml.ejs', {
|
|
39
|
+
subscriptionName,
|
|
40
|
+
topicName,
|
|
41
|
+
queueName
|
|
42
|
+
})
|
|
43
|
+
)
|
|
44
|
+
);
|
|
45
|
+
const parts = [chunks.join('\n')];
|
|
46
|
+
if (wsSubs.length > 0) {
|
|
47
|
+
parts.push(wsSubs.join('\n'));
|
|
48
|
+
}
|
|
49
|
+
if (s3Subs.length > 0) {
|
|
50
|
+
parts.push(s3Subs.join('\n'));
|
|
51
|
+
}
|
|
52
|
+
const body = parts.filter(Boolean).join('\n');
|
|
53
|
+
if (!body.trim()) {
|
|
54
|
+
return '';
|
|
55
|
+
}
|
|
56
|
+
return `Resources:\n${indentYaml(body, 2)}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function renderCrudInSqs(state) {
|
|
60
|
+
return renderResourceGroup({
|
|
61
|
+
ownTopics: state.crudOwnTopics,
|
|
62
|
+
sqsQueues: state.crudSqsQueues
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function renderRelationshipInSqs(state) {
|
|
67
|
+
return renderResourceGroup({
|
|
68
|
+
ownTopics: state.relationshipOwnTopics,
|
|
69
|
+
sqsQueues: state.relationshipSqsQueues,
|
|
70
|
+
dsqQueues: state.relationshipDsqQueues
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function renderRbacInSqs(state) {
|
|
75
|
+
return renderResourceGroup({
|
|
76
|
+
ownTopics: state.rbacOwnTopics,
|
|
77
|
+
sqsQueues: state.rbacSqsQueues
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export async function renderCustomFlowInSqs(state) {
|
|
82
|
+
return renderResourceGroup({
|
|
83
|
+
ownTopics: state.customOwnTopics,
|
|
84
|
+
sqsQueues: state.customSqsQueues,
|
|
85
|
+
dsqQueues: state.customDsqQueues,
|
|
86
|
+
s3Subscriptions: state.s3Subscriptions
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function renderSystemInSqs(state) {
|
|
91
|
+
return renderResourceGroup({
|
|
92
|
+
ownTopics: state.systemOwnTopics,
|
|
93
|
+
sqsQueues: state.systemSqsQueues,
|
|
94
|
+
dsqQueues: state.systemDsqQueues,
|
|
95
|
+
webSocketSubscriptions: state.webSocketSubscriptions
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function renderOut(state) {
|
|
100
|
+
const renderedTopics = await Promise.all(
|
|
101
|
+
state.outTopics.map((topicName) =>
|
|
102
|
+
renderResourceTemplate('FlowOut_Yaml.ejs', { topicName })
|
|
103
|
+
)
|
|
104
|
+
);
|
|
105
|
+
const body = renderedTopics.join('\n');
|
|
106
|
+
return `Resources:\n${indentYaml(body, 2)}`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function renderWebSocketSubscription(topicName) {
|
|
110
|
+
return renderResourceTemplate('WebSocketSubscription_Yaml.ejs', {
|
|
111
|
+
topicName
|
|
112
|
+
});
|
|
113
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { compileProject } from '../../compile/compileProject.js';
|
|
2
|
+
import { buildGenerationPlan } from '../../plan/buildGenerationPlan.js';
|
|
3
|
+
import { commitArtifacts } from '../../output/commitArtifacts.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Common pipeline runner for emitting and committing subsystem artifacts.
|
|
7
|
+
*
|
|
8
|
+
* @param {Object} params
|
|
9
|
+
* @param {string} params.rootPath Root path of the service project.
|
|
10
|
+
* @param {Object} [params.options={}] Options passed to compile and load.
|
|
11
|
+
* @param {Function} [params.loadInputs] Function to load schemas or inputs.
|
|
12
|
+
* @param {Function} params.emitArtifacts Function to emit artifacts.
|
|
13
|
+
* @param {string} params.managedScope Scope identifier for generation plan.
|
|
14
|
+
* @param {Array<string>|Function} params.resolveManagedPaths Managed paths.
|
|
15
|
+
* @returns {Promise<{ project: Object, files: Array<string> }>}
|
|
16
|
+
*/
|
|
17
|
+
export async function runSubsystemGeneration({
|
|
18
|
+
rootPath,
|
|
19
|
+
options = {},
|
|
20
|
+
loadInputs,
|
|
21
|
+
emitArtifacts,
|
|
22
|
+
managedScope,
|
|
23
|
+
resolveManagedPaths
|
|
24
|
+
}) {
|
|
25
|
+
const project = compileProject({ ...options, rootPath });
|
|
26
|
+
|
|
27
|
+
let inputs = {};
|
|
28
|
+
if (typeof loadInputs === 'function') {
|
|
29
|
+
inputs = await loadInputs(project, options);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const artifacts = await emitArtifacts({
|
|
33
|
+
project,
|
|
34
|
+
options,
|
|
35
|
+
...inputs
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
let managedPaths = resolveManagedPaths;
|
|
39
|
+
if (typeof resolveManagedPaths === 'function') {
|
|
40
|
+
managedPaths = await resolveManagedPaths({
|
|
41
|
+
project,
|
|
42
|
+
options,
|
|
43
|
+
artifacts,
|
|
44
|
+
...inputs
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const plan = buildGenerationPlan(project, artifacts, {
|
|
49
|
+
managedPaths,
|
|
50
|
+
managedScope
|
|
51
|
+
});
|
|
52
|
+
const files = await commitArtifacts(plan);
|
|
53
|
+
|
|
54
|
+
return { project, files };
|
|
55
|
+
}
|
|
@@ -87,7 +87,7 @@ export default async function findData(
|
|
|
87
87
|
}
|
|
88
88
|
};
|
|
89
89
|
|
|
90
|
-
let
|
|
90
|
+
let foundErrors = [];
|
|
91
91
|
|
|
92
92
|
let standardErrorParams = [
|
|
93
93
|
_izContext,
|
|
@@ -139,8 +139,8 @@ export default async function findData(
|
|
|
139
139
|
_izContext.logger.debug('objInstanceBase: ', objInstanceBase)
|
|
140
140
|
|
|
141
141
|
if (!objInstanceBase) {
|
|
142
|
-
|
|
143
|
-
standardErrorParams.push(
|
|
142
|
+
foundErrors.push(`can't get data in dynamo by ${identifiersBase}`)
|
|
143
|
+
standardErrorParams.push(foundErrors)
|
|
144
144
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
145
145
|
return {
|
|
146
146
|
returnResponse: 'FindData cannot get data in dynamo'
|
|
@@ -148,8 +148,8 @@ export default async function findData(
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
if (!objInstanceBase.hasOwnProperty(fieldName.fieldName)) {
|
|
151
|
-
|
|
152
|
-
standardErrorParams.push(
|
|
151
|
+
foundErrors.push(`data in dynamoDB have no ${fieldName.fieldName}`)
|
|
152
|
+
standardErrorParams.push(foundErrors)
|
|
153
153
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
154
154
|
return {
|
|
155
155
|
returnResponse: 'Data have no fieldName'
|
|
@@ -195,8 +195,8 @@ export default async function findData(
|
|
|
195
195
|
_izContext.logger.debug('objInstanceBase: ', objInstanceBase)
|
|
196
196
|
|
|
197
197
|
if (!objInstanceBase) {
|
|
198
|
-
|
|
199
|
-
standardErrorParams.push(
|
|
198
|
+
foundErrors.push(`can't get data in dynamo by ${identifiersBase}`)
|
|
199
|
+
standardErrorParams.push(foundErrors)
|
|
200
200
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
201
201
|
return {
|
|
202
202
|
returnResponse: 'FindData cannot get data in dynamo'
|
|
@@ -204,8 +204,8 @@ export default async function findData(
|
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
if (!objInstanceBase.hasOwnProperty(fieldName.fieldName)) {
|
|
207
|
-
|
|
208
|
-
standardErrorParams.push(
|
|
207
|
+
foundErrors.push(`data in dynamoDB have no ${fieldName.fieldName}`)
|
|
208
|
+
standardErrorParams.push(foundErrors)
|
|
209
209
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
210
210
|
return {
|
|
211
211
|
returnResponse: 'Data have no fieldName'
|
|
@@ -255,8 +255,8 @@ export default async function findData(
|
|
|
255
255
|
_izContext.logger.debug('getDataByGraph: ', getDataByGraph)
|
|
256
256
|
|
|
257
257
|
if (!getDataByGraph) {
|
|
258
|
-
|
|
259
|
-
standardErrorParams.push(
|
|
258
|
+
foundErrors.push(`can't get data of ${objType.objectType} in graph`)
|
|
259
|
+
standardErrorParams.push(foundErrors)
|
|
260
260
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
261
261
|
return {
|
|
262
262
|
returnResponse: 'FindData cannot get data in graph'
|
|
@@ -271,8 +271,8 @@ export default async function findData(
|
|
|
271
271
|
|
|
272
272
|
<% if (graphDetail.getInIdentifiers) { %>
|
|
273
273
|
if (!objInstanceFull.identifiers.hasOwnProperty(fieldName.fieldName)) {
|
|
274
|
-
|
|
275
|
-
standardErrorParams.push(
|
|
274
|
+
foundErrors.push(`nodeProperties have no this ${fieldName.fieldName}`)
|
|
275
|
+
standardErrorParams.push(foundErrors)
|
|
276
276
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
277
277
|
return {
|
|
278
278
|
returnResponse: 'Data have no fieldName'
|
|
@@ -283,8 +283,8 @@ export default async function findData(
|
|
|
283
283
|
_izContext.logger.debug('this fieldName is identifier, get dataValue in identifiers: ', dataValue)
|
|
284
284
|
<% } else { %>
|
|
285
285
|
if (!objInstanceFull.fields.hasOwnProperty(fieldName.fieldName)) {
|
|
286
|
-
|
|
287
|
-
standardErrorParams.push(
|
|
286
|
+
foundErrors.push(`nodeProperties have no this ${fieldName.fieldName}`)
|
|
287
|
+
standardErrorParams.push(foundErrors)
|
|
288
288
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
289
289
|
return {
|
|
290
290
|
returnResponse: 'Data have no fieldName'
|
|
@@ -314,8 +314,8 @@ export default async function findData(
|
|
|
314
314
|
else
|
|
315
315
|
|
|
316
316
|
<% } %> {
|
|
317
|
-
|
|
318
|
-
standardErrorParams.push(
|
|
317
|
+
foundErrors.push('unrecognized fieldName')
|
|
318
|
+
standardErrorParams.push(foundErrors)
|
|
319
319
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
320
320
|
return;
|
|
321
321
|
}
|
|
@@ -326,8 +326,8 @@ export default async function findData(
|
|
|
326
326
|
else
|
|
327
327
|
|
|
328
328
|
<% } %> {
|
|
329
|
-
|
|
330
|
-
standardErrorParams.push(
|
|
329
|
+
foundErrors.push('unrecognized objectType')
|
|
330
|
+
standardErrorParams.push(foundErrors)
|
|
331
331
|
await findDataSharedLib.completeFindDataMain(...standardErrorParams);
|
|
332
332
|
return {
|
|
333
333
|
returnResponse: 'Function FindData Error'
|
|
@@ -98,7 +98,7 @@ export default async function paginateProcessLogical(
|
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
let
|
|
101
|
+
let foundErrors = [];
|
|
102
102
|
let standardErrorParams = [
|
|
103
103
|
_izContext,
|
|
104
104
|
logicalResultId,
|
|
@@ -153,8 +153,8 @@ export default async function paginateProcessLogical(
|
|
|
153
153
|
|
|
154
154
|
if (!startKey && queryDatas.Items.length == 0) {
|
|
155
155
|
_izContext.logger.debug(`can't find data in table ${tableName}`);
|
|
156
|
-
|
|
157
|
-
standardErrorParams.push(
|
|
156
|
+
foundErrors.push(`can't find data in table ${tableName}`);
|
|
157
|
+
standardErrorParams.push(foundErrors);
|
|
158
158
|
await logicalResultsSharedLib.completeLogicalResultsMain(
|
|
159
159
|
...standardErrorParams
|
|
160
160
|
);
|
|
@@ -96,7 +96,7 @@ export default async function processLogical(
|
|
|
96
96
|
};
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
let
|
|
99
|
+
let foundErrors = [];
|
|
100
100
|
|
|
101
101
|
let standardErrorParams = [
|
|
102
102
|
_izContext,
|
|
@@ -114,16 +114,16 @@ export default async function processLogical(
|
|
|
114
114
|
element.comparison
|
|
115
115
|
)
|
|
116
116
|
) {
|
|
117
|
-
|
|
117
|
+
foundErrors.push('comparison is not possible comparison');
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
// validate partitionKeyValues
|
|
121
121
|
if (!element.hasOwnProperty('partitionKeyValues')) {
|
|
122
122
|
_izContext.logger.debug('element not have partitionKeyValues');
|
|
123
|
-
|
|
123
|
+
foundErrors.push('element not have partitionKeyValues');
|
|
124
124
|
} else if (Object.keys(element.partitionKeyValues).length === 0) {
|
|
125
125
|
_izContext.logger.debug('partitionKeyValues is empty');
|
|
126
|
-
|
|
126
|
+
foundErrors.push('partitionKeyValues is empty');
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
const objectSchemas = await getObjectSchema.getObjSchemaS3WithHierarchy(
|
|
@@ -186,7 +186,7 @@ export default async function processLogical(
|
|
|
186
186
|
if (element.hasOwnProperty('sortKeyValues')) {
|
|
187
187
|
continue;
|
|
188
188
|
} else {
|
|
189
|
-
|
|
189
|
+
foundErrors.push(
|
|
190
190
|
'schema error: dynamo storageResource set to groupByPartitionKeyField but no sortKey'
|
|
191
191
|
);
|
|
192
192
|
break;
|
|
@@ -219,7 +219,7 @@ export default async function processLogical(
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
if (!tableName) {
|
|
222
|
-
|
|
222
|
+
foundErrors.push('no valid dynamo storageResource found');
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
if (
|
|
@@ -230,19 +230,19 @@ export default async function processLogical(
|
|
|
230
230
|
_izContext.logger.debug(
|
|
231
231
|
'element have sortKeyValues but cannot find sortKey in object schemas'
|
|
232
232
|
);
|
|
233
|
-
|
|
233
|
+
foundErrors.push(
|
|
234
234
|
'element have sortKeyValues but cannot find sortKey in object schemas'
|
|
235
235
|
);
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
if (
|
|
239
|
-
_izContext.logger.debug('Have
|
|
240
|
-
standardErrorParams.push(
|
|
238
|
+
if (foundErrors.length > 0) {
|
|
239
|
+
_izContext.logger.debug('Have foundErrors: ', foundErrors);
|
|
240
|
+
standardErrorParams.push(foundErrors);
|
|
241
241
|
await logicalResultsSharedLib.completeLogicalResultsMain(
|
|
242
242
|
...standardErrorParams
|
|
243
243
|
);
|
|
244
244
|
return {
|
|
245
|
-
returnResponse: 'Have
|
|
245
|
+
returnResponse: 'Have foundErrors'
|
|
246
246
|
};
|
|
247
247
|
}
|
|
248
248
|
|
|
@@ -332,8 +332,8 @@ export default async function processLogical(
|
|
|
332
332
|
|
|
333
333
|
if (queryDatas.Items.length == 0) {
|
|
334
334
|
_izContext.logger.debug(`can't find data in ${tableName}`);
|
|
335
|
-
|
|
336
|
-
standardErrorParams.push(
|
|
335
|
+
foundErrors.push(`can't find data in ${tableName}`);
|
|
336
|
+
standardErrorParams.push(foundErrors);
|
|
337
337
|
await logicalResultsSharedLib.completeLogicalResultsMain(
|
|
338
338
|
...standardErrorParams
|
|
339
339
|
);
|
|
@@ -411,8 +411,8 @@ export default async function processLogical(
|
|
|
411
411
|
);
|
|
412
412
|
} else {
|
|
413
413
|
_izContext.logger.debug(`can't find data in ${tableName}`);
|
|
414
|
-
|
|
415
|
-
standardErrorParams.push(
|
|
414
|
+
foundErrors.push(`can't find data in ${tableName}`);
|
|
415
|
+
standardErrorParams.push(foundErrors);
|
|
416
416
|
await logicalResultsSharedLib.completeLogicalResultsMain(
|
|
417
417
|
...standardErrorParams
|
|
418
418
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import ejsLib from 'ejs';
|
|
3
|
+
import { flowHasOwnTopic } from '../custom/customFlows.js';
|
|
3
4
|
|
|
4
5
|
const TEMPLATE_URL = new URL('./templates/', import.meta.url);
|
|
5
6
|
const SOURCE = 'app/src/generatedCode/SystemFlowSchemas/WebSocketMain/source';
|
|
@@ -126,7 +127,7 @@ export function hasSystemWebSocket(
|
|
|
126
127
|
Array.isArray(flow?.event) &&
|
|
127
128
|
(flow.event.includes('s3') ||
|
|
128
129
|
(includeRelationshipOwnTopic &&
|
|
129
|
-
flow
|
|
130
|
+
flowHasOwnTopic(flow) &&
|
|
130
131
|
(flow.initiateBy === 'user' || flow.initiateBy === 'systemWithUser')))
|
|
131
132
|
)
|
|
132
133
|
);
|
|
@@ -36,7 +36,7 @@ test('generates RBAC own-topic WebSocket entries alongside their SQS handlers',
|
|
|
36
36
|
const rootPath = await createProject(true);
|
|
37
37
|
const result = await generateCreateTargetRoleHandler(rootPath);
|
|
38
38
|
|
|
39
|
-
assert.equal(result.files.length,
|
|
39
|
+
assert.equal(result.files.length, 60);
|
|
40
40
|
assert.match(
|
|
41
41
|
await readFile(join(rootPath, result.files[0].path), 'utf8'),
|
|
42
42
|
/CreateTargetRole/
|
|
@@ -118,7 +118,55 @@ test('generates RBAC own-topic WebSocket entries alongside their SQS handlers',
|
|
|
118
118
|
assert.match(validatorRbac, /return l2Hit;/);
|
|
119
119
|
assert.match(validatorRbac, /return cacheResult;/);
|
|
120
120
|
assert.doesNotMatch(validatorRbac, /L1 Cache hit:[^;]+;\s*return;/);
|
|
121
|
-
|
|
121
|
+
const validatorHdrInv = await readFile(
|
|
122
|
+
join(
|
|
123
|
+
rootPath,
|
|
124
|
+
'app/src/generatedCode/FlowRbac/ValidatorRbac/source/ValidatorRbac_HdrInv.js'
|
|
125
|
+
),
|
|
126
|
+
'utf8'
|
|
127
|
+
);
|
|
128
|
+
assert.match(
|
|
129
|
+
validatorHdrInv,
|
|
130
|
+
/import ValidatorRbac from '\.\/ValidatorRbac_Main\.js';/
|
|
131
|
+
);
|
|
132
|
+
assert.match(
|
|
133
|
+
validatorHdrInv,
|
|
134
|
+
/middleware\.setValidatorSchema\(validatorSchema\);/
|
|
135
|
+
);
|
|
136
|
+
assert.match(
|
|
137
|
+
validatorHdrInv,
|
|
138
|
+
/await ValidatorRbac\(event\._izContext, \.\.\.passOnProperties\);/
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const validatorHdrApi = await readFile(
|
|
142
|
+
join(
|
|
143
|
+
rootPath,
|
|
144
|
+
'app/src/generatedCode/FlowRbac/ValidatorRbac/source/ValidatorRbac_HdrApi.js'
|
|
145
|
+
),
|
|
146
|
+
'utf8'
|
|
147
|
+
);
|
|
148
|
+
assert.match(
|
|
149
|
+
validatorHdrApi,
|
|
150
|
+
/import ValidatorRbac from '\.\/ValidatorRbac_Main\.js';/
|
|
151
|
+
);
|
|
152
|
+
assert.match(
|
|
153
|
+
validatorHdrApi,
|
|
154
|
+
/middleware\.setValidatorSchema\(validatorSchema, { noAuthorizer: true }\);/
|
|
155
|
+
);
|
|
156
|
+
assert.match(
|
|
157
|
+
validatorHdrApi,
|
|
158
|
+
/await ValidatorRbac\(\s*event\._izContext,\s*\.\.\.passOnProperties\s*\);/
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
await assert.rejects(
|
|
162
|
+
readFile(
|
|
163
|
+
join(
|
|
164
|
+
rootPath,
|
|
165
|
+
'app/src/generatedCode/FlowRbac/ValidatorRbac/source/ValidatorRbac_HdrSqs.js'
|
|
166
|
+
)
|
|
167
|
+
)
|
|
168
|
+
);
|
|
169
|
+
|
|
122
170
|
assert.match(
|
|
123
171
|
await readFile(
|
|
124
172
|
join(
|
|
@@ -133,6 +181,16 @@ test('generates RBAC own-topic WebSocket entries alongside their SQS handlers',
|
|
|
133
181
|
join(rootPath, 'app/sls_yaml/generatedCode/source/flow-rbac.yml'),
|
|
134
182
|
'utf8'
|
|
135
183
|
);
|
|
184
|
+
assert.match(
|
|
185
|
+
rbacYaml,
|
|
186
|
+
/ValidatorRbacHdrInv:\n\s+handler: src\/generatedCode\/FlowRbac\/ValidatorRbac\/source\/ValidatorRbac_HdrInv\.main/
|
|
187
|
+
);
|
|
188
|
+
assert.match(
|
|
189
|
+
rbacYaml,
|
|
190
|
+
/ValidatorRbacHdrApi:\n\s+handler: src\/generatedCode\/FlowRbac\/ValidatorRbac\/source\/ValidatorRbac_HdrApi\.main/
|
|
191
|
+
);
|
|
192
|
+
assert.doesNotMatch(rbacYaml, /ValidatorRbacHdrSqs:/);
|
|
193
|
+
|
|
136
194
|
const limitYaml = await readFile(
|
|
137
195
|
join(rootPath, 'app/sls_yaml/generatedCode/source/flow-limits.yml'),
|
|
138
196
|
'utf8'
|
|
@@ -161,7 +219,7 @@ test('removes CreateTargetRole handler when RBAC is removed', async () => {
|
|
|
161
219
|
await generateCreateTargetRoleHandler(rootPath);
|
|
162
220
|
await writeFile(
|
|
163
221
|
objectPath,
|
|
164
|
-
"export default { objectType: 'user', addOnDataStructure: [] };\n"
|
|
222
|
+
"export default { objectType: 'user', generatedBy: 'user', fieldNames: { userId: { type: 'string', canUpdate: false, storageResourceTags: ['main'] } }, identifiers: [{ type: 'partitionKey', fieldName: 'userId' }], storageResources: { main: { storageType: 'dynamoDB', tableName: 'Users' } }, addOnDataStructure: [] };\n"
|
|
165
223
|
);
|
|
166
224
|
|
|
167
225
|
assert.deepEqual((await generateCreateTargetRoleHandler(rootPath)).files, []);
|
|
@@ -196,7 +254,7 @@ async function createProject(hasRbac) {
|
|
|
196
254
|
await mkdir(directory, { recursive: true });
|
|
197
255
|
await writeFile(
|
|
198
256
|
join(directory, 'User.js'),
|
|
199
|
-
`export default { objectType: 'user', fieldNames: [], identifiers: [], addOnDataStructure: ${addOns} };\n`
|
|
257
|
+
`export default { objectType: 'user', generatedBy: 'user', fieldNames: { userId: { type: 'string', canUpdate: false, storageResourceTags: ['main'] } }, identifiers: [{ type: 'partitionKey', fieldName: 'userId' }], storageResources: { main: { storageType: 'dynamoDB', tableName: 'Users' } }, addOnDataStructure: ${addOns} };\n`
|
|
200
258
|
);
|
|
201
259
|
return rootPath;
|
|
202
260
|
}
|
|
@@ -44,7 +44,7 @@ test('emits CRUD handlers and function YAML from schema data without reading gen
|
|
|
44
44
|
assert.match(createMain, /CreateLogicalLib/);
|
|
45
45
|
assert.match(
|
|
46
46
|
createMain,
|
|
47
|
-
/validateFieldNames\(_izContext, requestParams, objectSchemas,
|
|
47
|
+
/validateFieldNames\(_izContext, requestParams, objectSchemas, foundErrors\)/
|
|
48
48
|
);
|
|
49
49
|
assert.doesNotMatch(
|
|
50
50
|
createMain,
|
|
@@ -59,12 +59,12 @@ test('emits CRUD handlers and function YAML from schema data without reading gen
|
|
|
59
59
|
);
|
|
60
60
|
assert.match(
|
|
61
61
|
createLogicalLib,
|
|
62
|
-
/export async function resolveAndGenerateIdentifiers\(\s*_izContext,\s*requestParams,\s*objectSchema,\s*
|
|
62
|
+
/export async function resolveAndGenerateIdentifiers\(\s*_izContext,\s*requestParams,\s*objectSchema,\s*foundErrors\s*\)/
|
|
63
63
|
);
|
|
64
64
|
assert.match(createLogicalLib, /return \{\s*objectSchemas\s*\};/);
|
|
65
65
|
assert.match(
|
|
66
66
|
createLogicalLib,
|
|
67
|
-
/export function validateFieldNames\(\s*_izContext,\s*requestParams,\s*objectSchemas,\s*
|
|
67
|
+
/export function validateFieldNames\(\s*_izContext,\s*requestParams,\s*objectSchemas,\s*foundErrors\s*\)/
|
|
68
68
|
);
|
|
69
69
|
assert.doesNotMatch(
|
|
70
70
|
createLogicalLib,
|
|
@@ -1388,6 +1388,78 @@ test('emits autoProvisionOwnerTargetRole in CreateNodeCallback when service has
|
|
|
1388
1388
|
);
|
|
1389
1389
|
});
|
|
1390
1390
|
|
|
1391
|
+
test('emits synchronous before-hook invocation in Create_Main when event is generateCode and invocationType is lambdaSyncInv', async () => {
|
|
1392
|
+
const rootPath = await createProject(true);
|
|
1393
|
+
const schemas = join(rootPath, 'app/src/schemas');
|
|
1394
|
+
await writeFile(
|
|
1395
|
+
join(schemas, 'FlowSchemas/ValidateBeforeCreateSync.js'),
|
|
1396
|
+
"export default { flowTag: 'validateBeforeCreateSync', event: ['generateCode'], generatedCodeConfig: { generateCodeTag: 'create', codeHookTag: 'before', invocationType: 'lambdaSyncInv' }, objType: { objectType: 'order' } };\n"
|
|
1397
|
+
);
|
|
1398
|
+
await generateCrudApplicationArtifacts(rootPath, {
|
|
1399
|
+
serviceTag: 'orders'
|
|
1400
|
+
});
|
|
1401
|
+
|
|
1402
|
+
const createMain = await readFile(
|
|
1403
|
+
join(
|
|
1404
|
+
rootPath,
|
|
1405
|
+
'app/src/generatedCode/FlowObjects/Create/source/Create_Main.js'
|
|
1406
|
+
),
|
|
1407
|
+
'utf8'
|
|
1408
|
+
);
|
|
1409
|
+
assert.match(
|
|
1410
|
+
createMain,
|
|
1411
|
+
/lambda\.invokeSync\(\s*_izContext,\s*await lambdaSharedLib\.lambdaFunctionName\(\s*_izContext,\s*'validateBeforeCreateSync'\s*\)/
|
|
1412
|
+
);
|
|
1413
|
+
assert.match(createMain, /Hook validateBeforeCreateSync failed/);
|
|
1414
|
+
|
|
1415
|
+
execFileSync(
|
|
1416
|
+
process.execPath,
|
|
1417
|
+
[
|
|
1418
|
+
'--check',
|
|
1419
|
+
join(
|
|
1420
|
+
rootPath,
|
|
1421
|
+
'app/src/generatedCode/FlowObjects/Create/source/Create_Main.js'
|
|
1422
|
+
)
|
|
1423
|
+
],
|
|
1424
|
+
{ stdio: 'inherit' }
|
|
1425
|
+
);
|
|
1426
|
+
});
|
|
1427
|
+
|
|
1428
|
+
test('emits async before-hook callback and SNS publish in Create_Main when event is generateCode and invocationType is ownTopic', async () => {
|
|
1429
|
+
const rootPath = await createProject(true);
|
|
1430
|
+
const schemas = join(rootPath, 'app/src/schemas');
|
|
1431
|
+
await writeFile(
|
|
1432
|
+
join(schemas, 'FlowSchemas/ValidateBeforeCreateAsync.js'),
|
|
1433
|
+
"export default { flowTag: 'validateBeforeCreateAsync', event: ['generateCode'], generatedCodeConfig: { generateCodeTag: 'create', codeHookTag: 'before', invocationType: 'ownTopic' }, objType: { objectType: 'order' } };\n"
|
|
1434
|
+
);
|
|
1435
|
+
await generateCrudApplicationArtifacts(rootPath, {
|
|
1436
|
+
serviceTag: 'orders'
|
|
1437
|
+
});
|
|
1438
|
+
|
|
1439
|
+
const createMain = await readFile(
|
|
1440
|
+
join(
|
|
1441
|
+
rootPath,
|
|
1442
|
+
'app/src/generatedCode/FlowObjects/Create/source/Create_Main.js'
|
|
1443
|
+
),
|
|
1444
|
+
'utf8'
|
|
1445
|
+
);
|
|
1446
|
+
assert.match(createMain, /sns\.publishAsync\(_izContext,/);
|
|
1447
|
+
assert.match(
|
|
1448
|
+
createMain,
|
|
1449
|
+
/snsTopicArnByFlowSchema\(\s*_izContext,\s*'validateBeforeCreateAsync_In'\s*\)/
|
|
1450
|
+
);
|
|
1451
|
+
assert.match(createMain, /CreateBeforeHookCallbackHdrSqs/);
|
|
1452
|
+
|
|
1453
|
+
const callbackHandler = await readFile(
|
|
1454
|
+
join(
|
|
1455
|
+
rootPath,
|
|
1456
|
+
'app/src/generatedCode/FlowObjects/Create/source/CreateBeforeHookCallback_HdrSqs.js'
|
|
1457
|
+
),
|
|
1458
|
+
'utf8'
|
|
1459
|
+
);
|
|
1460
|
+
assert.match(callbackHandler, /CreateBeforeHookCallback_Main/);
|
|
1461
|
+
});
|
|
1462
|
+
|
|
1391
1463
|
async function createProject(withCrudObject) {
|
|
1392
1464
|
const rootPath = await mkdtemp(
|
|
1393
1465
|
join(tmpdir(), 'generate-service-code-v2-crud-application-')
|