@simitgroup/simpleapp-generator 1.6.7-i-alpha → 1.6.7-j-alpha

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/ReleaseNote.md CHANGED
@@ -1,4 +1,10 @@
1
- [1.6.7h-alpha]
1
+ [1.6.7j-alpha]
2
+
3
+ 1. Add Custom Field Constant File For Mini Api
4
+ 2. Update Scope Constant File
5
+ 3. Implement read/write split. for read data mongoose preferable go secondary server, which hope can reduce primary server load
6
+
7
+ [1.6.7i-alpha]
2
8
 
3
9
  1. Restructure Mini App
4
10
  2. Support Mini Api Access
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simitgroup/simpleapp-generator",
3
- "version": "1.6.7i-alpha",
3
+ "version": "1.6.7j-alpha",
4
4
  "description": "frontend nuxtjs and backend nests code generator using jsonschema",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -4,8 +4,27 @@
4
4
  const apiName = it.typename.toUpperCase() + 'Api';
5
5
  const titleName = titleCase(pascalName);
6
6
  const uglyName = upperFirstCase(it.name ?? '');
7
+ const schemaName = `SimtrainSchema.${uglyName}`;
8
+ const schemaAutoCompleteName = `SimtrainSchema.${uglyName}AutoComplete`;
7
9
 
8
10
  const serviceVariable = it.resourceName + 'Service';
11
+
12
+ const getTypeName = (typeName) => {
13
+ const systemTypes = ['boolean', 'string', 'number', 'object', 'integer'];
14
+ let tmpTypeName = typeName.replace('[','').replace(']','');
15
+
16
+ if(systemTypes.includes(tmpTypeName.toLowerCase())){
17
+ tmpTypeName = upperFirstCase(tmpTypeName.toLowerCase());
18
+ } else {
19
+ tmpTypeName = `SimtrainSchema.${tmpTypeName}`;
20
+ }
21
+
22
+ if(typeName.includes('[')){
23
+ return `[${tmpTypeName}]`;
24
+ }
25
+
26
+ return tmpTypeName;
27
+ }
9
28
  %>
10
29
 
11
30
  import {
@@ -20,11 +39,12 @@ import {
20
39
  Headers,
21
40
  Query,
22
41
  } from '@nestjs/common';
23
- import { ApiTags, ApiBody, ApiResponse, ApiOperation, ApiQuery } from '@nestjs/swagger';
42
+ import { ApiTags, ApiBody, ApiResponse, ApiOperation, ApiQuery, PartialType } from '@nestjs/swagger';
24
43
  import { ApiHeader } from 'src/types/api';
25
44
  import { <%= pascalName %>Service } from './<%= kebabName %>.service';
26
45
  import { ResourceApiListDto } from '../../dto/resource-api.schema';
27
- import { <%= uglyName %> } from 'src/openapi/backend-api';
46
+ import * as SimtrainSchema from '../../simtrain-schema';
47
+ import { Filter } from 'mongodb';
28
48
 
29
49
  @ApiTags('<%= titleName %>')
30
50
  @Controller('resources/<%= kebabName %>')
@@ -36,111 +56,154 @@ export class <%= pascalName %>Controller {
36
56
 
37
57
  <% if(action === 'list') { %>
38
58
  @Post('list')
39
- @ApiBody({
40
- type: ResourceApiListDto<<%= uglyName %>>,
41
- required: false,
42
- })
43
- findAll(@Headers() headers:ApiHeader, @Body() dto?: ResourceApiListDto<<%= uglyName %>>) {
44
- return this.<%= serviceVariable %>.findAll(headers, dto);
59
+ @ApiOperation({ operationId: 'list' })
60
+ @ApiBody({ type: ResourceApiListDto<<%= schemaName %>>, required: false })
61
+ @ApiResponse({ status: 200, description: 'Success', type: [<%= schemaName %>] })
62
+ @ApiResponse({ status: 400, description: 'Bad Request' })
63
+ @ApiResponse({ status: 500, description: 'Internal Error' })
64
+ async findAll(@Headers() headers:ApiHeader, @Body() dto?: ResourceApiListDto<<%= schemaName %>>) {
65
+ return await this.<%= serviceVariable %>.findAll(headers, dto);
45
66
  }
46
67
  <% } else if(action === 'detail') { %>
47
68
  @Get(':id')
48
- findOne(@Headers() headers: ApiHeader, @Param('id') id: string) {
49
- return this.<%= serviceVariable %>.findOne(headers, id);
69
+ @ApiOperation({ operationId: 'detail' })
70
+ @ApiResponse({ status: 200, description: 'Success', type: <%= schemaName %> })
71
+ @ApiResponse({ status: 404, description: 'Not Found' })
72
+ @ApiResponse({ status: 500, description: 'Internal Error' })
73
+ async findOne(@Headers() headers: ApiHeader, @Param('id') id: string) {
74
+ return await this.<%= serviceVariable %>.findOne(headers, id);
50
75
  }
51
76
  <% } else if(action === 'create') { %>
52
77
  @Post()
53
- @ApiBody({})
54
- create(
78
+ @ApiOperation({ operationId: 'create' })
79
+ @ApiBody({ type: <%= schemaName %>, required: true })
80
+ @ApiResponse({ status: 200, description: 'Success', type: <%= schemaName %> })
81
+ @ApiResponse({ status: 400, description: 'Bad Request' })
82
+ @ApiResponse({ status: 500, description: 'Internal Error' })
83
+ async create(
55
84
  @Headers() headers: ApiHeader,
56
85
  @Body() resourceDto: any,
57
86
  ) {
58
- return this.<%= serviceVariable %>.create(headers, resourceDto);
87
+ return await this.<%= serviceVariable %>.create(headers, resourceDto);
59
88
  }
60
89
  <% } else if(action === 'update') { %>
61
90
  @Put(':id')
62
- @ApiBody({})
63
- update(
91
+ @ApiOperation({ operationId: 'update' })
92
+ @ApiBody({ type: <%= schemaName %>, required: true })
93
+ @ApiResponse({ status: 200, description: 'Success', type: <%= schemaName %> })
94
+ @ApiResponse({ status: 400, description: 'Bad Request' })
95
+ @ApiResponse({ status: 404, description: 'Not Found' })
96
+ @ApiResponse({ status: 500, description: 'Internal Error' })
97
+ async update(
64
98
  @Headers() headers: ApiHeader,
65
99
  @Param('id') id: string,
66
100
  @Body() resourceDto: any,
67
101
  ) {
68
- return this.<%= serviceVariable %>.update(headers, id, resourceDto);
102
+ return await this.<%= serviceVariable %>.update(headers, id, resourceDto);
69
103
  }
70
104
  <% } else if(action === 'patch') { %>
71
105
  @Patch(':id')
72
- @ApiBody({})
73
- patch(
106
+ @ApiOperation({ operationId: 'patch' })
107
+ @ApiBody({ type: PartialType(<%= schemaName %>), required: true })
108
+ @ApiResponse({ status: 200, description: 'Success', type: <%= schemaName %> })
109
+ @ApiResponse({ status: 400, description: 'Bad Request' })
110
+ @ApiResponse({ status: 404, description: 'Not Found' })
111
+ @ApiResponse({ status: 500, description: 'Internal Error' })
112
+ async patch(
74
113
  @Headers() headers: ApiHeader,
75
114
  @Param('id') id: string,
76
115
  @Body() resourceDto: any,
77
116
  ) {
78
- return this.<%= serviceVariable %>.patch(headers, id, resourceDto);
117
+ return await this.<%= serviceVariable %>.patch(headers, id, resourceDto);
79
118
  }
80
119
  <% } else if(action === 'delete') { %>
81
120
  @Delete(':id')
82
- delete(
121
+ @ApiOperation({ operationId: 'delete' })
122
+ @ApiResponse({ status: 200, description: 'Success', type: <%= schemaName %> })
123
+ @ApiResponse({ status: 400, description: 'Bad Request' })
124
+ @ApiResponse({ status: 404, description: 'Not Found' })
125
+ @ApiResponse({ status: 500, description: 'Internal Error' })
126
+ async delete(
83
127
  @Headers() headers: ApiHeader,
84
128
  @Param('id') id: string,
85
129
  ) {
86
- return this.<%= serviceVariable %>.delete(headers, id);
130
+ return await this.<%= serviceVariable %>.delete(headers, id);
87
131
  }
88
132
  <% } else if(action === 'autoComplete') { %>
89
- @Post('autocomplete')
133
+ @Post('autoComplete')
134
+ @ApiOperation({ operationId: 'autoComplete' })
90
135
  @ApiQuery({ name: 'query', type: String })
91
136
  @ApiBody({ description: 'Mongo DB Filter', type: () => Object })
92
- findAutocomplete(
137
+ @ApiResponse({ status: 200, description: 'Success', type: <%= schemaAutoCompleteName %> })
138
+ @ApiResponse({ status: 400, description: 'Bad Request' })
139
+ @ApiResponse({ status: 404, description: 'Not Found' })
140
+ @ApiResponse({ status: 500, description: 'Internal Error' })
141
+ async findAutocomplete(
93
142
  @Headers() headers: ApiHeader,
94
143
  @Query('query') query: string,
95
- @Body() filter: any,
144
+ @Body() filter: Filter<<%= schemaName %>>,
96
145
  ) {
97
- return this.<%= serviceVariable %>.autocomplete(headers, query, filter);
146
+ return await this.<%= serviceVariable %>.autocomplete(headers, query, filter);
98
147
  }
99
148
  <% } else if(action === 'current') { %>
100
149
  <% } else { %>
101
- <% const apiSetting = it.apiSettings.find(item => item.action === action); %>
102
- <% if (apiSetting) { %>
103
- <% const hasBody = ['post', 'put', 'patch'].includes(apiSetting.method); %>
150
+ <% const api = it.apiSettings.find(item => item.action === action); %>
151
+ <% if (api) { %>
152
+ <% const hasBody = ['post', 'put', 'patch'].includes(api.method); %>
104
153
 
105
- <%
106
- const paramMatches = apiSetting.entryPoint.match(/:([\w]+)/g) || [];
107
- const paramNames = paramMatches.map(p => p.replace(':', ''));
154
+ <%
155
+ const paramsWithType = [];
156
+ const paramsWithoutType = [];
108
157
 
109
- const args = [];
110
- const output = [];
111
- const queryParams = [];
158
+ if(api.entryPoint && api.entryPoint.includes(':')) {
159
+ let subpath = api.entryPoint.split('/');
160
+ for(let a = 0; a < subpath.length; a++) {
161
+ const partstr = subpath[a];
162
+ if(partstr.includes(':')) {
163
+ const paraname = partstr.replace(':','');
164
+ paramsWithType.push(`${paraname}: string`);
165
+ paramsWithoutType.push(paraname);
166
+ }
167
+ }
168
+ }
112
169
 
113
- for (let i = 0; i < paramNames.length; i++) {
114
- const name = paramNames[i];
115
- args.push(name);
116
- output.push(name);
170
+ if(api.queryPara && api.queryPara.length > 0) {
171
+ for(let q=0; q < api.queryPara.length; q++) {
172
+ const qp = api['queryPara'][q];
173
+ paramsWithType.push(`${qp}: string`);
174
+ paramsWithoutType.push(qp);
175
+ }
117
176
  }
118
177
 
119
- if (hasBody) {
120
- output.push('data');
178
+ if(hasBody) {
179
+ paramsWithType.push(`data: ${getTypeName(api.schema)}`);
180
+ paramsWithoutType.push('data');
121
181
  }
122
182
  %>
123
183
 
124
- @<%= upperFirstCase(apiSetting.method) %>('<%= apiSetting.entryPoint %>')
125
- <% if (hasBody) { %>
126
- @ApiBody({
127
- description: 'Request Body',
128
- })
184
+ @<%= upperFirstCase(api.method) %>('<%= api.entryPoint %>')
185
+ @ApiOperation({ operationId: '<%= action %>', description: '<%= api.description %>' })
186
+ <% if(api.queryPara && api.queryPara.length > 0) { %>
187
+ <% for(let q = 0; q < api.queryPara.length; q++) { %>
188
+ @ApiQuery({name: "<%=api['queryPara'][q]%>", required: false, type: String})
189
+ <% } %>
129
190
  <% } %>
130
-
131
- <%= action %>(
191
+ <% if(hasBody) { %>
192
+ @ApiBody({ type: <%= getTypeName(api.schema) %> })
193
+ <%}%>
194
+ @ApiResponse({ status: 200, description: 'Success', type: <%= getTypeName(api.responseType) %> })
195
+ @ApiResponse({ status: 400, description: 'Bad Request' })
196
+ @ApiResponse({ status: 500, description: 'Internal Error' })
197
+ async <%= action %>(
132
198
  @Headers() headers: ApiHeader,
133
- <% args.forEach(arg => { %>
134
- @Param('<%= arg %>') <%= arg %>: string,
135
- <% }) %>
136
- <% if (hasBody) { %>
137
- @Body() data: any,
138
- <% } %>
139
- ) {
140
- return this.<%= serviceVariable %>.<%= action %>(headers, <%= output.join(', ') %>);
199
+ <%= paramsWithType.join(',') %>
200
+ ){
201
+ return await this.<%= serviceVariable %>.<%= action %>(
202
+ headers,
203
+ <%= paramsWithoutType.join(', ') %>
204
+ );
141
205
  }
142
206
  <% } %>
143
207
  <% } %>
144
-
145
208
  <% }); %>
146
209
  }
@@ -2,6 +2,25 @@
2
2
  const pascalName = upperFirstCase(it.resourceName);
3
3
  const apiName = it.typename.toUpperCase() + 'Api';
4
4
  const uglyName = upperFirstCase(it.name ?? '');
5
+ const schemaName = `SimtrainSchema.${uglyName}`;
6
+ const schemaAutoCompleteName = `SimtrainSchema.${uglyName}AutoComplete`;
7
+
8
+ const getTypeName = (typeName) => {
9
+ const systemTypes = ['boolean', 'string', 'number', 'object', 'integer'];
10
+ let tmpTypeName = typeName.replace('[','').replace(']','');
11
+
12
+ if(systemTypes.includes(tmpTypeName.toLowerCase())){
13
+ tmpTypeName = upperFirstCase(tmpTypeName.toLowerCase());
14
+ } else {
15
+ tmpTypeName = `SimtrainSchema.${tmpTypeName}`;
16
+ }
17
+
18
+ if(typeName.includes('[')){
19
+ return `[${tmpTypeName}]`;
20
+ }
21
+
22
+ return tmpTypeName;
23
+ }
5
24
  %>
6
25
 
7
26
  import { BadRequestException, Injectable } from '@nestjs/common';
@@ -10,7 +29,7 @@ import { <%= apiName %> } from 'src/openapi/backend-api';
10
29
  import { ApiHeader } from 'src/types/api';
11
30
  import { getOpenApiConfig } from 'src/utils/api';
12
31
  import { ResourceApiListDto } from '../../dto/resource-api.schema';
13
- import { <%= uglyName %> } from 'src/openapi/backend-api';
32
+ import * as SimtrainSchema from '../../simtrain-schema';
14
33
 
15
34
  @Injectable()
16
35
  export class <%= pascalName %>Service {
@@ -30,7 +49,7 @@ export class <%= pascalName %>Service {
30
49
  <% if (value !== true && typeof value !== 'object') { return; } %>
31
50
 
32
51
  <% if(action === 'list') { %>
33
- async findAll(headers: ApiHeader, dto?: ResourceApiListDto<<%= uglyName %>>) {
52
+ async findAll(headers: ApiHeader, dto?: ResourceApiListDto<<%= schemaName %>>) {
34
53
  const api = this.getApi(headers);
35
54
  const resp = await api.runSearch({
36
55
  fields: dto?.fields,
@@ -77,38 +96,48 @@ export class <%= pascalName %>Service {
77
96
  }
78
97
  <% } else if(action === 'current') { %>
79
98
  <% } else { %>
80
- <% const apiSetting = it.apiSettings.find(item => item.action === action); %>
81
- <% if (apiSetting) { %>
82
- <% const hasBody = ['post', 'put', 'patch'].includes(apiSetting.method); %>
99
+ <% const api = it.apiSettings.find(item => item.action === action); %>
100
+ <% if (api) { %>
101
+ <% const hasBody = ['post', 'put', 'patch'].includes(api.method); %>
83
102
 
84
- <%
85
- const paramMatches = apiSetting.entryPoint.match(/:([\w]+)/g) || [];
86
- const paramNames = paramMatches.map(p => p.replace(':', ''));
103
+ <%
104
+ const paramsWithType = [];
105
+ const paramsWithoutType = [];
87
106
 
88
- const args = paramNames.map(name => {
89
- return `${name}: string`;
90
- });
91
-
92
- const output = [];
93
- const queryParams = [];
94
-
95
- for (let i = 0; i < paramNames.length; i++) {
96
- const name = paramNames[i];
107
+ if(api.entryPoint && api.entryPoint.includes(':')) {
108
+ let subpath = api.entryPoint.split('/');
109
+ for(let a = 0; a < subpath.length; a++) {
110
+ const partstr = subpath[a];
111
+ if(partstr.includes(':')) {
112
+ const paraname = partstr.replace(':','');
113
+ paramsWithType.push(`${paraname}: string`);
114
+ paramsWithoutType.push(paraname);
115
+ }
116
+ }
117
+ }
97
118
 
98
- output.push(name);
119
+ if(api.queryPara && api.queryPara.length > 0) {
120
+ for(let q=0; q < api.queryPara.length; q++) {
121
+ const qp = api['queryPara'][q];
122
+ paramsWithType.push(`${qp}: string`);
123
+ paramsWithoutType.push(qp);
124
+ }
99
125
  }
100
126
 
101
- if (hasBody) {
102
- args.push('data: any');
103
- output.push('data');
127
+ if(hasBody) {
128
+ paramsWithType.push(`data: ${getTypeName(api.schema)}`);
129
+ paramsWithoutType.push('data');
104
130
  }
105
131
  %>
106
-
107
- async <%= action %>(headers: ApiHeader, <%= args.join(', ') %>) {
132
+
133
+ async <%= action %>(
134
+ headers: ApiHeader,
135
+ <%= paramsWithType.join(',') %>
136
+ ){
108
137
  const api = this.getApi(headers);
109
- const resp = await api.run<%= upperFirstCase(action) %>(<%= output.join(', ') %>);
138
+ const resp = await api.run<%= upperFirstCase(action) %>(<%= paramsWithoutType.join(', ') %>);
110
139
  return resp.data;
111
- }
140
+ }
112
141
  <% } %>
113
142
  <% } %>
114
143
  <% }) %>
@@ -7,45 +7,63 @@
7
7
  const resourcePascalName = upperFirstCase(simpleAppConfig.resourceName);
8
8
  const resourceKebabName = camelToKebab(simpleAppConfig.resourceName);
9
9
  const additionalApis = simpleAppConfig?.additionalApis || [];
10
+ const resourceTitleName = titleCase(resourcePascalName);
10
11
  let availableApis = {};
11
12
 
12
13
  Object.entries(miniAppWhitelistApis).forEach(([action, value]) => {
13
14
  if (value !== true && typeof value !== 'object') { return; }
14
15
  let method = '';
16
+ let description = '';
17
+
15
18
  switch(action) {
16
19
  case 'detail':
17
20
  method = 'get';
21
+ description = `Retrieve a single ${resourceTitleName} record by ID.`;
18
22
  break;
19
23
 
20
24
  case 'list':
25
+ method = 'post';
26
+ description = `Retrieve ${resourceTitleName} records with optional filtering, sorting, and field selection.`;
27
+ break;
28
+
21
29
  case 'create':
30
+ method = 'post';
31
+ description = `Create a new ${resourceTitleName} record.`;
32
+ break;
33
+
22
34
  case 'autoComplete':
23
35
  method = 'post';
36
+ description = `Retrieve a selectable list of ${resourceTitleName} options for dropdowns or autocomplete fields.`;
24
37
  break;
25
38
 
26
39
  case 'update':
27
40
  method = 'put';
41
+ description = `Replace an existing ${resourceTitleName} record with new data.`;
28
42
  break;
29
43
 
30
44
  case 'patch':
31
45
  method = 'patch';
46
+ description = `Update specific fields of an existing ${resourceTitleName} record.`;
32
47
  break;
33
48
 
34
49
  case 'delete':
35
50
  method = 'delete';
51
+ description = `Delete an existing ${resourceTitleName} record.`;
36
52
  break;
37
53
 
38
54
  case 'current':
39
55
  return;
40
- break;
41
56
 
42
57
  default:
43
- method = (additionalApis ?? []).find(item => item.action === action)?.method ?? '';
58
+ const additionalApiConfig = (additionalApis ?? []).find(item => item.action === action);
59
+ method = additionalApiConfig?.method ?? '';
60
+ description = additionalApiConfig?.description ?? '';
44
61
  break;
45
62
  }
46
63
 
47
64
  availableApis[action] = {
48
- method: method
65
+ method: method,
66
+ description: description,
49
67
  }
50
68
  });
51
69
 
@@ -0,0 +1,22 @@
1
+ <%
2
+ const modules = it.modules.sort((a, b) => a.docname.localeCompare(b.docname, undefined, { sensitivity: 'base' }));
3
+ %>
4
+
5
+ const customFields = [
6
+ <% modules.forEach(module => { %>
7
+ <%
8
+ const schema = module.schema;
9
+ const simpleAppConfig = schema['x-simpleapp-config'];
10
+ const isEnabled = simpleAppConfig?.customField?.isEnable || false;
11
+ %>
12
+ <% if(isEnabled) { %>
13
+ {
14
+ documentType: '<%= simpleAppConfig.documentType%>',
15
+ documentName: '<%= simpleAppConfig.documentName%>',
16
+ resourceName: '<%= simpleAppConfig.resourceName%>',
17
+ },
18
+ <% } %>
19
+ <% }); %>
20
+ ];
21
+
22
+ export default customFields;