Skip to content

Commit 69227eb

Browse files
committed
feat: Add sortby field (resolve #23)
1 parent c2fdf41 commit 69227eb

File tree

5 files changed

+74
-3
lines changed

5 files changed

+74
-3
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ Option | Type | Description
271271
`setDateRangeFrom(fromDate)` | `function` | Callback to set `dateRangeFrom`. `fromDate` must be ISO representation of a date, ie. `2022-05-18`, or `undefined` to reset.
272272
`dateRangeTo` | `string` | The to-date of the search query. `undefined` if unset.
273273
`setDateRangeTo(toDate)` | `function` | Callback to set `dateRangeto`. `toDate` must be ISO representation of a date, ie. `2022-05-18`, or `undefined` to reset.
274+
`sortby` | `array` | Specifies the order of results. Array of `{ field: string, direction: 'asc' | 'desc' }`
275+
`setSortby(sort)` | `function` | Callback to set `sortby`. `sort` must be an array of `{ field: string, direction: 'asc' | 'desc' }`, or `undefined` to reset.
274276
`results` | `object` | The result of the last search query; a [GeoJSON `FeatureCollection` with additional members](https://github.com/radiantearth/stac-api-spec/blob/v1.0.0-rc.2/fragments/itemcollection/README.md). `undefined` if the search request has not been submitted, or if there was an error.
275277
`state` | `string` | The status of the request. `"IDLE"` before and after the request is sent or received. `"LOADING"` when the request is in progress.
276278
`error` | [`Error`](#error) | Error information if the last request was unsuccessful. `undefined` if the last request was successful.

src/hooks/useStacSearch.test.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,30 @@ describe('useStacSearch — API supports POST', () => {
528528
expect(result.current.results).toEqual({ data: '12345' });
529529
});
530530

531+
it('includes sortBy in search', async () => {
532+
fetch
533+
.mockResponseOnce(
534+
JSON.stringify({ links: [{ rel: 'search', method: 'POST' }] }),
535+
{ url: 'https://fake-stac-api.net' }
536+
)
537+
.mockResponseOnce(JSON.stringify({ data: '12345' }));
538+
539+
const { result, waitForNextUpdate } = renderHook(
540+
() => useStacSearch(),
541+
{ wrapper }
542+
);
543+
await waitForNextUpdate();
544+
545+
act(() => result.current.setSortby([{ field: 'id', direction: 'asc'}]));
546+
act(() => result.current.submit());
547+
548+
await waitForNextUpdate();
549+
550+
const postPayload = parseRequestPayload(fetch.mock.calls[1][1]);
551+
expect(postPayload).toEqual({ sortby: [{ field: 'id', direction: 'asc'}], limit: 25 });
552+
expect(result.current.results).toEqual({ data: '12345' });
553+
});
554+
531555
// it('should reset state with each new StacApi instance', async () => {
532556
// const bbox: Bbox = [-0.59, 51.24, 0.30, 51.74];
533557
// fetch.mockResponseOnce(JSON.stringify({ data: '12345' }));
@@ -665,4 +689,29 @@ describe('useStacSearch — API supports GET', () => {
665689
expect(fetch.mock.calls[1][0]).toEqual('https://fake-stac-api.net/search?datetime=..%2F2022-05-17&limit=25');
666690
expect(result.current.results).toEqual({ data: '12345' });
667691
});
692+
693+
it('includes sortby', async () => {
694+
fetch
695+
.mockResponseOnce(
696+
JSON.stringify({ links: [] }),
697+
{ url: 'https://fake-stac-api.net' }
698+
)
699+
.mockResponseOnce(JSON.stringify({ data: '12345' }));
700+
701+
const { result, waitForNextUpdate } = renderHook(
702+
() => useStacSearch(),
703+
{ wrapper }
704+
);
705+
await waitForNextUpdate();
706+
707+
act(() => result.current.setSortby([
708+
{ field: 'id', direction: 'asc' },
709+
{ field: 'properties.cloud', direction: 'desc' },
710+
]));
711+
act(() => result.current.submit());
712+
await waitForNextUpdate();
713+
714+
expect(fetch.mock.calls[1][0]).toEqual('https://fake-stac-api.net/search?limit=25&sortby=%2Bid%2C-properties.cloud');
715+
expect(result.current.results).toEqual({ data: '12345' });
716+
});
668717
});

src/hooks/useStacSearch.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import type {
88
SearchPayload,
99
SearchResponse,
1010
LinkBody,
11+
Sortby
1112
} from '../types/stac';
1213
import { useStacApiContext } from '../context';
1314

@@ -24,6 +25,8 @@ type StacSearchHook = {
2425
setDateRangeFrom: (date: string) => void
2526
dateRangeTo?: string
2627
setDateRangeTo: (date: string) => void
28+
sortby?: Sortby[]
29+
setSortby: (sort: Sortby[]) => void
2730
submit: () => void
2831
results?: SearchResponse
2932
state: LoadingState;
@@ -40,6 +43,7 @@ function useStacSearch(): StacSearchHook {
4043
const [ collections, setCollections ] = useState<CollectionIdList>();
4144
const [ dateRangeFrom, setDateRangeFrom ] = useState<string>('');
4245
const [ dateRangeTo, setDateRangeTo ] = useState<string>('');
46+
const [ sortby, setSortby ] = useState<Sortby[]>();
4347
const [ state, setState ] = useState<LoadingState>('IDLE');
4448
const [ error, setError ] = useState<ApiError>();
4549

@@ -53,6 +57,7 @@ function useStacSearch(): StacSearchHook {
5357
setIds(undefined);
5458
setDateRangeFrom('');
5559
setDateRangeTo('');
60+
setSortby(undefined);
5661
};
5762

5863
/**
@@ -78,9 +83,10 @@ function useStacSearch(): StacSearchHook {
7883
ids,
7984
bbox,
8085
collections,
81-
dateRange: { from: dateRangeFrom, to: dateRangeTo }
86+
dateRange: { from: dateRangeFrom, to: dateRangeTo },
87+
sortby
8288
}),
83-
[ ids, bbox, collections, dateRangeFrom, dateRangeTo ]
89+
[ ids, bbox, collections, dateRangeFrom, dateRangeTo, sortby ]
8490
);
8591

8692
/**
@@ -179,6 +185,8 @@ function useStacSearch(): StacSearchHook {
179185
results,
180186
state,
181187
error,
188+
sortby,
189+
setSortby,
182190
nextPage: nextPageConfig ? nextPageFn : undefined,
183191
previousPage: previousPageConfig ? previousPageFn : undefined
184192
};

src/stac-api/index.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class StacApi {
6363
}
6464
}
6565

66-
payloadToQuery(payload: SearchPayload): string {
66+
payloadToQuery({ sortby, ...payload }: SearchPayload): string {
6767
const queryObj = {};
6868
for (const [key, value] of Object.entries(payload)) {
6969
if (!value) continue;
@@ -74,6 +74,13 @@ class StacApi {
7474
queryObj[key] = value;
7575
}
7676
}
77+
78+
if(sortby) {
79+
queryObj['sortby'] = sortby
80+
.map(( { field, direction } ) => `${direction === 'asc' ? '+' : '-'}${field}`)
81+
.join(',');
82+
}
83+
7784
return new URLSearchParams(queryObj).toString();
7885
}
7986

src/types/stac.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,17 @@ export type DateRange = {
88
from?: string,
99
to?: string
1010
}
11+
type Sortby = {
12+
field: string;
13+
direction: 'asc' | 'desc';
14+
}
1115

1216
export type SearchPayload = {
1317
ids?: IdList,
1418
bbox?: Bbox,
1519
collections?: CollectionIdList,
1620
dateRange?: DateRange,
21+
sortby?: Sortby[]
1722
}
1823

1924
export type LinkBody = SearchPayload & {

0 commit comments

Comments
 (0)