|
| 1 | +// src/core/DataFrame.js |
| 2 | + |
| 3 | +import { createFrame } from './createFrame.js'; |
| 4 | +import { extendDataFrame } from '../methods/autoExtend.js'; |
| 5 | + |
| 6 | +/** |
| 7 | + * @typedef {Object} TinyFrame |
| 8 | + * @property {Record<string, Float64Array | Int32Array>} columns - Columns of the frame |
| 9 | + */ |
| 10 | + |
| 11 | +/** |
| 12 | + * DataFrame — chainable API wrapper for TinyFrame structure. |
| 13 | + * Provides convenient access to columns, row count, and conversion to array of objects. |
| 14 | + */ |
| 15 | +export class DataFrame { |
| 16 | + /** |
| 17 | + * Main constructor. |
| 18 | + * @param {TinyFrame} frame - The underlying TinyFrame data structure |
| 19 | + * @throws {Error} If frame is not a valid TinyFrame |
| 20 | + */ |
| 21 | + constructor(frame) { |
| 22 | + if (!frame || typeof frame !== 'object' || !frame.columns) { |
| 23 | + throw new Error('Invalid TinyFrame passed to DataFrame'); |
| 24 | + } |
| 25 | + this._frame = frame; |
| 26 | + } |
| 27 | + |
| 28 | + /** |
| 29 | + * Factory method for creating a DataFrame from rows, columns, or another frame. |
| 30 | + * @param {Object[]|Record<string, any[]>|TinyFrame} input |
| 31 | + * @param {Object} [options] |
| 32 | + * @returns {DataFrame} |
| 33 | + */ |
| 34 | + static create(input, options = {}) { |
| 35 | + const frame = createFrame(input, options); |
| 36 | + return new DataFrame(frame); |
| 37 | + } |
| 38 | + |
| 39 | + /** |
| 40 | + * Returns the list of column names. |
| 41 | + * @returns {string[]} |
| 42 | + */ |
| 43 | + get columns() { |
| 44 | + return Object.keys(this._frame.columns); |
| 45 | + } |
| 46 | + |
| 47 | + /** |
| 48 | + * Returns the number of rows in the DataFrame. |
| 49 | + * @returns {number} |
| 50 | + */ |
| 51 | + get rowCount() { |
| 52 | + const first = Object.values(this._frame.columns)[0]; |
| 53 | + return first?.length || 0; |
| 54 | + } |
| 55 | + |
| 56 | + /** |
| 57 | + * Converts the DataFrame to an array of plain JavaScript objects (row-wise). |
| 58 | + * @returns {Array<Object>} Array of row objects |
| 59 | + */ |
| 60 | + toArray() { |
| 61 | + const result = []; |
| 62 | + const keys = this.columns; |
| 63 | + const len = this.rowCount; |
| 64 | + |
| 65 | + for (let i = 0; i < len; i++) { |
| 66 | + const row = {}; |
| 67 | + for (const key of keys) { |
| 68 | + row[key] = this._frame.columns[key][i]; |
| 69 | + } |
| 70 | + result.push(row); |
| 71 | + } |
| 72 | + return result; |
| 73 | + } |
| 74 | + |
| 75 | + /** |
| 76 | + * Returns the underlying TinyFrame data structure. |
| 77 | + * @returns {TinyFrame} |
| 78 | + */ |
| 79 | + get frame() { |
| 80 | + return this._frame; |
| 81 | + } |
| 82 | + |
| 83 | + /** |
| 84 | + * Handles the result of a DataFrame operation, checking if it should be printed |
| 85 | + * based on metadata |
| 86 | + * |
| 87 | + * @param {DataFrame} result - The DataFrame result to handle |
| 88 | + * @returns {DataFrame} The same DataFrame result |
| 89 | + * @private |
| 90 | + */ |
| 91 | + _handleResult(result) { |
| 92 | + // Check if the result has metadata indicating it should be printed |
| 93 | + if ( |
| 94 | + result && |
| 95 | + result._frame && |
| 96 | + result._frame._meta && |
| 97 | + result._frame._meta.shouldPrint |
| 98 | + ) { |
| 99 | + result.print(); |
| 100 | + // Clean up the metadata to avoid repeated printing |
| 101 | + delete result._frame._meta.shouldPrint; |
| 102 | + } |
| 103 | + return result; |
| 104 | + } |
| 105 | +} |
| 106 | + |
| 107 | +// Extend DataFrame with all methods from aggregation, filtering, etc. |
| 108 | +extendDataFrame(DataFrame); |
0 commit comments