From 506590b75a44e0ebed435b9038039e92acb5d50d Mon Sep 17 00:00:00 2001 From: Ivica Batinic Date: Tue, 18 May 2021 23:51:01 +0200 Subject: [PATCH 1/3] Add support for compare fn on View.sortMethod --- packages/datx/src/View.ts | 18 +++++++++----- packages/datx/src/helpers/view.ts | 5 ++++ packages/datx/src/types.ts | 3 +++ packages/datx/test/view.ts | 40 ++++++++++++++++++++++++++++++- 4 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 packages/datx/src/helpers/view.ts create mode 100644 packages/datx/src/types.ts diff --git a/packages/datx/src/View.ts b/packages/datx/src/View.ts index fd73de50e..50bdad822 100644 --- a/packages/datx/src/View.ts +++ b/packages/datx/src/View.ts @@ -3,6 +3,7 @@ import { action, computed, intercept, IObservableArray, observable, reaction } f import { SORTED_NO_WRITE, UNIQUE_MODEL } from './errors'; import { error } from './helpers/format'; +import { isPropertySelectorFn } from './helpers/view'; import { getModelId, getModelType } from './helpers/model/utils'; import { IIdentifier } from './interfaces/IIdentifier'; import { IModelConstructor } from './interfaces/IModelConstructor'; @@ -11,17 +12,18 @@ import { IType } from './interfaces/IType'; import { TChange } from './interfaces/TChange'; import { PureCollection } from './PureCollection'; import { PureModel } from './PureModel'; +import { SortMethod } from './types'; export class View { public readonly modelType: IType; - @observable public sortMethod?: string|((item: T) => any); + @observable public sortMethod?: SortMethod; private readonly __models: IObservableArray = observable.array([]); constructor( modelType: IModelConstructor|IType, protected __collection: PureCollection, - sortMethod?: string|((item: T) => any), + sortMethod?: SortMethod, models: Array = [], public unique: boolean = false, ) { @@ -55,10 +57,14 @@ export class View { .filter(Boolean) as Array; if (this.sortMethod) { - const sortFn = typeof this.sortMethod === 'string' - ? (item) => item[this.sortMethod as 'string'] - : this.sortMethod; - list.sort((a: T, b: T) => sortFn(a) - sortFn(b)); + const sortFn = + typeof this.sortMethod === 'string' ? (item) => item[this.sortMethod as 'string'] : this.sortMethod; + + if (isPropertySelectorFn(sortFn)) { + list.sort((a: T, b: T) => sortFn(a) - sortFn(b)); + } else { + list.sort(sortFn); + } } const instances = observable.array(list, { deep: false }); diff --git a/packages/datx/src/helpers/view.ts b/packages/datx/src/helpers/view.ts new file mode 100644 index 000000000..7c3ef2d41 --- /dev/null +++ b/packages/datx/src/helpers/view.ts @@ -0,0 +1,5 @@ +import { CompareFn, PropertySelectorFn } from '../types'; + +export function isPropertySelectorFn(fn: PropertySelectorFn | CompareFn): fn is PropertySelectorFn { + return fn.length === 1; +} diff --git a/packages/datx/src/types.ts b/packages/datx/src/types.ts new file mode 100644 index 000000000..554f2f7e3 --- /dev/null +++ b/packages/datx/src/types.ts @@ -0,0 +1,3 @@ +export type PropertySelectorFn = (item: T) => any; +export type CompareFn = (a: T, b: T) => number; +export type SortMethod = string | PropertySelectorFn | CompareFn; diff --git a/packages/datx/test/view.ts b/packages/datx/test/view.ts index 3593fab0a..4eab737dc 100644 --- a/packages/datx/test/view.ts +++ b/packages/datx/test/view.ts @@ -13,7 +13,7 @@ import { view, } from '../src'; -describe('Model', () => { +describe('view', () => { it('should init a view', () => { const collection = new Collection(); const viewInstance = new View('foo', collection); @@ -198,6 +198,44 @@ describe('Model', () => { expect(item2b && item2b.key).toBe(2); }); + it('should be able to sort with compare function and none unique props', () => { + class Foo extends Model { + public static type = 'foo'; + + @prop public notUnique!: number; + @prop public unique!: number; + } + class AppCollection extends Collection { + public static types = [Foo]; + } + + const collection = new AppCollection(); + const foos = collection.add([{ notUnique: 2, unique: 3 }, { notUnique: 2, unique: 1 }, { notUnique: 1, unique: 2 }], Foo); + + const compareFn = (a: Foo, b: Foo): number => { + if (a.notUnique === b.notUnique){ + return a.unique < b.unique ? -1 : 1 + } else { + return a.notUnique < b.notUnique ? -1 : 1 + } + } + + const viewInstance = new View(Foo, collection, compareFn, foos); + + console.log(JSON.stringify(viewInstance.list)); + + expect(viewInstance.length).toBe(3); + const item0a = viewInstance.list[0]; + const item1a = viewInstance.list[1]; + const item2a = viewInstance.list[2]; + expect(item0a && item0a.notUnique).toBe(1); + expect(item0a && item0a.unique).toBe(2); + expect(item1a && item1a.notUnique).toBe(2); + expect(item1a && item1a.unique).toBe(1); + expect(item2a && item2a.notUnique).toBe(2); + expect(item2a && item2a.unique).toBe(3); + }); + it('should be able to remove models', () => { class Foo extends Model { public static type = 'foo'; From cd3b69d8e454f4d420448df6ef76a13bf9de88be Mon Sep 17 00:00:00 2001 From: Ivica Batinic Date: Tue, 18 May 2021 23:54:00 +0200 Subject: [PATCH 2/3] typo --- packages/datx/test/view.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/datx/test/view.ts b/packages/datx/test/view.ts index 4eab737dc..f3f3cd1a8 100644 --- a/packages/datx/test/view.ts +++ b/packages/datx/test/view.ts @@ -198,7 +198,7 @@ describe('view', () => { expect(item2b && item2b.key).toBe(2); }); - it('should be able to sort with compare function and none unique props', () => { + it('should be able to sort with compare function and non-unique props', () => { class Foo extends Model { public static type = 'foo'; From 09830662ec36928f508253359d444b530e0f8961 Mon Sep 17 00:00:00 2001 From: Ivica Batinic Date: Sat, 22 May 2021 11:59:28 +0200 Subject: [PATCH 3/3] Move types to interfaces folder --- packages/datx/src/View.ts | 6 +++--- packages/datx/src/helpers/view.ts | 5 +++-- packages/datx/src/index.ts | 1 + packages/datx/src/interfaces/IView.ts | 3 +++ packages/datx/src/types.ts | 3 --- packages/datx/test/view.ts | 2 -- 6 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 packages/datx/src/interfaces/IView.ts delete mode 100644 packages/datx/src/types.ts diff --git a/packages/datx/src/View.ts b/packages/datx/src/View.ts index 50bdad822..348d42765 100644 --- a/packages/datx/src/View.ts +++ b/packages/datx/src/View.ts @@ -10,20 +10,20 @@ import { IModelConstructor } from './interfaces/IModelConstructor'; import { IRawView } from './interfaces/IRawView'; import { IType } from './interfaces/IType'; import { TChange } from './interfaces/TChange'; +import { ISortMethod } from './interfaces/IView'; import { PureCollection } from './PureCollection'; import { PureModel } from './PureModel'; -import { SortMethod } from './types'; export class View { public readonly modelType: IType; - @observable public sortMethod?: SortMethod; + @observable public sortMethod?: ISortMethod; private readonly __models: IObservableArray = observable.array([]); constructor( modelType: IModelConstructor|IType, protected __collection: PureCollection, - sortMethod?: SortMethod, + sortMethod?: ISortMethod, models: Array = [], public unique: boolean = false, ) { diff --git a/packages/datx/src/helpers/view.ts b/packages/datx/src/helpers/view.ts index 7c3ef2d41..ccf5944aa 100644 --- a/packages/datx/src/helpers/view.ts +++ b/packages/datx/src/helpers/view.ts @@ -1,5 +1,6 @@ -import { CompareFn, PropertySelectorFn } from '../types'; +import { ICompareFn, IPropertySelectorFn } from "../interfaces/IView"; -export function isPropertySelectorFn(fn: PropertySelectorFn | CompareFn): fn is PropertySelectorFn { + +export function isPropertySelectorFn(fn: IPropertySelectorFn | ICompareFn): fn is IPropertySelectorFn { return fn.length === 1; } diff --git a/packages/datx/src/index.ts b/packages/datx/src/index.ts index a4f5107b1..b57d22b05 100644 --- a/packages/datx/src/index.ts +++ b/packages/datx/src/index.ts @@ -47,6 +47,7 @@ export { IReferenceOptions } from './interfaces/IReferenceOptions'; export { IViewConstructor } from './interfaces/IViewConstructor'; export { IActionsMixin } from './interfaces/IActionsMixin'; export { IMetaMixin } from './interfaces/IMetaMixin'; +export { ISortMethod } from './interfaces/IView'; export { PatchType } from './enums/PatchType'; export { ReferenceType } from './enums/ReferenceType'; diff --git a/packages/datx/src/interfaces/IView.ts b/packages/datx/src/interfaces/IView.ts new file mode 100644 index 000000000..03cb4ccdf --- /dev/null +++ b/packages/datx/src/interfaces/IView.ts @@ -0,0 +1,3 @@ +export type IPropertySelectorFn = (item: T) => any; +export type ICompareFn = (a: T, b: T) => number; +export type ISortMethod = string | IPropertySelectorFn | ICompareFn; diff --git a/packages/datx/src/types.ts b/packages/datx/src/types.ts deleted file mode 100644 index 554f2f7e3..000000000 --- a/packages/datx/src/types.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type PropertySelectorFn = (item: T) => any; -export type CompareFn = (a: T, b: T) => number; -export type SortMethod = string | PropertySelectorFn | CompareFn; diff --git a/packages/datx/test/view.ts b/packages/datx/test/view.ts index f3f3cd1a8..8a3e0b3af 100644 --- a/packages/datx/test/view.ts +++ b/packages/datx/test/view.ts @@ -222,8 +222,6 @@ describe('view', () => { const viewInstance = new View(Foo, collection, compareFn, foos); - console.log(JSON.stringify(viewInstance.list)); - expect(viewInstance.length).toBe(3); const item0a = viewInstance.list[0]; const item1a = viewInstance.list[1];