@onehat/data 1.8.34 → 1.9.0

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 (28) hide show
  1. package/cypress/integration/Async.spec.js +1 -1
  2. package/cypress/integration/Entity.spec.js +3 -3
  3. package/cypress/integration/OneHatData.spec.js +6 -6
  4. package/cypress/integration/Property/Base64.spec.js +1 -1
  5. package/cypress/integration/Property/Boolean.spec.js +1 -1
  6. package/cypress/integration/Property/Currency.spec.js +1 -1
  7. package/cypress/integration/Property/Date.spec.js +1 -1
  8. package/cypress/integration/Property/DateTime.spec.js +1 -1
  9. package/cypress/integration/Property/Float.spec.js +1 -1
  10. package/cypress/integration/Property/Integer.spec.js +1 -1
  11. package/cypress/integration/Property/Json.spec.js +1 -1
  12. package/cypress/integration/Property/Percent.spec.js +1 -1
  13. package/cypress/integration/Property/PercentInt.spec.js +1 -1
  14. package/cypress/integration/Property/Property.spec.js +3 -3
  15. package/cypress/integration/Property/String.spec.js +1 -1
  16. package/cypress/integration/Property/Time.spec.js +1 -1
  17. package/cypress/integration/Property/Uuid.spec.js +1 -1
  18. package/cypress/integration/Repository/Ajax.spec.js +2 -2
  19. package/cypress/integration/Repository/LocalFromRemote.spec.js +3 -3
  20. package/cypress/integration/Repository/Memory.spec.js +29 -3
  21. package/cypress/integration/Repository/OneBuild.spec.js +4 -4
  22. package/cypress/integration/Repository/Repository.spec.js +38 -4
  23. package/cypress/integration/Schema.spec.js +2 -2
  24. package/cypress/support/index.js +1 -1
  25. package/package.json +11 -10
  26. package/src/Repository/Memory.js +33 -2
  27. package/src/Repository/Repository.js +55 -23
  28. package/src/Schema/Schema.js +2 -1
@@ -1,4 +1,4 @@
1
- import { OneHatData } from '../../src/OneHatData';
1
+ import { OneHatData } from '../../src/OneHatData.js';
2
2
 
3
3
  describe('Async playground', function() {
4
4
 
@@ -1,6 +1,6 @@
1
- import Entity from '../../src/Entity';
2
- import Schema from '../../src/Schema';
3
- import PropertyTypes from '../../src/Property';
1
+ import Entity from '../../src/Entity.js';
2
+ import Schema from '../../src/Schema/index.js';
3
+ import PropertyTypes from '../../src/Property/index.js';
4
4
 
5
5
 
6
6
  describe('Entity', function() {
@@ -1,9 +1,9 @@
1
- import { OneHatData } from '../../src/OneHatData';
2
- import GroupsDefinition from '../fixtures/Definitions/Groups';
3
- import GroupsUsersDefinition from '../fixtures/Definitions/GroupsUsers';
4
- import UsersDefinition from '../fixtures/Definitions/Users';
5
- import groupsUserData from '../fixtures/Data/GroupsUser';
6
- import KeyValues from '../../src/Schema/KeyValues';
1
+ import { OneHatData } from '../../src/OneHatData.js';
2
+ import GroupsDefinition from '../fixtures/Definitions/Groups.js';
3
+ import GroupsUsersDefinition from '../fixtures/Definitions/GroupsUsers.js';
4
+ import UsersDefinition from '../fixtures/Definitions/Users.js';
5
+ import groupsUserData from '../fixtures/Data/GroupsUser.js';
6
+ import KeyValues from '../../src/Schema/KeyValues.js';
7
7
 
8
8
 
9
9
  // NOTE: Cypress can't handle async functions for beforeEach,
@@ -1,4 +1,4 @@
1
- import PropertyTypes from '../../../src/Property';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
2
 
3
3
  describe('Base64Property', function() {
4
4
 
@@ -1,4 +1,4 @@
1
- import PropertyTypes from '../../../src/Property';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
2
 
3
3
  describe('BooleanProperty', function() {
4
4
 
@@ -1,4 +1,4 @@
1
- import PropertyTypes from '../../../src/Property';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
2
 
3
3
  describe('CurrencyProperty', function() {
4
4
 
@@ -1,4 +1,4 @@
1
- import PropertyTypes from '../../../src/Property';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
2
 
3
3
  describe('DateProperty', function() {
4
4
 
@@ -1,4 +1,4 @@
1
- import PropertyTypes from '../../../src/Property';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
2
 
3
3
  describe('DateTimeProperty', function() {
4
4
 
@@ -1,4 +1,4 @@
1
- import PropertyTypes from '../../../src/Property';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
2
 
3
3
  describe('FloatProperty', function() {
4
4
 
@@ -1,4 +1,4 @@
1
- import PropertyTypes from '../../../src/Property';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
2
 
3
3
  describe('IntegerProperty', function() {
4
4
  beforeEach(function() {
@@ -1,4 +1,4 @@
1
- import PropertyTypes from '../../../src/Property';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
2
  import _ from 'lodash';
3
3
 
4
4
  describe('JsonProperty', function() {
@@ -1,4 +1,4 @@
1
- import PropertyTypes from '../../../src/Property';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
2
 
3
3
  describe('PercentProperty', function() {
4
4
 
@@ -1,4 +1,4 @@
1
- import PropertyTypes from '../../../src/Property';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
2
 
3
3
  describe('PercentProperty', function() {
4
4
 
@@ -1,6 +1,6 @@
1
- import PropertyTypes from '../../../src/Property';
2
- import Entity from '../../../src/Entity';
3
- import Schema from '../../../src/Schema';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
+ import Entity from '../../../src/Entity.js';
3
+ import Schema from '../../../src/Schema/index.js';
4
4
 
5
5
  describe('Property', function() {
6
6
  beforeEach(function() {
@@ -1,4 +1,4 @@
1
- import PropertyTypes from '../../../src/Property';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
2
 
3
3
  describe('StringProperty', function() {
4
4
 
@@ -1,4 +1,4 @@
1
- import PropertyTypes from '../../../src/Property';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
2
 
3
3
  describe('TimeProperty', function() {
4
4
 
@@ -1,4 +1,4 @@
1
- import PropertyTypes from '../../../src/Property';
1
+ import PropertyTypes from '../../../src/Property/index.js';
2
2
 
3
3
  describe('UuidProperty', function() {
4
4
 
@@ -1,5 +1,5 @@
1
- import RepositoryTypes from '../../../src/Repository';
2
- import Schema from '../../../src/Schema';
1
+ import RepositoryTypes from '../../../src/Repository/index.js';
2
+ import Schema from '../../../src/Schema/index.js';
3
3
 
4
4
  describe('OneBuildRepository', function() {
5
5
  beforeEach(function() {
@@ -2,9 +2,9 @@ import {
2
2
  default as LocalFromRemoteRepository,
3
3
  MODE_LOCAL_MIRROR,
4
4
  MODE_COMMAND_QUEUE,
5
- } from '../../../src/Repository/LocalFromRemote';
6
- import MemoryRepository from '../../../src/Repository/Memory';
7
- import Schema from '../../../src/Schema';
5
+ } from '../../../src/Repository/LocalFromRemote/index.js';
6
+ import MemoryRepository from '../../../src/Repository/Memory.js';
7
+ import Schema from '../../../src/Schema/index.js';
8
8
  import momentAlt from 'relative-time-parser';
9
9
 
10
10
  describe('LocalFromRemote', function() {
@@ -1,5 +1,5 @@
1
- import RepositoryTypes from '../../../src/Repository';
2
- import Schema from '../../../src/Schema';
1
+ import RepositoryTypes from '../../../src/Repository/index.js';
2
+ import Schema from '../../../src/Schema/index.js';
3
3
 
4
4
  describe('MemoryRepository', function() {
5
5
  beforeEach(function() {
@@ -108,6 +108,32 @@ describe('MemoryRepository', function() {
108
108
  expect(result3).to.be.eq(1);
109
109
  });
110
110
 
111
+ it('natsort', function() {
112
+ const entities = this.repository.getEntitiesOnPage();
113
+ entities[0].value = 'foo1';
114
+ entities[1].value = 'foo12';
115
+ entities[2].value = 'foo2';
116
+
117
+ const before = this.repository.getRawValues();
118
+ expect(before[0].value).to.be.eq('foo1');
119
+ expect(before[1].value).to.be.eq('foo12');
120
+ expect(before[2].value).to.be.eq('foo2');
121
+ expect(before[3].value).to.be.eq('four');
122
+ expect(before[4].value).to.be.eq('five');
123
+
124
+ this.repository.sort({
125
+ name: 'value',
126
+ direction: 'ASC',
127
+ fn: 'natsort',
128
+ });
129
+ const after = this.repository.getRawValues();
130
+ expect(after[0].value).to.be.eq('five');
131
+ expect(after[1].value).to.be.eq('foo1');
132
+ expect(after[2].value).to.be.eq('foo2');
133
+ expect(after[3].value).to.be.eq('foo12');
134
+ expect(after[4].value).to.be.eq('four');
135
+ });
136
+
111
137
  });
112
138
 
113
139
  describe('filtering', function() {
@@ -210,7 +236,7 @@ describe('MemoryRepository', function() {
210
236
  expect(result.value).to.be.eq('four');
211
237
  });
212
238
 
213
- it.only('getIxById', function() {
239
+ it('getIxById', function() {
214
240
  this.repository.setPage(1);
215
241
  this.repository.setPageSize(2);
216
242
  let ix = this.repository.getIxById(1);
@@ -1,7 +1,7 @@
1
- import { OneHatData } from '../../../src/OneHatData';
2
- import UsersDefinition from '../../fixtures/Definitions/Users';
3
- import GroupsDefinition from '../../fixtures/Definitions/Groups';
4
- import UserData from '../../fixtures/Data/User';
1
+ import { OneHatData } from '../../../src/OneHatData.js';
2
+ import UsersDefinition from '../../fixtures/Definitions/Users.js';
3
+ import GroupsDefinition from '../../fixtures/Definitions/Groups.js';
4
+ import UserData from '../../fixtures/Data/User.js';
5
5
 
6
6
  const baseURL = Cypress.env('baseURL'),
7
7
  creds = {
@@ -1,5 +1,5 @@
1
- import RepositoryTypes from '../../../src/Repository';
2
- import Schema from '../../../src/Schema';
1
+ import RepositoryTypes from '../../../src/Repository/index.js';
2
+ import Schema from '../../../src/Schema/index.js';
3
3
 
4
4
  describe('Repository Base', function() {
5
5
  beforeEach(function() {
@@ -9,8 +9,9 @@ describe('Repository Base', function() {
9
9
  idProperty: 'key',
10
10
  displayProperty: 'value',
11
11
  properties: [
12
- { name: 'key', type: 'int' },
13
- { name: 'value' },
12
+ { name: 'key', type: 'int', },
13
+ { name: 'value', },
14
+ { name: 'json', type: 'json', },
14
15
  ],
15
16
  associations: {
16
17
  hasMany: [
@@ -215,6 +216,7 @@ describe('Repository Base', function() {
215
216
  expected = {
216
217
  direction: 'ASC',
217
218
  name: 'value',
219
+ fn: 'default',
218
220
  };
219
221
  expect(_.isEqual(sorters[0], expected)).to.be.true;
220
222
  });
@@ -229,6 +231,38 @@ describe('Repository Base', function() {
229
231
  expect(didFireChangeSorters).to.be.true;
230
232
  });
231
233
 
234
+ it('sort by non-existant field', function() {
235
+ let didError = false;
236
+ try {
237
+ this.repository.sort('foo');
238
+ } catch(err) {
239
+ expect(err).to.match(/Sorting property does not exist/);
240
+ didError = true;
241
+ }
242
+ expect(didError).to.be.true;
243
+ });
244
+
245
+ it('sort by non-sortable field', function() {
246
+ let didError = false;
247
+ try {
248
+ this.repository.sort('json');
249
+ } catch(err) {
250
+ expect(err).to.match(/Sorting property type is not sortable/);
251
+ didError = true;
252
+ }
253
+ expect(didError).to.be.true;
254
+ });
255
+
256
+ it('getSortField', function() {
257
+ const sortField = this.repository.getSortField();
258
+ expect(sortField).to.be.eq('value');
259
+ });
260
+
261
+ it('getSortDirection', function() {
262
+ const sortDirection = this.repository.getSortDirection();
263
+ expect(sortDirection).to.be.eq('ASC');
264
+ });
265
+
232
266
  });
233
267
 
234
268
  describe('filtering', function() {
@@ -1,5 +1,5 @@
1
- import Schema from '../../src/Schema';
2
- import GroupsUsersDefinition from '../fixtures/Definitions/GroupsUsers';
1
+ import Schema from '../../src/Schema/index.js';
2
+ import GroupsUsersDefinition from '../fixtures/Definitions/GroupsUsers.js';
3
3
 
4
4
 
5
5
  describe('Schema', function() {
@@ -1,2 +1,2 @@
1
1
  // https://on.cypress.io/configuration
2
- import './commands';
2
+ import './commands.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onehat/data",
3
- "version": "1.8.34",
3
+ "version": "1.9.0",
4
4
  "description": "JS data modeling package with adapters for many storage mediums.",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -37,28 +37,29 @@
37
37
  "dependencies": {
38
38
  "@onehat/events": "^1.6.5",
39
39
  "accounting-js": "^1.1.1",
40
- "axios": "^1.2.0",
41
- "chrono-node": "^2.4.1",
42
- "fast-xml-parser": "^4.0.11",
40
+ "axios": "^1.2.1",
41
+ "chrono-node": "^2.4.2",
42
+ "fast-xml-parser": "^4.0.12",
43
43
  "he": "^1.2.0",
44
- "js-base64": "^3.7.2",
44
+ "js-base64": "^3.7.3",
45
45
  "lodash": "^4.17.21",
46
46
  "moment": "^2.29.4",
47
+ "natsort": "^2.0.3",
47
48
  "numeral": "^2.0.6",
48
49
  "qs": "^6.11.0",
49
50
  "relative-time-parser": "^1.0.15",
50
51
  "uuid": "^9.0.0"
51
52
  },
52
53
  "devDependencies": {
53
- "@babel/core": "^7.20.2",
54
- "@babel/node": "^7.20.2",
54
+ "@babel/core": "^7.20.5",
55
+ "@babel/node": "^7.20.5",
55
56
  "@babel/plugin-proposal-class-properties": "^7.18.6",
56
57
  "@babel/plugin-transform-runtime": "^7.19.6",
57
58
  "@babel/preset-env": "^7.20.2",
58
59
  "@babel/register": "^7.18.9",
59
- "@babel/runtime": "^7.20.0",
60
- "@cypress/webpack-preprocessor": "^5.11.0",
61
- "babel-loader": "^9.1.0",
60
+ "@babel/runtime": "^7.20.6",
61
+ "@cypress/webpack-preprocessor": "^5.16.0",
62
+ "babel-loader": "^8.0.2",
62
63
  "cypress": "5.2.0",
63
64
  "ink-docstrap": "^1.3.2",
64
65
  "jsdoc": "^4.0.0",
@@ -2,6 +2,7 @@
2
2
 
3
3
  import Repository from './Repository.js';
4
4
  import Entity from '../Entity.js';
5
+ import natsort from 'natsort';
5
6
  import _ from 'lodash';
6
7
 
7
8
  const MEM_PREFIX = 'MEM-';
@@ -212,6 +213,13 @@ class MemoryRepository extends Repository {
212
213
  if (_.isFunction(sorter)) {
213
214
  return sorter;
214
215
  }
216
+ if (sorter.fn && sorter.fn !== 'default') {
217
+ if (sorter.fn === 'natsort') {
218
+ return MemoryRepository._getNatSort(sorter);
219
+ } else if (_.isFunction(sorter.fn)) {
220
+ return sorter.fn;
221
+ }
222
+ }
215
223
  return MemoryRepository._getCompareFunction(sorter);
216
224
  });
217
225
 
@@ -234,6 +242,27 @@ class MemoryRepository extends Repository {
234
242
  this.isSorted = true;
235
243
  }
236
244
 
245
+ /**
246
+ * Helper for _applySorters().
247
+ * Takes a sorter object and returns a valid compare function for use with Array.prototype.sort
248
+ * @param {object} sorter - Object with two properties: 'name' & 'direction'
249
+ * @return {function} - Compare function
250
+ * @private
251
+ * @static
252
+ */
253
+ static _getNatSort = (sorter) => {
254
+ const
255
+ name = sorter.name,
256
+ direction = sorter.direction.toUpperCase(),
257
+ sortFn = natsort.default({ desc: direction !== 'ASC', });
258
+ return (entity1, entity2) => {
259
+ const
260
+ a = entity1[name],
261
+ b = entity2[name];
262
+ return sortFn(a, b);
263
+ };
264
+ }
265
+
237
266
  /**
238
267
  * Helper for _applySorters().
239
268
  * Takes a sorter object and returns a valid compare function for use with Array.prototype.sort
@@ -243,10 +272,12 @@ class MemoryRepository extends Repository {
243
272
  * @static
244
273
  */
245
274
  static _getCompareFunction = (sorter) => {
246
- const name = sorter.name,
275
+ const
276
+ name = sorter.name,
247
277
  direction = sorter.direction.toUpperCase();
248
278
  return (entity1, entity2) => {
249
- const a = entity1[name],
279
+ const
280
+ a = entity1[name],
250
281
  b = entity2[name];
251
282
  if (a === b) {
252
283
  return 0;
@@ -1,7 +1,8 @@
1
1
  /** @module Repository */
2
2
 
3
3
  import EventEmitter from '@onehat/events';
4
- import Entity from '../Entity.js';
4
+ import Entity from '../Entity.js'
5
+ import PropertyTypes from '../Property/index.js';
5
6
  import {
6
7
  v4 as uuid,
7
8
  } from 'uuid';
@@ -305,7 +306,7 @@ export default class Repository extends EventEmitter {
305
306
  */
306
307
  _createStatics = () => {
307
308
  if (this.isDestroyed) {
308
- throw Error('this._createStatics is no longer valid. Entity has been destroyed.');
309
+ throw Error('this._createStatics is no longer valid. Repository has been destroyed.');
309
310
  }
310
311
  const staticsDefinitions = this.schema.repository.statics || this.originalConfig.statics; // The latter is mainly for lfr repositories
311
312
  if (!_.isEmpty(staticsDefinitions)) {
@@ -420,6 +421,9 @@ export default class Repository extends EventEmitter {
420
421
  * - repository.sort(); // Reverts back to default sort. To actually *clear* all sorters, use this.clearSort()
421
422
  * - repository.sort('last_name'); // sort by one property, ASC
422
423
  * - repository.sort('last_name', 'ASC'); // sort by one property
424
+ * - repository.sort('last_name', 'ASC', 'natsort'); // sort by one property with specific function
425
+ * - repository.sort('last_name', 'ASC', (a, b) => { ... })); // sort by one property with custom function
426
+ * - repository.sort((a, b) => { ... }); // sort by custom function
423
427
  * - repository.sort({ // sort by one property, object notation
424
428
  * name: 'last_name',
425
429
  * direction: 'ASC',
@@ -428,6 +432,7 @@ export default class Repository extends EventEmitter {
428
432
  * {
429
433
  * name: 'last_name',
430
434
  * direction: 'ASC',
435
+ * fn: 'natsort',
431
436
  * },
432
437
  * {
433
438
  * name: 'first_name',
@@ -438,7 +443,7 @@ export default class Repository extends EventEmitter {
438
443
  *
439
444
  * @return this
440
445
  */
441
- sort = (arg1 = null, arg2 = null) => {
446
+ sort = (arg1 = null, arg2 = 'ASC', arg3 = null) => {
442
447
  if (this.isDestroyed) {
443
448
  throw Error('this.sort is no longer valid. Repository has been destroyed.');
444
449
  }
@@ -446,18 +451,18 @@ export default class Repository extends EventEmitter {
446
451
  let sorters = [];
447
452
  if (_.isNil(arg1)) {
448
453
  sorters = this.getDefaultSorters();
449
- } else if (_.isArray(arg1)) {
450
- sorters = arg1;
451
- } else if (_.isObject(arg1)) { // includes functions
452
- sorters = [arg1];
453
454
  } else if (_.isString(arg1)) {
454
- if (_.isNil(arg2)) {
455
- arg2 = 'ASC';
456
- }
457
455
  sorters = [{
458
456
  name: arg1,
459
457
  direction: arg2,
458
+ fn: arg3,
460
459
  }];
460
+ } else if (_.isPlainObject(arg1)) {
461
+ sorters = [arg1];
462
+ } else if (_.isArray(arg1)) {
463
+ sorters = arg1;
464
+ } else if (_.isFunction(arg1)) {
465
+ sorters = [arg1];
461
466
  }
462
467
 
463
468
  this.setSorters(sorters);
@@ -480,7 +485,8 @@ export default class Repository extends EventEmitter {
480
485
  } else if (!_.isNil(this.schema.model.displayProperty)) {
481
486
  sorters = [{
482
487
  name: this.schema.model.displayProperty,
483
- direction: 'ASC'
488
+ direction: 'ASC',
489
+ fn: 'default',
484
490
  }];
485
491
  }
486
492
  }
@@ -508,16 +514,14 @@ export default class Repository extends EventEmitter {
508
514
  if (_.isFunction(sorter)) {
509
515
  return; // skip
510
516
  }
511
- // This is kind of a hack!
512
- // We get the first entity (assuming any exist) and check its properties.
513
- // TODO: refactor this so we can check even if no entities exist
514
- const entity = this.entities[0];
515
- if (entity) {
516
- const property = entity.getProperty(sorter.name);
517
- if (!property) {
518
- throw new Error('Sorting property does not exist.');
519
- }
520
- if (!property.isSortable) {
517
+ const propertyDefinition = _.find(this.schema.model.properties, (property) => property.name === sorter.name);
518
+ if (!propertyDefinition) {
519
+ throw new Error('Sorting property does not exist.');
520
+ }
521
+ const propertyType = propertyDefinition.type;
522
+ if (propertyType && PropertyTypes[propertyType]) {
523
+ const propertyInstance = new PropertyTypes[propertyType]();
524
+ if (!propertyInstance.isSortable) {
521
525
  throw new Error('Sorting property type is not sortable.');
522
526
  }
523
527
  }
@@ -1327,11 +1331,39 @@ export default class Repository extends EventEmitter {
1327
1331
  */
1328
1332
  getSchema = () => {
1329
1333
  if (this.isDestroyed) {
1330
- throw Error('this.getSchema is no longer valid. Entity has been destroyed.');
1334
+ throw Error('this.getSchema is no longer valid. Repository has been destroyed.');
1331
1335
  }
1332
1336
  return this.schema;
1333
1337
  }
1334
1338
 
1339
+ /**
1340
+ * Gets the sort field, if only one sorter is applied.
1341
+ * @return {Schema} schema
1342
+ */
1343
+ getSortField = () => {
1344
+ if (this.isDestroyed) {
1345
+ throw Error('this.getSortField is no longer valid. Repository has been destroyed.');
1346
+ }
1347
+ if (!this.allowsMultiSort || this.sorters.length < 1) {
1348
+ return null;
1349
+ }
1350
+ return this.sorters[0].name;
1351
+ }
1352
+
1353
+ /**
1354
+ * Gets the sort direction, if only one sorter is applied.
1355
+ * @return {Schema} schema
1356
+ */
1357
+ getSortDirection = () => {
1358
+ if (this.isDestroyed) {
1359
+ throw Error('this.getSortDirection is no longer valid. Repository has been destroyed.');
1360
+ }
1361
+ if (!this.allowsMultiSort || this.sorters.length < 1) {
1362
+ return null;
1363
+ }
1364
+ return this.sorters[0].direction;
1365
+ }
1366
+
1335
1367
  /**
1336
1368
  * Gets the associated Repository
1337
1369
  * @param {string} repositoryName - Name of the Repository to retrieve
@@ -1339,7 +1371,7 @@ export default class Repository extends EventEmitter {
1339
1371
  */
1340
1372
  getAssociatedRepository = (repositoryName) => {
1341
1373
  if (this.isDestroyed) {
1342
- throw Error('this.getAssociatedRepository is no longer valid. Entity has been destroyed.');
1374
+ throw Error('this.getAssociatedRepository is no longer valid. Repository has been destroyed.');
1343
1375
  }
1344
1376
 
1345
1377
  const schema = this.getSchema();
@@ -65,9 +65,10 @@ export default class Schema extends EventEmitter {
65
65
 
66
66
  /**
67
67
  * @member {object[]} sorters - Array of sorter definitions.
68
- * Each definition is an object with two keys:
68
+ * Each definition is an object with two or three keys:
69
69
  * - *name* - Name of Property to sort by.
70
70
  * - *direction* - 'ASC'|'DESC'
71
+ * - *fn* (optional) - The sort function to use. Can be either a name like 'nasort', 'default', or a sorting fn
71
72
  */
72
73
  sorters: [],
73
74