UNPKG

falcor

Version:

A JavaScript library for efficient data fetching.

268 lines (229 loc) 9.38 kB
const falcor = require("../../browser"); const LocalDataSource = require("../data/LocalDataSource"); const after = require("lodash/after"); const strip = require("../cleanData").stripDerefAndVersionKeys; const cacheGenerator = require("../CacheGenerator"); const noOp = () => {}; describe("Request deduping", () => { it("dedupes new requested paths with previous in-flight requests", done => { const onGet = jest.fn(); const model = new falcor.Model({ source: new LocalDataSource( { things: { 0: "thing: 0", 1: "thing: 1", 2: "thing: 2" } }, { wait: 0, onGet } ) }); const partDone = after(2, () => { expect(onGet.mock.calls[1][1]).toEqual([["things", "2"]]); done(); }); model .get(["things", { from: 0, to: 1 }]) .subscribe( response => expect(strip(response.json)).toEqual({ things: { 0: "thing: 0", 1: "thing: 1" } }), done, partDone ); model .get(["things", { from: 1, to: 2 }]) .subscribe( response => expect(strip(response.json)).toEqual({ things: { 1: "thing: 1", 2: "thing: 2" } }), done, partDone ); }); describe("dedupes from both ends of overlapping key sets", () => { const onGet = jest.fn(); const model = new falcor.Model({ source: new LocalDataSource( { things: { 0: "thing: 0", 1: "thing: 1", 2: "thing: 2", 3: "thing: 3", 4: "thing: 4", 5: "thing: 5" } }, { wait: 0, onGet } ) }); beforeEach(() => { onGet.mockClear(); model.setCache({}); }); it("using ranges", done => { const partDone = after(2, () => { expect(onGet.mock.calls[1][1]).toEqual([["things", [0, 3]]]); done(); }); model.get(["things", { from: 1, to: 2 }]).subscribe(noOp, done, partDone); model.get(["things", { from: 0, to: 3 }]).subscribe(noOp, done, partDone); }); it("using arrays", done => { const partDone = after(2, () => { expect(onGet.mock.calls[1][1]).toEqual([["things", [0, 5]]]); done(); }); model.get(["things", [2, 4]]).subscribe(noOp, done, partDone); model.get(["things", [0, 4, 5]]).subscribe(noOp, done, partDone); }); it("from range to array", done => { const partDone = after(2, () => { expect(onGet.mock.calls[1][1]).toEqual([["things", [0, 5]]]); done(); }); model.get(["things", { from: 2, to: 3 }]).subscribe(noOp, done, partDone); model.get(["things", [0, 3, 5]]).subscribe(noOp, done, partDone); }); it("from array to range", done => { const partDone = after(2, () => { expect(onGet.mock.calls[1][1]).toEqual([["things", [2, 4]]]); done(); }); model.get(["things", [0, 3, 5]]).subscribe(noOp, done, partDone); model.get(["things", { from: 2, to: 4 }]).subscribe(noOp, done, partDone); }); }); it("leaves ranges unrolled if possible", done => { const onGet = jest.fn(); const model = new falcor.Model({ source: new LocalDataSource( { things: { 0: "thing: 0", 1: "thing: 1", 2: "thing: 2", 3: "thing: 3" } }, { wait: 0, onGet } ) }); const partDone = after(2, () => { expect(onGet.mock.calls[1][1]).toEqual([["things", { from: 2, to: 3 }]]); done(); }); model.get(["things", { from: 0, to: 1 }]).subscribe(noOp, done, partDone); model.get(["things", { from: 0, to: 3 }]).subscribe(noOp, done, partDone); }); it("handles properties after ranges", done => { const onGet = jest.fn(); const model = new falcor.Model({ source: new LocalDataSource( { things: { 0: { name: "thing: 0" }, 1: { name: "thing: 1" }, 2: { name: "thing: 2" }, 3: { name: "thing: 3" } } }, { wait: 0, onGet } ) }); const partDone = after(2, () => { expect(onGet.mock.calls[1][1]).toEqual([["things", { from: 2, to: 3 }, "name"]]); done(); }); model.get(["things", { from: 0, to: 1 }, "name"]).subscribe(noOp, done, partDone); model.get(["things", { from: 1, to: 3 }, "name"]).subscribe(noOp, done, partDone); }); it("handles multiple ranges in path sets", done => { const onGet = jest.fn(); const model = new falcor.Model({ source: new LocalDataSource( { things: { 0: { name: "thing: 0", tags: { 0: "t0 tag: 0", 1: "t0 tag: 1", 2: "t0 tag: 2" } }, 1: { name: "thing: 1", tags: { 0: "t1 tag: 0", 1: "t1 tag: 1", 2: "t1 tag: 2" } }, 2: { name: "thing: 2", tags: { 0: "t2 tag: 0", 1: "t2 tag: 1", 2: "t2 tag: 2" } } } }, { wait: 0, onGet } ) }); const partDone = after(2, () => { expect(onGet.mock.calls[1][1]).toEqual([ ["things", { from: 0, to: 1 }, "tags", "0"], ["things", 2, "tags", { from: 0, to: 2 }] ]); done(); }); model.get(["things", { from: 0, to: 1 }, "tags", { from: 1, to: 2 }]).subscribe(noOp, done, partDone); model.get(["things", { from: 0, to: 2 }, "tags", { from: 0, to: 2 }]).subscribe(noOp, done, partDone); }); it("handles optimized and requested paths of different lengths", done => { const onGet = jest.fn(); const model = new falcor.Model({ source: new LocalDataSource( { things: { 0: { tags: { 0: "t0 tag: 0", 1: "t0 tag: 1" } } }, oneoff: { tags: { 0: "t2 tag: 0", 1: "t2 tag: 1" } }, thang: { that: { really: { is: { a: { thing: { of: { course: { tags: { 0: "thang tag: 0", 1: "thang tag: 1" } } } } } } } } } }, { wait: 0, onGet } ), cache: { things: { 1: falcor.Model.ref("thang.that.really.is.a.thing.of.course"), 2: falcor.Model.ref("oneoff") } } }); const partDone = after(2, () => { expect(onGet.mock.calls[1][1]).toEqual([ ["oneoff", "tags", { from: 0, to: 1 }], ["things", 0, "tags", "1"], ["thang", "that", "really", "is", "a", "thing", "of", "course", "tags", { from: 0, to: 1 }] ]); done(); }); model.get(["things", 0, "tags", 0]).subscribe(noOp, done, partDone); // path length differences: // things[0].tags[0,1] -> requested: 4, optimized: 4 // things[1].tags[0,1] -> requested: 4, optimized: 10 // things[2].tags[0,1] -> requested: 4, optimized: 3 model.get(["things", { from: 0, to: 2 }, "tags", { from: 0, to: 1 }]).subscribe(noOp, done, partDone); }); it("deduplicates gets with overlapping ranges", done => { const onGet = jest.fn(); const model = new falcor.Model({ source: new LocalDataSource(cacheGenerator(0, 3), { wait: 0, onGet }) }); const partDone = after(3, () => { expect(onGet.mock.calls[0][1]).toEqual([["videos", 0, "title"]]); expect(onGet.mock.calls[1][1]).toEqual([["videos", 1, "title"]]); expect(onGet.mock.calls[2][1]).toEqual([["videos", 2, "title"]]); done(); }); model.get(["videos", 0, "title"]).subscribe(noOp, done, partDone); model.get(["videos", 1, "title"]).subscribe(noOp, done, partDone); model.get(["videos", [0, 1, 2], "title"]).subscribe(noOp, done, partDone); }); });