@onehat/data 1.21.19 → 1.21.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,105 @@
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
+ import _ from 'lodash';
3
+
4
+ describe('MixedProperty', function() {
5
+
6
+ beforeEach(function() {
7
+ const
8
+ definition = {
9
+ type: 'mixed',
10
+ types: [
11
+ 'int',
12
+ 'string',
13
+ ],
14
+ },
15
+ Property = PropertyTypes[definition.type];
16
+ this.property = new Property(definition);
17
+ });
18
+
19
+ it('className', function() {
20
+ const className = this.property.getClassName();
21
+ expect(className).to.be.eq('Mixed');
22
+ });
23
+
24
+ it('events are handled properly', function() {
25
+ this.property.on('change', (property, oldValue, newValue) => {
26
+ if (property.getCurrentType() === 'int') {
27
+ expect(oldValue).to.be.eq(null);
28
+ expect(newValue).to.be.eq(42);
29
+ } else {
30
+ expect(oldValue).to.be.eq(null);
31
+ expect(newValue).to.be.eq('here');
32
+ }
33
+ });
34
+
35
+ this.property.setValue(42);
36
+ this.property.setValue('here');
37
+ });
38
+
39
+ describe('direct methods', function() {
40
+
41
+ it('getCurrentType', function() {
42
+ const currentType = this.property.getCurrentType();
43
+ expect(currentType).to.be.eq('int');
44
+
45
+ // switch type
46
+ this.property.setValue('Hello');
47
+ const newCurrentType = this.property.getCurrentType();
48
+ expect(newCurrentType).to.be.eq('string');
49
+ });
50
+
51
+ it('getInternalProperty', function() {
52
+ const intProperty = this.property.getInternalProperty('int');
53
+ expect(intProperty).to.be.not.undefined;
54
+ expect(intProperty.constructor.type).to.be.eq('int');
55
+
56
+ // switch type
57
+ this.property.setValue('Hello');
58
+ const stringProperty = this.property.getInternalProperty('string');
59
+ expect(stringProperty).to.be.not.undefined;
60
+ expect(stringProperty.constructor.type).to.be.eq('string');
61
+ });
62
+
63
+ it('destroy', function() {
64
+ this.property.destroy();
65
+ expect(this.property.internalProperties).to.be.empty;
66
+ });
67
+
68
+ });
69
+
70
+ it('passes methods to currentProperty', function() {
71
+
72
+ this.property.setValue(42);
73
+ expect(this.property.getSubmitValue()).to.be.eq(42);
74
+ expect(this.property.getCurrentType()).to.be.eq('int');
75
+
76
+ this.property.setValue('here');
77
+ expect(this.property.getSubmitValue()).to.be.eq('here');
78
+ expect(this.property.getCurrentType()).to.be.eq('string');
79
+
80
+ });
81
+
82
+ it('passes configs to internal properties', function() {
83
+ const
84
+ definition = {
85
+ type: 'mixed',
86
+ types: [
87
+ {
88
+ type: 'date',
89
+ readFormat: 'YYYY-MM-DD',
90
+ displayFormat: 'YYYY',
91
+ submitFormat: 'YYYY-MM',
92
+ },
93
+ 'string',
94
+ ],
95
+ },
96
+ Property = PropertyTypes[definition.type],
97
+ property = new Property(definition);
98
+
99
+ property.setValue('2025-10-17');
100
+ expect(property.getSubmitValue()).to.be.eq('2025-10');
101
+ expect(property.getDisplayValue()).to.be.eq('2025');
102
+ expect(property.getCurrentType()).to.be.eq('date');
103
+ });
104
+
105
+ });
@@ -44,6 +44,7 @@ describe('Property', function() {
44
44
  title: null,
45
45
  tooltip: null,
46
46
  viewerType: null,
47
+ formatter: null,
47
48
  };
48
49
  // console.log(defaults);
49
50
  // console.log(expected);
@@ -81,9 +82,14 @@ describe('Property', function() {
81
82
 
82
83
  it('getDisplayValue & displayValue', function() {
83
84
  this.property.setValue('12');
84
- const value = this.property.getDisplayValue();
85
+ let value = this.property.getDisplayValue();
85
86
  expect(value).to.be.eq(12);
86
87
  expect(value).to.be.eq(this.property.displayValue);
88
+
89
+ this.property.setFormatter('FormatInt');
90
+ this.property.setValue('12345');
91
+ value = this.property.getDisplayValue();
92
+ expect(value).to.be.eq('12,345');
87
93
  });
88
94
 
89
95
  it('hasMapping', function() {
@@ -38,6 +38,21 @@ describe('OneBuildRepository', function() {
38
38
  expect(r._params.test).to.be.eq(1);
39
39
  });
40
40
 
41
+ it('getBaseParamConditions', function() {
42
+ const
43
+ r = this.repository,
44
+ newConditions = {
45
+ 'conditions[Model.model]': 'test1',
46
+ 'conditions[Model.modelid]': 'test2',
47
+ };
48
+
49
+ r.setBaseParams(newConditions);
50
+
51
+ const conditions = r.getBaseParamConditions();
52
+
53
+ expect(conditions).to.eql(newConditions);
54
+ });
55
+
41
56
  it('hasParam', function() {
42
57
  const r = this.repository;
43
58
  r.setParam('test', 1);
@@ -1,2 +1,3 @@
1
1
  // https://on.cypress.io/configuration
2
2
  import './commands.js';
3
+ import 'cypress-localstorage-commands';
@@ -0,0 +1,20 @@
1
+ // ***********************************************************
2
+ // This example support/index.js is processed and
3
+ // loaded automatically before your test files.
4
+ //
5
+ // This is a great place to put global configuration and
6
+ // behavior that modifies Cypress.
7
+ //
8
+ // You can change the location of this file or turn off
9
+ // automatically serving support files with the
10
+ // 'supportFile' configuration option.
11
+ //
12
+ // You can read more here:
13
+ // https://on.cypress.io/configuration
14
+ // ***********************************************************
15
+
16
+ // Import commands.js using ES2015 syntax:
17
+ import './commands'
18
+
19
+ // Alternatively you can use CommonJS syntax:
20
+ // require('./commands')
package/cypress.config.js CHANGED
@@ -1,16 +1,17 @@
1
1
  import { defineConfig } from "cypress";
2
2
  import webpackPreprocessor from "@cypress/webpack-preprocessor";
3
+ import localstoragePlugin from 'cypress-localstorage-commands/plugin.js';
3
4
 
4
5
  export default defineConfig({
5
6
  e2e: {
6
7
  experimentalRunAllSpecs: true,
7
8
  chromeWebSecurity: false,
8
- setupNodeEvents(on) {
9
+ setupNodeEvents(on, config) {
9
10
  const options = webpackPreprocessor.defaultOptions;
10
11
  if (!options.module) {
11
12
  options.module = {
12
13
  rules: [],
13
- }
14
+ };
14
15
  }
15
16
  if (!options.module.rules) {
16
17
  options.module.rules = [];
@@ -18,24 +19,25 @@ export default defineConfig({
18
19
  options.module.rules.push({
19
20
  test: /\.(js|jsx|mjs)$/,
20
21
  exclude: [/node_modules\/(?!(@onehat)\/).*/],
21
- use: [{
22
- loader: 'babel-loader',
23
- options: {
24
- cacheDirectory: false,
25
- presets: [
26
- '@babel/preset-env'
27
- ],
28
- plugins: [
29
- '@babel/plugin-transform-class-properties',
30
- '@babel/plugin-transform-runtime'
31
- ],
32
- sourceType: 'unambiguous',
22
+ use: [
23
+ {
24
+ loader: 'babel-loader',
25
+ options: {
26
+ cacheDirectory: false,
27
+ presets: ['@babel/preset-env'],
28
+ plugins: [
29
+ '@babel/plugin-transform-class-properties',
30
+ '@babel/plugin-transform-runtime',
31
+ ],
32
+ sourceType: 'unambiguous',
33
+ },
33
34
  },
34
- }],
35
-
35
+ ],
36
36
  });
37
37
 
38
38
  on('file:preprocessor', webpackPreprocessor(options));
39
+
40
+ localstoragePlugin(on, config);
39
41
  },
40
42
  }
41
43
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/data",
3
- "version": "1.21.19",
3
+ "version": "1.21.21",
4
4
  "description": "JS data modeling package with adapters for many storage mediums.",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -37,39 +37,38 @@
37
37
  "homepage": "https://github.com/OneHatRepo/data#readme",
38
38
  "dependencies": {
39
39
  "@onehat/events": "^1.6.6",
40
- "async-wait-until": "^2.0.12",
41
- "accounting-js": "^1.1.1",
42
- "axios": "^1.6.2",
43
- "chrono-node": "^2.7.3",
40
+ "accounting-js": "^2.0.3",
41
+ "async-wait-until": "^2.0.31",
42
+ "axios": "^1.13.0",
43
+ "chrono-node": "^2.9.0",
44
44
  "he": "^1.2.0",
45
- "js-base64": "^3.7.5",
45
+ "js-base64": "^3.7.8",
46
46
  "lodash": "^4.17.21",
47
- "moment": "^2.29.4",
47
+ "moment": "^2.30.1",
48
48
  "natsort": "^2.0.3",
49
49
  "numeral": "^2.0.6",
50
50
  "object-hash": "^3.0.0",
51
- "qs": "^6.11.2",
51
+ "qs": "^6.14.0",
52
52
  "relative-time-parser": "^1.0.15",
53
53
  "uuid": "^9.0.1"
54
54
  },
55
55
  "peerDependencies": {
56
- "fast-xml-parser": "^4.4.1"
56
+ "fast-xml-parser": "^4.4.1",
57
+ "store2": "^2.14.3"
57
58
  },
58
59
  "devDependencies": {
59
- "@babel/core": "^7.22.1",
60
- "@babel/node": "^7.22.1",
61
- "@babel/plugin-transform-class-properties": "^7.22.3",
62
- "@babel/plugin-transform-runtime": "^7.22.4",
63
- "@babel/preset-env": "^7.22.4",
64
- "@babel/register": "^7.21.0",
65
- "@babel/runtime": "^7.22.3",
60
+ "@babel/core": "^7.24.5",
61
+ "@babel/plugin-transform-class-properties": "^7.24.1",
62
+ "@babel/plugin-transform-export-namespace-from": "^7.24.1",
63
+ "@babel/plugin-transform-runtime": "^7.24.3",
64
+ "@babel/preset-env": "^7.24.5",
65
+ "@babel/runtime": "^7.24.5",
66
66
  "@cypress/webpack-preprocessor": "^5.17.1",
67
- "babel-loader": "^9.1.2",
68
- "cypress": "12.15.0",
67
+ "cypress": "^13.15.2",
68
+ "cypress-localstorage-commands": "^2.2.7",
69
69
  "ink-docstrap": "^1.3.2",
70
70
  "joi": "^17.9.2",
71
71
  "jsdoc": "^4.0.2",
72
- "webpack": "^5.85.0",
73
72
  "yup": "^1.2.0"
74
73
  }
75
74
  }
@@ -113,17 +113,7 @@ class Entity extends EventEmitter {
113
113
  /**
114
114
  * @member {boolean} isTree - Whether this Entity is a TreeNode
115
115
  */
116
- this.isTree = schema.model.isTree || false;
117
-
118
- if (this.isTree && !schema.model.parentIdProperty) {
119
- throw new Error('parentIdProperty cannot be empty for a TreeNode');
120
- }
121
- if (this.isTree && this.repository?.isClosureTable && !schema.model.depthProperty) {
122
- throw new Error('depthProperty cannot be empty for a Closure Table TreeNode');
123
- }
124
- if (this.isTree && !schema.model.hasChildrenProperty) {
125
- throw new Error('hasChildrenProperty cannot be empty for a TreeNode');
126
- }
116
+ this.isTree = schema.repository.type === 'tree' || false;
127
117
 
128
118
  /**
129
119
  * @member {TreeNode} parent - The parent TreeNode for this TreeNode
@@ -346,7 +336,16 @@ class Entity extends EventEmitter {
346
336
  if (this.isDestroyed) {
347
337
  throw Error('this._createProperties is no longer valid. Entity has been destroyed.');
348
338
  }
349
- const propertyDefinitions = this.schema.model.properties;
339
+ let propertyDefinitions = this.schema.model.properties;
340
+ if (this.isTree) {
341
+ const treePropertyDefinitions = [
342
+ // defaults
343
+ { name: 'parentId', mapping: 'parentId', type: 'int', isEditingDisabled: true, isFilteringDisabled: true, },
344
+ { name: 'hasChildren', mapping: 'hasChildren', type: 'bool', isEditingDisabled: true, isFilteringDisabled: true, },
345
+ { name: 'depth', mapping: 'depth', type: 'int', isEditingDisabled: true, isFilteringDisabled: true, },
346
+ ];
347
+ propertyDefinitions = _.unionBy(propertyDefinitions, treePropertyDefinitions, 'name'); // propertyDefinitions will override treePropertyDefinitions
348
+ }
350
349
  let properties = {};
351
350
  _.each(propertyDefinitions, (definition) => {
352
351
  if (!definition.name) {
@@ -1625,16 +1624,16 @@ class Entity extends EventEmitter {
1625
1624
  /**
1626
1625
  * Loads the children of this TreeNode from repository.
1627
1626
  */
1628
- loadChildren = async (depth) => {
1627
+ loadChildren = async (depth = 1) => {
1629
1628
  this.ensureTree();
1630
1629
  if (this.isDestroyed) {
1631
1630
  throw Error('this.loadChildren is no longer valid. TreeNode has been destroyed.');
1632
1631
  }
1633
- if (!this.repository?.loadChildNodes) {
1634
- throw Error('repository.loadChildNodes is not defined.');
1632
+ if (!this.repository?.loadNode) {
1633
+ throw Error('repository.loadNode is not defined.');
1635
1634
  }
1636
1635
 
1637
- const children = await this.repository.loadChildNodes(this, depth);
1636
+ const children = await this.repository.loadNode(this, depth);
1638
1637
  this.areChildrenLoaded = true;
1639
1638
  return children;
1640
1639
  }
@@ -1642,8 +1641,8 @@ class Entity extends EventEmitter {
1642
1641
  /**
1643
1642
  * Alias for loadChildren
1644
1643
  */
1645
- reloadChildren = () => { // alias
1646
- return this.loadChildren();
1644
+ reloadChildren = (depth = 1) => { // alias
1645
+ return this.loadChildren(depth);
1647
1646
  }
1648
1647
 
1649
1648
  /**
@@ -1768,6 +1767,18 @@ class Entity extends EventEmitter {
1768
1767
  return parentIds.reverse().join('/');
1769
1768
  }
1770
1769
 
1770
+ /**
1771
+ * Gets the model that this entity uses
1772
+ * @return {string} model
1773
+ */
1774
+ getModel = () => {
1775
+ if (this.isTree && this.nodeType) {
1776
+ // Trees can have entities of different models
1777
+ return this.nodeType;
1778
+ }
1779
+ return this.repository.getModel();
1780
+ }
1781
+
1771
1782
  /**
1772
1783
  * Moves this TreeNode to another parentId.
1773
1784
  */
@@ -1777,7 +1788,7 @@ class Entity extends EventEmitter {
1777
1788
  throw Error('this.moveTreeNode is no longer valid. TreeNode has been destroyed.');
1778
1789
  }
1779
1790
  if (!this.repository?.moveTreeNode) {
1780
- throw Error('repository.moveTreeNode is not defined.');
1791
+ throw Error('repository.moveTreeNode is not defined.');
1781
1792
  }
1782
1793
 
1783
1794
  return this.repository.moveTreeNode(this, newParentId);
@@ -1789,7 +1800,7 @@ class Entity extends EventEmitter {
1789
1800
  */
1790
1801
  ensureTree = () => {
1791
1802
  if (!this.isTree) {
1792
- this.throwError('This Entity is not a tree!');
1803
+ throw Error('This Entity is not a tree!');
1793
1804
  return false;
1794
1805
  }
1795
1806
  return true;
@@ -1820,7 +1831,7 @@ class Entity extends EventEmitter {
1820
1831
  * @fires destroy
1821
1832
  */
1822
1833
  destroy = () => {
1823
- if (this.isFrozen) {
1834
+ if (this.isFrozen || this.isDestroyed) {
1824
1835
  return;
1825
1836
  }
1826
1837
 
package/src/OneHatData.js CHANGED
@@ -56,10 +56,10 @@ export class OneHatData extends EventEmitter {
56
56
  this.repositories = {};
57
57
 
58
58
  /**
59
- * @member {Object} uniqueRepositoriesMap - Object map of all unique Repositories, with signature of { mapName: id }
59
+ * @member {Object} uniqueRepositoryIdsMap - Object map of all unique Repositories, with signature of { mapName: id }
60
60
  * @private
61
61
  */
62
- this.uniqueRepositoriesMap = {};
62
+ this.uniqueRepositoryIdsMap = {};
63
63
 
64
64
  /**
65
65
  * @member {boolean} isDestroyed - Whether this object has been destroyed
@@ -495,8 +495,8 @@ export class OneHatData extends EventEmitter {
495
495
 
496
496
  /**
497
497
  * Gets or creates a unique repository with the supplied schemaName and name
498
- * @param {string} schemaName - Name of Schema
499
498
  * @param {string} mapName - Name of unique repository (will be internally mapped to an id)
499
+ * @param {string} schemaName - Name of Schema
500
500
  * @return {Repository} repository
501
501
  */
502
502
  getOrCreateUniqueRepository = async (mapName, schemaName) => {
@@ -505,7 +505,7 @@ export class OneHatData extends EventEmitter {
505
505
  }
506
506
 
507
507
  // Try to get it
508
- const id = this.uniqueRepositoriesMap[mapName];
508
+ let id = this.uniqueRepositoryIdsMap[mapName];
509
509
  if (id) {
510
510
  return this.getRepositoryById(id);
511
511
  }
@@ -517,8 +517,10 @@ export class OneHatData extends EventEmitter {
517
517
  }
518
518
 
519
519
  const repository = await this.createRepository(schemaName);
520
- this.uniqueRepositoriesMap[mapName] = repository.id;
520
+ id = repository.id;
521
+ repository.name += '-' + id;
521
522
  repository.isUnique = true;
523
+ this.uniqueRepositoryIdsMap[mapName] = repository.id;
522
524
  return repository;
523
525
  }
524
526
 
@@ -1,7 +1,7 @@
1
1
  /** @module Property */
2
2
 
3
3
  import Property from './Property.js';
4
- import accounting from 'accounting-js';
4
+ import * as accounting from 'accounting-js';
5
5
  import _ from 'lodash';
6
6
 
7
7
  /**
@@ -126,7 +126,7 @@ JsonProperty.className = 'Json';
126
126
  JsonProperty.type = 'json';
127
127
 
128
128
 
129
- // For the sake of OneBuild, create an alias of Json, that's Tag
129
+ // For the sake of OneBuild backwards compatibility, create an alias of Json, that's Tag
130
130
  export class TagProperty extends JsonProperty {}
131
131
  TagProperty.className = 'Tag';
132
132
  TagProperty.type = 'tag';