implement session repository
This commit is contained in:
parent
fb2fd76c6c
commit
b89206f113
@ -48,6 +48,7 @@ export default function() {
|
||||
});
|
||||
});
|
||||
|
||||
// close db after each test
|
||||
hooks.afterEach(function() {
|
||||
if (inst !== null)
|
||||
if (inst.open)
|
||||
|
||||
97
data/session_repo.js
Normal file
97
data/session_repo.js
Normal file
@ -0,0 +1,97 @@
|
||||
"use strict";
|
||||
|
||||
import Session from "../models/session.js";
|
||||
import WbDb from "./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");
|
||||
}
|
||||
|
||||
/** 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));
|
||||
|
||||
if (session.id === null)
|
||||
req.then((id) => session.id = id);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/** 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((session) => new Session(session));
|
||||
}
|
||||
}
|
||||
132
data/session_repo.test.js
Normal file
132
data/session_repo.test.js
Normal file
@ -0,0 +1,132 @@
|
||||
"use strict";
|
||||
|
||||
import { Team } from "../models/round.js";
|
||||
import Session from "../models/session.js";
|
||||
import WbDb from "./db.js";
|
||||
import SessionRepo from "./session_repo.js";
|
||||
|
||||
/** The instance used for the current test.
|
||||
*
|
||||
* Put test instances of `WbDb` into this variable. If it is used, the
|
||||
* connection is automatically closed after the test is done. That in turn
|
||||
* means that the database can then be deleted immediately, thus speeding up
|
||||
* the next test.
|
||||
*
|
||||
* @type {WbDb}
|
||||
*/
|
||||
let inst = null;
|
||||
|
||||
/** Wait for the `WbDb.EVENT_CHANGE` to be fired on `instance`.
|
||||
*
|
||||
* Uses the `inst` global variable if no `instance` parameter is passed.
|
||||
*
|
||||
* @param {WbDb=} instance The instance to wait on.
|
||||
*/
|
||||
function waitForChange(instance) {
|
||||
return new Promise(function(resolve) {
|
||||
(instance ?? inst).addEventListener(WbDb.EVENT_CHANGE, function() {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default function() {
|
||||
QUnit.module("session_repo", function(hooks) {
|
||||
|
||||
// delete test database before each test
|
||||
hooks.beforeEach(function() {
|
||||
return new Promise(function(resolve) {
|
||||
let req = indexedDB.deleteDatabase(WbDb.DB_NAME_TEST);
|
||||
req.onsuccess = function() {
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// close db after each test
|
||||
hooks.afterEach(function() {
|
||||
if (inst !== null)
|
||||
if (inst.open)
|
||||
inst.db.close();
|
||||
inst = null;
|
||||
});
|
||||
|
||||
QUnit.test("cannot call constructor", function(assert) {
|
||||
assert.throws(
|
||||
function() { new SessionRepo(); },
|
||||
new TypeError("SessionRepo cannot be constructed"));
|
||||
});
|
||||
|
||||
QUnit.test("initially no sessions", async function(assert) {
|
||||
inst = WbDb.get(true);
|
||||
await waitForChange(inst);
|
||||
let sessions = await SessionRepo.getAll(inst);
|
||||
assert.strictEqual(sessions.length, 0, "no sessions");
|
||||
});
|
||||
|
||||
QUnit.test("store single session", async function(assert) {
|
||||
inst = WbDb.get(true);
|
||||
let req = waitForChange(inst);
|
||||
|
||||
let session = new Session();
|
||||
session.ourTeam = "This is us!";
|
||||
session.theirTeam = "This is them!";
|
||||
session.goal = 2;
|
||||
session.anotherGame();
|
||||
session.currentGame.currentRound.winner = Team.We;
|
||||
session.anotherGame();
|
||||
assert.strictEqual(session.id, null, "no initial session id");
|
||||
|
||||
await req;
|
||||
let id = await SessionRepo.put(session, inst);
|
||||
assert.strictEqual(session.id, id, "session id has been updated");
|
||||
|
||||
let sessions = await SessionRepo.getAll(inst);
|
||||
assert.strictEqual(sessions.length, 1, "one stored session");
|
||||
assert.deepEqual(
|
||||
sessions[0].toStruct(), session.toStruct(), "sessions match");
|
||||
});
|
||||
|
||||
QUnit.test("store two sessions", async function(assert) {
|
||||
inst = WbDb.get(true);
|
||||
let req = waitForChange(inst);
|
||||
|
||||
let first = new Session();
|
||||
first.ourTeam = "Team A";
|
||||
first.theirTeam = "Team 1";
|
||||
first.goal = 2;
|
||||
first.anotherGame();
|
||||
first.currentGame.currentRound.winner = Team.We;
|
||||
first.anotherGame();
|
||||
|
||||
let second = new Session();
|
||||
second.ourTeam = "Team B";
|
||||
second.theirTeam = "Team 2";
|
||||
second.goal = 3;
|
||||
second.anotherGame();
|
||||
second.currentGame.currentRound.raise(Team.We);
|
||||
second.currentGame.currentRound.winner = Team.They;
|
||||
|
||||
await req;
|
||||
|
||||
let putFirst = SessionRepo.put(first, inst);
|
||||
let putSecond = SessionRepo.put(second, inst);
|
||||
await Promise.all([putFirst, putSecond]);
|
||||
|
||||
let sessions = await SessionRepo.getAll(inst);
|
||||
assert.strictEqual(sessions.length, 2, "two sessions stored");
|
||||
assert.notStrictEqual(sessions[0].id, sessions[1].id, "IDs don't match");
|
||||
|
||||
for (let session of sessions) {
|
||||
let expected = null;
|
||||
if (session.id === first.id) {
|
||||
expected = first.toStruct();
|
||||
} else if (session.id === second.id) {
|
||||
expected = second.toStruct();
|
||||
}
|
||||
|
||||
assert.deepEqual(session.toStruct(), expected, "sessions match");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
2
test.js
2
test.js
@ -6,6 +6,7 @@ import game from "./models/game.test.js";
|
||||
import session from "./models/session.test.js";
|
||||
|
||||
import db from "./data/db.test.js";
|
||||
import session_repo from "./data/session_repo.test.js";
|
||||
|
||||
QUnit.module("models", function() {
|
||||
round();
|
||||
@ -16,4 +17,5 @@ QUnit.module("models", function() {
|
||||
|
||||
QUnit.module("data", function() {
|
||||
db();
|
||||
session_repo();
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user