@onehat/data 1.17.2 → 1.17.5
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/cypress/e2e/Config.cy.js +1 -1
- package/cypress/e2e/Entity.cy.js +84 -2
- package/cypress/e2e/Repository/Ajax.cy.js +1 -1
- package/cypress/e2e/Repository/Memory.cy.js +1 -1
- package/cypress/e2e/Repository/OneBuild.cy.js +12 -3
- package/cypress/e2e/Repository/Repository.cy.js +229 -4
- package/cypress.config.js +0 -1
- package/package.json +3 -3
- package/src/Entity/Entity.js +69 -16
- package/src/Repository/Ajax.js +1 -15
- package/src/Repository/Memory.js +2 -6
- package/src/Repository/OneBuild.js +79 -2
- package/src/Repository/Repository.js +8 -4
package/cypress/e2e/Config.cy.js
CHANGED
package/cypress/e2e/Entity.cy.js
CHANGED
|
@@ -471,11 +471,11 @@ describe('Entity', function() {
|
|
|
471
471
|
});
|
|
472
472
|
|
|
473
473
|
it('hash', function() {
|
|
474
|
-
expect(this.entity.hash).to.be.eq(
|
|
474
|
+
expect(this.entity.hash).to.be.eq(5365087438356619);
|
|
475
475
|
|
|
476
476
|
// change a property & check again
|
|
477
477
|
this.entity.foo = 3;
|
|
478
|
-
expect(this.entity.hash).to.be.eq(
|
|
478
|
+
expect(this.entity.hash).to.be.eq(358445507972157);
|
|
479
479
|
});
|
|
480
480
|
|
|
481
481
|
});
|
|
@@ -900,4 +900,86 @@ describe('Entity', function() {
|
|
|
900
900
|
});
|
|
901
901
|
});
|
|
902
902
|
|
|
903
|
+
describe('tree', function() {
|
|
904
|
+
|
|
905
|
+
// Needed for all tree tests...
|
|
906
|
+
const
|
|
907
|
+
schema = new Schema({
|
|
908
|
+
name: 'nodes',
|
|
909
|
+
model: {
|
|
910
|
+
idProperty: 'id',
|
|
911
|
+
displayProperty: 'display',
|
|
912
|
+
parentIdProperty: 'parent_id',
|
|
913
|
+
depthProperty: 'depth',
|
|
914
|
+
hasChildrenProperty: 'hasChildren',
|
|
915
|
+
isTree: true,
|
|
916
|
+
isClosureTable: true,
|
|
917
|
+
properties: [
|
|
918
|
+
{ name: 'id', type: 'int' },
|
|
919
|
+
{ name: 'display' },
|
|
920
|
+
{ name: 'parent_id', type: 'int' },
|
|
921
|
+
{ name: 'depth', type: 'int' },
|
|
922
|
+
{ name: 'hasChildren', type: 'bool' },
|
|
923
|
+
],
|
|
924
|
+
},
|
|
925
|
+
}),
|
|
926
|
+
data = {
|
|
927
|
+
id: 2,
|
|
928
|
+
display: 'Child 1',
|
|
929
|
+
parent_id: 1,
|
|
930
|
+
depth: 1,
|
|
931
|
+
hasChildren: true,
|
|
932
|
+
},
|
|
933
|
+
creatEntity = async () => {
|
|
934
|
+
const entity = new Entity(schema, data);
|
|
935
|
+
entity.initialize();
|
|
936
|
+
return entity;
|
|
937
|
+
},
|
|
938
|
+
destoryEntity = (entity) => {
|
|
939
|
+
entity.destroy();
|
|
940
|
+
};
|
|
941
|
+
|
|
942
|
+
it('magic properties', function() {
|
|
943
|
+
(async () => {
|
|
944
|
+
const entity = await creatEntity();
|
|
945
|
+
|
|
946
|
+
expect(entity.parentId).to.be.eq(1);
|
|
947
|
+
expect(entity.depth).to.be.eq(1);
|
|
948
|
+
expect(entity.hasChildren).to.be.true;
|
|
949
|
+
|
|
950
|
+
destoryEntity(entity);
|
|
951
|
+
})();
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
it('parents/children', function() {
|
|
955
|
+
(async () => {
|
|
956
|
+
const entity = await creatEntity();
|
|
957
|
+
|
|
958
|
+
const parent = this.entity;
|
|
959
|
+
entity.parent = parent;
|
|
960
|
+
expect(entity.parent).to.be.eq(parent);
|
|
961
|
+
|
|
962
|
+
const children = [this.entity];
|
|
963
|
+
entity.children = children;
|
|
964
|
+
expect(entity.children).to.be.eq(children);
|
|
965
|
+
|
|
966
|
+
destoryEntity(entity);
|
|
967
|
+
})();
|
|
968
|
+
});
|
|
969
|
+
|
|
970
|
+
it('ensureTree', function() {
|
|
971
|
+
(async () => {
|
|
972
|
+
const entity = await creatEntity();
|
|
973
|
+
|
|
974
|
+
expect(entity.ensureTree()).to.be.true;
|
|
975
|
+
|
|
976
|
+
entity.isTree = false;
|
|
977
|
+
expect(entity.ensureTree()).to.be.false;
|
|
978
|
+
|
|
979
|
+
destoryEntity(entity);
|
|
980
|
+
})();
|
|
981
|
+
});
|
|
982
|
+
|
|
983
|
+
});
|
|
984
|
+
|
|
903
985
|
});
|
|
@@ -91,7 +91,7 @@ describe('OneBuildRepository', function() {
|
|
|
91
91
|
r.setValuelessParam('conditions[field IS NOT NULL]');
|
|
92
92
|
|
|
93
93
|
expect(r._params.conditions.field).to.be.eq(1);
|
|
94
|
-
expect(r._params.conditions
|
|
94
|
+
expect(r._params.conditions.undefined).to.be.eq('field IS NOT NULL');
|
|
95
95
|
});
|
|
96
96
|
|
|
97
97
|
it('clearParams', function() {
|
|
@@ -281,7 +281,7 @@ describe('MemoryRepository', function() {
|
|
|
281
281
|
expect(_.size(this.repository.getRawValues())).to.be.eq(5);
|
|
282
282
|
expect(_.size(this.repository.getOriginalData())).to.be.eq(5);
|
|
283
283
|
expect(_.size(this.repository.getParsedValues())).to.be.eq(5);
|
|
284
|
-
expect(this.repository.getByIx(
|
|
284
|
+
expect(this.repository.getByIx(4).value).to.be.eq('five');
|
|
285
285
|
expect(_.size(this.repository.getNonPersisted())).to.be.eq(0);
|
|
286
286
|
expect(_.size(this.repository.getPhantom())).to.be.eq(0);
|
|
287
287
|
expect(_.size(this.repository.getDirty())).to.be.eq(0);
|
|
@@ -66,12 +66,21 @@ describe('OneBuildRepository', function() {
|
|
|
66
66
|
it('401', function() {
|
|
67
67
|
cy.wrap((async () => {
|
|
68
68
|
|
|
69
|
-
let loggedOut = false
|
|
69
|
+
let loggedOut = false,
|
|
70
|
+
isError = false;
|
|
70
71
|
this.oneHatData.on('logout', function() { // NOTE: We are listening to the global oneHatData object, not just the individual repository
|
|
71
72
|
loggedOut = true;
|
|
72
73
|
});
|
|
73
|
-
|
|
74
|
-
|
|
74
|
+
try {
|
|
75
|
+
await this.repository.load();
|
|
76
|
+
} catch(e) {
|
|
77
|
+
isError = true;
|
|
78
|
+
}
|
|
79
|
+
if (!isError) {
|
|
80
|
+
expect(loggedOut).to.be.true;
|
|
81
|
+
} else {
|
|
82
|
+
throw Error('404 error! Maybe set baseUrl?')
|
|
83
|
+
}
|
|
75
84
|
|
|
76
85
|
})());
|
|
77
86
|
});
|
|
@@ -1050,7 +1050,7 @@ describe('Repository Base', function() {
|
|
|
1050
1050
|
|
|
1051
1051
|
});
|
|
1052
1052
|
|
|
1053
|
-
describe('
|
|
1053
|
+
describe('misc', function() {
|
|
1054
1054
|
it('setOptions', function() {
|
|
1055
1055
|
|
|
1056
1056
|
this.repository.setOptions({
|
|
@@ -1061,11 +1061,236 @@ describe('Repository Base', function() {
|
|
|
1061
1061
|
|
|
1062
1062
|
expect(this.repository.api.baseURL).to.be.eq('test123');
|
|
1063
1063
|
});
|
|
1064
|
+
|
|
1065
|
+
it('toString', function() {
|
|
1066
|
+
const str = this.repository.toString();
|
|
1067
|
+
expect(str).to.be.eq('NullRepository {bar} - foo');
|
|
1068
|
+
});
|
|
1064
1069
|
});
|
|
1065
1070
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1071
|
+
describe('tree', function() {
|
|
1072
|
+
|
|
1073
|
+
// Needed for all tree tests...
|
|
1074
|
+
const
|
|
1075
|
+
schema = new Schema({
|
|
1076
|
+
name: 'nodes',
|
|
1077
|
+
model: {
|
|
1078
|
+
idProperty: 'id',
|
|
1079
|
+
displayProperty: 'display',
|
|
1080
|
+
parentIdProperty: 'parent_id',
|
|
1081
|
+
depthProperty: 'depth',
|
|
1082
|
+
hasChildrenProperty: 'hasChildren',
|
|
1083
|
+
isTree: true,
|
|
1084
|
+
isClosureTable: true,
|
|
1085
|
+
properties: [
|
|
1086
|
+
{ name: 'id', type: 'int', },
|
|
1087
|
+
{ name: 'display', },
|
|
1088
|
+
{ name: 'parent_id', type: 'int', },
|
|
1089
|
+
{ name: 'depth', type: 'int', },
|
|
1090
|
+
{ name: 'hasChildren', type: 'bool', },
|
|
1091
|
+
],
|
|
1092
|
+
},
|
|
1093
|
+
repository: 'memory',
|
|
1094
|
+
}),
|
|
1095
|
+
Repository = RepositoryTypes.memory,
|
|
1096
|
+
data = [
|
|
1097
|
+
{
|
|
1098
|
+
id: 1,
|
|
1099
|
+
display: 'Root',
|
|
1100
|
+
parent_id: null,
|
|
1101
|
+
depth: 0,
|
|
1102
|
+
hasChildren: true,
|
|
1103
|
+
isChildrenLoaded: true,
|
|
1104
|
+
},
|
|
1105
|
+
{
|
|
1106
|
+
id: 2,
|
|
1107
|
+
display: 'Child 1',
|
|
1108
|
+
parent_id: 1,
|
|
1109
|
+
depth: 1,
|
|
1110
|
+
hasChildren: true,
|
|
1111
|
+
isChildrenLoaded: true,
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
id: 3,
|
|
1115
|
+
display: 'Child 2',
|
|
1116
|
+
parent_id: 1,
|
|
1117
|
+
depth: 1,
|
|
1118
|
+
isChildrenLoaded: true,
|
|
1119
|
+
},
|
|
1120
|
+
{
|
|
1121
|
+
id: 4,
|
|
1122
|
+
display: 'Grandchild',
|
|
1123
|
+
parent_id: 2,
|
|
1124
|
+
depth: 2,
|
|
1125
|
+
isChildrenLoaded: true,
|
|
1126
|
+
},
|
|
1127
|
+
],
|
|
1128
|
+
creatRepository = async () => {
|
|
1129
|
+
const repository = new Repository({
|
|
1130
|
+
id: 'tree',
|
|
1131
|
+
schema,
|
|
1132
|
+
isAutoLoad: true,
|
|
1133
|
+
isAutoSave: true,
|
|
1134
|
+
isPaginated: true,
|
|
1135
|
+
data,
|
|
1136
|
+
});
|
|
1137
|
+
await repository.initialize();
|
|
1138
|
+
return repository;
|
|
1139
|
+
},
|
|
1140
|
+
destoryRepository = (repository) => {
|
|
1141
|
+
repository.destroy();
|
|
1142
|
+
};
|
|
1143
|
+
|
|
1144
|
+
it('TreeNode (Entity) tests', function() {
|
|
1145
|
+
(async () => {
|
|
1146
|
+
const repository = await creatRepository();
|
|
1147
|
+
repository.assembleTreeNodes();
|
|
1148
|
+
|
|
1149
|
+
const
|
|
1150
|
+
id1 = repository.getById(1),
|
|
1151
|
+
id2 = repository.getById(2),
|
|
1152
|
+
id3 = repository.getById(3),
|
|
1153
|
+
id4 = repository.getById(4);
|
|
1154
|
+
|
|
1155
|
+
// hasChildren
|
|
1156
|
+
expect(id2.hasChildren).to.be.true;
|
|
1157
|
+
expect(id4.hasChildren).to.be.false;
|
|
1158
|
+
|
|
1159
|
+
// getParent
|
|
1160
|
+
expect(id2.getParent()).to.be.eq(id1);
|
|
1161
|
+
expect(id1.getParent()).to.be.null;
|
|
1162
|
+
|
|
1163
|
+
// getChildren
|
|
1164
|
+
let children = await id2.getChildren();
|
|
1165
|
+
expect(children).to.be.eql([id4]);
|
|
1166
|
+
|
|
1167
|
+
children = await id3.getChildren();
|
|
1168
|
+
expect(children).to.be.empty;
|
|
1169
|
+
|
|
1170
|
+
// hasThisChild
|
|
1171
|
+
let hasThisChild = await id2.hasThisChild(id3);
|
|
1172
|
+
expect(hasThisChild).to.be.false;
|
|
1173
|
+
|
|
1174
|
+
hasThisChild = await id2.hasThisChild(id4);
|
|
1175
|
+
expect(hasThisChild).to.be.true;
|
|
1176
|
+
|
|
1177
|
+
// loadChildren (& reloadChildren)
|
|
1178
|
+
// this needs to be on OneBuild spec
|
|
1179
|
+
|
|
1180
|
+
// getPrevousSibling
|
|
1181
|
+
let sibling = await id2.getPrevousSibling();
|
|
1182
|
+
expect(sibling).to.be.null;
|
|
1183
|
+
|
|
1184
|
+
sibling = await id3.getPrevousSibling();
|
|
1185
|
+
expect(sibling).to.be.eq(id2);
|
|
1186
|
+
|
|
1187
|
+
sibling = await id3.getNextSibling();
|
|
1188
|
+
expect(sibling).to.be.null;
|
|
1189
|
+
|
|
1190
|
+
sibling = await id2.getNextSibling();
|
|
1191
|
+
expect(sibling).to.be.eq(id3);
|
|
1192
|
+
|
|
1193
|
+
// getChildAt
|
|
1194
|
+
let child = await id1.getChildAt(0);
|
|
1195
|
+
expect(child).to.be.eq(id2);
|
|
1196
|
+
|
|
1197
|
+
child = await id1.getChildAt(1);
|
|
1198
|
+
expect(child).to.be.eq(id3);
|
|
1199
|
+
|
|
1200
|
+
child = await id1.getChildAt(2);
|
|
1201
|
+
expect(child).to.be.null;
|
|
1202
|
+
|
|
1203
|
+
// getFirstChild
|
|
1204
|
+
child = await id1.getFirstChild();
|
|
1205
|
+
expect(child).to.be.eq(id2);
|
|
1206
|
+
|
|
1207
|
+
child = await id4.getFirstChild();
|
|
1208
|
+
expect(child).to.be.null;
|
|
1209
|
+
|
|
1210
|
+
// getLastChild
|
|
1211
|
+
child = await id1.getLastChild();
|
|
1212
|
+
expect(child).to.be.eq(id3);
|
|
1213
|
+
|
|
1214
|
+
child = await id4.getLastChild();
|
|
1215
|
+
expect(child).to.be.null;
|
|
1216
|
+
|
|
1217
|
+
// getPath
|
|
1218
|
+
const path = id4.getPath();
|
|
1219
|
+
expect(path).to.be.eq('1/2/4');
|
|
1220
|
+
|
|
1221
|
+
destoryRepository(repository);
|
|
1222
|
+
})();
|
|
1223
|
+
});
|
|
1224
|
+
|
|
1225
|
+
it('getRootNodes', function() {
|
|
1226
|
+
(async () => {
|
|
1227
|
+
const repository = await creatRepository();
|
|
1228
|
+
repository.assembleTreeNodes();
|
|
1229
|
+
|
|
1230
|
+
const
|
|
1231
|
+
id1 = repository.getById(1);
|
|
1232
|
+
|
|
1233
|
+
const rootNodes = repository.getRootNodes();
|
|
1234
|
+
expect(rootNodes).to.be.eql([id1]);
|
|
1235
|
+
|
|
1236
|
+
destoryRepository(repository);
|
|
1237
|
+
})();
|
|
1238
|
+
});
|
|
1239
|
+
|
|
1240
|
+
it('assembleTreeNodes', function() {
|
|
1241
|
+
(async () => {
|
|
1242
|
+
const repository = await creatRepository();
|
|
1243
|
+
|
|
1244
|
+
const
|
|
1245
|
+
id1 = repository.getById(1),
|
|
1246
|
+
id2 = repository.getById(2),
|
|
1247
|
+
id3 = repository.getById(3),
|
|
1248
|
+
id4 = repository.getById(4);
|
|
1249
|
+
|
|
1250
|
+
// Verify no children or parents
|
|
1251
|
+
expect(id2.parent).to.be.null;
|
|
1252
|
+
expect(id2.children).to.be.empty;
|
|
1253
|
+
|
|
1254
|
+
repository.assembleTreeNodes();
|
|
1255
|
+
|
|
1256
|
+
// Now check that they are populated
|
|
1257
|
+
expect(id2.parent).to.be.eq(id1);
|
|
1258
|
+
expect(id2.children).to.be.eql([id4]);
|
|
1259
|
+
|
|
1260
|
+
// Re-assemble them
|
|
1261
|
+
repository.assembleTreeNodes();
|
|
1262
|
+
|
|
1263
|
+
// check them again
|
|
1264
|
+
expect(id2.parent).to.be.eq(id1);
|
|
1265
|
+
expect(id2.children).to.be.eql([id4]);
|
|
1266
|
+
|
|
1267
|
+
destoryRepository(repository);
|
|
1268
|
+
})();
|
|
1269
|
+
});
|
|
1270
|
+
|
|
1271
|
+
it('removeTreeNode', function() {
|
|
1272
|
+
(async () => {
|
|
1273
|
+
const repository = await creatRepository();
|
|
1274
|
+
repository.assembleTreeNodes();
|
|
1275
|
+
|
|
1276
|
+
const
|
|
1277
|
+
id1 = repository.getById(1),
|
|
1278
|
+
id2 = repository.getById(2),
|
|
1279
|
+
id3 = repository.getById(3),
|
|
1280
|
+
id4 = repository.getById(4);
|
|
1281
|
+
|
|
1282
|
+
const before = repository.getEntities();
|
|
1283
|
+
expect(before.length).to.be.eq(4);
|
|
1284
|
+
|
|
1285
|
+
repository.removeTreeNode(id2);
|
|
1286
|
+
|
|
1287
|
+
const after = repository.getEntities();
|
|
1288
|
+
expect(after.length).to.be.eq(2);
|
|
1289
|
+
|
|
1290
|
+
destoryRepository(repository);
|
|
1291
|
+
})();
|
|
1292
|
+
});
|
|
1293
|
+
|
|
1069
1294
|
});
|
|
1070
1295
|
|
|
1071
1296
|
});
|
package/cypress.config.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onehat/data",
|
|
3
|
-
"version": "1.17.
|
|
3
|
+
"version": "1.17.5",
|
|
4
4
|
"description": "JS data modeling package with adapters for many storage mediums.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"accounting-js": "^1.1.1",
|
|
41
41
|
"axios": "^1.4.0",
|
|
42
42
|
"chrono-node": "^2.6.3",
|
|
43
|
-
"fast-xml-parser": "^4.2.
|
|
43
|
+
"fast-xml-parser": "^4.2.4",
|
|
44
44
|
"he": "^1.2.0",
|
|
45
45
|
"js-base64": "^3.7.5",
|
|
46
46
|
"lodash": "^4.17.21",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"@babel/core": "^7.22.1",
|
|
56
56
|
"@babel/node": "^7.22.1",
|
|
57
57
|
"@babel/plugin-transform-class-properties": "^7.22.3",
|
|
58
|
-
"@babel/plugin-transform-runtime": "^7.
|
|
58
|
+
"@babel/plugin-transform-runtime": "^7.22.4",
|
|
59
59
|
"@babel/preset-env": "^7.22.4",
|
|
60
60
|
"@babel/register": "^7.21.0",
|
|
61
61
|
"@babel/runtime": "^7.22.3",
|
package/src/Entity/Entity.js
CHANGED
|
@@ -35,7 +35,7 @@ class Entity extends EventEmitter {
|
|
|
35
35
|
* @param {boolean} originalIsMapped - Has data already been mapped according to schema?
|
|
36
36
|
* @param {boolean} isDelayedSave - Should the repository skip autosave when immediately adding the record?
|
|
37
37
|
*/
|
|
38
|
-
constructor(schema, rawData = {}, repository = null, originalIsMapped = false, isDelayedSave = false, isRemotePhantomMode = false
|
|
38
|
+
constructor(schema, rawData = {}, repository = null, originalIsMapped = false, isDelayedSave = false, isRemotePhantomMode = false) {
|
|
39
39
|
super(...arguments);
|
|
40
40
|
|
|
41
41
|
if (!schema) {
|
|
@@ -118,12 +118,6 @@ class Entity extends EventEmitter {
|
|
|
118
118
|
throw new Error('hasChildrenProperty cannot be empty for a TreeNode');
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
/**
|
|
122
|
-
* @member {boolean} isRoot - Whether this TreeNode is the root TreeNode
|
|
123
|
-
* For trees only
|
|
124
|
-
*/
|
|
125
|
-
this.isRoot = false;
|
|
126
|
-
|
|
127
121
|
/**
|
|
128
122
|
* @member {TreeNode} parent - The parent TreeNode for this TreeNode
|
|
129
123
|
* For trees only
|
|
@@ -1504,7 +1498,7 @@ class Entity extends EventEmitter {
|
|
|
1504
1498
|
throw Error('this.getParentId is no longer valid. TreeNode has been destroyed.');
|
|
1505
1499
|
}
|
|
1506
1500
|
|
|
1507
|
-
return this.
|
|
1501
|
+
return this.getParentIdProperty().getSubmitValue();
|
|
1508
1502
|
}
|
|
1509
1503
|
|
|
1510
1504
|
/**
|
|
@@ -1517,13 +1511,24 @@ class Entity extends EventEmitter {
|
|
|
1517
1511
|
|
|
1518
1512
|
/**
|
|
1519
1513
|
* Getter of hasParent
|
|
1520
|
-
* Returns true if this
|
|
1514
|
+
* Returns true if this node has a parentId
|
|
1521
1515
|
* @return {boolean} hasParent
|
|
1522
1516
|
*/
|
|
1523
1517
|
get hasParent() {
|
|
1524
1518
|
this.ensureTree();
|
|
1525
1519
|
|
|
1526
|
-
return
|
|
1520
|
+
return !!this.parentId;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
/**
|
|
1524
|
+
* Getter of isRoot
|
|
1525
|
+
* Returns true if this node has no parent
|
|
1526
|
+
* @return {boolean} hasParent
|
|
1527
|
+
*/
|
|
1528
|
+
get isRoot() {
|
|
1529
|
+
this.ensureTree();
|
|
1530
|
+
|
|
1531
|
+
return !this.hasParent;
|
|
1527
1532
|
}
|
|
1528
1533
|
|
|
1529
1534
|
/**
|
|
@@ -1626,13 +1631,26 @@ class Entity extends EventEmitter {
|
|
|
1626
1631
|
if (this.isDestroyed) {
|
|
1627
1632
|
throw Error('this.getChildren is no longer valid. TreeNode has been destroyed.');
|
|
1628
1633
|
}
|
|
1629
|
-
|
|
1630
1634
|
if (!this.isChildrenLoaded) {
|
|
1631
1635
|
await this.loadChildren();
|
|
1632
1636
|
}
|
|
1633
1637
|
return this.children;
|
|
1634
1638
|
}
|
|
1635
1639
|
|
|
1640
|
+
/**
|
|
1641
|
+
* Whether the supplied TreeNode is a child of this TreeNode.
|
|
1642
|
+
* @return {boolean} hasThisChild
|
|
1643
|
+
*/
|
|
1644
|
+
hasThisChild = async (treeNode) => {
|
|
1645
|
+
this.ensureTree();
|
|
1646
|
+
if (this.isDestroyed) {
|
|
1647
|
+
throw Error('this.hasThisChild is no longer valid. TreeNode has been destroyed.');
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
const children = await this.getChildren();
|
|
1651
|
+
return _.includes(children, treeNode);
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1636
1654
|
/**
|
|
1637
1655
|
* Loads the children of this TreeNode from repository.
|
|
1638
1656
|
*/
|
|
@@ -1669,9 +1687,9 @@ class Entity extends EventEmitter {
|
|
|
1669
1687
|
const
|
|
1670
1688
|
parent = this.getParent(),
|
|
1671
1689
|
siblings = await parent.getChildren();
|
|
1672
|
-
let previous;
|
|
1690
|
+
let previous = null;
|
|
1673
1691
|
_.each(siblings, (treeNode) => {
|
|
1674
|
-
if (treeNode === this) {
|
|
1692
|
+
if (treeNode.id === this.id) {
|
|
1675
1693
|
return false;
|
|
1676
1694
|
}
|
|
1677
1695
|
previous = treeNode;
|
|
@@ -1699,7 +1717,7 @@ class Entity extends EventEmitter {
|
|
|
1699
1717
|
next = treeNode;
|
|
1700
1718
|
return false;
|
|
1701
1719
|
}
|
|
1702
|
-
if (treeNode === this) {
|
|
1720
|
+
if (treeNode.id === this.id) {
|
|
1703
1721
|
returnNext = true;
|
|
1704
1722
|
}
|
|
1705
1723
|
})
|
|
@@ -1716,6 +1734,9 @@ class Entity extends EventEmitter {
|
|
|
1716
1734
|
throw Error('this.getChildAt is no longer valid. TreeNode has been destroyed.');
|
|
1717
1735
|
}
|
|
1718
1736
|
|
|
1737
|
+
if (!this.children[ix]) {
|
|
1738
|
+
return null;
|
|
1739
|
+
}
|
|
1719
1740
|
return this.children[ix];
|
|
1720
1741
|
}
|
|
1721
1742
|
|
|
@@ -1729,6 +1750,9 @@ class Entity extends EventEmitter {
|
|
|
1729
1750
|
throw Error('this.getFirstChild is no longer valid. TreeNode has been destroyed.');
|
|
1730
1751
|
}
|
|
1731
1752
|
|
|
1753
|
+
if (!this.children[0]) {
|
|
1754
|
+
return null;
|
|
1755
|
+
}
|
|
1732
1756
|
return this.children[0];
|
|
1733
1757
|
}
|
|
1734
1758
|
|
|
@@ -1742,7 +1766,34 @@ class Entity extends EventEmitter {
|
|
|
1742
1766
|
throw Error('this.getLastChild is no longer valid. TreeNode has been destroyed.');
|
|
1743
1767
|
}
|
|
1744
1768
|
|
|
1745
|
-
|
|
1769
|
+
const child = this.children.slice(-1)[0];
|
|
1770
|
+
if (!child) {
|
|
1771
|
+
return null;
|
|
1772
|
+
}
|
|
1773
|
+
return child;
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
/**
|
|
1777
|
+
* Gets the path to this node.
|
|
1778
|
+
* @return {string} path
|
|
1779
|
+
*/
|
|
1780
|
+
getPath = () => {
|
|
1781
|
+
this.ensureTree();
|
|
1782
|
+
if (this.isDestroyed) {
|
|
1783
|
+
throw Error('this.getPath is no longer valid. TreeNode has been destroyed.');
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
const parentIds = [];
|
|
1787
|
+
let parent = this;
|
|
1788
|
+
while(parent.hasParent) { // stops at root
|
|
1789
|
+
parentIds.push(parent.id);
|
|
1790
|
+
parent = parent.parent;
|
|
1791
|
+
}
|
|
1792
|
+
if (parent.id !== this.id) {
|
|
1793
|
+
parentIds.push(parent.id); // add root id
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
return parentIds.reverse().join('/');
|
|
1746
1797
|
}
|
|
1747
1798
|
|
|
1748
1799
|
/**
|
|
@@ -1751,8 +1802,10 @@ class Entity extends EventEmitter {
|
|
|
1751
1802
|
*/
|
|
1752
1803
|
ensureTree = async () => {
|
|
1753
1804
|
if (!this.isTree) {
|
|
1754
|
-
this.throwError('This
|
|
1805
|
+
this.throwError('This Entity is not a tree!');
|
|
1806
|
+
return false;
|
|
1755
1807
|
}
|
|
1808
|
+
return true;
|
|
1756
1809
|
}
|
|
1757
1810
|
|
|
1758
1811
|
|
package/src/Repository/Ajax.js
CHANGED
|
@@ -559,10 +559,6 @@ class AjaxRepository extends Repository {
|
|
|
559
559
|
url = this.api.add,
|
|
560
560
|
data = entity.getSubmitValues();
|
|
561
561
|
|
|
562
|
-
if (entity.isRemotePhantomMode) {
|
|
563
|
-
data.isRemotePhantom = true;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
562
|
return this._send(method, url, data)
|
|
567
563
|
.then(result => {
|
|
568
564
|
if (this.debugMode) {
|
|
@@ -610,9 +606,6 @@ class AjaxRepository extends Repository {
|
|
|
610
606
|
data = {
|
|
611
607
|
entities: _.map(entities, entity => {
|
|
612
608
|
const values = entity.submitValues;
|
|
613
|
-
if (entity.isRemotePhantomMode) {
|
|
614
|
-
values.isRemotePhantom = true;
|
|
615
|
-
}
|
|
616
609
|
entity.isSaving = true;
|
|
617
610
|
return values;
|
|
618
611
|
}),
|
|
@@ -672,10 +665,6 @@ class AjaxRepository extends Repository {
|
|
|
672
665
|
url = this.api.edit,
|
|
673
666
|
data = entity.getSubmitValues();
|
|
674
667
|
|
|
675
|
-
if (entity.isRemotePhantomMode) {
|
|
676
|
-
data.isRemotePhantom = false;
|
|
677
|
-
}
|
|
678
|
-
|
|
679
668
|
return this._send(method, url, data)
|
|
680
669
|
.then(result => {
|
|
681
670
|
if (this.debugMode) {
|
|
@@ -723,9 +712,6 @@ class AjaxRepository extends Repository {
|
|
|
723
712
|
data = {
|
|
724
713
|
entities: _.map(entities, entity => {
|
|
725
714
|
const values = entity.submitValues;
|
|
726
|
-
if (entity.isRemotePhantomMode) {
|
|
727
|
-
values.isRemotePhantom = false;
|
|
728
|
-
}
|
|
729
715
|
entity.isSaving = true;
|
|
730
716
|
return values;
|
|
731
717
|
}),
|
|
@@ -971,7 +957,7 @@ class AjaxRepository extends Repository {
|
|
|
971
957
|
if (!promises.length) {
|
|
972
958
|
return;
|
|
973
959
|
}
|
|
974
|
-
return
|
|
960
|
+
return Promise.all(promises)
|
|
975
961
|
.then(this.axios.spread((...batchOperationResults) => {
|
|
976
962
|
// All requests are now complete
|
|
977
963
|
|
package/src/Repository/Memory.js
CHANGED
|
@@ -511,13 +511,9 @@ class MemoryRepository extends Repository {
|
|
|
511
511
|
|
|
512
512
|
super.removeEntity(entity);
|
|
513
513
|
|
|
514
|
-
if (this.hasSorters) {
|
|
515
|
-
this._applySorters();
|
|
516
|
-
}
|
|
517
|
-
if (this.hasFilters) {
|
|
518
|
-
this._applyFilters();
|
|
519
|
-
}
|
|
520
514
|
delete this._keyedEntities[id];
|
|
515
|
+
|
|
516
|
+
this._recalculate();
|
|
521
517
|
}
|
|
522
518
|
|
|
523
519
|
|
|
@@ -414,12 +414,16 @@ class OneBuildRepository extends AjaxRepository {
|
|
|
414
414
|
/**
|
|
415
415
|
* Gets the root nodes of this tree.
|
|
416
416
|
*/
|
|
417
|
-
getRootNodes = async (getChildren = false, depth) => {
|
|
417
|
+
getRootNodes = async (getChildren = false, depth, getChildParams) => {
|
|
418
418
|
this.ensureTree();
|
|
419
419
|
if (this.isDestroyed) {
|
|
420
420
|
this.throwError('this.setRootNode is no longer valid. Repository has been destroyed.');
|
|
421
421
|
return;
|
|
422
422
|
}
|
|
423
|
+
if (!this.isOnline) {
|
|
424
|
+
this.throwError('Offline');
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
423
427
|
|
|
424
428
|
// Clear all entities, if any exist
|
|
425
429
|
_.each(this.entities, (entity) => {
|
|
@@ -427,11 +431,84 @@ class OneBuildRepository extends AjaxRepository {
|
|
|
427
431
|
});
|
|
428
432
|
this.entities = [];
|
|
429
433
|
|
|
430
|
-
|
|
434
|
+
|
|
435
|
+
const data = {
|
|
436
|
+
url: this.name + '/getRootNodes',
|
|
437
|
+
data: qs.stringify({
|
|
438
|
+
getChildren,
|
|
439
|
+
depth,
|
|
440
|
+
conditions: getChildParams ? getChildParams() : null
|
|
441
|
+
}),
|
|
442
|
+
method: 'POST',
|
|
443
|
+
baseURL: this.api.baseURL,
|
|
444
|
+
};
|
|
431
445
|
|
|
446
|
+
if (this.debugMode) {
|
|
447
|
+
console.log('getRootNodes', data);
|
|
448
|
+
}
|
|
432
449
|
|
|
450
|
+
return this.axios(data)
|
|
451
|
+
.then((result) => {
|
|
452
|
+
if (this.debugMode) {
|
|
453
|
+
console.log('getRootNodes response', result);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const response = result.data;
|
|
457
|
+
if (!response.success) {
|
|
458
|
+
this.throwError(response.data);
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// TODO: Load up the repository with these root nodes
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
});
|
|
433
467
|
}
|
|
434
468
|
|
|
469
|
+
/**
|
|
470
|
+
* Searches all nodes for the supplied text.
|
|
471
|
+
* This basically takes the search query and returns whatever the server sends
|
|
472
|
+
*/
|
|
473
|
+
searchTree = async (q) => {
|
|
474
|
+
this.ensureTree();
|
|
475
|
+
if (this.isDestroyed) {
|
|
476
|
+
this.throwError('this.searchTree is no longer valid. Repository has been destroyed.');
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (!this.isOnline) {
|
|
480
|
+
this.throwError('Offline');
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
const data = {
|
|
485
|
+
url: this.name + '/searchTree',
|
|
486
|
+
data: qs.stringify({
|
|
487
|
+
q,
|
|
488
|
+
}),
|
|
489
|
+
method: 'POST',
|
|
490
|
+
baseURL: this.api.baseURL,
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
if (this.debugMode) {
|
|
494
|
+
console.log('searchTree', data);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
return this.axios(data)
|
|
498
|
+
.then((result) => {
|
|
499
|
+
if (this.debugMode) {
|
|
500
|
+
console.log('searchTree response', result);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const response = result.data;
|
|
504
|
+
if (!response.success) {
|
|
505
|
+
this.throwError(response.data);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
return response.data;
|
|
510
|
+
});
|
|
511
|
+
}
|
|
435
512
|
/**
|
|
436
513
|
* Loads the children of the supplied treeNode
|
|
437
514
|
*/
|
|
@@ -995,7 +995,7 @@ export default class Repository extends EventEmitter {
|
|
|
995
995
|
entity = Repository._createEntity(this.schema, data, this, isPersisted, originalIsMapped, isDelayedSave, this.isRemotePhantomMode);
|
|
996
996
|
}
|
|
997
997
|
this._relayEntityEvents(entity);
|
|
998
|
-
this.entities.unshift(entity);
|
|
998
|
+
this.entities.unshift(entity); // Add to *beginning* of entities array, so the phantom record will appear at the beginning of the current page
|
|
999
999
|
|
|
1000
1000
|
// Create id if needed
|
|
1001
1001
|
if (!this.isRemotePhantomMode && entity.isPhantom) {
|
|
@@ -1056,11 +1056,13 @@ export default class Repository extends EventEmitter {
|
|
|
1056
1056
|
addMultiple = async (allData, isPersisted = false, originalIsMapped = false) => {
|
|
1057
1057
|
|
|
1058
1058
|
let entities = [],
|
|
1059
|
-
i
|
|
1059
|
+
i,
|
|
1060
|
+
data,
|
|
1061
|
+
entity;
|
|
1060
1062
|
|
|
1061
1063
|
for (i = 0; i < allData.length; i++) {
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
+
data = allData[i];
|
|
1065
|
+
entity = await this.add(data, isPersisted, originalIsMapped);
|
|
1064
1066
|
entities.push(entity);
|
|
1065
1067
|
};
|
|
1066
1068
|
|
|
@@ -2013,7 +2015,9 @@ export default class Repository extends EventEmitter {
|
|
|
2013
2015
|
ensureTree = async () => {
|
|
2014
2016
|
if (!this.isTree) {
|
|
2015
2017
|
this.throwError('This Repository is not a tree!');
|
|
2018
|
+
return false;
|
|
2016
2019
|
}
|
|
2020
|
+
return true;
|
|
2017
2021
|
}
|
|
2018
2022
|
|
|
2019
2023
|
|