AsyncStore contracts#

@palmyralabs/palmyra-wire · lib/palmyra/store/AsyncStore.ts

Overview#

The TypeScript contract surface for every store the factory emits. Four read interfaces (LookupStore, QueryStore, GridStore, TreeQueryStore), one write interface (DataStore), plus helpers (ChartStore, AuthDecorator). DataStore is the form contract — there is no separate AsyncFormStore.

Interfaces#

interface BaseQueryStore<T> {
  getClient(): AxiosInstance;
}

interface AbstractQueryStore<T> extends BaseQueryStore<T> {
  query(request: QueryRequest): Promise<QueryResponse<T>>;
}

interface LookupStore<T> extends AbstractQueryStore<T> {}

interface QueryStore<T> extends AbstractQueryStore<T> {
  queryLayout(request: QueryRequest): Promise<any>;
  get(request: GetRequest): Promise<T>;
  getIdentity(o: T): any;
  getIdProperty(): strings;
}

interface GridStore<T> extends QueryStore<T> {
  export(request: ExportRequest): void;
}

interface DataStore<T> extends QueryStore<T> {
  post(data: T, request?: PostRequest):   Promise<T>;
  put(data: T,  request?: PutRequest):    Promise<T>;
  save(data: T, request?: PutRequest):    Promise<T>;
  remove(key: T | any, request?: RemoveRequest): Promise<T>;
}

interface TreeQueryStore<T, R> extends BaseQueryStore<T> {
  getChildren(data: T, options?: AbstractHandler): Promise<QueryResponse<R>>;
  getRoot(options?: AbstractHandler): Promise<R>;
}

interface ChartStore<T> {
  query(request: QueryRequest): Promise<T[]>;
}

interface AuthDecorator {
  decorate(request: any): void;
}

interface DefaultQueryParams {
  filter?: Record<any, any>;
  sort?:   strings;
}

Shared StoreOptions#

Every concrete store takes this options object (from lib/palmyra/store/Types.ts):

interface StoreOptions {
  endPointOptions?: Record<string, string | number>;   // vars substituted into {placeholders} in the URL
  axiosCustomizer?: (axios: AxiosInstance) => void;    // per-store axios tweak (interceptors, headers)
}

type IEndPoint = string | MultiEndPoint;

interface MultiEndPoint {
  query?:  string;
  get?:    string;
  post?:   string;
  put?:    string;
  delete?: string;
}

type strings = string | string[];

type APIErrorHandlerFactory = (config?: any) => (error: any) => boolean;

Example#

Depend on the contract, not the class — this keeps a page testable with a mock store:

import type { DataStore } from '@palmyralabs/palmyra-wire';

async function archiveUser(store: DataStore<User>, id: number) {
  const user = await store.get({ [store.getIdProperty() as string]: id });
  return store.save({ ...user, status: 'ARCHIVED' });
}