table.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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 Column from './column'
  7. import { sortArray } from './sort'
  8. type Table<Schema extends Table.Schema> = { readonly _rowCount: number, readonly _columns: ReadonlyArray<string> } & Table.Columns<Schema>
  9. /** An immutable table */
  10. namespace Table {
  11. export type Schema = { [field: string]: Column.Type }
  12. export type Columns<S extends Schema> = { [C in keyof S]: Column<S[C]['T']> }
  13. export type Row<S extends Schema> = { [C in keyof S]: S[C]['T'] }
  14. export type Arrays<S extends Schema> = { [C in keyof S]: ArrayLike<S[C]['T']> }
  15. export type PartialTable<S extends Table.Schema> = { readonly _rowCount: number, readonly _columns: ReadonlyArray<string> } & { [C in keyof S]?: Column<S[C]['T']> }
  16. export function pickColumns<S extends Schema>(schema: S, table: PartialTable<S>, guard: Partial<Columns<S>> = {}): Table<S> {
  17. const ret = Object.create(null);
  18. const keys = Object.keys(schema);
  19. ret._rowCount = table._rowCount;
  20. ret._columns = keys;
  21. for (const k of keys) {
  22. if (!!table[k]) ret[k] = table[k];
  23. else if (!!guard[k]) ret[k] = guard[k];
  24. else throw Error(`Cannot find column '${k}'.`);
  25. }
  26. return ret;
  27. }
  28. export function ofColumns<S extends Schema, R extends Table<S> = Table<S>>(columns: Columns<S>): R {
  29. const _columns = Object.keys(columns);
  30. const _rowCount = columns[_columns[0]].rowCount;
  31. return { _rowCount, _columns, ...(columns as any) };
  32. }
  33. export function ofRows<S extends Schema, R extends Table<S> = Table<S>>(schema: Schema, rows: ArrayLike<Row<S>>): R {
  34. const ret = Object.create(null);
  35. const rowCount = rows.length;
  36. const columns = Object.keys(schema);
  37. ret._rowCount = rowCount;
  38. ret._columns = columns;
  39. for (const k of columns) {
  40. (ret as any)[k] = Column.ofLambda({
  41. rowCount,
  42. type: schema[k],
  43. value: r => rows[r][k],
  44. valueKind: r => typeof rows[r][k] === 'undefined' ? Column.ValueKind.NotPresent : Column.ValueKind.Present
  45. })
  46. }
  47. return ret as R;
  48. }
  49. export function ofArrays<S extends Schema, R extends Table<S> = Table<S>>(schema: Schema, arrays: Arrays<S>): R {
  50. const ret = Object.create(null);
  51. const columns = Object.keys(schema);
  52. ret._rowCount = arrays[columns[0]].length;
  53. ret._columns = columns;
  54. for (const k of columns) {
  55. (ret as any)[k] = Column.ofArray({ array: arrays[k], type: schema[k] })
  56. }
  57. return ret as R;
  58. }
  59. export function view<S extends Schema, R extends Schema>(table: Table<S>, schema: R, view: ArrayLike<number>) {
  60. const ret = Object.create(null);
  61. const columns = Object.keys(schema);
  62. ret._rowCount = view.length;
  63. ret._columns = columns;
  64. for (const k of columns) {
  65. (ret as any)[k] = Column.view(table[k], view);
  66. }
  67. return ret as Table<R>;
  68. }
  69. /** Sort and return a new table */
  70. export function sort<T extends Table<S>, S extends Schema>(table: T, cmp: (i: number, j: number) => number) {
  71. const indices = new Int32Array(table._rowCount);
  72. for (let i = 0, _i = indices.length; i < _i; i++) indices[i] = i;
  73. sortArray(indices, (_, i, j) => cmp(i, j));
  74. let isIdentity = true;
  75. for (let i = 0, _i = indices.length; i < _i; i++) {
  76. if (indices[i] !== i) {
  77. isIdentity = false;
  78. break;
  79. }
  80. }
  81. if (isIdentity) return table;
  82. const ret = Object.create(null);
  83. ret._rowCount = table._rowCount;
  84. ret._columns = table._columns;
  85. for (const c of table._columns) {
  86. ret[c] = Column.view((table as any)[c], indices, false);
  87. }
  88. return ret;
  89. }
  90. }
  91. export default Table