import 'rxjs/add/observable/forkJoin'; import 'rxjs/add/observable/of'; import 'rxjs/add/operator/concatAll'; import 'rxjs/add/operator/delayWhen'; import 'rxjs/add/operator/do'; import 'rxjs/add/operator/materialize'; import 'rxjs/add/operator/mergeMap'; import 'rxjs/add/operator/switchMap'; import 'rxjs/add/operator/filter'; import { Observable } from 'rxjs/Observable'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { Database, Predicate, Query, QueryToken, SelectorMeta } from '../db'; import { ParsedWSMsg, WSMsgToDBHandler, GeneralSchemaDef } from '../utils'; /** * 用于 SDK 非更新 `lift()` 接口 `CacheValidate` 字段的 * 定义。常见的各种 getXXX 都属于非更新接口。(对用于更新的 * `lift()` 接口,即所有 `method` 字段为 `'create' | * 'update' | 'delete'` 的,如常见的 updateXXX,无效。) * * 决定 SDK 非更新 `lift()` 接口内 `request` 字段对应的 * Observable(一般是一个网络请求),在多次“同样的”调用下的 * 缓存行为。 * * Note: 两次非更新 `lift()` 调用是否是“同样的”,决定于它们 * 的目标结果集是否相同。而对于一个规范的非更新 `lift()` 接口, * 其目标结果集的描述来自查询相关字段,如:`query`, `tableName`, * `fields` 等。这些字段会被用来生成缓存键。当两次非更新 `lift()` * 调用所得到的缓存键相同,这两次调用就被认为是“同样的”。 * (缓存键的生成与 `request` 字段对应的 HTTP 请求信息无关。) */ export declare enum CacheStrategy { /** * 在多次同样的 `lift()` 调用里,仅第一次会执行 `request` 字段 * 对应的 Observable。 * * 如果我们相信第一次 `request` 得到的数据,结合后续来自其他 * 更新源(如 websocket)的更新可以保证查询对应的结果集一直 * 完整可用,使用该选项,以省略不必要的网络请求。 */ Request = 200, /** * 在多次同样的 `lift()` 调用里,每次都会执行 `request` 字段 * 对应的 Observable。 * * 如果第一次 `request` 得到的数据,结合后续来自其他更新源 * (如 websocket)的更新,不足以保证查询对应的结果集一直完整 * 可用;但同时,又有理由相信,其他更新源不完整的更新数据 * (在 cache,即 rdb 里)依然能改善产品的数据同步,使用该选项, * 确保每次同样的 `lift()` 调用都会重新做网络请求,将结果集 * 数据完整性保持在可控范围,并依赖来自其他更新源的数据提供 * 产品上需要的同步能力。 * * Note: 如果来自其他更新源的数据在产品上的价值微乎其微,可以 * 选择直接使用 fetch 接口代替 `lift()` 接口。 */ Cache = 201 } export interface ApiResult { request: Observable | Observable; /** * 使用 fields 指定需要查询的字段,where 指定查询条件, * orderBy 指定结果排序规则。更多支持的选项请见具体类型定义。 */ query: Query; tableName: string; cacheValidate: U; /** * 设定必须有值(非 undefined)的字段,在数据层尽可能 * 保证推出的数据有这些字段。请搭配 padding 字段使用。 */ required?: (keyof T)[]; /** * 指定需要关联其他数据模型(M)查询获得的字段,以及 * 该字段对应值应该包含的 M 里的字段,如: * { * creator: ['_id', 'name'], * executor: ['_id', 'name', 'avatarUrl'] * } */ assocFields?: AssocField; /** * 指定不希望出现在查询结果里的字段。 * 注:ApiResult.query.fields 中指定的希望出现的字段 * 拥有更高优先级,除非 ApiResult.query.fields 未定义 * 或为空([])。 */ excludeFields?: string[]; /** * 与 required 字段搭配使用,用于补充数据(确保 * required 字段有值)。当 required 中的字段缺值 * (undefined),会使用提供的 padding 函数去获取完整 * 数据。注意:请确保 padding 函数返回的 Observable 有 * 异常处理机制(catch)。 */ padding?: (missedId: string) => Observable; } export declare type AssocField = { [P in keyof T]?: AssocField | string[]; }; export interface CApiResult { request: Observable; tableName: string; method: 'create'; } export interface UDResult { request: Observable; tableName: string; method: 'update' | 'delete'; clause: Predicate; } export declare type CUDApiResult = CApiResult | UDResult; export declare type CUDBufferObject = { kind: 'CUD'; tableName: string; method: string; value: any; }; export declare type SocketCUDBufferObject = { kind: 'SocketCUD'; socketMessage: ParsedWSMsg; }; export declare type SelectorBufferObject = { kind: 'Selector'; realSelectorInfo: ApiResult; proxySelector: BehaviorSubject>; }; export declare type BufferObject = CUDBufferObject | SocketCUDBufferObject | SelectorBufferObject; export declare class Net { fields: Map; database: Database | undefined; private requestMap; private primaryKeys; persistedDataBuffer: BufferObject[]; private msgToDB; private validate; constructor(schemas: { schema: GeneralSchemaDef; name: string; }[]); initMsgToDBHandler(handler: WSMsgToDBHandler): void; lift(result: ApiResult): QueryToken; lift(result: ApiResult): QueryToken; lift(result: ApiResult): QueryToken; lift(result: CUDApiResult): Observable; handleApiResult(result: ApiResult): QueryToken; handleCUDAResult(result: CUDApiResult): Observable; persist(database: Database): Observable; bufferResponse(result: ApiResult): QueryToken; bufferCUDResponse(result: CUDApiResult): Observable; bufferSocketPush(socketMessage: ParsedWSMsg): Observable; private genCacheKey; private handleRequestCache; private getInfoFromResult; }