Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(core/biblio-db): Move from indexedDB to idb #2228

Merged
merged 21 commits into from
Aug 3, 2019
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 38 additions & 127 deletions src/core/biblio-db.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,60 +7,22 @@
* It's a standalone module that can be imported into other modules.
*
*/
/* globals IDBKeyRange, DOMException */
/* globals IDBKeyRange */
import { openDB } from "idb";
import { pub } from "./pubsubhub";
export const name = "core/biblio-db";

const ALLOWED_TYPES = new Set(["alias", "reference"]);
// Database initialization, tracked by "readyPromise"
const readyPromise = new Promise((resolve, reject) => {
let request;
try {
request = window.indexedDB.open("respec-biblio2", 12);
} catch (err) {
return reject(err);
}
request.onerror = () => {
reject(new DOMException(request.error.message, request.error.name));
};
request.onsuccess = () => {
resolve(request.result);
};
request.onupgradeneeded = async () => {
const db = request.result;
const readyPromise = openDB("respec-biblio2", 12, {
upgrade(db) {
Array.from(db.objectStoreNames).map(storeName =>
db.deleteObjectStore(storeName)
);
const promisesToCreateSchema = [
new Promise((resolve, reject) => {
try {
const store = db.createObjectStore("alias", { keyPath: "id" });
store.createIndex("aliasOf", "aliasOf", { unique: false });
store.transaction.oncomplete = resolve;
store.transaction.onerror = reject;
} catch (err) {
reject(err);
}
}),
new Promise((resolve, reject) => {
try {
const transaction = db.createObjectStore("reference", {
keyPath: "id",
}).transaction;
transaction.oncomplete = resolve;
transaction.onerror = reject;
} catch (err) {
reject(err);
}
}),
];
try {
await Promise.all(promisesToCreateSchema);
resolve();
} catch (err) {
reject(err);
}
};
const store = db.createObjectStore("alias", { keyPath: "id" });
store.createIndex("aliasOf", "aliasOf", { unique: false });
db.createObjectStore("reference", { keyPath: "id" });
},
});

export const biblioDB = {
Expand All @@ -78,7 +40,7 @@ export const biblioDB = {
if (await this.isAlias(id)) {
id = await this.resolveAlias(id);
}
return this.get("reference", id);
return await this.get("reference", id);
marcoscaceres marked this conversation as resolved.
Show resolved Hide resolved
},
/**
* Checks if the database has an id for a given type.
Expand All @@ -95,17 +57,9 @@ export const biblioDB = {
throw new TypeError("id is required");
}
const db = await this.ready;
return new Promise((resolve, reject) => {
const objectStore = db.transaction([type], "readonly").objectStore(type);
const range = IDBKeyRange.only(id);
const request = objectStore.openCursor(range);
request.onsuccess = () => {
resolve(!!request.result);
};
request.onerror = () => {
reject(new DOMException(request.error.message, request.error.name));
};
});
const objectStore = db.transaction([type], "readonly").objectStore(type);
const range = IDBKeyRange.only(id);
return !!(await objectStore.openCursor(range));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this was in the original, but it's still a bit ugly... maybe we can do?

Suggested change
return !!(await objectStore.openCursor(range));
const result = await objectStore.openCursor(range);
return result ? true : false;

Same with other one below...

Copy link
Collaborator

@saschanaz saschanaz Apr 9, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

? true : false? It doesn't look JavaScript-y for me... Maybe !!result?

(Because result ? part already coerces result into a boolean.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

!!result wfm

},
/**
* Checks if a given id is an alias.
Expand All @@ -118,19 +72,11 @@ export const biblioDB = {
throw new TypeError("id is required");
}
const db = await this.ready;
return new Promise((resolve, reject) => {
const objectStore = db
.transaction(["alias"], "readonly")
.objectStore("alias");
const range = IDBKeyRange.only(id);
const request = objectStore.openCursor(range);
request.onsuccess = () => {
resolve(!!request.result);
};
request.onerror = () => {
reject(new DOMException(request.error.message, request.error.name));
};
});
const objectStore = db
.transaction(["alias"], "readonly")
.objectStore("alias");
const range = IDBKeyRange.only(id);
return !!(await objectStore.openCursor(range));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above...

},
/**
* Resolves an alias to its corresponding reference id.
Expand All @@ -143,22 +89,13 @@ export const biblioDB = {
throw new TypeError("id is required");
}
const db = await this.ready;
return new Promise((resolve, reject) => {
const objectStore = db
.transaction("alias", "readonly")
.objectStore("alias");
const range = IDBKeyRange.only(id);
const request = objectStore.openCursor(range);
request.onsuccess = () => {
if (request.result === null) {
return resolve(null);
}
resolve(request.result.value.aliasOf);
};
request.onerror = () => {
reject(new DOMException(request.error.message, request.error.name));
};
});

const objectStore = db
.transaction("alias", "readonly")
.objectStore("alias");
const range = IDBKeyRange.only(id);
const result = await objectStore.openCursor(range);
return result ? result.value.aliasOf : result;
},
/**
* Get a reference or alias out of the database.
Expand All @@ -175,20 +112,10 @@ export const biblioDB = {
throw new TypeError("id is required");
}
const db = await this.ready;
return new Promise((resolve, reject) => {
const objectStore = db.transaction([type], "readonly").objectStore(type);
const range = IDBKeyRange.only(id);
const request = objectStore.openCursor(range);
request.onsuccess = () => {
if (request.result === null) {
return resolve(null);
}
resolve(request.result.value);
};
request.onerror = () => {
reject(new DOMException(request.error.message, request.error.name));
};
});
const objectStore = db.transaction([type], "readonly").objectStore(type);
const range = IDBKeyRange.only(id);
const result = await objectStore.openCursor(range);
return result ? result.value : result;
},
/**
* Adds references and aliases to database. This is usually the data from
Expand Down Expand Up @@ -226,8 +153,8 @@ export const biblioDB = {
}, aliasesAndRefs);
const promisesToAdd = Object.keys(aliasesAndRefs)
.map(type => {
return Array.from(aliasesAndRefs[type]).map(details =>
this.add(type, details)
return Array.from(aliasesAndRefs[type]).map(
async details => await this.add(type, details)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is redundant because the return type is still Promise, and it's expected.

);
})
.reduce((collector, promises) => collector.concat(promises), []);
Expand All @@ -251,15 +178,10 @@ export const biblioDB = {
}
const db = await this.ready;
const isInDB = await this.has(type, details.id);
return new Promise((resolve, reject) => {
const store = db.transaction([type], "readwrite").objectStore(type);
// update or add, depending of already having it in db
const request = isInDB ? store.put(details) : store.add(details);
request.onsuccess = resolve;
request.onerror = () => {
reject(new DOMException(request.error.message, request.error.name));
};
});
const store = db.transaction([type], "readwrite").objectStore(type);
// update or add, depending of already having it in db
const request = isInDB ? store.put(details) : store.add(details);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should do:
Maybe just:

Suggested change
const request = isInDB ? store.put(details) : store.add(details);
return isInDB ? await store.put(details) : await store.add(details);

return await request;
},
/**
* Closes the underlying database.
Expand All @@ -277,21 +199,10 @@ export const biblioDB = {
async clear() {
const db = await this.ready;
const storeNames = [...ALLOWED_TYPES];
const stores = await new Promise((resolve, reject) => {
const transaction = db.transaction(storeNames, "readwrite");
transaction.onerror = () => {
reject(
new DOMException(transaction.error.message, transaction.error.name)
);
};
resolve(transaction);
});
const clearStorePromises = storeNames.map(name => {
return new Promise(resolve => {
const request = stores.objectStore(name).clear();
request.onsuccess = resolve;
});
const stores = await db.transaction(storeNames, "readwrite");
const clearStorePromises = storeNames.map(async name => {
return await stores.objectStore(name).clear();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is redundant too. It still returns a Promise anyway.

});
Promise.all(clearStorePromises);
await Promise.all(clearStorePromises);
},
};
6 changes: 6 additions & 0 deletions tests/SpecRunner.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@
paths: {
"jquery": "deps/jquery",
"marked": "deps/marked",
"idb": "deps/idb",
},
shim: {
idb: {
exports: "idb",
},
},
deps: testFiles,
callback: runner,
Expand Down
3 changes: 1 addition & 2 deletions tests/spec/core/xref-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ describe("Core — xref", () => {

let cache;
beforeAll(async () => {
await new Promise(resolve => require(["deps/idb"], resolve));
const { openDB } = window.idb;
const { openDB } = await new Promise(resolve => require(["idb"], resolve));
const { IDBKeyVal } = await new Promise(resolve =>
require(["core/utils"], resolve)
);
Expand Down
7 changes: 6 additions & 1 deletion tests/test-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@ require.config({
w3c: "/base/js/w3c",
clipboard: "deps/clipboard",
hyperhtml: "deps/hyperhtml",
"idb-keyval": "deps/idb",
idb: "deps/idb",
jquery: "deps/jquery",
marked: "deps/marked",
pluralize: "deps/pluralize",
text: "deps/text",
webidl2: "deps/webidl2",
},
shim: {
idb: {
exports: "idb",
},
},
});