1
0
watterblock/data/session_repo.js

150 lines
5.1 KiB
JavaScript

"use strict";
import Session from "/models/session.js";
import WbDb from "/data/db.js";
/** A transaction or known type that can be turned into a transaction.
* @typedef {IDBTransaction|IDBDatabase|WbDb=} Transactable
*
* 1. If the transactable is a transaction already, it shall be used directy.
* No validation of the accessible object stores or mode should be done, the
* creator is responsible for ensuring correctness of those.
* 2. If the transactable is a database, a transaction with the provided stores
* shall be started on it.
* 3. If the transactable is an instance of `WbDb`, a transaction shall be
* started on its database.
* 4. Otherwise a transaction shall be started on the main `WbDb` instance.
*/
/** Transform a `Transactable` into a transaction.
*
* @param {Transactable} value The `Transactable` to turn into a transaction.
* @param {string[]} stores
* The object stores to acquire if the transaction has to be started.
* @param {IDBTransactionMode=} mode The transaction mode to use.
* @returns {IDBTransaction} A usable transaction.
*/
function toTransaction(value, stores, mode) {
if (value === undefined)
value = WbDb.get();
if (value instanceof WbDb)
value = value.db;
if (value instanceof IDBDatabase)
value = value.transaction(stores, mode);
if (!(value instanceof IDBTransaction))
throw new TypeError("transaction must be or become a IDBTransaction");
return value;
}
/** Turn a request into a promise.
*
* The promise fulfills if the request succeeds, and rejects if it fails.
*
* @param {IDBRequest} request The request to wrap.
* @returns A promise linked to the request.
*/
function requestToPromise(request) {
return new Promise(function(resolve, reject) {
request.onsuccess = (req) => resolve(req.target.result);
request.onerror = reject;
});
}
/** Collection of static function to interact with stored sessions. */
export default class SessionRepo {
constructor() {
throw new TypeError("SessionRepo cannot be constructed");
}
/** The symbol used to attach needed data to sessions. */
static #marker = Symbol("data/session_store");
/** Handle the Session.EVENT_CHANGE event, by storing the changed session in
* the DB.
*/
static async #handleChange() {
if (!(this instanceof Session))
throw new TypeError("session to put in must be an actual Session");
SessionRepo.put(this, this[SessionRepo.#marker]);
}
/** Put a session into the repository.
*
* If the passed session has no `id` set, the newly stored ID will be
* inserted back into it.
*
* @param {Session} session The session to store.
* @param {Transactable} transaction A transaction to use.
*
* @returns {Promise<number>} A promise containing the ID of the add session.
*/
static put(session, transaction) {
if (!(session instanceof Session))
throw new TypeError("session to put in must be an actual Session");
transaction = toTransaction(transaction, [WbDb.OS_SESSIONS], "readwrite");
let sessions = transaction.objectStore(WbDb.OS_SESSIONS);
let struct = session.toStruct();
let req = requestToPromise(sessions.put(struct));
// promise with which the session object can be altered
let alt = req;
// add id to original object if it is new
if (session.id === null)
alt = alt.then((id) => session.id = id);
// add change listener t oobject.
alt.then(() => { if (session[SessionRepo.#marker] === undefined) {
session.addEventListener(
Session.EVENT_CHANGE, SessionRepo.#handleChange);
session[SessionRepo.#marker] = transaction.db;
}});
// make sure alt is handled first
return req.then(res => res);
}
/** Get a specific session from the repository.
*
* @param {number} key The ID of the session to retrieve.
* @param {Transactable} transaction A transaction to use.
*
* @returns {Promise<Session | undefined>}
* The requested session, or undefined if it does not exist.
*/
static async get(key, transaction) {
transaction = toTransaction(transaction, [WbDb.OS_SESSIONS], "readonly");
let sessions = transaction.objectStore(WbDb.OS_SESSIONS);
let session = await requestToPromise(sessions.get(key));
if (session !== undefined) {
session = new Session(session);
session.addEventListener(
Session.EVENT_CHANGE, SessionRepo.#handleChange);
session[SessionRepo.#marker] = transaction.db;
}
return session;
}
/** Get all sessions in the repository.
*
* @param {Transactable} transaction A transaction to use.
*
* @returns {Promise<Session[]>} A promise containing the stored sessions.
*/
static async getAll(transaction) {
transaction = toTransaction(transaction, [WbDb.OS_SESSIONS], "readonly");
let sessions = transaction.objectStore(WbDb.OS_SESSIONS);
sessions = await requestToPromise(sessions.getAll());
return sessions.map(function(session) {
let res = new Session(session);
res.addEventListener(Session.EVENT_CHANGE, SessionRepo.#handleChange);
res[SessionRepo.#marker] = transaction.db;
return res;
});
}
}