@darlean/base
Version:
Base types and definitions for creating Darlean actors and suites
170 lines (169 loc) • 8.97 kB
TypeScript
import { IInstanceWrapper } from './instances';
import { IPersistenceQueryOptions, IPersistenceQueryResult } from './services/persistence';
import { ITableSearchItem, ITableSearchRequest, ITableSearchResponse } from './services/tables';
import { Changeable, IChangeable } from '@darlean/utils';
/**
* Represents something that can be loaded and persisted.
*
* Note: This interface is called `IPersistablePure` to have no naming conflict with the {@IPersistable} interface
* which is used a lot by application code so deserves to have the short name `IPersistable`.
*/
export interface IPersistablePure<T> {
/**
* Returns the last known version of the persistable, or undefined when the version is not yet known.
*/
getVersion(): string | undefined;
/**
* Loads the value from the underlying persistence store.
* @param whenNotPresent Defines what should happen when the underlying store does not have a
* value. The default is `'keep'`, which keeps the existing value (see remarks). It can also
* be set to `'clear'` which clears the value.
* @returns The loaded value
* @Remarks When the store does not return a value, `load` returns `undefined`, but the internal value
* is not adjusted (still has the old value). This makes it easy to
* provide an {@link IPersistable} with a default initial value, then call {@link load}, and when
* no data was yet present in the store, the earlier assigned default value is still present. To
* alter this behaviour, set whenUndefined to `'clear'`, which will clear the internal value.
*/
load(whenNotPresent?: 'keep' | 'clear'): Promise<T | undefined>;
/**
* Stores the value in the underlying persistence store.
* @param condition When `dirty`, only store the value when it is marked as dirty (default). When `always`,
* the store is also performed when the value is not changed.
*/
persist(condition?: 'dirty' | 'always'): Promise<void>;
}
/**
* Represents a value that can be loaded, changed and persisted.
*/
export interface IPersistable<T> extends IChangeable<T>, IPersistablePure<T> {
/**
* Returns the last known version of the persistable, or undefined when the version is not yet known.
*/
getVersion(): string | undefined;
/**
* Loads the value from the underlying persistence store.
* @param whenNotPresent Defined what should happen when the underlying store does not have a
* value. The default is `'keep'`, which keeps the existing value (see remarks). It can also
* be set to `'clear'` which clears the value.
* @returns The loaded value
* @Remarks When the store does not return a value, `load` returns `undefined`, but the internal value
* is not adjusted (still has the old value). This makes it easy to
* provide an {@link IPersistable} with a default initial value, then call {@link load}, and when
* no data was yet present in the store, the earlier assigned default value is still present. To
* alter this behaviour, set whenUndefined to `'clear'`, which will clear the internal value.
*/
load(whenNotPresent?: 'keep' | 'clear'): Promise<T | undefined>;
/**
* Stores the value in the underlying persistence store.
* @param condition When `dirty`, only store the value when it is marked as dirty (default). When `always`,
* the store is also performed when the value is not changed.
*/
persist(condition?: 'dirty' | 'always'): Promise<void>;
}
/**
* Interface to persistent storage that can be used to load and store values persistently.
*/
export interface IPersistence<T> {
/**
* Returns a new {@link IPersistable} instance with the provided partition key, sort key and
* initial value.
* @param partitionKey The partition key that will be used for later load and store actions
* @param sortKey The sort key that will be used for later load and store actions
* @param value The initial value that is assigned to {@IPersistable.value}.
* @remarks This method just returns a new {@link IPersistence} with an optional default value set; it does
* *not* perform and {@link load}ing of the data from the persistence store. For that, use {@link load}.
*/
persistable(partitionKey?: string[], sortKey?: string[], value?: T): IPersistable<T>;
/**
* Creates a new {@link IPersistable} instance with the provided partition and sort key, and
* loads the most recent value from the persistence store.
* @param partitionKey The partition key that will be used for this and later load and store actions
* @param sortKey The sort key that will be used for this and later load and store actions
*/
load(partitionKey?: string[], sortKey?: string[]): Promise<IPersistable<T>>;
/**
* Returns a new sub-persistence interface with the provided partition key added
* to the partition of the current instance.
* @param partitionKey The partition key fields that will be added to the existing partition key fields.
* Must be `undefined` or `[]` when the current instance already has a sort key assigned.
*/
sub(partitionKey?: string[]): IPersistence<T>;
/**
* Performs a query with the provided options.
* @param options
*/
query(options: IPersistenceQueryOptions): Promise<IPersistenceQueryResult<T>>;
}
export interface IMultiChunkTableSearchRequest {
maxTotalItems?: number;
}
/**
* Persistence that uses a Darlean Table as underlying storage. The interface is different from the similar
* {@link IPersistence}, but the returned {@link IPersistable} instances from the {@link persistable} and {@link load}
* methods are compatible.
*/
export interface ITablePersistence<T> {
/**
* Searches in the underlying table with the provided options.
*/
search(options: ITableSearchRequest): Promise<ITableSearchResponse>;
/**
* Convenience wrapper around {@link search} that returns an asynchronous iterator that can be used
* to iterate over the result chunks.
*/
searchChunks(options: ITableSearchRequest & IMultiChunkTableSearchRequest): AsyncGenerator<ITableSearchResponse, void>;
/**
* Convenience wrapper around {@link search} that returns an asynchronous iterator that can be used
* to iterate over the individual result items.
*/
searchItems(options: ITableSearchRequest & IMultiChunkTableSearchRequest): AsyncGenerator<ITableSearchItem, void>;
/**
* Returns a new {@link IPersistable} instance with the key and initial value.
* @remarks This method just returns a new {@link IPersistence} with an optional default value set; it does
* *not* perform and loading of the data from the persistence store. For that, use {@link load} or {@link IPersistable.load}.
*/
persistable(key: string[], value: T | undefined): IPersistable<T>;
/**
* Creates a new {@link IPersistable} instance with the provided key, and
* loads the most recent value from the persistence store.
*/
load(key: string[]): Promise<IPersistable<T>>;
}
export interface IVolatileTimerHandle {
cancel(): void;
pause(duration?: number): void;
resume(delay?: number): void;
}
export type VolatileTimerFactory<T extends object> = (wrapper: IInstanceWrapper<T>) => IVolatileTimer;
export interface IVolatileTimer {
once(handler: Function, delay: number, args?: unknown): IVolatileTimerHandle;
repeat(handler: Function, interval: number, delay?: number, nrRepeats?: number, args?: unknown): IVolatileTimerHandle;
}
export interface IMigrationDefinition<OldState extends IMigrationState = IMigrationState, Context = unknown> {
version: string;
name: string;
migrator: (persistable: IPersistable<OldState>, context: Context) => Promise<Context | void>;
}
export interface IMigrationState {
migrationInfo: string;
}
export interface IMigrationContext<T extends IMigrationState = IMigrationState, Context = unknown> {
perform(state: IPersistable<T>, nameResolver: () => Promise<string>, defaultValue: T): Promise<Context>;
}
/**
* Base class for creating custom persistables.
*/
export declare abstract class CustomPersistable<T> extends Changeable<T> implements IPersistable<T> {
private _version?;
constructor(value: T | undefined, dirty?: boolean);
getVersion(): string | undefined;
load(whenUndefined?: 'keep' | 'clear'): Promise<T | undefined>;
persist(condition?: 'dirty' | 'always'): Promise<void>;
protected setVersion(version: string | undefined): void;
protected abstract _load(): Promise<{
value: T | undefined;
version?: string;
}>;
protected abstract _persist(value: T | undefined, version: string): Promise<void>;
}