/* Jovian (c) 2020, License: MIT */ import { Class, PartialCustom } from '../type-transform'; import { Result } from '../common/util/enum.util'; export interface UpstreamIndexOptions { unique?: any; nonsparse?: any; } export interface UpstreamTargetMetadata { /** global id. e.g. $ref.local.s1.TestClass/local/6316e82600fe6e2c23fdbcb2 */ _gid: string; /** local id. e.g. 6316e82600fe6e2c23fdbcb2 */ _id: string; /** type full name, e.g. 'local.s1.TestClass' */ _tfn: string; /** type version, e.g. 0.0.1 */ _tv: string; /** data version (incremented for every update), e.g. 5 */ _v: number; /** time created */ _ct: number; /** time updated */ _ut: number; } export interface UpstreamDataIndexDefinition { name: string; options?: UpstreamIndexOptions; columns: {[column:string]: any}; } export const UpstreamComparisonType = Object.freeze({ 'greater than': '__GT', GT: '__GT', 'greater than or equal to': '__GTE', GTE: '__GTE', 'less than': '__LT', LT: '__LT', 'less than or equal to': '__LTE', LTE: '__LTE', 'not in': '__NOT_IN', 'none of': '__NOT_IN', 'is none of': '__NOT_IN', NOT_IN: '__NOT_IN', NIN: '__NOT_IN', 'any of': '__IN', 'is any of': '__IN', ANY_OF: '__IN', IN: '__IN', is: '__EQ', EQ: '__EQ', 'equal to': '__EQ', 'is not': '__NEQ', NEQ: '__NEQ', 'not equal to': '__NEQ', }); export interface UpstreamDataFilter { type: any; target: any; projection?: any; range?: { from?: any; to?: any; }; sort?: {[column: string]: number}[]; limit?: number; } export interface UpstreamDatastoreEndpointConfig { type: string; endpoint: string; credentials?: CredType; info?: any; } export interface UpstreamDatastoreConfig { path: string; endpoint: UpstreamDatastoreEndpointConfig; otherEndpoints?: { [endpointKey: string]: { type: string; endpoint: UpstreamDatastoreEndpointConfig; }; }; concurrency?: number; } export interface UpstreamDatastore { config: UpstreamDatastoreConfig; create: (type: Class | string, target: T, typeVersion?: string) => Promise>; read: (type: Class | string, gid: string, version?: number) => Promise>; update: (type: Class | string, gid:string, updater: UpstreamTargetUpdater) => Promise>; delete: (type: Class | string, gid:string) => Promise>; find: (type: Class | string, matcher: UpstreamTargetMatcher, limit?: number, indexName?: string) => Promise>; list: (type: Class | string, filter: UpstreamDataFilter) => Promise>; admin: UpstreamAdminOperations; index: UpstreamDataIndexes; } export interface UpstreamAdminOperations { dropCollection: (type: Class | string) => Promise>; }; export const ASC: 1 = 1; export const DESC: -1 = -1; export type UpstreamIndexSortValues = (typeof ASC | typeof DESC); export interface CollectionIndex { name: string; columns?: PartialCustom, options?: UpstreamIndexOptions, } export interface CollectionIndexes { [indexName: string]: CollectionIndex; } export interface KnownCollections { [typename: string]: { exists?: boolean; pending?: Promise>; pendingDelete?: Promise; collection?: T; timeIndexUpdated?: number; timeIndexDefinitionSet?: number; indexDefinitions?: CollectionIndexes; } } export interface UpstreamDataIndexes { checkDefinitions: (type: Class | string) => { definitions: CollectionIndexes; timeSet: number; timeUpdated: number; }; setDefinitions: (type: Class | string, indexDefinitions: CollectionIndexes) => void; create: (type: Class | string, index: CollectionIndex) => Promise>; delete: (type: Class | string, index: CollectionIndex) => Promise>; list: (type: Class | string) => Promise>; ensure: (type: Class | string, indexDefinitions?: CollectionIndexes, forceRecheck?: boolean) => Promise>; } export interface UpstreamIndexType { get: (target: Partial) => Promise; find: (target: Partial) => Promise; indexInfo: () => CollectionIndex; } export interface UpstreamTargetUpdater { set? : { [K in keyof T]: T[K] } typeVersionMatch?: string; versionMatch?: number; } export type UpstreamTargetMatcher = { [K in keyof T]: T[K] }; export interface UpstreamDatastoreActionItem { target: any; action: string; params: any; } export type UpstreamDatastorePathResolver = string | ((target: Partial) => Promise | string> | string); export interface UpstreamClassConfig { universe?: { [universeName: string]: UpstreamDatastorePathResolver; } index?: Indexes; } export const defaultUpstreamDatabaseName = 'upstream_data'; export const defaultUpstreamMetadataTable = '__upstream_meta'; export const defaultUpstreamTxDataTable = '__upstream_tx'; export const defaultUpstreamUniverse = 'local'; export const defaultUpstreamPath = 'local'; export const defaultUpstreamRoute = '__upstream_df_route'; export const upstreamRuntime = { skipMetaChecks: false, trackLastInsertIds: true, }; function aliasedName(type: Class) { if ((type as any).importedName) { return (type as any).importedName; } const path = (type as any).path; if (!path) { return type.name; } const prefix = path.namespace ? `${path.namespace}.` : ''; if (path.importedName) { return prefix + path.importedName; } else { return prefix + type.name; } } export function typeFullName(type: Class): string { const typeAny = (type as any); if (typeAny.globalName) { return typeAny.globalName; } if (typeAny?.nscInfo) { const season = typeAny.nscInfo.season ? typeAny.nscInfo.season : 1; typeAny.globalName = `${typeAny.nscInfo.name}.s${season}.${typeAny.nameAtDef ? typeAny.nameAtDef : typeAny.name}`; } else { typeAny.globalName = aliasedName(type); } return typeAny.globalName; } export function getGlobalId(type: Class | string, path: string, localId: string) { type = typeof type === 'string' ? type : typeFullName(type); if (type.indexOf('.') === -1) { type = `local.s1.${type}`; // throw new Error(`Global type without namespace (missing dot)`); } if (path) { return `$ref.${type}/${path}/${localId}`; } else { return `$ref.${type}/${localId}`; } } export function parseGlobalId(glid: string) { const lit = glid.split('/'); const header = lit[0]; lit[0] = ''; const localId = lit.pop(); const path = lit.filter(a => a).join('/'); return { typeFullName: header.substring(4), path, localId, }; }