hola-server 1.0.11 → 2.0.1

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 (83) hide show
  1. package/README.md +196 -1
  2. package/core/array.js +79 -142
  3. package/core/bash.js +208 -259
  4. package/core/chart.js +26 -16
  5. package/core/cron.js +14 -3
  6. package/core/date.js +15 -44
  7. package/core/encrypt.js +19 -9
  8. package/core/file.js +42 -29
  9. package/core/lhs.js +32 -6
  10. package/core/meta.js +213 -289
  11. package/core/msg.js +20 -7
  12. package/core/number.js +105 -103
  13. package/core/obj.js +15 -12
  14. package/core/random.js +9 -6
  15. package/core/role.js +69 -77
  16. package/core/thread.js +12 -2
  17. package/core/type.js +300 -261
  18. package/core/url.js +20 -12
  19. package/core/validate.js +29 -26
  20. package/db/db.js +297 -227
  21. package/db/entity.js +631 -963
  22. package/db/gridfs.js +120 -166
  23. package/design/add_default_field_attr.md +56 -0
  24. package/http/context.js +22 -8
  25. package/http/cors.js +25 -8
  26. package/http/error.js +27 -9
  27. package/http/express.js +70 -41
  28. package/http/params.js +70 -42
  29. package/http/router.js +51 -40
  30. package/http/session.js +59 -36
  31. package/index.js +85 -9
  32. package/package.json +2 -2
  33. package/router/clone.js +28 -36
  34. package/router/create.js +21 -26
  35. package/router/delete.js +24 -28
  36. package/router/read.js +137 -123
  37. package/router/update.js +38 -56
  38. package/setting.js +22 -6
  39. package/skills/array.md +155 -0
  40. package/skills/bash.md +91 -0
  41. package/skills/chart.md +54 -0
  42. package/skills/code.md +422 -0
  43. package/skills/context.md +177 -0
  44. package/skills/date.md +58 -0
  45. package/skills/express.md +255 -0
  46. package/skills/file.md +60 -0
  47. package/skills/lhs.md +54 -0
  48. package/skills/meta.md +1023 -0
  49. package/skills/msg.md +30 -0
  50. package/skills/number.md +88 -0
  51. package/skills/obj.md +36 -0
  52. package/skills/params.md +206 -0
  53. package/skills/random.md +22 -0
  54. package/skills/role.md +59 -0
  55. package/skills/session.md +281 -0
  56. package/skills/storage.md +743 -0
  57. package/skills/thread.md +22 -0
  58. package/skills/type.md +547 -0
  59. package/skills/url.md +34 -0
  60. package/skills/validate.md +48 -0
  61. package/test/cleanup/close-db.js +5 -0
  62. package/test/core/array.js +226 -0
  63. package/test/core/chart.js +51 -0
  64. package/test/core/file.js +59 -0
  65. package/test/core/lhs.js +44 -0
  66. package/test/core/number.js +167 -12
  67. package/test/core/obj.js +47 -0
  68. package/test/core/random.js +24 -0
  69. package/test/core/thread.js +20 -0
  70. package/test/core/type.js +216 -0
  71. package/test/core/validate.js +67 -0
  72. package/test/db/db-ops.js +99 -0
  73. package/test/db/pipe_test.txt +0 -0
  74. package/test/db/test_case_design.md +528 -0
  75. package/test/db/test_db_class.js +613 -0
  76. package/test/db/test_entity_class.js +414 -0
  77. package/test/db/test_gridfs_class.js +234 -0
  78. package/test/entity/create.js +1 -1
  79. package/test/entity/delete-mixed.js +156 -0
  80. package/test/entity/ref-filter.js +63 -0
  81. package/tool/gen_i18n.js +55 -21
  82. package/test/crud/router.js +0 -99
  83. package/test/router/user.js +0 -17
@@ -0,0 +1,156 @@
1
+ const { strictEqual } = require("assert");
2
+ const { Entity } = require("../../db/entity");
3
+ const { EntityMeta } = require("../../core/meta");
4
+ const { SUCCESS } = require("../../http/code");
5
+
6
+ // Parent with mixed keep/cascade references
7
+ const role_mix_meta = new EntityMeta({
8
+ creatable: true,
9
+ readable: true,
10
+ updatable: true,
11
+ deleteable: true,
12
+ collection: "role_delete_mix",
13
+ primary_keys: ["name"],
14
+ ref_label: "name",
15
+ fields: [
16
+ { name: "name", required: true }
17
+ ]
18
+ });
19
+
20
+ const user_keep_meta = new EntityMeta({
21
+ creatable: true,
22
+ readable: true,
23
+ updatable: true,
24
+ deleteable: true,
25
+ collection: "user_delete_keep",
26
+ primary_keys: ["name"],
27
+ fields: [
28
+ { name: "name", required: true },
29
+ { name: "role", type: "string", ref: "role_delete_mix", delete: "keep", required: true }
30
+ ]
31
+ });
32
+
33
+ const audit_cascade_meta = new EntityMeta({
34
+ creatable: true,
35
+ readable: true,
36
+ updatable: true,
37
+ deleteable: true,
38
+ collection: "audit_delete_cascade",
39
+ primary_keys: ["name"],
40
+ fields: [
41
+ { name: "name", required: true },
42
+ { name: "role", type: "string", ref: "role_delete_mix", delete: "cascade", required: true }
43
+ ]
44
+ });
45
+
46
+ role_mix_meta.validate_meta_info();
47
+ user_keep_meta.validate_meta_info();
48
+ audit_cascade_meta.validate_meta_info();
49
+
50
+ const role_mix_entity = new Entity(role_mix_meta);
51
+ const user_keep_entity = new Entity(user_keep_meta);
52
+ const audit_cascade_entity = new Entity(audit_cascade_meta);
53
+
54
+ // Parent with array ref cascade chain
55
+ const role_array_meta = new EntityMeta({
56
+ creatable: true,
57
+ readable: true,
58
+ updatable: true,
59
+ deleteable: true,
60
+ collection: "role_delete_array",
61
+ primary_keys: ["name"],
62
+ ref_label: "name",
63
+ fields: [
64
+ { name: "name", required: true }
65
+ ]
66
+ });
67
+
68
+ const user_array_meta = new EntityMeta({
69
+ creatable: true,
70
+ readable: true,
71
+ updatable: true,
72
+ deleteable: true,
73
+ collection: "user_delete_array",
74
+ primary_keys: ["name"],
75
+ ref_label: "name",
76
+ fields: [
77
+ { name: "name", required: true },
78
+ { name: "roles", type: "array", ref: "role_delete_array", delete: "cascade", required: true }
79
+ ]
80
+ });
81
+
82
+ const audit_array_meta = new EntityMeta({
83
+ creatable: true,
84
+ readable: true,
85
+ updatable: true,
86
+ deleteable: true,
87
+ collection: "audit_delete_array",
88
+ primary_keys: ["name"],
89
+ fields: [
90
+ { name: "name", required: true },
91
+ { name: "user", type: "string", ref: "user_delete_array", delete: "cascade", required: true }
92
+ ]
93
+ });
94
+
95
+ role_array_meta.validate_meta_info();
96
+ user_array_meta.validate_meta_info();
97
+ audit_array_meta.validate_meta_info();
98
+
99
+ const role_array_entity = new Entity(role_array_meta);
100
+ const user_array_entity = new Entity(user_array_meta);
101
+ const audit_array_entity = new Entity(audit_array_meta);
102
+
103
+ describe("Entity delete cascade/keep edges", function () {
104
+ beforeEach(async function () {
105
+ await role_mix_entity.delete({});
106
+ await user_keep_entity.delete({});
107
+ await audit_cascade_entity.delete({});
108
+ await role_array_entity.delete({});
109
+ await user_array_entity.delete({});
110
+ await audit_array_entity.delete({});
111
+ });
112
+
113
+ after(async function () {
114
+ await role_mix_entity.delete({});
115
+ await user_keep_entity.delete({});
116
+ await audit_cascade_entity.delete({});
117
+ await role_array_entity.delete({});
118
+ await user_array_entity.delete({});
119
+ await audit_array_entity.delete({});
120
+ });
121
+
122
+ it("should cascade deletions while keeping keep-referenced entities", async function () {
123
+ await role_mix_entity.create_entity({ name: "role1" });
124
+ const role = await role_mix_entity.find_one({ name: "role1" });
125
+
126
+ const { code: uCode } = await user_keep_entity.create_entity({ name: "u1", role: "role1" });
127
+ strictEqual(uCode, SUCCESS);
128
+ const { code: aCode } = await audit_cascade_entity.create_entity({ name: "a1", role: "role1" });
129
+ strictEqual(aCode, SUCCESS);
130
+
131
+ const result = await role_mix_entity.delete_entity([role._id + ""]);
132
+ strictEqual(result.code, SUCCESS);
133
+ strictEqual(await role_mix_entity.count({}), 0);
134
+ strictEqual(await user_keep_entity.count({}), 1);
135
+ strictEqual(await audit_cascade_entity.count({}), 0);
136
+ });
137
+
138
+ it("should cascade through array refs and downstream cascades", async function () {
139
+ await role_array_entity.create_entity({ name: "r1" });
140
+ await role_array_entity.create_entity({ name: "r2" });
141
+ const role1 = await role_array_entity.find_one({ name: "r1" });
142
+
143
+ const { code: uCode } = await user_array_entity.create_entity({ name: "u1", roles: ["r1", "r2"] });
144
+ strictEqual(uCode, SUCCESS);
145
+ const user = await user_array_entity.find_one({ name: "u1" });
146
+ const { code: aCode } = await audit_array_entity.create_entity({ name: "a1", user: user._id + "" });
147
+ strictEqual(aCode, SUCCESS);
148
+
149
+ const result = await role_array_entity.delete_entity([role1._id + ""]);
150
+ strictEqual(result.code, SUCCESS);
151
+
152
+ strictEqual(await role_array_entity.count({}), 1); // r2 remains
153
+ strictEqual(await user_array_entity.count({}), 0); // u1 cascaded
154
+ strictEqual(await audit_array_entity.count({}), 0); // a1 cascaded via user deletion
155
+ });
156
+ });
@@ -0,0 +1,63 @@
1
+ const { strictEqual } = require("assert");
2
+ const { Entity } = require("../../db/entity");
3
+ const { EntityMeta } = require("../../core/meta");
4
+ const { SUCCESS, REF_NOT_FOUND } = require("../../http/code");
5
+
6
+ const role_meta = new EntityMeta({
7
+ collection: "role_filter",
8
+ primary_keys: ["name"],
9
+ ref_label: "name",
10
+ fields: [
11
+ { name: "name", type: "string", required: true },
12
+ { name: "status", type: "boolean", required: true }
13
+ ],
14
+ ref_filter: { status: true }
15
+ });
16
+ role_meta.validate_meta_info();
17
+ const role_entity = new Entity(role_meta);
18
+
19
+ const user_meta = new EntityMeta({
20
+ collection: "user_filter",
21
+ primary_keys: ["name"],
22
+ fields: [
23
+ { name: "name", type: "string", required: true },
24
+ { name: "role", type: "string", ref: "role_filter", required: true }
25
+ ]
26
+ });
27
+ user_meta.validate_meta_info();
28
+ const user_entity = new Entity(user_meta);
29
+
30
+ describe("Entity ref_filter", function () {
31
+ beforeEach(async function () {
32
+ await role_entity.delete({});
33
+ await user_entity.delete({});
34
+ });
35
+
36
+ after(async function () {
37
+ await role_entity.delete({});
38
+ await user_entity.delete({});
39
+ });
40
+
41
+ it("should reject ref values filtered out by ref_filter", async function () {
42
+ await role_entity.create_entity({ name: "active", status: true });
43
+ await role_entity.create_entity({ name: "inactive", status: false });
44
+
45
+ const { code, err } = await user_entity.create_entity({ name: "u1", role: "inactive" });
46
+ strictEqual(code, REF_NOT_FOUND);
47
+ strictEqual(err[0], "role");
48
+
49
+ const { code: ok } = await user_entity.create_entity({ name: "u2", role: "active" });
50
+ strictEqual(ok, SUCCESS);
51
+ });
52
+
53
+ it("find_by_ref_value should obey default ref_filter", async function () {
54
+ await role_entity.create_entity({ name: "active", status: true });
55
+ await role_entity.create_entity({ name: "inactive", status: false });
56
+
57
+ const active = await role_entity.find_by_ref_value("active", { _id: 1 });
58
+ strictEqual(active.length, 1);
59
+
60
+ const inactive = await role_entity.find_by_ref_value("inactive", { _id: 1 });
61
+ strictEqual(inactive.length, 0);
62
+ });
63
+ });
package/tool/gen_i18n.js CHANGED
@@ -1,30 +1,64 @@
1
+ /**
2
+ * @fileoverview I18n JSON file generation from entity metadata.
3
+ * @module tool/gen_i18n
4
+ */
5
+
1
6
  const fs = require('fs');
2
7
  const { get_all_metas, get_entity_meta } = require('../core/meta');
3
8
 
9
+ /**
10
+ * Capitalize first letter of string.
11
+ * @param {string} s - String to capitalize.
12
+ * @returns {string} Capitalized string.
13
+ */
4
14
  const capitalize = (s) => {
5
- if (typeof s !== 'string') return ''
6
- return s.charAt(0).toUpperCase() + s.slice(1)
7
- }
15
+ if (typeof s !== 'string') return '';
16
+ return s.charAt(0).toUpperCase() + s.slice(1);
17
+ };
8
18
 
9
- const gen_i18n = (file_path, keep_hint) => {
10
- let json_file = fs.readFileSync(file_path);
11
- let json = JSON.parse(json_file);
19
+ /**
20
+ * Process entity metadata and add to i18n JSON.
21
+ * @param {Object} json - I18n JSON object.
22
+ * @param {Object} meta - Entity metadata.
23
+ * @param {boolean} keep_hint - Whether to generate hint fields.
24
+ */
25
+ const process_entity_i18n = (json, meta, keep_hint) => {
26
+ // Initialize collection object
27
+ json[meta.collection] = json[meta.collection] || {};
28
+ json[meta.collection]["_label"] = json[meta.collection]["_label"] || capitalize(meta.collection);
12
29
 
13
- const metas = get_all_metas();
14
- for (let i = 0; i < metas.length; i++) {
15
- const meta = get_entity_meta(metas[i]);
16
- json[meta.collection] || (json[meta.collection] = {});
17
- json[meta.collection]["_label"] || (json[meta.collection]["_label"] = capitalize(meta.collection));
18
- const fields = meta.fields.filter(f => f.sys != true);
19
- for (let j = 0; j < fields.length; j++) {
20
- const field = fields[j];
21
- json[meta.collection][field.name] || (json[meta.collection][field.name] = capitalize(field.name));
22
- if (keep_hint) {
23
- json[meta.collection][field.name + "_hint"] || (json[meta.collection][field.name + "_hint"] = "")
24
- }
30
+ // Process non-system fields
31
+ const fields = meta.fields.filter((f) => f.sys !== true);
32
+ fields.forEach((field) => {
33
+ json[meta.collection][field.name] = json[meta.collection][field.name] || capitalize(field.name);
34
+
35
+ if (keep_hint) {
36
+ const hint_key = field.name + "_hint";
37
+ json[meta.collection][hint_key] = json[meta.collection][hint_key] || "";
25
38
  }
26
- }
39
+ });
40
+ };
41
+
42
+ /**
43
+ * Generate i18n JSON file from entity metadata.
44
+ * Reads existing file, merges with entity field names, and writes back.
45
+ * @param {string} file_path - Path to i18n JSON file.
46
+ * @param {boolean} [keep_hint=false] - Whether to generate hint fields for each field.
47
+ */
48
+ const gen_i18n = (file_path, keep_hint = false) => {
49
+ // Read existing JSON file
50
+ const json_file = fs.readFileSync(file_path, 'utf8');
51
+ const json = JSON.parse(json_file);
52
+
53
+ // Process all entity metadata
54
+ const metas = get_all_metas();
55
+ metas.forEach((meta_name) => {
56
+ const meta = get_entity_meta(meta_name);
57
+ process_entity_i18n(json, meta, keep_hint);
58
+ });
59
+
60
+ // Write updated JSON
27
61
  fs.writeFileSync(file_path, JSON.stringify(json, null, 2));
28
- }
62
+ };
29
63
 
30
- module.exports = { gen_i18n }
64
+ module.exports = { gen_i18n };
@@ -1,99 +0,0 @@
1
- const chai = require('chai');
2
- const chai_http = require('chai-http');
3
- const { strictEqual, deepStrictEqual } = require('assert');
4
-
5
- const { init_express_server } = require('../../http/express');
6
- const { get_entity_meta } = require('../../core/meta');
7
- const { Entity } = require('../../db/entity');
8
- const { SUCCESS } = require('../../http/code');
9
-
10
- const server = init_express_server(__dirname + "/../");
11
- chai.use(chai_http);
12
-
13
- describe('user router controller crud testing', () => {
14
- const user_entity = new Entity(get_entity_meta("user"));
15
- const role_entity = new Entity(get_entity_meta("role"));
16
-
17
- beforeEach((done) => {
18
- user_entity.delete({}).then(_ => {
19
- role_entity.delete({}).then(_ => {
20
- done();
21
- });
22
- });
23
- });
24
-
25
- describe('/POST create user', () => {
26
-
27
- it('it should POST a user successfully with all the valid values', async (done) => {
28
- await role_entity.create_entity({ "name": "admin", desc: "admin role" });
29
- await role_entity.create_entity({ "name": "user", desc: "user role" });
30
- const role_count = (await role_entity.find({})).length;
31
- strictEqual(role_count, 2);
32
-
33
- const user = {
34
- name: "hery",
35
- email: "hery@easyserver.com",
36
- role: "admin,user",
37
- age: "10",
38
- status: "true"
39
- }
40
- chai.request(server)
41
- .post('/user/create')
42
- .send(user)
43
- .end(async (err, res) => {
44
- strictEqual(res.status, 200);
45
- strictEqual(res.body.code, SUCCESS);
46
-
47
- const db_user = await user_entity.find_one(user_entity.primary_key_query({ "name": "hery" }));
48
- const db_roles = await role_entity.find({});
49
- strictEqual(db_user.name, "hery");
50
- strictEqual(db_user.age, 10);
51
- deepStrictEqual(db_user.role, db_roles.map(r => r["_id"] + ""));
52
- done();
53
- });
54
- });
55
-
56
- it('it should read the entity success', async (done) => {
57
- await role_entity.create_entity({ "name": "admin", desc: "admin role" });
58
- await role_entity.create_entity({ "name": "user", desc: "user role" });
59
- await user_entity.create_entity({
60
- name: "hery",
61
- email: "hery@easyserver.com",
62
- role: "admin,user",
63
- age: "10",
64
- status: "true"
65
- });
66
-
67
- const db_user = await user_entity.find_one(user_entity.primary_key_query({ "name": "hery" }));
68
-
69
- chai.request(server)
70
- .post('/user/read')
71
- .send({ "_id": db_user._id + "", "attr_names": "name,age" })
72
- .end(async (err, res) => {
73
- strictEqual(res.status, 200);
74
- strictEqual(res.body.err, undefined);
75
- strictEqual(res.body.code, SUCCESS);
76
-
77
- const user = res.body.data;
78
- strictEqual(user.name, "hery");
79
- strictEqual(user.age, 10);
80
- strictEqual(user.email, undefined);
81
- strictEqual(user.status, undefined);
82
-
83
- done();
84
- });
85
- });
86
-
87
- it('it should get entity fields', async (done) => {
88
- chai.request(server)
89
- .get('/user/meta')
90
- .end(async (err, res) => {
91
- strictEqual(res.status, 200);
92
- strictEqual(res.body.code, SUCCESS);
93
- strictEqual(res.body.data.fields.length, 5);
94
-
95
- done();
96
- });
97
- });
98
- });
99
- });
@@ -1,17 +0,0 @@
1
- const { init_router } = require('../../http/router')
2
-
3
- module.exports = init_router({
4
- creatable: true,
5
- readable: true,
6
- updatable: true,
7
- deleteable: true,
8
- collection: "user",
9
- primary_keys: ["name"],
10
- fields: [
11
- { name: "name", required: true },
12
- { name: "email", type: "string" },
13
- { name: "age", type: "uint" },
14
- { name: "role", type: "array", ref: "role", required: true },
15
- { name: "status", type: "boolean", sys: true }
16
- ]
17
- });