hola-server 0.3.18 → 0.3.21
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/core/meta.js +49 -11
- package/db/entity.js +129 -25
- package/package.json +1 -1
- package/router/read.js +3 -3
- package/test/core/meta.js +62 -0
- package/test/entity/read.js +13 -6
package/core/meta.js
CHANGED
|
@@ -12,8 +12,10 @@ const meta_manager = {};
|
|
|
12
12
|
* create is false, this attribute can be shown in property list but sys property can't be shown in property list
|
|
13
13
|
*
|
|
14
14
|
* routes: configure customer defined routes
|
|
15
|
+
* link property: field link property link to entity field and the field should ref to an entity.
|
|
16
|
+
* and the field name should be the same with the ref entity field name and shouldn't make as required and no other property
|
|
15
17
|
*/
|
|
16
|
-
const field_attrs = ["name", "type", "required", "ref", "delete", "create", "list", "search", "update", "clone", "sys"];
|
|
18
|
+
const field_attrs = ["name", "type", "required", "ref", "link", "delete", "create", "list", "search", "update", "clone", "sys"];
|
|
17
19
|
const meta_attrs = ["collection", "primary_keys", "fields", "creatable", "readable", "updatable", "deleteable", "cloneable", "after_read",
|
|
18
20
|
"before_create", "after_create", "before_clone", "after_clone", "before_update", "after_update", "before_delete", "after_delete", "create", "clone", "update", "batch_update", "after_batch_update", "delete",
|
|
19
21
|
"ref_label", "ref_filter", "route", "user_field"];
|
|
@@ -37,14 +39,16 @@ const validate_field = (meta, field) => {
|
|
|
37
39
|
if (field.type) {
|
|
38
40
|
get_type(field.type);
|
|
39
41
|
} else {
|
|
40
|
-
field.
|
|
42
|
+
if (!field.link) {
|
|
43
|
+
field.type = "string"
|
|
44
|
+
}
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
if (meta.primary_keys.includes(field.name)) {
|
|
44
48
|
field.required = true;
|
|
45
49
|
}
|
|
46
50
|
|
|
47
|
-
if (field.ref) {
|
|
51
|
+
if (field.ref && !field.link) {
|
|
48
52
|
const ref_meta = meta_manager[field.ref];
|
|
49
53
|
if (!ref_meta) {
|
|
50
54
|
throw new Error("meta:" + meta.collection + ",field:" + field.name + " refers invalid meta:" + field.ref + "]");
|
|
@@ -71,6 +75,16 @@ const validate_field = (meta, field) => {
|
|
|
71
75
|
}
|
|
72
76
|
}
|
|
73
77
|
|
|
78
|
+
if (field.link) {
|
|
79
|
+
const keys = Object.keys(field);
|
|
80
|
+
const support_keys_for_links = ["name", "link", "list"]
|
|
81
|
+
keys.forEach(key => {
|
|
82
|
+
if (!support_keys_for_links.includes(key)) {
|
|
83
|
+
throw new Error("Link field just supports name, link,list property. The attribute [" + key + "] isn't supported for LINK field:" + JSON.stringify(field) + " and meta:" + meta.collection);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
74
88
|
const keys = Object.keys(field);
|
|
75
89
|
keys.forEach(key => {
|
|
76
90
|
if (!field_attrs.includes(key)) {
|
|
@@ -85,13 +99,35 @@ const validate_field = (meta, field) => {
|
|
|
85
99
|
* @param {meta fields} fields
|
|
86
100
|
*/
|
|
87
101
|
const validate_fields = (meta, fields) => {
|
|
88
|
-
const
|
|
102
|
+
const fields_map = fields.reduce((map, field) => { map[field.name] = field; return map; }, {});
|
|
103
|
+
const check_duplicate_field_names = [];
|
|
104
|
+
|
|
89
105
|
fields.forEach(field => {
|
|
90
106
|
validate_field(meta, field);
|
|
91
|
-
if (
|
|
107
|
+
if (check_duplicate_field_names.includes(field.name)) {
|
|
92
108
|
throw new Error("Duplicate field defined [" + JSON.stringify(field) + "] for meta:" + meta.collection);
|
|
93
109
|
} else {
|
|
94
|
-
|
|
110
|
+
check_duplicate_field_names.push(field.name);
|
|
111
|
+
}
|
|
112
|
+
if (field.link) {
|
|
113
|
+
const link_field = fields_map[field.link];
|
|
114
|
+
if (!link_field) {
|
|
115
|
+
throw new Error("link field [" + JSON.stringify(field) + "] should link to one field defined in meta:" + meta.collection);
|
|
116
|
+
} else {
|
|
117
|
+
if (!link_field.ref) {
|
|
118
|
+
throw new Error("link field [" + JSON.stringify(field) + "] link to field [" + JSON.stringify(link_field) + "] should ref to one entity in meta:" + meta.collection);
|
|
119
|
+
}
|
|
120
|
+
const entity = get_entity_meta(link_field.ref);
|
|
121
|
+
const link_entity_field = entity.fields_map[field.name];
|
|
122
|
+
if (!link_entity_field) {
|
|
123
|
+
throw new Error("link field [" + JSON.stringify(field) + "] should link to one field defined in meta:" + entity.collection);
|
|
124
|
+
}
|
|
125
|
+
//set type to link field type
|
|
126
|
+
field.type = link_entity_field.type;
|
|
127
|
+
if (link_entity_field.ref) {
|
|
128
|
+
field.ref = link_entity_field.ref;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
95
131
|
}
|
|
96
132
|
});
|
|
97
133
|
|
|
@@ -167,22 +203,24 @@ class EntityMeta {
|
|
|
167
203
|
this.ref_fields = this.meta.fields.filter(field => field.ref);
|
|
168
204
|
this.ref_by_metas = [];
|
|
169
205
|
|
|
206
|
+
this.link_fields = this.meta.fields.filter(field => field.link);
|
|
207
|
+
this.fields_map = meta.fields.reduce((map, field) => { map[field.name] = field; return map; }, {});
|
|
170
208
|
this.fields = meta.fields;
|
|
171
209
|
this.primary_keys = meta.primary_keys;
|
|
172
210
|
this.field_names = this.fields.map(field => field.name);
|
|
173
211
|
this.user_field = meta.user_field;
|
|
174
212
|
|
|
175
213
|
this.property_fields = this.fields.filter(field => field.sys != true);
|
|
176
|
-
this.create_fields = this.fields.filter(field => field.create != false && field.sys != true);
|
|
177
|
-
this.update_fields = this.fields.filter(field => field.create != false && field.update != false && field.sys != true);
|
|
178
|
-
this.search_fields = this.fields.filter(field => field.search != false && field.sys != true);
|
|
179
|
-
this.clone_fields = this.fields.filter(field => field.clone != false && field.sys != true);
|
|
214
|
+
this.create_fields = this.fields.filter(field => field.create != false && field.sys != true && !field.link);
|
|
215
|
+
this.update_fields = this.fields.filter(field => field.create != false && field.update != false && field.sys != true && !field.link);
|
|
216
|
+
this.search_fields = this.fields.filter(field => field.search != false && field.sys != true && !field.link);
|
|
217
|
+
this.clone_fields = this.fields.filter(field => field.clone != false && field.sys != true && !field.link);
|
|
180
218
|
this.list_fields = this.fields.filter(field => field.list != false && field.sys != true);
|
|
181
219
|
this.primary_key_fields = this.fields.filter(field => meta.primary_keys.includes(field.name));
|
|
182
220
|
this.required_field_names = this.fields.filter(field => field.required == true || this.primary_keys.includes(field.name)).map(field => field.name);
|
|
183
221
|
|
|
184
222
|
this.file_fields = meta.fields.filter(f => f.type === 'file');
|
|
185
|
-
this.upload_fields = this.file_fields && this.file_fields.length > 0 ? this.file_fields.map(f => ({ name: f.name
|
|
223
|
+
this.upload_fields = this.file_fields && this.file_fields.length > 0 ? this.file_fields.map(f => ({ name: f.name })) : [];
|
|
186
224
|
|
|
187
225
|
set_callback(this, "after_read", meta.after_read);
|
|
188
226
|
set_callback(this, "before_create", meta.before_create);
|
package/db/entity.js
CHANGED
|
@@ -180,10 +180,20 @@ class Entity {
|
|
|
180
180
|
});
|
|
181
181
|
|
|
182
182
|
const list_field_names = this.meta.list_fields.map(f => f.name);
|
|
183
|
+
const ref_fields = [];
|
|
184
|
+
const link_fields = [];
|
|
185
|
+
|
|
183
186
|
const attrs = {};
|
|
184
|
-
attr_names.split(",").forEach(
|
|
187
|
+
attr_names.split(",").forEach((attr) => {
|
|
185
188
|
if (list_field_names.includes(attr)) {
|
|
186
189
|
attrs[attr] = 1;
|
|
190
|
+
const field = this.meta.fields_map[attr];
|
|
191
|
+
if (field.link) {
|
|
192
|
+
link_fields.push(field);
|
|
193
|
+
attrs[field.link] = 1;
|
|
194
|
+
} else if (field.ref) {
|
|
195
|
+
ref_fields.push(field);
|
|
196
|
+
}
|
|
187
197
|
}
|
|
188
198
|
});
|
|
189
199
|
|
|
@@ -203,7 +213,8 @@ class Entity {
|
|
|
203
213
|
|
|
204
214
|
const total = await this.count(search_query);
|
|
205
215
|
const list = await this.find_page(search_query, sort, page_int, page_limit, attrs);
|
|
206
|
-
const
|
|
216
|
+
const list_link = await this.read_link_attrs(list, link_fields);
|
|
217
|
+
const data = await this.convert_ref_attrs(list_link, ref_fields);
|
|
207
218
|
|
|
208
219
|
if (is_log_debug()) {
|
|
209
220
|
log_debug(LOG_ENTITY, "total:" + total + ",data:" + JSON.stringify(data));
|
|
@@ -520,17 +531,18 @@ class Entity {
|
|
|
520
531
|
}
|
|
521
532
|
|
|
522
533
|
/**
|
|
523
|
-
* Validate the param object and invoke the logic to read entity
|
|
524
|
-
*
|
|
534
|
+
* Use objectid to read entity properties. Validate the param object and invoke the logic to read entity properties.
|
|
535
|
+
* This method doesn't convert ref property, so all the ref properties are objectid of the ref entity.
|
|
536
|
+
* It also donesn't inclue link property. This is used for form view to do create/update the entity.
|
|
525
537
|
* @param {object id of the entity} _id object id of the entity
|
|
526
538
|
* @param {attr names to retrieve} attr_names
|
|
527
539
|
*
|
|
528
540
|
*/
|
|
529
|
-
async
|
|
541
|
+
async read_property(_id, attr_names) {
|
|
530
542
|
const query = oid_query(_id);
|
|
531
543
|
if (query == null) {
|
|
532
544
|
if (is_log_error()) {
|
|
533
|
-
log_error(LOG_ENTITY, "
|
|
545
|
+
log_error(LOG_ENTITY, "read_property invalid id:" + _id);
|
|
534
546
|
}
|
|
535
547
|
return { code: INVALID_PARAMS, err: ["_id"] };
|
|
536
548
|
}
|
|
@@ -546,7 +558,7 @@ class Entity {
|
|
|
546
558
|
const results = await this.find(query, attrs);
|
|
547
559
|
if (results && results.length == 1) {
|
|
548
560
|
if (is_log_debug()) {
|
|
549
|
-
log_debug("
|
|
561
|
+
log_debug("read_property with query:" + JSON.stringify(query) + ",attrs:" + JSON.stringify(attrs) + ",result:" + JSON.stringify(results));
|
|
550
562
|
}
|
|
551
563
|
return { code: SUCCESS, data: results[0] };
|
|
552
564
|
} else {
|
|
@@ -555,33 +567,42 @@ class Entity {
|
|
|
555
567
|
}
|
|
556
568
|
|
|
557
569
|
/**
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
async
|
|
570
|
+
* Use objectid to read entity properties. Validate the param object and invoke the logic to read entity properties.
|
|
571
|
+
* It will convert object ref attributes to ref_label property of the ref entity and also read link attributes.
|
|
572
|
+
* @param {object id of the entity} _id object id of the entity
|
|
573
|
+
* @param {attr names to retrieve} attr_names
|
|
574
|
+
*
|
|
575
|
+
*/
|
|
576
|
+
async read_entity(_id, attr_names) {
|
|
565
577
|
const query = oid_query(_id);
|
|
566
578
|
if (query == null) {
|
|
567
579
|
if (is_log_error()) {
|
|
568
|
-
log_error(LOG_ENTITY, "
|
|
580
|
+
log_error(LOG_ENTITY, "read_entity invalid id:" + _id);
|
|
569
581
|
}
|
|
570
582
|
return { code: INVALID_PARAMS, err: ["_id"] };
|
|
571
583
|
}
|
|
572
584
|
|
|
573
585
|
if (!attr_names) {
|
|
574
586
|
if (is_log_error()) {
|
|
575
|
-
log_error(LOG_ENTITY, "
|
|
587
|
+
log_error(LOG_ENTITY, "read_entity invalid attr_names:" + attr_names);
|
|
576
588
|
}
|
|
577
589
|
return { code: INVALID_PARAMS, err: ["attr_names"] };
|
|
578
590
|
}
|
|
579
591
|
|
|
580
592
|
const field_names = this.meta.property_fields.map(f => f.name);
|
|
593
|
+
const ref_fields = [];
|
|
594
|
+
const link_fields = [];
|
|
581
595
|
const attrs = {};
|
|
582
596
|
attr_names.split(",").forEach(function (attr) {
|
|
583
597
|
if (field_names.includes(attr)) {
|
|
584
598
|
attrs[attr] = 1;
|
|
599
|
+
const field = this.meta.fields_map[attr];
|
|
600
|
+
if (field.link) {
|
|
601
|
+
link_fields.push(field);
|
|
602
|
+
attrs[field.link] = 1;
|
|
603
|
+
} else if (field.ref) {
|
|
604
|
+
ref_fields.push(field);
|
|
605
|
+
}
|
|
585
606
|
}
|
|
586
607
|
});
|
|
587
608
|
|
|
@@ -597,10 +618,12 @@ class Entity {
|
|
|
597
618
|
}
|
|
598
619
|
}
|
|
599
620
|
|
|
600
|
-
const
|
|
621
|
+
const list_link = await this.read_link_attrs(results, link_fields);
|
|
622
|
+
const converted = await this.convert_ref_attrs(list_link, ref_fields);
|
|
623
|
+
|
|
601
624
|
if (converted && converted.length == 1) {
|
|
602
625
|
if (is_log_debug()) {
|
|
603
|
-
log_debug("
|
|
626
|
+
log_debug("read_entity with query:" + JSON.stringify(query) + ",attrs:" + JSON.stringify(attrs) + ",converted:" + JSON.stringify(converted));
|
|
604
627
|
}
|
|
605
628
|
return { code: SUCCESS, data: converted[0] };
|
|
606
629
|
}
|
|
@@ -877,17 +900,17 @@ class Entity {
|
|
|
877
900
|
* @param {element of object} elements
|
|
878
901
|
* @returns
|
|
879
902
|
*/
|
|
880
|
-
async convert_ref_attrs(elements) {
|
|
881
|
-
if (elements &&
|
|
882
|
-
for (let i = 0; i <
|
|
883
|
-
const ref_field =
|
|
903
|
+
async convert_ref_attrs(elements, ref_fields) {
|
|
904
|
+
if (elements && ref_fields && ref_fields.length > 0) {
|
|
905
|
+
for (let i = 0; i < ref_fields.length; i++) {
|
|
906
|
+
const ref_field = ref_fields[i];
|
|
884
907
|
let id_array = [];
|
|
885
908
|
for (let j = 0; j < elements.length; j++) {
|
|
886
909
|
const obj = elements[j];
|
|
887
910
|
const value = obj[ref_field.name];
|
|
888
911
|
if (Array.isArray(value)) {
|
|
889
912
|
id_array = id_array.concat(value);
|
|
890
|
-
} else {
|
|
913
|
+
} else if (value) {
|
|
891
914
|
id_array.push(value);
|
|
892
915
|
}
|
|
893
916
|
}
|
|
@@ -896,13 +919,16 @@ class Entity {
|
|
|
896
919
|
const ref_meta = get_entity_meta(ref_field.ref);
|
|
897
920
|
const ref_entity = new Entity(ref_meta);
|
|
898
921
|
const ref_labels = await ref_entity.get_ref_labels(id_array);
|
|
899
|
-
const
|
|
922
|
+
const id_key = "_id";
|
|
923
|
+
const label_map_obj = map_array_to_obj(ref_labels, id_key, ref_meta.ref_label);
|
|
900
924
|
for (let j = 0; j < elements.length; j++) {
|
|
901
925
|
const obj = elements[j];
|
|
902
926
|
const value = obj[ref_field.name];
|
|
927
|
+
obj[ref_field.name + id_key] = value;
|
|
928
|
+
|
|
903
929
|
if (Array.isArray(value)) {
|
|
904
930
|
obj[ref_field.name] = value.map(v => label_map_obj[v]);
|
|
905
|
-
} else {
|
|
931
|
+
} else if (value) {
|
|
906
932
|
obj[ref_field.name] = label_map_obj[value];
|
|
907
933
|
}
|
|
908
934
|
}
|
|
@@ -911,6 +937,84 @@ class Entity {
|
|
|
911
937
|
return elements;
|
|
912
938
|
}
|
|
913
939
|
|
|
940
|
+
/**
|
|
941
|
+
* read the link attrs
|
|
942
|
+
* @param {*} elements
|
|
943
|
+
* @returns
|
|
944
|
+
*/
|
|
945
|
+
async read_link_attrs(elements, link_fields) {
|
|
946
|
+
if (elements && link_fields && link_fields.length > 0) {
|
|
947
|
+
//key is entity name, value is array of fields
|
|
948
|
+
const entity_attr_map = link_fields.reduce((map, field) => {
|
|
949
|
+
const link_field = this.meta.fields_map[field.link];
|
|
950
|
+
if (map[link_field.ref]) {
|
|
951
|
+
map[link_field.ref].push(field.name);
|
|
952
|
+
} else {
|
|
953
|
+
map[link_field.ref] = [field.name];
|
|
954
|
+
}
|
|
955
|
+
return map;
|
|
956
|
+
}, {});
|
|
957
|
+
|
|
958
|
+
//key entity, value: attr property used to query
|
|
959
|
+
const entity_filter_map = link_fields.reduce((map, field) => {
|
|
960
|
+
const link_field = this.meta.fields_map[field.link];
|
|
961
|
+
if (map[link_field.ref]) {
|
|
962
|
+
(!map[link_field.ref].includes(link_field.name)) && map[link_field.ref].push(link_field.name);
|
|
963
|
+
} else {
|
|
964
|
+
map[link_field.ref] = [link_field.name];
|
|
965
|
+
}
|
|
966
|
+
return map;
|
|
967
|
+
}, {});
|
|
968
|
+
|
|
969
|
+
const entities = Object.keys(entity_filter_map);
|
|
970
|
+
for (let i = 0; i < entities.length; i++) {
|
|
971
|
+
const meta = get_entity_meta(entities[i]);
|
|
972
|
+
const entity = new Entity(meta);
|
|
973
|
+
let id_array = [];
|
|
974
|
+
for (let j = 0; j < elements.length; j++) {
|
|
975
|
+
const obj = elements[j];
|
|
976
|
+
const linked_attrs = entity_filter_map[entities[i]];
|
|
977
|
+
for (let k = 0; k < linked_attrs.length; k++) {
|
|
978
|
+
const id = obj[linked_attrs[k]];
|
|
979
|
+
id_array.push(id);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
id_array = unique(id_array);
|
|
983
|
+
const query = oid_queries(id_array);
|
|
984
|
+
const attr_fields = entity_attr_map[entities[i]];
|
|
985
|
+
const attrs = {};
|
|
986
|
+
const ref_fields = [];
|
|
987
|
+
attr_fields.forEach((attr) => {
|
|
988
|
+
attrs[attr] = 1;
|
|
989
|
+
const field = meta.fields_map[attr];
|
|
990
|
+
if (!field.link && field.ref) {
|
|
991
|
+
ref_fields.push(field);
|
|
992
|
+
}
|
|
993
|
+
});
|
|
994
|
+
|
|
995
|
+
const ref_entity_items = await entity.find(query, attrs);
|
|
996
|
+
if (ref_entity_items && ref_entity_items.length > 0) {
|
|
997
|
+
await entity.convert_ref_attrs(ref_entity_items, ref_fields);
|
|
998
|
+
|
|
999
|
+
for (let j = 0; j < elements.length; j++) {
|
|
1000
|
+
const obj = elements[j];
|
|
1001
|
+
const linked_attrs = entity_filter_map[entities[i]];
|
|
1002
|
+
for (let k = 0; k < linked_attrs.length; k++) {
|
|
1003
|
+
const id = obj[linked_attrs[k]];
|
|
1004
|
+
const [link_obj] = ref_entity_items.filter(o => o._id + "" == id);
|
|
1005
|
+
if (link_obj) {
|
|
1006
|
+
const copy_obj = { ...link_obj };
|
|
1007
|
+
delete copy_obj["_id"];
|
|
1008
|
+
elements[j] = { ...obj, ...copy_obj };
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
return elements;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
914
1018
|
/**
|
|
915
1019
|
* get ref labels of the object, use ref_filter
|
|
916
1020
|
* @returns
|
package/package.json
CHANGED
package/router/read.js
CHANGED
|
@@ -59,7 +59,7 @@ const init_read_router = function (router, meta) {
|
|
|
59
59
|
res.json({ code: code, err: err, total: total, data: data });
|
|
60
60
|
}));
|
|
61
61
|
|
|
62
|
-
router.post('/
|
|
62
|
+
router.post('/read_entity', wrap_http(async function (req, res) {
|
|
63
63
|
let params = required_post_params(req, ["_id", "attr_names"]);
|
|
64
64
|
if (params === null) {
|
|
65
65
|
res.json({ code: NO_PARAMS, err: '[_id,attr_names] checking params are failed!' });
|
|
@@ -74,7 +74,7 @@ const init_read_router = function (router, meta) {
|
|
|
74
74
|
res.json({ code: code, err: err, data: data });
|
|
75
75
|
}));
|
|
76
76
|
|
|
77
|
-
router.post('/
|
|
77
|
+
router.post('/read_property', wrap_http(async function (req, res) {
|
|
78
78
|
let params = required_post_params(req, ["_id", "attr_names"]);
|
|
79
79
|
if (params === null) {
|
|
80
80
|
res.json({ code: NO_PARAMS, err: '[_id,attr_names] checking params are failed!' });
|
|
@@ -82,7 +82,7 @@ const init_read_router = function (router, meta) {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
const { _id, attr_names } = params;
|
|
85
|
-
const { code, err, data } = await entity.
|
|
85
|
+
const { code, err, data } = await entity.read_property(_id, attr_names);
|
|
86
86
|
if (!has_value(code)) {
|
|
87
87
|
throw new Error("the method should return code");
|
|
88
88
|
}
|
package/test/core/meta.js
CHANGED
|
@@ -274,6 +274,68 @@ describe('EntityMeta', function () {
|
|
|
274
274
|
});
|
|
275
275
|
});
|
|
276
276
|
|
|
277
|
+
it('should fails for wrong link ', function () {
|
|
278
|
+
throws(() => {
|
|
279
|
+
const entity_meta1 = new EntityMeta({
|
|
280
|
+
collection: "user_link1",
|
|
281
|
+
primary_keys: ["name"],
|
|
282
|
+
fields: [
|
|
283
|
+
{ name: "name", type: "string", required: true },
|
|
284
|
+
{ name: "role", type: "string", link: "other", required: true },
|
|
285
|
+
]
|
|
286
|
+
});
|
|
287
|
+
entity_meta1.validate_meta_info();
|
|
288
|
+
});
|
|
289
|
+
throws(() => {
|
|
290
|
+
const entity_meta1 = new EntityMeta({
|
|
291
|
+
collection: "user_link2",
|
|
292
|
+
primary_keys: ["name"],
|
|
293
|
+
fields: [
|
|
294
|
+
{ name: "name", type: "string", required: true },
|
|
295
|
+
{ name: "role", type: "string", link: "other" },
|
|
296
|
+
]
|
|
297
|
+
});
|
|
298
|
+
entity_meta1.validate_meta_info();
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
throws(() => {
|
|
302
|
+
const entity_meta1 = new EntityMeta({
|
|
303
|
+
collection: "user_link3",
|
|
304
|
+
primary_keys: ["name"],
|
|
305
|
+
fields: [
|
|
306
|
+
{ name: "name", type: "string", required: true },
|
|
307
|
+
{ name: "role", link: "other" },
|
|
308
|
+
]
|
|
309
|
+
});
|
|
310
|
+
entity_meta1.validate_meta_info();
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
it('should success for link ', function () {
|
|
315
|
+
const entity_meta1 = new EntityMeta({
|
|
316
|
+
collection: "role_link_other",
|
|
317
|
+
primary_keys: ["name"],
|
|
318
|
+
ref_label: "name",
|
|
319
|
+
fields: [
|
|
320
|
+
{ name: "name", type: "string", required: true },
|
|
321
|
+
{ name: "desc", type: "string", required: true },
|
|
322
|
+
]
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
const entity_meta2 = new EntityMeta({
|
|
326
|
+
collection: "user_link_other",
|
|
327
|
+
primary_keys: ["name"],
|
|
328
|
+
fields: [
|
|
329
|
+
{ name: "name", type: "string", required: true },
|
|
330
|
+
{ name: "user_role", type: "string", ref: "role_link_other", required: true },
|
|
331
|
+
{ name: "desc", link: "user_role", list: true },
|
|
332
|
+
]
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
strictEqual(entity_meta1.validate_meta_info(), true);
|
|
336
|
+
strictEqual(entity_meta2.validate_meta_info(), true);
|
|
337
|
+
});
|
|
338
|
+
|
|
277
339
|
it('should fails for wrong primary key type', function () {
|
|
278
340
|
throws(() => {
|
|
279
341
|
const entity_meta1 = new EntityMeta({
|
package/test/entity/read.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { SUCCESS,
|
|
1
|
+
const { SUCCESS, } = require('../../http/code');
|
|
2
2
|
const { strictEqual, deepStrictEqual } = require('assert');
|
|
3
3
|
const { Entity } = require('../../db/entity');
|
|
4
4
|
const { EntityMeta } = require('../../core/meta');
|
|
@@ -18,7 +18,8 @@ const user = {
|
|
|
18
18
|
{ name: "role", type: "array", ref: "role_read", required: true },
|
|
19
19
|
{ name: "depart", type: "string", ref: "department_read", required: true },
|
|
20
20
|
{ name: "status", type: "boolean" },
|
|
21
|
-
{ name: "desc", type: "string", search: false }
|
|
21
|
+
{ name: "desc", type: "string", search: false },
|
|
22
|
+
{ name: "people", link: "depart" },
|
|
22
23
|
]
|
|
23
24
|
};
|
|
24
25
|
|
|
@@ -32,7 +33,8 @@ const department = {
|
|
|
32
33
|
ref_label: "name",
|
|
33
34
|
fields: [
|
|
34
35
|
{ name: "name", required: true },
|
|
35
|
-
{ name: "
|
|
36
|
+
{ name: "people", type: "int" },
|
|
37
|
+
{ name: "desc", type: "string" },
|
|
36
38
|
]
|
|
37
39
|
};
|
|
38
40
|
|
|
@@ -65,6 +67,7 @@ const department_entity = new Entity(department_meta);
|
|
|
65
67
|
const init_db = async () => {
|
|
66
68
|
await user_entity.delete({});
|
|
67
69
|
await role_entity.delete({});
|
|
70
|
+
await department_entity.delete({});
|
|
68
71
|
|
|
69
72
|
await role_entity.create_entity({ name: "admin", status: true });
|
|
70
73
|
await role_entity.create_entity({ name: "user", status: true });
|
|
@@ -72,8 +75,10 @@ const init_db = async () => {
|
|
|
72
75
|
await role_entity.create_entity({ name: "user2", status: true });
|
|
73
76
|
await role_entity.create_entity({ name: "user3", status: true });
|
|
74
77
|
|
|
75
|
-
await department_entity.create_entity({ name: "dev" });
|
|
76
|
-
await department_entity.create_entity({ name: "test" });
|
|
78
|
+
await department_entity.create_entity({ name: "dev", people: 20 });
|
|
79
|
+
const result = await department_entity.create_entity({ name: "test", people: 30 });
|
|
80
|
+
strictEqual(result.err, undefined);
|
|
81
|
+
strictEqual(result.code, SUCCESS);
|
|
77
82
|
|
|
78
83
|
const { code, err } = await user_entity.create_entity({ "name": "user1", pwd: "pwd", age: "10", depart: "dev", role: "user", status: "true", email: "test@test.com", desc: "abcd" });
|
|
79
84
|
strictEqual(err, undefined);
|
|
@@ -100,7 +105,7 @@ describe('Entity Query', function () {
|
|
|
100
105
|
it('search user by name', async function () {
|
|
101
106
|
await init_db();
|
|
102
107
|
|
|
103
|
-
const query = { "attr_names": "name,age", page: "1", limit: "10", sort_by: "name", desc: "true" };
|
|
108
|
+
const query = { "attr_names": "name,age,depart,people", page: "1", limit: "10", sort_by: "name", desc: "true" };
|
|
104
109
|
const params = { age: "20" };
|
|
105
110
|
|
|
106
111
|
const { code, err, total, data } = await user_entity.list_entity(query, null, params);
|
|
@@ -110,6 +115,8 @@ describe('Entity Query', function () {
|
|
|
110
115
|
strictEqual(data.length, 3);
|
|
111
116
|
strictEqual(data[0].age, 20);
|
|
112
117
|
strictEqual(data[0].name, "user15");
|
|
118
|
+
strictEqual(data[0].people, 30);
|
|
119
|
+
strictEqual(data[0].depart, "test");
|
|
113
120
|
strictEqual(data[0].status, undefined);
|
|
114
121
|
});
|
|
115
122
|
|