schema.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. /**
  2. * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import * as Data from './data-model'
  7. import Column, { ColumnHelpers } from '../../../mol-base/collections/column'
  8. import Table from '../../../mol-base/collections/table'
  9. export function toTypedFrame<Schema extends FrameSchema, Frame extends TypedFrame<Schema> = TypedFrame<Schema>>(schema: Schema, frame: Data.Frame): Frame {
  10. return createTypedFrame(schema, frame) as Frame;
  11. }
  12. export function toTable<Schema extends Table.Schema, R extends Table<Schema> = Table<Schema>>(schema: Schema, category: Data.Category): R {
  13. return new _TypedCategory(category, schema, true) as any;
  14. }
  15. export const Types = Column.Type
  16. export type FrameSchema = { [category: string]: Table.Schema }
  17. export type TypedFrame<Schema extends FrameSchema> = {
  18. readonly _header?: string,
  19. readonly _frame: Data.Frame
  20. } & { [C in keyof Schema]: Table<Schema[C]> }
  21. type ColumnCtor = (field: Data.Field, category: Data.Category, key: string) => Column<any>
  22. function getColumnCtor(t: Column.Type): ColumnCtor {
  23. switch (t.kind) {
  24. case 'str': return (f, c, k) => createColumn(Column.Type.str, f, f.str, f.toStringArray);
  25. case 'int': return (f, c, k) => createColumn(Column.Type.int, f, f.int, f.toIntArray);
  26. case 'float': return (f, c, k) => createColumn(Column.Type.float, f, f.float, f.toFloatArray);
  27. case 'vector': return (f, c, k) => {
  28. const dim = t.dim;
  29. const value = (row: number) => Data.getVector(c, k, dim, row);
  30. return createColumn(t, f, value, params => ColumnHelpers.createAndFillArray(f.rowCount, value, params));
  31. }
  32. case 'matrix': return (f, c, k) => {
  33. const rows = t.rows, cols = t.cols;
  34. const value = (row: number) => Data.getMatrix(c, k, rows, cols, row);
  35. return createColumn(t, f, value, params => ColumnHelpers.createAndFillArray(f.rowCount, value, params));
  36. }
  37. }
  38. }
  39. function createColumn<T>(type: Column.Type, field: Data.Field, value: (row: number) => T, toArray: Column<T>['toArray']): Column<T> {
  40. return {
  41. '@type': type,
  42. '@array': field['@array'],
  43. isDefined: field.isDefined,
  44. rowCount: field.rowCount,
  45. value,
  46. valueKind: field.valueKind,
  47. areValuesEqual: field.areValuesEqual,
  48. toArray
  49. };
  50. }
  51. class _TypedFrame implements TypedFrame<any> { // tslint:disable-line:class-name
  52. header = this._frame.header;
  53. constructor(public _frame: Data.Frame, schema: FrameSchema) {
  54. for (const k of Object.keys(schema)) {
  55. Object.defineProperty(this, k, { value: createTypedCategory(k, schema[k], _frame), enumerable: true, writable: false, configurable: false });
  56. }
  57. }
  58. }
  59. class _TypedCategory implements Table<any> { // tslint:disable-line:class-name
  60. _rowCount = this._category.rowCount;
  61. _columns: ReadonlyArray<string>;
  62. constructor(public _category: Data.Category, schema: Table.Schema, public _isDefined: boolean) {
  63. const fieldKeys = Object.keys(schema);
  64. this._columns = fieldKeys;
  65. const cache = Object.create(null);
  66. for (const k of fieldKeys) {
  67. const cType = schema[k];
  68. const ctor = getColumnCtor(cType);
  69. Object.defineProperty(this, k, {
  70. get: function() {
  71. if (cache[k]) return cache[k];
  72. const field = _category.getField(k);
  73. cache[k] = !!field ? ctor(field, _category, k) : Column.Undefined(_category.rowCount, cType);
  74. return cache[k];
  75. },
  76. enumerable: true,
  77. configurable: false
  78. });
  79. }
  80. }
  81. }
  82. function createTypedFrame(schema: FrameSchema, frame: Data.Frame): any {
  83. return new _TypedFrame(frame, schema);
  84. }
  85. function createTypedCategory(key: string, schema: Table.Schema, frame: Data.Frame) {
  86. const cat = frame.categories[key[0] === '_' ? key : '_' + key];
  87. return new _TypedCategory(cat || Data.Category.Empty, schema, !!cat);
  88. }