datum-focus
Version:
Data shape, model, metadata, JSON, JSON Schema, GraphQL, MongoDB query and aggregations, iterator generators
120 lines (107 loc) • 3.18 kB
text/typescript
import sift, { Query } from "sift";
import { v4 as guid } from "uuid";
import record from ".../../generation/generators/record";
import { Guid } from "../../string";
import { Model } from "../../model";
import { entity, Entity, Repository, RESULT_CODE__ACCEPTED, RESULT_CODE__CREATED, RESULT_CODE__OK, StoreResult } from "../repository";
export type K = { _id: Guid };
async function* asyncIterable<T extends {}>(
collection: Record<Guid, T>,
query?: Query<T>
): AsyncGenerator<Entity<T>> {
const test = sift(query || {});
const keys = Object.keys(collection);
for (const _id of keys) {
const record = collection[_id];
if (!record) {
continue;
}
const entity = { _id, ...record };
if (test(entity)) {
yield Promise.resolve(entity);
}
}
}
export class EphemeralRepository<T extends {} = {}>
implements Repository<T>
{
constructor(public readonly model: Model<T>, collection?: Record<Guid, Entity<T>>) {
this.collection = collection || {};
}
public readonly collection: Record<Guid, Entity<T>>;
get count(): Promise<number> {
return Promise.resolve(Object.keys(this.collection).length);
}
create(record: T): Promise<StoreResult<T>> {
const ntt = entity(record);
this.collection[ntt._id] = ntt;
return Promise.resolve(<StoreResult<T>>{
_id: ntt._id,
rescode: RESULT_CODE__CREATED,
});
}
delete(_id: string): Promise<StoreResult<T>> {
const record = this.collection[_id];
if (!record) {
return Promise.resolve(<StoreResult<T>>{
_id,
rescode: RESULT_CODE__OK,
});
}
delete this.collection[_id];
return Promise.resolve(<StoreResult<T>>{
_id,
rescode: RESULT_CODE__ACCEPTED,
});
}
find(_id: string): Promise<StoreResult<T>> {
let entity!: Entity<T>;
for (const ntt of Object.values(this.collection)) {
if (ntt._id === _id) {
entity = ntt;
break;
}
}
return Promise.resolve({
_id,
data: entity,
rescode: RESULT_CODE__OK,
});
}
/*
grow(amount: number): Promise<void> {
return new Promise(resolve => {
const name = this.model.name;
console.log(`Generating ${amount} fake ${name}...`);
for (let i = 0; i < amount; i++) {
Object.assign(this.collection, {
[guid()]: <T>record(this.model.fields, getModelMap()),
});
}
console.log(`${Object.keys(this.collection).length} ${name}s total.`);
resolve();
});
}*/
select(query?: Query<T>): Promise<AsyncIterable<Entity<T>>> {
return Promise.resolve(asyncIterable<T>(this.collection, query));
}
shrink(amount: number): Promise<void> {
return new Promise(resolve => {
const keys = Object.keys(this.collection);
keys
.splice(Math.max(0, keys.length - amount))
.forEach(key => delete this.collection[key]);
resolve();
});
}
update({
_id,
...record
}: Entity<Partial<T>>): Promise<StoreResult<T>> {
Object.assign(this.collection, { [_id]: record });
return Promise.resolve(<StoreResult<T>>{
_id,
rescode: RESULT_CODE__ACCEPTED,
});
}
}