Skip to content

Commit

Permalink
improve types for progress event
Browse files Browse the repository at this point in the history
  • Loading branch information
eduardomourar committed Oct 27, 2020
1 parent 814f5a3 commit 33174ee
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 59 deletions.
2 changes: 1 addition & 1 deletion python/rpdk/typescript/templates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Congratulations on starting development! Next steps:
Implement CloudFormation resource here. Each function must always return a ProgressEvent.

```typescript
const progress: ProgressEvent = ProgressEvent.builder<ProgressEvent<ResourceModel>>()
const progress = ProgressEvent.builder<ProgressEvent<ResourceModel>>()

// Required
// Must be one of OperationStatus.InProgress, OperationStatus.Failed, OperationStatus.Success
Expand Down
22 changes: 11 additions & 11 deletions python/rpdk/typescript/templates/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ class Resource extends BaseResource<ResourceModel> {
request: ResourceHandlerRequest<ResourceModel>,
callbackContext: CallbackContext,
logger: LoggerProxy
): Promise<ProgressEvent> {
const model: ResourceModel = new ResourceModel(request.desiredResourceState);
): Promise<ProgressEvent<ResourceModel, CallbackContext>> {
const model = new ResourceModel(request.desiredResourceState);
const progress = ProgressEvent.progress<ProgressEvent<ResourceModel, CallbackContext>>(model);
// TODO: put code here

Expand Down Expand Up @@ -69,8 +69,8 @@ class Resource extends BaseResource<ResourceModel> {
request: ResourceHandlerRequest<ResourceModel>,
callbackContext: CallbackContext,
logger: LoggerProxy
): Promise<ProgressEvent> {
const model: ResourceModel = new ResourceModel(request.desiredResourceState);
): Promise<ProgressEvent<ResourceModel, CallbackContext>> {
const model = new ResourceModel(request.desiredResourceState);
const progress = ProgressEvent.progress<ProgressEvent<ResourceModel, CallbackContext>>(model);
// TODO: put code here
progress.status = OperationStatus.Success;
Expand All @@ -93,8 +93,8 @@ class Resource extends BaseResource<ResourceModel> {
request: ResourceHandlerRequest<ResourceModel>,
callbackContext: CallbackContext,
logger: LoggerProxy
): Promise<ProgressEvent> {
const model: ResourceModel = new ResourceModel(request.desiredResourceState);
): Promise<ProgressEvent<ResourceModel, CallbackContext>> {
const model = new ResourceModel(request.desiredResourceState);
const progress = ProgressEvent.progress<ProgressEvent<ResourceModel, CallbackContext>>();
// TODO: put code here
progress.status = OperationStatus.Success;
Expand All @@ -116,8 +116,8 @@ class Resource extends BaseResource<ResourceModel> {
request: ResourceHandlerRequest<ResourceModel>,
callbackContext: CallbackContext,
logger: LoggerProxy
): Promise<ProgressEvent> {
const model: ResourceModel = new ResourceModel(request.desiredResourceState);
): Promise<ProgressEvent<ResourceModel, CallbackContext>> {
const model = new ResourceModel(request.desiredResourceState);
// TODO: put code here
const progress = ProgressEvent.success<ProgressEvent<ResourceModel, CallbackContext>>(model);
return progress;
Expand All @@ -138,8 +138,8 @@ class Resource extends BaseResource<ResourceModel> {
request: ResourceHandlerRequest<ResourceModel>,
callbackContext: CallbackContext,
logger: LoggerProxy
): Promise<ProgressEvent> {
const model: ResourceModel = new ResourceModel(request.desiredResourceState);
): Promise<ProgressEvent<ResourceModel, CallbackContext>> {
const model = new ResourceModel(request.desiredResourceState);
// TODO: put code here
const progress = ProgressEvent.builder<ProgressEvent<ResourceModel, CallbackContext>>()
.status(OperationStatus.Success)
Expand All @@ -149,7 +149,7 @@ class Resource extends BaseResource<ResourceModel> {
}
}

const resource = new Resource(ResourceModel.TYPE_NAME, ResourceModel);
export const resource = new Resource(ResourceModel.TYPE_NAME, ResourceModel);

export const entrypoint = resource.entrypoint;

Expand Down
6 changes: 3 additions & 3 deletions src/exceptions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HandlerErrorCode } from './interface';
import { BaseModel, HandlerErrorCode } from './interface';
import { ProgressEvent } from './proxy';

export abstract class BaseHandlerException extends Error {
Expand All @@ -13,8 +13,8 @@ export abstract class BaseHandlerException extends Error {
Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain
}

public toProgressEvent(): ProgressEvent {
return ProgressEvent.failed(this.errorCode, this.toString());
public toProgressEvent<T extends BaseModel = BaseModel>(): ProgressEvent<T> {
return ProgressEvent.failed<ProgressEvent<T>>(this.errorCode, this.toString());
}
}

Expand Down
47 changes: 28 additions & 19 deletions src/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,14 @@ const MUTATING_ACTIONS: [Action, Action, Action] = [
Action.Delete,
];

export type HandlerSignature = Callable<
export type HandlerSignature<T extends BaseModel> = Callable<
[Optional<SessionProxy>, any, Dict, LoggerProxy],
Promise<ProgressEvent>
Promise<ProgressEvent<T>>
>;
export class HandlerSignatures extends Map<Action, HandlerSignature> {}
export class HandlerSignatures<T extends BaseModel> extends Map<
Action,
HandlerSignature<T>
> {}
class HandlerEvents extends Map<Action, string | symbol> {}

/**
Expand All @@ -69,8 +72,8 @@ function ensureSerialize<T extends BaseModel>(toResponse = false): MethodDecorat
descriptor.value = async function (
event: any | Dict,
context: any
): Promise<ProgressEvent | CfnResponse<T>> {
const progress: ProgressEvent = await originalMethod.apply(this, [
): Promise<ProgressEvent<T> | CfnResponse<T>> {
const progress: ProgressEvent<T> = await originalMethod.apply(this, [
event,
context,
]);
Expand Down Expand Up @@ -108,10 +111,10 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
constructor(
public readonly typeName: string,
public readonly modelTypeReference: Constructor<T>,
private handlers?: HandlerSignatures
private handlers?: HandlerSignatures<T>
) {
this.typeName = typeName || '';
this.handlers = handlers || new HandlerSignatures();
this.handlers = handlers || new HandlerSignatures<T>();

this.lambdaLogger = console;

Expand Down Expand Up @@ -256,7 +259,10 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
}
}

public addHandler = (action: Action, f: HandlerSignature): HandlerSignature => {
public addHandler = (
action: Action,
f: HandlerSignature<T>
): HandlerSignature<T> => {
this.handlers.set(action, f);
return f;
};
Expand All @@ -266,12 +272,12 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
request: BaseResourceHandlerRequest<T>,
action: Action,
callbackContext: Dict
): Promise<ProgressEvent> => {
): Promise<ProgressEvent<T>> => {
const actionName = action == null ? '<null>' : action.toString();
if (!this.handlers.has(action)) {
throw new Error(`Unknown action ${actionName}`);
}
const handle: HandlerSignature = this.handlers.get(action);
const handle: HandlerSignature<T> = this.handlers.get(action);
// We will make the callback context and resource states readonly
// to avoid modification at a later time
deepFreeze(callbackContext);
Expand Down Expand Up @@ -328,15 +334,15 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
public async testEntrypoint(
eventData: any | Dict,
context?: any
): Promise<ProgressEvent>;
): Promise<ProgressEvent<T>>;
@boundMethod
@ensureSerialize<T>()
public async testEntrypoint(
eventData: Dict,
context?: any
): Promise<ProgressEvent> {
): Promise<ProgressEvent<T>> {
let msg = 'Uninitialized';
let progress: ProgressEvent;
let progress: ProgressEvent<T>;
try {
if (!this.modelTypeReference) {
throw new exceptions.InternalFailure(
Expand All @@ -359,11 +365,14 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
err.stack = `${new Error().stack}\n${err.stack}`;
if (err instanceof BaseHandlerException) {
this.log(`Handler error: ${err.message}`, err);
progress = err.toProgressEvent();
progress = err.toProgressEvent<T>();
} else {
this.log(`Exception caught: ${err.message}`, err);
msg = err.message || msg;
progress = ProgressEvent.failed(HandlerErrorCode.InternalFailure, msg);
progress = ProgressEvent.failed<ProgressEvent<T>>(
HandlerErrorCode.InternalFailure,
msg
);
}
}
return Promise.resolve(progress);
Expand Down Expand Up @@ -431,8 +440,8 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
public async entrypoint(
eventData: Dict,
context: LambdaContext
): Promise<ProgressEvent> {
let progress: ProgressEvent;
): Promise<ProgressEvent<T>> {
let progress: ProgressEvent<T>;
let bearerToken: string;
try {
if (!this.modelTypeReference) {
Expand Down Expand Up @@ -498,10 +507,10 @@ export abstract class BaseResource<T extends BaseModel = BaseModel> {
err.stack = `${new Error().stack}\n${err.stack}`;
if (err instanceof BaseHandlerException) {
this.log(`Handler error: ${err.message}`, err);
progress = err.toProgressEvent();
progress = err.toProgressEvent<T>();
} else {
this.log(`Exception caught: ${err.message}`, err);
progress = ProgressEvent.failed(
progress = ProgressEvent.failed<ProgressEvent<T>>(
HandlerErrorCode.InternalFailure,
err.message
);
Expand Down
12 changes: 6 additions & 6 deletions tests/lib/proxy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('when getting session proxy', () => {
});

test('get session returns proxy', () => {
const proxy: SessionProxy = SessionProxy.getSession({
const proxy = SessionProxy.getSession({
accessKeyId: '',
secretAccessKey: '',
sessionToken: '',
Expand All @@ -31,14 +31,14 @@ describe('when getting session proxy', () => {
});

test('get session returns null', () => {
const proxy: SessionProxy = SessionProxy.getSession(null);
const proxy = SessionProxy.getSession(null);
expect(proxy).toBeNull();
});

test('progress event failed is json serializable', () => {
const errorCode: HandlerErrorCode = HandlerErrorCode.AlreadyExists;
const errorCode = HandlerErrorCode.AlreadyExists;
const message = 'message of failed event';
const event: ProgressEvent = ProgressEvent.failed(errorCode, message);
const event = ProgressEvent.failed(errorCode, message);
expect(event.status).toBe(OperationStatus.Failed);
expect(event.errorCode).toBe(errorCode);
expect(event.message).toBe(message);
Expand Down Expand Up @@ -76,7 +76,7 @@ describe('when getting session proxy', () => {
someotherkey: 'b',
somenullkey: null,
});
const event = ProgressEvent.progress(model, null);
const event = ProgressEvent.progress<ProgressEvent<ResourceModel>>(model, null);
event.message = message;
const serialized = event.serialize();
expect(serialized).toMatchObject({
Expand All @@ -102,7 +102,7 @@ describe('when getting session proxy', () => {
someotherkey: 'd',
}),
];
const event = new ProgressEvent({
const event = new ProgressEvent<ResourceModel>({
status: OperationStatus.Success,
message,
resourceModels: models,
Expand Down
Loading

0 comments on commit 33174ee

Please sign in to comment.