Skip to content

Commit

Permalink
feat(store,storeconfig): config for deepFreeze function
Browse files Browse the repository at this point in the history
Adds deepFreezeFunction in StoreConfigOptions and unit tests for feature
Can use custom deepFreeze for complex objects in store

Resolves salesforce#124
  • Loading branch information
orangeswim committed Apr 17, 2019
1 parent eea3106 commit 1d7535c
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 1 deletion.
79 changes: 79 additions & 0 deletions akita/__tests__/deepFreeze.spec.ts
@@ -0,0 +1,79 @@
import { Store } from '../src/store';
import { StoreConfig } from '../src/storeConfig';
import { deepFreeze } from '../src/deepFreeze';

class SpecialObject {
specialString: string = 'special';
specialNumber: number = 2;

constructor(params: Partial<ComplexState>) {
Object.assign(this, params);
}
}

class ComplexState {
propertyString: string = '';
propertyNumber: number = 1;
specialObject: SpecialObject = new SpecialObject({});

constructor(params: Partial<ComplexState>) {
Object.assign(this, params);
}
}

@StoreConfig({
name: 'complexState'
})
class ComplexStore extends Store<ComplexState> {
constructor() {
super(new ComplexState({}));
}
}

const complexStore = new ComplexStore();

describe('store with no custom deepFreeze', () => {
it('should use default function', () => {
expect(complexStore.deepFreeze).toEqual(deepFreeze);
});

it('should freeze all properties', () => {
expect(Object.isFrozen(complexStore._value().propertyNumber)).toBeTruthy();
expect(Object.isFrozen(complexStore._value().propertyString)).toBeTruthy();
expect(Object.isFrozen(complexStore._value().specialObject)).toBeTruthy();
expect(Object.isFrozen(complexStore._value().specialObject.specialNumber)).toBeTruthy();
expect(Object.isFrozen(complexStore._value().specialObject.specialString)).toBeTruthy();
});
});

function deepFreezeCustom(o: ComplexState) {
Object.freeze(o);

return o;
}

@StoreConfig({
name: 'complexState2',
deepFreezeFunction: deepFreezeCustom
})
class ComplexStoreCustom extends Store<ComplexState> {
constructor() {
super(new ComplexState({}));
}
}

const complexStoreCustom = new ComplexStoreCustom();

describe('store with custom deepFreeze', () => {
it('should use custom function', () => {
expect(complexStoreCustom.deepFreeze).toEqual(deepFreezeCustom);
});

it('should not freeze all properties', () => {
expect(Object.isFrozen(complexStoreCustom._value().propertyNumber)).toBeTruthy();
expect(Object.isFrozen(complexStoreCustom._value().propertyString)).toBeTruthy();
expect(Object.isFrozen(complexStoreCustom._value().specialObject)).toBeFalsy();
expect(Object.isFrozen(complexStoreCustom._value().specialObject.specialNumber)).toBeTruthy();
expect(Object.isFrozen(complexStoreCustom._value().specialObject.specialString)).toBeTruthy();
});
});
7 changes: 6 additions & 1 deletion akita/src/store.ts
Expand Up @@ -133,14 +133,19 @@ export class Store<S> {
return this.config.idKey || this.options.idKey || DEFAULT_ID_KEY;
}

// @internal
get deepFreeze() {
return this.config.deepFreezeFunction || this.options.deepFreezeFunction || deepFreeze;
}

// @internal
get cacheConfig() {
return this.config.cache || this.options.cache;
}

// @internal
_setState(newStateFn: (state: Readonly<S>) => S, _dispatchAction = true) {
this.storeValue = __DEV__ ? deepFreeze(newStateFn(this._value())) : newStateFn(this._value());
this.storeValue = __DEV__ ? this.deepFreeze(newStateFn(this._value())) : newStateFn(this._value());

if (!this.store) {
this.store = new BehaviorSubject(this.storeValue);
Expand Down
1 change: 1 addition & 0 deletions akita/src/storeConfig.ts
Expand Up @@ -4,6 +4,7 @@ export type StoreConfigOptions = {
idKey?: string;
storeName?: string;
cache?: { ttl: number };
deepFreezeFunction?: (o: any) => any;
};

export type UpdatableStoreConfigOptions = {
Expand Down

0 comments on commit 1d7535c

Please sign in to comment.