@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.
@@ -155,7 +155,7 @@ describe('Config options', function() {
155
155
 
156
156
  });
157
157
 
158
- it.only('Replace this.method with config.method', function() {
158
+ it('Replace this.method with config.method', function() {
159
159
 
160
160
  class Base {
161
161
  constructor(config = {}) {
@@ -471,11 +471,11 @@ describe('Entity', function() {
471
471
  });
472
472
 
473
473
  it('hash', function() {
474
- expect(this.entity.hash).to.be.eq(4635951664292355);
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(1510366977941323);
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[0]).to.be.eq('field IS NOT NULL');
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(2).value).to.be.eq('five');
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
- await this.repository.load();
74
- expect(loggedOut).to.be.true;
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('options', function() {
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
- it('toString', function() {
1067
- const str = this.repository.toString();
1068
- expect(str).to.be.eq('NullRepository {bar} - foo');
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
@@ -1,6 +1,5 @@
1
1
  import { defineConfig } from "cypress";
2
2
  import webpackPreprocessor from "@cypress/webpack-preprocessor";
3
- import Webpack from "webpack";
4
3
 
5
4
  export default defineConfig({
6
5
  e2e: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/data",
3
- "version": "1.17.2",
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.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.19.6",
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",
@@ -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, isRoot = 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.geParentIdProperty().getSubmitValue();
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 is not a root node
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 !this.isRoot;
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
- return this.children.slice(-1)[0]
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 Repository is not a tree!');
1805
+ this.throwError('This Entity is not a tree!');
1806
+ return false;
1755
1807
  }
1808
+ return true;
1756
1809
  }
1757
1810
 
1758
1811
 
@@ -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 this.axios.all(promises)
960
+ return Promise.all(promises)
975
961
  .then(this.axios.spread((...batchOperationResults) => {
976
962
  // All requests are now complete
977
963
 
@@ -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
- // TODO: Load root nodes (and possibly their children)
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
- const data = allData[i],
1063
- entity = await this.add(data, isPersisted, originalIsMapped);
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