Mailspring/spec/models/query-subscription-spec.coffee
Ben Gotow 62fab52f7b feat(observables): Implementation of observables to replace some stores
Summary:
Add concept of "final" to Query, clean up internals

Tiny bug fixes

RxJs Observables!

WIP

Test Plan: Run tests

Reviewers: evan, juan

Reviewed By: juan

Differential Revision: https://phab.nylas.com/D2319
2015-12-07 16:52:46 -08:00

257 lines
11 KiB
CoffeeScript

DatabaseStore = require '../../src/flux/stores/database-store'
QuerySubscription = require '../../src/flux/models/query-subscription'
Thread = require '../../src/flux/models/thread'
Label = require '../../src/flux/models/label'
Utils = require '../../src/flux/models/utils'
describe "QuerySubscription", ->
describe "constructor", ->
it "should throw an error if the query is a count query", ->
query = DatabaseStore.findAll(Label).count()
expect( => new QuerySubscription(query)).toThrow()
it "should throw an error if a query is not provided", ->
expect( => new QuerySubscription({})).toThrow()
it "should fetch an initial result set", ->
spyOn(QuerySubscription.prototype, '_refetchResultSet')
sub = new QuerySubscription(DatabaseStore.findAll(Label))
expect(QuerySubscription.prototype._refetchResultSet).toHaveBeenCalled()
describe "applyChangeRecord", ->
spyOn(Utils, 'generateTempId').andCallFake => ""
scenarios = [{
name: "query with full set of objects (4)"
query: DatabaseStore.findAll(Thread)
.where(Thread.attributes.accountId.equal('a'))
.limit(4)
.offset(2)
lastResultSet: [
new Thread(accountId: 'a', id: '4', lastMessageReceivedTimestamp: 4)
new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 3),
new Thread(accountId: 'a', id: '2', lastMessageReceivedTimestamp: 2),
new Thread(accountId: 'a', id: '1', lastMessageReceivedTimestamp: 1),
]
tests: [{
name: 'Item saved which belongs in the set'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'a', id: '5', lastMessageReceivedTimestamp: 3.5)]
type: 'persist'
newResultSet:[
new Thread(accountId: 'a', id: '4', lastMessageReceivedTimestamp: 4),
new Thread(accountId: 'a', id: '5', lastMessageReceivedTimestamp: 3.5),
new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 3),
new Thread(accountId: 'a', id: '2', lastMessageReceivedTimestamp: 2),
]
refetchRequired: false
},{
name: 'Item saved which does not match query clauses'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'b', id: '5', lastMessageReceivedTimestamp: 5)]
type: 'persist'
newResultSet: 'unchanged'
refetchRequired: false
},{
name: 'Item saved which does not lie in the range after sorting'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'b', id: '5', lastMessageReceivedTimestamp: -2)]
type: 'persist'
newResultSet: 'unchanged'
refetchRequired: false
},{
name: 'Item in set saved'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'a', id: '4', lastMessageReceivedTimestamp: 4, subject: 'hello')]
type: 'persist'
newResultSet:[
new Thread(accountId: 'a', id: '4', lastMessageReceivedTimestamp: 4, subject: 'hello')
new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 3),
new Thread(accountId: 'a', id: '2', lastMessageReceivedTimestamp: 2),
new Thread(accountId: 'a', id: '1', lastMessageReceivedTimestamp: 1),
]
refetchRequired: false
},{
name: 'Item in set saved, sort order changed (within range only)'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 1.5)]
type: 'persist'
newResultSet:[
new Thread(accountId: 'a', id: '4', lastMessageReceivedTimestamp: 4),
new Thread(accountId: 'a', id: '2', lastMessageReceivedTimestamp: 2),
new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 1.5),
new Thread(accountId: 'a', id: '1', lastMessageReceivedTimestamp: 1),
]
refetchRequired: false
},{
name: 'Item in set saved, sort order changed and sorted to edge of set (impacting last)'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 6)]
type: 'persist'
refetchRequired: true
},{
name: 'Item in set saved, sort order changed and sorted to edge of set (impacting first)'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: -1)]
type: 'persist'
refetchRequired: true
},{
name: 'Item in set saved, no longer matches query clauses'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'b', id: '4', lastMessageReceivedTimestamp: 4)]
type: 'persist'
newResultSet: [
new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 3),
new Thread(accountId: 'a', id: '2', lastMessageReceivedTimestamp: 2),
new Thread(accountId: 'a', id: '1', lastMessageReceivedTimestamp: 1),
]
refetchRequired: true
},{
name: 'Item in set deleted'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'a', id: '4')]
type: 'unpersist'
newResultSet: [
new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 3),
new Thread(accountId: 'a', id: '2', lastMessageReceivedTimestamp: 2),
new Thread(accountId: 'a', id: '1', lastMessageReceivedTimestamp: 1),
]
refetchRequired: true
},{
name: 'Item not in set deleted'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'a', id: '5')]
type: 'unpersist'
newResultSet: 'unchanged'
refetchRequired: false
}]
},{
name: "query with fewer than LIMIT objects"
query: DatabaseStore.findAll(Thread)
.where(Thread.attributes.accountId.equal('a'))
.limit(4)
.offset(2)
lastResultSet: [
new Thread(accountId: 'a', id: '4', lastMessageReceivedTimestamp: 4)
new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 3),
new Thread(accountId: 'a', id: '2', lastMessageReceivedTimestamp: 2)
]
tests: [{
name: 'Item in set saved, no longer matches query clauses'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'b', id: '4', lastMessageReceivedTimestamp: 4)]
type: 'persist'
newResultSet: [
new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 3),
new Thread(accountId: 'a', id: '2', lastMessageReceivedTimestamp: 2),
]
refetchRequired: false
},{
name: 'Item in set deleted'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'a', id: '4')]
type: 'unpersist'
newResultSet: [
new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 3),
new Thread(accountId: 'a', id: '2', lastMessageReceivedTimestamp: 2),
]
refetchRequired: false
}]
},{
name: "query with ASC sort order"
query: DatabaseStore.findAll(Thread)
.where(Thread.attributes.accountId.equal('a'))
.limit(4)
.offset(2)
.order(Thread.attributes.lastMessageReceivedTimestamp.ascending())
lastResultSet: [
new Thread(accountId: 'a', id: '1', lastMessageReceivedTimestamp: 1)
new Thread(accountId: 'a', id: '2', lastMessageReceivedTimestamp: 2)
new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 3)
new Thread(accountId: 'a', id: '4', lastMessageReceivedTimestamp: 4)
]
tests: [{
name: 'Item in set saved, sort order changed'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 1.5)]
type: 'persist'
newResultSet:[
new Thread(accountId: 'a', id: '1', lastMessageReceivedTimestamp: 1)
new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 1.5)
new Thread(accountId: 'a', id: '2', lastMessageReceivedTimestamp: 2)
new Thread(accountId: 'a', id: '4', lastMessageReceivedTimestamp: 4)
]
refetchRequired: false
}]
},{
name: "query with multiple sort orders"
query: DatabaseStore.findAll(Thread)
.where(Thread.attributes.accountId.equal('a'))
.limit(4)
.offset(2)
.order([
Thread.attributes.lastMessageReceivedTimestamp.ascending(),
Thread.attributes.unread.descending()
])
lastResultSet: [
new Thread(accountId: 'a', id: '1', lastMessageReceivedTimestamp: 1, unread: true)
new Thread(accountId: 'a', id: '2', lastMessageReceivedTimestamp: 1, unread: false)
new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 1, unread: false)
new Thread(accountId: 'a', id: '4', lastMessageReceivedTimestamp: 2, unread: true)
]
tests: [{
name: 'Item in set saved, secondary sort order changed'
change:
objectClass: Thread.name
objects: [new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 1, unread: true)]
type: 'persist'
newResultSet:[
new Thread(accountId: 'a', id: '1', lastMessageReceivedTimestamp: 1, unread: true)
new Thread(accountId: 'a', id: '3', lastMessageReceivedTimestamp: 1, unread: true)
new Thread(accountId: 'a', id: '2', lastMessageReceivedTimestamp: 1, unread: false)
new Thread(accountId: 'a', id: '4', lastMessageReceivedTimestamp: 2, unread: true)
]
refetchRequired: false
}]
}]
jasmine.unspy(Utils, 'generateTempId')
describe "scenarios", ->
scenarios.forEach (scenario) =>
scenario.tests.forEach (test) =>
it "with #{scenario.name}, should correctly apply #{test.name}", ->
@q = new QuerySubscription(scenario.query, -> )
@q._lastResultSet = scenario.lastResultSet
spyOn(@q, '_invokeCallbacks')
spyOn(@q, '_refetchResultSet')
@q.applyChangeRecord(test.change)
if test.newResultSet is 'unchanged'
expect(@q._invokeCallbacks).not.toHaveBeenCalled()
expect(@q._lastResultSet).toEqual(scenario.lastResultSet)
else if test.newResultSet
expect(@q._invokeCallbacks).toHaveBeenCalled()
expect(@q._lastResultSet).toEqual(test.newResultSet)
if test.refetchRequired
expect(@q._refetchResultSet).toHaveBeenCalled()
else
expect(@q._refetchResultSet).not.toHaveBeenCalled()