Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
improve types for progress event
  • Loading branch information
eduardomourar committed Oct 27, 2020
commit 33174ee1a72bb86f8cfec177d8e2136a20722bcd
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