UNPKG

@actyx/sdk

Version:
115 lines (104 loc) 4.3 kB
/* * Actyx SDK: Functions for writing distributed apps * deployed on peer-to-peer networks, without any servers. * * Copyright (C) 2021 Actyx AG */ import { SubscribeMonotonicResponseIO } from '.' import { Observable, EMPTY } from '../../node_modules/rxjs' import { EventsSortOrder, NodeId, OffsetMap, TimeInjector, Where } from '../types' import { mockEventStore } from './mockEventStore' import { testEventStore, TestEventStore } from './testEventStore' import { Event, Events, OffsetsResponse, UnstoredEvents } from './types' /** * Get the store's node id. */ export type RequestNodeId = () => Observable<NodeId> /** * Request the full present of the store, so the maximum CONTIGUOUS offset for each source that the store has seen and ingested. * The store will NEVER deliver events across PSN gaps. So the 'present' signifies that which the store is willing to deliver to us. * If Offset=2 of some source never reaches our store, that source’s present will never progress beyond Offset=1 for our store. * Nor will it expose us to those events that lie after the gap. * This also returns the events per source which are pending replication to this node. */ export type RequestOffsets = () => Promise<OffsetsResponse> /** * This method is only concerned with already persisted events, so it will always return a finite (but possibly large) * stream. * It is an ERROR to query with unbounded or future PSN. * * The returned event chunks can contain events from multiple sources. If the sort order is unsorted, we guarantee * that chunks will be sorted by ascending psn for each source. * * Looking for a semantic snapshot can be accomplished by getting events in reverse event key order and aborting the * iteration as soon as a semantic snapshot is found. * * Depending on latency between pond and store the store will traverse into the past a bit further than needed, but * given that store and pond are usually on the same machine this won't be that bad, and in any case this is perferable * to needing a way of sending a javascript predicate to the store. */ export type DoQuery = ( lowerBound: OffsetMap, // this is the lower bound, regardless of requested sort order. upperBound: OffsetMap, query: Where<unknown>, sortOrder: EventsSortOrder, horizon?: string, ) => Observable<Event> /** * This method is concerned with both persisted and future events, so it will always return an infinite stream. * * The returned event chunks can contain events from multiple sources. Any individual source will not time-travel. * There is not sorting between different sources, not even within a single chunk. * * Getting events up to a maximum event key can be achieved for a finite set of sources by specifying sort by * event key and aborting as soon as the desired event key is reached. */ export type DoSubscribe = ( lowerBound: OffsetMap, query: Where<unknown>, horizon?: string, ) => Observable<Event> export type DoSubscribeMonotonic = ( session: string, lowerBound: OffsetMap, query: Where<unknown>, horizon?: string, ) => Observable<SubscribeMonotonicResponseIO> /** * Store the events in the store and return them as generic events. */ export type DoPersistEvents = (events: UnstoredEvents) => Observable<Events> export type TypedMsg = { type: string } export type EventStore = { readonly offsets: RequestOffsets readonly queryUnchecked: ( aqlQuery: string, sortOrder: EventsSortOrder, lowerBound?: OffsetMap, ) => Observable<TypedMsg> readonly query: DoQuery readonly subscribe: DoSubscribe readonly subscribeUnchecked: (aqlQuery: string, lowerBound?: OffsetMap) => Observable<TypedMsg> readonly subscribeMonotonic: DoSubscribeMonotonic readonly persistEvents: DoPersistEvents } const noopEventStore: EventStore = { subscribe: () => EMPTY, subscribeUnchecked: () => EMPTY, subscribeMonotonic: () => EMPTY, query: () => EMPTY, queryUnchecked: () => EMPTY, offsets: () => Promise.resolve({ present: {}, toReplicate: {} }), persistEvents: () => EMPTY, } export const EventStore: { noop: EventStore mock: () => EventStore test: (nodeId?: NodeId, timeInjector?: TimeInjector) => TestEventStore } = { noop: noopEventStore, mock: mockEventStore, test: testEventStore, }