Skip to content

Commit

Permalink
fix(lambda-event-source): allow dynamodb filtering on boolean value (#…
Browse files Browse the repository at this point in the history
…31011)

### Issue # (if applicable)

Closes #30734 

### Reason for this change

Filtering on boolean values was not possible

### Description of changes

`lambda.FilterRule.isEqual(...)` now accepts `boolean` values

### Description of how you validated changes

Added a unit test and integration test

### Checklist
- [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md)

----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
mellevanderlinde authored Aug 28, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent e3e5e1c commit 9946ab0
Showing 12 changed files with 849 additions and 1 deletion.

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

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

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

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
{
"Resources": {
"FServiceRole3AC82EE1": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
}
}
],
"Version": "2012-10-17"
},
"ManagedPolicyArns": [
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
]
]
}
]
}
},
"FServiceRoleDefaultPolicy17A19BFA": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": "dynamodb:ListStreams",
"Effect": "Allow",
"Resource": "*"
},
{
"Action": [
"dynamodb:DescribeStream",
"dynamodb:GetRecords",
"dynamodb:GetShardIterator"
],
"Effect": "Allow",
"Resource": {
"Fn::GetAtt": [
"TD925BC7E",
"StreamArn"
]
}
}
],
"Version": "2012-10-17"
},
"PolicyName": "FServiceRoleDefaultPolicy17A19BFA",
"Roles": [
{
"Ref": "FServiceRole3AC82EE1"
}
]
}
},
"FC4345940": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"ZipFile": "exports.handler = async function handler(event) {\n console.log('event:', JSON.stringify(event, undefined, 2));\n return { event };\n}"
},
"Handler": "index.handler",
"Role": {
"Fn::GetAtt": [
"FServiceRole3AC82EE1",
"Arn"
]
},
"Runtime": "nodejs18.x"
},
"DependsOn": [
"FServiceRoleDefaultPolicy17A19BFA",
"FServiceRole3AC82EE1"
]
},
"FDynamoDBEventSourcelambdaeventsourcefilterbooleandynamodbT2161ED824BB5B64C": {
"Type": "AWS::Lambda::EventSourceMapping",
"Properties": {
"BatchSize": 5,
"EventSourceArn": {
"Fn::GetAtt": [
"TD925BC7E",
"StreamArn"
]
},
"FilterCriteria": {
"Filters": [
{
"Pattern": "{\"eventName\":[\"INSERT\"],\"dynamodb\":{\"NewImage\":{\"id\":{\"BOOL\":[true]}}}}"
}
]
},
"FunctionName": {
"Ref": "FC4345940"
},
"StartingPosition": "LATEST"
}
},
"TD925BC7E": {
"Type": "AWS::DynamoDB::Table",
"Properties": {
"AttributeDefinitions": [
{
"AttributeName": "id",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "id",
"KeyType": "HASH"
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
},
"StreamSpecification": {
"StreamViewType": "NEW_IMAGE"
}
},
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
}
},
"Parameters": {
"BootstrapVersion": {
"Type": "AWS::SSM::Parameter::Value<String>",
"Default": "/cdk-bootstrap/hnb659fds/version",
"Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
}
},
"Rules": {
"CheckBootstrapVersion": {
"Assertions": [
{
"Assert": {
"Fn::Not": [
{
"Fn::Contains": [
[
"1",
"2",
"3",
"4",
"5"
],
{
"Ref": "BootstrapVersion"
}
]
}
]
},
"AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
}
]
}
}
}

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as cdk from 'aws-cdk-lib';
import * as integ from '@aws-cdk/integ-tests-alpha';
import { TestFunction } from './test-function';
import { DynamoEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';

const app = new cdk.App();

const stack = new cdk.Stack(app, 'lambda-event-source-filter-boolean-dynamodb');

const fn = new TestFunction(stack, 'F');
const table = new dynamodb.Table(stack, 'T', {
partitionKey: {
name: 'id',
type: dynamodb.AttributeType.STRING,
},
stream: dynamodb.StreamViewType.NEW_IMAGE,
removalPolicy: cdk.RemovalPolicy.DESTROY,
});

fn.addEventSource(new DynamoEventSource(table, {
batchSize: 5,
startingPosition: lambda.StartingPosition.LATEST,
filters: [
lambda.FilterCriteria.filter({
eventName: lambda.FilterRule.isEqual('INSERT'),
dynamodb: {
NewImage: {
id: { BOOL: lambda.FilterRule.isEqual(true) },
},
},
}),
],
}));

new integ.IntegTest(app, 'DynamoDBFilterBoolean', {
testCases: [stack],
});

app.synth();
25 changes: 25 additions & 0 deletions packages/aws-cdk-lib/aws-lambda-event-sources/README.md
Original file line number Diff line number Diff line change
@@ -169,6 +169,7 @@ and add it to your Lambda function. The following parameters will impact Amazon
* __startingPosition__: Will determine where to being consumption, either at the most recent ('LATEST') record or the oldest record ('TRIM_HORIZON'). 'TRIM_HORIZON' will ensure you process all available data, while 'LATEST' will ignore all records that arrived prior to attaching the event source.
* __tumblingWindow__: The duration in seconds of a processing window when using streams.
* __enabled__: If the DynamoDB Streams event source mapping should be enabled. The default is true.
* __filters__: Filters to apply before sending a change event from a DynamoDB table to a Lambda function. Events that are filtered out are not sent to the Lambda function.

```ts
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
@@ -188,6 +189,30 @@ fn.addEventSource(new DynamoEventSource(table, {
}));
```

The following code sets up a Lambda function with a DynamoDB event source. A filter is applied to only send DynamoDB events to
the Lambda function when the `id` column is a boolean that equals `true`.

```ts
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { DynamoEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';

declare const table: dynamodb.Table;

declare const fn: lambda.Function;
fn.addEventSource(new DynamoEventSource(table, {
startingPosition: lambda.StartingPosition.LATEST,
filters: [
lambda.FilterCriteria.filter({
eventName: lambda.FilterRule.isEqual('INSERT'),
dynamodb: {
NewImage: {
id: { BOOL: lambda.FilterRule.isEqual(true) },
},
},
}),
],
}));
```
## Kinesis

You can write Lambda functions to process streaming data in Amazon Kinesis Streams. For more information about Amazon Kinesis, see [Amazon Kinesis
49 changes: 49 additions & 0 deletions packages/aws-cdk-lib/aws-lambda-event-sources/test/dynamo.test.ts
Original file line number Diff line number Diff line change
@@ -949,4 +949,53 @@ describe('DynamoEventSource', () => {
}).toThrowError('S3 onFailure Destination is not supported for this event source');

});

test('filter on boolean', () => {
// GIVEN
const stack = new cdk.Stack();
const fn = new TestFunction(stack, 'Fn');
const table = new dynamodb.Table(stack, 'T', {
partitionKey: {
name: 'id',
type: dynamodb.AttributeType.STRING,
},
stream: dynamodb.StreamViewType.NEW_IMAGE,
});

// WHEN
fn.addEventSource(new sources.DynamoEventSource(table, {
startingPosition: lambda.StartingPosition.LATEST,
filters: [
lambda.FilterCriteria.filter({
eventName: lambda.FilterRule.isEqual('INSERT'),
dynamodb: {
NewImage: {
id: { BOOL: lambda.FilterRule.isEqual(true) },
},
},
}),
],
}));

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::Lambda::EventSourceMapping', {
'EventSourceArn': {
'Fn::GetAtt': [
'TD925BC7E',
'StreamArn',
],
},
'FunctionName': {
'Ref': 'Fn9270CBC0',
},
'FilterCriteria': {
'Filters': [
{
'Pattern': '{"eventName":["INSERT"],"dynamodb":{"NewImage":{"id":{"BOOL":[true]}}}}',
},
],
},
'StartingPosition': 'LATEST',
});
});
});
2 changes: 1 addition & 1 deletion packages/aws-cdk-lib/aws-lambda/lib/event-source-filter.ts
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ export class FilterRule {
/**
* Equals comparison operator
*/
public static isEqual(item: string | number): any {
public static isEqual(item: string | number | boolean): any {
if (typeof item === 'number') {
return [{ numeric: ['=', item] }];
}

0 comments on commit 9946ab0

Please sign in to comment.