Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added in-memory collection #322

Merged
merged 1 commit into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading