Skip to content

Commit 7896f5d

Browse files
authored
Merge pull request #73 from diegomvh/master
Count, Levels and allow Null values
2 parents 6b779a7 + 59bbe37 commit 7896f5d

File tree

2 files changed

+70
-22
lines changed

2 files changed

+70
-22
lines changed

src/index.ts

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ const COLLECTION_OPERATORS = ['any', 'all'];
44
const BOOLEAN_FUNCTIONS = ['startswith', 'endswith', 'contains'];
55
const SUPPORTED_EXPAND_PROPERTIES = [
66
'expand',
7+
'levels',
78
'select',
89
'top',
10+
'count',
911
'orderby',
1012
'filter',
1113
];
@@ -34,6 +36,8 @@ export type ExpandOptions<T> = {
3436
filter: Filter;
3537
orderBy: OrderBy<T>;
3638
top: number;
39+
levels: number | 'max';
40+
count: boolean | Filter;
3741
expand: Expand<T>;
3842
}
3943

@@ -91,10 +95,10 @@ export const ITEM_ROOT = "";
9195
export default function <T>({
9296
select: $select,
9397
search: $search,
94-
top: $top,
95-
skip: $skip,
9698
skiptoken: $skiptoken,
9799
format: $format,
100+
top,
101+
skip,
98102
filter,
99103
transform,
100104
orderBy,
@@ -107,12 +111,7 @@ export default function <T>({
107111
}: Partial<QueryOptions<T>> = {}) {
108112
let path = '';
109113

110-
const params: any = {
111-
$filter: (filter || count instanceof Object) && buildFilter(count instanceof Object ? count : filter),
112-
$apply: transform && buildTransforms(transform),
113-
$expand: expand && buildExpand(expand),
114-
$orderby: orderBy && buildOrderBy(orderBy),
115-
};
114+
const params: any = {};
116115

117116
if (key) {
118117
if (typeof key === 'object') {
@@ -125,6 +124,18 @@ export default function <T>({
125124
}
126125
}
127126

127+
if (filter || typeof count === 'object')
128+
params.$filter = buildFilter(typeof count === 'object' ? count : filter);
129+
130+
if (transform)
131+
params.$apply = buildTransforms(transform);
132+
133+
if (expand)
134+
params.$expand = buildExpand(expand);
135+
136+
if (orderBy)
137+
params.$orderby = buildOrderBy(orderBy);
138+
128139
if (count) {
129140
if (typeof count === 'boolean') {
130141
params.$count = true;
@@ -133,6 +144,14 @@ export default function <T>({
133144
}
134145
}
135146

147+
if (typeof top === 'number') {
148+
params.$top = top;
149+
}
150+
151+
if (typeof skip === 'number') {
152+
params.$skip = skip;
153+
}
154+
136155
if (action) {
137156
path += `/${action}`;
138157
}
@@ -159,7 +178,7 @@ export default function <T>({
159178
.reduce((acc, alias) => Object.assign(acc, {[alias.handleName()]: alias.handleValue()}), params);
160179
}
161180

162-
return buildUrl(path, { $select, $search, $top, $skip, $skiptoken, $format, ...params });
181+
return buildUrl(path, { $select, $search, $skiptoken, $format, ...params });
163182
}
164183

165184
function buildFilter(filters: Filter = {}, propPrefix = ''): string {
@@ -402,12 +421,22 @@ function buildExpand<T>(expands: Expand<T>): string {
402421
) {
403422
return expandKeys
404423
.map(key => {
405-
const value =
406-
key === 'filter'
407-
? buildFilter((expands as NestedExpandOptions<any>)[key])
408-
: key.toLowerCase() === 'orderby'
409-
? buildOrderBy((expands as NestedExpandOptions<any>)[key] as OrderBy<T>)
410-
: buildExpand((expands as NestedExpandOptions<any>)[key] as Expand<T>);
424+
let value;
425+
switch (key) {
426+
case 'filter':
427+
value = buildFilter((expands as NestedExpandOptions<any>)[key]);
428+
break;
429+
case 'orderBy':
430+
value = buildOrderBy((expands as NestedExpandOptions<any>)[key] as OrderBy<T>);
431+
break;
432+
case 'levels':
433+
case 'count':
434+
case 'top':
435+
value = `${(expands as NestedExpandOptions<any>)[key]}`;
436+
break;
437+
default:
438+
value = buildExpand((expands as NestedExpandOptions<any>)[key] as Expand<T>);
439+
}
411440
return `$${key.toLowerCase()}=${value}`;
412441
})
413442
.join(';');
@@ -508,13 +537,9 @@ function buildOrderBy<T>(orderBy: OrderBy<T>, prefix: string = ''): string {
508537

509538
function buildUrl(path: string, params: PlainObject): string {
510539
// This can be refactored using URL API. But IE does not support it.
511-
const queries: string[] = [];
512-
for (const key of Object.getOwnPropertyNames(params)) {
513-
const value = params[key];
514-
if (value === 0 || !!value) {
515-
queries.push(`${key}=${value}`);
516-
}
517-
}
540+
const queries: string[] = Object.getOwnPropertyNames(params)
541+
.filter(key => params[key] !== undefined && params[key] !== '')
542+
.map(key => `${key}=${params[key]}`);
518543
return queries.length ? `${path}?${queries.join('&')}` : path;
519544
}
520545

test/index.test.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1464,6 +1464,29 @@ describe('expand', () => {
14641464
expect(actual).toEqual(expected);
14651465
});
14661466

1467+
it('should allow expand with count', () => {
1468+
const expand = { Friends: { count: true } };
1469+
const expected = '?$expand=Friends($count=true)';
1470+
const actual = buildQuery({ expand });
1471+
expect(actual).toEqual(expected);
1472+
});
1473+
1474+
it('should allow expand with levels', () => {
1475+
type Bar = { Friends: { Photos: any}, One: { Two: any }};
1476+
const expand: Expand<Bar> = { Friends: { expand: { Photos: { levels: 10 }}} };
1477+
const expected = '?$expand=Friends($expand=Photos($levels=10))';
1478+
const actual = buildQuery({ expand });
1479+
expect(actual).toEqual(expected);
1480+
});
1481+
1482+
it('should allow expand with max levels', () => {
1483+
type Bar = { Friends: { Photos: any}, One: { Two: any }};
1484+
const expand: Expand<Bar> = { Friends: { expand: { Photos: { levels: 'max' }}} };
1485+
const expected = '?$expand=Friends($expand=Photos($levels=max))';
1486+
const actual = buildQuery({ expand });
1487+
expect(actual).toEqual(expected);
1488+
});
1489+
14671490
it('should allow expand with select and top', () => {
14681491
const expand = { Friends: { select: 'Name', top: 10 } };
14691492
const expected = '?$expand=Friends($select=Name;$top=10)';

0 commit comments

Comments
 (0)