Skip to content

Commit

Permalink
feat(storage): Added search records functionality (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
royWeisselberg authored Dec 16, 2024
1 parent 66afa82 commit f20f501
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 1 deletion.
48 changes: 48 additions & 0 deletions build/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,54 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/IncrementStorageForKeyRequestBody"
/storage/search/{term}:
get:
operationId: searchRecord
responses:
"200":
description: OK
content:
application/json:
schema: {}
"404":
description: ""
content:
application/json:
schema:
properties:
reason:
type: string
required:
- reason
type: object
"500":
description: ""
content:
application/json:
schema:
properties:
reason:
type: string
type: object
tags:
- Storage
security: []
parameters:
- in: path
name: term
required: true
schema:
type: string
- in: header
name: x-monday-access-token
required: true
schema:
type: string
- in: query
name: cursor
required: false
schema:
type: string
/secure-storage/{key}:
get:
operationId: getSecureStorage
Expand Down
9 changes: 8 additions & 1 deletion src/domain/storage/base-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { isDefined } from 'types/type-guards';
import { fetchWrapper } from 'utils/fetch-wrapper';
import { Logger } from 'utils/logger';

import type { Options, RequestOptions, Token } from 'types/storage.type';
import type { Options, RequestOptions, SearchOptions, Token } from 'types/storage.type';

export abstract class BaseStorage {
protected logger: Logger;
Expand Down Expand Up @@ -81,4 +81,11 @@ export abstract class BaseStorage {
const fullPath = `${storageUrl}/${key}?shareGlobally=${shareGlobally}`;
return fullPath;
}

public searchUrl(key: string, options: SearchOptions) {
const storageUrl = this.getStorageUrlV2();
const cursor = options.cursor ? `&cursor=${options.cursor}` : '';
const fullPath = `${storageUrl}/items?term=${key}${cursor}`;
return fullPath;
}
}
24 changes: 24 additions & 0 deletions src/domain/storage/storage.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,28 @@ export class StorageController {
const result = await storageService.incrementCounter(period, { incrementBy, kind, renewalDate });
return result;
}

@Get('search/{term}')
@OperationId('searchRecord')
@SuccessResponse(StatusCodes.OK, ReasonPhrases.OK)
public async searchRecords(
@Path() term: string,
@Header('x-monday-access-token') accessToken: string,
@Res() notFoundResponse: TsoaResponse<StatusCodes.NOT_FOUND, { reason: string }>,
@Res() serverError: TsoaResponse<StatusCodes.INTERNAL_SERVER_ERROR, { reason?: string }>,
@Query() cursor?: string
) {
const storageService = new StorageService(accessToken);
const result = await storageService.search(term, { cursor });
const { success, records } = result;
if (!success && records === null) {
return notFoundResponse(StatusCodes.NOT_FOUND, { reason: 'Key not found' });
}

if (!success) {
return serverError(StatusCodes.INTERNAL_SERVER_ERROR, { reason: 'An error occurred while fetching the key' });
}

return result;
}
}
21 changes: 21 additions & 0 deletions src/domain/storage/storage.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import type {
IStorageInstance,
Options,
Period,
SearchOptions,
SearchResponse,
SearchServerResponse,
SetResponse
} from 'types/storage.type';

Expand Down Expand Up @@ -75,4 +78,22 @@ export class StorageService extends BaseStorage implements IStorageInstance {
}
}
}

async search<T extends JsonDataContract['value']>(
key: string,
options: SearchOptions = {}
): Promise<SearchResponse<T>> {
const url = this.searchUrl(key, options);
const params = { method: 'GET' };
const result = await this.storageFetchV2<SearchServerResponse<T>>(url, params);
if (!isDefined(result)) {
return { success: false, records: null };
}

const response: SearchResponse<T> = { success: true, records: result.records };
if (result.cursor) {
response.cursor = result.cursor;
}
return response;
}
}
34 changes: 34 additions & 0 deletions src/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,40 @@ export function RegisterRoutes(app: Router) {
}
});
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
app.get('/storage/search/:term',
...(fetchMiddlewares<RequestHandler>(StorageController)),
...(fetchMiddlewares<RequestHandler>(StorageController.prototype.searchRecords)),

async function StorageController_searchRecords(request: ExRequest, response: ExResponse, next: any) {
const args: Record<string, TsoaRoute.ParameterSchema> = {
term: {"in":"path","name":"term","required":true,"dataType":"string"},
accessToken: {"in":"header","name":"x-monday-access-token","required":true,"dataType":"string"},
notFoundResponse: {"in":"res","name":"404","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"reason":{"dataType":"string","required":true}}},
serverError: {"in":"res","name":"500","required":true,"dataType":"nestedObjectLiteral","nestedProperties":{"reason":{"dataType":"string"}}},
cursor: {"in":"query","name":"cursor","dataType":"string"},
};

// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa

let validatedArgs: any[] = [];
try {
validatedArgs = templateService.getValidatedArgs({ args, request, response });

const controller = new StorageController();

await templateService.apiHandler({
methodName: 'searchRecords',
controller,
response,
next,
validatedArgs,
successStatus: 200,
});
} catch (err) {
return next(err);
}
});
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
app.get('/secure-storage/:key',
...(fetchMiddlewares<RequestHandler>(SecureStorageController)),
...(fetchMiddlewares<RequestHandler>(SecureStorageController.prototype.getSecureValue)),
Expand Down
20 changes: 20 additions & 0 deletions src/shared/types/storage.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,23 @@ export type ErrorResponse =
}
| undefined
| null;

export type SearchOptions = {
cursor?: string;
};

export type SearchEntity<T extends JsonDataContract['value']> = {
key: string;
value: T;
backendOnly: boolean;
};

export type SearchServerResponse<T extends JsonDataContract['value']> = {
records: Array<SearchEntity<T>> | null;
cursor?: string;
};

export type SearchResponse<T extends JsonDataContract['value']> = {
success: boolean;
error?: string;
} & SearchServerResponse<T>;

0 comments on commit f20f501

Please sign in to comment.