UNPKG

harperdb

Version:

HarperDB is a distributed database, caching service, streaming broker, and application development platform focused on performance and ease of use.

151 lines (150 loc) 8.04 kB
import type { User } from '../security/user.ts'; import type { OperationFunctionName } from '../server/serverHelpers/serverUtilities.ts'; import { DatabaseTransaction } from './DatabaseTransaction.ts'; import { IterableEventQueue } from './IterableEventQueue.ts'; import type { Entry, RecordObject } from './RecordEncoder.ts'; import { RequestTarget } from './RequestTarget.ts'; export interface ResourceInterface<Record extends object = any> extends Partial<RecordObject>, Pick<UpdatableRecord<Record>, 'addTo' | 'subtractFrom'> { allowRead(user: User, target: RequestTarget, context: Context): boolean | Promise<boolean>; get?(target?: RequestTargetOrId): (Record & Partial<RecordObject>) | Promise<Record & Partial<RecordObject>> | AsyncIterable<Record & Partial<RecordObject>> | Promise<AsyncIterable<Record & Partial<RecordObject>>>; search?(target: RequestTarget): AsyncIterable<Record & Partial<RecordObject>>; allowCreate(user: User, record: Promise<Record & RecordObject>, context: Context): boolean | Promise<boolean>; create?(newRecord: Partial<Record & RecordObject>, target: RequestTargetOrId): void | (Record & Partial<RecordObject>) | Promise<Record & Partial<RecordObject>>; post?(target: RequestTargetOrId, newRecord: Partial<Record & RecordObject>): void | (Record & Partial<RecordObject>) | Promise<Record & Partial<RecordObject>>; allowUpdate(user: User, record: Promise<Record & RecordObject>, context: Context): boolean | Promise<boolean>; put?(record: Record & RecordObject, target: RequestTargetOrId): void | (Record & Partial<RecordObject>) | Promise<void | (Record & Partial<RecordObject>)>; patch?(record: Partial<Record & RecordObject>, target: RequestTargetOrId): void | (Record & Partial<RecordObject>) | Promise<void | (Record & Partial<RecordObject>)>; update?(updates: Record & RecordObject, fullUpdate: true): ResourceInterface<Record & Partial<RecordObject>>; update?(updates: Partial<Record & RecordObject>, fullUpdate?: boolean): ResourceInterface<Record & Partial<RecordObject>> | Promise<ResourceInterface<Record & Partial<RecordObject>> | UpdatableRecord<Record & Partial<RecordObject>>>; allowDelete(user: User, target: RequestTarget, context: Context): boolean | Promise<boolean>; delete?(target: RequestTargetOrId): boolean | Promise<boolean>; invalidate(target: RequestTargetOrId): void | Promise<void>; publish?(target: RequestTargetOrId, record: Record, options?: any): void; subscribe?(request: SubscriptionRequest): AsyncIterable<Record> | Promise<AsyncIterable<Record>>; doesExist(): boolean; wasLoadedFromSource(): boolean | void; } export interface Context { /** The user making the request */ user?: User; /** The database transaction object */ transaction?: DatabaseTransaction; /** If the operation that will be performed with this context should check user authorization */ authorize?: number; /** The last modification time of any data that has been accessed with this context */ lastModified?: number; /** The time at which a saved record should expire */ expiresAt?: number; /** Indicates that caching should not be applied */ noCache?: boolean; /** Indicates that values from the source data should be stored as a cached value */ noCacheStore?: boolean; /** Only return values from the table, and don't use data from the source */ onlyIfCached?: boolean; /** Allows data from a caching table to be used if there is an error retrieving data from the source */ staleIfError?: boolean; /** Indicates any cached data must be revalidated */ mustRevalidate?: boolean; /** An array of nodes to replicate to */ replicateTo?: string[]; replicateFrom?: boolean; replicatedConfirmation?: number; originatingOperation?: OperationFunctionName; previousResidency?: string[]; loadedFromSource?: boolean; nodeName?: string; resourceCache?: Map<Id, any>; _freezeRecords?: boolean; } export interface SourceContext<TRequestContext = Context, Record extends object = any> { /** The original request context passed from the caching layer */ requestContext: TRequestContext; /** The existing record, from the existing entry (if any) */ replacingRecord?: Record; /** The existing database entry (if any) */ replacingEntry?: Entry; /** The version/timestamp of the existing record */ replacingVersion?: number; /** Indicates that values from the source data should NOT be stored as a cached value */ noCacheStore?: boolean; /** Reference to the source Resource instance */ source?: ResourceInterface<Record>; /** Shared resource cache from parent context for visibility of modifications */ resourceCache?: Map<Id, any>; /** Database transaction for the context */ transaction?: DatabaseTransaction; /** The time at which the cached entry should expire (ms since epoch) */ expiresAt?: number; /** The last modification time of any data accessed with this context */ lastModified?: number; } export type Operator = 'and' | 'or'; export type Comparator = 'between' | 'contains' | 'ends_with' | 'eq' | 'equals' | 'greater_than' | 'greater_than_equal' | 'less_than' | 'less_than_equal' | 'ne' | 'not_equal' | 'starts_with'; export type DirectCondition<Record extends object = any> = TypedDirectCondition<Record, keyof Record>; interface TypedDirectCondition<Record extends object, Property extends keyof Record> { attribute?: keyof Record | Array<keyof Record> | string | string[]; search_attribute?: keyof Record | Array<keyof Record> | string | string[]; comparator?: Comparator; search_type?: Comparator; value?: Record[Property]; search_value?: Record[Property]; } interface ConditionGroup<Record extends object = any> { conditions?: Conditions<Record>; operator?: Operator; } export type Condition<Record extends object = any> = DirectCondition<Record> & ConditionGroup<Record>; export type Conditions<Record extends object = any> = Condition<Record>[]; export interface Sort<Record extends object = any> { attribute: keyof Record; descending?: boolean; next?: Sort<Record>; } export interface SubSelect { name: string; select: (string | SubSelect)[]; } export type Select = (string | SubSelect)[]; export interface SubscriptionRequest { /** The starting time of events to return (defaults to now) */ startTime?: number; /** The count of previously recorded events to return */ previousCount?: number; /** If the current record state should be omitted as the first event */ omitCurrent?: boolean; onlyChildren?: boolean; includeDescendants?: boolean; supportsTransactions?: boolean; rawEvents?: boolean; listener: Listener; } export type Query = RequestTarget; export type RequestTargetOrId = RequestTarget | Id; export type Id = number | string | (number | string | null)[] | null; export type UpdatableRecord<Record extends object = any> = TypedUpdatableRecord<Record, keyof Record>; interface TypedUpdatableRecord<Record extends object, Property extends keyof Record> extends RecordObject { set(property: Property, value: Record[Property]): void; getProperty(property: Property): Record[Property]; addTo(property: Property, value: Record[Property]): void; subtractFrom(property: Property, value: Record[Property]): void; } export interface Subscription<Event extends object = any> extends IterableEventQueue<Event> { new (listener: Listener<Event>): any; listener: Listener<Event>; subscriptions: Listener<Event>[]; startTime?: number; end(): void; toJSON(): { name: 'subscription'; }; } type Listener<Payload extends object = any> = (payload: ListenerPayload<Payload>) => void; interface ListenerPayload<Payload extends object = any> { id: Id; localTime: number; value: Payload; version: number; type: string; beginTxn: boolean; } export {};