Add an abstract Database class

This commit is contained in:
Oliver-Akins 2025-04-30 21:57:32 -06:00
parent 48b31f7dec
commit 34be2b0626
4 changed files with 126 additions and 7 deletions

View file

@ -1,9 +1,34 @@
function createDiceTable(size) {
return {
name: `Dice/d${size}`,
buckets: {
type: `range`,
min: 1,
max: size,
step: 1,
},
graph: {
type: `bar`,
stacked: true,
},
};
};
export function registerMetaSettings() { export function registerMetaSettings() {
game.settings.register(__ID__, `tables`, { game.settings.register(__ID__, `tables`, {
scope: `world`, scope: `world`,
type: Array, type: Object,
config: false, config: false,
requiresReload: false, requiresReload: false,
default: {
"Dice/d4": createDiceTable(4),
"Dice/d6": createDiceTable(6),
"Dice/d8": createDiceTable(8),
"Dice/d10": createDiceTable(10),
"Dice/d12": createDiceTable(12),
"Dice/d20": createDiceTable(20),
"Dice/d100": createDiceTable(100),
},
}); });
game.settings.register(__ID__, `data`, { game.settings.register(__ID__, `data`, {

View file

@ -0,0 +1,89 @@
/* eslint-disable no-unused-vars */
export class Database {
// MARK: Table Ops
static createTable(tableConfig) {
throw new Error(`createTable() must be defined`);
};
/** @returns {Array<Table>} */
static getTables() {
const tables = game.settings.get(__ID__, `tables`);
return Object.values(tables) ?? [];
};
static getTable(tableID) {
const tables = game.settings.get(__ID__, `tables`);
if (!tables[tableID]) { return };
return tables[tableID];
};
static deleteTable(tableID) {
throw new Error(`deleteTable() must be defined`);
};
// MARK: Row Ops
static createRow(table, userID, row) {
throw new Error(`createRow() must be implemented`);
};
static getRows(tableID, userIDs, privacy = `none`) {
throw new Error(`getRows() must be implemented`);
};
static updateRow(table, userID, rowID, changes) {
throw new Error(`updateRow() must be implemented`);
};
static deleteRow(table, userID, rowID) {
throw new Error(`deleteRow() must be implemented`);
};
// MARK: Applications
static _apps = new Map();
/**
* Adds an application into the registry so that when a data update
* is received, we can re-render the sheets.
*
* @param app an ApplicationV2 instance
*/
static addApp(app) {
this._apps.set(app.id, app);
this.registerListeners();
};
/**
* Adds an application into the registry so that when a data update
* is received, we can re-render the sheets.
*
* @param app an ApplicationV2 instance
*/
static removeApp(app) {
this._apps.delete(app.id);
if (this._apps.size === 0) {
this.unregisterListeners();
};
};
/**
* Rerenders all of the applications that are displaying data from
* this database
*/
static render() {
for (const app of Object.values(this.apps)) {
app.render();
};
};
// MARK: Listeners
/**
* Used to listen for changes from other clients and rerender the apps
* as required in order to keep the data as up-to-date as possible.
*/
static registerListeners() {};
static unregisterListeners() {};
};
/* eslint-enable no-unused-vars */

View file

@ -1,9 +1,9 @@
/* eslint-disable no-unused-vars */ import { Database } from "./Database.mjs";
import { filterPrivateRows } from "../filterPrivateRows.mjs"; import { filterPrivateRows } from "../filterPrivateRows.mjs";
const { randomID, mergeObject } = foundry.utils; const { randomID, mergeObject } = foundry.utils;
export class MemoryDatabase { export class MemoryDatabase extends Database {
static #tables = { static #tables = {
"Dice/d10": { "Dice/d10": {
name: `Dice/d10`, name: `Dice/d10`,
@ -14,7 +14,8 @@ export class MemoryDatabase {
max: 10, max: 10,
step: 1, step: 1,
}, },
config: { graph: {
type: `bar`,
stacked: true, stacked: true,
}, },
}, },
@ -74,8 +75,8 @@ export class MemoryDatabase {
static #rows = {}; static #rows = {};
/** @returns {Array<Table>} */
static getTables() { static getTables() {
/** @type {Array<{ name: string; }>} */
return Object.values(this.#tables); return Object.values(this.#tables);
}; };
@ -146,5 +147,3 @@ export class MemoryDatabase {
static unregisterListeners() {}; static unregisterListeners() {};
}; };
/* eslint-enable no-unused-vars */

View file

@ -3,7 +3,13 @@ import { Logger } from "./Logger.mjs";
const { deepClone } = foundry.utils; const { deepClone } = foundry.utils;
const { StringField, NumberField } = foundry.data.fields; const { StringField, NumberField } = foundry.data.fields;
/**
* @param {unknown} value The value to validate
* @param {BucketConfig} options The bucket config for the table
* @returns Whether or not the value is valid for the table
*/
export function validateValue(value, options) { export function validateValue(value, options) {
/** @type {BucketConfig} */
let opts = deepClone(options); let opts = deepClone(options);
if (validatorTypes[opts.type] == null) { if (validatorTypes[opts.type] == null) {
Logger.error(`Failed to find type validator for: ${opts.type}`); Logger.error(`Failed to find type validator for: ${opts.type}`);