Skip to content
This repository was archived by the owner on Jun 1, 2025. It is now read-only.

Commit 812554e

Browse files
authored
Merge pull request #225 from ghiscoding/feat/gridodata-unit-tests
feat(odata): add presets to GridOdata Service (and unit tests), closes #206
2 parents 16b7f3e + 96bcea9 commit 812554e

18 files changed

+1521
-396
lines changed

src/app/examples/grid-graphql.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export class GridGraphqlComponent implements OnInit, OnDestroy {
135135
{ columnId: 'company', searchTerms: ['xyz'], operator: 'IN' }
136136
],
137137
sorters: [
138-
// direction can typed as 'asc' (uppercase or lowercase) and/or use the SortDirection type
138+
// direction can written as 'asc' (uppercase or lowercase) and/or use the SortDirection type
139139
{ columnId: 'name', direction: 'asc' },
140140
{ columnId: 'company', direction: SortDirection.DESC }
141141
],

src/app/examples/grid-odata.component.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import {
66
Filters,
77
GridOdataService,
88
GridOption,
9-
Statistic
9+
Statistic,
10+
SortDirection,
11+
OperatorType
1012
} from './../modules/angular-slickgrid';
1113

1214
const defaultPageSize = 20;
@@ -41,20 +43,22 @@ export class GridOdataComponent implements OnInit {
4143
processing = true;
4244
status = { text: 'processing...', class: 'alert alert-danger' };
4345

44-
constructor(private http: HttpClient) {}
46+
constructor(private http: HttpClient) { }
4547

4648
ngOnInit(): void {
4749
this.columnDefinitions = [
48-
{ id: 'name', name: 'Name', field: 'name', sortable: true, type: FieldType.string,
50+
{
51+
id: 'name', name: 'Name', field: 'name', sortable: true, type: FieldType.string,
4952
filterable: true,
5053
filter: {
5154
model: Filters.compoundInput
5255
}
5356
},
54-
{ id: 'gender', name: 'Gender', field: 'gender', filterable: true, sortable: true,
57+
{
58+
id: 'gender', name: 'Gender', field: 'gender', filterable: true, sortable: true,
5559
filter: {
5660
model: Filters.singleSelect,
57-
collection: [ { value: '', label: '' }, { value: 'male', label: 'male' }, { value: 'female', label: 'female' } ]
61+
collection: [{ value: '', label: '' }, { value: 'male', label: 'male' }, { value: 'female', label: 'female' }]
5862
}
5963
},
6064
{ id: 'company', name: 'Company', field: 'company' }
@@ -80,6 +84,18 @@ export class GridOdataComponent implements OnInit {
8084
pageSize: defaultPageSize,
8185
totalItems: 0
8286
},
87+
presets: {
88+
// you can also type operator as string, e.g.: operator: 'EQ'
89+
filters: [
90+
{ columnId: 'gender', searchTerms: ['male'], operator: OperatorType.equal },
91+
],
92+
sorters: [
93+
// direction can be written as 'asc' (uppercase or lowercase) and/or use the SortDirection type
94+
{ columnId: 'name', direction: 'asc' },
95+
{ columnId: 'gender', direction: SortDirection.DESC }
96+
],
97+
pagination: { pageNumber: 2, pageSize: 20 }
98+
},
8399
backendServiceApi: {
84100
service: new GridOdataService(),
85101
preProcess: () => this.displaySpinner(true),
@@ -200,7 +216,7 @@ export class GridOdataComponent implements OnInit {
200216
}
201217

202218
this.http.get(url).subscribe(data => {
203-
const dataArray = <any[]> data;
219+
const dataArray = <any[]>data;
204220

205221
// Read the result field from the JSON response.
206222
const firstRow = skip;
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
export enum CaseType {
2+
/** For example: camelCase */
23
camelCase,
4+
5+
/** For example: PascalCase */
36
pascalCase,
4-
snakeCase
7+
8+
/** For example: snake_case */
9+
snakeCase,
10+
11+
/** For example: kebab-case */
12+
kebabCase,
513
}

src/app/modules/angular-slickgrid/models/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ export * from './keyCode.enum';
8282
export * from './multiColumnSort.interface';
8383
export * from './multipleSelectOption.interface';
8484
export * from './odataOption.interface';
85+
export * from './odataSortingOption.interface';
8586
export * from './onEventArgs.interface';
8687
export * from './operatorString';
8788
export * from './operatorType.enum';

src/app/modules/angular-slickgrid/models/odataOption.interface.ts

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,30 @@ import { BackendServiceOption } from './backendServiceOption.interface';
22
import { CaseType } from './caseType';
33

44
export interface OdataOption extends BackendServiceOption {
5-
caseType?: CaseType;
6-
top?: number;
7-
skip?: number;
8-
filter?: string;
9-
filterBy?: any;
10-
filterBySeparator?: string;
11-
filterQueue?: any[];
12-
orderBy?: string;
13-
[key: string]: any;
5+
/** What is the casing type to use? Typically that would be 1 of the following 2: camelCase or PascalCase */
6+
caseType?: CaseType;
7+
8+
/** How many rows to pull? */
9+
top?: number;
10+
11+
/** How many rows to skip on the pagination? */
12+
skip?: number;
13+
14+
/** (alias to "filter") Filter string (or array of string) that must be a valid OData string */
15+
filter?: string | string[];
16+
17+
/** Filter string (or array of string) that must be a valid OData string */
18+
filterBy?: any;
19+
20+
/** What is separator between each filters? Typically "and", "or" */
21+
filterBySeparator?: 'and' | 'or';
22+
23+
/** Filter queue */
24+
filterQueue?: any[];
25+
26+
/** Sorting string (or array of string) that must be a valid OData string */
27+
orderBy?: string | string[];
28+
29+
/** When accessed as an object */
30+
[key: string]: any;
1431
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { SortDirection, SortDirectionString } from './index';
2+
3+
export interface OdataSortingOption {
4+
field: string;
5+
direction: SortDirection | SortDirectionString;
6+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export type OperatorString = '' | '<>' | '!=' | '=' | '==' | '>' | '>=' | '<' | '<=' | '*' | 'a*' | '*z' | 'EQ' | 'GE' | 'GT' | 'NE' | 'LE' | 'LT' | 'IN' | 'NIN' | 'NOT_IN' | 'IN_CONTAINS' | 'NIN_CONTAINS' | 'NOT_IN_CONTAINS' | 'endsWith' | 'startsWith';
1+
export type OperatorString = '' | '<>' | '!=' | '=' | '==' | '>' | '>=' | '<' | '<=' | '*' | 'a*' | '*z' | 'EQ' | 'GE' | 'GT' | 'NE' | 'LE' | 'LT' | 'IN' | 'NIN' | 'NOT_IN' | 'IN_CONTAINS' | 'NIN_CONTAINS' | 'NOT_IN_CONTAINS' | 'NOT_CONTAINS' | 'Not_Contains' | 'Contains' | 'endsWith' | 'startsWith';

src/app/modules/angular-slickgrid/services/__tests__/graphql.service.spec.ts

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const gridStub = {
4545
setSortColumns: jest.fn(),
4646
};
4747

48-
describe('CollectionService', () => {
48+
describe('GraphqlService', () => {
4949
let mockColumns: Column[];
5050
let service: GraphqlService;
5151
let paginationOptions: Pagination;
@@ -203,10 +203,11 @@ describe('CollectionService', () => {
203203
gridOptionMock.enablePagination = false;
204204

205205
service.init({ datasetName: 'users', columnDefinitions: columns }, paginationOptions, gridStub);
206+
service.updatePagination(3, 20);
206207
const query = service.buildQuery();
207-
gridOptionMock.enablePagination = true; // reset it for the next test
208208

209209
expect(removeSpaces(query)).toBe(removeSpaces(expectation));
210+
gridOptionMock.enablePagination = true; // reset it for the next test
210211
});
211212

212213
it('should have a different pagination offset when it is updated before calling the buildQuery query (presets does that)', () => {
@@ -480,7 +481,7 @@ describe('CollectionService', () => {
480481
expect(currentPagination).toEqual({ pageNumber: 3, pageSize: 20 });
481482
});
482483

483-
it('should return a query with the new pagination and use default pagination size when not provided as argument', () => {
484+
it('should return a query with the new pagination and use pagination size options that was passed to service options when it is not provided as argument to "processOnPaginationChanged"', () => {
484485
const expectation = `query{users(first:10, offset:20) { totalCount,nodes { id, field1, field2 }}}`;
485486
const querySpy = jest.spyOn(service, 'buildQuery');
486487

@@ -589,12 +590,12 @@ describe('CollectionService', () => {
589590
});
590591

591592
it('should return a query with multiple filters when the filters object has multiple search and they are passed as a filter trigger by a filter event and is of type ColumnFilters', () => {
592-
const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:EQ, value:"female"}, {field:company, operator:Contains, value:"abc"}]) { totalCount,nodes{ id,company,gender,name } }}`;
593+
const expectation = `query{users(first:10, offset:0, filterBy:[{field:gender, operator:EQ, value:"female"}, {field:company, operator:Not_Contains, value:"abc"}]) { totalCount,nodes{ id,company,gender,name } }}`;
593594
const mockColumnGender = { id: 'gender', field: 'gender' } as Column;
594595
const mockColumnCompany = { id: 'company', field: 'company' } as Column;
595596
const mockColumnFilters = {
596597
gender: { columnId: 'gender', columnDef: mockColumnGender, searchTerms: ['female'], operator: 'EQ' },
597-
company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: 'Contains' },
598+
company: { columnId: 'company', columnDef: mockColumnCompany, searchTerms: ['abc'], operator: OperatorType.notContains },
598599
} as ColumnFilters;
599600

600601
service.init(serviceOptions, paginationOptions, gridStub);
@@ -807,10 +808,10 @@ describe('CollectionService', () => {
807808
});
808809

809810
it('should return a query using a different field to query when the column has a "queryField" defined in its definition', () => {
810-
const expectation = `query{users(first:10, offset:0, filterBy:[{field:isMale, operator:EQ, value:"female"}]) { totalCount,nodes{ id,company,gender,name } }}`;
811+
const expectation = `query{users(first:10, offset:0, filterBy:[{field:isMale, operator:EQ, value:"true"}]) { totalCount,nodes{ id,company,gender,name } }}`;
811812
const mockColumn = { id: 'gender', field: 'gender', queryField: 'isMale' } as Column;
812813
const mockColumnFilters = {
813-
gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' },
814+
gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: [true], operator: 'EQ' },
814815
} as ColumnFilters;
815816

816817
service.init(serviceOptions, paginationOptions, gridStub);
@@ -847,6 +848,23 @@ describe('CollectionService', () => {
847848

848849
expect(removeSpaces(query)).toBe(removeSpaces(expectation));
849850
});
851+
852+
it('should return a query without any sorting after clearFilters was called', () => {
853+
const expectation = `query{ users(first:10,offset:0) { totalCount,nodes{id, company, gender,name} }}`;
854+
const mockColumn = { id: 'gender', field: 'gender' } as Column;
855+
const mockColumnFilters = {
856+
gender: { columnId: 'gender', columnDef: mockColumn, searchTerms: ['female'], operator: 'EQ' },
857+
} as ColumnFilters;
858+
859+
service.init(serviceOptions, paginationOptions, gridStub);
860+
service.updateFilters(mockColumnFilters, false);
861+
service.clearFilters();
862+
const currentFilters = service.getCurrentFilters();
863+
const query = service.buildQuery();
864+
865+
expect(removeSpaces(query)).toBe(removeSpaces(expectation));
866+
expect(currentFilters).toEqual([]);
867+
});
850868
});
851869

852870
describe('updateSorters method', () => {
@@ -925,5 +943,40 @@ describe('CollectionService', () => {
925943
expect(removeSpaces(query)).toBe(removeSpaces(expectation));
926944
expect(currentSorters).toEqual([{ columnId: 'gender', direction: 'DESC' }, { columnId: 'name', direction: 'ASC' }]);
927945
});
946+
947+
it('should return a query without the field sorter when its field property is missing', () => {
948+
const expectation = `query { users(first:10, offset:0, orderBy:[{field:gender, direction:DESC}]) {
949+
totalCount, nodes { id,company,gender,name }}}`;
950+
const mockColumnSort = [
951+
{ columnId: 'gender', sortCol: { id: 'gender', field: 'gender' }, sortAsc: false },
952+
{ columnId: 'firstName', sortCol: { id: 'firstName' }, sortAsc: true }
953+
] as ColumnSort[];
954+
955+
service.init(serviceOptions, paginationOptions, gridStub);
956+
service.updateSorters(mockColumnSort);
957+
const query = service.buildQuery();
958+
const currentSorters = service.getCurrentSorters();
959+
960+
expect(removeSpaces(query)).toBe(removeSpaces(expectation));
961+
expect(currentSorters).toEqual([{ columnId: 'gender', direction: 'DESC' }, { columnId: 'firstName', direction: 'ASC' }]);
962+
});
963+
964+
it('should return a query without any sorting after clearSorters was called', () => {
965+
const expectation = `query { users(first:10, offset:0) {
966+
totalCount, nodes { id,company,gender,name }}}`;
967+
const mockColumnSort = [
968+
{ columnId: 'gender', sortCol: { id: 'gender', field: 'gender' }, sortAsc: false },
969+
{ columnId: 'firstName', sortCol: { id: 'firstName', field: 'firstName' }, sortAsc: true }
970+
] as ColumnSort[];
971+
972+
service.init(serviceOptions, paginationOptions, gridStub);
973+
service.updateSorters(mockColumnSort);
974+
service.clearSorters();
975+
const query = service.buildQuery();
976+
const currentSorters = service.getCurrentSorters();
977+
978+
expect(removeSpaces(query)).toBe(removeSpaces(expectation));
979+
expect(currentSorters).toEqual([]);
980+
});
928981
});
929982
});

0 commit comments

Comments
 (0)