mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-12 04:25:31 +08:00
a14a5212ac
Summary: Until now, we've been hiding transactions beneath the surface. When you call persistModel, you're implicitly creating a transaction. You could explicitly create them with `atomically`..., but there were several critical problems that are fixed in this diff: - Calling persistModel / unpersistModel within a transaction could cause the DatabaseStore to trigger. This could result in other parts of the app making queries /during/ the transaction, potentially before the COMMIT occurred and saved the changes. The new, explicit inTransaction syntax holds all changes until after COMMIT and then triggers. - Calling atomically and then calling persistModel inside that resulted in us having to check whether a transaction was present and was gross. - Many parts of the code ran extensive logic inside a promise chained within `atomically`: BAD: ``` DatabaseStore.atomically => DatabaseStore.persistModel(draft) => GoMakeANetworkRequestThatReturnsAPromise ``` OVERWHELMINGLY BETTER: ``` DatabaseStore.inTransaction (t) => t.persistModel(draft) .then => GoMakeANetworkRequestThatReturnsAPromise ``` Having explicit transactions also puts us on equal footing with Sequelize and other ORMs. Note that you /have/ to call DatabaseStore.inTransaction (t) =>. There is no other way to access the methods that let you alter the database. :-) Other changes: - This diff removes Message.labels and the Message-Labels table. We weren't using Message-level labels anywhere, and the table could grow very large. - This diff changes the page size during initial sync from 250 => 200 in an effort to make transactions a bit faster. Test Plan: Run tests! Reviewers: juan, evan Reviewed By: juan, evan Differential Revision: https://phab.nylas.com/D2353
95 lines
3 KiB
CoffeeScript
95 lines
3 KiB
CoffeeScript
_ = require 'underscore'
|
|
|
|
{NylasAPI,
|
|
Event,
|
|
Actions,
|
|
APIError,
|
|
EventRSVPTask,
|
|
DatabaseStore,
|
|
DatabaseTransaction,
|
|
AccountStore} = require 'nylas-exports'
|
|
|
|
describe "EventRSVPTask", ->
|
|
beforeEach ->
|
|
spyOn(DatabaseStore, 'find').andCallFake => Promise.resolve(@event)
|
|
spyOn(DatabaseTransaction.prototype, '_query').andCallFake -> Promise.resolve([])
|
|
spyOn(DatabaseTransaction.prototype, 'persistModel').andCallFake -> Promise.resolve()
|
|
@myName = "Ben Tester"
|
|
@myEmail = "tester@nylas.com"
|
|
@event = new Event
|
|
id: '12233AEDF5'
|
|
accountId: TEST_ACCOUNT_ID
|
|
title: 'Meeting with Ben Bitdiddle'
|
|
description: ''
|
|
location: ''
|
|
when:
|
|
end_time: 1408123800
|
|
start_time: 1408120200
|
|
start: 1408120200
|
|
end: 1408123800
|
|
participants: [
|
|
{"name": "Ben Bitdiddle",
|
|
"email": "ben@bitdiddle.com",
|
|
"status": "yes"},
|
|
{"name": @myName,
|
|
"email": @myEmail,
|
|
"status": 'noreply'}
|
|
]
|
|
@task = new EventRSVPTask(@event, "no")
|
|
|
|
describe "performLocal", ->
|
|
it "should mark our status as no", ->
|
|
@task.performLocal()
|
|
advanceClock()
|
|
expect(@event.participants[1].status).toBe "no"
|
|
|
|
it "should trigger an action to persist the change", ->
|
|
@task.performLocal()
|
|
advanceClock()
|
|
expect(DatabaseTransaction.prototype.persistModel).toHaveBeenCalled()
|
|
|
|
describe "performRemote", ->
|
|
it "should make the POST request to the message endpoint", ->
|
|
spyOn(NylasAPI, 'makeRequest').andCallFake => new Promise (resolve,reject) ->
|
|
@task.performRemote()
|
|
options = NylasAPI.makeRequest.mostRecentCall.args[0]
|
|
expect(options.path).toBe("/send-rsvp")
|
|
expect(options.method).toBe('POST')
|
|
expect(options.accountId).toBe(@event.accountId)
|
|
expect(options.body.event_id).toBe(@event.id)
|
|
expect(options.body.status).toBe("no")
|
|
|
|
describe "when the remote API request fails", ->
|
|
beforeEach ->
|
|
spyOn(NylasAPI, 'makeRequest').andCallFake -> Promise.reject(new APIError(body: '', statusCode: 400))
|
|
|
|
it "should not be marked with the status", ->
|
|
@event = new Event
|
|
id: '12233AEDF5'
|
|
title: 'Meeting with Ben Bitdiddle'
|
|
description: ''
|
|
location: ''
|
|
when:
|
|
end_time: 1408123800
|
|
start_time: 1408120200
|
|
start: 1408120200
|
|
end: 1408123800
|
|
participants: [
|
|
{"name": "Ben Bitdiddle",
|
|
"email": "ben@bitdiddle.com",
|
|
"status": "yes"},
|
|
{"name": @myName,
|
|
"email": @myEmail,
|
|
"status": 'noreply'}
|
|
]
|
|
@task = new EventRSVPTask(@event, "no")
|
|
@task.performLocal()
|
|
@task.performRemote()
|
|
advanceClock()
|
|
expect(@event.participants[1].status).toBe "noreply"
|
|
|
|
it "should trigger an action to persist the change", ->
|
|
@task.performLocal()
|
|
@task.performRemote()
|
|
advanceClock()
|
|
expect(DatabaseTransaction.prototype.persistModel).toHaveBeenCalled()
|