Skip to content

Commit

Permalink
search and count by post
Browse files Browse the repository at this point in the history
  • Loading branch information
PJGitLan committed Dec 7, 2023
1 parent 4b5e9f1 commit ed5f5ec
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 26 deletions.
10 changes: 5 additions & 5 deletions javascript/lib/api/src/client/handles/messages-http.ts
Expand Up @@ -112,7 +112,7 @@ export class DefaultHttpMessagesHandle implements HttpMessagesHandle {
claim(thingId: string, claimMessage: any, options?: MessagesOptions): Promise<GenericResponse> {
const messageOptions = options === undefined ? DefaultMessagesOptions.getInstance() : options;
messageOptions.addHeader(Header.CONTENT_TYPE, ContentType.JSON);
return this.requestFactory.fetchRequest({
return this.requestFactory.fetchGenericJsonRequest({
verb: HttpVerb.POST,
id: thingId,
path: 'inbox/claim',
Expand All @@ -135,7 +135,7 @@ export class DefaultHttpMessagesHandle implements HttpMessagesHandle {
contentType: string = ContentType.JSON, options?: MessagesOptions): Promise<GenericResponse> {
const messageOptions = options === undefined ? DefaultMessagesOptions.getInstance() : options;
messageOptions.addHeader(Header.CONTENT_TYPE, contentType);
return this.requestFactory.fetchRequest({
return this.requestFactory.fetchGenericJsonRequest({
verb: HttpVerb.POST,
id: thingId,
path: `inbox/messages/${messageSubject}`,
Expand All @@ -158,7 +158,7 @@ export class DefaultHttpMessagesHandle implements HttpMessagesHandle {
contentType: string = ContentType.JSON, options?: MessagesOptions): Promise<GenericResponse> {
const messageOptions = options === undefined ? DefaultMessagesOptions.getInstance() : options;
messageOptions.addHeader(Header.CONTENT_TYPE, contentType);
return this.requestFactory.fetchRequest({
return this.requestFactory.fetchGenericJsonRequest({
verb: HttpVerb.POST,
id: thingId,
path: `outbox/messages/${messageSubject}`,
Expand All @@ -183,7 +183,7 @@ export class DefaultHttpMessagesHandle implements HttpMessagesHandle {
Promise<GenericResponse> {
const messageOptions = options === undefined ? DefaultMessagesOptions.getInstance() : options;
messageOptions.addHeader(Header.CONTENT_TYPE, contentType);
return this.requestFactory.fetchRequest({
return this.requestFactory.fetchGenericJsonRequest({
verb: HttpVerb.POST,
id: thingId,
path: `features/${featureId}/inbox/messages/${messageSubject}`,
Expand All @@ -208,7 +208,7 @@ export class DefaultHttpMessagesHandle implements HttpMessagesHandle {
Promise<GenericResponse> {
const messageOptions = options === undefined ? DefaultMessagesOptions.getInstance() : options;
messageOptions.addHeader(Header.CONTENT_TYPE, contentType);
return this.requestFactory.fetchRequest({
return this.requestFactory.fetchGenericJsonRequest({
verb: HttpVerb.POST,
id: thingId,
path: `features/${featureId}/outbox/messages/${messageSubject}`,
Expand Down
44 changes: 44 additions & 0 deletions javascript/lib/api/src/client/handles/search.ts
Expand Up @@ -25,13 +25,29 @@ export interface SearchHandle {
*/
search(options?: SearchOptions): Promise<SearchThingsResponse>;

/**
* Searches for Things that match the restrictions set in options using a http post request.
*
* @param options - Options to use for the search.
* @returns The search result
*/
postSearch(options?: SearchOptions): Promise<SearchThingsResponse>;

/**
* Counts the Things that match the restrictions set in options.
*
* @param options - Options to use for the search.
* @returns The count
*/
count(options?: CountOptions): Promise<number>;

/**
* Counts the Things that match the restrictions set in options using a http post request.
*
* @param options - Options to use for the search.
* @returns The count
*/
postCount(options?: CountOptions): Promise<number>;
}

/**
Expand Down Expand Up @@ -66,6 +82,20 @@ export class DefaultSearchHandle implements SearchHandle {
});
}

/**
* Searches for Things that match the restrictions set in options using a http post request.
*
* @param options - Options to use for the search.
* @returns The search result
*/
postSearch(options?: SearchOptions): Promise<SearchThingsResponse> {
return this.requestFactory.fetchFormRequest({
verb: HttpVerb.POST,
parser: SearchThingsResponse.fromObject,
payload: options?.getOptions()
});
}

/**
* Counts the Things that match the restrictions set in options.
*
Expand All @@ -81,4 +111,18 @@ export class DefaultSearchHandle implements SearchHandle {
});
}

/**
* Counts the Things that match the restrictions set in options using a http post request.
*
* @param options - Options to use for the search.
* @returns The count
*/
postCount(options?: CountOptions): Promise<number> {
return this.requestFactory.fetchFormRequest({
verb: HttpVerb.POST,
parser: Number,
path: 'count',
payload: options?.getOptions()
});
}
}
Expand Up @@ -31,7 +31,7 @@ export class HttpRequestSender extends RequestSender {

public fetchRequest(options: FetchRequest): Promise<GenericResponse> {
return this.requester.doRequest(options.verb, this.buildUrl(options.id, options.path, options.requestOptions),
this.buildHeader(options.requestOptions), JSON.stringify(options.payload))
this.buildHeader(options.requestOptions), options.payload)
.then(response => {
if (response.status >= 200 && response.status < 300) {
return response;
Expand All @@ -52,12 +52,7 @@ export class HttpRequestSender extends RequestSender {
let urlSuffix = id === undefined ? '' : `/${id}`;
urlSuffix = path === undefined ? urlSuffix : `${urlSuffix}/${path}`;
if (options !== undefined && options.getOptions().size > 0) {
const values = options.getOptions();
let result = '';
values.forEach((v, k) => {
result += `&${k}=${v}`;
});
urlSuffix = `${urlSuffix}?${result.substr(1)}`;
urlSuffix = `${urlSuffix}?${this.mapToQueryParams(options.getOptions())}`;
}
const baseUrlWithSuffix = this.baseUrl.withPath(`${this.baseUrl.path}${urlSuffix}`);
const authenticatedBaseUrl = authenticateWithUrl(baseUrlWithSuffix, this.authenticationProviders);
Expand Down
72 changes: 59 additions & 13 deletions javascript/lib/api/src/client/request-factory/request-sender.ts
Expand Up @@ -18,7 +18,6 @@ import { RequestOptions } from '../../options/request.options';
* Handle to send requests.
*/
export abstract class RequestSender {

/**
* Fetches the specified request and returns an object of type T.
*
Expand All @@ -27,8 +26,31 @@ export abstract class RequestSender {
* @returns A Promise for the specified object
*/
public fetchJsonRequest<T>(options: ParseRequest<T>): Promise<T> {
return this.fetchRequest(options)
.then(response => options.parser(response.body));
return this.fetchGenericJsonRequest(options).then(response => options.parser(response.body));
}

/**
* Fetches the specified request and returns an object of type T.
*
* @typeParam T - The type of object to return
* @param options - The options to use for the request.
* @returns A Promise for the specified object
*/
public fetchFormRequest<T>(options: FetchFormRequest<T>): Promise<T> {
return this.fetchRequest({
...options,
payload: options.payload
? this.mapToQueryParams(options.payload)
: undefined
}).then(response => options.parser(response.body));
}

protected mapToQueryParams(map: Map<string, string>): string {
let result = '';
map.forEach((value, key) => {
result += `&${key}=${value}`;
});
return result.substring(1);
}

/**
Expand All @@ -39,16 +61,32 @@ export abstract class RequestSender {
* @returns A Promise for the specified object
*/
public fetchPutRequest<T>(options: ParseRequest<T>): Promise<PutResponse<T>> {
return this.fetchRequest(options)
.then(response => {
if (response.status === 201) {
return new PutResponse(options.parser(response.body), response.status, response.headers);
}
if (response.status === 204) {
return new PutResponse<T>(null, response.status, response.headers);
}
return Promise.reject(`Received unknown status code: ${response.status}`);
});
return this.fetchGenericJsonRequest(options).then(response => {
if (response.status === 201) {
return new PutResponse(
options.parser(response.body),
response.status,
response.headers
);
}
if (response.status === 204) {
return new PutResponse<T>(null, response.status, response.headers);
}
return Promise.reject(`Received unknown status code: ${response.status}`);
});
}

/**
* Fetches the specified request and checks if the request was successful.
*
* @param options - The options to use for the request.
* @returns A Promise for the response
*/
public fetchGenericJsonRequest(options: FetchRequest): Promise<GenericResponse> {
return this.fetchRequest({
...options,
payload: JSON.stringify(options.payload)
});
}

/**
Expand Down Expand Up @@ -90,6 +128,14 @@ export interface FetchRequest {
payload?: any;
}

/**
* The options needed for a Request.
*/
export interface FetchFormRequest<T> extends ParseRequest<T> {
/** The payload to send with he request. */
payload?: Map<string, string>;
}

/**
* The options needed for a Request that parses the server response.
*/
Expand Down
Expand Up @@ -119,6 +119,16 @@ export class WebSocketRequestSender extends RequestSender {
});
}

/**
* Fetches the specified request and checks if the request was successful.
*
* @param options - The options to use for the request.
* @returns A Promise for the response
*/
public fetchGenericJsonRequest(options: FetchRequest): Promise<GenericResponse> {
return this.fetchRequest(options);
}

/**
* Sends a Message and returns the response.
*
Expand Down
62 changes: 61 additions & 1 deletion javascript/lib/api/tests/client/http/search.http.spec.ts
Expand Up @@ -14,14 +14,51 @@
import { HttpVerb } from '../../../src/client/constants/http-verb';
import { SearchHandle } from '../../../src/client/handles/search';
import { SearchThingsResponse } from '../../../src/model/response';
import { DefaultSearchOptions } from '../../../src/options/request.options';
import { HttpHelper as H } from './http.helper';

describe('Http Search Handle', () => {
const baseRequest = 'search/things';
const handle: SearchHandle = H.thingsClient.getSearchHandle();
const errorHandle: SearchHandle = H.errorThingsClient.getSearchHandle();

it('gets the Thing', () => {
const searchOptions = DefaultSearchOptions.getInstance()
.withLimit(0, 25)
.withFilter(
'and(like(definition,"*test*"),and(or(ilike(/attributes/test,"*test*"),eq(/definition,"test"))))'
)
.withFields("thingId", "definition", "attributes", "features");

const expectedPayload =
"option=limit(0%2C25)&filter=and(like(definition%2C%22*test*%22)%2Cand(or(ilike(%2Fattributes%2Ftest%2C%22*test*%22)%2Ceq(%2Fdefinition%2C%22test%22))))&fields=thingId%2Cdefinition%2Cattributes%2Cfeatures";


it('gets the Thing by post with search options', () => {
const response = new SearchThingsResponse([H.thing], -1);
return H.test({
toTest: () => handle.postSearch(searchOptions),
testBody: response.toObject(),
expected: response,
payload:expectedPayload,
request: baseRequest,
method: HttpVerb.POST,
status: 200,
});
});

it("gets the Thing by post", () => {
const response = new SearchThingsResponse([H.thing], -1);
return H.test({
toTest: () => handle.postSearch(),
testBody: response.toObject(),
expected: response,
request: baseRequest,
method: HttpVerb.POST,
status: 200,
});
});

it("gets the Thing", () => {
const response = new SearchThingsResponse([H.thing], -1);
return H.test({
toTest: () => handle.search(),
Expand All @@ -44,6 +81,29 @@ describe('Http Search Handle', () => {
});
});

it("counts Things by post with search options", () => {
return H.test({
toTest: () => handle.postCount(searchOptions),
testBody: 4,
expected: 4,
request: `${baseRequest}/count`,
method: HttpVerb.POST,
payload: expectedPayload,
status: 200,
});
});

it("counts Things by post", () => {
return H.test({
toTest: () => handle.postCount(),
testBody: 4,
expected: 4,
request: `${baseRequest}/count`,
method: HttpVerb.POST,
status: 200,
});
});

it('returns a search error message', () => {
return H.testError(() => errorHandle.search());
});
Expand Down

0 comments on commit ed5f5ec

Please sign in to comment.