@izara_project/izara-core-generate-service-code 1.0.66 → 1.0.67

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.
Files changed (27) hide show
  1. package/docs/TriggeredCache Flow.drawio +193 -0
  2. package/docs/test.mmd +47 -0
  3. package/docs/test.png +0 -0
  4. package/package.json +2 -2
  5. package/src/compile/loadSchemas.js +23 -1
  6. package/src/emit/crud/emitCrudApplicationArtifacts.js +9 -5
  7. package/src/emit/crud/templates/CreateEndpoint_Main.ejs +5 -5
  8. package/src/emit/crud/templates/DeleteEndpoint_Main.ejs +5 -5
  9. package/src/emit/crud/templates/FlowEndpointComplete_Main.ejs +25 -4
  10. package/src/emit/crud/templates/FlowHandler_HdrApi.ejs +18 -0
  11. package/src/emit/crud/templates/GetEndpoint_Main.ejs +2 -2
  12. package/src/emit/crud/templates/UpdateEndpoint_Main.ejs +10 -8
  13. package/src/emit/custom/customFlows.js +76 -25
  14. package/src/emit/custom/emitCustomFlowApplicationArtifacts.js +92 -75
  15. package/src/emit/custom/templates/FlowEndpoint_Main.ejs +4 -4
  16. package/src/emit/custom/templates/triggerCache/CheckTriggerCache_Main.ejs +1 -1
  17. package/src/emit/function/functionYamlArtifact.js +26 -12
  18. package/src/emit/rbac/emitRbacApplicationArtifacts.js +21 -7
  19. package/src/emit/relationship/emitRelationshipApplicationArtifacts.js +6 -5
  20. package/src/emit/relationship/templates/ChangeRelationship_Main.ejs +2 -2
  21. package/src/emit/resource/emitResourceArtifacts.js +400 -105
  22. package/src/emit/system/emitSystemWebSocketArtifacts.js +2 -1
  23. package/src/generate.js +2 -2
  24. package/test/crudApplicationArtifacts.test.js +1 -1
  25. package/test/customFlowApplicationArtifacts.test.js +37 -34
  26. package/test/publicApi.test.js +9 -9
  27. package/test/resourceArtifacts.test.js +1 -1
@@ -0,0 +1,193 @@
1
+ <mxfile host="app.diagrams.net">
2
+ <diagram name="Page-1" id="pXYk_RwGkFAkQVFTFBd9">
3
+ <mxGraphModel grid="1" page="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
4
+ <root>
5
+ <mxCell id="0" />
6
+ <mxCell id="1" parent="0" />
7
+ <mxCell id="tqax0Luh1uLb62xYIonj-1" parent="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;strokeColor=light-dark(#000000,#FF66FF);" value="PrepComparisData_Main" vertex="1">
8
+ <mxGeometry height="120" width="120" x="354" y="120" as="geometry" />
9
+ </mxCell>
10
+ <mxCell id="tqax0Luh1uLb62xYIonj-2" edge="1" parent="1" source="tqax0Luh1uLb62xYIonj-1" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" value="">
11
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
12
+ <mxPoint x="370" y="330" as="sourcePoint" />
13
+ <mxPoint x="414" y="340" as="targetPoint" />
14
+ </mxGeometry>
15
+ </mxCell>
16
+ <mxCell id="tqax0Luh1uLb62xYIonj-3" connectable="0" parent="tqax0Luh1uLb62xYIonj-2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=#60a917;fontColor=#ffffff;labelBorderColor=#2D7600;" value="checkTriggeredCacheV2&amp;nbsp;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;ว่ามีงานของ triggerFlow อื่นที่ยังค้างอยูไหม&lt;/div&gt;" vertex="1">
17
+ <mxGeometry relative="1" x="-0.1668" y="2" as="geometry">
18
+ <mxPoint x="-2" y="78" as="offset" />
19
+ </mxGeometry>
20
+ </mxCell>
21
+ <mxCell id="tqax0Luh1uLb62xYIonj-15" connectable="0" parent="tqax0Luh1uLb62xYIonj-2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=#60a917;fontColor=#ffffff;labelBorderColor=#2D7600;" value="checkTriggerFlowCompleteAwaitingStepV2&amp;nbsp;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;ว่ามีงานของ triggerFlow อื่นที่ยังค้างอยูไหม&lt;/div&gt;" vertex="1">
22
+ <mxGeometry relative="1" x="-0.1668" y="2" as="geometry">
23
+ <mxPoint x="4" y="339" as="offset" />
24
+ </mxGeometry>
25
+ </mxCell>
26
+ <mxCell id="tqax0Luh1uLb62xYIonj-23" connectable="0" parent="tqax0Luh1uLb62xYIonj-2" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];labelBackgroundColor=#60a917;fontColor=#ffffff;labelBorderColor=#2D7600;" value="checkTriggerResetedV2&amp;nbsp;&lt;div&gt;&lt;br&gt;&lt;/div&gt;&lt;div&gt;ว่ามีงานของ triggerFlow อื่นที่ยังค้างอยูไหม&lt;/div&gt;" vertex="1">
27
+ <mxGeometry relative="1" x="-0.1668" y="2" as="geometry">
28
+ <mxPoint x="764" y="218" as="offset" />
29
+ </mxGeometry>
30
+ </mxCell>
31
+ <mxCell id="tqax0Luh1uLb62xYIonj-4" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;" value="">
32
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
33
+ <mxPoint x="360" y="380" as="sourcePoint" />
34
+ <mxPoint x="360" y="480" as="targetPoint" />
35
+ </mxGeometry>
36
+ </mxCell>
37
+ <mxCell id="tqax0Luh1uLb62xYIonj-5" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;" value="">
38
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
39
+ <mxPoint x="480" y="380" as="sourcePoint" />
40
+ <mxPoint x="480" y="480" as="targetPoint" />
41
+ </mxGeometry>
42
+ </mxCell>
43
+ <mxCell id="tqax0Luh1uLb62xYIonj-6" parent="1" style="rounded=1;whiteSpace=wrap;html=1;" value="มี" vertex="1">
44
+ <mxGeometry height="30" width="80" x="320" y="480" as="geometry" />
45
+ </mxCell>
46
+ <mxCell id="tqax0Luh1uLb62xYIonj-7" parent="1" style="rounded=1;whiteSpace=wrap;html=1;" value="ไม่มี" vertex="1">
47
+ <mxGeometry height="30" width="80" x="440" y="480" as="geometry" />
48
+ </mxCell>
49
+ <mxCell id="tqax0Luh1uLb62xYIonj-9" edge="1" parent="1" source="tqax0Luh1uLb62xYIonj-6" style="endArrow=classic;html=1;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" value="">
50
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
51
+ <mxPoint x="320" y="495" as="sourcePoint" />
52
+ <mxPoint x="200" y="495" as="targetPoint" />
53
+ </mxGeometry>
54
+ </mxCell>
55
+ <mxCell id="tqax0Luh1uLb62xYIonj-11" parent="1" style="shape=tape;whiteSpace=wrap;html=1;" value="สร้าง request ไปที่&lt;div&gt;triggerFlow&lt;/div&gt;" vertex="1">
56
+ <mxGeometry height="135" width="120" x="80" y="427.5" as="geometry" />
57
+ </mxCell>
58
+ <mxCell id="tqax0Luh1uLb62xYIonj-12" parent="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;strokeColor=light-dark(#000000,#FF66FF);" value="CheckTriggerCache&lt;div&gt;Complete&lt;/div&gt;" vertex="1">
59
+ <mxGeometry height="104" width="104" x="370" y="800" as="geometry" />
60
+ </mxCell>
61
+ <mxCell id="tqax0Luh1uLb62xYIonj-16" edge="1" parent="1" source="tqax0Luh1uLb62xYIonj-12" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;" value="">
62
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
63
+ <mxPoint x="210" y="680" as="sourcePoint" />
64
+ <mxPoint x="420" y="640" as="targetPoint" />
65
+ </mxGeometry>
66
+ </mxCell>
67
+ <mxCell id="tqax0Luh1uLb62xYIonj-17" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" target="tqax0Luh1uLb62xYIonj-6" value="">
68
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
69
+ <mxPoint x="360" y="600" as="sourcePoint" />
70
+ <mxPoint x="330" y="530" as="targetPoint" />
71
+ </mxGeometry>
72
+ </mxCell>
73
+ <mxCell id="tqax0Luh1uLb62xYIonj-18" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" value="">
74
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
75
+ <mxPoint x="479.65999999999997" y="600" as="sourcePoint" />
76
+ <mxPoint x="479.65999999999997" y="510" as="targetPoint" />
77
+ </mxGeometry>
78
+ </mxCell>
79
+ <mxCell id="tqax0Luh1uLb62xYIonj-19" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" value="">
80
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
81
+ <mxPoint x="520" y="494.65647058823527" as="sourcePoint" />
82
+ <mxPoint x="640" y="494.65647058823527" as="targetPoint" />
83
+ </mxGeometry>
84
+ </mxCell>
85
+ <mxCell id="tqax0Luh1uLb62xYIonj-20" parent="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;strokeColor=light-dark(#000000,#FF66FF);" value="ProcessTriggerCache&lt;div&gt;PrepComparisData&lt;/div&gt;" vertex="1">
86
+ <mxGeometry height="104" width="104" x="640" y="443" as="geometry" />
87
+ </mxCell>
88
+ <mxCell id="tqax0Luh1uLb62xYIonj-21" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="tqax0Luh1uLb62xYIonj-22" value="">
89
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
90
+ <mxPoint x="744" y="494.6464705882353" as="sourcePoint" />
91
+ <mxPoint x="864" y="494.6464705882353" as="targetPoint" />
92
+ </mxGeometry>
93
+ </mxCell>
94
+ <mxCell id="tqax0Luh1uLb62xYIonj-22" parent="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;strokeColor=light-dark(#000000,#FF66FF);" value="ProcessTriggerCache&lt;div&gt;PrepComparisData&lt;/div&gt;" vertex="1">
95
+ <mxGeometry height="104" width="104" x="864" y="443" as="geometry" />
96
+ </mxCell>
97
+ <mxCell id="tqax0Luh1uLb62xYIonj-24" edge="1" parent="1" source="tqax0Luh1uLb62xYIonj-22" style="endArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" value="">
98
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
99
+ <mxPoint x="990" y="520" as="sourcePoint" />
100
+ <mxPoint x="1080" y="495" as="targetPoint" />
101
+ </mxGeometry>
102
+ </mxCell>
103
+ <mxCell id="tqax0Luh1uLb62xYIonj-25" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" target="tqax0Luh1uLb62xYIonj-26" value="">
104
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
105
+ <mxPoint x="1180" y="480" as="sourcePoint" />
106
+ <mxPoint x="1150" y="410" as="targetPoint" />
107
+ </mxGeometry>
108
+ </mxCell>
109
+ <mxCell id="tqax0Luh1uLb62xYIonj-26" parent="1" style="rounded=1;whiteSpace=wrap;html=1;" value="มี" vertex="1">
110
+ <mxGeometry height="30" width="80" x="1140" y="360" as="geometry" />
111
+ </mxCell>
112
+ <mxCell id="tqax0Luh1uLb62xYIonj-27" edge="1" parent="1" source="tqax0Luh1uLb62xYIonj-26" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" target="tqax0Luh1uLb62xYIonj-11" value="">
113
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
114
+ <Array as="points">
115
+ <mxPoint x="1180" y="80" />
116
+ <mxPoint x="170" y="80" />
117
+ </Array>
118
+ <mxPoint x="860" y="240" as="sourcePoint" />
119
+ <mxPoint x="910" y="190" as="targetPoint" />
120
+ </mxGeometry>
121
+ </mxCell>
122
+ <mxCell id="tqax0Luh1uLb62xYIonj-28" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;" value="">
123
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
124
+ <mxPoint x="1180" y="520" as="sourcePoint" />
125
+ <mxPoint x="1180" y="600" as="targetPoint" />
126
+ </mxGeometry>
127
+ </mxCell>
128
+ <mxCell id="tqax0Luh1uLb62xYIonj-29" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#60a917;fontColor=#ffffff;strokeColor=#2D7600;" value="&lt;div&gt;&lt;span style=&quot;font-size: 11px; white-space: nowrap; background-color: rgb(74, 137, 12);&quot;&gt;checkTriggerResetedV2&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br&gt;&lt;/div&gt;check&amp;nbsp;Timestamp Match&lt;span style=&quot;background-color: transparent; color: light-dark(rgb(255, 255, 255), rgb(18, 18, 18));&quot;&gt;&amp;nbsp;&lt;/span&gt;" vertex="1">
129
+ <mxGeometry height="60" width="200" x="1080" y="720" as="geometry" />
130
+ </mxCell>
131
+ <mxCell id="tqax0Luh1uLb62xYIonj-30" parent="1" style="rounded=1;whiteSpace=wrap;html=1;" value="ไม่มี" vertex="1">
132
+ <mxGeometry height="30" width="80" x="1140" y="600" as="geometry" />
133
+ </mxCell>
134
+ <mxCell id="tqax0Luh1uLb62xYIonj-31" edge="1" parent="1" source="tqax0Luh1uLb62xYIonj-30" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" value="">
135
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
136
+ <mxPoint x="1179.41" y="640" as="sourcePoint" />
137
+ <mxPoint x="1179.4099999999999" y="720" as="targetPoint" />
138
+ </mxGeometry>
139
+ </mxCell>
140
+ <mxCell id="tqax0Luh1uLb62xYIonj-33" parent="1" style="rounded=1;whiteSpace=wrap;html=1;" value="match" vertex="1">
141
+ <mxGeometry height="30" width="80" x="1360" y="735" as="geometry" />
142
+ </mxCell>
143
+ <mxCell id="tqax0Luh1uLb62xYIonj-34" parent="1" style="rounded=1;whiteSpace=wrap;html=1;" value="not match" vertex="1">
144
+ <mxGeometry height="30" width="80" x="920" y="735" as="geometry" />
145
+ </mxCell>
146
+ <mxCell id="tqax0Luh1uLb62xYIonj-35" edge="1" parent="1" source="tqax0Luh1uLb62xYIonj-29" style="endArrow=classic;html=1;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" target="tqax0Luh1uLb62xYIonj-34" value="">
147
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
148
+ <mxPoint x="1120" y="680" as="sourcePoint" />
149
+ <mxPoint x="1170" y="630" as="targetPoint" />
150
+ </mxGeometry>
151
+ </mxCell>
152
+ <mxCell id="tqax0Luh1uLb62xYIonj-36" edge="1" parent="1" source="tqax0Luh1uLb62xYIonj-29" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" target="tqax0Luh1uLb62xYIonj-33" value="">
153
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
154
+ <mxPoint x="1120" y="680" as="sourcePoint" />
155
+ <mxPoint x="1170" y="630" as="targetPoint" />
156
+ </mxGeometry>
157
+ </mxCell>
158
+ <mxCell id="tqax0Luh1uLb62xYIonj-37" edge="1" parent="1" source="tqax0Luh1uLb62xYIonj-34" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" target="tqax0Luh1uLb62xYIonj-20" value="">
159
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
160
+ <Array as="points">
161
+ <mxPoint x="690" y="750" />
162
+ </Array>
163
+ <mxPoint x="930" y="680" as="sourcePoint" />
164
+ <mxPoint x="980" y="630" as="targetPoint" />
165
+ </mxGeometry>
166
+ </mxCell>
167
+ <mxCell id="tqax0Luh1uLb62xYIonj-38" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;" value="">
168
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
169
+ <mxPoint x="1440" y="750" as="sourcePoint" />
170
+ <mxPoint x="1560" y="750" as="targetPoint" />
171
+ </mxGeometry>
172
+ </mxCell>
173
+ <mxCell id="tqax0Luh1uLb62xYIonj-39" parent="1" style="shape=tape;whiteSpace=wrap;html=1;" value="PrepComparisData_Out" vertex="1">
174
+ <mxGeometry height="100" width="230" x="1560" y="690" as="geometry" />
175
+ </mxCell>
176
+ <mxCell id="tqax0Luh1uLb62xYIonj-40" edge="1" parent="1" source="tqax0Luh1uLb62xYIonj-11" style="endArrow=classic;html=1;rounded=0;exitX=0.25;exitY=1;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="tqax0Luh1uLb62xYIonj-12" value="">
177
+ <mxGeometry height="50" relative="1" width="50" as="geometry">
178
+ <Array as="points">
179
+ <mxPoint x="110" y="852" />
180
+ </Array>
181
+ <mxPoint x="780" y="680" as="sourcePoint" />
182
+ <mxPoint x="830" y="630" as="targetPoint" />
183
+ </mxGeometry>
184
+ </mxCell>
185
+ <mxCell id="tqax0Luh1uLb62xYIonj-41" connectable="0" parent="tqax0Luh1uLb62xYIonj-40" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="Sub to Out topic" vertex="1">
186
+ <mxGeometry relative="1" x="-0.6336" y="-2" as="geometry">
187
+ <mxPoint as="offset" />
188
+ </mxGeometry>
189
+ </mxCell>
190
+ </root>
191
+ </mxGraphModel>
192
+ </diagram>
193
+ </mxfile>
package/docs/test.mmd ADDED
@@ -0,0 +1,47 @@
1
+ flowchart TD
2
+ classDef process fill:#d4edda,stroke:#28a745,stroke-width:2px,color:#000;
3
+ classDef check fill:#fff3cd,stroke:#ffc107,stroke-width:2px,color:#000;
4
+ classDef complete fill:#cce5ff,stroke:#007bff,stroke-width:2px,color:#000;
5
+ classDef subflow fill:#e2e3e5,stroke:#6c757d,stroke-width:2px,color:#000;
6
+ classDef decision fill:#f8d7da,stroke:#dc3545,stroke-width:2px,color:#000;
7
+
8
+ Start((จุดเริ่มต้น)) --> ProcessMain
9
+
10
+ subgraph Process [1. Process Step]
11
+ ProcessMain["PrepComparisData_Main<br/>(Process Step)"]:::process
12
+ CheckReset{"checkTriggerResetedV2<br/>(Timestamp Match)"}:::decision
13
+ CheckCache{"checkTriggeredCacheV2<br/>(เช็คว่ามีงานย่อยต้องทำไหม?)"}:::decision
14
+ CreateReq["สร้าง request ไปที่ triggerFlow<br/>(ยิงงานย่อย)"]:::process
15
+
16
+ ProcessMain --> CheckReset
17
+ CheckReset -- "not match" --> ProcessMain
18
+ CheckReset -- "match" --> CheckCache
19
+ CheckCache -- "มีงาน" --> CreateReq
20
+ end
21
+
22
+ SubFlow["triggerFlow<br/>(งานย่อย)"]:::subflow
23
+
24
+ subgraph Check [2. Check Step]
25
+ SubOut["Sub to Out topic<br/>(รับ Message งานย่อยที่เสร็จ)"]:::check
26
+ CheckComplete["CheckTriggerCacheComplete<br/>(Check Step)"]:::check
27
+ CheckFlow{"checkTriggerFlowComplete<br/>AwaitingStepV2<br/>(ตรวจว่าทุกงานเสร็จหรือยัง?)"}:::decision
28
+
29
+ SubOut --> CheckComplete
30
+ CheckComplete --> CheckFlow
31
+ end
32
+
33
+ subgraph Complete [3. Complete Step]
34
+ OutMain["PrepComparisData_Out<br/>(Complete Step)"]:::complete
35
+ end
36
+
37
+ %% เส้นทางเชื่อมต่อระหว่างกลุ่ม
38
+ CreateReq -- "ส่งงาน" --> SubFlow
39
+ SubFlow -- "ทำงานเสร็จ ส่ง passBack" --> SubOut
40
+
41
+ CheckCache -- "ไม่มีงาน (ข้ามไปทำ Complete)" --> OutMain
42
+
43
+ CheckFlow -- "มีงานค้าง (รอตัวถัดไป)" --> Wait((รอ Message ถัดไป))
44
+ CheckFlow -- "ไม่มีงานค้าง (เสร็จหมด 100%)" --> OutMain
45
+
46
+ %% เส้นสีแดงสำหรับ Loop Not Match
47
+ linkStyle 1 stroke:#dc3545,stroke-width:2px
package/docs/test.png ADDED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@izara_project/izara-core-generate-service-code",
3
- "version": "1.0.66",
3
+ "version": "1.0.67",
4
4
  "description": "Code for locally generating per service files",
5
5
  "homepage": "https://bitbucket.org/izara-core-support-services/izara-core-support-services-generate-service-code#readme",
6
6
  "repository": {
@@ -33,7 +33,7 @@
33
33
  "@izara_project/izara-shared-service-schemas": "^1.0.65"
34
34
  },
35
35
  "devDependencies": {
36
- "@izara_project/izara-core-library-service-schemas": "^1.0.158",
36
+ "@izara_project/izara-core-library-service-schemas": "1.0.158",
37
37
  "@izara_project/izara-shared-service-schemas": "^1.0.66",
38
38
  "jest": "^30.4.2"
39
39
  }
@@ -1,6 +1,7 @@
1
1
  import { readdir, stat } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { pathToFileURL } from 'node:url';
4
+ import { utils } from '@izara_project/izara-core-library-service-schemas';
4
5
 
5
6
  export async function loadLocalSchemaDirectory(project, directoryName) {
6
7
  const directoryPath = join(project.schemaRoot, directoryName);
@@ -22,7 +23,28 @@ export async function loadLocalSchemaDirectory(project, directoryName) {
22
23
  if (!module.default || typeof module.default !== 'object') {
23
24
  throw new TypeError(`Schema module must default-export an object or array: ${filePath}`);
24
25
  }
25
- schemas.push(...(Array.isArray(module.default) ? module.default : [module.default]));
26
+ const loadedSchemas = Array.isArray(module.default) ? module.default : [module.default];
27
+
28
+ if (process.env.NODE_ENV !== 'test') {
29
+ for (const schema of loadedSchemas) {
30
+ let status = true;
31
+ let errors = [];
32
+
33
+ if (directoryName === 'ObjectSchemas') {
34
+ [status, errors] = utils.validateBasicObjectSchema({}, schema);
35
+ } else if (directoryName === 'RelationshipSchemas') {
36
+ [status, errors] = utils.validateRelationshipSchema({}, schema);
37
+ } else if (directoryName === 'FlowSchemas') {
38
+ [status, errors] = utils.validateBasicFlowSchema({}, schema);
39
+ }
40
+
41
+ if (!status) {
42
+ throw new Error(`Schema validation failed for ${entry.name}:\n${errors.join('\n')}`);
43
+ }
44
+ }
45
+ }
46
+
47
+ schemas.push(...loadedSchemas);
26
48
  }
27
49
  return schemas;
28
50
  }
@@ -83,12 +83,14 @@ async function emitAction(action, objects, flows, serviceTag) {
83
83
  return {
84
84
  artifacts,
85
85
  functions: [
86
- { type: 'inv', functionName: 'GetHdrInv', handlerPath: `${handlerRoot}/Get_HdrInv.main`, roleName: 'FlowObjectsRole' },
86
+ { type: 'inv', functionName: 'GetHdrInv', handlerPath: `${handlerRoot}/Get_HdrInv.main`, roleName: 'FlowObjectsRole', flowTag: action, flowStepName: '' },
87
87
  {
88
88
  type: 'api',
89
89
  functionName: 'GetHdrApi',
90
90
  handlerPath: `${handlerRoot}/Get_HdrApi.main`,
91
91
  roleName: 'FlowObjectsRole',
92
+ flowTag: action,
93
+ flowStepName: '',
92
94
  routes: objects.filter(isCrudObject).map(object => ({
93
95
  path: `/${serviceTag ?? '${self:custom.iz_serviceName}'}/${object.objectType}/get`,
94
96
  upperName: upperFirst(object.objectType)
@@ -99,6 +101,8 @@ async function emitAction(action, objects, flows, serviceTag) {
99
101
  functionName: 'GetRangeHdrApi',
100
102
  handlerPath: `${handlerRoot}/GetRange_HdrApi.main`,
101
103
  roleName: 'FlowObjectsRole',
104
+ flowTag: 'GetRange',
105
+ flowStepName: '',
102
106
  routes: objects.filter(isCrudObject)
103
107
  .filter(object => object.identifiers && object.identifiers.some(i => i.type === 'sortKey'))
104
108
  .map(object => ({
@@ -116,22 +120,22 @@ async function emitAction(action, objects, flows, serviceTag) {
116
120
  { path: `${source}/${action}_HdrWbs.js`, content: await render('FlowEndpoint_HdrWbs.ejs', { ...shared, mainFileName: `${action}_WbsMain`, functionName: action, route: action }) }
117
121
  );
118
122
  const functions = [
119
- { type: 'wbs', functionName: `${action}HdrWbs`, handlerPath: `${handlerRoot}/${action}_HdrWbs.main`, roleName: 'FlowObjectsRole', routeName: action },
120
- { type: 'sqs', functionName: `${action}HdrSqs`, handlerPath: `${handlerRoot}/${action}_HdrSqs.main`, roleName: 'FlowObjectsRole', queueName: `${action}HdrSqs` }
123
+ { type: 'wbs', functionName: `${action}HdrWbs`, handlerPath: `${handlerRoot}/${action}_HdrWbs.main`, roleName: 'FlowObjectsRole', routeName: action, flowTag: action, flowStepName: '' },
124
+ { type: 'sqs', functionName: `${action}HdrSqs`, handlerPath: `${handlerRoot}/${action}_HdrSqs.main`, roleName: 'FlowObjectsRole', queueName: `${action}HdrSqs`, flowTag: action, flowStepName: '' }
121
125
  ];
122
126
  const complete = `${action}Complete`;
123
127
  artifacts.push(
124
128
  { path: `${source}/${complete}_Main.js`, content: await render('FlowEndpointComplete_Main.ejs', { action }) },
125
129
  { path: `${source}/${complete}_HdrSqs.js`, content: await render('FlowHandler_HdrSqs.ejs', { ...shared, mainFileName: `${complete}_Main`, functionName: complete, queueName: `${action}CompleteHdrSqs` }) }
126
130
  );
127
- functions.push({ type: 'sqs', functionName: `${action}CompleteHdrSqs`, handlerPath: `${handlerRoot}/${complete}_HdrSqs.main`, roleName: 'FlowObjectsRole', queueName: `${action}CompleteHdrSqs` });
131
+ functions.push({ type: 'sqs', functionName: `${action}CompleteHdrSqs`, handlerPath: `${handlerRoot}/${complete}_HdrSqs.main`, roleName: 'FlowObjectsRole', queueName: `${action}CompleteHdrSqs`, flowTag: action, flowStepName: 'Complete' });
128
132
  if (generateCode.some(config => config.codeHookTag === 'beforeLogical')) {
129
133
  const beforeMain = `${action}BeforeLogical_Main`;
130
134
  artifacts.push(
131
135
  { path: `${source}/${beforeMain}.js`, content: await render('FlowEndpointBeforeLogical_Main.ejs', shared) },
132
136
  { path: `${source}/${action}BeforeLogical_HdrSqs.js`, content: await render('FlowHandler_HdrSqs.ejs', { ...shared, mainFileName: beforeMain, functionName: `${action}BeforeLogicalMain`, queueName: `${action}BeforeLogicalHdrSqs` }) }
133
137
  );
134
- functions.push({ type: 'sqs', functionName: `${action}BeforeLogicalHdrSqs`, handlerPath: `${handlerRoot}/${action}BeforeLogical_HdrSqs.main`, roleName: 'FlowObjectsRole', queueName: `${action}BeforeLogicalHdrSqs` });
138
+ functions.push({ type: 'sqs', functionName: `${action}BeforeLogicalHdrSqs`, handlerPath: `${handlerRoot}/${action}BeforeLogical_HdrSqs.main`, roleName: 'FlowObjectsRole', queueName: `${action}BeforeLogicalHdrSqs`, flowTag: action, flowStepName: 'BeforeLogical' });
135
139
  }
136
140
  return { artifacts, functions };
137
141
  }
@@ -63,7 +63,7 @@ export async function <%- flowTag %>MainLogical(
63
63
  beforeLogicalResults = {}
64
64
  ) {
65
65
  try {
66
- _izContext.logger.debug('createMainLogical:', {
66
+ _izContext.logger.debug('[<%- flowTag %>MainLogical] started', {
67
67
  requestParams,
68
68
  callingFlowConfig,
69
69
  beforeLogicalResults
@@ -406,7 +406,7 @@ export default async function <%- flowTag %>(
406
406
  //(</additionalParams>)
407
407
  ) {
408
408
  try {
409
- _izContext.logger.debug('createMain:', { requestParams, callingFlowConfig });
409
+ _izContext.logger.debug('[<%- flowTag %>] createMain:', { requestParams, callingFlowConfig });
410
410
 
411
411
  const errorsFound = [];
412
412
  const objType = createObjType(requestParams.objectType);
@@ -606,13 +606,13 @@ export default async function <%- flowTag %>(
606
606
  }
607
607
  <%_ } _%>
608
608
 
609
- await asyncFlowSharedLib.initAwaitingStepsWithAttrs(
609
+ await asyncFlowSharedLib.createAwaitingMultipleSteps(
610
610
  _izContext,
611
- awaitingMultipleStepIds,
612
611
  asyncFlowSharedLib.createPendingStepId(
613
612
  _izContext.uniqueRequestId,
614
613
  'beforeLogical_<%= objectType %>'
615
- )
614
+ ),
615
+ awaitingMultipleStepIds
616
616
  );
617
617
 
618
618
  //(<beforePublish_<%= objectType %>>)
@@ -53,7 +53,7 @@ export async function <%- flowTag %>MainLogical(
53
53
  beforeLogicalResults = {}
54
54
  ) {
55
55
  try {
56
- _izContext.logger.debug('deleteMainLogical:', { requestParams, callingFlowConfig, beforeLogicalResults });
56
+ _izContext.logger.debug('[<%- flowTag %>MainLogical] started', { requestParams, callingFlowConfig, beforeLogicalResults });
57
57
 
58
58
  //(<beforeDeleteMainLogical>)
59
59
  //(</beforeDeleteMainLogical>)
@@ -157,7 +157,7 @@ export default async function <%- flowTag %>(
157
157
  //(</additionalParams>)
158
158
  ) {
159
159
  try {
160
- _izContext.logger.debug('deleteMain:', { requestParams, callingFlowConfig });
160
+ _izContext.logger.debug('[<%- flowTag %>]', { requestParams, callingFlowConfig });
161
161
 
162
162
  const errorsFound = [];
163
163
  const objType = createObjType(requestParams.objectType);
@@ -281,13 +281,13 @@ export default async function <%- flowTag %>(
281
281
  }
282
282
  <%_ } _%>
283
283
 
284
- await asyncFlowSharedLib.initAwaitingStepsWithAttrs(
284
+ await asyncFlowSharedLib.createAwaitingMultipleSteps(
285
285
  _izContext,
286
- awaitingMultipleStepIds,
287
286
  asyncFlowSharedLib.createPendingStepId(
288
287
  hash(identifiers),
289
288
  'beforeLogical_<%= objectType %>'
290
- )
289
+ ),
290
+ awaitingMultipleStepIds
291
291
  );
292
292
 
293
293
  //(<beforePublish_<%= objectType %>>)
@@ -6,8 +6,14 @@ import { sns } from '@izara_project/izara-core-library-external-request';
6
6
  import { consts } from '@izara_project/izara-core-library-service-schemas';
7
7
  import { NoRetryError } from '@izara_project/izara-core-library-core';
8
8
 
9
- const { TOPIC_NAME_GENERATE_CODE } = consts;
9
+ const { TOPIC_NAME_GENERATE_CODE, PREFIX: _constPrefix } = consts;
10
+ <%_ if (action === 'Create') { _%>
11
+ const PREFIX = { ASYNC: _constPrefix.CREATE_OBJECT_ASYNC };
12
+ <%_ } else if (action === 'Update') { _%>
13
+ const PREFIX = { ASYNC: _constPrefix.updateNode };
14
+ <%_ } else { _%>
10
15
  const PREFIX = { ASYNC: '<%- action %>AsyncEndpoint' };
16
+ <%_ } _%>
11
17
 
12
18
  function empty(value) {
13
19
  return value == null || (typeof value === 'object' && Object.keys(value).length === 0);
@@ -24,6 +30,7 @@ function validateInput(returnValue, status, graphServiceTag, errorsFound) {
24
30
 
25
31
  export default async function <%- action %>Complete(_izContext, requestParams, passBackProperties) {
26
32
  try {
33
+ _izContext.logger.debug('[<%- action %>Complete] started', { requestParams });
27
34
  const { returnValue, status, errorsFound = [], graphServiceTag, parentFlowId } = requestParams;
28
35
  if (empty(returnValue?.requestParams)) throw new NoRetryError('message not an object');
29
36
  validateInput(returnValue, status, graphServiceTag, errorsFound);
@@ -31,12 +38,24 @@ export default async function <%- action %>Complete(_izContext, requestParams, p
31
38
 
32
39
  const awaitingStepId = await asyncFlowSharedLib.createAwaitingStepId(parentFlowId, PREFIX.ASYNC);
33
40
  const pending = await asyncFlowSharedLib.findPendingStepAwaitingMultipleSteps(_izContext, awaitingStepId);
41
+ _izContext.logger.debug('[<%- action %>Complete] awaiting step', {
42
+ awaitingStepId,
43
+ pending
44
+ });
45
+ if (!pending) {
46
+ _izContext.logger.warn(`No pending step found for awaitingStepId: ${awaitingStepId}`);
47
+ return { returnValue, status, errorsFound };
48
+ }
34
49
  const result = await asyncFlowSharedLib.checkAllAwaitingStepsFinishedWithReturnParams(
35
50
  _izContext, pending.pendingStepId, awaitingStepId, errorsFound
36
51
  );
52
+ _izContext.logger.debug('[<%- action %>Complete] all awaiting steps result', { isComplete: result.isComplete, awaitingStepId, pendingStepId: pending.pendingStepId });
37
53
 
38
54
  if (result.isComplete) {
39
- const node = returnValue.queryResult.return<%- action %>Node ?? {};
55
+ const nodeResultKey = `return<%- action %>dNode`;
56
+ const fallbackNodeResultKey = `return<%- action %>Node`;
57
+ const nodeResult = returnValue.queryResult[nodeResultKey] ?? returnValue.queryResult[fallbackNodeResultKey] ?? {};
58
+ const node = nodeResult[`<%- action.toLowerCase() %>NodeResult`] ?? nodeResult;
40
59
  const existsNode = node.existsNode && Object.keys(node.existsNode).length
41
60
  ? { objType: returnValue.requestParams.objType, objInstanceFull: node.existsNode.objInstanceFull }
42
61
  : null;
@@ -58,10 +77,12 @@ export default async function <%- action %>Complete(_izContext, requestParams, p
58
77
  errorsFound
59
78
  });
60
79
  const messageAttributes = callingFlowSharedLib.addParentPassBackCallingFlowToSnsResponseMessageAttributes(passBackProperties, {});
80
+ const topicArn = await snsSharedLib.snsTopicArnByFlowSchema(_izContext, TOPIC_NAME_GENERATE_CODE.out<%- action %>NodeComplete);
81
+ _izContext.logger.debug('[<%- action %>Complete] publishing to SNS', { TopicArn: topicArn, message });
61
82
  await sns.publishAsync(_izContext, {
62
83
  Message: JSON.stringify(message),
63
84
  MessageAttributes: sns.createStringMessageAttributes(_izContext, messageAttributes),
64
- TopicArn: await snsSharedLib.snsTopicArnByFlowSchema(_izContext, TOPIC_NAME_GENERATE_CODE.out<%- action %>NodeComplete)
85
+ TopicArn: topicArn
65
86
  });
66
87
  //(<afterSendMessage>)
67
88
  //(</afterSendMessage>)
@@ -69,7 +90,7 @@ export default async function <%- action %>Complete(_izContext, requestParams, p
69
90
  await asyncFlowSharedLib.removeAwaitingMultipleStep(_izContext, awaitingStepId, pending.pendingStepId, errorsFound);
70
91
  return { returnValue, status, errorsFound };
71
92
  } catch (error) {
72
- _izContext.logger.error('<%- action %>Complete error:', error);
93
+ _izContext.logger.error('[<%- action %>Complete] error:', error);
73
94
  throw error;
74
95
  }
75
96
  }
@@ -27,6 +27,24 @@ export const main = middleware.wrap(async (event, context) => {
27
27
  event._izContext?.logger?.debug(`[${context.awsRequestId}] Received API request in <%= flowStepName %>`);
28
28
 
29
29
  try {
30
+ let objectType;
31
+ if (event.routeKey) {
32
+ const path = event.routeKey.split(' ')[1];
33
+ if (path) {
34
+ const segments = path.split('/');
35
+ const serviceName = process.env.iz_serviceName;
36
+ const serviceIndex = segments.indexOf(serviceName);
37
+ if (serviceIndex !== -1 && segments.length > serviceIndex + 1) {
38
+ objectType = segments[serviceIndex + 1];
39
+ }
40
+ }
41
+ }
42
+
43
+ if (objectType) {
44
+ event.body = event.body || {};
45
+ event.body.objectType = objectType;
46
+ }
47
+
30
48
  const passOnProperties = [
31
49
  event.body,
32
50
  //(<additionalParams>)
@@ -25,7 +25,7 @@ import {
25
25
  utils,
26
26
  dataDetailsLib
27
27
  } from '@izara_project/izara-core-library-service-schemas';
28
- const { getObjSchemaS3WithHierarchy } = getObjectSchema;
28
+ const { getObjectSchemaCombineFieldNamesWithCache } = getObjectSchema;
29
29
  const { getGraphServiceTagWithCache } = serviceConfig;
30
30
  const { objInstanceFromObjInstanceBase, dynamoDbIdentifiersByStorageResource } =
31
31
  identifiersObject;
@@ -81,7 +81,7 @@ export default async function <%- flowTag %>(
81
81
  const objType = createObjType(requestParams.objectType);
82
82
 
83
83
  // ── Load schema ───────────────────────────────────────────────────────────
84
- const objectSchema = await getObjSchemaS3WithHierarchy(_izContext, objType);
84
+ const objectSchema = await getObjectSchemaCombineFieldNamesWithCache(_izContext, objType);
85
85
  _izContext.logger.debug('objectSchema:', objectSchema);
86
86
 
87
87
  // ── Build getDataDetails ──────────────────────────────────────────────────
@@ -57,7 +57,7 @@ export async function <%- flowTag %>MainLogical(
57
57
  beforeLogicalResults = {}
58
58
  ) {
59
59
  try {
60
- _izContext.logger.debug('updateMainLogical:', { requestParams, callingFlowConfig, beforeLogicalResults });
60
+ _izContext.logger.debug('[<%- flowTag %>MainLogical] started', { requestParams, callingFlowConfig, beforeLogicalResults });
61
61
 
62
62
  //(<beforeUpdateMainLogical>)
63
63
  //(</beforeUpdateMainLogical>)
@@ -192,7 +192,7 @@ export async function <%- flowTag %>MainLogical(
192
192
  //(</additionalAttributes>)
193
193
 
194
194
 
195
- records = awaitingStepIds.lenght === 0 ? listOfRecords : [];
195
+ const records = awaitingStepIds.length === 0 ? listOfRecords : [];
196
196
  awaitingStepIds.push({
197
197
  awaitingStepId: asyncFlowSharedLib.createAwaitingStepId(
198
198
  parentFlowId,
@@ -202,10 +202,12 @@ export async function <%- flowTag %>MainLogical(
202
202
  });
203
203
 
204
204
  if (awaitingStepIds.length) {
205
- const awaitingMultipleStep = await asyncFlowSharedLib.createAwaitingMultipleStepsWithAdditionalAttributes(
205
+ const awaitingMultipleStep = await asyncFlowSharedLib.createAwaitingMultipleSteps(
206
206
  _izContext,
207
- awaitingStepIds,
208
- asyncFlowSharedLib.createPendingStepId(_izContext.uniqueRequestId)
207
+ asyncFlowSharedLib.createPendingStepId(
208
+ _izContext.uniqueRequestId
209
+ ),
210
+ awaitingStepIds
209
211
  );
210
212
  _izContext.logger.debug('awaitingMultipleStep', awaitingMultipleStep);
211
213
  }
@@ -315,7 +317,7 @@ export async function <%- flowTag %>MainLogical(
315
317
  };
316
318
 
317
319
  } catch (err) {
318
- _izContext.logger.error('error updateMainLogical:', err);
320
+ _izContext.logger.error('[<%- flowTag %>MainLogical] error:', err);
319
321
  throw err;
320
322
  }
321
323
  }
@@ -335,7 +337,7 @@ export default async function <%- flowTag %>(
335
337
  //(</additionalParams>)
336
338
  ) {
337
339
  try {
338
- _izContext.logger.debug('updateMain:', { requestParams, callingFlowConfig });
340
+ _izContext.logger.debug('[<%- flowTag %>] started', { requestParams, callingFlowConfig });
339
341
 
340
342
  // ── Build identifiers (used for hash in beforeLogical) ──────────────────
341
343
  const identifiers = requestParams.objInstanceFull.identifiers;
@@ -505,7 +507,7 @@ export default async function <%- flowTag %>(
505
507
  );
506
508
 
507
509
  } catch (err) {
508
- _izContext.logger.error('error updateMain:', err);
510
+ _izContext.logger.error('[<%- flowTag %>] error:', err);
509
511
  throw err;
510
512
  }
511
513
  }