@onehat/data 1.17.0 → 1.17.3

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 (37) hide show
  1. package/cypress/{integration/Config.spec.js → e2e/Config.cy.js} +1 -1
  2. package/cypress/{integration/Entity.spec.js → e2e/Entity.cy.js} +84 -2
  3. package/cypress/{integration/Repository/Ajax.spec.js → e2e/Repository/Ajax.cy.js} +1 -1
  4. package/cypress/{integration/Repository/Memory.spec.js → e2e/Repository/Memory.cy.js} +1 -1
  5. package/cypress/{integration/Repository/OneBuild.spec.js → e2e/Repository/OneBuild.cy.js} +12 -3
  6. package/cypress/{integration/Repository/Repository.spec.js → e2e/Repository/Repository.cy.js} +225 -4
  7. package/cypress/plugins/index.js +2 -32
  8. package/cypress.config.js +42 -0
  9. package/package.json +22 -22
  10. package/src/Entity/Entity.js +357 -3
  11. package/src/Repository/Ajax.js +13 -3
  12. package/src/Repository/Memory.js +2 -6
  13. package/src/Repository/OneBuild.js +80 -0
  14. package/src/Repository/Repository.js +126 -34
  15. package/src/Schema/Schema.js +33 -0
  16. package/cypress/cypress.json +0 -177
  17. package/cypress.json +0 -1
  18. package/src/Entity/TreeNode.js +0 -190
  19. /package/cypress/{integration/Async.spec.js → e2e/Async.cy.js} +0 -0
  20. /package/cypress/{integration/OneHatData.spec.js → e2e/OneHatData.cy.js} +0 -0
  21. /package/cypress/{integration/Property/Base64.spec.js → e2e/Property/Base64.cy.js} +0 -0
  22. /package/cypress/{integration/Property/Boolean.spec.js → e2e/Property/Boolean.cy.js} +0 -0
  23. /package/cypress/{integration/Property/Currency.spec.js → e2e/Property/Currency.cy.js} +0 -0
  24. /package/cypress/{integration/Property/Date.spec.js → e2e/Property/Date.cy.js} +0 -0
  25. /package/cypress/{integration/Property/DateTime.spec.js → e2e/Property/DateTime.cy.js} +0 -0
  26. /package/cypress/{integration/Property/Float.spec.js → e2e/Property/Float.cy.js} +0 -0
  27. /package/cypress/{integration/Property/Integer.spec.js → e2e/Property/Integer.cy.js} +0 -0
  28. /package/cypress/{integration/Property/Json.spec.js → e2e/Property/Json.cy.js} +0 -0
  29. /package/cypress/{integration/Property/Percent.spec.js → e2e/Property/Percent.cy.js} +0 -0
  30. /package/cypress/{integration/Property/PercentInt.spec.js → e2e/Property/PercentInt.cy.js} +0 -0
  31. /package/cypress/{integration/Property/Property.spec.js → e2e/Property/Property.cy.js} +0 -0
  32. /package/cypress/{integration/Property/String.spec.js → e2e/Property/String.cy.js} +0 -0
  33. /package/cypress/{integration/Property/Time.spec.js → e2e/Property/Time.cy.js} +0 -0
  34. /package/cypress/{integration/Property/Uuid.spec.js → e2e/Property/Uuid.cy.js} +0 -0
  35. /package/cypress/{integration/Repository/LocalFromRemote.spec.js → e2e/Repository/LocalFromRemote.cy.js} +0 -0
  36. /package/cypress/{integration/Schema.spec.js → e2e/Schema.cy.js} +0 -0
  37. /package/cypress/support/{index.js → e2e.js} +0 -0
@@ -108,7 +108,7 @@ export default class Repository extends EventEmitter {
108
108
  */
109
109
  pageSize: 10,
110
110
 
111
- sorters: (schema && schema.model && schema.model.sorters) ? schema.model.sorters : [],
111
+ sorters: schema.model.sorters || [],
112
112
 
113
113
  /**
114
114
  * @member {string} batchOrder - Comma-separated ordering of add, edit, and delete batch operations
@@ -189,22 +189,28 @@ export default class Repository extends EventEmitter {
189
189
  this.total = 0;
190
190
 
191
191
  /**
192
- * @member {Boolean} isFiltered - State: whether or not any filters are currently applied to entities
192
+ * @member {boolean} isFiltered - State: whether or not any filters are currently applied to entities
193
193
  */
194
194
  this.isFiltered = false;
195
195
 
196
196
  /**
197
- * @member {Boolean} isInitialized - State: whether or not this repository has been completely initialized
197
+ * @member {boolean} isInitialized - State: whether or not this repository has been completely initialized
198
198
  */
199
199
  this.isInitialized = false;
200
200
 
201
201
  /**
202
- * @member {Boolean} isLoaded - State: whether or not entities have been loaded at least once
202
+ * @member {boolean} isTree - Whether this Repository contains TreeNodes
203
+ * @readonly
204
+ */
205
+ this.isTree = schema.model.isTree || false;
206
+
207
+ /**
208
+ * @member {boolean} isLoaded - State: whether or not entities have been loaded at least once
203
209
  */
204
210
  this.isLoaded = false;
205
211
 
206
212
  /**
207
- * @member {Boolean} isLoading - State: whether or not entities are currently being loaded
213
+ * @member {boolean} isLoading - State: whether or not entities are currently being loaded
208
214
  */
209
215
  this.isLoading = false;
210
216
 
@@ -214,12 +220,12 @@ export default class Repository extends EventEmitter {
214
220
  this.lastLoaded = null;
215
221
 
216
222
  /**
217
- * @member {Boolean} isSaving - State: whether or not entities are currently being saved
223
+ * @member {boolean} isSaving - State: whether or not entities are currently being saved
218
224
  */
219
225
  this.isSaving = false;
220
226
 
221
227
  /**
222
- * @member {Boolean} isSorted - State: whether or not any sorting is currently applied to entities
228
+ * @member {boolean} isSorted - State: whether or not any sorting is currently applied to entities
223
229
  */
224
230
  this.isSorted = false;
225
231
 
@@ -412,7 +418,7 @@ export default class Repository extends EventEmitter {
412
418
  // /____/\____/_/ \__/
413
419
 
414
420
  /**
415
- * @member {Boolean} hasSorters - Whether or not any sorters are applied
421
+ * @member {boolean} hasSorters - Whether or not any sorters are applied
416
422
  */
417
423
  get hasSorters() {
418
424
  if (this.isDestroyed) {
@@ -501,22 +507,20 @@ export default class Repository extends EventEmitter {
501
507
  return;
502
508
  }
503
509
  let sorters = [];
504
- if (this.schema?.model) {
505
- if (_.size(this.schema.model.sorters) > 0) {
506
- sorters = this.schema.model.sorters
507
- } else if (!_.isNil(this.schema.model.sortProperty)) {
508
- sorters = [{
509
- name: this.schema.model.sortProperty,
510
- direction: 'ASC',
511
- fn: 'default',
512
- }];
513
- } else if (!_.isNil(this.schema.model.displayProperty)) {
514
- sorters = [{
515
- name: this.schema.model.displayProperty,
516
- direction: 'ASC',
517
- fn: 'default',
518
- }];
519
- }
510
+ if (_.size(this.schema.model.sorters) > 0) {
511
+ sorters = this.schema.model.sorters
512
+ } else if (!_.isNil(this.schema.model.sortProperty)) {
513
+ sorters = [{
514
+ name: this.schema.model.sortProperty,
515
+ direction: 'ASC',
516
+ fn: 'default',
517
+ }];
518
+ } else if (!_.isNil(this.schema.model.displayProperty)) {
519
+ sorters = [{
520
+ name: this.schema.model.displayProperty,
521
+ direction: 'ASC',
522
+ fn: 'default',
523
+ }];
520
524
  }
521
525
  return sorters;
522
526
  }
@@ -576,7 +580,7 @@ export default class Repository extends EventEmitter {
576
580
  // /_/ /_/_/\__/\___/_/
577
581
 
578
582
  /**
579
- * @member {Boolean} hasFilters - Whether or not any filters are applied
583
+ * @member {boolean} hasFilters - Whether or not any filters are applied
580
584
  */
581
585
  get hasFilters() {
582
586
  if (this.isDestroyed) {
@@ -991,7 +995,7 @@ export default class Repository extends EventEmitter {
991
995
  entity = Repository._createEntity(this.schema, data, this, isPersisted, originalIsMapped, isDelayedSave, this.isRemotePhantomMode);
992
996
  }
993
997
  this._relayEntityEvents(entity);
994
- 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
995
999
 
996
1000
  // Create id if needed
997
1001
  if (!this.isRemotePhantomMode && entity.isPhantom) {
@@ -1052,11 +1056,13 @@ export default class Repository extends EventEmitter {
1052
1056
  addMultiple = async (allData, isPersisted = false, originalIsMapped = false) => {
1053
1057
 
1054
1058
  let entities = [],
1055
- i;
1059
+ i,
1060
+ data,
1061
+ entity;
1056
1062
 
1057
1063
  for (i = 0; i < allData.length; i++) {
1058
- const data = allData[i],
1059
- entity = await this.add(data, isPersisted, originalIsMapped);
1064
+ data = allData[i];
1065
+ entity = await this.add(data, isPersisted, originalIsMapped);
1060
1066
  entities.push(entity);
1061
1067
  };
1062
1068
 
@@ -1459,10 +1465,10 @@ export default class Repository extends EventEmitter {
1459
1465
  }
1460
1466
 
1461
1467
  const schema = this.getSchema();
1462
- if (!schema.model.associations.hasOne.includes(repositoryName) &&
1463
- !schema.model.associations.hasMany.includes(repositoryName) &&
1464
- !schema.model.associations.belongsTo.includes(repositoryName) &&
1465
- !schema.model.associations.belongsToMany.includes(repositoryName)
1468
+ if (!schema.model.associations?.hasOne.includes(repositoryName) &&
1469
+ !schema.model.associations?.hasMany.includes(repositoryName) &&
1470
+ !schema.model.associations?.belongsTo.includes(repositoryName) &&
1471
+ !schema.model.associations?.belongsToMany.includes(repositoryName)
1466
1472
  ) {
1467
1473
  this.throwError(repositoryName + ' is not associated with this schema');
1468
1474
  return;
@@ -1821,7 +1827,7 @@ export default class Repository extends EventEmitter {
1821
1827
  * Mainly used for phantom Entities
1822
1828
  * Helper for delete()
1823
1829
  */
1824
- removeEntity(entity) { // standard function notation so it can be called by child class
1830
+ removeEntity(entity) { // standard function notation so it can be called by child class via super.removeEntity
1825
1831
  this.entities = _.filter(this.entities, e => e !== entity);
1826
1832
  entity.destroy();
1827
1833
  }
@@ -1931,6 +1937,92 @@ export default class Repository extends EventEmitter {
1931
1937
  }
1932
1938
 
1933
1939
 
1940
+ // ______
1941
+ // /_ __/_______ ___ _____
1942
+ // / / / ___/ _ \/ _ \/ ___/
1943
+ // / / / / / __/ __(__ )
1944
+ // /_/ /_/ \___/\___/____/
1945
+
1946
+
1947
+ /**
1948
+ * Gets the root TreeNodes
1949
+ */
1950
+ getRootNodes = () => {
1951
+ this.ensureTree();
1952
+ if (this.isDestroyed) {
1953
+ this.throwError('this.getRootNodes is no longer valid. Repository has been destroyed.');
1954
+ return;
1955
+ }
1956
+
1957
+ // Look through all entities and pull out the root nodes.
1958
+ // Subclasses of Repository will override this method to get root nodes from server
1959
+ const entities = _.filter(this.getEntities(), (entity) => {
1960
+ return entity.isRoot;
1961
+ })
1962
+ return entities;
1963
+ }
1964
+
1965
+ /**
1966
+ * Populates the TreeNodes with .parent and .children references
1967
+ */
1968
+ assembleTreeNodes = () => {
1969
+ this.ensureTree();
1970
+ if (this.isDestroyed) {
1971
+ this.throwError('this.assembleTreeNodes is no longer valid. Repository has been destroyed.');
1972
+ return;
1973
+ }
1974
+
1975
+ const treeNodes = this.getEntities();
1976
+
1977
+ // Reset all parent/child relationships
1978
+ _.each(treeNodes, (treeNode) => {
1979
+ treeNode.parent = null;
1980
+ treeNode.children = [];
1981
+ });
1982
+
1983
+ // Rebuild all parent/child relationships
1984
+ _.each(treeNodes, (treeNode) => {
1985
+ const parent = this.getById(treeNode.parentId);
1986
+ if (parent) {
1987
+ treeNode.parent = parent;
1988
+ parent.children.push(treeNode);
1989
+ }
1990
+ });
1991
+ }
1992
+
1993
+ /**
1994
+ * Removes the treeNode and all of its children from repository
1995
+ * without deleting anything on the server
1996
+ */
1997
+ removeTreeNode = (treeNode) => {
1998
+ if (!_.isEmpty(treeNode.children)) {
1999
+ const children = treeNode.children;
2000
+ treeNode.parent = null;
2001
+ treeNode.children = [];
2002
+
2003
+ _.each(children, (child) => {
2004
+ this.removeTreeNode(child);
2005
+ });
2006
+ }
2007
+
2008
+ this.removeEntity(treeNode);
2009
+ }
2010
+
2011
+ /**
2012
+ * Helper to make sure this Repository is a tree
2013
+ * @private
2014
+ */
2015
+ ensureTree = async () => {
2016
+ if (!this.isTree) {
2017
+ this.throwError('This Repository is not a tree!');
2018
+ return false;
2019
+ }
2020
+ return true;
2021
+ }
2022
+
2023
+
2024
+
2025
+
1934
2026
 
1935
2027
 
1936
2028
  // ____ __ _
@@ -64,6 +64,39 @@ export default class Schema extends EventEmitter {
64
64
  */
65
65
  sortProperty: null,
66
66
 
67
+ /**
68
+ * @member {string} parentIdProperty - name of parent_id Property (e.g. 'categories__parent_id' for Adjacency Lists, and parent_id for Closure Tables)
69
+ * For trees only
70
+ */
71
+ parentIdProperty: null,
72
+
73
+ /**
74
+ * @member {string} depthIdProperty - name of depth Property (e.g. 'categories__depth' for Adjacency Lists, and depth for Closure Tables)
75
+ * For trees only
76
+ */
77
+ depthProperty: null,
78
+
79
+ /**
80
+ * @member {string} hasChildrenProperty - name of hasChildren Property (e.g. 'categories__has_children' for Adjacency Lists, and has_children for Closure Tables)
81
+ * For trees only
82
+ */
83
+ hasChildrenProperty: null,
84
+
85
+ /**
86
+ * @member {boolean} isTree - Whether this model has hierarchical tree data
87
+ */
88
+ isTree: false,
89
+
90
+ /**
91
+ * @member {boolean} isAdjacencyList - Whether this tree is an Adjacency List
92
+ */
93
+ isAdjacencyList: false,
94
+
95
+ /**
96
+ * @member {boolean} isClosureTable - Whether this tree is a Closure Table
97
+ */
98
+ isClosureTable: false,
99
+
67
100
  /**
68
101
  * @member {array} properties - Array of Property definition objects
69
102
  */
@@ -1,177 +0,0 @@
1
- {
2
- "title": "JSON schema for https://cypress.io test runner cypress.json file. Details at https://on.cypress.io/configuration",
3
- "$schema": "http://json-schema.org/draft-04/schema#",
4
- "type": "object",
5
- "properties": {
6
- "baseUrl" : {
7
- "type": "string",
8
- "description": "Url used as prefix for cy.visit() or cy.request() command’s url. Example http://localhost:3030 or https://test.my-domain.com"
9
- },
10
- "env": {
11
- "type": "object",
12
- "description": "Any values to be set as environment variables",
13
- "body": {}
14
- },
15
- "ignoreTestFiles": {
16
- "type": ["string", "array"],
17
- "items": {
18
- "type": "string"
19
- },
20
- "description": "A String or Array of glob patterns used to ignore test files that would otherwise be shown in your list of tests. Cypress uses minimatch with the options: {dot: true, matchBase: true}. We suggest using http://globtester.com to test what files would match."
21
- },
22
- "numTestsKeptInMemory": {
23
- "type": "number",
24
- "default": 50,
25
- "description": "The number of tests for which snapshots and command data are kept in memory. Reduce this number if you are experiencing high memory consumption in your browser during a test run."
26
- },
27
- "port": {
28
- "type": "number",
29
- "default": null,
30
- "description": "Port used to host Cypress. Normally this is a randomly generated port"
31
- },
32
- "reporter": {
33
- "type": "string",
34
- "default": "spec",
35
- "description": "The reporter used when running headlessly or in CI. See https://on.cypress.io/reporters"
36
- },
37
- "reporterOptions": {
38
- "type": "object",
39
- "default": null,
40
- "description": "The reporter options used. Supported options depend on the reporter. See https://on.cypress.io/reporters#Reporter-Options"
41
- },
42
- "watchForFileChanges": {
43
- "type": "boolean",
44
- "default": true,
45
- "description": "Whether Cypress will watch and restart tests on test file changes"
46
- },
47
- "defaultCommandTimeout": {
48
- "type": "number",
49
- "default": 4000,
50
- "description": "Time, in milliseconds, to wait until most DOM based commands are considered timed out"
51
- },
52
- "execTimeout": {
53
- "type": "number",
54
- "default": 60000,
55
- "description": "Time, in milliseconds, to wait for a system command to finish executing during a cy.exec() command"
56
- },
57
- "pageLoadTimeout": {
58
- "type": "number",
59
- "default": 60000,
60
- "description": "Time, in milliseconds, to wait for page transition events or cy.visit(), cy.go(), cy.reload() commands to fire their page load events"
61
- },
62
- "requestTimeout": {
63
- "type": "number",
64
- "default": 5000,
65
- "description": "Time, in milliseconds, to wait for an XHR request to go out in a cy.wait() command"
66
- },
67
- "responseTimeout": {
68
- "type": "number",
69
- "default": 30000,
70
- "description": "Time, in milliseconds, to wait until a response in a cy.request(), cy.wait(), cy.fixture(), cy.getCookie(), cy.getCookies(), cy.setCookie(), cy.clearCookie(), cy.clearCookies(), and cy.screenshot() commands"
71
- },
72
- "fileServerFolder": {
73
- "type": "string",
74
- "default": "root project folder",
75
- "description": "Path to folder where application files will attempt to be served from"
76
- },
77
- "fixturesFolder": {
78
- "type": ["string", "boolean"],
79
- "default": "cypress/fixtures",
80
- "description": "Path to folder containing fixture files (Pass false to disable)"
81
- },
82
- "integrationFolder": {
83
- "type": "string",
84
- "default": "cypress/integration",
85
- "description": "Path to folder containing integration test files"
86
- },
87
- "pluginsFile": {
88
- "type": ["string", "boolean"],
89
- "default": "cypress/plugins/index.js",
90
- "description": "Path to plugins file. (Pass false to disable)"
91
- },
92
- "screenshotsFolder": {
93
- "type": "string",
94
- "default": "cypress/screenshots",
95
- "description": "Path to folder where screenshots will be saved from cy.screenshot() command or after a headless or CI run’s test failure"
96
- },
97
- "supportFile": {
98
- "type": ["string", "boolean"],
99
- "default": "cypress/support/index.js",
100
- "description": "Path to file to load before test files load. This file is compiled and bundled. (Pass false to disable)"
101
- },
102
- "videosFolder": {
103
- "type": "string",
104
- "default": "cypress/videos",
105
- "description": "Path to folder where videos will be saved after a headless or CI run"
106
- },
107
- "trashAssetsBeforeRuns": {
108
- "type": "boolean",
109
- "default": true,
110
- "description": "Whether Cypress will trash assets within the screenshotsFolder and videosFolder before headless test runs."
111
- },
112
- "videoCompression": {
113
- "type": ["number", "boolean"],
114
- "default": 32,
115
- "description": "The quality setting for the video compression, in Constant Rate Factor (CRF). The value can be false to disable compression or a value between 0 and 51, where a lower value results in better quality (at the expense of a higher file size)."
116
- },
117
- "video": {
118
- "type": "boolean",
119
- "default": true,
120
- "description": "Whether Cypress will record a video of the test run when running headlessly."
121
- },
122
- "videoUploadOnPasses": {
123
- "type": "boolean",
124
- "default": true,
125
- "description": "Whether Cypress will upload the video to the Dashboard even if all tests are passing. This applies only when recording your runs to the Dashboard. Turn this off if you’d like the video uploaded only when there are failing tests."
126
- },
127
- "chromeWebSecurity": {
128
- "type": "boolean",
129
- "default": true,
130
- "description": "Whether Chrome Web Security for same-origin policy and insecure mixed content is enabled. Read more about this at https://on.cypress.io/web-security"
131
- },
132
- "userAgent": {
133
- "type": "string",
134
- "default": null,
135
- "description": "Enables you to override the default user agent the browser sends in all request headers. User agent values are typically used by servers to help identify the operating system, browser, and browser version. See User-Agent MDN Documentation for example user agent values here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent"
136
- },
137
- "blacklistHosts": {
138
- "type": ["string", "array"],
139
- "items": {
140
- "type": "string"
141
- },
142
- "default": null,
143
- "description": "A String or Array of hosts that you wish to block traffic for. Please read the notes for examples on using this https://on.cypress.io/configuration#blacklistHosts"
144
- },
145
- "modifyObstructiveCode": {
146
- "type": "boolean",
147
- "default": true,
148
- "description": "Whether Cypress will search for and replace obstructive JS code found in .js or .html files that prevents Cypress from working. Please read the notes for more information on this setting. https://on.cypress.io/configuration#modifyObstructiveCode"
149
- },
150
- "viewportHeight": {
151
- "type": "number",
152
- "default": 660,
153
- "description": "Default height in pixels for the application under tests’ viewport (Override with cy.viewport() command)"
154
- },
155
- "viewportWidth": {
156
- "type": "number",
157
- "default": 1000,
158
- "description": "Default width in pixels for the application under tests’ viewport. (Override with cy.viewport() command)"
159
- },
160
- "animationDistanceThreshold": {
161
- "type": "number",
162
- "default": 5,
163
- "description": "The distance in pixels an element must exceed over time to be considered animating"
164
- },
165
- "waitForAnimations": {
166
- "type": "boolean",
167
- "default": true,
168
- "description": "Whether to wait for elements to finish animating before executing commands"
169
- },
170
- "projectId": {
171
- "type": "string",
172
- "default": null,
173
- "description": "A 6 character string to identify this project with Dashboard service. See https://on.cypress.io/dashboard-service#Identification"
174
- }
175
- }
176
- }
177
-
package/cypress.json DELETED
@@ -1 +0,0 @@
1
- {}
@@ -1,190 +0,0 @@
1
- /** @module Entity */
2
-
3
- import Entity from './Entity.js';
4
- import _ from 'lodash';
5
-
6
- /**
7
- * Class represents a TreeNode which adds Tree methods to Entity
8
- * TreeNode is hierarchical, so other TreeNodes can appear in this.children
9
- *
10
- * @extends Entity
11
- */
12
- class TreeNode extends Entity {
13
- constructor(schema, rawData = {}, repository = null, originalIsMapped = false, isDelayedSave = false, isRemotePhantomMode = false, isRoot = false) {
14
- super(...arguments);
15
-
16
- if (!schema.model.parentIdProperty) {
17
- throw new Error('parentIdProperty cannot be empty');
18
- }
19
-
20
- /**
21
- * @member {boolean} isTreeNode - Whether this Entity is a TreeNode
22
- */
23
- this.isTreeNode = true;
24
-
25
- /**
26
- * @member {boolean} isRoot - Whether this TreeNode is the root TreeNode
27
- */
28
- this.isRoot = isRoot;
29
-
30
- /**
31
- * @member {TreeNode} parent - The parent TreeNode for this TreeNode
32
- */
33
- this.parent = null;
34
-
35
- /**
36
- * @member {array} children - Contains any children of this TreeNode
37
- */
38
- this.children = [];
39
-
40
- /**
41
- * @member {boolean} isChildrenLoaded - Whether child TreeNodes have loaded for this TreeNode
42
- */
43
- this.isChildrenLoaded = false;
44
-
45
-
46
- // UI State
47
- this.isVisible = false;
48
-
49
- this.isExpanded = false;
50
- }
51
-
52
- /**
53
- * Gets the "parentId" Property object for this TreeNode.
54
- * This is the Property whose value represents the id for the parent TreeNode.
55
- * @return {Property} parentId Property
56
- */
57
- getParentIdProperty = () => {
58
- if (this.isDestroyed) {
59
- throw Error('this.getParentIdProperty is no longer valid. TreeNode has been destroyed.');
60
- }
61
- const parentIdProperty = this.getSchema().model.parentIdProperty;
62
- if (!parentIdProperty) {
63
- throw new Error('No parentIdProperty found for ' + schema.name);
64
- }
65
- return this.getProperty(parentIdProperty);
66
- }
67
-
68
- /**
69
- * Gets the parentId for this TreeNode.
70
- * @return {any} parentId - The parentId
71
- */
72
- getParentId = () => {
73
- if (this.isDestroyed) {
74
- throw Error('this.getParentId is no longer valid. TreeNode has been destroyed.');
75
- }
76
- return this.geParentIdProperty().getSubmitValue();
77
- }
78
-
79
- /**
80
- * Getter of the parentId for this TreeNode.
81
- * @return {any} parentId - The parentId
82
- */
83
- get parentId() {
84
- return this.getParentId();
85
- }
86
-
87
- /**
88
- * Getter of hasParent
89
- * Returns true if this.parent is truthy
90
- * @return {boolean} hasParent
91
- */
92
- get hasParent() {
93
- return !!this.parent;
94
- }
95
-
96
- getParent = () => {
97
- if (this.isDestroyed) {
98
- throw Error('this.getParent is no longer valid. TreeNode has been destroyed.');
99
- }
100
- return this.parent;
101
- }
102
-
103
- /**
104
- * Getter of hasChildren
105
- * @return {boolean} hasParent
106
- */
107
- get hasChildren() {
108
- return !_.isEmpty(this.children);
109
- }
110
-
111
- getChildren = async () => {
112
- if (this.isDestroyed) {
113
- throw Error('this.getChildren is no longer valid. TreeNode has been destroyed.');
114
- }
115
- if (!this.isChildrenLoaded) {
116
- await this.loadChildren();
117
- }
118
- return this.children;
119
- }
120
-
121
- loadChidren = async () => {
122
- if (this.isDestroyed) {
123
- throw Error('this.loadChidren is no longer valid. TreeNode has been destroyed.');
124
- }
125
- this.children = await this.repository.loadChildTreeNodes(this); // populates the children with a reference to this in child.parent
126
- this.isChildrenLoaded = true;
127
- }
128
-
129
- getPrevousSibling = async () => {
130
- if (this.isDestroyed) {
131
- throw Error('this.getPrevousSibling is no longer valid. TreeNode has been destroyed.');
132
- }
133
- const
134
- parent = this.getParent(),
135
- siblings = await parent.getChildren();
136
- let previous;
137
- _.each(siblings, (treeNode) => {
138
- if (treeNode === this) {
139
- return false;
140
- }
141
- previous = treeNode;
142
- })
143
- return previous;
144
- }
145
-
146
- getNextSibling = async () => {
147
- if (this.isDestroyed) {
148
- throw Error('this.getNextSibling is no longer valid. TreeNode has been destroyed.');
149
- }
150
- const
151
- parent = this.getParent(),
152
- siblings = await parent.getChildren();
153
- let returnNext = false,
154
- next = null;
155
- _.each(siblings, (treeNode) => {
156
- if (returnNext) {
157
- next = treeNode;
158
- return false;
159
- }
160
- if (treeNode === this) {
161
- returnNext = true;
162
- }
163
- })
164
- return next;
165
- }
166
-
167
- getChildAt = (ix) => {
168
- if (this.isDestroyed) {
169
- throw Error('this.getChildAt is no longer valid. TreeNode has been destroyed.');
170
- }
171
- return this.children[ix];
172
- }
173
-
174
- getFirstChild = () => {
175
- if (this.isDestroyed) {
176
- throw Error('this.getFirstChild is no longer valid. TreeNode has been destroyed.');
177
- }
178
- return this.children[0];
179
- }
180
-
181
- getLastChild = () => {
182
- if (this.isDestroyed) {
183
- throw Error('this.getLastChild is no longer valid. TreeNode has been destroyed.');
184
- }
185
- return this.children.slice(-1)[0]
186
- }
187
-
188
- }
189
-
190
- export default TreeNode;