More database-related spec fixes

This commit is contained in:
Ben Gotow 2016-01-25 11:35:11 -08:00
parent 6a28cd8cda
commit c9e5b68f16
9 changed files with 61 additions and 72 deletions

View file

@ -244,7 +244,7 @@ class MessageList extends React.Component
</div>
_renderLabels: =>
labels = @state.currentThread.sortedLabels()
labels = @state.currentThread.sortedCategories()
labels = _.reject labels, (l) -> l.name is 'important'
labels.map (label) =>
<MailLabel label={label} key={label.id} onRemove={ => @_onRemoveLabel(label) }/>

View file

@ -70,7 +70,7 @@ c3 = new ListTabular.Column
ignoredIds = _.pluck(currentCategories, 'id')
ignoredIds.push(cat.id) for cat in CategoryStore.hiddenCategories(account)
for label in (thread.sortedLabels())
for label in (thread.sortedCategories())
continue if label.id in ignoredIds
c3LabelComponentCache[label.id] ?= <MailLabel label={label} key={label.id} />
labels.push c3LabelComponentCache[label.id]

View file

@ -2,7 +2,7 @@ _ = require 'underscore'
Contact = require '../../../src/flux/models/contact'
Message = require '../../../src/flux/models/message'
Thread = require '../../../src/flux/models/thread'
Label = require '../../../src/flux/models/label'
Category = require '../../../src/flux/models/category'
CategoryStore = require '../../../src/flux/stores/category-store'
DatabaseStore = require '../../../src/flux/stores/database-store'
AccountStore = require '../../../src/flux/stores/account-store'
@ -14,17 +14,17 @@ describe "UnreadNotifications", ->
beforeEach ->
Main.activate()
inbox = new Label(id: "l1", name: "inbox", displayName: "Inbox")
archive = new Label(id: "l2", name: "archive", displayName: "Archive")
inbox = new Category(id: "l1", name: "inbox", displayName: "Inbox")
archive = new Category(id: "l2", name: "archive", displayName: "Archive")
spyOn(CategoryStore, "getStandardCategory").andReturn inbox
account = AccountStore.accounts()[0]
@threadA = new Thread
labels: [inbox]
categories: [inbox]
@threadB = new Thread
labels: [archive]
categories: [archive]
@msg1 = new Message
unread: true

View file

@ -12,7 +12,7 @@ describe "ModelQuery", ->
beforeEach ->
@q = new ModelQuery(Thread, @db)
@m1 = Thread.attributes.id.equal(4)
@m2 = Thread.attributes.labels.contains('label-id')
@m2 = Thread.attributes.categories.contains('category-id')
it "should accept an array of Matcher objects", ->
@q.where([@m1,@m2])
@ -148,17 +148,17 @@ describe "ModelQuery", ->
it "should correctly generate `contains` queries using JOINS", ->
@runScenario Thread,
builder: (q) -> q.where(Thread.attributes.labels.contains('label-id')).where({id: '1234'})
builder: (q) -> q.where(Thread.attributes.categories.contains('category-id')).where({id: '1234'})
sql: "SELECT `Thread`.`data` FROM `Thread` \
INNER JOIN `Thread-Label` AS `M1` ON `M1`.`id` = `Thread`.`id` \
WHERE `M1`.`value` = 'label-id' AND `Thread`.`id` = '1234' \
INNER JOIN `Thread-Category` AS `M1` ON `M1`.`id` = `Thread`.`id` \
WHERE `M1`.`value` = 'category-id' AND `Thread`.`id` = '1234' \
ORDER BY `Thread`.`last_message_received_timestamp` DESC"
@runScenario Thread,
builder: (q) -> q.where([Thread.attributes.labels.contains('l-1'), Thread.attributes.labels.contains('l-2')])
builder: (q) -> q.where([Thread.attributes.categories.contains('l-1'), Thread.attributes.categories.contains('l-2')])
sql: "SELECT `Thread`.`data` FROM `Thread` \
INNER JOIN `Thread-Label` AS `M1` ON `M1`.`id` = `Thread`.`id` \
INNER JOIN `Thread-Label` AS `M2` ON `M2`.`id` = `Thread`.`id` \
INNER JOIN `Thread-Category` AS `M1` ON `M1`.`id` = `Thread`.`id` \
INNER JOIN `Thread-Category` AS `M2` ON `M2`.`id` = `Thread`.`id` \
WHERE `M1`.`value` = 'l-1' AND `M2`.`value` = 'l-2' \
ORDER BY `Thread`.`last_message_received_timestamp` DESC"

View file

@ -216,7 +216,7 @@ describe "QuerySubscription", ->
subscription = new QuerySubscription(DatabaseStore.findAll(Thread))
subscription.update()
advanceClock()
expect(subscription._fetchRange).toHaveBeenCalledWith(QueryRange.infinite(), {entireModels: true})
expect(subscription._fetchRange).toHaveBeenCalledWith(QueryRange.infinite(), {entireModels: true, version: 2})
it "should fetch full full models only when the previous set is empty", ->
subscription = new QuerySubscription(DatabaseStore.findAll(Thread))
@ -224,7 +224,7 @@ describe "QuerySubscription", ->
subscription._set.addModelsInRange([new Thread()], new QueryRange(start: 0, end: 1))
subscription.update()
advanceClock()
expect(subscription._fetchRange).toHaveBeenCalledWith(QueryRange.infinite(), {entireModels: false})
expect(subscription._fetchRange).toHaveBeenCalledWith(QueryRange.infinite(), {entireModels: false, version: 2})
describe "when the query has a range", ->
beforeEach ->
@ -236,7 +236,7 @@ describe "QuerySubscription", ->
subscription._set = null
subscription.update()
advanceClock()
expect(subscription._fetchRange).toHaveBeenCalledWith(@query.range(), {entireModels: true})
expect(subscription._fetchRange).toHaveBeenCalledWith(@query.range(), {entireModels: true, version: 2})
describe "when we have a previous range", ->
it "should call _fetchRange for the ranges representing the difference", ->
@ -250,5 +250,5 @@ describe "QuerySubscription", ->
subscription.update()
advanceClock()
expect(subscription._fetchRange.callCount).toBe(2)
expect(subscription._fetchRange.calls[0].args).toEqual([customRange1, {entireModels: true}])
expect(subscription._fetchRange.calls[1].args).toEqual([customRange2, {entireModels: true}])
expect(subscription._fetchRange.calls[0].args).toEqual([customRange1, {entireModels: true, version: 2}])
expect(subscription._fetchRange.calls[1].args).toEqual([customRange2, {entireModels: true, version: 2}])

View file

@ -1,6 +1,6 @@
Message = require '../../src/flux/models/message'
Thread = require '../../src/flux/models/thread'
Label = require '../../src/flux/models/label'
Category = require '../../src/flux/models/category'
{Utils} = require 'nylas-exports'
_ = require 'underscore'
@ -20,49 +20,49 @@ describe 'Thread', ->
iterations += 1
console.log((Date.now() - start) / 1000.0 + "ms per 1000")
describe '.sortLabels()', ->
getSortedLabels = (inputs) ->
labels = _.map inputs, (i) ->
new Label(name: i, displayName: i)
thread = new Thread(labels: labels)
return thread.sortedLabels()
describe 'sortedCategories', ->
sortedForCategoryNames = (inputs) ->
categories = _.map inputs, (i) ->
new Category(name: i, displayName: i)
thread = new Thread(categories: categories)
return thread.sortedCategories()
it "puts 'important' label first, if it's present", ->
inputs = ['alphabetically before important', 'important']
actualOut = getSortedLabels inputs
actualOut = sortedForCategoryNames inputs
expect(actualOut[0].displayName).toBe 'important'
it "ignores 'important' label if not present", ->
inputs = ['not important']
actualOut = getSortedLabels inputs
actualOut = sortedForCategoryNames inputs
expect(actualOut.length).toBe 1
expect(actualOut[0].displayName).toBe 'not important'
it "doesn't display 'sent', 'all', 'archive', or 'drafts'", ->
inputs = ['sent', 'all', 'archive', 'drafts']
actualOut = getSortedLabels inputs
actualOut = sortedForCategoryNames inputs
expect(actualOut.length).toBe 0
it "displays standard category names which aren't hidden next, if they're present", ->
inputs = ['inbox', 'important', 'social']
actualOut = _.pluck getSortedLabels(inputs), 'displayName'
actualOut = _.pluck sortedForCategoryNames(inputs), 'displayName'
expectedOut = ['important', 'inbox', 'social']
expect(actualOut).toEqual expectedOut
it "ignores standard category names if they aren't present", ->
inputs = ['social', 'work', 'important']
actualOut = _.pluck getSortedLabels(inputs), 'displayName'
actualOut = _.pluck sortedForCategoryNames(inputs), 'displayName'
expectedOut = ['important', 'social', 'work']
expect(actualOut).toEqual expectedOut
it "puts user-added categories at the end", ->
inputs = ['food', 'inbox']
actualOut = _.pluck getSortedLabels(inputs), 'displayName'
actualOut = _.pluck sortedForCategoryNames(inputs), 'displayName'
expectedOut = ['inbox', 'food']
expect(actualOut).toEqual expectedOut
it "sorts user-added categories by displayName", ->
inputs = ['work', 'social', 'receipts', 'important', 'inbox']
actualOut = _.pluck getSortedLabels(inputs), 'displayName'
actualOut = _.pluck sortedForCategoryNames(inputs), 'displayName'
expectedOut = ['important', 'inbox', 'receipts', 'social', 'work']
expect(actualOut).toEqual expectedOut

View file

@ -3,8 +3,7 @@ DatabaseStore = require '../../src/flux/stores/database-store'
DatabaseTransaction = require '../../src/flux/stores/database-transaction'
ThreadCountsStore = require '../../src/flux/stores/thread-counts-store'
Thread = require '../../src/flux/models/thread'
Folder = require '../../src/flux/models/folder'
Label = require '../../src/flux/models/label'
Category = require '../../src/flux/models/category'
Matcher = require '../../src/flux/attributes/matcher'
WindowBridge = require '../../src/window-bridge'
@ -66,10 +65,10 @@ describe "ThreadCountsStore", ->
describe "_fetchCountsMissing", ->
beforeEach ->
ThreadCountsStore._categories = [
new Label(id: "l1", name: "inbox", displayName: "Inbox", accountId: 'a1'),
new Label(id: "l2", name: "archive", displayName: "Archive", accountId: 'a1'),
new Label(id: "l3", displayName: "Happy Days", accountId: 'a1'),
new Label(id: "l4", displayName: "Sad Days", accountId: 'a1')
new Category(id: "l1", name: "inbox", displayName: "Inbox", accountId: 'a1'),
new Category(id: "l2", name: "archive", displayName: "Archive", accountId: 'a1'),
new Category(id: "l3", displayName: "Happy Days", accountId: 'a1'),
new Category(id: "l4", displayName: "Sad Days", accountId: 'a1')
]
ThreadCountsStore._deltas =
l1: 10
@ -138,23 +137,15 @@ describe "ThreadCountsStore", ->
expect(ThreadCountsStore._fetchCountsMissing).not.toHaveBeenCalled()
describe "_fetchCountForCategory", ->
it "should make the appropriate label or folder database query", ->
it "should make the appropriate category database query", ->
spyOn(DatabaseStore, 'count')
Matcher.muid = 0
ThreadCountsStore._fetchCountForCategory(new Label(id: 'l1', accountId: 'a1'))
ThreadCountsStore._fetchCountForCategory(new Category(id: 'l1', accountId: 'a1'))
Matcher.muid = 0
expect(DatabaseStore.count).toHaveBeenCalledWith(Thread, [
Thread.attributes.categories.contains('l1'),
Thread.attributes.accountId.equal('a1'),
Thread.attributes.unread.equal(true),
Thread.attributes.labels.contains('l1')
])
Matcher.muid = 0
ThreadCountsStore._fetchCountForCategory(new Folder(id: 'l1', accountId: 'a1'))
Matcher.muid = 0
expect(DatabaseStore.count).toHaveBeenCalledWith(Thread, [
Thread.attributes.accountId.equal('a1'),
Thread.attributes.unread.equal(true),
Thread.attributes.folders.contains('l1')
])
describe "_saveCounts", ->
@ -185,23 +176,25 @@ describe "ThreadCountsStore", ->
describe "CategoryDatabaseMutationObserver", ->
beforeEach ->
@label1 = new Label(id: "l1", name: "inbox", displayName: "Inbox")
@label2 = new Label(id: "l2", name: "archive", displayName: "Archive")
@label3 = new Label(id: "l3", displayName: "Happy Days")
@label4 = new Label(id: "l4", displayName: "Sad Days")
@category1 = new Category(id: "l1", name: "inbox", displayName: "Inbox")
@category2 = new Category(id: "l2", name: "archive", displayName: "Archive")
@category3 = new Category(id: "l3", displayName: "Happy Days")
@category4 = new Category(id: "l4", displayName: "Sad Days")
# Values here are the "after" state. Below, the spy on the query returns the
# "current" state.
@threadA = new Thread
id: "A"
unread: true
labels: [@label1, @label4]
categories: [@category1, @category4]
@threadB = new Thread
id: "B"
unread: true
labels: [@label3]
categories: [@category3]
@threadC = new Thread
id: "C"
unread: false
labels: [@label1, @label3]
categories: [@category1, @category3]
describe "given a set of modifying models", ->
scenarios = [{
@ -220,7 +213,7 @@ describe "CategoryDatabaseMutationObserver", ->
}
}]
scenarios.forEach ({type, expected}) ->
it "should call countsDidChange with the folder / label membership deltas (#{type})", ->
it "should call countsDidChange with the category membership deltas (#{type})", ->
queryResolves = []
query = jasmine.createSpy('query').andCallFake =>
new Promise (resolve, reject) ->
@ -235,16 +228,14 @@ describe "CategoryDatabaseMutationObserver", ->
objectIds: [@threadA.id, @threadB.id, @threadC.id]
objectClass: Thread.name
})
expect(query.callCount).toBe(2)
expect(query.calls[0].args[0]).toEqual("SELECT `Thread`.id as id, `Thread-Label`.`value` as catId FROM `Thread` INNER JOIN `Thread-Label` ON `Thread`.`id` = `Thread-Label`.`id` WHERE `Thread`.id IN ('A','B','C') AND `Thread`.unread = 1")
expect(query.calls[1].args[0]).toEqual("SELECT `Thread`.id as id, `Thread-Folder`.`value` as catId FROM `Thread` INNER JOIN `Thread-Folder` ON `Thread`.`id` = `Thread-Folder`.`id` WHERE `Thread`.id IN ('A','B','C') AND `Thread`.unread = 1")
expect(query.callCount).toBe(1)
expect(query.calls[0].args[0]).toEqual("SELECT `Thread`.id as id, `Thread-Category`.`value` as catId FROM `Thread` INNER JOIN `Thread-Category` ON `Thread`.`id` = `Thread-Category`.`id` WHERE `Thread`.id IN ('A','B','C') AND `Thread`.unread = 1")
queryResolves[0]([
{id: @threadA.id, catId: @label1.id},
{id: @threadA.id, catId: @label3.id},
{id: @threadB.id, catId: @label2.id},
{id: @threadB.id, catId: @label3.id},
{id: @threadA.id, catId: @category1.id},
{id: @threadA.id, catId: @category3.id},
{id: @threadB.id, catId: @category2.id},
{id: @threadB.id, catId: @category3.id},
])
queryResolves[1]([])
waitsForPromise =>
beforePromise.then (result) =>

View file

@ -119,7 +119,7 @@ class Thread extends Model
#
categoryNamed: (name) -> return _.findWhere(@categories, {name})
sortedLabels: ->
sortedCategories: ->
return [] unless @labels
out = []

View file

@ -35,11 +35,9 @@ class CategoryDatabaseMutationObserver
if type is 'persist'
for thread in objects
continue unless thread.unread
for collection in ['labels', 'folders']
if thread[collection]
for cat in thread[collection]
categories[cat.id] ?= 0
categories[cat.id] += 1
for cat in thread.categories
categories[cat.id] ?= 0
categories[cat.id] += 1
for key, val of categories
delete categories[key] if val is 0