Skip to content

Commit

Permalink
fix(sdk): custom bind method on awscdk targets (#3769)
Browse files Browse the repository at this point in the history
Following @eladb's recommendation in PR #3398, I removed the import of `target-awscdk` and `target-tf-aws`, and checked if the `host` implements the methods of the `IAwsFunction` interface. This way, the error that was occurring due to not having `aws-cdk-lib` globally installed no longer happens.

## Checklist

- [x] Title matches [Winglang's style guide](https://www.winglang.io/contributing/start-here/pull_requests#how-are-pull-request-titles-formatted)
- [x] Description explains motivation and solution
- [x] Tests added (always)
- [ ] Docs updated (only required for features)
- [ ] Added `pr/e2e-full` label if this feature requires end-to-end testing

*By submitting this pull request, I confirm that my contribution is made under the terms of the [Wing Cloud Contribution License](https://github.com/winglang/wing/blob/main/CONTRIBUTION_LICENSE.md)*.
  • Loading branch information
marciocadev authored Aug 11, 2023
1 parent f416d4b commit 8b517b8
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 7 deletions.
15 changes: 13 additions & 2 deletions examples/tests/valid/dynamo.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { DynamoDBClient, PutItemCommand } = require("@aws-sdk/client-dynamodb");
const { DynamoDBClient, PutItemCommand, GetItemCommand } = require("@aws-sdk/client-dynamodb");

const client = new DynamoDBClient({});

Expand All @@ -7,8 +7,19 @@ export async function _putItem(tableName, item) {
TableName: tableName,
Item: item,
});

const response = await client.send(command);
console.log(response);
return;
}

export async function _getItem(tableName, key) {
const command = new GetItemCommand({
TableName: tableName,
Key: key
});

const response = await client.send(command);
console.log(response);
return response;
}
123 changes: 123 additions & 0 deletions examples/tests/valid/dynamo_awscdk.w
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*\
skip: true
\*/
// this example only works on AWS (intentionally)

bring "aws-cdk-lib" as awscdk;
bring aws;
bring cloud;
bring util;

enum AttributeType {
String,
Number,
Binary,
}

struct Attribute {
type: AttributeType;
value: Json;
}

class DynamoTable {
table: awscdk.aws_dynamodb.Table;
tableName: str;
init() {
let target = util.env("WING_TARGET");
if target != "awscdk" {
throw("Unsupported target: ${target} (expected 'awscdk')");
}

this.table = new awscdk.aws_dynamodb.Table(
tableName: this.node.addr,
billingMode: awscdk.aws_dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: awscdk.RemovalPolicy.DESTROY,
partitionKey: awscdk.aws_dynamodb.Attribute {
name: "Flavor",
type: awscdk.aws_dynamodb.AttributeType.STRING,
},
);
this.tableName = this.table.tableName;
}

bind(host: std.IInflightHost, ops: Array<str>) {
if let host = aws.Function.from(host) {
if ops.contains("putItem") {
host.addPolicyStatements([aws.PolicyStatement {
actions: ["dynamodb:PutItem"],
resources: [this.table.tableArn],
effect: aws.Effect.ALLOW,
}]);
}

if ops.contains("getItem") {
host.addPolicyStatements([aws.PolicyStatement {
actions: ["dynamodb:GetItem"],
resources: [this.table.tableArn],
effect: aws.Effect.ALLOW,
}]);
}
}
}

extern "./dynamo.js" inflight _putItem(tableName: str, item: Json): void;
inflight putItem(item: Map<Attribute>) {
let json = this._itemToJson(item);
this._putItem(this.tableName, json);
}

extern "./dynamo.js" inflight _getItem(tableName: str, key: Json): Json;
inflight getItem(key: Map<Attribute>): Json {
let json = this._itemToJson(key);
return this._getItem(this.tableName, json);
}

inflight _itemToJson(item: Map<Attribute>): Json {
let json = MutJson {};
for key in item.keys() {
let attribute = item.get(key);
let attributeTypeStr = this._attributeTypeToString(attribute.type);

let innerJson = MutJson {};
innerJson.set(attributeTypeStr, attribute.value);
json.set(key, innerJson);
}
return json;
}

inflight _attributeTypeToString(type: AttributeType): str {
if type == AttributeType.String {
return "S";
} elif type == AttributeType.Number {
return "N";
} elif type == AttributeType.Binary {
return "B";
}
}
}

// --- tests ---

let table = new DynamoTable();

test "cdk table" {
table.putItem({
"Flavor" => Attribute {
type: AttributeType.String,
value: "Chocolate",
},
"Quantity" => Attribute {
type: AttributeType.String,
value: "20Kg"
}
});

let c = table.getItem({
"Flavor" => Attribute {
type: AttributeType.String,
value: "Chocolate",
}
});
assert(c.get("Item").get("Flavor").get("S").asStr() == "Chocolate");
assert(c.get("Item").get("Quantity").get("S").asStr() == "20Kg");
}
11 changes: 8 additions & 3 deletions libs/wingsdk/src/shared-aws/function.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { PolicyStatement } from "./types";
import { IInflightHost } from "../std";
import { Function as TfAwsFunction } from "../target-tf-aws";

/**
* A shared interface for AWS functions.
Expand Down Expand Up @@ -30,10 +29,16 @@ export class Function {
* @param host The inflight host.
*/
public static from(host: IInflightHost): IAwsFunction | undefined {
if (host instanceof TfAwsFunction) {
if (this.isAwsFunction(host)) {
return host;
}

return undefined;
}

private static isAwsFunction(obj: any): obj is IAwsFunction {
return (
typeof obj.addPolicyStatements === "function" &&
typeof obj.addEnvironment === "function"
);
}
}
4 changes: 2 additions & 2 deletions libs/wingsdk/src/target-awscdk/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import { Construct } from "constructs";
import * as cloud from "../cloud";
import * as core from "../core";
import { createBundle } from "../shared/bundling";
import { PolicyStatement } from "../shared-aws";
import { IAwsFunction, PolicyStatement } from "../shared-aws";
import { IInflightHost } from "../std";

/**
* AWS implementation of `cloud.Function`.
*
* @inflight `@winglang/sdk.cloud.IFunctionClient`
*/
export class Function extends cloud.Function {
export class Function extends cloud.Function implements IAwsFunction {
private readonly function: CdkFunction;
/** Function ARN */
public readonly arn: string;
Expand Down

0 comments on commit 8b517b8

Please sign in to comment.