schema.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. /**
  2. * Copyright (c) 2017 mol* 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 { Database, Table, Column, ColumnHelpers } from 'mol-data/db'
  8. export function toDatabase<Schema extends Database.Schema, Frame extends Database<Schema> = Database<Schema>>(schema: Schema, frame: Data.Frame): Frame {
  9. return createDatabase(schema, frame) as Frame;
  10. }
  11. export function toTable<Schema extends Table.Schema, R extends Table<Schema> = Table<Schema>>(schema: Schema, category: Data.Category): R {
  12. return new CategoryTable(category, schema, true) as any;
  13. }
  14. type ColumnCtor = (field: Data.Field, category: Data.Category, key: string) => Column<any>
  15. function getColumnCtor(t: Column.Schema): ColumnCtor {
  16. switch (t.kind) {
  17. case 'str': return (f, c, k) => createColumn(Column.Type.str, f, f.str, f.toStringArray);
  18. case 'int': return (f, c, k) => createColumn(Column.Type.int, f, f.int, f.toIntArray);
  19. case 'float': return (f, c, k) => createColumn(Column.Type.float, f, f.float, f.toFloatArray);
  20. case 'tensor': return (f, c, k) => {
  21. const space = t.space;
  22. const value = (row: number) => Data.getTensor(c, k, space, row);
  23. return createColumn(t, f, value, params => ColumnHelpers.createAndFillArray(f.rowCount, value, params));
  24. }
  25. }
  26. }
  27. function createColumn<T>(type: Column.Type, field: Data.Field, value: (row: number) => T, toArray: Column<T>['toArray']): Column<T> {
  28. return {
  29. '@type': type,
  30. '@array': field['@array'],
  31. isDefined: field.isDefined,
  32. rowCount: field.rowCount,
  33. value,
  34. valueKind: field.valueKind,
  35. areValuesEqual: field.areValuesEqual,
  36. toArray
  37. };
  38. }
  39. class CategoryTable implements Table<any> { // tslint:disable-line:class-name
  40. _rowCount: number;
  41. _columns: ReadonlyArray<string>;
  42. _schema: any;
  43. [k: string]: any;
  44. constructor(category: Data.Category, schema: Table.Schema, public _isDefined: boolean) {
  45. const fieldKeys = Object.keys(schema);
  46. this._rowCount = category.rowCount;
  47. this._columns = fieldKeys;
  48. this._schema = schema;
  49. const cache = Object.create(null);
  50. for (const k of fieldKeys) {
  51. const cType = schema[k];
  52. const ctor = getColumnCtor(cType);
  53. Object.defineProperty(this, k, {
  54. get: function() {
  55. if (cache[k]) return cache[k];
  56. const field = category.getField(k);
  57. cache[k] = !!field ? ctor(field, category, k) : Column.Undefined(category.rowCount, cType);
  58. return cache[k];
  59. },
  60. enumerable: true,
  61. configurable: false
  62. });
  63. }
  64. }
  65. }
  66. function createDatabase(schema: Database.Schema, frame: Data.Frame): Database<any> {
  67. const tables = Object.create(null);
  68. for (const k of Object.keys(schema)) {
  69. tables[k] = createTable(k, (schema as any)[k], frame);
  70. }
  71. return Database.ofTables(frame.header, schema, tables);
  72. }
  73. function createTable(key: string, schema: Table.Schema, frame: Data.Frame) {
  74. const cat = frame.categories[key];
  75. return new CategoryTable(cat || Data.Category.empty(key), schema, !!cat);
  76. }