Skip to content

Commit 1c487b1

Browse files
authored
Merge pull request #15 from AlphaQuantJS/dev
fix: refactor aggregation methods and tests, replace deprecated DataF…
2 parents 9c21e5f + e06541b commit 1c487b1

13 files changed

Lines changed: 993 additions & 1073 deletions

File tree

src/methods/dataframe/aggregation/count.js

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,42 +7,42 @@
77
*/
88
export const count =
99
({ validateColumn }) =>
10-
(df, column) => {
10+
(df, column) => {
1111
// Validate that the column exists
12-
validateColumn(df, column);
12+
validateColumn(df, column);
1313

14-
// Get Series for the column and count valid values
15-
const series = df.col(column);
16-
const values = series.toArray();
14+
// Get Series for the column and count valid values
15+
const series = df.col(column);
16+
const values = series.toArray();
1717

18-
let validCount = 0;
19-
for (let i = 0; i < values.length; i++) {
20-
const value = values[i];
21-
if (value !== null && value !== undefined && !Number.isNaN(value)) {
22-
validCount++;
23-
}
18+
let validCount = 0;
19+
for (let i = 0; i < values.length; i++) {
20+
const value = values[i];
21+
if (value !== null && value !== undefined && !Number.isNaN(value)) {
22+
validCount++;
2423
}
24+
}
2525

26-
return validCount;
27-
};
26+
return validCount;
27+
};
2828

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

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

44-
// Регистрируем метод count в прототипе DataFrame
45-
DataFrame.prototype.count = function(column) {
44+
// Register the count method in the DataFrame prototype
45+
DataFrame.prototype.count = function (column) {
4646
return countFn(this, column);
4747
};
4848
};

src/methods/dataframe/aggregation/register.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@ import { register as registerLast } from './last.js';
1313
import { register as registerMode } from './mode.js';
1414
import { register as registerVariance } from './variance.js';
1515
import { register as registerStd } from './std.js';
16-
// Файл sort.js не найден, поэтому импорт закомментирован
17-
// import { register as registerSort } from './sort.js';
1816

1917
/**
2018
* Registers all aggregation methods on DataFrame prototype
@@ -32,9 +30,6 @@ export const registerDataFrameAggregation = (DataFrame) => {
3230
registerMode(DataFrame);
3331
registerVariance(DataFrame);
3432
registerStd(DataFrame);
35-
// registerSort(DataFrame); // Закомментировано, так как файл sort.js отсутствует
36-
37-
// Add additional aggregation methods here as they are implemented
3833
};
3934

4035
export default registerDataFrameAggregation;

test/methods/dataframe/aggregation/count.test.js

Lines changed: 36 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ import { DataFrame } from '../../../../src/core/dataframe/DataFrame.js';
1212
import { Series } from '../../../../src/core/dataframe/Series.js';
1313
import { count } from '../../../../src/methods/dataframe/aggregation/count.js';
1414

15-
import {
16-
testWithBothStorageTypes,
17-
createDataFrameWithStorage,
18-
} from '../../../utils/storageTestUtils.js';
1915
/**
2016
* Tests for the DataFrame count function
2117
*/
@@ -120,50 +116,47 @@ describe('DataFrame count function', () => {
120116
const countFn = count({ validateColumn });
121117

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

127123
// Tests with real DataFrames
128124
describe('DataFrame count with real DataFrames', () => {
129-
// Run tests with both storage types
130-
testWithBothStorageTypes((storageType) => {
131-
describe(`with ${storageType} storage`, () => {
132-
// Create a DataFrame with the specified storage type
133-
const df = createDataFrameWithStorage(DataFrame, testData, storageType);
134-
135-
test('should count all non-null, non-undefined, non-NaN values in a column', () => {
136-
// Create a validator that does nothing
137-
const validateColumn = () => {};
138-
const countFn = count({ validateColumn });
139-
140-
// Call the count function directly
141-
// All 5 values in the value column are valid
142-
expect(countFn(df, 'value')).toBe(5);
143-
// All 5 values in the category column are valid
144-
expect(countFn(df, 'category')).toBe(5);
145-
// Only 2 valid values ('20' and 30) in the mixed column, others are null, undefined and NaN
146-
expect(countFn(df, 'mixed')).toBe(2);
147-
});
148-
149-
test('should handle mixed data types and ignore null, undefined, and NaN', () => {
150-
// Create a validator that does nothing
151-
const validateColumn = () => {};
152-
const countFn = count({ validateColumn });
153-
154-
// In the mixed column there is a string '20', a number 30, null, undefined and NaN
155-
// The count function should only count valid values ('20' and 30)
156-
expect(countFn(df, 'mixed')).toBe(2);
157-
});
158-
159-
test('throws on corrupted frame', () => {
160-
// Create a minimally valid frame but without required structure
161-
const broken = {};
162-
const validateColumn = () => {};
163-
const countFn = count({ validateColumn });
164-
165-
expect(() => countFn(broken, 'a')).toThrow();
166-
});
125+
describe('with standard storage', () => {
126+
// Create a DataFrame using fromRows for proper column names
127+
const df = DataFrame.fromRows(testData);
128+
129+
test('should count all non-null, non-undefined, non-NaN values in a column', () => {
130+
// Create a mock validator
131+
const validateColumn = vi.fn();
132+
const countFn = count({ validateColumn });
133+
134+
// Call the count function directly
135+
// All 5 values in the value column are valid
136+
expect(countFn(df, 'value')).toBe(5);
137+
// All 5 values in the category column are valid
138+
expect(countFn(df, 'category')).toBe(5);
139+
// Only 2 valid values ('20' and 30) in the mixed column, others are null, undefined and NaN
140+
expect(countFn(df, 'mixed')).toBe(2);
141+
});
142+
143+
test('should handle mixed data types and ignore null, undefined, and NaN', () => {
144+
// Create a mock validator
145+
const validateColumn = vi.fn();
146+
const countFn = count({ validateColumn });
147+
148+
// In the mixed column there is a string '20', a number 30, null, undefined and NaN
149+
// The count function should only count valid values ('20' and 30)
150+
expect(countFn(df, 'mixed')).toBe(2);
151+
});
152+
153+
test('throws on corrupted frame', () => {
154+
// Create a minimally valid frame but without required structure
155+
const broken = {};
156+
const validateColumn = vi.fn();
157+
const countFn = count({ validateColumn });
158+
159+
expect(() => countFn(broken, 'a')).toThrow();
167160
});
168161
});
169162
});

test/methods/dataframe/aggregation/first.test.js

Lines changed: 94 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -12,112 +12,105 @@ import {
1212
register,
1313
} from '../../../../src/methods/dataframe/aggregation/first.js';
1414
import { DataFrame } from '../../../../src/core/dataframe/DataFrame.js';
15-
import { describe, it, expect, vi, beforeEach } from 'vitest';
16-
17-
import {
18-
testWithBothStorageTypes,
19-
createDataFrameWithStorage,
20-
} from '../../../utils/storageTestUtils.js';
15+
import { describe, it, expect, vi } from 'vitest';
2116

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

25-
// Test data for use in all tests
26-
const testData = [
27-
{ value: 10, category: 'A', mixed: '20' },
28-
{ value: 20, category: 'B', mixed: 30 },
29-
{ value: 30, category: 'A', mixed: null },
30-
{ value: 40, category: 'C', mixed: undefined },
31-
{ value: 50, category: 'B', mixed: NaN },
32-
];
33-
3420
describe('first method', () => {
35-
// Run tests with both storage types
36-
testWithBothStorageTypes((storageType) => {
37-
describe(`with ${storageType} storage`, () => {
38-
// Create a DataFrame with the specified storage type
39-
const df = createDataFrameWithStorage(DataFrame, testData, storageType);
40-
41-
// Test the first function directly
42-
it('should return the first value in a column', () => {
43-
// Create a first function with a mock validator
44-
const validateColumn = vi.fn();
45-
const firstFn = first({ validateColumn });
46-
47-
// Call the first function
48-
const result = firstFn(df, 'value');
49-
50-
// Check the result
51-
expect(result).toBe(10);
52-
expect(validateColumn).toHaveBeenCalledWith(df, 'value');
53-
});
54-
55-
it('should handle special values (null, undefined, NaN)', () => {
56-
// Create a first function with a mock validator
57-
const validateColumn = vi.fn();
58-
const firstFn = first({ validateColumn });
59-
60-
// Check that the first values are returned correctly
61-
expect(firstFn(df, 'mixed')).toBe('20');
62-
expect(validateColumn).toHaveBeenCalledWith(df, 'mixed');
63-
});
64-
65-
it('should return undefined for empty DataFrame', () => {
66-
// Create an empty DataFrame
67-
const emptyDf = createDataFrameWithStorage(DataFrame, [], storageType);
68-
69-
// Create a first function with a mock validator
70-
const validateColumn = vi.fn();
71-
const firstFn = first({ validateColumn });
72-
73-
// Call the first function
74-
const result = firstFn(emptyDf, 'value');
75-
76-
// Check the result
77-
expect(result).toBeUndefined();
78-
// For an empty DataFrame, the validator is not called, as we immediately return undefined
79-
});
80-
81-
it('should throw error for non-existent column', () => {
82-
// Create a validator that throws an error
83-
const validateColumn = (df, column) => {
84-
if (!df.columns.includes(column)) {
85-
throw new Error(`Column '${column}' not found`);
86-
}
87-
};
88-
89-
// Create a first function with our validator
90-
const firstFn = first({ validateColumn });
91-
92-
// Check that the function throws an error for non-existent columns
93-
expect(() => firstFn(df, 'nonexistent')).toThrow(
94-
'Column \'nonexistent\' not found',
95-
);
96-
});
97-
98-
// Test the DataFrame.first method
99-
it('should be available as a DataFrame method', () => {
100-
// Check that the first method is available in DataFrame
101-
expect(typeof df.first).toBe('function');
102-
103-
// Call the first method and check the result
104-
expect(df.first('value')).toBe(10);
105-
expect(df.first('category')).toBe('A');
106-
});
107-
it('should handle empty DataFrame gracefully', () => {
108-
// Create an empty DataFrame
109-
const emptyDf = createDataFrameWithStorage(DataFrame, [], storageType);
110-
111-
// Check that the first method returns undefined for an empty DataFrame
112-
expect(emptyDf.first('value')).toBeUndefined();
113-
});
114-
115-
it('should throw error for non-existent column', () => {
116-
// Check that the first method throws an error for non-existent columns
117-
expect(() => df.first('nonexistent')).toThrow(
118-
'Column \'nonexistent\' not found',
119-
);
120-
});
21+
describe('with standard storage', () => {
22+
// Test data for use in all tests
23+
const testData = [
24+
{ value: 10, category: 'A', mixed: '20' },
25+
{ value: 20, category: 'B', mixed: 30 },
26+
{ value: 30, category: 'A', mixed: null },
27+
{ value: 40, category: 'C', mixed: undefined },
28+
{ value: 50, category: 'B', mixed: NaN },
29+
];
30+
31+
// Create DataFrame using fromRows for proper column names
32+
const df = DataFrame.fromRows(testData);
33+
34+
// Test the first function directly
35+
it('should return the first value in a column', () => {
36+
// Create a first function with a mock validator
37+
const validateColumn = vi.fn();
38+
const firstFn = first({ validateColumn });
39+
40+
// Call the first function
41+
const result = firstFn(df, 'value');
42+
43+
// Check the result
44+
expect(result).toBe(10);
45+
expect(validateColumn).toHaveBeenCalledWith(df, 'value');
46+
});
47+
48+
it('should handle special values (null, undefined, NaN)', () => {
49+
// Create a first function with a mock validator
50+
const validateColumn = vi.fn();
51+
const firstFn = first({ validateColumn });
52+
53+
// Check that the first values are returned correctly
54+
expect(firstFn(df, 'mixed')).toBe('20');
55+
expect(validateColumn).toHaveBeenCalledWith(df, 'mixed');
56+
});
57+
58+
it('should return undefined for empty DataFrame', () => {
59+
// Create an empty DataFrame using fromRows
60+
const emptyDf = DataFrame.fromRows([]);
61+
62+
// Create a first function with a mock validator
63+
const validateColumn = vi.fn();
64+
const firstFn = first({ validateColumn });
65+
66+
// Call the first function
67+
const result = firstFn(emptyDf, 'value');
68+
69+
// Check the result
70+
expect(result).toBeUndefined();
71+
// For an empty DataFrame, the validator is not called, as we immediately return undefined
72+
});
73+
74+
it('should throw error for non-existent column', () => {
75+
// Create a validator that throws an error
76+
const validateColumn = (df, column) => {
77+
if (!df.columns.includes(column)) {
78+
throw new Error(`Column '${column}' not found`);
79+
}
80+
};
81+
82+
// Create a first function with our validator
83+
const firstFn = first({ validateColumn });
84+
85+
// Check that the function throws an error for non-existent columns
86+
expect(() => firstFn(df, 'nonexistent')).toThrow(
87+
"Column 'nonexistent' not found",
88+
);
89+
});
90+
91+
// Test the DataFrame.first method
92+
it('should be available as a DataFrame method', () => {
93+
// Check that the first method is available in DataFrame
94+
expect(typeof df.first).toBe('function');
95+
96+
// Call the first method and check the result
97+
expect(df.first('value')).toBe(10);
98+
expect(df.first('category')).toBe('A');
99+
});
100+
101+
it('should handle empty DataFrame gracefully', () => {
102+
// Create an empty DataFrame using fromRows
103+
const emptyDf = DataFrame.fromRows([]);
104+
105+
// Check that the first method returns undefined for an empty DataFrame
106+
expect(emptyDf.first('value')).toBeUndefined();
107+
});
108+
109+
it('should throw error for non-existent column', () => {
110+
// Check that the first method throws an error for non-existent columns
111+
expect(() => df.first('nonexistent')).toThrow(
112+
"Column 'nonexistent' not found",
113+
);
121114
});
122115
});
123116
});

0 commit comments

Comments
 (0)