Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions src/methods/dataframe/aggregation/count.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,42 @@
*/
export const count =
({ validateColumn }) =>
(df, column) => {
(df, column) => {
// Validate that the column exists
validateColumn(df, column);
validateColumn(df, column);

// Get Series for the column and count valid values
const series = df.col(column);
const values = series.toArray();
// Get Series for the column and count valid values
const series = df.col(column);
const values = series.toArray();

let validCount = 0;
for (let i = 0; i < values.length; i++) {
const value = values[i];
if (value !== null && value !== undefined && !Number.isNaN(value)) {
validCount++;
}
let validCount = 0;
for (let i = 0; i < values.length; i++) {
const value = values[i];
if (value !== null && value !== undefined && !Number.isNaN(value)) {
validCount++;
}
}

return validCount;
};
return validCount;
};

/**
* Registers the count method on DataFrame prototype
* @param {Class} DataFrame - DataFrame class to extend
*/
export const register = (DataFrame) => {
// Создаем валидатор для проверки существования колонки
// Create a validator to check column existence
const validateColumn = (df, column) => {
if (!df.columns.includes(column)) {
throw new Error(`Column '${column}' not found`);
}
};

// Создаем функцию count с валидатором
// Create a function count with validator
const countFn = count({ validateColumn });

// Регистрируем метод count в прототипе DataFrame
DataFrame.prototype.count = function(column) {
// Register the count method in the DataFrame prototype
DataFrame.prototype.count = function (column) {
return countFn(this, column);
};
};
Expand Down
5 changes: 0 additions & 5 deletions src/methods/dataframe/aggregation/register.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ import { register as registerLast } from './last.js';
import { register as registerMode } from './mode.js';
import { register as registerVariance } from './variance.js';
import { register as registerStd } from './std.js';
// Файл sort.js не найден, поэтому импорт закомментирован
// import { register as registerSort } from './sort.js';

/**
* Registers all aggregation methods on DataFrame prototype
Expand All @@ -32,9 +30,6 @@ export const registerDataFrameAggregation = (DataFrame) => {
registerMode(DataFrame);
registerVariance(DataFrame);
registerStd(DataFrame);
// registerSort(DataFrame); // Закомментировано, так как файл sort.js отсутствует

// Add additional aggregation methods here as they are implemented
};

export default registerDataFrameAggregation;
79 changes: 36 additions & 43 deletions test/methods/dataframe/aggregation/count.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ import { DataFrame } from '../../../../src/core/dataframe/DataFrame.js';
import { Series } from '../../../../src/core/dataframe/Series.js';
import { count } from '../../../../src/methods/dataframe/aggregation/count.js';

import {
testWithBothStorageTypes,
createDataFrameWithStorage,
} from '../../../utils/storageTestUtils.js';
/**
* Tests for the DataFrame count function
*/
Expand Down Expand Up @@ -120,50 +116,47 @@ describe('DataFrame count function', () => {
const countFn = count({ validateColumn });

// Check that the function throws an error for non-existent columns
expect(() => countFn(df, 'z')).toThrow('Column \'z\' not found');
expect(() => countFn(df, 'z')).toThrow("Column 'z' not found");
});
});

// Tests with real DataFrames
describe('DataFrame count with real DataFrames', () => {
// Run tests with both storage types
testWithBothStorageTypes((storageType) => {
describe(`with ${storageType} storage`, () => {
// Create a DataFrame with the specified storage type
const df = createDataFrameWithStorage(DataFrame, testData, storageType);

test('should count all non-null, non-undefined, non-NaN values in a column', () => {
// Create a validator that does nothing
const validateColumn = () => {};
const countFn = count({ validateColumn });

// Call the count function directly
// All 5 values in the value column are valid
expect(countFn(df, 'value')).toBe(5);
// All 5 values in the category column are valid
expect(countFn(df, 'category')).toBe(5);
// Only 2 valid values ('20' and 30) in the mixed column, others are null, undefined and NaN
expect(countFn(df, 'mixed')).toBe(2);
});

test('should handle mixed data types and ignore null, undefined, and NaN', () => {
// Create a validator that does nothing
const validateColumn = () => {};
const countFn = count({ validateColumn });

// In the mixed column there is a string '20', a number 30, null, undefined and NaN
// The count function should only count valid values ('20' and 30)
expect(countFn(df, 'mixed')).toBe(2);
});

test('throws on corrupted frame', () => {
// Create a minimally valid frame but without required structure
const broken = {};
const validateColumn = () => {};
const countFn = count({ validateColumn });

expect(() => countFn(broken, 'a')).toThrow();
});
describe('with standard storage', () => {
// Create a DataFrame using fromRows for proper column names
const df = DataFrame.fromRows(testData);

test('should count all non-null, non-undefined, non-NaN values in a column', () => {
// Create a mock validator
const validateColumn = vi.fn();
const countFn = count({ validateColumn });

// Call the count function directly
// All 5 values in the value column are valid
expect(countFn(df, 'value')).toBe(5);
// All 5 values in the category column are valid
expect(countFn(df, 'category')).toBe(5);
// Only 2 valid values ('20' and 30) in the mixed column, others are null, undefined and NaN
expect(countFn(df, 'mixed')).toBe(2);
});

test('should handle mixed data types and ignore null, undefined, and NaN', () => {
// Create a mock validator
const validateColumn = vi.fn();
const countFn = count({ validateColumn });

// In the mixed column there is a string '20', a number 30, null, undefined and NaN
// The count function should only count valid values ('20' and 30)
expect(countFn(df, 'mixed')).toBe(2);
});

test('throws on corrupted frame', () => {
// Create a minimally valid frame but without required structure
const broken = {};
const validateColumn = vi.fn();
const countFn = count({ validateColumn });

expect(() => countFn(broken, 'a')).toThrow();
});
});
});
195 changes: 94 additions & 101 deletions test/methods/dataframe/aggregation/first.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,112 +12,105 @@ import {
register,
} from '../../../../src/methods/dataframe/aggregation/first.js';
import { DataFrame } from '../../../../src/core/dataframe/DataFrame.js';
import { describe, it, expect, vi, beforeEach } from 'vitest';

import {
testWithBothStorageTypes,
createDataFrameWithStorage,
} from '../../../utils/storageTestUtils.js';
import { describe, it, expect, vi } from 'vitest';

// Register the first method in DataFrame for tests
register(DataFrame);

// Test data for use in all tests
const testData = [
{ value: 10, category: 'A', mixed: '20' },
{ value: 20, category: 'B', mixed: 30 },
{ value: 30, category: 'A', mixed: null },
{ value: 40, category: 'C', mixed: undefined },
{ value: 50, category: 'B', mixed: NaN },
];

describe('first method', () => {
// Run tests with both storage types
testWithBothStorageTypes((storageType) => {
describe(`with ${storageType} storage`, () => {
// Create a DataFrame with the specified storage type
const df = createDataFrameWithStorage(DataFrame, testData, storageType);

// Test the first function directly
it('should return the first value in a column', () => {
// Create a first function with a mock validator
const validateColumn = vi.fn();
const firstFn = first({ validateColumn });

// Call the first function
const result = firstFn(df, 'value');

// Check the result
expect(result).toBe(10);
expect(validateColumn).toHaveBeenCalledWith(df, 'value');
});

it('should handle special values (null, undefined, NaN)', () => {
// Create a first function with a mock validator
const validateColumn = vi.fn();
const firstFn = first({ validateColumn });

// Check that the first values are returned correctly
expect(firstFn(df, 'mixed')).toBe('20');
expect(validateColumn).toHaveBeenCalledWith(df, 'mixed');
});

it('should return undefined for empty DataFrame', () => {
// Create an empty DataFrame
const emptyDf = createDataFrameWithStorage(DataFrame, [], storageType);

// Create a first function with a mock validator
const validateColumn = vi.fn();
const firstFn = first({ validateColumn });

// Call the first function
const result = firstFn(emptyDf, 'value');

// Check the result
expect(result).toBeUndefined();
// For an empty DataFrame, the validator is not called, as we immediately return undefined
});

it('should throw error for non-existent column', () => {
// Create a validator that throws an error
const validateColumn = (df, column) => {
if (!df.columns.includes(column)) {
throw new Error(`Column '${column}' not found`);
}
};

// Create a first function with our validator
const firstFn = first({ validateColumn });

// Check that the function throws an error for non-existent columns
expect(() => firstFn(df, 'nonexistent')).toThrow(
'Column \'nonexistent\' not found',
);
});

// Test the DataFrame.first method
it('should be available as a DataFrame method', () => {
// Check that the first method is available in DataFrame
expect(typeof df.first).toBe('function');

// Call the first method and check the result
expect(df.first('value')).toBe(10);
expect(df.first('category')).toBe('A');
});
it('should handle empty DataFrame gracefully', () => {
// Create an empty DataFrame
const emptyDf = createDataFrameWithStorage(DataFrame, [], storageType);

// Check that the first method returns undefined for an empty DataFrame
expect(emptyDf.first('value')).toBeUndefined();
});

it('should throw error for non-existent column', () => {
// Check that the first method throws an error for non-existent columns
expect(() => df.first('nonexistent')).toThrow(
'Column \'nonexistent\' not found',
);
});
describe('with standard storage', () => {
// Test data for use in all tests
const testData = [
{ value: 10, category: 'A', mixed: '20' },
{ value: 20, category: 'B', mixed: 30 },
{ value: 30, category: 'A', mixed: null },
{ value: 40, category: 'C', mixed: undefined },
{ value: 50, category: 'B', mixed: NaN },
];

// Create DataFrame using fromRows for proper column names
const df = DataFrame.fromRows(testData);

// Test the first function directly
it('should return the first value in a column', () => {
// Create a first function with a mock validator
const validateColumn = vi.fn();
const firstFn = first({ validateColumn });

// Call the first function
const result = firstFn(df, 'value');

// Check the result
expect(result).toBe(10);
expect(validateColumn).toHaveBeenCalledWith(df, 'value');
});

it('should handle special values (null, undefined, NaN)', () => {
// Create a first function with a mock validator
const validateColumn = vi.fn();
const firstFn = first({ validateColumn });

// Check that the first values are returned correctly
expect(firstFn(df, 'mixed')).toBe('20');
expect(validateColumn).toHaveBeenCalledWith(df, 'mixed');
});

it('should return undefined for empty DataFrame', () => {
// Create an empty DataFrame using fromRows
const emptyDf = DataFrame.fromRows([]);

// Create a first function with a mock validator
const validateColumn = vi.fn();
const firstFn = first({ validateColumn });

// Call the first function
const result = firstFn(emptyDf, 'value');

// Check the result
expect(result).toBeUndefined();
// For an empty DataFrame, the validator is not called, as we immediately return undefined
});

it('should throw error for non-existent column', () => {
// Create a validator that throws an error
const validateColumn = (df, column) => {
if (!df.columns.includes(column)) {
throw new Error(`Column '${column}' not found`);
}
};

// Create a first function with our validator
const firstFn = first({ validateColumn });

// Check that the function throws an error for non-existent columns
expect(() => firstFn(df, 'nonexistent')).toThrow(
"Column 'nonexistent' not found",
);
});

// Test the DataFrame.first method
it('should be available as a DataFrame method', () => {
// Check that the first method is available in DataFrame
expect(typeof df.first).toBe('function');

// Call the first method and check the result
expect(df.first('value')).toBe(10);
expect(df.first('category')).toBe('A');
});

it('should handle empty DataFrame gracefully', () => {
// Create an empty DataFrame using fromRows
const emptyDf = DataFrame.fromRows([]);

// Check that the first method returns undefined for an empty DataFrame
expect(emptyDf.first('value')).toBeUndefined();
});

it('should throw error for non-existent column', () => {
// Check that the first method throws an error for non-existent columns
expect(() => df.first('nonexistent')).toThrow(
"Column 'nonexistent' not found",
);
});
});
});
Loading
Loading