UNPKG

@platform/cell.typesystem

Version:

The 'strongly typed sheets' system of the CellOS.

176 lines (175 loc) 5.57 kB
import { coord, Uri } from './common'; import { TypedSheetRow } from './TypedSheetRow'; export class TypedSheetData { constructor(args) { this._rows = []; this._status = 'INIT'; this._total = -1; this._loading = []; this._isLoaded = false; this._sheet = args.sheet; this.typename = args.typename; this.types = args.types; this._ctx = args.ctx; this._range = TypedSheetData.formatRange(args.range); } static formatRange(input) { const text = (input || '').trim(); const DEFAULT = TypedSheetData.DEFAULT; if (!text) { return DEFAULT.RANGE; } const range = coord.range.fromKey(text); if (!range.isValid) { return DEFAULT.RANGE; } const left = { key: range.left.key, index: range.left.row, isInfinity: isInfinity(range.left.key), }; const right = { key: range.right.key, index: range.right.row, isInfinity: isInfinity(range.right.key), }; if (left.isInfinity && right.isInfinity) { return DEFAULT.RANGE; } if (left.isInfinity) { left.index = DEFAULT.PAGE - 1; } if (right.isInfinity) { right.index = DEFAULT.PAGE - 1; } const edges = [Math.max(0, left.index) + 1, Math.max(0, right.index) + 1].sort(diff); return `${edges[0]}:${edges[1]}`; } get uri() { return this._sheet.uri; } get rows() { return this._rows; } get range() { return this._range; } get status() { return this._status; } get isLoaded() { return this._isLoaded; } get total() { return this._total; } toString() { return this.uri.toString(); } exists(index) { return Boolean(this._rows[index]); } row(index) { if (index < 0) { throw new Error(`Row index must be >=0`); } if (!this.exists(index)) { this._rows[index] = this.createRow(index); } return this._rows[index]; } async load(args) { var _a; let argRange = typeof args === 'string' ? args : (_a = args) === null || _a === void 0 ? void 0 : _a.range; if (argRange) { argRange = this.expandRange(argRange); } const query = argRange || this.range; const alreadyLoading = this._loading.find(item => item.query === query); if (alreadyLoading) { return alreadyLoading.promise; } const ns = this.uri.toString(); const promise = new Promise(async (resolve, reject) => { this._status = 'LOADING'; const sheet = this._sheet; this.fire({ type: 'SHEET/loading', payload: { sheet, range: query }, }); const { total, error } = await this._ctx.fetch.getCells({ ns, query }); if (error) { reject(new Error(error.message)); } const range = coord.range.fromKey(query); const min = Math.max(0, range.left.row); const max = Math.min(total.rows - 1, range.right.row); const wait = Array.from({ length: max - min + 1 }).map((v, i) => { const index = i + min; return this.row(index).load(); }); await Promise.all(wait); this._total = total.rows; this._status = 'LOADED'; this._isLoaded = true; this._loading = this._loading.filter(item => item.query !== query); this.fire({ type: 'SHEET/loaded', payload: { sheet, range: this.range, total: this.total, }, }); return resolve(this); }); this._loading = [...this._loading, { query, promise }]; return promise; } filter(fn) { return this.rows.filter((row, i) => fn(row.props, i)); } find(fn) { return this.rows.find((row, i) => fn(row.props, i)); } map(fn) { return this.rows.map((row, i) => fn(row.props, i)); } forEach(fn) { this.rows.forEach((row, i) => fn(row.props, i)); } expandRange(range) { range = TypedSheetData.formatRange(range); this._range = this.isLoaded ? mergeRanges(range, this._range) : range; return this._range; } fire(e) { this._ctx.event$.next(e); } createRow(index) { const uri = Uri.create.row(this.uri.toString(), (index + 1).toString()); const columns = this.types; const ctx = this._ctx; const typename = this.typename; const sheet = this._sheet; return TypedSheetRow.create({ sheet, typename, uri, columns, ctx }); } } TypedSheetData.create = (args) => { return new TypedSheetData(args); }; TypedSheetData.DEFAULT = { RANGE: '1:500', PAGE: 500, }; const diff = (a, b) => a - b; const isInfinity = (input) => input === '*' || input === '**'; const mergeRanges = (input1, input2) => { const range1 = coord.range.fromKey(input1).square; const range2 = coord.range.fromKey(input2).square; const min = Math.min(0, range1.left.row, range2.left.row) + 1; const max = Math.max(range1.right.row, range2.right.row) + 1; return `${min}:${max}`; };