test/generic/JungleDB.spec.js
describe('JungleDB', () => {
it('can connect', (done) => {
let called = false;
const db = new JungleDB('test', 1, { onUpgradeNeeded: () => {
called = true;
}});
db.connect().then(() => {
expect(called).toBe(true);
expect(db._dbVersion).toBe(1);
db.destroy().then(done);
});
});
it('can reconnect to a database', (done) => {
let called = false;
(async function () {
let db = new JungleDB('test', 1, { onUpgradeNeeded: () => {
called = true;
}});
await db.connect();
expect(called).toBe(true);
expect(db._dbVersion).toBe(1);
await db.close();
called = false;
db = new JungleDB('test', 1, { onUpgradeNeeded: () => {
called = true;
}});
await db.connect();
expect(called).toBe(false);
expect(db._dbVersion).toBe(1);
await db.close();
called = false;
db = new JungleDB('test', 2, { onUpgradeNeeded: () => {
called = true;
}});
await db.connect();
expect(called).toBe(true);
expect(db._dbVersion).toBe(2);
await db.destroy();
})().then(done, done.fail);
});
it('can create and delete object stores', (done) => {
(async function () {
// Write something into an object store.
let db = new JungleDB('test', 1);
let st = db.createObjectStore('testStore');
await db.connect();
await st.put('test', 'succeeded');
await db.close();
// And test whether it is still there.
db = new JungleDB('test', 1);
st = db.createObjectStore('testStore');
await db.connect();
expect(await st.get('test')).toBe('succeeded');
await db.close();
// Delete it now.
db = new JungleDB('test', 2);
await db.deleteObjectStore('testStore');
await db.connect();
await db.close();
// And check that is has been deleted.
db = new JungleDB('test', 3);
st = db.createObjectStore('testStore');
await db.connect();
expect(await st.get('test')).toBe(undefined);
await st.put('test', 'succeeded');
expect(await st.get('test')).toBe('succeeded');
await db.destroy();
// And check that destroy has worked.
db = new JungleDB('test', 3);
st = db.createObjectStore('testStore');
await db.connect();
expect(await st.get('test')).toBe(undefined);
await db.destroy();
})().then(done, done.fail);
});
it('does not throw errors when recreating existing stores', (done) => {
(async function () {
// Write something into an object store.
let db = new JungleDB('test', 1);
let st = db.createObjectStore('testStore');
st.createIndex('test');
await db.connect();
await st.put('test', 'succeeded');
await db.close();
// Create another index
db = new JungleDB('test', 2);
st = db.createObjectStore('testStore');
st.createIndex('test');
st.createIndex('test2');
await db.connect();
expect(await st.get('test')).toBe('succeeded');
await db.destroy();
})().then(done, done.fail);
});
it('can use advanced upgrade methods (new signatures)', (done) => {
let upgradeCall = { called: false, oldVersion: null, newVersion: null };
async function connect(version) {
// Write something into an object store.
let db = new JungleDB('testme', version, { onUpgradeNeeded: (oldVersion, newVersion) => {
upgradeCall = { called: true, oldVersion: oldVersion, newVersion: newVersion };
}});
const store = db.createObjectStore('books', { upgradeCondition: (oldVersion) => oldVersion < 1 });
if (version === 1) {
db.createObjectStore('notNeeded', { upgradeCondition: (oldVersion, newVersion) => oldVersion < 1 });
}
const titleIndex = store.createIndex('by_title', 'title', { upgradeCondition: (oldVersion) => oldVersion < 1 });
const authorIndex = store.createIndex('by_author', 'author', { upgradeCondition: (oldVersion) => oldVersion < 1 });
if (version >= 2) {
db.deleteObjectStore('notNeeded', { upgradeCondition: (oldVersion) => oldVersion === 1 });
}
if (version === 2) {
// Version 2 introduces a new index of books by year.
const yearIndex = store.createIndex('by_year', 'year', { upgradeCondition: (oldVersion) => oldVersion < 2 });
}
if (version >= 3) {
// Version 3 introduces a new object store for magazines with two indexes.
store.deleteIndex('by_year', { upgradeCondition: (oldVersion) => oldVersion === 2 });
const magazines = db.createObjectStore('magazines', { upgradeCondition: (oldVersion) => oldVersion < 3 });
const publisherIndex = magazines.createIndex('by_publisher', 'publisher', { upgradeCondition: (oldVersion) => oldVersion < 3 });
const frequencyIndex = magazines.createIndex('by_frequency', 'frequency', { upgradeCondition: (oldVersion) => oldVersion < 3 });
}
await db.connect();
return db;
}
(async function () {
/** @type {IJungleDB} */
let db = await connect(1);
expect(upgradeCall.called).toBe(true);
expect(upgradeCall.oldVersion).toBe(0);
expect(upgradeCall.newVersion).toBe(1);
let store = db.getObjectStore('books');
expect(store).toBeTruthy();
expect(store.index('by_title')).toBeTruthy();
expect(store.index('by_author')).toBeTruthy();
expect(store.index('by_year')).toBeFalsy();
expect(db.getObjectStore('magazines')).toBeFalsy();
expect(db.getObjectStore('notNeeded')).toBeTruthy();
await db.close();
// No changes with same version.
upgradeCall = { called: false, oldVersion: null, newVersion: null };
db = await connect(1);
expect(upgradeCall.called).toBe(false);
store = db.getObjectStore('books');
expect(store).toBeTruthy();
expect(store.index('by_title')).toBeTruthy();
expect(store.index('by_author')).toBeTruthy();
expect(store.index('by_year')).toBeFalsy();
expect(db.getObjectStore('magazines')).toBeFalsy();
expect(db.getObjectStore('notNeeded')).toBeTruthy();
await db.close();
// Upgrade to 2.
upgradeCall = { called: false, oldVersion: null, newVersion: null };
db = await connect(2);
expect(upgradeCall.called).toBe(true);
expect(upgradeCall.oldVersion).toBe(1);
expect(upgradeCall.newVersion).toBe(2);
store = db.getObjectStore('books');
expect(store).toBeTruthy();
expect(store.index('by_title')).toBeTruthy();
expect(store.index('by_author')).toBeTruthy();
expect(store.index('by_year')).toBeTruthy();
expect(db.getObjectStore('magazines')).toBeFalsy();
expect(db.getObjectStore('notNeeded')).toBeFalsy();
await db.close();
// Upgrade to 3.
upgradeCall = { called: false, oldVersion: null, newVersion: null };
db = await connect(3);
expect(upgradeCall.called).toBe(true);
expect(upgradeCall.oldVersion).toBe(2);
expect(upgradeCall.newVersion).toBe(3);
store = db.getObjectStore('books');
expect(store).toBeTruthy();
expect(store.index('by_title')).toBeTruthy();
expect(store.index('by_author')).toBeTruthy();
expect(store.index('by_year')).toBeFalsy();
let magazines = db.getObjectStore('magazines');
expect(magazines).toBeTruthy();
expect(magazines.index('by_publisher')).toBeTruthy();
expect(magazines.index('by_frequency')).toBeTruthy();
expect(db.getObjectStore('notNeeded')).toBeFalsy();
await db.close();
await db.destroy();
// Immediate upgrade to 3.
upgradeCall = { called: false, oldVersion: null, newVersion: null };
db = await connect(3);
expect(upgradeCall.called).toBe(true);
expect(upgradeCall.oldVersion).toBe(0);
expect(upgradeCall.newVersion).toBe(3);
store = db.getObjectStore('books');
expect(store).toBeTruthy();
expect(store.index('by_title')).toBeTruthy();
expect(store.index('by_author')).toBeTruthy();
expect(store.index('by_year')).toBeFalsy();
magazines = db.getObjectStore('magazines');
expect(magazines).toBeTruthy();
expect(magazines.index('by_publisher')).toBeTruthy();
expect(magazines.index('by_frequency')).toBeTruthy();
expect(db.getObjectStore('notNeeded')).toBeFalsy();
await db.close();
await db.destroy();
})().then(done, done.fail);
});
it('can delete stores with indices', (done) => {
(async function () {
// Write something into an object store.
let db = new JungleDB('test', 1);
let st = db.createObjectStore('testStore');
st.createIndex('test');
await db.connect();
await st.put('test', {'test': 'succeeded'});
expect(await st.index('test').count()).toBe(1);
await db.close();
// Create another index
db = new JungleDB('test', 2);
db.deleteObjectStore('testStore', {indexNames: ['test']});
st = db.createObjectStore('testStore');
st.createIndex('test');
await db.connect();
expect(await st.index('test').count()).toBe(0);
await db.destroy();
})().then(done, done.fail);
});
it('can change entries in onUpgradeNeeded callback', (done) => {
(async function () {
// Write something into an object store.
let upgraded = false;
let db = new JungleDB('test', 1, {
onUpgradeNeeded: () => {
upgraded = true;
}
});
let st = db.createObjectStore('testStore');
await db.connect();
expect(upgraded).toBe(true);
await st.put('test', 'value');
await st.put('test2', 'value2');
await db.close();
// Create another index
upgraded = false;
db = new JungleDB('test', 2, {
onUpgradeNeeded: async (oldVersion, newVersion, jdb) => {
upgraded = true;
const st = jdb.getObjectStore('testStore');
const tx = st.transaction();
await st.valueStream((value, key) => {
tx.putSync(key, 'new' + value);
return true;
});
await tx.commit();
}
});
st = db.createObjectStore('testStore');
await db.connect();
expect(upgraded).toBe(true);
expect(await st.get('test')).toBe('newvalue');
expect(await st.get('test2')).toBe('newvalue2');
await db.destroy();
})().then(done, done.fail);
});
it('can truncate tables in onUpgradeNeeded callback', (done) => {
(async function () {
// Write something into an object store.
let upgraded = false;
let db = new JungleDB('test', 1, {
onUpgradeNeeded: () => {
upgraded = true;
}
});
let st = db.createObjectStore('testStore');
let st2 = db.createObjectStore('testStore2');
await db.connect();
expect(upgraded).toBe(true);
await st.put('test', 'value');
await st2.put('test2', 'value2');
await db.close();
// Create another index
upgraded = false;
db = new JungleDB('test', 2, {
onUpgradeNeeded: async (oldVersion, newVersion, jdb) => {
upgraded = true;
const st = jdb.getObjectStore('testStore');
const tx = st.transaction();
await tx.truncate();
const st2 = jdb.getObjectStore('testStore2');
const tx2 = st2.transaction();
await tx2.truncate();
await JungleDB.commitCombined(tx, tx2);
}
});
st = db.createObjectStore('testStore');
st2 = db.createObjectStore('testStore2');
await db.connect();
expect(upgraded).toBe(true);
expect(await st.get('test')).toBeUndefined();
expect(await st2.get('test2')).toBeUndefined();
await st2.put('test2', 'value2');
expect(await st2.get('test2')).toBe('value2');
await st2.truncate();
await db.destroy();
})().then(done, done.fail);
});
});