@getanthill/datastore
Version:
Event-Sourced Datastore
283 lines (243 loc) • 6.75 kB
text/typescript
import type {
AxiosResponse,
AxiosResponseHeaders,
RawAxiosResponseHeaders,
} from 'axios';
import type { ModelConfig } from '../typings';
import type { DatastoreConfig } from './Datastore';
import type Datastore from './Datastore';
export type { AxiosResponse, DatastoreConfig };
import { omit } from 'lodash';
export default class Model<T> {
modelConfig: ModelConfig;
datastore: Datastore;
constructor(datastore: Datastore, modelConfig: ModelConfig) {
this.modelConfig = modelConfig;
this.datastore = datastore;
}
get name() {
return this.modelConfig.name;
}
async request(handler: Function, ...args: any[]): Promise<any> {
const { data } = await handler.call(this.datastore, ...args);
return data;
}
heartbeat(): Promise<{ status: string }> {
return this.request(this.datastore.heartbeat);
}
createModel(): Promise<any> {
return this.request(this.datastore.createModel, this.modelConfig);
}
updateModel(): Promise<any> {
return this.request(this.datastore.updateModel, this.modelConfig);
}
createModelIndexes(): Promise<any> {
return this.request(this.datastore.createModelIndexes, this.modelConfig);
}
getSchema(): Promise<any> {
return this.request(this.datastore.getSchema, this.name);
}
async encryptOne(payload: Partial<T>, fields: string[] = []): Promise<T> {
const [decrypted] = await this.request(
this.datastore.encrypt,
this.name,
[payload],
fields,
);
return decrypted;
}
encryptMany(payloads: Partial<T>[], fields: string[] = []): Promise<T[]> {
return this.request(this.datastore.encrypt, this.name, payloads, fields);
}
async decryptOne(payload: Partial<T>, fields: string[] = []): Promise<T> {
const [decrypted] = await this.request(
this.datastore.decrypt,
this.name,
[payload],
fields,
);
return decrypted;
}
decryptMany(payloads: Partial<T>[], fields: string[] = []): Promise<T[]> {
return this.request(this.datastore.decrypt, this.name, payloads, fields);
}
createOne(payload: Partial<T>, headers?: object): Promise<T> {
return this.request(this.datastore.create, this.name, payload, headers);
}
createMany(payloads: Partial<T>[]): Promise<T[]> {
return Promise.all(payloads.map((p) => this.createOne(p)));
}
/**
* @deprecated in favor of createOne + createMany
*/
create(payload: T | T[]): Promise<T | T[]> {
if (Array.isArray(payload)) {
return Promise.all(
payload.map((p) => this.request(this.datastore.create, this.name, p)),
) as Promise<T[]>;
}
return this.request(
this.datastore.create,
this.name,
payload,
) as Promise<T>;
}
updateOne(payload: Partial<T>, headers?: object): Promise<T> {
return this.request(
this.datastore.update,
this.name,
/* @ts-ignore */
payload[this.modelConfig.correlation_field],
omit(payload, this.modelConfig.correlation_field),
headers,
);
}
updateMany(payloads: Partial<T>[]): Promise<T[]> {
return Promise.all(payloads.map((p) => this.updateOne(p)));
}
/**
* @deprecated
*/
update(payload: object | object[]): Promise<T | T[]> {
if (Array.isArray(payload)) {
return Promise.all(
payload.map((p) =>
this.request(
this.datastore.update,
this.name,
p[this.modelConfig.correlation_field],
omit(p, this.modelConfig.correlation_field),
),
),
) as Promise<T[]>;
}
return this.request(
this.datastore.update,
this.name,
/* @ts-ignore */
payload[this.modelConfig.correlation_field],
omit(payload, this.modelConfig.correlation_field),
) as Promise<T>;
}
apply(
eventType: string,
payload: object,
headers?: object,
eventVersion = '0_0_0',
): Promise<T> {
return this.request(
this.datastore.apply,
this.name,
/* @ts-ignore */
payload[this.modelConfig.correlation_field],
eventType,
eventVersion,
omit(payload, this.modelConfig.correlation_field),
headers,
);
}
get(
correlationId: string,
headers?: {
'force-primary'?: true;
},
): Promise<T> {
return this.request(this.datastore.get, this.name, correlationId, headers);
}
count(query: T & Record<string, unknown>): Promise<number> {
return this.datastore.count.call(this.datastore, this.name, query);
}
find(
query: Partial<T>,
page?: number,
pageSize?: number,
headers?: {
page?: number;
'page-size'?: number;
'cursor-last-id'?: string;
'force-primary'?: true;
},
): Promise<T[]> {
return this.request(
this.datastore.find,
this.name,
query,
page,
pageSize,
headers,
);
}
events(
correlationId: string,
page?: number,
pageSize?: number,
): Promise<any[]> {
return this.request(
this.datastore.events,
this.name,
correlationId,
page,
pageSize,
);
}
version(correlationId: string, version: number): Promise<T> {
return this.request(
this.datastore.version,
this.name,
correlationId,
version,
);
}
at(correlationId: string, date: Date | string): Promise<T> {
return this.request(this.datastore.at, this.name, correlationId, date);
}
restore(correlationId: string, version: number): Promise<T> {
return this.request(
this.datastore.restore,
this.name,
correlationId,
version,
);
}
snapshot(correlationId: string): Promise<T> {
return this.request(this.datastore.snapshot, this.name, correlationId);
}
archive(correlationId: string, deep?: boolean): Promise<T> {
return this.request(this.datastore.archive, this.name, correlationId, deep);
}
unarchive(correlationId: string, deep?: boolean): Promise<T> {
return this.request(
this.datastore.unarchive,
this.name,
correlationId,
deep,
);
}
delete(correlationId: string, deep?: boolean): Promise<T> {
return this.request(this.datastore.delete, this.name, correlationId, deep);
}
async updateOverwhelmingly<T>(
query: object,
handler: (entity: T) => Promise<T>,
progress: (
stats: {
total: number;
done: number;
error: number;
progress: number;
restored: number;
},
entity: T,
headers: RawAxiosResponseHeaders | AxiosResponseHeaders,
) => void,
pageSize?: number,
) {
return this.datastore.updateOverwhelmingly<T>(
this.name,
query,
handler,
progress,
pageSize,
);
}
}