table.ts 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  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 function pickColumns<S extends Schema, T extends S>(schema: S, table: Table<T>): Table<S> {
  16. const ret = Object.create(null);
  17. const keys = Object.keys(schema);
  18. ret._rowCount = table._rowCount;
  19. ret._columns = keys;
  20. for (const k of keys) ret[k] = table[k];
  21. return ret;
  22. }
  23. export function ofColumns<S extends Schema, R extends Table<S> = Table<S>>(columns: Columns<S>): R {
  24. const _columns = Object.keys(columns);
  25. const _rowCount = columns[_columns[0]].rowCount;
  26. return { _rowCount, _columns, ...(columns as any) };
  27. }
  28. export function ofRows<S extends Schema, R extends Table<S> = Table<S>>(schema: Schema, rows: ArrayLike<Row<S>>): R {
  29. const ret = Object.create(null);
  30. const rowCount = rows.length;
  31. const columns = Object.keys(schema);
  32. ret._rowCount = rowCount;
  33. ret._columns = columns;
  34. for (const k of columns) {
  35. (ret as any)[k] = Column.ofLambda({
  36. rowCount,
  37. type: schema[k],
  38. value: r => rows[r][k],
  39. valueKind: r => typeof rows[r][k] === 'undefined' ? Column.ValueKind.NotPresent : Column.ValueKind.Present
  40. })
  41. }
  42. return ret as R;
  43. }
  44. export function ofArrays<S extends Schema, R extends Table<S> = Table<S>>(schema: Schema, arrays: Arrays<S>): R {
  45. const ret = Object.create(null);
  46. const columns = Object.keys(schema);
  47. ret._rowCount = arrays[columns[0]].length;
  48. ret._columns = columns;
  49. for (const k of Object.keys(schema)) {
  50. (ret as any)[k] = Column.ofArray({ array: arrays[k], type: schema[k] })
  51. }
  52. return ret as R;
  53. }
  54. /** Sort and return a new table */
  55. export function sort<T extends Table<S>, S extends Schema>(table: T, cmp: (i: number, j: number) => number) {
  56. const indices = new Int32Array(table._rowCount);
  57. for (let i = 0, _i = indices.length; i < _i; i++) indices[i] = i;
  58. sortArray(indices, (_, i, j) => cmp(i, j));
  59. let isIdentity = true;
  60. for (let i = 0, _i = indices.length; i < _i; i++) {
  61. if (indices[i] !== i) {
  62. isIdentity = false;
  63. break;
  64. }
  65. }
  66. if (isIdentity) return table;
  67. const ret = Object.create(null);
  68. ret._rowCount = table._rowCount;
  69. ret._columns = table._columns;
  70. for (const c of table._columns) {
  71. ret[c] = Column.permutation((table as any)[c], indices, false);
  72. }
  73. return ret;
  74. }
  75. }
  76. export default Table