Skip to content

Commit

Permalink
Added in-memory collection (#322)
Browse files Browse the repository at this point in the history
  • Loading branch information
RunDevelopment authored Oct 26, 2023
1 parent f671d56 commit 9f35b0e
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 1 deletion.
89 changes: 89 additions & 0 deletions src/lib/data-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,52 @@ export interface DBApi {
readonly architectures: CollectionApi<ArchId, Arch>;
}

/**
* A collections of key-value pairs.
*
* All operations guarantee atomicity, consistency, and isolation (see ACID).
* Durability is not always guaranteed and depends on the implementation.
*/
export interface CollectionApi<Id, Value> {
/**
* Returns the value of the given id.
*
* @throws if the id does not exist
*/
get(id: Id): Promise<Value>;
/**
* Returns all ids in the collection.
*/
getIds(): Promise<Id[]>;
/**
* Returns map representation of the collection.
*
* Changes to the map will not be reflected in the collection.
*/
getAll(): Promise<Map<Id, Value>>;

/**
* Sets the value of the given ids. The values of ids that already exist
* will be overwritten. Ids that do not exist will be added to be collection.
*
* The order of ids is irrelevant.
*
* @throws if there are duplicate ids.
*/
update(updates: Iterable<readonly [Id, Value]>): Promise<void>;
/**
* Removes the given ids from the collection.
*
* Duplicate ids and ids not in the collection are ignored. The order of ids is irrelevant.
*/
delete(ids: Iterable<Id>): Promise<void>;
/**
* Changes the id of a value.
*
* Does nothing if `from` and `to` are the same.
*
* @throws if `from` does not exist or `to` already exists.
*/
changeId(from: Id, to: Id): Promise<void>;
}

Expand Down Expand Up @@ -78,3 +117,53 @@ export function notifyOnWrite<Id, Value>(
},
};
}

/**
* A collection that is backed by a simple `Map`.
*/
export class MapCollection<Id, Value> implements CollectionApi<Id, Value> {
public map: Map<Id, Value>;

constructor(map: Map<Id, Value> = new Map()) {
this.map = map;
}

get(id: Id): Promise<Value> {
const value = this.map.get(id);
if (value === undefined) {
throw new Error(`No value for id ${String(id)}`);
}
return Promise.resolve(value);
}
getIds(): Promise<Id[]> {
return Promise.resolve([...this.map.keys()]);
}
getAll(): Promise<Map<Id, Value>> {
return Promise.resolve(new Map(this.map));
}
update(updates: Iterable<readonly [Id, Value]>): Promise<void> {
updates = new Map(updates);
for (const [id, value] of updates) {
this.map.set(id, value);
}
return Promise.resolve();
}
delete(ids: Iterable<Id>): Promise<void> {
for (const id of ids) {
this.map.delete(id);
}
return Promise.resolve();
}
changeId(from: Id, to: Id): Promise<void> {
const value = this.map.get(from);
if (value === undefined) {
throw new Error(`No value for id ${String(from)}`);
}
if (this.map.has(to)) {
throw new Error(`Id ${String(to)} already exists`);
}
this.map.delete(from);
this.map.set(to, value);
return Promise.resolve();
}
}
3 changes: 2 additions & 1 deletion src/lib/server/file-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ const modelApi: CollectionApi<ModelId, Model> = {

async update(updates: Iterable<readonly [ModelId, Model]>): Promise<void> {
await Promise.all(
[...updates].map(async ([id, value]) => {
[...new Map(updates)].map(async ([id, value]) => {
await writeModelData(id, value);
console.warn(`Updated model data of ${id}`);
})
Expand Down Expand Up @@ -220,6 +220,7 @@ function ofJsonFile<Id extends string, Value>(
},

async update(updates: Iterable<readonly [Id, Value]>): Promise<void> {
updates = new Map(updates);
await file.update((old) => {
for (const [id, value] of updates) {
old[id] = value;
Expand Down

0 comments on commit 9f35b0e

Please sign in to comment.