Skip to content

Commit

Permalink
feat: cache flush (#345)
Browse files Browse the repository at this point in the history
* feat: cache flush

* feat: cache flush
  • Loading branch information
nidhidham authored Mar 14, 2023
1 parent 34b6453 commit e1c2b91
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 8 deletions.
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"uuid": "8.3.2"
},
"dependencies": {
"@gomomento/generated-types": "0.49.1",
"@gomomento/generated-types": "0.50.0",
"@grpc/grpc-js": "1.7.3",
"google-protobuf": "^3.21.2",
"jwt-decode": "3.1.2"
Expand Down
13 changes: 13 additions & 0 deletions src/cache-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
CacheSortedSetPutElement,
CacheSortedSetPutElements,
MomentoLogger,
CacheFlush,
} from '.';
import {range} from './internal/utils/collections';
import {CacheClientProps} from './cache-client-props';
Expand Down Expand Up @@ -591,6 +592,18 @@ export class CacheClient {
return await this.controlClient.deleteCache(cacheName);
}

/**
* Flushes / clears all the items of the given cache
*
* @param {string} cacheName - The cache to be flushed.
* @returns {Promise<CacheFlush.Response>} -
* {@link CacheFlush.Success} on success.
* {@link CacheFlush.Error} on failure.
*/
public async flushCache(cacheName: string): Promise<CacheFlush.Response> {
return await this.controlClient.flushCache(cacheName);
}

/**
* Lists all caches.
*
Expand Down
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as CacheListPushFront from './messages/responses/cache-list-push-front'
import * as CacheListRemoveValue from './messages/responses/cache-list-remove-value';
import * as CacheSet from './messages/responses/cache-set';
import * as CacheDelete from './messages/responses/cache-delete';
import * as CacheFlush from './messages/responses/cache-flush';
import * as CreateCache from './messages/responses/create-cache';
import * as DeleteCache from './messages/responses/delete-cache';
import * as ListCaches from './messages/responses/list-caches';
Expand Down Expand Up @@ -109,6 +110,7 @@ export {
CacheSet,
CacheSetIfNotExists,
CacheDelete,
CacheFlush,
CreateCache,
DeleteCache,
ListCaches,
Expand Down
34 changes: 34 additions & 0 deletions src/internal/control-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
ListSigningKeys,
RevokeSigningKey,
MomentoLogger,
CacheFlush,
} from '..';
import {version} from '../../package.json';
import {IdleGrpcClientWrapper} from './grpc/idle-grpc-client-wrapper';
Expand Down Expand Up @@ -115,6 +116,39 @@ export class ControlClient {
});
}

public async flushCache(cacheName: string): Promise<CacheFlush.Response> {
try {
validateCacheName(cacheName);
} catch (err) {
return new CacheFlush.Error(normalizeSdkError(err as Error));
}
this.logger.trace(`Flushing cache: ${cacheName}`);
return await this.sendFlushCache(cacheName);
}

private async sendFlushCache(
cacheName: string
): Promise<CacheFlush.Response> {
const request = new grpcControl._FlushCacheRequest({
cache_name: cacheName,
});
return await new Promise(resolve => {
this.clientWrapper.getClient().FlushCache(
request,
{
interceptors: this.interceptors,
},
(err, resp) => {
if (resp) {
resolve(new CacheFlush.Success());
} else {
resolve(new CacheFlush.Error(cacheServiceErrorMapper(err)));
}
}
);
});
}

public async listCaches(): Promise<ListCaches.Response> {
const request = new grpcControl._ListCachesRequest();
request.next_token = '';
Expand Down
48 changes: 48 additions & 0 deletions src/messages/responses/cache-flush.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import {SdkError} from '../../errors/errors';
import {ResponseBase, ResponseError, ResponseSuccess} from './response-base';

/**
* Parent response type for a flush cache request. The
* response object is resolved to a type-safe object of one of
* the following subtypes:
*
* - {Success}
* - {Error}
*
* `instanceof` type guards can be used to operate on the appropriate subtype.
* @example
* For example:
* ```
* if (response instanceof CacheFlush.Error) {
* // Handle error as appropriate. The compiler will smart-cast `response` to type
* // `CacheFlush.Error` in this block, so you will have access to the properties
* // of the Error class; e.g. `response.errorCode()`.
* }
* ```
*/
export abstract class Response extends ResponseBase {}

class _Success extends Response {}

/**
* Indicates a Successful cache flush request.
*/
export class Success extends ResponseSuccess(_Success) {}

class _Error extends Response {
constructor(protected _innerException: SdkError) {
super();
}
}

/**
* Indicates that an error occurred during the cache flush request.
*
* This response object includes the following fields that you can use to determine
* how you would like to handle the error:
*
* - `errorCode()` - a unique Momento error code indicating the type of error that occurred.
* - `message()` - a human-readable description of the error
* - `innerException()` - the original error that caused the failure; can be re-thrown.
*/
export class Error extends ResponseError(_Error) {}
46 changes: 46 additions & 0 deletions test/integration/create-delete-list-cache.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
WithCache,
} from './integration-setup';
import {
CacheFlush,
CacheGet,
CreateCache,
DeleteCache,
ListCaches,
Expand Down Expand Up @@ -56,3 +58,47 @@ describe('create/delete cache', () => {
});
});
});

describe('flush cache', () => {
ItBehavesLikeItValidatesCacheName((props: ValidateCacheProps) => {
return Momento.flushCache(props.cacheName);
});

it('should return NotFoundError if flushing a non-existent cache', async () => {
const cacheName = v4();
const flushResponse = await Momento.flushCache(cacheName);
expect(flushResponse).toBeInstanceOf(CacheFlush.Response);
expect(flushResponse).toBeInstanceOf(CacheFlush.Error);
if (flushResponse instanceof CacheFlush.Error) {
expect(flushResponse.errorCode()).toEqual(
MomentoErrorCode.NOT_FOUND_ERROR
);
}
});

it('should return success while flushing empty cache', async () => {
const cacheName = v4();
await Momento.createCache(cacheName);
const flushResponse = await Momento.flushCache(cacheName);
expect(flushResponse).toBeInstanceOf(CacheFlush.Response);
expect(flushResponse).toBeInstanceOf(CacheFlush.Success);
});

it('should return success while flushing non-empty cache', async () => {
const cacheName = v4();
const key1 = v4();
const key2 = v4();
const value1 = v4();
const value2 = v4();
await Momento.createCache(cacheName);
await Momento.set(cacheName, key1, value1);
await Momento.set(cacheName, key2, value2);
const flushResponse = await Momento.flushCache(cacheName);
expect(flushResponse).toBeInstanceOf(CacheFlush.Response);
expect(flushResponse).toBeInstanceOf(CacheFlush.Success);
const getResponse1 = await Momento.get(cacheName, key1);
const getResponse2 = await Momento.get(cacheName, key2);
expect(getResponse1).toBeInstanceOf(CacheGet.Miss);
expect(getResponse2).toBeInstanceOf(CacheGet.Miss);
});
});

0 comments on commit e1c2b91

Please sign in to comment.