From f5bbf25d4fe19dedf76e84e48672a3fc063de021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9ry=20Debongnie?= Date: Sun, 14 Apr 2019 15:37:27 +0200 Subject: [PATCH] [IMP] store: add deep tracking for changes This is only at the level of the store currently. To be useful, we need to work on the 'connect' function. --- src/store.ts | 30 +++++++++++++++++++----------- tests/store.test.ts | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/store.ts b/src/store.ts index 0d233970..590fc495 100644 --- a/src/store.ts +++ b/src/store.ts @@ -137,18 +137,22 @@ export function makeObserver(): Observer { } if (newVal !== value) { value = newVal; - observe(newVal); + observe(newVal, obj); obj.__owl__.rev!++; observer.rev++; + let parent = obj; + do { + parent.__owl__.deepRev++; + } while ((parent = parent.__owl__.parent)); } } }); - observe(value); + observe(value, obj); } - function observeObj(obj: T) { + function observeObj(obj: T, parent?: any) { const keys = Object.keys(obj); - obj.__owl__ = { rev: 1 }; + obj.__owl__ = { rev: 1, deepRev: 1, parent }; Object.defineProperty(obj, "__owl__", { enumerable: false }); for (let key of keys) { addProp(obj, key, obj[key]); @@ -173,6 +177,10 @@ export function makeObserver(): Observer { ModifiedArrayProto[method] = function(...args) { observer.rev++; this.__owl__.rev++; + let parent = this; + do { + parent.__owl__.deepRev++; + } while ((parent = parent.__owl__.parent)); let inserted; switch (method) { case "push": @@ -185,23 +193,23 @@ export function makeObserver(): Observer { } if (inserted) { for (let elem of inserted) { - observe(elem); + observe(elem, this); } } return initialMethod.call(this, ...args); }; } - function observeArr(arr: Array) { - (arr).__owl__ = { rev: 1 }; + function observeArr(arr: Array, parent?: any) { + (arr).__owl__ = { rev: 1, deepRev: 1, parent }; Object.defineProperty(arr, "__owl__", { enumerable: false }); (arr).__proto__ = ModifiedArrayProto; for (let i = 0; i < arr.length; i++) { - observe(arr[i]); + observe(arr[i], arr); } } - function observe(value: any) { + function observe(value: any, parent?: any) { if (value === null) { // fun fact: typeof null === 'object' return; @@ -214,9 +222,9 @@ export function makeObserver(): Observer { return; } if (Array.isArray(value)) { - observeArr(value); + observeArr(value, parent); } else { - observeObj(value); + observeObj(value, parent); } } diff --git a/tests/store.test.ts b/tests/store.test.ts index 286529dc..01c618d8 100644 --- a/tests/store.test.ts +++ b/tests/store.test.ts @@ -296,6 +296,18 @@ describe("observer", () => { expect(state.arr[0].__owl__.rev).toBe(2); }); + test("properly observe objects in object", () => { + const observer = makeObserver(); + const state: any = { a: { b: 1 } }; + observer.observe(state); + expect(state.__owl__.rev).toBe(1); + expect(state.a.__owl__.rev).toBe(1); + + state.a.b = 2; + expect(state.__owl__.rev).toBe(1); + expect(state.a.__owl__.rev).toBe(2); + }); + test("reobserve new object values", () => { const observer = makeObserver(); const obj: any = { a: 1 }; @@ -312,6 +324,27 @@ describe("observer", () => { expect(obj.a.__owl__.rev).toBe(2); }); + test("deep observe misc changes", () => { + const observer = makeObserver(); + const state: any = { o: { a: 1 }, arr: [1], n: 13 }; + observer.observe(state); + expect(state.__owl__.rev).toBe(1); + expect(state.__owl__.deepRev).toBe(1); + + state.o.a = 2; + expect(observer.rev).toBe(2); + expect(state.__owl__.rev).toBe(1); + expect(state.__owl__.deepRev).toBe(2); + + state.arr.push(2); + expect(state.__owl__.rev).toBe(1); + expect(state.__owl__.deepRev).toBe(3); + + state.n = 155; + expect(state.__owl__.rev).toBe(2); + expect(state.__owl__.deepRev).toBe(4); + }); + test("properly handle already observed state", () => { const observer = makeObserver(); const obj1: any = { a: 1 };