mirror of
https://github.com/lingble/twenty.git
synced 2025-10-29 11:52:28 +00:00
Fix CSV export missing last page (#7167)
This commit is contained in:
@@ -142,10 +142,6 @@ export const useTableData = ({
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const MAXIMUM_REQUESTS = isDefined(totalCount)
|
||||
? Math.min(maximumRequests, totalCount / pageSize)
|
||||
: maximumRequests;
|
||||
|
||||
const fetchNextPage = async () => {
|
||||
setInflight(true);
|
||||
setPreviousRecordCount(records.length);
|
||||
@@ -167,8 +163,8 @@ export const useTableData = ({
|
||||
}
|
||||
|
||||
if (
|
||||
pageCount >= MAXIMUM_REQUESTS ||
|
||||
(isDefined(totalCount) && records.length === totalCount)
|
||||
pageCount >= maximumRequests ||
|
||||
(isDefined(totalCount) && records.length >= totalCount)
|
||||
) {
|
||||
setPageCount(0);
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
import { FindOperator, Not } from 'typeorm';
|
||||
|
||||
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||
|
||||
import { GraphqlQueryFilterFieldParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-filter/graphql-query-filter-field.parser';
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
|
||||
describe('GraphqlQueryFilterFieldParser', () => {
|
||||
let parser: GraphqlQueryFilterFieldParser;
|
||||
let mockFieldMetadataMap: Record<string, FieldMetadataInterface>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockFieldMetadataMap = {
|
||||
simpleField: {
|
||||
id: '1',
|
||||
name: 'simpleField',
|
||||
type: FieldMetadataType.TEXT,
|
||||
label: 'Simple Field',
|
||||
objectMetadataId: 'obj1',
|
||||
},
|
||||
};
|
||||
parser = new GraphqlQueryFilterFieldParser(mockFieldMetadataMap);
|
||||
});
|
||||
it('should parse simple field correctly', () => {
|
||||
const result = parser.parse('simpleField', 'value', false);
|
||||
|
||||
expect(result).toEqual({ simpleField: 'value' });
|
||||
});
|
||||
|
||||
it('should negate simple field correctly', () => {
|
||||
const result = parser.parse('simpleField', 'value', true);
|
||||
|
||||
expect(result).toEqual({ simpleField: Not('value') });
|
||||
});
|
||||
|
||||
it('should parse object value using operator parser', () => {
|
||||
const result = parser.parse('simpleField', { like: '%value%' }, false);
|
||||
|
||||
expect(result).toEqual({
|
||||
simpleField: new FindOperator('like', '%%value%%'),
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,131 +0,0 @@
|
||||
import {
|
||||
FindOperator,
|
||||
ILike,
|
||||
In,
|
||||
IsNull,
|
||||
LessThan,
|
||||
LessThanOrEqual,
|
||||
Like,
|
||||
MoreThan,
|
||||
MoreThanOrEqual,
|
||||
Not,
|
||||
} from 'typeorm';
|
||||
|
||||
import { GraphqlQueryRunnerException } from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
import { GraphqlQueryFilterOperatorParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-filter/graphql-query-filter-operator.parser';
|
||||
|
||||
describe('GraphqlQueryFilterOperatorParser', () => {
|
||||
let parser: GraphqlQueryFilterOperatorParser;
|
||||
|
||||
beforeEach(() => {
|
||||
parser = new GraphqlQueryFilterOperatorParser();
|
||||
});
|
||||
|
||||
describe('parseOperator', () => {
|
||||
it('should parse eq operator correctly', () => {
|
||||
const result = parser.parseOperator({ eq: 'value' }, false);
|
||||
|
||||
expect(result).toBe('value');
|
||||
});
|
||||
|
||||
it('should parse neq operator correctly', () => {
|
||||
const result = parser.parseOperator({ neq: 'value' }, false);
|
||||
|
||||
expect(result).toBeInstanceOf(FindOperator);
|
||||
expect(result).toEqual(Not('value'));
|
||||
});
|
||||
|
||||
it('should parse gt operator correctly', () => {
|
||||
const result = parser.parseOperator({ gt: 5 }, false);
|
||||
|
||||
expect(result).toBeInstanceOf(FindOperator);
|
||||
expect(result).toEqual(MoreThan(5));
|
||||
});
|
||||
|
||||
it('should parse gte operator correctly', () => {
|
||||
const result = parser.parseOperator({ gte: 5 }, false);
|
||||
|
||||
expect(result).toBeInstanceOf(FindOperator);
|
||||
expect(result).toEqual(MoreThanOrEqual(5));
|
||||
});
|
||||
|
||||
it('should parse lt operator correctly', () => {
|
||||
const result = parser.parseOperator({ lt: 5 }, false);
|
||||
|
||||
expect(result).toBeInstanceOf(FindOperator);
|
||||
expect(result).toEqual(LessThan(5));
|
||||
});
|
||||
|
||||
it('should parse lte operator correctly', () => {
|
||||
const result = parser.parseOperator({ lte: 5 }, false);
|
||||
|
||||
expect(result).toBeInstanceOf(FindOperator);
|
||||
expect(result).toEqual(LessThanOrEqual(5));
|
||||
});
|
||||
|
||||
it('should parse in operator correctly', () => {
|
||||
const result = parser.parseOperator({ in: [1, 2, 3] }, false);
|
||||
|
||||
expect(result).toBeInstanceOf(FindOperator);
|
||||
expect(result).toEqual(In([1, 2, 3]));
|
||||
});
|
||||
|
||||
it('should parse is operator with NULL correctly', () => {
|
||||
const result = parser.parseOperator({ is: 'NULL' }, false);
|
||||
|
||||
expect(result).toBeInstanceOf(FindOperator);
|
||||
expect(result).toEqual(IsNull());
|
||||
});
|
||||
|
||||
it('should parse is operator with non-NULL value correctly', () => {
|
||||
const result = parser.parseOperator({ is: 'NOT_NULL' }, false);
|
||||
|
||||
expect(result).toBeInstanceOf(FindOperator);
|
||||
expect(result).toEqual(Not(IsNull()));
|
||||
});
|
||||
|
||||
it('should parse like operator correctly', () => {
|
||||
const result = parser.parseOperator({ like: 'test' }, false);
|
||||
|
||||
expect(result).toBeInstanceOf(FindOperator);
|
||||
expect(result).toEqual(Like('%test%'));
|
||||
});
|
||||
|
||||
it('should parse ilike operator correctly', () => {
|
||||
const result = parser.parseOperator({ ilike: 'test' }, false);
|
||||
|
||||
expect(result).toBeInstanceOf(FindOperator);
|
||||
expect(result).toEqual(ILike('%test%'));
|
||||
});
|
||||
|
||||
it('should parse startsWith operator correctly', () => {
|
||||
const result = parser.parseOperator({ startsWith: 'test' }, false);
|
||||
|
||||
expect(result).toBeInstanceOf(FindOperator);
|
||||
expect(result).toEqual(ILike('test%'));
|
||||
});
|
||||
|
||||
it('should parse endsWith operator correctly', () => {
|
||||
const result = parser.parseOperator({ endsWith: 'test' }, false);
|
||||
|
||||
expect(result).toBeInstanceOf(FindOperator);
|
||||
expect(result).toEqual(ILike('%test'));
|
||||
});
|
||||
|
||||
it('should negate the operator when isNegated is true', () => {
|
||||
const result = parser.parseOperator({ eq: 'value' }, true);
|
||||
|
||||
expect(result).toBeInstanceOf(FindOperator);
|
||||
expect(result).toEqual(Not('value'));
|
||||
});
|
||||
|
||||
it('should throw an exception for unsupported operator', () => {
|
||||
expect(() =>
|
||||
parser.parseOperator({ unsupported: 'value' }, false),
|
||||
).toThrow(GraphqlQueryRunnerException);
|
||||
expect(() =>
|
||||
parser.parseOperator({ unsupported: 'value' }, false),
|
||||
).toThrow('Operator "unsupported" is not supported');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
import { isArray } from 'class-validator';
|
||||
import { ObjectLiteral, WhereExpressionBuilder } from 'typeorm';
|
||||
|
||||
import { FieldMetadataInterface } from 'src/engine/metadata-modules/field-metadata/interfaces/field-metadata.interface';
|
||||
@@ -48,6 +49,10 @@ export class GraphqlQueryFilterFieldParser {
|
||||
}
|
||||
const [[operator, value]] = Object.entries(filterValue);
|
||||
|
||||
if (operator === 'in' && (!isArray(value) || value.length === 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { sql, params } = this.computeWhereConditionParts(
|
||||
fieldMetadata,
|
||||
operator,
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
import { OrderByDirection } from 'src/engine/api/graphql/workspace-query-builder/interfaces/record.interface';
|
||||
|
||||
import { GraphqlQueryOrderFieldParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query-order/graphql-query-order.parser';
|
||||
import { FieldMetadataType } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
|
||||
import { FieldMetadataMap } from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util';
|
||||
|
||||
describe('GraphqlQueryOrderFieldParser', () => {
|
||||
let parser: GraphqlQueryOrderFieldParser;
|
||||
const fieldMetadataMap: FieldMetadataMap = {};
|
||||
|
||||
beforeEach(() => {
|
||||
fieldMetadataMap['name'] = {
|
||||
id: 'name-id',
|
||||
name: 'name',
|
||||
type: FieldMetadataType.TEXT,
|
||||
label: 'Name',
|
||||
objectMetadataId: 'object-id',
|
||||
};
|
||||
fieldMetadataMap['age'] = {
|
||||
id: 'age-id',
|
||||
name: 'age',
|
||||
type: FieldMetadataType.NUMBER,
|
||||
label: 'Age',
|
||||
objectMetadataId: 'object-id',
|
||||
};
|
||||
fieldMetadataMap['address'] = {
|
||||
id: 'address-id',
|
||||
name: 'address',
|
||||
type: FieldMetadataType.ADDRESS,
|
||||
label: 'Address',
|
||||
objectMetadataId: 'object-id',
|
||||
};
|
||||
|
||||
parser = new GraphqlQueryOrderFieldParser(fieldMetadataMap);
|
||||
});
|
||||
describe('parse', () => {
|
||||
it('should parse simple order by fields', () => {
|
||||
const orderBy = [
|
||||
{ name: OrderByDirection.AscNullsFirst },
|
||||
{ age: OrderByDirection.DescNullsLast },
|
||||
];
|
||||
const result = parser.parse(orderBy);
|
||||
|
||||
expect(result).toEqual({
|
||||
name: { direction: 'ASC', nulls: 'FIRST' },
|
||||
age: { direction: 'DESC', nulls: 'LAST' },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user