@simitgroup/simpleapp-generator 1.0.8 → 1.0.14
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/README.md +128 -1
- package/dist/createproject.js +39 -18
- package/dist/createproject.js.map +1 -1
- package/dist/generate.js +49 -20
- package/dist/generate.js.map +1 -1
- package/dist/index.js +36 -25
- package/dist/index.js.map +1 -1
- package/dist/processors/jsonschemabuilder.js +60 -9
- package/dist/processors/jsonschemabuilder.js.map +1 -1
- package/dist/storage.js +5 -0
- package/dist/storage.js.map +1 -0
- package/package.json +10 -5
- package/src/createproject.ts +40 -14
- package/src/generate.ts +62 -28
- package/src/index.ts +31 -20
- package/src/processors/jsonschemabuilder.ts +70 -15
- package/src/storage.ts +3 -0
- package/src/type.ts +24 -2
- package/templates/SimpleAppClient.eta +10 -5
- package/templates/SimpleAppController.eta +4 -1
- package/templates/SimpleAppService.eta +87 -11
- package/templates/basic/controller.eta +17 -1
- package/templates/basic/model.eta +1 -1
- package/templates/basic/pageindex.vue.eta +50 -0
- package/templates/basic/pageindexwithid.vue.eta +1 -0
- package/templates/basic/service.eta +2 -0
- package/templates/basic/{apiclient.eta → simpleappclient.eta} +15 -7
- package/templates/nuxt/app.vue.eta +8 -0
- package/templates/nuxt/components.crudsimple.vue.eta +95 -0
- package/templates/nuxt/components.debugdocdata.vue.eta +20 -0
- package/templates/nuxt/components.eventmonitor.vue.eta +79 -0
- package/templates/nuxt/components.menus.vue.eta +8 -0
- package/templates/nuxt/composables.getautocomplete.ts.eta +24 -0
- package/templates/nuxt/composables.getmenus.ts.eta +8 -0
- package/templates/nuxt/env.eta +3 -0
- package/templates/nuxt/layouts.default.vue.eta +10 -0
- package/templates/{nuxt.config.eta → nuxt/nuxt.config.ts.eta} +6 -3
- package/templates/nuxt/pages.index.vue.eta +3 -0
- package/templates/{nuxt.plugins.eta → nuxt/plugins.simpleapp.ts.eta} +12 -2
- package/templates/nuxt/server.api.ts.eta +131 -0
- package/templates/nuxt/tailwind.config.ts.eta +9 -0
- package/templates/nuxt/tailwind.css.eta +28 -0
- package/templates/nuxt.env.eta +0 -2
|
@@ -3,24 +3,46 @@ import { JSONSchema7, JSONSchema7Definition,JSONSchema7Array,JSONSchema7TypeName
|
|
|
3
3
|
import * as js7 from 'json-schema';
|
|
4
4
|
import { capitalizeFirstLetter } from '../libs';
|
|
5
5
|
import {JsonSchemaProperties} from "../type"
|
|
6
|
+
import { Logger, ILogObj } from "tslog";
|
|
7
|
+
import $RefParser from "@apidevtools/json-schema-ref-parser";
|
|
8
|
+
import {foreignkeys} from '../storage'
|
|
6
9
|
// import { ConflictException } from '@nestjs/common';
|
|
7
10
|
import {
|
|
8
11
|
FieldModel,
|
|
9
12
|
Fieldtypes,
|
|
10
13
|
ChildModels,
|
|
11
14
|
SchemaModel,
|
|
15
|
+
TypeForeignKey,
|
|
16
|
+
TypeForeignKeyCatalogue
|
|
12
17
|
} from '../type';
|
|
13
18
|
import { json } from 'stream/consumers';
|
|
14
|
-
|
|
19
|
+
const log: Logger<ILogObj> = new Logger();
|
|
20
|
+
const FIELD_AUTOCOMPLETE_CODE='field-autocomplete-code'
|
|
21
|
+
const FIELD_AUTOCOMPLETE_NAME='field-autocomplete-name'
|
|
22
|
+
const FOREIGNKEY_PROPERTY='x-foreignkey'
|
|
15
23
|
let allmodels: ChildModels = {};
|
|
16
|
-
|
|
24
|
+
let fullschema={}
|
|
25
|
+
let fieldAutoCompleteCode=''
|
|
26
|
+
let fieldAutoCompleteName=''
|
|
27
|
+
|
|
28
|
+
export const readJsonSchemaBuilder = async (
|
|
17
29
|
doctype: string,
|
|
18
30
|
docname: string,
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
orijsondata:JSONSchema7,
|
|
32
|
+
allforeignkeys:TypeForeignKeyCatalogue
|
|
33
|
+
) => {
|
|
34
|
+
|
|
35
|
+
fieldAutoCompleteCode=''
|
|
36
|
+
fieldAutoCompleteName=''
|
|
21
37
|
allmodels = {};
|
|
22
|
-
const validateddata: JSONSchema7 = { ...
|
|
38
|
+
const validateddata: JSONSchema7 = { ...orijsondata };
|
|
23
39
|
let schema: SchemaModel | SchemaModel[];
|
|
40
|
+
const tmpjsondata = await $RefParser.dereference(orijsondata).then((schema)=>{
|
|
41
|
+
// console.log("schema",doctype, schema['properties']['category']? schema['properties']['category']:'')
|
|
42
|
+
return schema
|
|
43
|
+
})
|
|
44
|
+
const jsondata:JSONSchema7 = {...tmpjsondata} as JSONSchema7
|
|
45
|
+
|
|
24
46
|
|
|
25
47
|
if (jsondata && jsondata.type == 'object') {
|
|
26
48
|
//no _id then need add
|
|
@@ -30,14 +52,22 @@ export const readJsonSchemaBuilder = (
|
|
|
30
52
|
} else if (jsondata.type == 'array') {
|
|
31
53
|
throw(`unsupport array type for ${docname}.${doctype}`)
|
|
32
54
|
}
|
|
33
|
-
|
|
34
|
-
|
|
55
|
+
if(fieldAutoCompleteCode=='') {
|
|
56
|
+
log.error(`you shall define 1 field with format:'${FIELD_AUTOCOMPLETE_CODE}'`)
|
|
57
|
+
throw "missing field format"
|
|
58
|
+
}
|
|
59
|
+
if(fieldAutoCompleteName=='') {
|
|
60
|
+
log.error(`you shall define 1 field with format: '${FIELD_AUTOCOMPLETE_NAME}'}`)
|
|
61
|
+
throw "missing field format"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return Promise.resolve(allmodels);
|
|
35
65
|
};
|
|
36
66
|
|
|
37
67
|
|
|
38
|
-
const processObject =
|
|
68
|
+
const processObject = (doctype: string,
|
|
39
69
|
docname: string,
|
|
40
|
-
jsondata:JSONSchema7,)
|
|
70
|
+
jsondata:JSONSchema7,) =>{
|
|
41
71
|
if(!jsondata['properties']){
|
|
42
72
|
throw ("Invalid json schema {doctype}.{docname}, no 'properties' defined")
|
|
43
73
|
}
|
|
@@ -79,14 +109,39 @@ const genSchema = (
|
|
|
79
109
|
const objectitem:JSONSchema7= {} as JSONSchema7
|
|
80
110
|
Object.assign(objectitem,obj.items);
|
|
81
111
|
|
|
82
|
-
// Object.assign(objtmp,jsondata?[key]:{});
|
|
83
112
|
const isrequired = requiredlist && requiredlist.includes(key);
|
|
84
|
-
// console.log('----', key, isrequired, obj);
|
|
85
113
|
const newName: string = docname + capitalizeFirstLetter(key);
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
114
|
+
if(obj.format && obj.format==FIELD_AUTOCOMPLETE_CODE){
|
|
115
|
+
fieldAutoCompleteCode=key
|
|
116
|
+
}
|
|
117
|
+
if(obj.format && obj.format==FIELD_AUTOCOMPLETE_NAME){
|
|
118
|
+
fieldAutoCompleteName=key
|
|
119
|
+
}
|
|
120
|
+
// if (obj.type == 'object' && obj.items ){
|
|
121
|
+
// console.log("Refer to another object",docname,': ',key,obj,obj.items)
|
|
122
|
+
|
|
123
|
+
// obj,obj.items
|
|
124
|
+
//foreignkeys
|
|
125
|
+
//FOREIGNKEY_PROPERTY
|
|
126
|
+
// newmodel[key] = 'Object';
|
|
127
|
+
// }
|
|
128
|
+
// else
|
|
89
129
|
if (obj.type == 'object') {
|
|
130
|
+
|
|
131
|
+
if(obj[FOREIGNKEY_PROPERTY]){
|
|
132
|
+
console.warn("FOREIGNKEY_PROPERTY exists",FOREIGNKEY_PROPERTY,obj[FOREIGNKEY_PROPERTY])
|
|
133
|
+
const masterdatacollection = obj[FOREIGNKEY_PROPERTY]
|
|
134
|
+
const clientdatacollection = docname.toLowerCase()
|
|
135
|
+
const foreignkeyidentity= key+'._id'
|
|
136
|
+
if(!foreignkeys[masterdatacollection]){
|
|
137
|
+
let tmp:TypeForeignKey = {} as TypeForeignKey
|
|
138
|
+
tmp[clientdatacollection]=[foreignkeyidentity]
|
|
139
|
+
foreignkeys[masterdatacollection] = tmp
|
|
140
|
+
}else{
|
|
141
|
+
foreignkeys[masterdatacollection][clientdatacollection].push(foreignkeyidentity)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
}
|
|
90
145
|
genSchema(newName, obj.type, obj.properties, obj.required);
|
|
91
146
|
newmodel[key] = newName;
|
|
92
147
|
} else if (obj.type == 'array' && obj.items && objectitem?.type == 'object') {
|
|
@@ -104,7 +159,7 @@ const genSchema = (
|
|
|
104
159
|
// console.log(key,'--------newmodel',obj, newmodel[key]);
|
|
105
160
|
}
|
|
106
161
|
}
|
|
107
|
-
allmodels[docname] = { type: schematype, model: newmodel };
|
|
162
|
+
allmodels[docname] = { type: schematype, model: newmodel,codeField: fieldAutoCompleteCode ,nameField: fieldAutoCompleteName };
|
|
108
163
|
return newmodel;
|
|
109
164
|
};
|
|
110
165
|
|
package/src/storage.ts
ADDED
package/src/type.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JSONSchema7, JSONSchema7Definition } from 'json-schema';
|
|
2
2
|
export type ChildModels = {
|
|
3
|
-
[key: string]: { type: string; model: SchemaModel };
|
|
3
|
+
[key: string]: { type: string; model: SchemaModel,codeField:string,nameField:string };
|
|
4
4
|
};
|
|
5
5
|
export enum Fieldtypes {
|
|
6
6
|
'string' = 'string',
|
|
@@ -35,8 +35,30 @@ export type JsonSchemaProperties= {
|
|
|
35
35
|
// JSONSchema7Definition ,JSONSchema7
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
export type TypeForeignKeyCatalogue = {
|
|
39
|
+
[cataloguename:string]:TypeForeignKey
|
|
40
|
+
}
|
|
41
|
+
export type TypeForeignKey={
|
|
42
|
+
[collection:string]:string[]
|
|
43
|
+
}
|
|
39
44
|
export type ModuleObject = {
|
|
40
45
|
doctype:string
|
|
41
46
|
docname:string
|
|
47
|
+
}
|
|
48
|
+
export type TypeGenerateDocumentVariable ={
|
|
49
|
+
name: string
|
|
50
|
+
doctype: string
|
|
51
|
+
models: ChildModels
|
|
52
|
+
autocompletecode:string
|
|
53
|
+
autocompletename:string
|
|
54
|
+
schema: SchemaModel
|
|
55
|
+
apiSchemaName: string
|
|
56
|
+
typename: string
|
|
57
|
+
fullApiSchemaName: string
|
|
58
|
+
fullTypeName:string
|
|
59
|
+
jsonschema: JSONSchema7
|
|
60
|
+
bothEndCode: string
|
|
61
|
+
frontEndCode: string
|
|
62
|
+
backEndCode: string
|
|
63
|
+
controllerCode:string
|
|
42
64
|
}
|
|
@@ -14,6 +14,7 @@ type crudType = {
|
|
|
14
14
|
export class SimpleAppClient<
|
|
15
15
|
TData extends { _id?: string },
|
|
16
16
|
TApi extends crudType,
|
|
17
|
+
defaultTimeout:number = 5000;
|
|
17
18
|
> {
|
|
18
19
|
protected docapi;
|
|
19
20
|
protected data = <Ref<TData>>ref({} as TData);
|
|
@@ -36,7 +37,7 @@ export class SimpleAppClient<
|
|
|
36
37
|
};
|
|
37
38
|
|
|
38
39
|
async getById(id: string) {
|
|
39
|
-
return await this.docapi.runFindOne(id).then((res: AxiosResponse) => {
|
|
40
|
+
return await this.docapi.runFindOne(id,{timeout:this.defaultTimeout}).then((res: AxiosResponse) => {
|
|
40
41
|
// this.data.value = { ...res.data };
|
|
41
42
|
Object.assign(this.data.value, res.data);
|
|
42
43
|
return res;
|
|
@@ -48,7 +49,7 @@ export class SimpleAppClient<
|
|
|
48
49
|
return await Promise.reject(errors);
|
|
49
50
|
} else {
|
|
50
51
|
return await this.docapi
|
|
51
|
-
.runCreate(this.data.value)
|
|
52
|
+
.runCreate(this.data.value,{timeout:this.defaultTimeout})
|
|
52
53
|
.then((res: AxiosResponse) => {
|
|
53
54
|
this.data.value = { ...res.data };
|
|
54
55
|
return res;
|
|
@@ -62,17 +63,17 @@ export class SimpleAppClient<
|
|
|
62
63
|
return await Promise.reject(errors);
|
|
63
64
|
} else {
|
|
64
65
|
return await this.docapi
|
|
65
|
-
.runUpdate(recordid, this.data.value)
|
|
66
|
+
.runUpdate(recordid, this.data.value,{timeout:this.defaultTimeout})
|
|
66
67
|
.then((res: AxiosResponse) => {
|
|
67
68
|
return res;
|
|
68
69
|
});
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
72
|
async delete(id: string) {
|
|
72
|
-
return await this.docapi.runDelete(id);
|
|
73
|
+
return await this.docapi.runDelete(id,{timeout:this.defaultTimeout});
|
|
73
74
|
}
|
|
74
75
|
async list() {
|
|
75
|
-
return await this.docapi.runList();
|
|
76
|
+
return await this.docapi.runList({timeout:this.defaultTimeout});
|
|
76
77
|
}
|
|
77
78
|
find() {}
|
|
78
79
|
hook(type: string, data: TData) {
|
|
@@ -81,6 +82,10 @@ export class SimpleAppClient<
|
|
|
81
82
|
}
|
|
82
83
|
validateFailed() {
|
|
83
84
|
const ajv = new Ajv({ allErrors: true });
|
|
85
|
+
ajv.addKeyword({
|
|
86
|
+
keyword:'autocompletesrc',
|
|
87
|
+
type:'string'
|
|
88
|
+
});
|
|
84
89
|
addFormats(ajv);
|
|
85
90
|
this.errorlist.value = {};
|
|
86
91
|
this.hook('pre-validation', this.data.value);
|
|
@@ -20,6 +20,7 @@ type ServiceType = {
|
|
|
20
20
|
findIdThenDelete: Function;
|
|
21
21
|
findIdThenUpdate: Function;
|
|
22
22
|
setData: Function;
|
|
23
|
+
getAutoComplete: Function;
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
// @ApiTags(doctype)
|
|
@@ -37,7 +38,9 @@ export class SimpleAppController<TService extends ServiceType, TApiSchema, T> {
|
|
|
37
38
|
async _list() {
|
|
38
39
|
return this.service.list();
|
|
39
40
|
}
|
|
40
|
-
|
|
41
|
+
async _autocomplete(keyword: string) {
|
|
42
|
+
return this.service.getAutoComplete(keyword);
|
|
43
|
+
}
|
|
41
44
|
async _findOne(id: string) {
|
|
42
45
|
const result = (await this.service.findById(id)) as TApiSchema;
|
|
43
46
|
|
|
@@ -3,7 +3,7 @@ import { InjectModel } from '@nestjs/mongoose';
|
|
|
3
3
|
import { Model } from 'mongoose';
|
|
4
4
|
import Ajv from 'ajv';
|
|
5
5
|
import addFormats from 'ajv-formats';
|
|
6
|
-
|
|
6
|
+
import foreignkeys from '../dicts/foreignkeys.json';
|
|
7
7
|
import {
|
|
8
8
|
NotFoundException,
|
|
9
9
|
InternalServerErrorException,
|
|
@@ -11,6 +11,11 @@ import {
|
|
|
11
11
|
@Injectable()
|
|
12
12
|
export class SimpleAppService<T extends { _id?: string }> {
|
|
13
13
|
protected jsonschema = { type: 'object', properties: {}, required: [] };
|
|
14
|
+
protected documentIdentityCode = 'code';
|
|
15
|
+
protected documentIdentityName = 'label';
|
|
16
|
+
protected documentName = 'category';
|
|
17
|
+
protected documentType = 'CAT';
|
|
18
|
+
protected LIMITPERPAGE = 20;
|
|
14
19
|
protected data: T = { _id: '' } as T;
|
|
15
20
|
protected doc: Model<T>;
|
|
16
21
|
protected errorlist = [];
|
|
@@ -21,7 +26,7 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
21
26
|
setSchema = (newschema) => (this.jsonschema = newschema);
|
|
22
27
|
getSchema = () => this.doc.schema.obj;
|
|
23
28
|
getData = () => {
|
|
24
|
-
console.log('thisdata', this.data);
|
|
29
|
+
//console.log('thisdata', this.data);
|
|
25
30
|
return this.data;
|
|
26
31
|
};
|
|
27
32
|
setData = (newdata: T) => {
|
|
@@ -41,11 +46,34 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
41
46
|
throw new InternalServerErrorException(err.message);
|
|
42
47
|
}
|
|
43
48
|
}
|
|
49
|
+
async getAutoComplete(keyword: string) {
|
|
50
|
+
try {
|
|
51
|
+
const filter1 = {};
|
|
52
|
+
const filter2 = {};
|
|
53
|
+
filter1[this.documentIdentityCode] = { $regex: keyword };
|
|
54
|
+
filter2[this.documentIdentityName] = { $regex: keyword };
|
|
55
|
+
const filterobj = { $or: [filter1, filter2] };
|
|
56
|
+
const projections = {
|
|
57
|
+
id: `\$_id`,
|
|
58
|
+
label: `\$${this.documentIdentityCode}`,
|
|
59
|
+
name: `\$${this.documentIdentityName}`,
|
|
60
|
+
};
|
|
61
|
+
const products = await this.doc.find(filterobj, projections, {
|
|
62
|
+
limit: this.LIMITPERPAGE,
|
|
63
|
+
});
|
|
64
|
+
const productlist = products.map((p: T) => {
|
|
65
|
+
return p;
|
|
66
|
+
});
|
|
67
|
+
return productlist;
|
|
68
|
+
} catch (err) {
|
|
69
|
+
throw new InternalServerErrorException(err.message);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
44
72
|
async findById(id: string) {
|
|
45
73
|
try {
|
|
46
|
-
console.log('findById', id);
|
|
74
|
+
//console.log('findById', id);
|
|
47
75
|
this.data = await this.doc.findById(id);
|
|
48
|
-
console.log('findById done', this.data);
|
|
76
|
+
//console.log('findById done', this.data);
|
|
49
77
|
} catch (err) {
|
|
50
78
|
//error
|
|
51
79
|
throw new InternalServerErrorException(err.message);
|
|
@@ -55,7 +83,7 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
55
83
|
//data not found
|
|
56
84
|
throw new NotFoundException('Document Not found:');
|
|
57
85
|
}
|
|
58
|
-
console.log('this.data', this.data);
|
|
86
|
+
//console.log('this.data', this.data);
|
|
59
87
|
return this.data;
|
|
60
88
|
// return this;
|
|
61
89
|
}
|
|
@@ -78,8 +106,14 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
78
106
|
this.findIdThenUpdate(id, this.data);
|
|
79
107
|
}
|
|
80
108
|
async delete() {
|
|
109
|
+
|
|
81
110
|
const id: string = this.getRecordId();
|
|
82
|
-
this.
|
|
111
|
+
const dependency = await this.getRelatedRecords(id);
|
|
112
|
+
if (!dependency) {
|
|
113
|
+
return await this.findIdThenDelete(id);
|
|
114
|
+
} else {
|
|
115
|
+
return dependency;
|
|
116
|
+
}
|
|
83
117
|
}
|
|
84
118
|
hook(type: string, data: T) {
|
|
85
119
|
return true;
|
|
@@ -87,7 +121,12 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
87
121
|
validateData(data: T) {
|
|
88
122
|
const ajv = new Ajv({ allErrors: true });
|
|
89
123
|
addFormats(ajv);
|
|
90
|
-
|
|
124
|
+
ajv.addFormat('field-autocomplete-code', /.*$/);
|
|
125
|
+
ajv.addFormat('field-autocomplete-name', /.*$/);
|
|
126
|
+
ajv.addKeyword({
|
|
127
|
+
keyword: 'x-foreignkey',
|
|
128
|
+
type: 'string',
|
|
129
|
+
});
|
|
91
130
|
if (!this.hook('pre-validation', data)) {
|
|
92
131
|
const erromsg: string[] = [];
|
|
93
132
|
for (let i = 0; i < this.errorlist.length; i++) {
|
|
@@ -98,7 +137,7 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
98
137
|
const validate = ajv.compile(this.jsonschema);
|
|
99
138
|
const valid = validate(data);
|
|
100
139
|
if (!valid) {
|
|
101
|
-
console.log(validate.errors);
|
|
140
|
+
//console.log(validate.errors);
|
|
102
141
|
const erromsg: string[] = [];
|
|
103
142
|
for (let i = 0; i < validate.errors.length; i++) {
|
|
104
143
|
erromsg.push(validate.errors[i].message);
|
|
@@ -111,8 +150,14 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
111
150
|
async findIdThenDelete(id: string) {
|
|
112
151
|
// const data = await this.findById(id);
|
|
113
152
|
try {
|
|
114
|
-
|
|
115
|
-
|
|
153
|
+
//console.log('deletedeletedeletedelete');
|
|
154
|
+
const dependency = await this.getRelatedRecords(id);
|
|
155
|
+
if (!dependency) {
|
|
156
|
+
const deleteresult = await this.doc.findByIdAndDelete(id);
|
|
157
|
+
return deleteresult;
|
|
158
|
+
} else {
|
|
159
|
+
return Promise.reject(dependency);
|
|
160
|
+
}
|
|
116
161
|
} catch (err) {
|
|
117
162
|
throw new InternalServerErrorException(err.message);
|
|
118
163
|
}
|
|
@@ -122,13 +167,44 @@ export class SimpleAppService<T extends { _id?: string }> {
|
|
|
122
167
|
// const existingdata = await this.findById(id);
|
|
123
168
|
|
|
124
169
|
try {
|
|
125
|
-
console.log('findIdThenUpdate', id);
|
|
170
|
+
//console.log('findIdThenUpdate', id);
|
|
126
171
|
this.validateData(data);
|
|
127
172
|
// const result = await existingdata.doc.updateOne(data);
|
|
128
173
|
const result = await this.doc.findByIdAndUpdate(id, data);
|
|
174
|
+
|
|
129
175
|
return result;
|
|
130
176
|
} catch (err) {
|
|
131
177
|
throw new InternalServerErrorException(err.message);
|
|
132
178
|
}
|
|
133
179
|
}
|
|
180
|
+
|
|
181
|
+
//find what foreign key constraint
|
|
182
|
+
async getRelatedRecords(id: string) {
|
|
183
|
+
const foreignkeysettings = foreignkeys[this.documentName];
|
|
184
|
+
//console.log('foreignkeysettings', foreignkeysettings);
|
|
185
|
+
const propkeys = Object.getOwnPropertyNames(foreignkeysettings);
|
|
186
|
+
|
|
187
|
+
if (propkeys.length > 0) {
|
|
188
|
+
//console.log('Have properties');
|
|
189
|
+
for (let i = 0; i < propkeys.length; i++) {
|
|
190
|
+
const collectionname = propkeys[i];
|
|
191
|
+
//console.log('run ', i, collectionname);
|
|
192
|
+
const fobjs = foreignkeysettings[propkeys[i]];
|
|
193
|
+
const collection = this.doc.db.collection(collectionname);
|
|
194
|
+
//single schema may have multiple foreign key link here, loop all
|
|
195
|
+
for (let j = 0; j < fobjs.length; j++) {
|
|
196
|
+
const fkey = fobjs[j];
|
|
197
|
+
const filter = {};
|
|
198
|
+
filter[fkey] = id;
|
|
199
|
+
//console.log('getRelatedRecords get filter', collectionname, filter);
|
|
200
|
+
const result = await collection.findOne(filter);
|
|
201
|
+
//console.log('getRelatedRecords', result);
|
|
202
|
+
if (result) {
|
|
203
|
+
return Promise.reject(result);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return Promise.resolve(null);
|
|
209
|
+
}
|
|
134
210
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
Post,
|
|
11
11
|
Delete,
|
|
12
12
|
Body,
|
|
13
|
+
Query,
|
|
13
14
|
Param,
|
|
14
15
|
Type,
|
|
15
16
|
} from '@nestjs/common';
|
|
@@ -42,7 +43,20 @@ export class <%= it.typename %>Controller extends SimpleAppController<
|
|
|
42
43
|
async list() {
|
|
43
44
|
return this._list();
|
|
44
45
|
}
|
|
45
|
-
|
|
46
|
+
//autocomplete shall above :id
|
|
47
|
+
@Get('/autocomplete')
|
|
48
|
+
@ApiResponse({
|
|
49
|
+
status: 200,
|
|
50
|
+
description: 'Found',
|
|
51
|
+
type: ()=>[{id:'100',label:'label1'}],
|
|
52
|
+
})
|
|
53
|
+
@ApiResponse({ status: 500, description: 'Internal error' })
|
|
54
|
+
@ApiOperation({ operationId: 'autoComplete' })
|
|
55
|
+
async autoComplete(@Query('keyword') keyword: string) {
|
|
56
|
+
return this._autocomplete(keyword);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
46
60
|
@Get(':id')
|
|
47
61
|
@ApiResponse({
|
|
48
62
|
status: 200,
|
|
@@ -55,6 +69,8 @@ export class <%= it.typename %>Controller extends SimpleAppController<
|
|
|
55
69
|
async findOne(@Param('id') id: string) {
|
|
56
70
|
return await this._findOne(id);
|
|
57
71
|
}
|
|
72
|
+
|
|
73
|
+
|
|
58
74
|
|
|
59
75
|
@Post()
|
|
60
76
|
@ApiResponse({
|
|
@@ -30,6 +30,6 @@ const schemasetting = {
|
|
|
30
30
|
<%}) %>
|
|
31
31
|
};
|
|
32
32
|
|
|
33
|
-
export const <%= it.doctype %>MongoSchema = new Schema(schemasetting)
|
|
33
|
+
export const <%= it.doctype %>MongoSchema = new Schema(schemasetting,{collection: '<%= it.name %>'})
|
|
34
34
|
.post('validate', (doc: <%= it.typename %>) => beforeSave(doc))
|
|
35
35
|
.pre('save', () => {});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<% let skipcolumns = ['_id','createdby','created','updatedby','updated','organization_id','branch_id','tenant_id','doctype'] %>
|
|
3
|
+
<div>
|
|
4
|
+
<CrudSimple :document="doc" title="<%= it.typename %>" #default="o"
|
|
5
|
+
:listColumns="columns">
|
|
6
|
+
|
|
7
|
+
<%Object.keys(it.jsonschema.properties).forEach(function(key) { %>
|
|
8
|
+
<% let obj=it.jsonschema.properties[key] %>
|
|
9
|
+
<% if(skipcolumns.indexOf(key)>=0){ %>
|
|
10
|
+
<% } else if(obj.type=='boolean'){ %>
|
|
11
|
+
<SimpleAppCheckbox :setting="o.getField('#/properties/<%= key %>')" v-model="data.<%= key %>"/>
|
|
12
|
+
<% } else if(obj.type=='number' || obj.type=='integer'){ %>
|
|
13
|
+
<SimpleAppNumber :setting="o.getField('#/properties/<%= key %>')" v-model="data.<%= key %>"/>
|
|
14
|
+
<% } else if(obj.type=='array' && obj.items && obj.items.type =='string' ){ %>
|
|
15
|
+
<SimpleAppChip :setting="o.getField('#/properties/<%= key %>')" v-model="data.<%= key %>"/>
|
|
16
|
+
<% } else if(obj.type=='object' && typeof obj['x-foreignkey']!='undefined'){ %>
|
|
17
|
+
<SimpleAppAutocomplete :setting="o.getField('#/properties/<%= key %>')"
|
|
18
|
+
v-model="data.<%= key %>" optionLabel="label" :remote-src="getAutocomplete('<%=obj['x-foreignkey']%>')"/>
|
|
19
|
+
<% } else if(obj.type=='string'){ %>
|
|
20
|
+
<% if(obj.format=='date'){ %>
|
|
21
|
+
<SimpleAppText type="<%=formattype%>" :setting="o.getField('#/properties/<%= key %>')" v-model="data.<%= key %>"/>
|
|
22
|
+
<% } else if(obj.format=='email'){ %>
|
|
23
|
+
<SimpleAppText type="<%=formattype%>" :setting="o.getField('#/properties/<%= key %>')" v-model="data.<%= key %>"/>
|
|
24
|
+
<% } else if(obj.enum){ %>
|
|
25
|
+
<SimpleAppRadio :setting="o.getField('#/properties/<%= key %>')" v-model="data.<%= key %>"/>
|
|
26
|
+
<% } else {%>
|
|
27
|
+
<SimpleAppText :setting="o.getField('#/properties/<%= key %>')" v-model="data.<%= key %>"/>
|
|
28
|
+
<% }%>
|
|
29
|
+
<% } else { %>
|
|
30
|
+
<SimpleAppText :setting="o.getField('#/properties/<%= key %>')" v-model="data.<%= key %>"/>
|
|
31
|
+
<% }%>
|
|
32
|
+
<%})%>
|
|
33
|
+
|
|
34
|
+
</CrudSimple>
|
|
35
|
+
</div>
|
|
36
|
+
</template>
|
|
37
|
+
<script setup lang="ts">
|
|
38
|
+
import { <%= it.typename %>Doc } from "../../simpleapp/simpleappdocs/<%= it.typename %>Doc";
|
|
39
|
+
const { $event, $listen } = useNuxtApp();
|
|
40
|
+
const doc = new <%= it.typename %>Doc($event, $listen);
|
|
41
|
+
const data = doc.getReactiveData();
|
|
42
|
+
const columns = [
|
|
43
|
+
<%Object.keys(it.jsonschema.properties).forEach(function(key) { %>
|
|
44
|
+
<%let obj=it.jsonschema.properties[key] %>
|
|
45
|
+
<%if(skipcolumns.indexOf(key)>=0){%>/* skip system columns <%=key%>*/
|
|
46
|
+
<%} else if(['string','number','integer'].indexOf(obj.type)>=0){%>'<%=key%>',<%}%>
|
|
47
|
+
<%})%>
|
|
48
|
+
]
|
|
49
|
+
</script>
|
|
50
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<template></template>
|
|
@@ -13,6 +13,8 @@ import { <%Object.keys(it.models).forEach(function(key) { %> <%=key %>, <%})%> }
|
|
|
13
13
|
|
|
14
14
|
@Injectable()
|
|
15
15
|
export class <%= it.typename %>Service extends SimpleAppService<<%= it.typename %>> {
|
|
16
|
+
protected documentIdentityCode='<%~ it.autocompletecode %>'
|
|
17
|
+
protected documentIdentityName='<%~ it.autocompletename %>'
|
|
16
18
|
constructor(@InjectModel('<%= it.name %>') mydoc: Model<<%= it.typename %>>,
|
|
17
19
|
) {
|
|
18
20
|
super(mydoc);
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* and regenerate this file.
|
|
5
5
|
*/
|
|
6
6
|
import { SimpleAppClient } from "@simitgroup/simpleapp-vue-component/src/SimpleAppClient";
|
|
7
|
+
|
|
7
8
|
// import { JSONSchema7 } from 'json-schema';
|
|
8
9
|
import { Configuration,
|
|
9
10
|
<%= it.doctype.toUpperCase()%>Api,
|
|
@@ -18,11 +19,14 @@ import { Configuration,
|
|
|
18
19
|
|
|
19
20
|
export class <%= it.typename%>Doc extends SimpleAppClient<<%= it.typename%>,<%= it.doctype.toUpperCase()%>Api>{
|
|
20
21
|
public readonly schema= <%~ JSON.stringify(it.jsonschema) %>;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
protected documentIdentityCode='<%~ it.autocompletecode %>'
|
|
23
|
+
protected documentIdentityName='<%~ it.autocompletename %>'
|
|
24
|
+
constructor(event:any,listen?:any) {
|
|
25
|
+
const apiconfig = new Configuration({ basePath: useRuntimeConfig().public.APP_URL+'/api' });
|
|
24
26
|
const apiobj = new <%= it.doctype.toUpperCase()%>Api(apiconfig)
|
|
25
|
-
super(apiobj)
|
|
27
|
+
super(apiobj,'<%= it.doctype %>','<%=it.name %>')
|
|
28
|
+
this.event=event
|
|
29
|
+
this.listen=listen
|
|
26
30
|
|
|
27
31
|
this.setNew();
|
|
28
32
|
}
|
|
@@ -30,9 +34,13 @@ export class <%= it.typename%>Doc extends SimpleAppClient<<%= it.typename%>,<%=
|
|
|
30
34
|
const newdata = {
|
|
31
35
|
|
|
32
36
|
<%Object.keys(it.schema).forEach(function(key){%>
|
|
33
|
-
<%let field=it.schema[key]%>
|
|
34
|
-
<% if(field.type=='
|
|
35
|
-
|
|
37
|
+
<%let field=it.schema[key]%>
|
|
38
|
+
<% if(typeof field.default !='undefined' && field.type=='string'){%>
|
|
39
|
+
<%=key%> : '<%= field.default %>',
|
|
40
|
+
<%} else if(typeof field.default !='undefined'){%>
|
|
41
|
+
<%=key%> : <%= field.default %>,
|
|
42
|
+
<%} else if(field.type=='boolean' ){%>
|
|
43
|
+
<%=key%> :false ,
|
|
36
44
|
<%} else if(typeof field=='string'){%>
|
|
37
45
|
<%=key%> : <<%= field %>>{},
|
|
38
46
|
<%} else if(field.type=='string'){%>
|