docs: update README, add some more jsdoc

This commit is contained in:
Andy Burke 2025-07-15 00:15:28 -07:00
parent 22a8b4d03f
commit 55a73c3d0a
10 changed files with 155 additions and 30 deletions

107
fsdb.ts
View file

@ -1,3 +1,8 @@
/**
* We just write to the disk to reduce complexity.
* @module
*/
import * as fs from '@std/fs';
import * as path from '@std/path';
import by_lurid from './organizers/by_lurid.ts';
@ -29,7 +34,9 @@ export interface FSDB_INDEXER<T> {
lookup(value: string, options?: FSDB_SEARCH_OPTIONS<T>): Promise<string[]>;
}
/** Represents a collection of like items within the database on disk. */
/**
* Represents a collection of like items within the database on disk.
*/
export class FSDB_COLLECTION<T extends Record<string, any>> {
private config: FSDB_COLLECTION_CONFIG;
public INDEX: Record<string, FSDB_INDEXER<any>>;
@ -93,7 +100,14 @@ export class FSDB_COLLECTION<T extends Record<string, any>> {
Deno.writeTextFileSync(collection_info_file_path, collection_info_json);
}
/** Get the "organized" path for the given item within the database. */
/**
* Get the "organized" path for the given item within the database.
*
* @param {any} item The item to organize.
* @param {string} [id_field] Optional override for id_field.
*
* @returns {string} An organized, resolved item path.
*/
public get_organized_item_path(item: any, id_field?: string): string {
const id: string = item[id_field ?? this.config.id_field];
const path_elements: string[] = this.config.organize(id);
@ -101,11 +115,24 @@ export class FSDB_COLLECTION<T extends Record<string, any>> {
return resolved_item_path;
}
/** Get the "organized" path for the given id within the database. */
/**
* Get the "organized" path for the given id within the database.
*
* @param {string} id The id to organize.
*
* @returns {string} An organized, resolved path for the id.
*/
public get_organized_id_path(id: string): string {
return this.get_organized_item_path({ id }, 'id');
}
/**
* Ensure the item's directory exists.
*
* @param {any} item The item to be stored.
* @param {string} [id_field] Optional override of the id_field.
* @returns {string} An organized, resolved path for the item, with the containing directory created.
*/
private async ensure_item_path(item: any, id_field?: string): Promise<string> {
const organized_item_path: string = this.get_organized_item_path(item, id_field);
const organized_item_dir: string = path.dirname(organized_item_path);
@ -135,7 +162,13 @@ export class FSDB_COLLECTION<T extends Record<string, any>> {
}
}
/** Get an item from the collection given its id. */
/**
* Get an item from the collection.
*
* @param {string} id The item id to look up.
*
* @returns {Promise<T | null>} Returns a promise for either the item or `null` if it cannot be found.
*/
async get(id: string): Promise<T | null> {
const item_path: string = this.get_organized_id_path(id);
const item_exists: boolean = await fs.exists(item_path);
@ -155,7 +188,13 @@ export class FSDB_COLLECTION<T extends Record<string, any>> {
return item;
}
/** Create an item in the collection. */
/**
* Create an item in the collection.
*
* @param {T} item The item to be stored in the collection.
*
* @returns {Promise<T>} Returns a promise for the item after it has been stored.
*/
async create(item: T): Promise<T> {
const item_path: string = this.get_organized_item_path(item);
const item_exists: boolean = await fs.exists(item_path);
@ -176,7 +215,13 @@ export class FSDB_COLLECTION<T extends Record<string, any>> {
return item;
}
/** Update the given item in the collection, requiring the id to be stable. */
/**
* Update the given item in the collection, requiring the id to be stable.
*
* @param {T} item The item to be updated in the collection.
*
* @returns {Promise<T>} Returns a promise for the item after it has been updated.
*/
async update(item: T): Promise<T> {
const item_path: string = this.get_organized_item_path(item);
const id: string = item[this.config.id_field];
@ -199,7 +244,13 @@ export class FSDB_COLLECTION<T extends Record<string, any>> {
return item;
}
/** Delete the given item from the collection. */
/**
* Delete the given item from the collection.
*
* @param {T} item The item to be updated in the collection.
*
* @returns {Promise<T>} Returns a promise for the item after it has been deleted or `null` if the item wasn't in the collection.
*/
async delete(item: T): Promise<T | null> {
const item_path = this.get_organized_item_path(item);
const item_exists = await fs.exists(item_path);
@ -241,7 +292,13 @@ export class FSDB_COLLECTION<T extends Record<string, any>> {
return item;
}
/** Iterate through the items. */
/**
* Iterate through all items in the collection.
*
* @param {FSDB_SEARCH_OPTIONS} options The item to be updated in the collection.
*
* @returns {Promise<WALK_ENTRY<T>[]>} Returns an array of `WALK_ENTRY` items for items given the input options.
*/
async all({
limit = 100,
offset = 0,
@ -314,16 +371,22 @@ export class FSDB_COLLECTION<T extends Record<string, any>> {
return results;
}
/** Use indexes to search for matching items. */
async find(criteria: Record<string, any>, input_options?: FSDB_SEARCH_OPTIONS<T>): Promise<WALK_ENTRY<T>[]> {
/**
* Use indexes to search for matching items.
*
* @param {Record<string, any>} criteria The criteria an item should match, usually a field like `{ email: 'someone@somewhere.com` }`
* @param {FSDB_SEARCH_OPTIONS<T>} options
* @returns {Promise<WALK_ENTRY<T>[]>} Returns an array of `WALK_ENTRY` items for items given the input options.
*/
async find(criteria: Record<string, any>, options?: FSDB_SEARCH_OPTIONS<T>): Promise<WALK_ENTRY<T>[]> {
if (Deno.env.get('FSDB_PERF')) performance.mark('fsdb_find_begin');
const options: FSDB_SEARCH_OPTIONS<T> = {
const find_options: FSDB_SEARCH_OPTIONS<T> = {
...{
limit: 100,
offset: 0
},
...(input_options ?? {})
...(options ?? {})
};
const results: WALK_ENTRY<T>[] = [];
@ -333,12 +396,12 @@ export class FSDB_COLLECTION<T extends Record<string, any>> {
const indexer_for_search_key: FSDB_INDEXER<T> | undefined = this.INDEX[search_key];
const value: string = criteria[search_key];
if (indexer_for_search_key) {
item_paths.push(...await indexer_for_search_key.lookup(value, input_options));
item_paths.push(...await indexer_for_search_key.lookup(value, find_options));
}
}
const limit = options?.limit ?? 100;
const offset = options?.offset ?? 0;
const limit = find_options.limit ?? 100;
const offset = find_options.offset ?? 0;
let counter = 0;
for await (const item_path of item_paths) {
@ -369,13 +432,19 @@ export class FSDB_COLLECTION<T extends Record<string, any>> {
this.emit('find', {
criteria,
options,
options: find_options,
results
});
return results;
}
/**
* Add an event listener.
*
* @param {string} event The event to listen for.
* @param {(event_data: any) => void} handler The handler for the event.
*/
public on(event: string, handler: (event_data: any) => void) {
const listeners: ((event: any) => void)[] = this.event_listeners[event] = this.event_listeners[event] ?? [];
if (!listeners.includes(handler)) {
@ -393,6 +462,12 @@ export class FSDB_COLLECTION<T extends Record<string, any>> {
}
}
/**
* Remove an event listener.
*
* @param {string} event The event that was listened to.
* @param {(event_data: any) => void} handler The handler that was registered that should be removed.
*/
public off(event: string, handler: (event_data: any) => void) {
const listeners: ((event: any) => void)[] = this.event_listeners[event] = this.event_listeners[event] ?? [];
if (listeners.includes(handler)) {