UNPKG

@platform/cell.typesystem

Version:

The 'strongly typed sheets' system of the CellOS.

194 lines (193 loc) 6.72 kB
import { Subject } from 'rxjs'; import { share, takeUntil } from 'rxjs/operators'; import { TypeClient } from '../../TypeSystem.core'; import { ERROR, ErrorList, MemoryCache, Uri, util } from './common'; import { TypedSheetData } from './TypedSheetData'; import { TypedSheetState } from './TypedSheetState'; import { SheetPool } from '../TypedSheet.SheetPool'; const fromClient = (client) => { const fetch = util.fetcher.fromClient(client); return { load: (ns) => TypedSheet.load({ fetch, ns }), }; }; export class TypedSheet { constructor(args) { this._dispose$ = new Subject(); this._data = {}; this.dispose$ = this._dispose$.pipe(share()); this.uri = Uri.ns(args.uri); this.implements = Uri.ns(args.implements); this.pool = args.pool; const pool = this.pool; const cache = args.cache || MemoryCache.create(); const event$ = args.event$ || new Subject(); const dispose$ = this.dispose$; this.event$ = event$.asObservable().pipe(takeUntil(dispose$), share()); this.state = TypedSheetState.create({ sheet: this, event$, fetch: args.fetch, cache }); this._ctx = TypedSheet.ctx({ fetch: this.state.fetch, event$, dispose$, cache, pool }); this._typeDefs = args.types; this._errorList = ErrorList.create({ defaultType: ERROR.TYPE.SHEET, errors: args.errors }); pool.add(this); } static ctx(args) { const fetch = args.fetch; const cache = args.cache || MemoryCache.create(); const event$ = args.event$ || new Subject(); const dispose$ = args.dispose$ || new Subject(); const pool = args.pool || SheetPool.create(); return { event$, dispose$, fetch, cache, pool, sheet: { load(args) { return TypedSheet.load(Object.assign(Object.assign({}, args), { fetch, cache, event$ })); }, create(args) { return TypedSheet.create(Object.assign(Object.assign({}, args), { fetch, cache, event$ })); }, }, }; } static async load(args) { var _a, _b, _c, _d; const { fetch, cache, event$ } = args; const sheetNs = Uri.ns(args.ns); const pool = args.pool || SheetPool.create(); if (pool.exists(args.ns)) { return pool.sheet(args.ns); } const res = await args.fetch.getNs({ ns: sheetNs.toString() }); if (res.error) { throw new Error(res.error.message); } if (!((_b = (_a = res.ns) === null || _a === void 0 ? void 0 : _a.type) === null || _b === void 0 ? void 0 : _b.implements)) { const err = `The namespace (${sheetNs}) does not contain an "implements" type reference.`; throw new Error(err); } const implementsNs = Uri.ns((_d = (_c = res.ns) === null || _c === void 0 ? void 0 : _c.type) === null || _d === void 0 ? void 0 : _d.implements); const typeDefs = await TypeClient.load({ ns: implementsNs.toString(), fetch, cache, }); const types = typeDefs.defs; const errors = typeDefs.errors; return new TypedSheet({ uri: sheetNs, implements: implementsNs, types, fetch, cache, event$, errors, pool, }); } static async create(args) { const { fetch, event$, cache } = args; const implementsNs = Uri.ns(args.implements); const sheetNs = args.ns ? Uri.ns(args.ns) : Uri.create.ns(Uri.cuid()); const pool = args.pool || SheetPool.create(); if (args.ns && pool.exists(args.ns)) { return pool.sheet(args.ns); } const typeDefs = await TypeClient.load({ ns: implementsNs.toString(), fetch, cache, }); const types = typeDefs.defs; const errors = typeDefs.errors; return new TypedSheet({ uri: sheetNs, implements: implementsNs, types, fetch, cache, event$, errors, pool, }); } dispose() { this._data = {}; this._dispose$.next(); this._dispose$.complete(); this.state.dispose(); } get isDisposed() { return this._dispose$.isStopped; } get ok() { return this.errors.length === 0; } get errors() { return this._errorList.list; } get types() { if (!this._types) { const types = []; this._typeDefs.forEach(def => { const { typename, columns } = def; const item = types.find(item => item.typename === typename); if (item) { item.columns = [...item.columns, ...columns]; } else { types.push({ typename, columns }); } }); this._types = types; } return this._types; } toString() { return this.uri.toString(); } async info() { const res = await this._ctx.fetch.getNs({ ns: this.uri.toString() }); const exists = Boolean(res.ns); const ns = (res.ns || {}); return { exists, ns }; } data(input) { this.throwIfDisposed('data'); const args = typeof input === 'string' ? { typename: input } : input; const { typename, range } = args; const ctx = this._ctx; if (this._data[typename]) { const res = this._data[typename]; if (args.range && res.range !== args.range) { res.expandRange(args.range); } return res; } const defs = this._typeDefs; const def = defs.find(def => def.typename === typename); if (!def) { const names = defs.map(def => `'${def.typename}'`).join(', '); const err = `Definitions for typename '${typename}' not found. Available typenames: ${names}.`; throw new Error(err); } const types = def.columns; const res = TypedSheetData.create({ sheet: this, typename, types, ctx, range, }); this._data[typename] = res; return res; } throwIfDisposed(action) { if (this.isDisposed) { throw new Error(`Cannot ${action} because [TypedSheet] is disposed.`); } } } TypedSheet.client = fromClient;