diff --git a/src/decorators/memoize.ts b/src/decorators/memoize.ts index 9f6b353..622be24 100644 --- a/src/decorators/memoize.ts +++ b/src/decorators/memoize.ts @@ -1,8 +1,17 @@ -export function Memoize(): Function { +export function Memoize(propsToWatch?: string[]): Function { + const hasPropsToWatch = typeof propsToWatch !== 'undefined' && Array.isArray(propsToWatch); + if (typeof propsToWatch !== 'undefined' && !hasPropsToWatch) { + throw new Error('Somethings wrong with the propsToWatch Array'); + } return function(target: any, propertyKey: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function(this: any, ...args: any[]) { - const reflectKey = `${JSON.stringify(this)}_${JSON.stringify(args)}_${propertyKey}`; + let modelKeyPart = this; + if (hasPropsToWatch) { + const filteredEntries = Object.entries(this).filter(([k,v]) => propsToWatch.includes(k)) + modelKeyPart = Object.fromEntries(filteredEntries); + } + const reflectKey = `${JSON.stringify(modelKeyPart)}_${JSON.stringify(args)}_${propertyKey}`; const hasReflectData = Reflect.hasMetadata(reflectKey, target); if (hasReflectData) { diff --git a/tests/decorators/memoize.spec.ts b/tests/decorators/memoize.spec.ts index 6311167..0aac41f 100644 --- a/tests/decorators/memoize.spec.ts +++ b/tests/decorators/memoize.spec.ts @@ -9,8 +9,32 @@ class MemoizeTestModel extends Serde { } } +class MemoizeArgsTestModel extends Serde { + name: string; + @Memoize() doNameRandom(t: string): string { + return this.name + t + (Math.random() * 10); + } +} + +class MemoizePropsToWatchTestModel extends Serde { + name: string; + desc: string + @Memoize(['name']) doNameRandom(): string { + return this.name + (Math.random() * 10); + } +} + +class MemoizePropsToWatchArgsTestModel extends Serde { + name: string; + desc: string + @Memoize(['name']) doNameRandom(t: string): string { + return this.name + t + (Math.random() * 10); + } +} + + describe('@Memoize() Decorator', () => { - it('should remember...', () => { + it('should remember, no args or propsToWatch', () => { const testModel = new MemoizeTestModel().deserialize({ name: 'test model', }); @@ -19,4 +43,48 @@ describe('@Memoize() Decorator', () => { const result2 = testModel.doNameRandom(); expect(result1).toBe(result2); }); + + it('should remember with args, no propsToWatch', () => { + const testModel = new MemoizeArgsTestModel().deserialize({ + name: 'test model', + }); + + const result1 = testModel.doNameRandom('t'); + const result1a = testModel.doNameRandom('t'); + const result2 = testModel.doNameRandom('r'); + expect(result1).toBe(result1a); + expect(result1).not.toBe(result2); + }); + + it('should remember with propsToWatch, no args', () => { + const testModel = new MemoizePropsToWatchTestModel().deserialize({ + name: 'test model', + desc: 'this is a desc' + }); + + const result1 = testModel.doNameRandom(); + testModel.desc = 'this is a desc updated' + const result2 = testModel.doNameRandom(); + testModel.name = 'test model updated'; + const result1a = testModel.doNameRandom(); + expect(result1).toBe(result2); + expect(result1).not.toBe(result1a); + }); + + it('should remember with propsToWatch, and args', () => { + const testModel = new MemoizePropsToWatchArgsTestModel().deserialize({ + name: 'test model', + desc: 'this is a desc' + }); + + const result1 = testModel.doNameRandom('t'); + const result1a = testModel.doNameRandom('t'); + testModel.desc = 'this is a desc updated' + const result2 = testModel.doNameRandom('r'); + testModel.name = 'test model updated'; + const result1b = testModel.doNameRandom('t'); + expect(result1).not.toBe(result2); + expect(result1).toBe(result1a); + expect(result1).not.toBe(result1b); + }); }); \ No newline at end of file