From 88b901d8a50470de991a70d4e55c25108cebb174 Mon Sep 17 00:00:00 2001 From: Ben Gotow Date: Thu, 14 Jan 2016 12:03:06 -0800 Subject: [PATCH] New QueryRange specs, fixes --- .../mutable-query-result-set-spec.coffee | 13 +-- spec/models/query-range-spec.coffee | 88 +++++++++++++++++++ .../models/mutable-query-result-set.coffee | 2 +- src/flux/models/query-range.coffee | 8 +- src/flux/models/query-subscription.coffee | 2 +- 5 files changed, 103 insertions(+), 10 deletions(-) create mode 100644 spec/models/query-range-spec.coffee diff --git a/spec/models/mutable-query-result-set-spec.coffee b/spec/models/mutable-query-result-set-spec.coffee index 5f5caee8d..254ca1786 100644 --- a/spec/models/mutable-query-result-set-spec.coffee +++ b/spec/models/mutable-query-result-set-spec.coffee @@ -70,7 +70,7 @@ describe "MutableQueryResultSet", -> 'C': {id: 'C', clientId: 'C-local'}, }) - describe "addIdsInRange", -> + fdescribe "addIdsInRange", -> describe "when the set is currently empty", -> it "should set the result set to the provided one", -> @set = new MutableQueryResultSet() @@ -101,10 +101,13 @@ describe "MutableQueryResultSet", -> @set.addIdsInRange(['0', '1', '2'], new QueryRange(offset: 2, limit: 3)) .not.toThrow() - it "should throw an exception if the range provided and the ids provided are different lengths", -> - expect => - @set.addIdsInRange(['F', 'G', 'H'], new QueryRange(offset: 10, limit: 5)) - .toThrow() + it "should work if the IDs array is shorter than the result range they represent (addition)", -> + @set.addIdsInRange(['F', 'G', 'H'], new QueryRange(offset: 10, limit: 5)) + expect(@set.ids()).toEqual(['A','B','C','D','E', 'F', 'G', 'H']) + + it "should work if the IDs array is shorter than the result range they represent (replacement)", -> + @set.addIdsInRange(['A', 'B', 'C'], new QueryRange(offset: 5, limit: 5)) + expect(@set.ids()).toEqual(['A','B','C']) it "should correctly add ids (trailing) and update the offset", -> @set.addIdsInRange(['F', 'G', 'H'], new QueryRange(offset: 10, limit: 3)) diff --git a/spec/models/query-range-spec.coffee b/spec/models/query-range-spec.coffee new file mode 100644 index 000000000..4c65090b1 --- /dev/null +++ b/spec/models/query-range-spec.coffee @@ -0,0 +1,88 @@ +QueryRange = require '../../src/flux/models/query-range' + +describe "QueryRange", -> + describe "@infinite", -> + it "should return a query range with a null limit and offset", -> + infinite = QueryRange.infinite() + expect(infinite.limit).toBe(null) + expect(infinite.offset).toBe(null) + + describe "@rangesBySubtracting", -> + it "should throw an exception if either range is infinite", -> + infinite = QueryRange.infinite() + expect -> + QueryRange.rangesBySubtracting(infinite, new QueryRange({offset: 0, limit: 10})) + .toThrow() + expect -> + QueryRange.rangesBySubtracting(new QueryRange({offset: 0, limit: 10}), infinite) + .toThrow() + + it "should return one or more ranges created by punching the provided range", -> + test = ({a, b, result}) -> + expect(QueryRange.rangesBySubtracting(a, b)).toEqual(result) + test + a: new QueryRange(offset: 0, limit: 10), + b: new QueryRange(offset: 3, limit: 3), + result: [new QueryRange(offset: 0, limit: 3), new QueryRange(offset: 6, limit: 4)] + test + a: new QueryRange(offset: 0, limit: 10), + b: new QueryRange(offset: 3, limit: 10), + result: [new QueryRange(offset: 0, limit: 3)] + test + a: new QueryRange(offset: 0, limit: 10), + b: new QueryRange(offset: 0, limit: 10), + result: [] + test + a: new QueryRange(offset: 5, limit: 10), + b: new QueryRange(offset: 0, limit: 4), + result: [new QueryRange(offset: 5, limit: 10)] + test + a: new QueryRange(offset: 5, limit: 10), + b: new QueryRange(offset: 0, limit: 8), + result: [new QueryRange(offset: 8, limit: 7)] + + describe "isInfinite", -> + it "should return true for an infinite range, false otherwise", -> + infinite = QueryRange.infinite() + expect(infinite.isInfinite()).toBe(true) + expect(new QueryRange(offset:0, limit:4).isInfinite()).toBe(false) + + describe "start", -> + it "should be an alias for offset", -> + expect((new QueryRange(offset:3, limit:4)).start).toBe(3) + + describe "end", -> + it "should be offset + limit", -> + expect((new QueryRange(offset:3, limit:4)).end).toBe(7) + + describe "isContiguousWith", -> + it "should return true if either range is infinite", -> + a = new QueryRange(offset:3, limit:4) + expect(a.isContiguousWith(QueryRange.infinite())).toBe(true) + expect(QueryRange.infinite().isContiguousWith(a)).toBe(true) + + it "should return true if the ranges intersect or touch, false otherwise", -> + a = new QueryRange(offset:3, limit:4) + b = new QueryRange(offset:0, limit:2) + c = new QueryRange(offset:0, limit:3) + d = new QueryRange(offset:7, limit:10) + e = new QueryRange(offset:8, limit:10) + + # True + + expect(a.isContiguousWith(d)).toBe(true) + expect(d.isContiguousWith(a)).toBe(true) + + expect(a.isContiguousWith(c)).toBe(true) + expect(c.isContiguousWith(a)).toBe(true) + + # False + + expect(a.isContiguousWith(b)).toBe(false) + expect(b.isContiguousWith(a)).toBe(false) + + expect(a.isContiguousWith(e)).toBe(false) + expect(e.isContiguousWith(a)).toBe(false) + + expect(b.isContiguousWith(e)).toBe(false) + expect(e.isContiguousWith(b)).toBe(false) diff --git a/src/flux/models/mutable-query-result-set.coffee b/src/flux/models/mutable-query-result-set.coffee index f770132ed..022686b4f 100644 --- a/src/flux/models/mutable-query-result-set.coffee +++ b/src/flux/models/mutable-query-result-set.coffee @@ -53,7 +53,7 @@ class MutableQueryResultSet extends QueryResultSet existingBefore = @_ids.slice(0, range.offset - @_offset) existingAfter = [] - if currentEnd > rangeIdsEnd + if rangeIds.length is range.limit and currentEnd > rangeIdsEnd existingAfter = @_ids.slice(rangeIdsEnd - @_offset) @_ids = [].concat(existingBefore, rangeIds, existingAfter) diff --git a/src/flux/models/query-range.coffee b/src/flux/models/query-range.coffee index 4e479ac44..4459495a2 100644 --- a/src/flux/models/query-range.coffee +++ b/src/flux/models/query-range.coffee @@ -4,8 +4,8 @@ class QueryRange @rangeWithUnion: (a, b) -> return QueryRange.infinite() if a.isInfinite() or b.isInfinite() - if not a.intersects(b) - throw new Error('You cannot union ranges which do not overlap.') + if not a.isContiguousWith(b) + throw new Error('You cannot union ranges which do not touch or intersect.') new QueryRange start: Math.min(a.start, b.start) @@ -48,7 +48,9 @@ class QueryRange isEqual: (b) -> return @start is b.start and @end is b.end - intersects: (b) -> + # Returns true if joining the two ranges would not result in empty space. + # ie: they intersect or touch + isContiguousWith: (b) -> return true if @isInfinite() or b.isInfinite() return @start <= b.start <= @end or @start <= b.end <= @end diff --git a/src/flux/models/query-subscription.coffee b/src/flux/models/query-subscription.coffee index bf68ded83..7e98a16f2 100644 --- a/src/flux/models/query-subscription.coffee +++ b/src/flux/models/query-subscription.coffee @@ -141,7 +141,7 @@ class QuerySubscription rangeQuery ?= @_query DatabaseStore.run(rangeQuery, {format: false}).then (results) => - @_set = null unless @_set?.range().intersects(range) + @_set = null unless @_set?.range().isContiguousWith(range) @_set ?= new MutableQueryResultSet() if entireModels