Handle database connection errors gracefully

When opening a second Atom instance (e.g. when running the integration specs)
indexedDB connections will fail. In this case, StateStore.prototype.save
and StateStore.prototype.load will become noops.

Signed-off-by: Katrina Uychaco <kuychaco@github.com>
This commit is contained in:
Max Brunsfeld
2016-02-09 14:30:10 -08:00
committed by Katrina Uychaco
parent 9b2c791c86
commit b0cf440f9c
3 changed files with 35 additions and 12 deletions

View File

@@ -1,11 +1,14 @@
/** @babel */
import {it, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
import {it, fit, ffit, fffit, beforeEach, afterEach} from './async-spec-helpers'
const StateStore = require('../src/state-store.js')
describe("StateStore", () => {
let databaseName = `test-database-${Date.now()}`
let version = 1
it("can save and load states", () => {
const store = new StateStore()
const store = new StateStore(databaseName, version)
return store.save('key', {foo:'bar'})
.then(() => store.load('key'))
.then((state) => {
@@ -13,9 +16,16 @@ describe("StateStore", () => {
})
})
it("resolves with null when a non-existent key is loaded", () => {
const store = new StateStore(databaseName, version)
return store.load('no-such-key').then((value) => {
expect(value).toBeNull()
})
});
describe("when there is an error reading from the database", () => {
it("rejects the promise returned by load", () => {
const store = new StateStore()
const store = new StateStore(databaseName, version)
const fakeErrorEvent = {target: {errorCode: "Something bad happened"}}

View File

@@ -127,7 +127,7 @@ class AtomEnvironment extends Model
@emitter = new Emitter
@disposables = new CompositeDisposable
@stateStore = new StateStore
@stateStore = new StateStore('AtomEnvironments', 1)
@deserializers = new DeserializerManager(this)
@deserializeTimings = {}

View File

@@ -2,28 +2,33 @@
module.exports =
class StateStore {
constructor () {
this.dbPromise = new Promise((resolve, reject) => {
let dbOpenRequest = indexedDB.open('AtomEnvironments', 1)
constructor (databaseName, version) {
this.dbPromise = new Promise((resolve) => {
let dbOpenRequest = indexedDB.open(databaseName, version)
dbOpenRequest.onupgradeneeded = (event) => {
let db = event.target.result
db.createObjectStore('states')
resolve(db)
}
dbOpenRequest.onsuccess = () => {
resolve(dbOpenRequest.result)
}
dbOpenRequest.onerror = reject
dbOpenRequest.onerror = (error) => {
console.error("Could not connect to indexedDB", error)
resolve(null)
}
})
}
save (key, value) {
return this.dbPromise.then(db => {
value.storedAt = new Date().toString()
if (!db) {
return
}
return new Promise((resolve, reject) => {
var request = db.transaction(['states'], 'readwrite')
.objectStore('states')
.put(value, key)
.put({value: value, storedAt: new Date().toString()}, key)
request.onsuccess = resolve
request.onerror = reject
@@ -33,12 +38,20 @@ class StateStore {
load (key) {
return this.dbPromise.then(db => {
if (!db) {
return null
}
return new Promise((resolve, reject) => {
var request = db.transaction(['states'])
.objectStore('states')
.get(key)
request.onsuccess = (event) => resolve(event.target.result)
request.onsuccess = (event) => {
let result = event.target.result
resolve(result ? result.value : null)
}
request.onerror = (event) => reject(event)
})
})