├── ballerina ├── icon.png ├── Ballerina.toml ├── external_functions.bal ├── build.gradle ├── utils.bal ├── Module.md ├── Package.md ├── constatnts.bal ├── Dependencies.toml ├── stream_implementor.bal ├── client.bal ├── tests │ └── test.bal └── records.bal ├── docs ├── setup │ └── resources │ │ ├── view-user.png │ │ ├── create-user.png │ │ ├── create-group.png │ │ ├── create-access-key.png │ │ ├── create-user-review.png │ │ ├── download-access-key.png │ │ ├── create-group-policies.png │ │ ├── create-user-iam-user.png │ │ └── create-user-set-permission.png └── spec │ └── spec.md ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .github ├── pull_request_template.md ├── CODEOWNERS ├── workflows │ ├── trivy-scan.yml │ ├── daily-build.yml │ ├── pull-request.yml │ ├── ci.yml │ ├── release.yml │ ├── build-with-bal-test-graalvm.yml │ └── dev-stg-release.yml └── issue_template.md ├── gradle.properties ├── .gitignore ├── settings.gradle ├── examples ├── build.sh ├── game-scores │ ├── README.md │ └── client.bal └── build.gradle ├── gradlew.bat ├── gradlew ├── README.md └── LICENSE /ballerina/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-aws.dynamodb/HEAD/ballerina/icon.png -------------------------------------------------------------------------------- /docs/setup/resources/view-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-aws.dynamodb/HEAD/docs/setup/resources/view-user.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-aws.dynamodb/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /docs/setup/resources/create-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-aws.dynamodb/HEAD/docs/setup/resources/create-user.png -------------------------------------------------------------------------------- /docs/setup/resources/create-group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-aws.dynamodb/HEAD/docs/setup/resources/create-group.png -------------------------------------------------------------------------------- /docs/setup/resources/create-access-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-aws.dynamodb/HEAD/docs/setup/resources/create-access-key.png -------------------------------------------------------------------------------- /docs/setup/resources/create-user-review.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-aws.dynamodb/HEAD/docs/setup/resources/create-user-review.png -------------------------------------------------------------------------------- /docs/setup/resources/download-access-key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-aws.dynamodb/HEAD/docs/setup/resources/download-access-key.png -------------------------------------------------------------------------------- /docs/setup/resources/create-group-policies.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-aws.dynamodb/HEAD/docs/setup/resources/create-group-policies.png -------------------------------------------------------------------------------- /docs/setup/resources/create-user-iam-user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-aws.dynamodb/HEAD/docs/setup/resources/create-user-iam-user.png -------------------------------------------------------------------------------- /docs/setup/resources/create-user-set-permission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ballerina-platform/module-ballerinax-aws.dynamodb/HEAD/docs/setup/resources/create-user-set-permission.png -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Purpose 2 | 3 | Fixes: 4 | 5 | ## Examples 6 | 7 | ## Checklist 8 | - [ ] Linked to an issue 9 | - [ ] Updated the specification 10 | - [ ] Updated the changelog 11 | - [ ] Added tests 12 | - [ ] Checked native-image compatibility -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # See: https://help.github.com/articles/about-codeowners/ 5 | 6 | # These owners will be the default owners for everything in the repo. 7 | * @daneshk @lnash94 @TharmiganK @shafreenAnfar 8 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.caching=true 2 | group=io.ballerina.stdlib 3 | version=2.4.0-SNAPSHOT 4 | 5 | ballerinaLangVersion=2201.11.0 6 | checkstylePluginVersion=10.12.0 7 | spotbugsPluginVersion=6.0.18 8 | shadowJarPluginVersion=8.1.1 9 | downloadPluginVersion=5.4.0 10 | releasePluginVersion=2.8.0 11 | testngVersion=7.6.1 12 | eclipseLsp4jVersion=0.12.0 13 | ballerinaGradlePluginVersion=2.3.0 14 | -------------------------------------------------------------------------------- /ballerina/Ballerina.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | distribution = "2201.11.0-20241218-101200-109f6cc7" 3 | org = "ballerinax" 4 | name = "aws.dynamodb" 5 | version = "2.4.0" 6 | authors = ["Ballerina"] 7 | repository = "https://github.com/ballerina-platform/module-ballerinax-aws.dynamodb" 8 | keywords = ["Communication/Email", "Cost/Free", "Vendor/Google"] 9 | icon = "icon.png" 10 | license = ["Apache-2.0"] 11 | 12 | [build-options] 13 | observabilityIncluded = true 14 | -------------------------------------------------------------------------------- /.github/workflows/trivy-scan.yml: -------------------------------------------------------------------------------- 1 | name: Trivy 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: "30 20 * * *" 7 | 8 | jobs: 9 | call_workflow: 10 | name: Run Trivy Scan Workflow 11 | if: ${{ github.repository_owner == 'ballerina-platform' }} 12 | uses: ballerina-platform/ballerina-library/.github/workflows/trivy-scan-template.yml@main 13 | secrets: inherit 14 | with: 15 | additional-build-flags: "-x :aws.dynamodb-examples:build" 16 | -------------------------------------------------------------------------------- /.github/workflows/daily-build.yml: -------------------------------------------------------------------------------- 1 | name: Daily build 2 | 3 | on: 4 | schedule: 5 | - cron: "30 2 * * *" 6 | 7 | jobs: 8 | call_workflow: 9 | name: Run Daily Build Workflow 10 | if: ${{ github.repository_owner == 'ballerina-platform' }} 11 | uses: ballerina-platform/ballerina-library/.github/workflows/daily-build-connector-template.yml@main 12 | secrets: inherit 13 | with: 14 | repo-name: module-ballerinax-aws.dynamodb 15 | additional-build-flags: "-x :aws.dynamodb-examples:build" 16 | additional-test-flags: "-x :aws.dynamodb-examples:test" 17 | -------------------------------------------------------------------------------- /.github/workflows/pull-request.yml: -------------------------------------------------------------------------------- 1 | name: PR Build 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} 5 | cancel-in-progress: true 6 | 7 | on: pull_request 8 | 9 | jobs: 10 | call_workflow: 11 | name: Run PR Build Workflow 12 | if: ${{ github.repository_owner == 'ballerina-platform' }} 13 | uses: ballerina-platform/ballerina-library/.github/workflows/pr-build-connector-template.yml@main 14 | secrets: inherit 15 | with: 16 | additional-build-flags: "-x :aws.dynamodb-examples:build" 17 | additional-test-flags: "-x :aws.dynamodb-examples:test" 18 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - 2201.[0-9]+.x 8 | repository_dispatch: 9 | types: check_connector_for_breaking_changes 10 | 11 | jobs: 12 | call_workflow: 13 | name: Run Connector Build Workflow 14 | if: ${{ github.repository_owner == 'ballerina-platform' }} 15 | uses: ballerina-platform/ballerina-library/.github/workflows/build-connector-template.yml@main 16 | secrets: inherit 17 | with: 18 | repo-name: module-ballerinax-aws.dynamodb 19 | additional-build-flags: "-x :aws.dynamodb-examples:build" 20 | additional-test-flags: "-x :aws.dynamodb-examples:test" 21 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Publish Release 2 | 3 | on: 4 | workflow_dispatch: 5 | repository_dispatch: 6 | types: [ stdlib-release-pipeline ] 7 | 8 | jobs: 9 | call_workflow: 10 | name: Run Release Workflow 11 | if: ${{ github.repository_owner == 'ballerina-platform' }} 12 | uses: ballerina-platform/ballerina-library/.github/workflows/release-package-connector-template.yml@main 13 | secrets: inherit 14 | with: 15 | package-name: aws.dynamodb 16 | package-org: ballerinax 17 | additional-build-flags: "-x :aws.dynamodb-examples:build" 18 | additional-release-flags: "-x :aws.dynamodb-examples:build" 19 | additional-publish-flags: "-x :aws.dynamodb-examples:build" 20 | -------------------------------------------------------------------------------- /.github/workflows/build-with-bal-test-graalvm.yml: -------------------------------------------------------------------------------- 1 | name: GraalVM Check 2 | 3 | on: 4 | schedule: 5 | - cron: "30 18 * * *" 6 | workflow_dispatch: 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | call_stdlib_workflow: 14 | name: Run StdLib Workflow 15 | if: ${{ github.event_name != 'schedule' || (github.event_name == 'schedule' && github.repository_owner == 'ballerina-platform') }} 16 | uses: ballerina-platform/ballerina-library/.github/workflows/build-with-bal-test-graalvm-connector-template.yml@main 17 | secrets: inherit 18 | with: 19 | additional-build-flags: "-x :aws.dynamodb-examples:build" 20 | -------------------------------------------------------------------------------- /.github/workflows/dev-stg-release.yml: -------------------------------------------------------------------------------- 1 | name: Publish to the Ballerina Dev\Stage Central 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | environment: 7 | type: choice 8 | description: Select Environment 9 | required: true 10 | options: 11 | - DEV CENTRAL 12 | - STAGE CENTRAL 13 | 14 | jobs: 15 | call_workflow: 16 | name: Run Dev\Stage Central Publish Workflow 17 | if: ${{ github.repository_owner == 'ballerina-platform' }} 18 | uses: ballerina-platform/ballerina-library/.github/workflows/dev-stage-central-publish-connector-template.yml@main 19 | secrets: inherit 20 | with: 21 | environment: ${{ github.event.inputs.environment }} 22 | additional-publish-flags: "-x :aws.dynamodb-examples:build" 23 | -------------------------------------------------------------------------------- /.github/issue_template.md: -------------------------------------------------------------------------------- 1 | **Description:** 2 | 3 | 4 | **Suggested Labels:** 5 | 6 | 7 | **Suggested Assignees:** 8 | 9 | 10 | **Affected Product Version:** 11 | 12 | **OS, DB, other environment details and versions:** 13 | 14 | **Steps to reproduce:** 15 | 16 | 17 | **Related Issues:** 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # Ignore everything in this directory 26 | target 27 | .classpath 28 | .settings 29 | .project 30 | *.iml 31 | *.iws 32 | *.ipr 33 | .idea 34 | .m2 35 | .vscode/ 36 | *.ballerina/ 37 | 38 | # Ignore ballerina files 39 | temp.bal.ballerina/ 40 | target/ 41 | .DS_Store 42 | Config.toml 43 | 44 | # Ballerina configuartion file 45 | Config.toml 46 | 47 | # Target folder of ballerina project 48 | /target 49 | 50 | 51 | # resource folder in tests folder 52 | /tests/resources 53 | 54 | # resources folder 55 | /resources/*.json 56 | 57 | # idea files 58 | *.idea 59 | 60 | # .ballerina files 61 | *.ballerina 62 | 63 | # docker files 64 | *.env 65 | 66 | # Java related ignores 67 | **/build/ 68 | .gradle/ 69 | 70 | # Ignore installers and archives 71 | *.deb 72 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.3/userguide/building_swift_projects.html in the Gradle documentation. 6 | */ 7 | 8 | pluginManagement { 9 | plugins { 10 | id "com.github.spotbugs-base" version "${spotbugsPluginVersion}" 11 | id "com.github.johnrengelman.shadow" version "${shadowJarPluginVersion}" 12 | id "de.undercouch.download" version "${downloadPluginVersion}" 13 | id "net.researchgate.release" version "${releasePluginVersion}" 14 | id "io.ballerina.plugin" version "${ballerinaGradlePluginVersion}" 15 | } 16 | 17 | repositories { 18 | gradlePluginPortal() 19 | maven { 20 | url = 'https://maven.pkg.github.com/ballerina-platform/*' 21 | credentials { 22 | username System.getenv("packageUser") 23 | password System.getenv("packagePAT") 24 | } 25 | } 26 | } 27 | } 28 | 29 | plugins { 30 | id "com.gradle.enterprise" version "3.2" 31 | } 32 | 33 | rootProject.name = 'module-ballerinax-aws.dynamodb' 34 | 35 | include ':aws.dynamodb-ballerina' 36 | include ':aws.dynamodb-examples' 37 | 38 | project(':aws.dynamodb-ballerina').projectDir = file("ballerina") 39 | project(':aws.dynamodb-examples').projectDir = file("examples") 40 | 41 | gradleEnterprise { 42 | buildScan { 43 | termsOfServiceUrl = 'https://gradle.com/terms-of-service' 44 | termsOfServiceAgree = 'yes' 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ballerina/external_functions.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/jballerina.java; 18 | 19 | isolated function ofEpochSecond(int epochSeconds, int nanoAdjustments) returns handle = @java:Method { 20 | 'class: "java.time.Instant", 21 | name: "ofEpochSecond" 22 | } external; 23 | 24 | isolated function getZoneId(handle zoneId) returns handle = @java:Method { 25 | 'class: "java.time.ZoneId", 26 | name: "of" 27 | } external; 28 | 29 | isolated function atZone(handle receiver, handle zoneId) returns handle = @java:Method { 30 | 'class: "java.time.Instant", 31 | name: "atZone" 32 | } external; 33 | 34 | isolated function ofPattern(handle pattern) returns handle = @java:Method { 35 | 'class: "java.time.format.DateTimeFormatter", 36 | name: "ofPattern" 37 | } external; 38 | 39 | isolated function format(handle receiver, handle dateTimeFormatter) returns handle = @java:Method { 40 | 'class: "java.time.ZonedDateTime", 41 | name: "format" 42 | } external; 43 | -------------------------------------------------------------------------------- /examples/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | BAL_EXAMPLES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 4 | BAL_CENTRAL_DIR="$HOME/.ballerina/repositories/central.ballerina.io/" 5 | BAL_HOME_DIR="$BAL_EXAMPLES_DIR/../ballerina" 6 | 7 | set -e 8 | 9 | case "$1" in 10 | build) 11 | BAL_CMD="build" 12 | ;; 13 | run) 14 | BAL_CMD="run" 15 | ;; 16 | *) 17 | echo "Invalid command provided: '$1'. Please provide 'build' or 'run' as the command." 18 | exit 1 19 | ;; 20 | esac 21 | 22 | # Read Ballerina package name 23 | BAL_PACKAGE_NAME=$(awk -F'"' '/^name/ {print $2}' "$BAL_HOME_DIR/Ballerina.toml") 24 | 25 | # Push the package to the local repository 26 | cd "$BAL_HOME_DIR" && 27 | bal pack && 28 | bal push --repository=local 29 | 30 | # Remove the cache directories in the repositories 31 | cacheDirs=($(ls -d "$BAL_CENTRAL_DIR"/cache-* 2>/dev/null)) 32 | for dir in "${cacheDirs[@]}"; do 33 | [ -d "$dir" ] && rm -r "$dir" 34 | done 35 | echo "Successfully cleaned the cache directories" 36 | 37 | # Update the central repository 38 | BAL_DESTINATION_DIR="$HOME/.ballerina/repositories/central.ballerina.io/bala/ballerinax/$BAL_PACKAGE_NAME" 39 | BAL_SOURCE_DIR="$HOME/.ballerina/repositories/local/bala/ballerinax/$BAL_PACKAGE_NAME" 40 | [ -d "$BAL_DESTINATION_DIR" ] && rm -r "$BAL_DESTINATION_DIR" 41 | [ -d "$BAL_SOURCE_DIR" ] && cp -r "$BAL_SOURCE_DIR" "$BAL_DESTINATION_DIR" 42 | echo "Successfully updated the local central repositories" 43 | 44 | echo "$BAL_DESTINATION_DIR" 45 | echo "$BAL_SOURCE_DIR" 46 | 47 | # Loop through examples in the examples directory 48 | find "$BAL_EXAMPLES_DIR" -type f -name "*.bal" | while read -r BAL_EXAMPLE_FILE; do 49 | bal "$BAL_CMD" --offline "$BAL_EXAMPLE_FILE" 50 | done 51 | 52 | # Remove generated JAR files 53 | find "$BAL_HOME_DIR" -maxdepth 1 -type f -name "*.jar" | while read -r JAR_FILE; do 54 | rm "$JAR_FILE" 55 | done 56 | -------------------------------------------------------------------------------- /examples/game-scores/README.md: -------------------------------------------------------------------------------- 1 | # Mobile Game High Scores 2 | 3 | ## Overview 4 | 5 | Imagine you are developing a mobile gaming application that tracks high scores for different games. In this scenario, DynamoDB could be employed to manage the backend data storage efficiently. This example demonstrates how DynamoDB can be used to store and manage high scores efficiently, providing low-latency access to data and allowing for seamless scaling as the number of players and high scores grows. DynamoDB's ability to handle large amounts of data with high throughput makes it suitable for such real-time, dynamic applications. This example demonstrates how the basic operations of updating/deleting the high scores can be performed using the `dynamodb` connector. 6 | 7 | ## Implementation 8 | 9 | 1. Create a table 10 | 11 | You create a DynamoDB table named "HighScores" with the following structure: 12 | a. Partition key: GameID (String) 13 | b. Sort key: Score (Number) 14 | 15 | 2. Insert High scores 16 | 17 | Whenever a player completes a game, the mobile app sends the high score data to DynamoDB. 18 | 19 | 3. Querying the high scores 20 | 21 | Players can view the top scores for a specific game. The program is written to retrieve the top 10 high scores for the game. 22 | 23 | 3. Updating high scores 24 | 25 | If a player achieves a higher score, the app updates the DynamoDB record. Using the `updateItem` API, the player name for the high score of 500 in the "FlappyBird" game to "NewPlayer." 26 | 27 | 4. Delete high scores 28 | 29 | If a player wants to remove their score, the app can delete the corresponding record using the `deleteItem` API. 30 | 31 | ## Run the Example 32 | 33 | First, clone this repository, and then run the following commands to run this example in your local machine. 34 | 35 | ```sh 36 | // Run the dynamoDB client 37 | $ cd examples/game/client 38 | $ bal run 39 | ``` 40 | -------------------------------------------------------------------------------- /examples/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import org.apache.tools.ant.taskdefs.condition.Os 20 | 21 | apply plugin: 'java' 22 | 23 | def graalvmFlag = "" 24 | 25 | task testExamples { 26 | if (project.hasProperty("balGraalVMTest")) { 27 | graalvmFlag = "--graalvm" 28 | } 29 | doLast { 30 | try { 31 | exec { 32 | workingDir project.projectDir 33 | println("Working dir: ${workingDir}") 34 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 35 | commandLine 'sh', "/c", "chmod +x ./build.sh && ./build.sh run && exit %%ERRORLEVEL%%" 36 | } else { 37 | commandLine 'sh', "-c", "chmod +x ./build.sh && ./build.sh run" 38 | } 39 | } 40 | } catch (Exception e) { 41 | println("Example Build failed: " + e.message) 42 | throw e 43 | } 44 | } 45 | } 46 | 47 | task buildExamples { 48 | gradle.taskGraph.whenReady { graph -> 49 | if (graph.hasTask(":dynamodb-examples:test")) { 50 | buildExamples.enabled = false 51 | } else { 52 | testExamples.enabled = false 53 | } 54 | } 55 | doLast { 56 | try { 57 | exec { 58 | workingDir project.projectDir 59 | println("Working dir: ${workingDir}") 60 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 61 | commandLine 'sh', "/c", "chmod +x ./build.s && ./build.sh build && exit %%ERRORLEVEL%%" 62 | } else { 63 | commandLine 'sh', "-c", "chmod +x ./build.sh && ./build.sh build" 64 | } 65 | } 66 | } catch (Exception e) { 67 | println("Example Build failed: " + e.message) 68 | throw e 69 | } 70 | } 71 | } 72 | 73 | buildExamples.dependsOn ":aws.dynamodb-ballerina:build" 74 | testExamples.dependsOn ":aws.dynamodb-ballerina:build" 75 | test.dependsOn testExamples 76 | build.dependsOn buildExamples 77 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /ballerina/build.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. 3 | * 4 | * WSO2 LLC. licenses this file to you under the Apache License, 5 | * Version 2.0 (the "License"); you may not use this file except 6 | * in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, 12 | * software distributed under the License is distributed on an 13 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | * KIND, either express or implied. See the License for the 15 | * specific language governing permissions and limitations 16 | * under the License. 17 | */ 18 | 19 | import org.apache.tools.ant.taskdefs.condition.Os 20 | 21 | buildscript { 22 | repositories { 23 | maven { 24 | url = 'https://maven.pkg.github.com/ballerina-platform/plugin-gradle' 25 | credentials { 26 | username System.getenv("packageUser") 27 | password System.getenv("packagePAT") 28 | } 29 | } 30 | } 31 | dependencies { 32 | classpath "io.ballerina:plugin-gradle:${project.ballerinaGradlePluginVersion}" 33 | } 34 | } 35 | 36 | plugins { 37 | id 'io.ballerina.plugin' 38 | } 39 | 40 | description = 'Dynamodb - Ballerina' 41 | 42 | def packageName = "aws.dynamodb" 43 | def packageOrg = "ballerinax" 44 | def tomlVersion = stripBallerinaExtensionVersion("${project.version}") 45 | def ballerinaTomlFilePlaceHolder = new File("${project.rootDir}/build-config/resources/Ballerina.toml") 46 | def ballerinaTomlFile = new File("$project.projectDir/Ballerina.toml") 47 | 48 | def stripBallerinaExtensionVersion(String extVersion) { 49 | if (extVersion.matches(project.ext.timestampedVersionRegex)) { 50 | def splitVersion = extVersion.split('-') 51 | if (splitVersion.length > 3) { 52 | def strippedValues = splitVersion[0..-4] 53 | return strippedValues.join('-') 54 | } else { 55 | return extVersion 56 | } 57 | } else { 58 | return extVersion.replace("${project.ext.snapshotVersion}", "") 59 | } 60 | } 61 | 62 | ballerina { 63 | packageOrganization = packageOrg 64 | module = packageName 65 | testCoverageParam = "--code-coverage --coverage-format=xml --excludes=\"modules/oas/**\"" 66 | isConnector = true 67 | langVersion = ballerinaLangVersion 68 | platform = "java17" 69 | } 70 | 71 | task updateTomlFiles { 72 | doLast { 73 | def newBallerinaToml = ballerinaTomlFilePlaceHolder.text.replace("@project.version@", project.version) 74 | newBallerinaToml = newBallerinaToml.replace("@toml.version@", tomlVersion) 75 | ballerinaTomlFile.text = newBallerinaToml 76 | } 77 | } 78 | 79 | task commitTomlFiles { 80 | doLast { 81 | project.exec { 82 | ignoreExitValue true 83 | if (Os.isFamily(Os.FAMILY_WINDOWS)) { 84 | commandLine 'cmd', '/c', "git commit -m \"[Automated] Update the toml files\" Ballerina.toml Dependencies.toml" 85 | } else { 86 | commandLine 'sh', '-c', "git commit -m '[Automated] Update the toml files' Ballerina.toml Dependencies.toml" 87 | } 88 | } 89 | } 90 | } 91 | 92 | clean { 93 | def folder = file('build') 94 | if( folder.exists() ) { 95 | delete 'build' 96 | } 97 | } 98 | 99 | publishToMavenLocal.dependsOn build 100 | publish.dependsOn build 101 | -------------------------------------------------------------------------------- /examples/game-scores/client.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 LLC. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/io; 18 | import ballerina/os; 19 | import ballerinax/aws.dynamodb; 20 | 21 | public function main() returns error? { 22 | dynamodb:ConnectionConfig amazonDynamodbConfig = { 23 | awsCredentials: { 24 | accessKeyId: os:getEnv("ACCESS_KEY_ID"), 25 | secretAccessKey: os:getEnv("SECRET_ACCESS_KEY") 26 | }, 27 | region: os:getEnv("REGION") 28 | }; 29 | 30 | dynamodb:Client amazonDynamodbClient = check new (amazonDynamodbConfig); 31 | dynamodb:TableCreateInput createTableInput = { 32 | TableName: "HighScores", 33 | AttributeDefinitions: [ 34 | {AttributeName: "GameID", AttributeType: "S"}, 35 | {AttributeName: "Score", AttributeType: "N"} 36 | ], 37 | KeySchema: [ 38 | {AttributeName: "GameID", KeyType: "HASH"}, 39 | {AttributeName: "Score", KeyType: "RANGE"} 40 | ], 41 | ProvisionedThroughput: { 42 | ReadCapacityUnits: 5, 43 | WriteCapacityUnits: 5 44 | } 45 | }; 46 | _ = check amazonDynamodbClient->createTable(createTableInput); 47 | 48 | dynamodb:ItemCreateInput createItemInput = { 49 | TableName: "HighScores", 50 | Item: { 51 | "GameID": {"S": "FlappyBird"}, 52 | "Score": {"N": "500"}, 53 | "PlayerName": {"S": "JohnDoe"} 54 | } 55 | }; 56 | dynamodb:ItemDescription createItemResult = check amazonDynamodbClient->createItem(createItemInput); 57 | io:println("Added item: ", createItemResult); 58 | 59 | dynamodb:QueryInput queryInput = { 60 | TableName: "HighScores", 61 | KeyConditionExpression: "GameID = :game", 62 | ExpressionAttributeValues: { 63 | ":game": {"S": "FlappyBird"} 64 | }, 65 | Limit: 10, 66 | ScanIndexForward: false 67 | }; 68 | 69 | stream response = check amazonDynamodbClient->query(queryInput); 70 | check response.forEach(function(dynamodb:QueryOutput resp) { 71 | io:println(resp?.Item); 72 | }); 73 | 74 | dynamodb:ItemUpdateInput updateItemInput = { 75 | TableName: "HighScores", 76 | Key: { 77 | "GameID": {"S": "FlappyBird"}, 78 | "Score": {"N": "1000"} 79 | }, 80 | UpdateExpression: "set PlayerName = :name", 81 | ExpressionAttributeValues: { 82 | ":name": {"S": "Jasper"} 83 | } 84 | }; 85 | dynamodb:ItemDescription updateItemResult = check amazonDynamodbClient->updateItem(updateItemInput); 86 | io:println("Updated the high score: ", updateItemResult); 87 | 88 | dynamodb:ItemDeleteInput deleteItemInput = { 89 | TableName: "HighScores", 90 | Key: { 91 | "GameID": {"S": "FlappyBird"}, 92 | "Score": {"N": "500"} 93 | } 94 | }; 95 | 96 | dynamodb:ItemDescription deleteItemResult = check amazonDynamodbClient->deleteItem(deleteItemInput); 97 | io:println("Deleted the high score: ", deleteItemResult); 98 | } 99 | -------------------------------------------------------------------------------- /ballerina/utils.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | import ballerina/crypto; 17 | import ballerina/jballerina.java; 18 | import ballerina/lang.array; 19 | import ballerina/time; 20 | import ballerina/url; 21 | 22 | # Represents any error related to the dynamodb module. 23 | public type Error distinct error; 24 | 25 | isolated function getSignedRequestHeaders(string host, string accessKey, string secretKey, string region, string verb, 26 | string uri, string amzTarget, json requestPayload) returns map|error { 27 | 28 | string content_type = APPLICATION_JSON; 29 | string canonicalUri = check getCanonicalURI(uri); 30 | string payload = requestPayload === EMPTY_STRING ? EMPTY_STRING : requestPayload.toJsonString(); 31 | 32 | [int, decimal] & readonly currentTime = time:utcNow(); 33 | string|error amzDate = utcToString(currentTime, ISO8601_BASIC_DATE_FORMAT); 34 | string|error dateStamp = utcToString(currentTime, SHORT_DATE_FORMAT); 35 | 36 | if amzDate is string && dateStamp is string { 37 | string canonicalQuerystring = EMPTY_STRING; 38 | 39 | string canonicalHeaders = CONTENT_TYPE + COLON + content_type + NEW_LINE + HOST + COLON + host + NEW_LINE + 40 | X_AMZ_DATE + COLON + amzDate + NEW_LINE + X_AMZ_TARGET + COLON + amzTarget + NEW_LINE; 41 | 42 | string signedHeaders = CONTENT_TYPE + SEMICOLON + HOST + SEMICOLON + X_AMZ_DATE + SEMICOLON + X_AMZ_TARGET; 43 | 44 | string payloadHash = array:toBase16(crypto:hashSha256(payload.toBytes())).toLowerAscii(); 45 | 46 | string canonicalRequest = verb + NEW_LINE + canonicalUri + NEW_LINE + canonicalQuerystring + NEW_LINE 47 | + canonicalHeaders + NEW_LINE + signedHeaders + NEW_LINE + payloadHash; 48 | 49 | string credentialScope = dateStamp + SLASH + region + SLASH + AWS_SERVICE 50 | + SLASH + AWS4_REQUEST; 51 | 52 | string stringToSign = AWS4_HMAC_SHA256 + NEW_LINE + amzDate + NEW_LINE + credentialScope + NEW_LINE 53 | + array:toBase16(crypto:hashSha256(canonicalRequest.toBytes())).toLowerAscii(); 54 | 55 | byte[] signingKey = check getSignatureKey(secretKey, dateStamp, region, AWS_SERVICE); 56 | 57 | string signature = array:toBase16(check crypto:hmacSha256(stringToSign.toBytes(), signingKey)).toLowerAscii(); 58 | 59 | string authorizationHeader = AWS4_HMAC_SHA256 + SPACE + CREDENTIAL + EQUAL + accessKey + SLASH 60 | + credentialScope + COMMA + SPACE + SIGNED_HEADER + EQUAL + signedHeaders 61 | + COMMA + SPACE + SIGNATURE + EQUAL + signature; 62 | 63 | map headers = {}; 64 | headers[HEADER_CONTENT_TYPE] = content_type; 65 | headers[HEADER_HOST] = host; 66 | headers[HEADER_X_AMZ_DATE] = amzDate; 67 | headers[HEADER_X_AMZ_TARGET] = amzTarget; 68 | headers[HEADER_AUTHORIZATION] = authorizationHeader; 69 | 70 | return headers; 71 | } else { 72 | if amzDate is error { 73 | return error(GENERATE_SIGNED_REQUEST_HEADERS_FAILED_MSG, amzDate); 74 | } else if dateStamp is error { 75 | return error(GENERATE_SIGNED_REQUEST_HEADERS_FAILED_MSG, dateStamp); 76 | } else { 77 | return error(GENERATE_SIGNED_REQUEST_HEADERS_FAILED_MSG); 78 | } 79 | } 80 | } 81 | 82 | isolated function sign(byte[] key, string msg) returns byte[]|error { 83 | return check crypto:hmacSha256(msg.toBytes(), key); 84 | } 85 | 86 | isolated function getSignatureKey(string secretKey, string datestamp, string region, string serviceName) 87 | returns byte[]|error { 88 | string awskey = (AWS4 + secretKey); 89 | byte[] kDate = check sign(awskey.toBytes(), datestamp); 90 | byte[] kRegion = check sign(kDate, region); 91 | byte[] kService = check sign(kRegion, serviceName); 92 | byte[] kSigning = check sign(kService, AWS4_REQUEST); 93 | return kSigning; 94 | } 95 | 96 | isolated function utcToString(time:Utc utc, string pattern) returns string|error { 97 | [int, decimal] [epochSeconds, lastSecondFraction] = utc; 98 | int nanoAdjustments = (lastSecondFraction * 1000000000); 99 | var instant = ofEpochSecond(epochSeconds, nanoAdjustments); 100 | var zoneId = getZoneId(java:fromString(Z)); 101 | var zonedDateTime = atZone(instant, zoneId); 102 | var dateTimeFormatter = ofPattern(java:fromString(pattern)); 103 | handle formatString = format(zonedDateTime, dateTimeFormatter); 104 | return formatString.toBalString(); 105 | } 106 | 107 | isolated function getCanonicalURI(string requestURI) returns string|error { 108 | string value = check url:encode(requestURI, UTF_8); 109 | return re `%2F`.replaceAll(value, SLASH, 0); 110 | } 111 | -------------------------------------------------------------------------------- /ballerina/Module.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | [Amazon DynamoDB](https://aws.amazon.com/dynamodb/) is a fully managed, serverless, key-value NoSQL database designed to run high-performance applications at any scale. DynamoDB offers built-in security, continuous backups, automated multi-region replication, in-memory caching, and data export tools. 4 | 5 | The Ballerina AWS DynamoDB connector provides the capability to programatically handle [AWS DynamoDB](hhttps://aws.amazon.com/dynamodb/) related operations. 6 | This module supports [Amazon DynamoDB REST API 20120810](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/Welcome.html). 7 | 8 | ## Setup guide 9 | 10 | ### Step 1: Create an AWS account 11 | 12 | * If you don't already have an AWS account, you need to create one. Go to the [AWS Management Console](https://console.aws.amazon.com/console/home), click on "Create a new AWS Account," and follow the instructions. 13 | 14 | ### Step 2: Get the access key ID and the secret access key 15 | 16 | Once you log in to your AWS account, you need to create a user group and a user with the necessary permissions to access DynamoDB. To do this, follow the steps below: 17 | 18 | 1. Create an AWS user group 19 | 20 | * Navigate to the Identity and Access Management (IAM) service. Click on "Groups" and then "Create New Group." 21 | 22 | Create user group 23 | 24 | * Enter a group name and attach the necessary policies to the group. For example, you can attach the "AmazonDynamoDBFullAccess" policy to provide full access to DynamoDB. 25 | 26 | Attach policy 27 | 28 | 2. Create an IAM user 29 | 30 | * In the IAM console, navigate to "Users" and click on "Add user." 31 | 32 | Add user 33 | 34 | * Enter a username, tick the "Provide user access to the AWS Management Console - optional" checkbox, and click "I want to create an IAM user". This will enable programmatic access through access keys. 35 | 36 | Create IAM user 37 | 38 | * Click through the permission setup, and add the user to the user group we previously created. 39 | 40 | Attach user group 41 | 42 | * Review the details and click "Create user." 43 | 44 | Review user 45 | 46 | 3. Generate access key ID and secret access key 47 | 48 | * Once the user is created, you will see a success message. Navigate to the "Users" tab, and select the user you created. 49 | 50 | View User 51 | 52 | * Click on the "Create access key" button to generate the access key ID and secret access key. 53 | 54 | Create access key 55 | 56 | * Follow the steps and download the CSV file containing the credentials. 57 | 58 | Download credentials 59 | 60 | ## Quickstart 61 | 62 | To use the `dynamodb` connector in your Ballerina project, modify the `.bal` file as follows: 63 | 64 | ### Step 1: Import the module 65 | 66 | Import the `ballerinax/aws.dynamodb` module into your Ballerina project. 67 | ```ballerina 68 | import ballerinax/aws.dynamodb; 69 | ``` 70 | 71 | ### Step 2: Instantiate a new connector 72 | 73 | Create a new `dynamodb:Client` by providing the access key ID, secret access key, and the region. 74 | ```ballerina 75 | dynamodb:Client dynamoDb = check new ({ 76 | awsCredentials: { 77 | accessKeyId, 78 | secretAccessKey 79 | }, 80 | region 81 | }); 82 | ``` 83 | 84 | ### Step 3: Invoke the connector operation 85 | 86 | Now, utilize the available connector operations. 87 | ```ballerina 88 | public function main() returns error? { 89 | dynamodb:Client dynamoDb = ...// 90 | dynamodb:TableCreateInput tableInput = { 91 | TableName: "HighScores", 92 | AttributeDefinitions: [ 93 | {AttributeName: "GameID", AttributeType: "S"}, 94 | {AttributeName: "Score", AttributeType: "N"} 95 | ], 96 | KeySchema: [ 97 | {AttributeName: "GameID", KeyType: "HASH"}, 98 | {AttributeName: "Score", KeyType: "RANGE"} 99 | ], 100 | ProvisionedThroughput: { 101 | ReadCapacityUnits: 5, 102 | WriteCapacityUnits: 5 103 | } 104 | }; 105 | _ = check dynamoDb->createTable(tableInput); 106 | } 107 | ``` 108 | 109 | ### Step 4: Run the Ballerina application 110 | 111 | Use the following command to compile and run the Ballerina program. 112 | 113 | ```bash 114 | bal run 115 | ``` 116 | 117 | ## Examples 118 | 119 | The `dynamodb` connector provides practical examples illustrating usage in various scenarios. Explore these [examples](https://github.com/ballerina-platform/module-ballerinax-aws.dynamodb/tree/master/examples), covering use cases like creating, reading, updating, deleting data from tables. 120 | 121 | 1. [Maintain a game score dashboard](https://github.com/ballerina-platform/module-ballerinax-aws.dynamodb/tree/master/examples/game-scores) 122 | This example shows how to use the DynamoDB APIs to manage a mobile gaming application dashboard that tracks high scores for different games. 123 | 124 | For comprehensive information about the connector's functionality, configuration, and usage in Ballerina programs, refer to the `dynamodb` connector's reference guide in [Ballerina Central](https://central.ballerina.io/ballerinax/aws.dynamodb/latest). 125 | -------------------------------------------------------------------------------- /ballerina/Package.md: -------------------------------------------------------------------------------- 1 | ## Package Overview 2 | 3 | [Amazon DynamoDB](https://aws.amazon.com/dynamodb/) is a fully managed, serverless, key-value NoSQL database designed to run high-performance applications at any scale. DynamoDB offers built-in security, continuous backups, automated multi-region replication, in-memory caching, and data export tools. 4 | 5 | The Ballerina AWS DynamoDB connector provides the capability to programmatically handle [AWS DynamoDB](hhttps://aws.amazon.com/dynamodb/) related operations. 6 | This module supports [Amazon DynamoDB REST API 20120810](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/Welcome.html). 7 | 8 | ## Setup guide 9 | 10 | ### Step 1: Create an AWS account 11 | 12 | * If you don't already have an AWS account, you need to create one. Go to the [AWS Management Console](https://console.aws.amazon.com/console/home), click on "Create a new AWS Account," and follow the instructions. 13 | 14 | ### Step 2: Get the access key ID and the secret access key 15 | 16 | Once you log in to your AWS account, you need to create a user group and a user with the necessary permissions to access DynamoDB. To do this, follow the steps below: 17 | 18 | 1. Create an AWS user group 19 | 20 | * Navigate to the Identity and Access Management (IAM) service. Click on "Groups" and then "Create New Group." 21 | 22 | Create user group 23 | 24 | * Enter a group name and attach the necessary policies to the group. For example, you can attach the "AmazonDynamoDBFullAccess" policy to provide full access to DynamoDB. 25 | 26 | Attach policy 27 | 28 | 2. Create an IAM user 29 | 30 | * In the IAM console, navigate to "Users" and click on "Add user." 31 | 32 | Add user 33 | 34 | * Enter a username, tick the "Provide user access to the AWS Management Console - optional" checkbox, and click "I want to create an IAM user". This will enable programmatic access through access keys. 35 | 36 | Create IAM user 37 | 38 | * Click through the permission setup, and add the user to the user group we previously created. 39 | 40 | Attach user group 41 | 42 | * Review the details and click "Create user." 43 | 44 | Review user 45 | 46 | 3. Generate access key ID and secret access key 47 | 48 | * Once the user is created, you will see a success message. Navigate to the "Users" tab, and select the user you created. 49 | 50 | View User 51 | 52 | * Click on the "Create access key" button to generate the access key ID and secret access key. 53 | 54 | Create access key 55 | 56 | * Follow the steps and download the CSV file containing the credentials. 57 | 58 | Download credentials 59 | 60 | ## Quickstart 61 | 62 | To use the `dynamodb` connector in your Ballerina project, modify the `.bal` file as follows: 63 | 64 | ### Step 1: Import the module 65 | 66 | Import the `ballerinax/aws.dynamodb` module into your Ballerina project. 67 | ```ballerina 68 | import ballerinax/aws.dynamodb; 69 | ``` 70 | 71 | ### Step 2: Instantiate a new connector 72 | 73 | Create a new `dynamodb:Client` by providing the access key ID, secret access key, and the region. 74 | ```ballerina 75 | dynamodb:Client dynamoDb = check new ({ 76 | awsCredentials: { 77 | accessKeyId, 78 | secretAccessKey 79 | }, 80 | region 81 | }); 82 | ``` 83 | 84 | ### Step 3: Invoke the connector operation 85 | 86 | Now, utilize the available connector operations. 87 | ```ballerina 88 | public function main() returns error? { 89 | dynamodb:Client dynamoDb = ...// 90 | dynamodb:TableCreateInput tableInput = { 91 | TableName: "HighScores", 92 | AttributeDefinitions: [ 93 | {AttributeName: "GameID", AttributeType: "S"}, 94 | {AttributeName: "Score", AttributeType: "N"} 95 | ], 96 | KeySchema: [ 97 | {AttributeName: "GameID", KeyType: "HASH"}, 98 | {AttributeName: "Score", KeyType: "RANGE"} 99 | ], 100 | ProvisionedThroughput: { 101 | ReadCapacityUnits: 5, 102 | WriteCapacityUnits: 5 103 | } 104 | }; 105 | _ = check dynamoDb->createTable(tableInput); 106 | } 107 | ``` 108 | 109 | ### Step 4: Run the Ballerina application 110 | 111 | Use the following command to compile and run the Ballerina program. 112 | 113 | ```bash 114 | bal run 115 | ``` 116 | 117 | ## Examples 118 | 119 | The `dynamodb` connector provides practical examples illustrating usage in various scenarios. Explore these [examples](https://github.com/ballerina-platform/module-ballerinax-aws.dynamodb/tree/master/examples), covering use cases like creating, reading, updating, deleting data from tables. 120 | 121 | 1. [Maintain a game score dashboard](https://github.com/ballerina-platform/module-ballerinax-aws.dynamodb/tree/master/examples/game-scores) 122 | This example shows how to use the DynamoDB APIs to manage a mobile gaming application dashboard that tracks high scores for different games. 123 | 124 | For comprehensive information about the connector's functionality, configuration, and usage in Ballerina programs, refer to the `dynamodb` connector's reference guide in [Ballerina Central](https://central.ballerina.io/ballerinax/aws.dynamodb/latest). 125 | -------------------------------------------------------------------------------- /ballerina/constatnts.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | const string AWS_HOST = "amazonaws.com"; 18 | const string AWS_SERVICE = "dynamodb"; 19 | const string VERSION = "DynamoDB_20120810"; 20 | 21 | const string UTF_8 = "UTF-8"; 22 | const string HOST = "host"; 23 | const string CONTENT_TYPE = "content-type"; 24 | const string APPLICATION_JSON = "application/json"; 25 | const string X_AMZ_DATE = "x-amz-date"; 26 | const string X_AMZ_TARGET = "x-amz-target"; 27 | const string AWS4_REQUEST = "aws4_request"; 28 | const string AWS4_HMAC_SHA256 = "AWS4-HMAC-SHA256"; 29 | const string CREDENTIAL = "Credential"; 30 | const string SIGNED_HEADER = "SignedHeaders"; 31 | const string SIGNATURE = "Signature"; 32 | const string AWS4 = "AWS4"; 33 | const string ISO8601_BASIC_DATE_FORMAT = "yyyyMMdd'T'HHmmss'Z'"; 34 | const string SHORT_DATE_FORMAT = "yyyyMMdd"; 35 | const string ENCODED_SLASH = "%2F"; 36 | const string SLASH = "/"; 37 | const string EMPTY_STRING = ""; 38 | const string NEW_LINE = "\n"; 39 | const string COLON = ":"; 40 | const string SEMICOLON = ";"; 41 | const string EQUAL = "="; 42 | const string SPACE = " "; 43 | const string COMMA = ","; 44 | const string DOT = "."; 45 | const string Z = "Z"; 46 | 47 | // HTTP. 48 | const string POST = "POST"; 49 | const string HTTPS = "https://"; 50 | 51 | // Constants to refer the headers. 52 | const string HEADER_CONTENT_TYPE = "Content-Type"; 53 | const string HEADER_X_AMZ_CONTENT_SHA256 = "X-Amz-Content-Sha256"; 54 | const string HEADER_X_AMZ_DATE = "X-Amz-Date"; 55 | const string HEADER_X_AMZ_TARGET = "X-Amz-Target"; 56 | const string HEADER_HOST = "Host"; 57 | const string HEADER_AUTHORIZATION = "Authorization"; 58 | 59 | const string GENERATE_SIGNED_REQUEST_HEADERS_FAILED_MSG = "Error occurred while generating signed request headers."; 60 | 61 | # Represents the attribute types supported by Amazon DynamoDB. 62 | public enum AttributeType { 63 | # Represents a string 64 | S, 65 | # Represents a number 66 | N, 67 | # Represents a binary data 68 | B 69 | } 70 | 71 | # Represents the key type of an attribute in a DynamoDB table. 72 | # This enum is used in the `KeySchema` of a `TableSchema` to specify the type of the key attribute. 73 | public enum KeyType { 74 | # Represents the partition key 75 | HASH, 76 | # Represents the sort key 77 | RANGE 78 | } 79 | 80 | # Represents the types of projections that can be used in a DynamoDB query. 81 | public enum ProjectionType { 82 | KEYS_ONLY, 83 | # All of the item attributes are projected. 84 | ALL, 85 | # Only the specified attributes of the queried item(s) are projected. 86 | INCLUDE, 87 | # All of the item attributes are projected except for the specified attributes. 88 | EXCLUDE 89 | } 90 | 91 | # Represents the types of server-side encryption supported by DynamoDB. 92 | public enum SSEType { 93 | AES256, KMS 94 | } 95 | 96 | # Represents the stream view type of a DynamoDB table. 97 | public enum StreamViewType { 98 | # Returns all of the attributes of the item, as they appear after the UpdateItem operation 99 | NEW_IMAGE, 100 | # Returns all of the attributes of the item, as they appeared before the UpdateItem operation 101 | OLD_IMAGE, 102 | # Returns both the new and the old images of the item 103 | NEW_AND_OLD_IMAGES, 104 | # Returns only the key attributes of the item, not the other attributes 105 | KEYS_ONLY 106 | } 107 | 108 | # Represents the billing mode of a DynamoDB table. 109 | public enum BillingMode { 110 | # Represents the provisioned throughput mode for a DynamoDB table 111 | PROVISIONED, 112 | # Represents the pay-per-request billing mode for DynamoDB 113 | PAY_PER_REQUEST 114 | } 115 | 116 | # Represents the status of an index. 117 | public enum IndexStatus { 118 | # Represents the state of a DynamoDB table being created 119 | CREATING, 120 | # Represents the state of an update operation in AWS DynamoDB 121 | UPDATING, 122 | # Represents the state of a DynamoDB operation where an item is being deleted 123 | DELETING, 124 | # Represents the status of an item in DynamoDB as active 125 | ACTIVE 126 | } 127 | 128 | # Represents the status of a replica in Amazon DynamoDB. 129 | public enum ReplicaStatus { 130 | CREATING, CREATION_FAILED,UPDATING, DELETING, ACTIVE, REGION_DISABLED, INACCESSIBLE_ENCRYPTION_CREDENTIALS 131 | } 132 | 133 | # Represents the status of a DynamoDB operation. 134 | public enum Status { 135 | ENABLING, ENABLED, DISABLING, DISABLED, UPDATING 136 | } 137 | 138 | # Represents the status of an AWS DynamoDB table. 139 | public enum TableStatus { 140 | CREATING, UPDATING, DELETING, ACTIVE, INACCESSIBLE_ENCRYPTION_CREDENTIALS, ARCHIVING, ARCHIVED 141 | } 142 | 143 | # Represents the comparison operators used in DynamoDB queries. 144 | public enum ComparisonOperator { 145 | # Equal to 146 | EQ, 147 | # Not equal to 148 | NE, 149 | # In 150 | IN, 151 | # Less than or equal to 152 | LE, 153 | # Less than 154 | LT, 155 | # Greater than or equal to 156 | GE, 157 | # Greater than 158 | GT, 159 | # Between 160 | BETWEEN, 161 | # Not null 162 | NOT_NULL, 163 | # Null 164 | NULL, 165 | # Contains 166 | CONTAINS, 167 | # Does not contain 168 | NOT_CONTAINS, 169 | # Begins with 170 | BEGINS_WITH 171 | } 172 | 173 | # Represents the conditional operator used in DynamoDB operations. 174 | public enum ConditionalOperator { 175 | AND, OR 176 | } 177 | 178 | # Represents the return consumed capacity mode for DynamoDB operations. 179 | public enum ReturnConsumedCapacity { 180 | # Consistent read with indexes 181 | INDEXES, 182 | # Consistent read with all the provisioned attributes 183 | TOTAL, 184 | # Eventually consistent read 185 | NONE 186 | } 187 | 188 | # Represents the enum for the return item collection metrics in AWS DynamoDB. 189 | public enum ReturnItemCollectionMetrics { 190 | SIZE, 191 | NONE 192 | } 193 | 194 | # Represents the possible return values of a DynamoDB operation. 195 | public enum ReturnValues { 196 | NONE, ALL_OLD, UPDATED_OLD, ALL_NEW, UPDATED_NEW 197 | } 198 | 199 | # Represents the actions that can be performed on a DynamoDB table. 200 | public enum Action { 201 | ADD, PUT, DELETE 202 | } 203 | 204 | # Represents the SELECT operation in DynamoDB. 205 | public enum Select { 206 | ALL_ATTRIBUTES, ALL_PROJECTED_ATTRIBUTES, SPECIFIC_ATTRIBUTES, COUNT 207 | } 208 | 209 | # Represents the status of a stream. 210 | public enum StreamStatus { 211 | ENABLING, ENABLED, DISABLING, DISABLED 212 | } 213 | 214 | # Represents the event name. 215 | public enum eventName { 216 | INSERT, MODIFY, REMOVE 217 | } 218 | 219 | # Represents the type of shard iterator to be used when reading data from a DynamoDB stream. 220 | public enum ShardIteratorType { 221 | # Start reading at the last (untrimmed) stream record, which is the oldest record in the 222 | # shard. In DynamoDB Streams, there is a 24 hour limit on data retention. Stream records 223 | # whose age exceeds this limit are subject to removal (trimming) from the stream 224 | TRIM_HORIZON, 225 | # Start reading just after the most recent stream record in the shard, so that you always 226 | # read the most recent data in the shard 227 | LATEST, 228 | # Start reading exactly from the position denoted by a specific sequence number 229 | AT_SEQUENCE_NUMBER, 230 | # Start reading right after the position denoted by a specific sequence number 231 | AFTER_SEQUENCE_NUMBER 232 | } 233 | 234 | # Represents the status of the time to live (TTL) attribute of an item in Amazon DynamoDB. 235 | public enum TimeToLiveStatus { 236 | ENABLING, DISABLING, ENABLED, DISABLED 237 | } 238 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Use the maximum available, or set MAX_FD != -1 to use that value. 89 | MAX_FD=maximum 90 | 91 | warn () { 92 | echo "$*" 93 | } >&2 94 | 95 | die () { 96 | echo 97 | echo "$*" 98 | echo 99 | exit 1 100 | } >&2 101 | 102 | # OS specific support (must be 'true' or 'false'). 103 | cygwin=false 104 | msys=false 105 | darwin=false 106 | nonstop=false 107 | case "$( uname )" in #( 108 | CYGWIN* ) cygwin=true ;; #( 109 | Darwin* ) darwin=true ;; #( 110 | MSYS* | MINGW* ) msys=true ;; #( 111 | NONSTOP* ) nonstop=true ;; 112 | esac 113 | 114 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 115 | 116 | 117 | # Determine the Java command to use to start the JVM. 118 | if [ -n "$JAVA_HOME" ] ; then 119 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 120 | # IBM's JDK on AIX uses strange locations for the executables 121 | JAVACMD=$JAVA_HOME/jre/sh/java 122 | else 123 | JAVACMD=$JAVA_HOME/bin/java 124 | fi 125 | if [ ! -x "$JAVACMD" ] ; then 126 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 127 | 128 | Please set the JAVA_HOME variable in your environment to match the 129 | location of your Java installation." 130 | fi 131 | else 132 | JAVACMD=java 133 | if ! command -v java >/dev/null 2>&1 134 | then 135 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 136 | 137 | Please set the JAVA_HOME variable in your environment to match the 138 | location of your Java installation." 139 | fi 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | 201 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 202 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 203 | 204 | # Collect all arguments for the java command; 205 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 206 | # shell script including quotes and variable substitutions, so put them in 207 | # double quotes to make sure that they get re-expanded; and 208 | # * put everything else in single quotes, so that it's not re-expanded. 209 | 210 | set -- \ 211 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 212 | -classpath "$CLASSPATH" \ 213 | org.gradle.wrapper.GradleWrapperMain \ 214 | "$@" 215 | 216 | # Stop when "xargs" is not available. 217 | if ! command -v xargs >/dev/null 2>&1 218 | then 219 | die "xargs is not available" 220 | fi 221 | 222 | # Use "xargs" to parse quoted args. 223 | # 224 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 225 | # 226 | # In Bash we could simply go: 227 | # 228 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 229 | # set -- "${ARGS[@]}" "$@" 230 | # 231 | # but POSIX shell has neither arrays nor command substitution, so instead we 232 | # post-process each arg (as a line of input to sed) to backslash-escape any 233 | # character that might be a shell metacharacter, then use eval to reverse 234 | # that process (while maintaining the separation between arguments), and wrap 235 | # the whole thing up as a single "set" statement. 236 | # 237 | # This will of course break if any of these variables contains a newline or 238 | # an unmatched quote. 239 | # 240 | 241 | eval "set -- $( 242 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 243 | xargs -n1 | 244 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 245 | tr '\n' ' ' 246 | )" '"$@"' 247 | 248 | exec "$JAVACMD" "$@" 249 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ballerina Amazon DynamoDB Connector 2 | [![Build Status](https://github.com/ballerina-platform/module-ballerinax-aws.dynamodb/workflows/CI/badge.svg)](https://github.com/ballerina-platform/module-ballerinax-aws.dynamodb/actions?query=workflow%3ACI) 3 | [![codecov](https://codecov.io/gh/ballerina-platform/module-ballerinax-aws.dynamodb/branch/main/graph/badge.svg)](https://codecov.io/gh/ballerina-platform/module-ballerinax-aws.dynamodb) 4 | [![GitHub Last Commit](https://img.shields.io/github/last-commit/ballerina-platform/module-ballerinax-aws.dynamodb.svg)](https://github.com/ballerina-platform/module-ballerinax-aws.dynamodb./commits/master) 5 | [![GraalVM Check](https://github.com/ballerina-platform/module-ballerinax-aws.dynamodb/actions/workflows/build-with-bal-test-native.yml/badge.svg)](https://github.com/ballerina-platform/module-ballerinax-aws.dynamodb/actions/workflows/build-with-bal-test-native.yml) 6 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) 7 | 8 | [Amazon DynamoDB](https://aws.amazon.com/dynamodb/) is a fully managed, serverless, key-value NoSQL database designed to run high-performance applications at any scale. DynamoDB offers built-in security, continuous backups, automated multi-region replication, in-memory caching, and data export tools. 9 | 10 | ## Overview 11 | 12 | The connector provides the capability to programatically handle AWS DynamoDB related operations. 13 | 14 | This module supports [Amazon DynamoDB REST API 20120810](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/Welcome.html). 15 | 16 | ## Setup guide 17 | 18 | ### Step 1: Create an AWS account 19 | 20 | * If you don't already have an AWS account, you need to create one. Go to the [AWS Management Console](https://console.aws.amazon.com/console/home), click on "Create a new AWS Account," and follow the instructions. 21 | 22 | ### Step 2: Get the access key ID and the secret access key 23 | 24 | Once you log in to your AWS account, you need to create a user group and a user with the necessary permissions to access DynamoDB. To do this, follow the steps below: 25 | 26 | 1. Create an AWS user group 27 | 28 | * Navigate to the Identity and Access Management (IAM) service. Click on "Groups" and then "Create New Group." 29 | 30 | Create user group 31 | 32 | * Enter a group name and attach the necessary policies to the group. For example, you can attach the "AmazonDynamoDBFullAccess" policy to provide full access to DynamoDB. 33 | 34 | Attach policy 35 | 36 | 2. Create an IAM user 37 | 38 | * In the IAM console, navigate to "Users" and click on "Add user." 39 | 40 | Add user 41 | 42 | * Enter a username, tick the "Provide user access to the AWS Management Console - optional" checkbox, and click "I want to create an IAM user". This will enable programmatic access through access keys. 43 | 44 | Create IAM user 45 | 46 | * Click through the permission setup, and add the user to the user group we previously created. 47 | 48 | Attach user group 49 | 50 | * Review the details and click "Create user." 51 | 52 | Review user 53 | 54 | 3. Generate access key ID and secret access key 55 | 56 | * Once the user is created, you will see a success message. Navigate to the "Users" tab, and select the user you created. 57 | 58 | View User 59 | 60 | * Click on the "Create access key" button to generate the access key ID and secret access key. 61 | 62 | Create access key 63 | 64 | * Follow the steps and download the CSV file containing the credentials. 65 | 66 | Download credentials 67 | 68 | ## Quickstart 69 | 70 | To use the `dynamodb` connector in your Ballerina project, modify the `.bal` file as follows: 71 | 72 | ### Step 1: Import the module 73 | 74 | Import the `ballerinax/aws.dynamodb` module into your Ballerina project. 75 | ```ballerina 76 | import ballerinax/aws.dynamodb; 77 | ``` 78 | 79 | ### Step 2: Instantiate a new connector 80 | 81 | Instantiate a new `dynamodb:Client` using the access key ID, secret access key and the region. 82 | ```ballerina 83 | dynamodb:Client dynamoDb = check new ({ 84 | awsCredentials: { 85 | accessKeyId, 86 | secretAccessKey 87 | }, 88 | region 89 | }); 90 | ``` 91 | 92 | ### Step 3: Invoke the connector operation 93 | 94 | Now, utilize the available connector operations. 95 | ```ballerina 96 | public function main() returns error? { 97 | dynamodb:Client dynamoDb = ...// 98 | dynamodb:TableCreateInput tableInput = { 99 | TableName: "HighScores", 100 | AttributeDefinitions: [ 101 | {AttributeName: "GameID", AttributeType: "S"}, 102 | {AttributeName: "Score", AttributeType: "N"} 103 | ], 104 | KeySchema: [ 105 | {AttributeName: "GameID", KeyType: "HASH"}, 106 | {AttributeName: "Score", KeyType: "RANGE"} 107 | ], 108 | ProvisionedThroughput: { 109 | ReadCapacityUnits: 5, 110 | WriteCapacityUnits: 5 111 | } 112 | }; 113 | _ = check dynamoDb->createTable(tableInput); 114 | } 115 | ``` 116 | 117 | ### Step 4: Run the Ballerina application 118 | 119 | Use the following command to compile and run the Ballerina program. 120 | 121 | ```bash 122 | bal run 123 | ``` 124 | 125 | ## Examples 126 | 127 | The `dynamodb` connector provides practical examples illustrating usage in various scenarios. Explore these [examples](https://github.com/ballerina-platform/module-ballerinax-aws.dynamodb/tree/master/examples), covering use cases like creating, reading, updating, deleting data from tables. 128 | 129 | 1. [Maintain a game score dashboard](https://github.com/ballerina-platform/module-ballerinax-aws.dynamodb/tree/master/examples/game-scores) 130 | This example shows how to use the DynamoDB APIs to manage a mobile gaming application dashboard that tracks high scores for different games. 131 | 132 | ## Issues and projects 133 | 134 | The **Issues** and **Projects** tabs are disabled for this repository as this is part of the Ballerina library. To report bugs, request new features, start new discussions, view project boards, etc., visit the Ballerina library [parent repository](https://github.com/ballerina-platform/ballerina-library). 135 | 136 | This repository only contains the source code for the package. 137 | 138 | ## Build from the source 139 | 140 | ### Prerequisites 141 | 142 | 1. Download and install Java SE Development Kit (JDK) version 21. You can download it from either of the following sources: 143 | 144 | * [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) 145 | * [OpenJDK](https://adoptium.net/) 146 | 147 | > **Note:** After installation, remember to set the `JAVA_HOME` environment variable to the directory where JDK was installed. 148 | 149 | 2. Download and install [Ballerina Swan Lake](https://ballerina.io/). 150 | 151 | 3. Download and install [Docker](https://www.docker.com/get-started). 152 | 153 | > **Note**: Ensure that the Docker daemon is running before executing any tests. 154 | 155 | ### Build options 156 | 157 | Execute the commands below to build from the source. 158 | 159 | 1. To build the package: 160 | ``` 161 | ./gradlew clean build 162 | ``` 163 | 164 | 2. To run the tests: 165 | ``` 166 | ./gradlew clean test 167 | ``` 168 | 169 | 3. To build the without the tests: 170 | ``` 171 | ./gradlew clean build -x test 172 | ``` 173 | 174 | 5. To debug package with a remote debugger: 175 | ``` 176 | ./gradlew clean build -Pdebug= 177 | ``` 178 | 179 | 6. To debug with the Ballerina language: 180 | ``` 181 | ./gradlew clean build -PbalJavaDebug= 182 | ``` 183 | 184 | 7. Publish the generated artifacts to the local Ballerina Central repository: 185 | ``` 186 | ./gradlew clean build -PpublishToLocalCentral=true 187 | ``` 188 | 189 | 8. Publish the generated artifacts to the Ballerina Central repository: 190 | ``` 191 | ./gradlew clean build -PpublishToCentral=true 192 | ``` 193 | 194 | ## Contribute to Ballerina 195 | 196 | As an open-source project, Ballerina welcomes contributions from the community. 197 | 198 | For more information, go to the [contribution guidelines](https://github.com/ballerina-platform/ballerina-lang/blob/master/CONTRIBUTING.md). 199 | 200 | ## Code of conduct 201 | 202 | All the contributors are encouraged to read the [Ballerina Code of Conduct](https://ballerina.io/code-of-conduct). 203 | 204 | ## Useful links 205 | 206 | * For more information go to the [`aws.dynamodb` package](https://lib.ballerina.io/ballerinax/aws.dynamodb/latest). 207 | * For example demonstrations of the usage, go to [Ballerina By Examples](https://ballerina.io/learn/by-example/). 208 | * Chat live with us via our [Discord server](https://discord.gg/ballerinalang). 209 | * Post all technical questions on Stack Overflow with the [#ballerina](https://stackoverflow.com/questions/tagged/ballerina) tag. 210 | -------------------------------------------------------------------------------- /ballerina/Dependencies.toml: -------------------------------------------------------------------------------- 1 | # AUTO-GENERATED FILE. DO NOT MODIFY. 2 | 3 | # This file is auto-generated by Ballerina for managing dependency versions. 4 | # It should not be modified by hand. 5 | 6 | [ballerina] 7 | dependencies-toml-version = "2" 8 | distribution-version = "2201.8.5" 9 | 10 | [[package]] 11 | org = "ballerina" 12 | name = "auth" 13 | version = "2.10.0" 14 | dependencies = [ 15 | {org = "ballerina", name = "crypto"}, 16 | {org = "ballerina", name = "jballerina.java"}, 17 | {org = "ballerina", name = "lang.array"}, 18 | {org = "ballerina", name = "lang.string"}, 19 | {org = "ballerina", name = "log"} 20 | ] 21 | 22 | [[package]] 23 | org = "ballerina" 24 | name = "cache" 25 | version = "3.7.1" 26 | dependencies = [ 27 | {org = "ballerina", name = "constraint"}, 28 | {org = "ballerina", name = "jballerina.java"}, 29 | {org = "ballerina", name = "task"}, 30 | {org = "ballerina", name = "time"} 31 | ] 32 | 33 | [[package]] 34 | org = "ballerina" 35 | name = "constraint" 36 | version = "1.5.0" 37 | dependencies = [ 38 | {org = "ballerina", name = "jballerina.java"} 39 | ] 40 | 41 | [[package]] 42 | org = "ballerina" 43 | name = "crypto" 44 | version = "2.6.2" 45 | dependencies = [ 46 | {org = "ballerina", name = "jballerina.java"}, 47 | {org = "ballerina", name = "time"} 48 | ] 49 | modules = [ 50 | {org = "ballerina", packageName = "crypto", moduleName = "crypto"} 51 | ] 52 | 53 | [[package]] 54 | org = "ballerina" 55 | name = "file" 56 | version = "1.9.0" 57 | dependencies = [ 58 | {org = "ballerina", name = "io"}, 59 | {org = "ballerina", name = "jballerina.java"}, 60 | {org = "ballerina", name = "os"}, 61 | {org = "ballerina", name = "time"} 62 | ] 63 | 64 | [[package]] 65 | org = "ballerina" 66 | name = "http" 67 | version = "2.10.12" 68 | dependencies = [ 69 | {org = "ballerina", name = "auth"}, 70 | {org = "ballerina", name = "cache"}, 71 | {org = "ballerina", name = "constraint"}, 72 | {org = "ballerina", name = "crypto"}, 73 | {org = "ballerina", name = "file"}, 74 | {org = "ballerina", name = "io"}, 75 | {org = "ballerina", name = "jballerina.java"}, 76 | {org = "ballerina", name = "jwt"}, 77 | {org = "ballerina", name = "lang.array"}, 78 | {org = "ballerina", name = "lang.decimal"}, 79 | {org = "ballerina", name = "lang.int"}, 80 | {org = "ballerina", name = "lang.regexp"}, 81 | {org = "ballerina", name = "lang.runtime"}, 82 | {org = "ballerina", name = "lang.string"}, 83 | {org = "ballerina", name = "lang.value"}, 84 | {org = "ballerina", name = "log"}, 85 | {org = "ballerina", name = "mime"}, 86 | {org = "ballerina", name = "oauth2"}, 87 | {org = "ballerina", name = "observe"}, 88 | {org = "ballerina", name = "time"}, 89 | {org = "ballerina", name = "url"} 90 | ] 91 | modules = [ 92 | {org = "ballerina", packageName = "http", moduleName = "http"}, 93 | {org = "ballerina", packageName = "http", moduleName = "http.httpscerr"} 94 | ] 95 | 96 | [[package]] 97 | org = "ballerina" 98 | name = "io" 99 | version = "1.6.0" 100 | dependencies = [ 101 | {org = "ballerina", name = "jballerina.java"}, 102 | {org = "ballerina", name = "lang.value"} 103 | ] 104 | modules = [ 105 | {org = "ballerina", packageName = "io", moduleName = "io"} 106 | ] 107 | 108 | [[package]] 109 | org = "ballerina" 110 | name = "jballerina.java" 111 | version = "0.0.0" 112 | modules = [ 113 | {org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"} 114 | ] 115 | 116 | [[package]] 117 | org = "ballerina" 118 | name = "jwt" 119 | version = "2.10.0" 120 | dependencies = [ 121 | {org = "ballerina", name = "cache"}, 122 | {org = "ballerina", name = "crypto"}, 123 | {org = "ballerina", name = "jballerina.java"}, 124 | {org = "ballerina", name = "lang.int"}, 125 | {org = "ballerina", name = "lang.string"}, 126 | {org = "ballerina", name = "log"}, 127 | {org = "ballerina", name = "time"} 128 | ] 129 | 130 | [[package]] 131 | org = "ballerina" 132 | name = "lang.__internal" 133 | version = "0.0.0" 134 | dependencies = [ 135 | {org = "ballerina", name = "jballerina.java"}, 136 | {org = "ballerina", name = "lang.object"} 137 | ] 138 | 139 | [[package]] 140 | org = "ballerina" 141 | name = "lang.array" 142 | version = "0.0.0" 143 | dependencies = [ 144 | {org = "ballerina", name = "jballerina.java"}, 145 | {org = "ballerina", name = "lang.__internal"} 146 | ] 147 | modules = [ 148 | {org = "ballerina", packageName = "lang.array", moduleName = "lang.array"} 149 | ] 150 | 151 | [[package]] 152 | org = "ballerina" 153 | name = "lang.decimal" 154 | version = "0.0.0" 155 | dependencies = [ 156 | {org = "ballerina", name = "jballerina.java"} 157 | ] 158 | 159 | [[package]] 160 | org = "ballerina" 161 | name = "lang.error" 162 | version = "0.0.0" 163 | scope = "testOnly" 164 | dependencies = [ 165 | {org = "ballerina", name = "jballerina.java"} 166 | ] 167 | 168 | [[package]] 169 | org = "ballerina" 170 | name = "lang.int" 171 | version = "0.0.0" 172 | dependencies = [ 173 | {org = "ballerina", name = "jballerina.java"}, 174 | {org = "ballerina", name = "lang.__internal"}, 175 | {org = "ballerina", name = "lang.object"} 176 | ] 177 | 178 | [[package]] 179 | org = "ballerina" 180 | name = "lang.object" 181 | version = "0.0.0" 182 | 183 | [[package]] 184 | org = "ballerina" 185 | name = "lang.regexp" 186 | version = "0.0.0" 187 | dependencies = [ 188 | {org = "ballerina", name = "jballerina.java"} 189 | ] 190 | 191 | [[package]] 192 | org = "ballerina" 193 | name = "lang.runtime" 194 | version = "0.0.0" 195 | dependencies = [ 196 | {org = "ballerina", name = "jballerina.java"} 197 | ] 198 | modules = [ 199 | {org = "ballerina", packageName = "lang.runtime", moduleName = "lang.runtime"} 200 | ] 201 | 202 | [[package]] 203 | org = "ballerina" 204 | name = "lang.string" 205 | version = "0.0.0" 206 | dependencies = [ 207 | {org = "ballerina", name = "jballerina.java"}, 208 | {org = "ballerina", name = "lang.regexp"} 209 | ] 210 | 211 | [[package]] 212 | org = "ballerina" 213 | name = "lang.value" 214 | version = "0.0.0" 215 | dependencies = [ 216 | {org = "ballerina", name = "jballerina.java"} 217 | ] 218 | 219 | [[package]] 220 | org = "ballerina" 221 | name = "log" 222 | version = "2.9.0" 223 | dependencies = [ 224 | {org = "ballerina", name = "io"}, 225 | {org = "ballerina", name = "jballerina.java"}, 226 | {org = "ballerina", name = "lang.value"}, 227 | {org = "ballerina", name = "observe"} 228 | ] 229 | modules = [ 230 | {org = "ballerina", packageName = "log", moduleName = "log"} 231 | ] 232 | 233 | [[package]] 234 | org = "ballerina" 235 | name = "mime" 236 | version = "2.9.0" 237 | dependencies = [ 238 | {org = "ballerina", name = "io"}, 239 | {org = "ballerina", name = "jballerina.java"}, 240 | {org = "ballerina", name = "lang.int"} 241 | ] 242 | 243 | [[package]] 244 | org = "ballerina" 245 | name = "oauth2" 246 | version = "2.10.0" 247 | dependencies = [ 248 | {org = "ballerina", name = "cache"}, 249 | {org = "ballerina", name = "crypto"}, 250 | {org = "ballerina", name = "jballerina.java"}, 251 | {org = "ballerina", name = "log"}, 252 | {org = "ballerina", name = "time"}, 253 | {org = "ballerina", name = "url"} 254 | ] 255 | 256 | [[package]] 257 | org = "ballerina" 258 | name = "observe" 259 | version = "1.2.2" 260 | dependencies = [ 261 | {org = "ballerina", name = "jballerina.java"} 262 | ] 263 | 264 | [[package]] 265 | org = "ballerina" 266 | name = "os" 267 | version = "1.8.0" 268 | dependencies = [ 269 | {org = "ballerina", name = "io"}, 270 | {org = "ballerina", name = "jballerina.java"} 271 | ] 272 | modules = [ 273 | {org = "ballerina", packageName = "os", moduleName = "os"} 274 | ] 275 | 276 | [[package]] 277 | org = "ballerina" 278 | name = "random" 279 | version = "1.5.0" 280 | scope = "testOnly" 281 | dependencies = [ 282 | {org = "ballerina", name = "jballerina.java"}, 283 | {org = "ballerina", name = "time"} 284 | ] 285 | modules = [ 286 | {org = "ballerina", packageName = "random", moduleName = "random"} 287 | ] 288 | 289 | [[package]] 290 | org = "ballerina" 291 | name = "task" 292 | version = "2.5.0" 293 | dependencies = [ 294 | {org = "ballerina", name = "jballerina.java"}, 295 | {org = "ballerina", name = "time"} 296 | ] 297 | 298 | [[package]] 299 | org = "ballerina" 300 | name = "test" 301 | version = "0.0.0" 302 | scope = "testOnly" 303 | dependencies = [ 304 | {org = "ballerina", name = "jballerina.java"}, 305 | {org = "ballerina", name = "lang.error"} 306 | ] 307 | modules = [ 308 | {org = "ballerina", packageName = "test", moduleName = "test"} 309 | ] 310 | 311 | [[package]] 312 | org = "ballerina" 313 | name = "time" 314 | version = "2.4.0" 315 | dependencies = [ 316 | {org = "ballerina", name = "jballerina.java"} 317 | ] 318 | modules = [ 319 | {org = "ballerina", packageName = "time", moduleName = "time"} 320 | ] 321 | 322 | [[package]] 323 | org = "ballerina" 324 | name = "url" 325 | version = "2.4.0" 326 | dependencies = [ 327 | {org = "ballerina", name = "jballerina.java"} 328 | ] 329 | modules = [ 330 | {org = "ballerina", packageName = "url", moduleName = "url"} 331 | ] 332 | 333 | [[package]] 334 | org = "ballerinai" 335 | name = "observe" 336 | version = "0.0.0" 337 | dependencies = [ 338 | {org = "ballerina", name = "jballerina.java"}, 339 | {org = "ballerina", name = "observe"} 340 | ] 341 | modules = [ 342 | {org = "ballerinai", packageName = "observe", moduleName = "observe"} 343 | ] 344 | 345 | [[package]] 346 | org = "ballerinax" 347 | name = "aws.dynamodb" 348 | version = "2.4.0" 349 | dependencies = [ 350 | {org = "ballerina", name = "crypto"}, 351 | {org = "ballerina", name = "http"}, 352 | {org = "ballerina", name = "io"}, 353 | {org = "ballerina", name = "jballerina.java"}, 354 | {org = "ballerina", name = "lang.array"}, 355 | {org = "ballerina", name = "lang.runtime"}, 356 | {org = "ballerina", name = "log"}, 357 | {org = "ballerina", name = "os"}, 358 | {org = "ballerina", name = "random"}, 359 | {org = "ballerina", name = "test"}, 360 | {org = "ballerina", name = "time"}, 361 | {org = "ballerina", name = "url"}, 362 | {org = "ballerinai", name = "observe"}, 363 | {org = "ballerinax", name = "client.config"} 364 | ] 365 | modules = [ 366 | {org = "ballerinax", packageName = "aws.dynamodb", moduleName = "aws.dynamodb"} 367 | ] 368 | 369 | [[package]] 370 | org = "ballerinax" 371 | name = "client.config" 372 | version = "1.0.1" 373 | dependencies = [ 374 | {org = "ballerina", name = "http"}, 375 | {org = "ballerina", name = "oauth2"} 376 | ] 377 | modules = [ 378 | {org = "ballerinax", packageName = "client.config", moduleName = "client.config"} 379 | ] 380 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /docs/spec/spec.md: -------------------------------------------------------------------------------- 1 | # Specification: Ballerina DynamoDB Library 2 | 3 | _Authors_: @bhashinee 4 | _Reviewers_: @daneshk 5 | _Created_: 2023/11/09 6 | _Updated_: 2022/11/10 7 | _Edition_: Swan Lake 8 | 9 | ## Introduction 10 | 11 | This is the specification for the DynamoDB connector of [Ballerina language](https://ballerina.io/), which allows you to access the Amazon DynamoDB REST API. 12 | 13 | The DynamoDB connector specification has evolved and may continue to evolve in the future. The released versions of the specification can be found under the relevant GitHub tag. 14 | 15 | If you have any feedback or suggestions about the library, start a discussion via a [GitHub issue](https://github.com/ballerina-platform/ballerina-standard-library/issues) or in the [Discord server](https://discord.gg/ballerinalang). Based on the outcome of the discussion, the specification and implementation can be updated. Community feedback is always welcome. Any accepted proposal, which affects the specification is stored under `/docs/proposals`. Proposals under discussion can be found with the label `type/proposal` in GitHub. 16 | 17 | The conforming implementation of the specification is released and included in the distribution. Any deviation from the specification is considered a bug. 18 | 19 | ## Contents 20 | 1. [Overview](#1-overview) 21 | 2. [Client](#2-client) 22 | 1. [Client Configurations](#21-client-configurations) 23 | 2. [Initialization](#22-initialization) 24 | 3. [APIs](#23-apis) 25 | 1. [createTable](#createTable) 26 | 2. [deleteTable](#deleteTable) 27 | 3. [describeTable](#describeTable) 28 | 4. [listTables](#listTables) 29 | 5. [updateTable](#updateTable) 30 | 6. [createItem](#createItem) 31 | 7. [getItem](#getItem) 32 | 8. [deleteItem](#deleteItem) 33 | 9. [updateItem](#updateItem) 34 | 10. [query](#query) 35 | 11. [scan](#scan) 36 | 12. [getBatchItems](#getBatchItems) 37 | 13. [writeBatchItems](#writeBatchItems) 38 | 14. [describeLimits](#describeLimits) 39 | 15. [createBackup](#createBackup) 40 | 16. [deleteBackup](#deleteBackup) 41 | 17. [getTTL](#getTTL) 42 | 43 | ## 1. [Overview](#1-overview) 44 | 45 | The Ballerina `dynamodb` library facilitates APIs to allow you to access the Amazon DynamoDB REST API. Amazon DynamoDB is a fully managed NoSQL database service that provides fast and predictable performance with seamless scalability. Amazon DynamoDB enables customers to offload the administrative burdens of operating and scaling distributed databases to AWS, so they do not have to worry about hardware provisioning, setup and configuration, replication, software patching, or cluster scaling. 46 | 47 | ## 2. [Client](#2-client) 48 | 49 | `dynamodb:Client` can be used to access the Amazon DynamoDB REST API. 50 | 51 | ### 2.1. [Client Configurations](#21-client-configurations) 52 | 53 | When initializing the client, following configurations can be provided, 54 | 55 | ```ballerina 56 | public type ConnectionConfig record {| 57 | *config:ConnectionConfig; 58 | never auth?; 59 | # AWS credentials 60 | AwsCredentials|AwsTemporaryCredentials awsCredentials; 61 | # AWS Region 62 | string region; 63 | |}; 64 | ``` 65 | 66 | ### 2.2. [Initialization](#22-initialization) 67 | 68 | A client can be initialized by providing the AwsCredentials and optionally the other configurations in `ClientConfiguration`. 69 | 70 | ```ballerina 71 | ConnectionConfig config = { 72 | awsCredentials: {accessKeyId: "ACCESS_KEY_ID", secretAccessKey: "SECRET_ACCESS_KEY"}, 73 | region: "ap-south-1" 74 | }; 75 | 76 | Client dynamoDBClient = check new (config); 77 | ``` 78 | 79 | ### 2.3 [APIs](#23-apis) 80 | 81 | #### [createTable](#createTable) 82 | 83 | This API can be used to create a new table in DynamoDB with the specified parameters. 84 | 85 | ```ballerina 86 | # Creates a table. The CreateTable operation adds a new table to your account. In an AWS account, table names must be 87 | # unique within each Region. That is, you can have two tables with same name if you create the tables in different 88 | # Regions. 89 | # 90 | # + tableCreationInput - The request payload to create a table 91 | # + return - If success, dynamodb:TableDescription record, else an error 92 | remote isolated function createTable(TableCreateInput tableCreationInput) returns TableDescription|error { 93 | ``` 94 | 95 | #### [deleteTable](#deleteTable) 96 | 97 | This API can be used to delete a table in DynamoDB with the given table name. 98 | 99 | ```ballerina 100 | # Deletes a table. 101 | # 102 | # + tableName - The name of the table to delete 103 | # + return - If success, dynamodb:TableDescription record, else an error 104 | remote isolated function deleteTable(string tableName) returns TableDescription|error { 105 | ``` 106 | 107 | #### [describeTable](#describeTable) 108 | 109 | This API can be used to get the table details in DynamoDB with the given table name. 110 | 111 | ```ballerina 112 | # Describes a table. 113 | # 114 | # + tableName - The name of the table to delete 115 | # + return - If success, dynamodb:TableDescription record, else an error 116 | remote isolated function describeTable(string tableName) returns TableDescription|error { 117 | ``` 118 | 119 | #### [listTables](#listTables) 120 | 121 | This API can be used to list all the tables relavant to your account. 122 | 123 | ```ballerina 124 | # Lists all tables. 125 | # 126 | # + return - If success, stream, else an error 127 | remote isolated function listTables() returns stream|error { 128 | ``` 129 | 130 | #### [updateTable](#updateTable) 131 | 132 | This API can be used to update the entries in the table with the specified parameters. 133 | 134 | ```ballerina 135 | # Updates a table. 136 | # 137 | # + tableUpdateInput - The request payload to update a table 138 | # + return - If success, dynamodb:TableDescription record, else an error 139 | remote isolated function updateTable(TableUpdateInput tableUpdateInput) returns TableDescription|error { 140 | ``` 141 | 142 | #### [createItem](#createItem) 143 | 144 | This API can be used to add a new item to the table. 145 | 146 | ```ballerina 147 | # Creates a new item, or replaces an old item with a new item. If an item that has the same primary key as the new 148 | # item already exists in the specified table, the new item completely replaces the existing item. You can perform a 149 | # conditional put operation (add a new item if one with the specified primary key doesn't exist), or replace an 150 | # existing item if it has certain attribute values. 151 | # 152 | # + itemCreateInput - The request payload to create an item 153 | # + return - If success, dynamodb:ItemDescription record, else an error 154 | remote isolated function createItem(ItemCreateInput itemCreateInput) returns ItemDescription|error { 155 | ``` 156 | 157 | #### [getItem](#getItem) 158 | 159 | This API can be used to get a specific item from the table. 160 | 161 | ```ballerina 162 | # Gets an item. 163 | # 164 | # + itemGetInput - The request payload to get an item 165 | # + return - If success, dynamodb:GetItemOutput record, else an error 166 | remote isolated function getItem(ItemGetInput itemGetInput) returns ItemGetOutput|error { 167 | ``` 168 | 169 | #### [deleteItem](#deleteItem) 170 | 171 | This API can be used to delete a specific item from the table. 172 | 173 | ```ballerina 174 | # Deletes an item. 175 | # 176 | # + itemDeleteInput - The request payload to delete an item 177 | # + return - If success, dynamodb:ItemDescription record, else an error 178 | remote isolated function deleteItem(ItemDeleteInput itemDeleteInput) returns ItemDescription|error { 179 | ``` 180 | 181 | #### [updateItem](#updateItem) 182 | 183 | This API can be used to update a specific item from the table. 184 | 185 | ```ballerina 186 | # Updates an item 187 | # 188 | # + itemUpdateInput - The request payload to update an item 189 | # + return - If success, dynamodb:ItemDescription record, else an error 190 | remote isolated function updateItem(ItemUpdateInput itemUpdateInput) returns ItemDescription|error { 191 | ``` 192 | 193 | #### [query](#query) 194 | 195 | This API can be used retrieve items from a table that match specific criteria. 196 | 197 | ```ballerina 198 | # Returns all items with a particular partition key value. You must provide the name of the partition key attribute 199 | # and a single value for that attribute. Optionally, you can provide a sort key attribute and use a comparison 200 | # operator to refine the search results. 201 | # 202 | # + queryInput - The request payload to query 203 | # + return - If success, stream, else an error 204 | remote isolated function query(QueryInput queryInput) returns stream|error { 205 | ``` 206 | 207 | #### [scan](#scan) 208 | 209 | This API can be used to read all the items in a table and return them as a result set. 210 | 211 | ```ballerina 212 | # Returns one or more items and item attributes by accessing every item in a table or a secondary index. 213 | # 214 | # + scanInput - The request payload to scan 215 | # + return - If success, stream, else an error 216 | remote isolated function scan(ScanInput scanInput) returns stream|error { 217 | ``` 218 | 219 | #### [getBatchItems](#getBatchItems) 220 | 221 | This API can be used to retrieve multiple items from one or more tables in a single request. This operation is designed for efficiency and allows you to request items from multiple tables or multiple items from a single table using a single API call. 222 | 223 | ```ballerina 224 | # Returns the attributes of one or more items from one or more tables. You identify requested items by primary key. 225 | # 226 | # + batchItemGetInput - The request payload to get items as batch 227 | # + return - If success, stream, else an error 228 | remote isolated function getBatchItems(BatchItemGetInput batchItemGetInput) returns stream|error { 229 | ``` 230 | 231 | #### [writeBatchItems](#writeBatchItems) 232 | 233 | This API can be used to perform multiple write operations (PutItem, UpdateItem, DeleteItem) across one or more tables in a single request. This operation is designed for efficiency and allows you to execute multiple write operations with a single API call. 234 | 235 | ```ballerina 236 | # Puts or deletes multiple items in one or more tables. 237 | # 238 | # + batchItemInsertInput - The request payload to write items as batch 239 | # + return - If success, dynamodb:BatchItemInsertOutput record, else an error 240 | remote isolated function writeBatchItems(BatchItemInsertInput batchItemInsertInput) returns BatchItemInsertOutput|error { 241 | ``` 242 | 243 | #### [describeLimits](#describeLimits) 244 | 245 | This API can be used to get information about the current account limits and usage for certain operations in Amazon DynamoDB. 246 | 247 | ```ballerina 248 | # Returns the current provisioned-capacity quotas for your AWS account in a Region, both for the Region as a whole 249 | # and for any one DynamoDB table that you create there. 250 | # 251 | # + return - If success, dynamodb:LimitDescription record, else an error 252 | remote isolated function describeLimits() returns LimitDescription|error { 253 | ``` 254 | 255 | #### [createBackup](#createBackup) 256 | 257 | This API can be used to manually create a backup for a table. 258 | 259 | ```ballerina 260 | # Creates a back up from the given table 261 | # 262 | # + backupCreateInput - The request payload to backup the table 263 | # + return - If success, dynamodb:BackupDetails record, else an error 264 | remote isolated function createBackup(BackupCreateInput backupCreateInput) returns BackupDetails|error { 265 | ``` 266 | 267 | #### [deleteBackup](#deleteBackup) 268 | 269 | This API can be used to delete a backup of a table. 270 | 271 | ```ballerina 272 | # Deletes an existing backup of a table. 273 | # 274 | # + backupArn - The backupArn of the table that needs to be deleted 275 | # + return - If success, dynamodb:BackupDescription record, else an error 276 | remote isolated function deleteBackup(string backupArn) returns BackupDescription|error { 277 | ``` 278 | 279 | #### [getTTL](#getTTL) 280 | 281 | This API can be used to get the Time to Live status of a table. 282 | 283 | ```ballerina 284 | # The description of the Time to Live (TTL) status on the specified table. 285 | # 286 | # + tableName - Table name 287 | # + return - If success, dynamodb:TTLDescription record, else an error 288 | remote isolated function getTTL(string tableName) returns TTLDescription|error { 289 | ``` 290 | -------------------------------------------------------------------------------- /ballerina/stream_implementor.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/http; 18 | 19 | class TableStream { 20 | private string[] currentEntries = []; 21 | private int index = 0; 22 | private final http:Client httpClient; 23 | private final string accessKeyId; 24 | private final string secretAccessKey; 25 | private final string region; 26 | private final string awsHost; 27 | private final string uri = SLASH; 28 | private string? exclusiveStartTableName; 29 | 30 | isolated function init(http:Client httpClient, string host, string accessKey, string secretKey, string region) 31 | returns error? { 32 | self.httpClient = httpClient; 33 | self.accessKeyId = accessKey; 34 | self.secretAccessKey = secretKey; 35 | self.region = region; 36 | self.awsHost = AWS_SERVICE + DOT + self.region + DOT + AWS_HOST; 37 | self.exclusiveStartTableName = null; 38 | self.currentEntries = check self.fetchTableNames(); 39 | } 40 | 41 | public isolated function next() returns record {|string value;|}|error? { 42 | if self.index < self.currentEntries.length() { 43 | record {|string value;|} tableName = {value: self.currentEntries[self.index]}; 44 | self.index += 1; 45 | return tableName; 46 | } 47 | if self.exclusiveStartTableName is string { 48 | self.index = 0; 49 | self.currentEntries = check self.fetchTableNames(); 50 | record {|string value;|} tableName = {value: self.currentEntries[self.index]}; 51 | self.index += 1; 52 | return tableName; 53 | } 54 | return (); 55 | } 56 | 57 | isolated function fetchTableNames() returns string[]|error { 58 | string target = VERSION + DOT + "ListTables"; 59 | TableListRequest request = { 60 | ExclusiveStartTableName: self.exclusiveStartTableName 61 | }; 62 | json payload = check request.cloneWithType(json); 63 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 64 | self.secretAccessKey, self.region, 65 | POST, self.uri, target, payload); 66 | json response = check self.httpClient->post(self.uri, payload, signedRequestHeaders); 67 | TableList tableListResp = check response.cloneWithType(TableList); 68 | self.exclusiveStartTableName = tableListResp?.LastEvaluatedTableName; 69 | string[]? tableList = tableListResp?.TableNames; 70 | if tableList is string[] { 71 | return tableList; 72 | } 73 | return []; 74 | } 75 | } 76 | 77 | class ScanStream { 78 | private ScanOutput[] currentEntries = []; 79 | private int index = 0; 80 | private final http:Client httpClient; 81 | private final string accessKeyId; 82 | private final string secretAccessKey; 83 | private final string region; 84 | private final string awsHost; 85 | private final string uri = SLASH; 86 | private ScanInput scanRequest; 87 | 88 | isolated function init(http:Client httpClient, string host, string accessKey, string secretKey, string region, 89 | ScanInput scanRequest) returns error? { 90 | self.httpClient = httpClient; 91 | self.accessKeyId = accessKey; 92 | self.secretAccessKey = secretKey; 93 | self.region = region; 94 | self.awsHost = AWS_SERVICE + DOT + self.region + DOT + AWS_HOST; 95 | self.scanRequest = scanRequest; 96 | self.currentEntries = check self.fetchScan(); 97 | } 98 | 99 | public isolated function next() returns record {|ScanOutput value;|}|error? { 100 | if self.index < self.currentEntries.length() { 101 | record {|ScanOutput value;|} response = {value: self.currentEntries[self.index]}; 102 | self.index += 1; 103 | return response; 104 | } 105 | if self.scanRequest?.ExclusiveStartKey is map { 106 | self.index = 0; 107 | self.currentEntries = check self.fetchScan(); 108 | if self.index < self.currentEntries.length() { 109 | record {|ScanOutput value;|} response = {value: self.currentEntries[self.index]}; 110 | self.index += 1; 111 | return response; 112 | } 113 | } 114 | return (); 115 | } 116 | 117 | isolated function fetchScan() returns ScanOutput[]|error { 118 | string target = VERSION + DOT + "Scan"; 119 | json payload = check self.scanRequest.cloneWithType(json); 120 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 121 | self.secretAccessKey, self.region, 122 | POST, self.uri, target, payload); 123 | json jsonResponse = check self.httpClient->post(self.uri, payload, signedRequestHeaders); 124 | QueryOrScanOutput response = check jsonResponse.cloneWithType(QueryOrScanOutput); 125 | self.scanRequest.ExclusiveStartKey = response?.LastEvaluatedKey; 126 | map[]? items = response?.Items; 127 | if items is map[] { 128 | ScanOutput[] scanResponseArr = []; 129 | foreach map item in items { 130 | ScanOutput scanResponse = { 131 | ConsumedCapacity: response?.ConsumedCapacity, 132 | Item: item 133 | }; 134 | scanResponseArr.push(scanResponse); 135 | } 136 | return scanResponseArr; 137 | } else { 138 | return []; 139 | } 140 | } 141 | } 142 | 143 | class QueryStream { 144 | private QueryOutput[] currentEntries = []; 145 | private int index = 0; 146 | private final http:Client httpClient; 147 | private final string accessKeyId; 148 | private final string secretAccessKey; 149 | private final string region; 150 | private final string awsHost; 151 | private final string uri = SLASH; 152 | private QueryInput queryRequest; 153 | 154 | isolated function init(http:Client httpClient, string host, string accessKey, string secretKey, string region, 155 | QueryInput queryRequest) returns error? { 156 | self.httpClient = httpClient; 157 | self.accessKeyId = accessKey; 158 | self.secretAccessKey = secretKey; 159 | self.region = region; 160 | self.awsHost = AWS_SERVICE + DOT + self.region + DOT + AWS_HOST; 161 | self.queryRequest = queryRequest; 162 | self.currentEntries = check self.fetchQuery(); 163 | } 164 | 165 | public isolated function next() returns record {|QueryOutput value;|}|error? { 166 | if self.index < self.currentEntries.length() { 167 | record {|QueryOutput value;|} response = {value: self.currentEntries[self.index]}; 168 | self.index += 1; 169 | return response; 170 | } 171 | if self.queryRequest?.ExclusiveStartKey is map { 172 | self.index = 0; 173 | self.currentEntries = check self.fetchQuery(); 174 | if self.index < self.currentEntries.length() { 175 | record {|QueryOutput value;|} response = {value: self.currentEntries[self.index]}; 176 | self.index += 1; 177 | return response; 178 | } 179 | } 180 | return (); 181 | } 182 | 183 | isolated function fetchQuery() returns QueryOutput[]|error { 184 | string target = VERSION + DOT + "Query"; 185 | json payload = check self.queryRequest.cloneWithType(json); 186 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 187 | self.secretAccessKey, self.region, 188 | POST, self.uri, target, payload); 189 | json jsonResponse = check self.httpClient->post(self.uri, payload, signedRequestHeaders); 190 | QueryOrScanOutput response = check jsonResponse.cloneWithType(QueryOrScanOutput); 191 | self.queryRequest.ExclusiveStartKey = response?.LastEvaluatedKey; 192 | map[]? items = response?.Items; 193 | if items is map[] { 194 | QueryOutput[] queryResponseArr = []; 195 | foreach map item in items { 196 | QueryOutput queryResponse = { 197 | ConsumedCapacity: response?.ConsumedCapacity, 198 | Item: item 199 | }; 200 | queryResponseArr.push(queryResponse); 201 | } 202 | return queryResponseArr; 203 | } else { 204 | return []; 205 | } 206 | } 207 | } 208 | 209 | class ItemsBatchGetStream { 210 | private BatchItem[] currentEntries = []; 211 | private int index = 0; 212 | private final http:Client httpClient; 213 | private final string accessKeyId; 214 | private final string secretAccessKey; 215 | private final string region; 216 | private final string awsHost; 217 | private final string uri = SLASH; 218 | private BatchItemGetInput itemsBatchGetRequest; 219 | 220 | isolated function init(http:Client httpClient, string host, string accessKey, string secretKey, string region, 221 | BatchItemGetInput itemsBatchGetRequest) returns error? { 222 | self.httpClient = httpClient; 223 | self.accessKeyId = accessKey; 224 | self.secretAccessKey = secretKey; 225 | self.region = region; 226 | self.awsHost = AWS_SERVICE + DOT + self.region + DOT + AWS_HOST; 227 | self.itemsBatchGetRequest = itemsBatchGetRequest; 228 | self.currentEntries = check self.fetchBatchItems(); 229 | } 230 | 231 | public isolated function next() returns record {|BatchItem value;|}|error? { 232 | if self.index < self.currentEntries.length() { 233 | record {|BatchItem value;|} response = {value: self.currentEntries[self.index]}; 234 | self.index += 1; 235 | return response; 236 | } 237 | if self.itemsBatchGetRequest.RequestItems.keys().length() != 0 { 238 | self.index = 0; 239 | self.currentEntries = check self.fetchBatchItems(); 240 | if self.index < self.currentEntries.length() { 241 | record {|BatchItem value;|} response = {value: self.currentEntries[self.index]}; 242 | self.index += 1; 243 | return response; 244 | } 245 | } 246 | return (); 247 | } 248 | 249 | isolated function fetchBatchItems() returns BatchItem[]|error { 250 | string target = VERSION + DOT + "BatchGetItem"; 251 | json payload = check self.itemsBatchGetRequest.cloneWithType(json); 252 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 253 | self.secretAccessKey, self.region, 254 | POST, self.uri, target, payload); 255 | json jsonResponse = check self.httpClient->post(self.uri, payload, signedRequestHeaders); 256 | BatchGetItemsOutput response = check jsonResponse.cloneWithType(BatchGetItemsOutput); 257 | 258 | self.itemsBatchGetRequest.RequestItems = self.getRequestItemsToNextBatch(response); 259 | map[]>?? batchResponses = response?.Responses; 260 | ConsumedCapacity[]?? consumedCapacities = response?.ConsumedCapacity; 261 | map consumedCapacityMap = {}; 262 | if consumedCapacities is ConsumedCapacity[] { 263 | foreach ConsumedCapacity consumedCapacity in consumedCapacities { 264 | consumedCapacityMap[consumedCapacity?.TableName.toString()] = consumedCapacity; 265 | } 266 | } 267 | if batchResponses is map[]> { 268 | BatchItem[] itemResponseArr = []; 269 | string[] keys = batchResponses.keys(); 270 | foreach string keyName in keys { 271 | map[] items = batchResponses.get(keyName); 272 | ConsumedCapacity? consumedCapacity = consumedCapacityMap.hasKey(keyName) ? 273 | consumedCapacityMap.get(keyName) : (); 274 | foreach map item in items { 275 | BatchItem itemResponse = { 276 | ConsumedCapacity: consumedCapacity, 277 | TableName: keyName, 278 | Item: item 279 | }; 280 | itemResponseArr.push(itemResponse); 281 | } 282 | } 283 | return itemResponseArr; 284 | } else { 285 | return []; 286 | } 287 | } 288 | // Get RequestItem to construct request payload for the next batch 289 | private isolated function getRequestItemsToNextBatch(BatchGetItemsOutput itemsBatchGetResponse) 290 | returns map { 291 | map?? unprocessedKeys = itemsBatchGetResponse?.UnprocessedKeys; 292 | return (unprocessedKeys is map && unprocessedKeys !== {}) ? 293 | >unprocessedKeys : {}; 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /ballerina/client.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/http; 18 | import ballerinax/'client.config; 19 | 20 | # The Ballerina AWS DynamoDB connector provides the capability to access AWS Simple Email Service related operations. 21 | # This connector lets you to to send email messages to your customers. 22 | # 23 | @display {label: "Amazon DynamoDB", iconPath: "icon.png"} 24 | public isolated client class Client { 25 | private final http:Client awsDynamoDb; 26 | private final string accessKeyId; 27 | private final string secretAccessKey; 28 | private final string? securityToken; 29 | private final string region; 30 | private final string awsHost; 31 | private final string uri = SLASH; 32 | 33 | # Initializes the connector. During initialization you have to pass access key id, secret access key, and region. 34 | # Create an AWS account and obtain tokens following 35 | # [this guide](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html). 36 | # 37 | # + awsDynamoDBConfig - Configuration required to initialize the client 38 | # + httpConfig - HTTP configuration 39 | # + return - An error on failure of initialization or else `()` 40 | public isolated function init(ConnectionConfig config) returns error? { 41 | self.accessKeyId = config.awsCredentials.accessKeyId; 42 | self.secretAccessKey = config.awsCredentials.secretAccessKey; 43 | self.securityToken = config.awsCredentials?.securityToken; 44 | self.region = config.region; 45 | self.awsHost = AWS_SERVICE + DOT + self.region + DOT + AWS_HOST; 46 | string endpoint = HTTPS + self.awsHost; 47 | 48 | http:ClientConfiguration httpClientConfig = check config:constructHTTPClientConfig(config); 49 | self.awsDynamoDb = check new (endpoint, httpClientConfig); 50 | } 51 | 52 | # Creates a table. The CreateTable operation adds a new table to your account. In an AWS account, table names must be 53 | # unique within each Region. That is, you can have two tables with same name if you create the tables in different 54 | # Regions. 55 | # 56 | # + tableCreationInput - The request payload to create a table 57 | # + return - If success, dynamodb:TableDescription record, else an error 58 | remote isolated function createTable(TableCreateInput tableCreationInput) returns TableDescription|error { 59 | string target = VERSION + DOT + "CreateTable"; 60 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 61 | self.secretAccessKey, self.region, 62 | POST, self.uri, target, tableCreationInput.toJson()); 63 | map response = check self.awsDynamoDb->post(self.uri, tableCreationInput, signedRequestHeaders); 64 | json tableDescription = check response.TableDescription; 65 | return tableDescription.fromJsonWithType(); 66 | } 67 | 68 | # Deletes a table. 69 | # 70 | # + tableName - The name of the table to delete 71 | # + return - If success, dynamodb:TableDescription record, else an error 72 | remote isolated function deleteTable(string tableName) returns TableDescription|error { 73 | string target = VERSION + DOT + "DeleteTable"; 74 | json payload = { 75 | "TableName": tableName 76 | }; 77 | 78 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 79 | self.secretAccessKey, self.region, 80 | POST, self.uri, target, payload); 81 | json response = check self.awsDynamoDb->post(self.uri, payload, signedRequestHeaders); 82 | json tableDescription = check response.TableDescription; 83 | return tableDescription.fromJsonWithType(); 84 | } 85 | 86 | # Describes a table. 87 | # 88 | # + tableName - The name of the table to delete 89 | # + return - If success, dynamodb:TableDescription record, else an error 90 | remote isolated function describeTable(string tableName) returns TableDescription|error { 91 | string target = VERSION + DOT + "DescribeTable"; 92 | json payload = { 93 | "TableName": tableName 94 | }; 95 | 96 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 97 | self.secretAccessKey, self.region, 98 | POST, self.uri, target, payload); 99 | json response = check self.awsDynamoDb->post(self.uri, payload, signedRequestHeaders); 100 | json 'table = check response.Table; 101 | return 'table.fromJsonWithType(); 102 | } 103 | 104 | # Lists all tables. 105 | # 106 | # + return - If success, stream, else an error 107 | remote isolated function listTables() returns stream|error { 108 | TableStream tableStream = check new TableStream(self.awsDynamoDb, self.awsHost, self.accessKeyId, 109 | self.secretAccessKey, self.region 110 | ); 111 | return new stream(tableStream); 112 | } 113 | 114 | # Updates a table. 115 | # 116 | # + tableUpdateInput - The request payload to update a table 117 | # + return - If success, dynamodb:TableDescription record, else an error 118 | remote isolated function updateTable(TableUpdateInput tableUpdateInput) returns TableDescription|error { 119 | string target = VERSION + DOT + "UpdateTable"; 120 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 121 | self.secretAccessKey, self.region, 122 | POST, self.uri, target, tableUpdateInput.toJson()); 123 | json response = check self.awsDynamoDb->post(self.uri, tableUpdateInput, signedRequestHeaders); 124 | json tableDescription = check response.TableDescription; 125 | return tableDescription.fromJsonWithType(); 126 | } 127 | 128 | # Creates a new item, or replaces an old item with a new item. If an item that has the same primary key as the new 129 | # item already exists in the specified table, the new item completely replaces the existing item. You can perform a 130 | # conditional put operation (add a new item if one with the specified primary key doesn't exist), or replace an 131 | # existing item if it has certain attribute values. 132 | # 133 | # + itemCreateInput - The request payload to create an item 134 | # + return - If success, dynamodb:ItemDescription record, else an error 135 | remote isolated function createItem(ItemCreateInput itemCreateInput) returns ItemDescription|error { 136 | string target = VERSION + DOT + "PutItem"; 137 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 138 | self.secretAccessKey, self.region, 139 | POST, self.uri, target, itemCreateInput.toJson()); 140 | json response = check self.awsDynamoDb->post(self.uri, itemCreateInput, signedRequestHeaders); 141 | return response.fromJsonWithType(); 142 | } 143 | 144 | # Gets an item. 145 | # 146 | # + itemGetInput - The request payload to get an item 147 | # + return - If success, dynamodb:GetItemOutput record, else an error 148 | remote isolated function getItem(ItemGetInput itemGetInput) returns ItemGetOutput|error { 149 | string target = VERSION + DOT + "GetItem"; 150 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 151 | self.secretAccessKey, self.region, 152 | POST, self.uri, target, itemGetInput.toJson()); 153 | json response = check self.awsDynamoDb->post(self.uri, itemGetInput, signedRequestHeaders); 154 | return response.fromJsonWithType(); 155 | } 156 | 157 | # Deletes an item. 158 | # 159 | # + itemDeleteInput - The request payload to delete an item 160 | # + return - If success, dynamodb:ItemDescription record, else an error 161 | remote isolated function deleteItem(ItemDeleteInput itemDeleteInput) returns ItemDescription|error { 162 | string target = VERSION + DOT + "DeleteItem"; 163 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 164 | self.secretAccessKey, self.region, 165 | POST, self.uri, target, itemDeleteInput.toJson()); 166 | ItemDescription response = check self.awsDynamoDb->post(self.uri, itemDeleteInput, signedRequestHeaders); 167 | return response; 168 | } 169 | 170 | # Updates an item 171 | # 172 | # + itemUpdateInput - The request payload to update an item 173 | # + return - If success, dynamodb:ItemDescription record, else an error 174 | remote isolated function updateItem(ItemUpdateInput itemUpdateInput) returns ItemDescription|error { 175 | string target = VERSION + DOT + "UpdateItem"; 176 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 177 | self.secretAccessKey, self.region, 178 | POST, self.uri, target, itemUpdateInput.toJson()); 179 | json response = check self.awsDynamoDb->post(self.uri, itemUpdateInput, signedRequestHeaders); 180 | return response.fromJsonWithType(); 181 | } 182 | 183 | # Returns all items with a particular partition key value. You must provide the name of the partition key attribute 184 | # and a single value for that attribute. Optionally, you can provide a sort key attribute and use a comparison 185 | # operator to refine the search results. 186 | # 187 | # + queryInput - The request payload to query 188 | # + return - If success, stream, else an error 189 | remote isolated function query(QueryInput queryInput) returns stream|error { 190 | 191 | QueryStream queryStream = check new QueryStream(self.awsDynamoDb, self.awsHost, self.accessKeyId, 192 | self.secretAccessKey, self.region, queryInput 193 | ); 194 | return new stream(queryStream); 195 | } 196 | 197 | # Returns one or more items and item attributes by accessing every item in a table or a secondary index. 198 | # 199 | # + scanInput - The request payload to scan 200 | # + return - If success, stream, else an error 201 | remote isolated function scan(ScanInput scanInput) returns stream|error { 202 | 203 | ScanStream scanStream = check new ScanStream(self.awsDynamoDb, self.awsHost, self.accessKeyId, 204 | self.secretAccessKey, self.region, scanInput 205 | ); 206 | return new stream(scanStream); 207 | } 208 | 209 | # Returns the attributes of one or more items from one or more tables. You identify requested items by primary key. 210 | # 211 | # + batchItemGetInput - The request payload to get items as batch 212 | # + return - If success, stream, else an error 213 | remote isolated function getBatchItems(BatchItemGetInput batchItemGetInput) returns stream|error { 214 | ItemsBatchGetStream itemsBatchGetStream = check new ItemsBatchGetStream(self.awsDynamoDb, self.awsHost, 215 | self.accessKeyId, self.secretAccessKey, 216 | self.region, batchItemGetInput 217 | ); 218 | return new stream(itemsBatchGetStream); 219 | } 220 | 221 | # Puts or deletes multiple items in one or more tables. 222 | # 223 | # + batchItemInsertInput - The request payload to write items as batch 224 | # + return - If success, dynamodb:BatchItemInsertOutput record, else an error 225 | remote isolated function writeBatchItems(BatchItemInsertInput batchItemInsertInput) returns BatchItemInsertOutput|error { 226 | string target = VERSION + DOT + "BatchWriteItem"; 227 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 228 | self.secretAccessKey, self.region, 229 | POST, self.uri, target, batchItemInsertInput.toJson()); 230 | json response = check self.awsDynamoDb->post(self.uri, batchItemInsertInput, signedRequestHeaders); 231 | return response.fromJsonWithType(); 232 | } 233 | 234 | # Returns the current provisioned-capacity quotas for your AWS account in a Region, both for the Region as a whole 235 | # and for any one DynamoDB table that you create there. 236 | # 237 | # + return - If success, dynamodb:LimitDescription record, else an error 238 | remote isolated function describeLimits() returns LimitDescription|error { 239 | string target = VERSION + DOT + "DescribeLimits"; 240 | json payload = {}; 241 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 242 | self.secretAccessKey, self.region, 243 | POST, self.uri, target, payload); 244 | json response = check self.awsDynamoDb->post(self.uri, payload, signedRequestHeaders); 245 | return response.fromJsonWithType(); 246 | } 247 | 248 | # Creates a back up from the given table 249 | # 250 | # + backupCreateInput - The request payload to backup the table 251 | # + return - If success, dynamodb:BackupDetails record, else an error 252 | remote isolated function createBackup(BackupCreateInput backupCreateInput) returns BackupDetails|error { 253 | string target = VERSION + DOT + "CreateBackup"; 254 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 255 | self.secretAccessKey, self.region, 256 | POST, self.uri, target, backupCreateInput); 257 | json response = check self.awsDynamoDb->post(self.uri, backupCreateInput, signedRequestHeaders); 258 | json backUpDetails = check response.BackupDetails; 259 | return backUpDetails.fromJsonWithType(); 260 | } 261 | 262 | # Deletes an existing backup of a table. 263 | # 264 | # + backupArn - The backupArn of the table that needs to be deleted 265 | # + return - If success, dynamodb:BackupDescription record, else an error 266 | remote isolated function deleteBackup(string backupArn) returns BackupDescription|error { 267 | string target = VERSION + DOT + "DeleteBackup"; 268 | json payload = { 269 | "BackupArn": backupArn 270 | }; 271 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 272 | self.secretAccessKey, self.region, 273 | POST, self.uri, target, payload); 274 | json response = check self.awsDynamoDb->post(self.uri, payload, signedRequestHeaders); 275 | json backUpDetails = check response.BackupDescription; 276 | return backUpDetails.fromJsonWithType(); 277 | } 278 | 279 | # The description of the Time to Live (TTL) status on the specified table. 280 | # 281 | # + tableName - Table name 282 | # + return - If success, dynamodb:TTLDescription record, else an error 283 | remote isolated function getTTL(string tableName) returns TTLDescription|error { 284 | string target = VERSION + DOT + "DescribeTimeToLive"; 285 | json payload = { 286 | "TableName": tableName 287 | }; 288 | map signedRequestHeaders = check getSignedRequestHeaders(self.awsHost, self.accessKeyId, 289 | self.secretAccessKey, self.region, 290 | POST, self.uri, target, payload); 291 | json timeToLiveResponse = check self.awsDynamoDb->post(self.uri, payload, signedRequestHeaders); 292 | json timeToLiveDescription = check timeToLiveResponse.TimeToLiveDescription; 293 | return timeToLiveDescription.fromJsonWithType(); 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /ballerina/tests/test.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerina/lang.runtime; 18 | import ballerina/log; 19 | import ballerina/os; 20 | import ballerina/test; 21 | import ballerina/random; 22 | import ballerina/io; 23 | 24 | configurable string accessKeyId = os:getEnv("ACCESS_KEY_ID"); 25 | configurable string secretAccessKey = os:getEnv("SECRET_ACCESS_KEY"); 26 | configurable string region = os:getEnv("REGION"); 27 | 28 | float randomValue = random:createDecimal(); 29 | 30 | final string mainTable = "Thread" + randomValue.toString(); 31 | final string secondaryTable = "SecondaryThread" + randomValue.toString(); 32 | 33 | ConnectionConfig config = { 34 | awsCredentials: {accessKeyId: accessKeyId, secretAccessKey: secretAccessKey}, 35 | region: region 36 | }; 37 | 38 | Client dynamoDBClient = check new (config); 39 | 40 | @test:Config {} 41 | function testCreateTable() returns error? { 42 | TableCreateInput payload = { 43 | AttributeDefinitions: [ 44 | { 45 | AttributeName: "ForumName", 46 | AttributeType: "S" 47 | }, 48 | { 49 | AttributeName: "Subject", 50 | AttributeType: "S" 51 | }, 52 | { 53 | AttributeName: "LastPostDateTime", 54 | AttributeType: "S" 55 | } 56 | ], 57 | TableName: mainTable, 58 | KeySchema: [ 59 | { 60 | AttributeName: "ForumName", 61 | KeyType: HASH 62 | }, 63 | { 64 | AttributeName: "Subject", 65 | KeyType: RANGE 66 | } 67 | ], 68 | LocalSecondaryIndexes: [ 69 | { 70 | IndexName: "LastPostIndex", 71 | KeySchema: [ 72 | { 73 | AttributeName: "ForumName", 74 | KeyType: HASH 75 | }, 76 | { 77 | AttributeName: "LastPostDateTime", 78 | KeyType: RANGE 79 | } 80 | ], 81 | Projection: { 82 | ProjectionType: KEYS_ONLY 83 | } 84 | } 85 | ], 86 | ProvisionedThroughput: { 87 | ReadCapacityUnits: 5, 88 | WriteCapacityUnits: 5 89 | }, 90 | Tags: [ 91 | { 92 | Key: "Owner", 93 | Value: "BlueTeam" 94 | } 95 | ] 96 | }; 97 | TableDescription createTablesResult = check dynamoDBClient->createTable(payload); 98 | test:assertEquals(createTablesResult?.TableName, mainTable, "Thread table is not created."); 99 | test:assertEquals(createTablesResult?.TableStatus, CREATING, "Table is not created."); 100 | payload.TableName = secondaryTable; 101 | createTablesResult = check dynamoDBClient->createTable(payload); 102 | test:assertEquals(createTablesResult?.TableName, secondaryTable, 103 | "SecondaryThread table is not created."); 104 | log:printInfo("Testing CreateTable is completed."); 105 | } 106 | 107 | @test:Config { 108 | dependsOn: [testCreateTable] 109 | } 110 | function testDescribeTable() returns error? { 111 | TableDescription response = check dynamoDBClient->describeTable(mainTable); 112 | test:assertEquals(response?.TableName, mainTable, "Expected table is not described."); 113 | log:printInfo("Testing DescribeTable is completed."); 114 | } 115 | 116 | @test:Config { 117 | dependsOn: [testDescribeTable] 118 | } 119 | function updateTable() returns error? { 120 | _ = check executeWithRetry(testUpdateTable, 20, 3); 121 | } 122 | 123 | function testUpdateTable() returns error? { 124 | TableUpdateInput request = { 125 | TableName: mainTable, 126 | ProvisionedThroughput: { 127 | ReadCapacityUnits: 10, 128 | WriteCapacityUnits: 10 129 | } 130 | }; 131 | TableDescription response = check dynamoDBClient->updateTable(request); 132 | ProvisionedThroughputDescription? provisionedThroughput = response?.ProvisionedThroughput; 133 | if provisionedThroughput !is () { 134 | test:assertEquals(provisionedThroughput?.ReadCapacityUnits, 5, "Read Capacity Units are not updated in table."); 135 | test:assertEquals(provisionedThroughput?.WriteCapacityUnits, 5, "Write Capacity Units are not updated in table."); 136 | } 137 | log:printInfo("Testing UpdateTable is completed."); 138 | } 139 | 140 | @test:Config { 141 | dependsOn: [updateTable] 142 | } 143 | function testListTables() returns error? { 144 | stream response = check dynamoDBClient->listTables(); 145 | test:assertTrue(response.next() is record {|string value;|}, "Expected result is not obtained."); 146 | check response.forEach(function(string tableName) { 147 | log:printInfo(tableName); 148 | }); 149 | log:printInfo("Testing ListTables is completed."); 150 | } 151 | 152 | @test:Config { 153 | dependsOn: [testListTables] 154 | } 155 | function testPutItem() returns error? { 156 | ItemCreateInput request = { 157 | TableName: mainTable, 158 | Item: { 159 | "LastPostDateTime": { 160 | "S": "201303190422" 161 | }, 162 | "Tags": { 163 | "SS": [ 164 | "Update", 165 | "Multiple Items", 166 | "HelpMe" 167 | ] 168 | }, 169 | "ForumName": { 170 | "S": "Amazon DynamoDB" 171 | }, 172 | "Message": { 173 | "S": "I want to update multiple items in a single call. What's the best way to do that?" 174 | }, 175 | "Subject": { 176 | "S": "How do I update multiple items?" 177 | }, 178 | "LastPostedBy": { 179 | "S": "fred@example.com" 180 | } 181 | }, 182 | ConditionExpression: "ForumName <> :f and Subject <> :s", 183 | ReturnValues: ALL_OLD, 184 | ReturnItemCollectionMetrics: SIZE, 185 | ReturnConsumedCapacity: TOTAL, 186 | ExpressionAttributeValues: { 187 | ":f": { 188 | "S": "Amazon DynamoDB" 189 | }, 190 | ":s": { 191 | "S": "How do I update multiple items?" 192 | } 193 | } 194 | }; 195 | 196 | ItemDescription response = check dynamoDBClient->createItem(request); 197 | log:printInfo(response.toString()); 198 | log:printInfo("Testing CreateItem is completed."); 199 | } 200 | 201 | @test:Config { 202 | dependsOn: [testPutItem] 203 | } 204 | function testGetItem() returns error? { 205 | ItemGetInput request = { 206 | TableName: mainTable, 207 | Key: { 208 | "ForumName": { 209 | "S": "Amazon DynamoDB" 210 | }, 211 | "Subject": { 212 | "S": "How do I update multiple items?" 213 | } 214 | }, 215 | ProjectionExpression: "LastPostDateTime, Message, Tags", 216 | ConsistentRead: true, 217 | ReturnConsumedCapacity: TOTAL 218 | }; 219 | ItemGetOutput response = check dynamoDBClient->getItem(request); 220 | log:printInfo(response?.Item.toString()); 221 | log:printInfo("Testing GetItem is completed."); 222 | } 223 | 224 | @test:Config { 225 | dependsOn: [testGetItem] 226 | } 227 | function testUpdateItem() returns error? { 228 | ItemUpdateInput request = { 229 | TableName: mainTable, 230 | Key: { 231 | "ForumName": { 232 | "S": "Amazon DynamoDB" 233 | }, 234 | "Subject": { 235 | "S": "How do I update multiple items?" 236 | } 237 | }, 238 | UpdateExpression: "set LastPostedBy = :val1", 239 | ConditionExpression: "LastPostedBy = :val2", 240 | ExpressionAttributeValues: { 241 | ":val1": { 242 | "S": "alice@example.com" 243 | }, 244 | ":val2": { 245 | "S": "fred@example.com" 246 | } 247 | }, 248 | ReturnValues: ALL_NEW, 249 | ReturnConsumedCapacity: TOTAL, 250 | ReturnItemCollectionMetrics: SIZE 251 | }; 252 | ItemDescription response = check dynamoDBClient->updateItem(request); 253 | log:printInfo(response.toString()); 254 | log:printInfo("Testing UpdateItem is completed."); 255 | } 256 | 257 | @test:Config { 258 | dependsOn: [testUpdateItem] 259 | } 260 | function testQuery() returns error? { 261 | QueryInput request = { 262 | TableName: mainTable, 263 | ConsistentRead: true, 264 | KeyConditionExpression: "ForumName = :val", 265 | ExpressionAttributeValues: {":val": {"S": "Amazon DynamoDB"}} 266 | }; 267 | stream response = check dynamoDBClient->query(request); 268 | check response.forEach(function(QueryOutput resp) { 269 | test:assertTrue(resp?.Item is map); 270 | }); 271 | log:printInfo("Testing Query is completed."); 272 | } 273 | 274 | @test:Config { 275 | dependsOn: [testQuery] 276 | } 277 | function testScan() returns error? { 278 | ScanInput request = { 279 | TableName: mainTable, 280 | FilterExpression: "LastPostedBy = :val", 281 | ExpressionAttributeValues: {":val": {"S": "alice@example.com"}}, 282 | ReturnConsumedCapacity: TOTAL 283 | }; 284 | 285 | stream response = check dynamoDBClient->scan(request); 286 | check response.forEach(function(ScanOutput resp) { 287 | test:assertTrue(resp?.Item is map); 288 | }); 289 | log:printInfo("Testing Scan is completed."); 290 | } 291 | 292 | @test:Config { 293 | dependsOn: [testScan] 294 | } 295 | function testWriteBatchItems() returns error? { 296 | BatchItemInsertInput request = { 297 | RequestItems: { 298 | [secondaryTable]: [ 299 | { 300 | PutRequest: { 301 | Item: { 302 | "LastPostDateTime": { 303 | "S": "201303190423" 304 | }, 305 | "Tags": { 306 | "SS": [ 307 | "Update", 308 | "Multiple Items", 309 | "HelpMe" 310 | ] 311 | }, 312 | "ForumName": { 313 | "S": "Amazon S3" 314 | }, 315 | "Message": { 316 | "S": "I want to update multiple items in a single call. What's the best way to do that?" 317 | }, 318 | "Subject": { 319 | "S": "How do I update multiple items?" 320 | }, 321 | "LastPostedBy": { 322 | "S": "john@example.com" 323 | } 324 | } 325 | } 326 | }, 327 | { 328 | PutRequest: { 329 | Item: { 330 | "LastPostDateTime": { 331 | "S": "201303190423" 332 | }, 333 | "Tags": { 334 | "SS": [ 335 | "Update", 336 | "Multiple Items", 337 | "HelpMe" 338 | ] 339 | }, 340 | "ForumName": { 341 | "S": "Amazon DynamoDB" 342 | }, 343 | "Message": { 344 | "S": "I want to update multiple items in a single call. What's the best way to do that?" 345 | }, 346 | "Subject": { 347 | "S": "How do I update multiple items?" 348 | }, 349 | "LastPostedBy": { 350 | "S": "fred@example.com" 351 | } 352 | } 353 | } 354 | }, 355 | { 356 | PutRequest: { 357 | Item: { 358 | "LastPostDateTime": { 359 | "S": "201303190423" 360 | }, 361 | "Tags": { 362 | "SS": [ 363 | "Update", 364 | "Multiple Items", 365 | "HelpMe" 366 | ] 367 | }, 368 | "ForumName": { 369 | "S": "Amazon SimpleDB" 370 | }, 371 | "Message": { 372 | "S": "I want to update multiple items in a single call. What's the best way to do that?" 373 | }, 374 | "Subject": { 375 | "S": "How do I update multiple items?" 376 | }, 377 | "LastPostedBy": { 378 | "S": "james@example.com" 379 | } 380 | } 381 | } 382 | }, 383 | { 384 | PutRequest: { 385 | Item: { 386 | "LastPostDateTime": { 387 | "S": "201303190423" 388 | }, 389 | "Tags": { 390 | "SS": [ 391 | "Update", 392 | "Multiple Items", 393 | "HelpMe" 394 | ] 395 | }, 396 | "ForumName": { 397 | "S": "Amazon SES" 398 | }, 399 | "Message": { 400 | "S": "I want to send an email using AWS SES. What's the best way to do that?" 401 | }, 402 | "Subject": { 403 | "S": "How do I send a mail?" 404 | }, 405 | "LastPostedBy": { 406 | "S": "anne@example.com" 407 | } 408 | } 409 | } 410 | } 411 | ] 412 | }, 413 | ReturnConsumedCapacity: TOTAL 414 | }; 415 | 416 | io:println(request.toString()); 417 | 418 | BatchItemInsertOutput response = check dynamoDBClient->writeBatchItems(request); 419 | log:printInfo(response.toString()); 420 | log:printInfo("Testing WriteBatchItems(put) is completed."); 421 | } 422 | 423 | @test:Config { 424 | dependsOn: [testWriteBatchItems] 425 | } 426 | function testGetBatchItems() returns error? { 427 | BatchItemGetInput request = { 428 | RequestItems: { 429 | [mainTable]: { 430 | Keys: [ 431 | { 432 | "ForumName": {"S": "Amazon DynamoDB"}, 433 | "Subject": {"S": "How do I update multiple items?"} 434 | } 435 | ], 436 | ProjectionExpression: "ForumName, Message" 437 | }, 438 | [secondaryTable]: { 439 | Keys: [ 440 | { 441 | "ForumName": {"S": "Amazon S3"}, 442 | "Subject": {"S": "How do I update multiple items?"} 443 | } 444 | ], 445 | ProjectionExpression: "ForumName, Message, LastPostedBy" 446 | } 447 | }, 448 | ReturnConsumedCapacity: TOTAL 449 | }; 450 | 451 | stream response = check dynamoDBClient->getBatchItems(request); 452 | check response.forEach(function(BatchItem item) { 453 | log:printInfo(item?.Item.toString()); 454 | }); 455 | log:printInfo("Testing BatchGetItem is completed."); 456 | } 457 | 458 | @test:Config { 459 | dependsOn: [testGetBatchItems] 460 | } 461 | function testDeleteItem() returns error? { 462 | ItemDeleteInput request = { 463 | TableName: mainTable, 464 | Key: { 465 | "ForumName": { 466 | "S": "Amazon DynamoDB" 467 | }, 468 | "Subject": { 469 | "S": "How do I update multiple items?" 470 | } 471 | }, 472 | ReturnConsumedCapacity: TOTAL, 473 | ReturnItemCollectionMetrics: SIZE, 474 | ReturnValues: ALL_OLD 475 | }; 476 | ItemDescription response = check dynamoDBClient->deleteItem(request); 477 | log:printInfo(response.toString()); 478 | log:printInfo("Testing DeleteItem is completed."); 479 | } 480 | 481 | @test:Config {} 482 | function testDescribeLimits() returns error? { 483 | LimitDescription response = check dynamoDBClient->describeLimits(); 484 | test:assertTrue(response?.AccountMaxReadCapacityUnits is int, "AccountMaxReadCapacityUnits in DescribeLimits is " + 485 | "not an integer."); 486 | test:assertTrue(response?.AccountMaxWriteCapacityUnits is int, "AccountMaxWriteCapacityUnits in DescribeLimits is " + 487 | "not an integer."); 488 | test:assertTrue(response?.TableMaxReadCapacityUnits is int, "TableMaxReadCapacityUnits in DescribeLimits is " + 489 | "not an integer."); 490 | test:assertTrue(response?.TableMaxWriteCapacityUnits is int, "TableMaxWriteCapacityUnits in DescribeLimits is " + 491 | "not an integer."); 492 | log:printInfo("Testing DescribeLimits is completed."); 493 | } 494 | 495 | @test:AfterSuite 496 | function deleteTables() returns error? { 497 | _ = check executeWithRetry(testDeleteTable, 20, 3); 498 | } 499 | 500 | function testDeleteTable() returns error? { 501 | TableDescription response = check dynamoDBClient->deleteTable(mainTable); 502 | log:printInfo(response.toString()); 503 | test:assertEquals(response?.TableName, mainTable, "Expected table is not deleted."); 504 | response = check dynamoDBClient->deleteTable(secondaryTable); 505 | log:printInfo(response.toString()); 506 | test:assertEquals(response?.TableName, secondaryTable, "Expected table is not deleted."); 507 | log:printInfo("Testing DeleteTable is completed."); 508 | } 509 | 510 | # Executes a given function with retry. If there is no error the function will 511 | # immediately return. If there's errors it will retry as per given parameters. 512 | # 513 | # + testFunc - Test function to execute 514 | # + delayBetweenRetries - Time delay between two retries in seconds 515 | # + maxRetryCount - Maximum count to retry before giving up 516 | # + errorMsg - (Optional) Part or exact error message to check. Retry will happen 517 | # only if this matches with the error that is returned by executing the testFunc. 518 | # If not provided, retry will happen for any error returned by the testFunc. 519 | # + return - Stream of Calendars on success or else an error 520 | function executeWithRetry(function () returns error? testFunc, decimal delayBetweenRetries, 521 | int maxRetryCount, string? errorMsg = ()) returns error? { 522 | 523 | int currentRetryCount = 0; 524 | error? testResult = (); 525 | while (currentRetryCount < maxRetryCount) { 526 | if currentRetryCount > 0 { 527 | runtime:sleep(delayBetweenRetries); 528 | log:printWarn("Function returned an error. Retrying for " 529 | + (currentRetryCount + 1).toString() + "th time"); 530 | } 531 | testResult = testFunc(); 532 | currentRetryCount = currentRetryCount + 1; 533 | if testResult is error { 534 | if errorMsg == () { 535 | continue; 536 | } else { 537 | if string:includes(testResult.message(), errorMsg, 0) { 538 | continue; 539 | } else { 540 | break; 541 | } 542 | } 543 | } else { 544 | break; 545 | } 546 | } 547 | return testResult; 548 | } 549 | 550 | @test:Config { 551 | dependsOn: [testCreateTable] 552 | } 553 | function testCreateBackupAndDeleteBackup() returns error? { 554 | BackupCreateInput backupRequest = { 555 | TableName: mainTable, 556 | BackupName: "ThreadBackup" 557 | }; 558 | BackupDetails response = check dynamoDBClient->createBackup(backupRequest); 559 | test:assertEquals(response.BackupName, "ThreadBackup"); 560 | string backupArn = response.BackupArn; 561 | BackupDescription backupDescription = check dynamoDBClient->deleteBackup(backupArn); 562 | test:assertEquals(backupDescription.BackupDetails?.BackupName, "ThreadBackup"); 563 | } 564 | 565 | @test:Config { 566 | dependsOn: [testCreateTable] 567 | } 568 | function testTimeToLive() returns error? { 569 | TTLDescription response = check dynamoDBClient->getTTL(mainTable); 570 | test:assertEquals(response.TimeToLiveStatus, "DISABLED"); 571 | } 572 | -------------------------------------------------------------------------------- /ballerina/records.bal: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. 2 | // 3 | // WSO2 Inc. licenses this file to you under the Apache License, 4 | // Version 2.0 (the "License"); you may not use this file except 5 | // in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, 11 | // software distributed under the License is distributed on an 12 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | // KIND, either express or implied. See the License for the 14 | // specific language governing permissions and limitations 15 | // under the License. 16 | 17 | import ballerinax/'client.config; 18 | 19 | # Represents the AWS DynamoDB Connector configurations. 20 | @display {label: "Connection Config"} 21 | public type ConnectionConfig record {| 22 | *config:ConnectionConfig; 23 | # Auth credentials are ignored 24 | never auth?; 25 | # AWS credentials 26 | AwsCredentials|AwsTemporaryCredentials awsCredentials; 27 | # AWS Region 28 | string region; 29 | |}; 30 | 31 | # Represents AWS credentials. 32 | # 33 | # + accessKeyId - AWS access key 34 | # + secretAccessKey - AWS secret key 35 | public type AwsCredentials record { 36 | string accessKeyId; 37 | @display { 38 | label: "", 39 | kind: "password" 40 | } 41 | string secretAccessKey; 42 | }; 43 | 44 | # Represents AWS temporary credentials. 45 | public type AwsTemporaryCredentials record { 46 | # AWS access key 47 | string accessKeyId; 48 | # AWS secret key 49 | @display { 50 | label: "", 51 | kind: "password" 52 | } 53 | string secretAccessKey; 54 | # AWS secret token 55 | @display { 56 | label: "", 57 | kind: "password" 58 | } 59 | string securityToken; 60 | }; 61 | 62 | # Describes the current provisioned-capacity quotas for your AWS account in a Region, both for the Region as a whole and 63 | # for any one DynamoDB table that you create there. 64 | public type LimitDescription record { 65 | # The maximum total read capacity units that your account allows you to provision across all of your tables in this Region 66 | int? AccountMaxReadCapacityUnits?; 67 | # The maximum total write capacity units that your account allows you to provision across all of your tables in this Region 68 | int? AccountMaxWriteCapacityUnits?; 69 | # The maximum read capacity units that your account allows you to provision for a new table that you are creating in this Region, including the read capacity units 70 | int? TableMaxReadCapacityUnits?; 71 | # The maximum write capacity units that your account allows you to provision for a new table that you are creating in this Region, including the write capacity units 72 | # provisioned for its global secondary indexes (GSIs). 73 | int? TableMaxWriteCapacityUnits?; 74 | }; 75 | 76 | # Represents the response after `WriteBatchItem` operation. 77 | public type BatchItemInsertOutput record { 78 | # The capacity units consumed by the entire `BatchWriteItem` operation 79 | ConsumedCapacity[]? ConsumedCapacity?; 80 | # A list of tables that were processed by `BatchWriteItem` and, for each table, information about 81 | # any item collections that were affected by individual `DeleteItem` or `PutItem` operations. 82 | map? ItemCollectionMetrics?; 83 | # A map of tables and requests against those tables that were not processed. The `UnprocessedItems` 84 | # value is in the same form as `RequestItems`, so you can provide this value directly to a subsequent 85 | # `BatchGetItem` operation. 86 | map? UnprocessedItems?; 87 | }; 88 | 89 | # Represents the request payload `BatchWriteItem` operation. 90 | public type BatchItemInsertInput record {| 91 | # A map of one or more table names and, for each table, a list of operations to be performed 92 | # (DeleteRequest or PutRequest) 93 | map RequestItems; 94 | # Determines the level of detail about provisioned throughput consumption that is returned 95 | # in the response. Valid Values: INDEXES | TOTAL | NONE 96 | ReturnConsumedCapacity ReturnConsumedCapacity?; 97 | # Determines whether item collection metrics are returned. Valid Values: SIZE | NONE 98 | ReturnItemCollectionMetrics ReturnItemCollectionMetrics?; 99 | |}; 100 | 101 | # Represents the response after `BatchGetItem` operation, so the value can be provided directly to a subsequent `BatchGetItem` operation. 102 | type BatchGetItemsOutput record { 103 | # The read capacity units consumed by the entire BatchGetItem operation 104 | ConsumedCapacity[]? ConsumedCapacity?; 105 | # A map of table name to a list of items. Each object in Responses consists of a table name, along with a 106 | # map of attribute data consisting of the data type and attribute value 107 | map[]>? Responses?; 108 | # A map of tables and their respective keys that were not processed with the current response. The 109 | # `UnprocessedKeys` value is in the same form as `RequestItems`, so the value can be provided 110 | # directly to a subsequent `BatchGetItem` operation 111 | map? UnprocessedKeys?; 112 | }; 113 | 114 | # Represents ItemByBatchGet 115 | public type BatchItem record { 116 | # The read capacity units consumed by the entire BatchGetItem operation 117 | ConsumedCapacity? ConsumedCapacity?; 118 | # The name of the table containing the requested item 119 | string? TableName?; 120 | # The requested item 121 | map? Item?; 122 | }; 123 | 124 | # Represents the request payload for a `BatchGetItem` operation. 125 | public type BatchItemGetInput record {| 126 | # A map of one or more table names and, for each table, a map that describes one or more items to 127 | # retrieve from that table 128 | map RequestItems; 129 | # Determines the level of detail about provisioned throughput consumption that is returned in 130 | # the response. Valid Values: INDEXES | TOTAL | NONE 131 | ReturnConsumedCapacity ReturnConsumedCapacity?; 132 | |}; 133 | 134 | # Represents the request payload for `Scan` Operation. 135 | public type ScanInput record {| 136 | # The name of the table containing the requested items; or, if you provide IndexName, the name of the 137 | # table to which that index belongs 138 | string TableName; 139 | # This is a legacy parameter. Use ProjectionExpression instead 140 | string[] AttributesToGet?; 141 | # This is a legacy parameter. Use FilterExpression instead. Valid Values: AND | OR 142 | ConditionalOperator ConditionalOperator?; 143 | # A Boolean value that determines the read consistency model during the scan 144 | boolean ConsistentRead?; 145 | # The primary key of the first item that this operation will evaluate. Use the value that was 146 | # returned for `LastEvaluatedKey` in the previous operation 147 | map? ExclusiveStartKey?; 148 | # One or more substitution tokens for attribute names in an expression 149 | map ExpressionAttributeNames?; 150 | # One or more values that can be substituted in an expression 151 | map ExpressionAttributeValues?; 152 | # A string that contains conditions that DynamoDB applies after the Scan operation, but before the 153 | # data is returned to you. Items that do not satisfy the FilterExpression criteria are not returned 154 | string FilterExpression?; 155 | # The name of a secondary index to scan. This index can be any local secondary index or global secondary 156 | # index. Note that if you use the IndexName parameter, you must also provide TableName 157 | string IndexName?; 158 | # The maximum number of items to evaluate (not necessarily the number of matching items) 159 | int Limit?; 160 | # A string that identifies one or more attributes to retrieve from the specified table or index 161 | string ProjectionExpression?; 162 | # Determines the level of detail about provisioned throughput consumption that is returned in 163 | # the response. Valid Values: INDEXES | TOTAL | NONE 164 | ReturnConsumedCapacity ReturnConsumedCapacity?; 165 | # This is a legacy parameter. Use FilterExpression instead 166 | map ScanFilter?; 167 | # For a parallel Scan request, Segment identifies an individual segment to be scanned by an application 168 | # worker 169 | int Segment?; 170 | # The attributes to be returned in the result. Valid Values: ALL_ATTRIBUTES | ALL_PROJECTED_ATTRIBUTES | 171 | # SPECIFIC_ATTRIBUTES |COUNT 172 | Select Select?; 173 | # For a parallel Scan request, TotalSegments represents the total number of segments into which the 174 | # Scan operation will be divided 175 | int TotalSegments?; 176 | |}; 177 | 178 | # Represents the response of Query operation. 179 | public type QueryOutput record { 180 | # The capacity units consumed by the Query operation 181 | ConsumedCapacity? ConsumedCapacity?; 182 | # An Item that match the query criteria. It consists of an attribute name and the value for that attribute 183 | map? Item?; 184 | }; 185 | 186 | # Reperesents the response of Scan operation. 187 | public type ScanOutput record { 188 | # The capacity units consumed by the Scan operation 189 | ConsumedCapacity? ConsumedCapacity?; 190 | # An Item that match the scan criteria. It consists of an attribute name and the value for that attribute 191 | map? Item?; 192 | }; 193 | 194 | type QueryOrScanOutput record { 195 | ConsumedCapacity? ConsumedCapacity?; 196 | int? Count?; 197 | map[]? Items?; 198 | map? LastEvaluatedKey?; 199 | int? ScannedCount?; 200 | }; 201 | 202 | # Represents the request payload for `Query` Operation. 203 | public type QueryInput record {| 204 | # The name of the table containing the requested items 205 | string TableName; 206 | # This is a legacy parameter. Use ProjectionExpression instead 207 | string[] AttributesToGet?; 208 | # This is a legacy parameter. Use FilterExpression instead. Valid Values: AND | OR 209 | ConditionalOperator ConditionalOperator?; 210 | # Determines the read consistency model: If set to true, then the operation uses strongly consistent 211 | # reads; otherwise, the operation uses eventually consistent reads 212 | boolean ConsistentRead?; 213 | # The primary key of the first item that this operation will evaluate 214 | map? ExclusiveStartKey?; 215 | # One or more substitution tokens for attribute names in an expression 216 | map ExpressionAttributeNames?; 217 | # One or more values that can be substituted in an expression 218 | map ExpressionAttributeValues?; 219 | # A string that contains conditions that DynamoDB applies after the Query operation, but before the 220 | # data is returned to you. Items that do not satisfy the FilterExpression criteria are not returned 221 | string FilterExpression?; 222 | # The name of an index to query. This index can be any local secondary index or global secondary index on 223 | # the table. Note that if you use the IndexName parameter, you must also provide TableName. 224 | string IndexName?; 225 | # The condition that specifies the key values for items to be retrieved by the Query action 226 | string KeyConditionExpression?; 227 | # This is a legacy parameter. Use KeyConditionExpression instead 228 | map KeyConditions?; 229 | # The maximum number of items to evaluate (not necessarily the number of matching items) 230 | int Limit?; 231 | # A string that identifies one or more attributes to retrieve from the table 232 | string ProjectionExpression?; 233 | # This is a legacy parameter. Use FilterExpression instead 234 | map QueryFilter?; 235 | # Determines the level of detail about provisioned throughput consumption that is returned in 236 | # the response. Valid Values: INDEXES | TOTAL | NONE 237 | ReturnConsumedCapacity ReturnConsumedCapacity?; 238 | # Specifies the order for index traversal: If true (default), the traversal is performed in 239 | # ascending order; if false, the traversal is performed in descending order 240 | boolean ScanIndexForward?; 241 | # The attributes to be returned in the result. Valid Values: ALL_ATTRIBUTES | ALL_PROJECTED_ATTRIBUTES | 242 | # SPECIFIC_ATTRIBUTES | COUNT 243 | Select Select?; 244 | |}; 245 | 246 | # Represents the request payload to update an item. 247 | public type ItemUpdateInput record {| 248 | # The primary key of the item to be updated. Each element consists of an attribute name and a value for that 249 | # attribute 250 | map Key; 251 | # The name of the table containing the item to update 252 | string TableName; 253 | # This is a legacy parameter. Use UpdateExpression instead 254 | map AttributeUpdates?; 255 | # This is a legacy parameter. Use ConditionExpression instead. Valid Values: AND | OR 256 | ConditionalOperator ConditionalOperator?; 257 | # This is a legacy parameter. Use ConditionExpression instead 258 | string ConditionExpression?; 259 | # This is a legacy parameter. Use ConditionExpression instead 260 | map Expected?; 261 | # One or more substitution tokens for attribute names in an expression 262 | map ExpressionAttributeNames?; 263 | # One or more values that can be substituted in an expression 264 | map ExpressionAttributeValues?; 265 | # Determines the level of detail about provisioned throughput consumption that is returned in 266 | # the response. Valid Values: INDEXES | TOTAL | NONE 267 | ReturnConsumedCapacity ReturnConsumedCapacity?; 268 | # Determines whether item collection metrics are returned. Valid Values: SIZE | NONE 269 | ReturnItemCollectionMetrics ReturnItemCollectionMetrics?; 270 | # Use ReturnValues if you want to get the item attributes as they appear before or after they are 271 | # updated. Valid Values: NONE | ALL_OLD | UPDATED_OLD | ALL_NEW | UPDATED_NEW 272 | ReturnValues ReturnValues?; 273 | # An expression that defines one or more attributes to be updated, the action to be performed on 274 | # them, and new values for them 275 | string UpdateExpression?; 276 | |}; 277 | 278 | # Represents the request payload to delete an item. 279 | public type ItemDeleteInput record {| 280 | # A map of attribute names to AttributeValue objects, representing the primary key of the item to delete 281 | map Key; 282 | # The name of the table from which to delete the item 283 | string TableName; 284 | # This is a legacy parameter. Use ConditionExpression instead. Valid Values: AND | OR 285 | ConditionalOperator ConditionalOperator?; 286 | # A condition that must be satisfied in order for a conditional DeleteItem to succeed 287 | string ConditionExpression?; 288 | # This is a legacy parameter. Use ConditionExpression instead 289 | map Expected?; 290 | # One or more substitution tokens for attribute names in an expression 291 | map ExpressionAttributeNames?; 292 | # One or more values that can be substituted in an expression 293 | map ExpressionAttributeValues?; 294 | # Determines the level of detail about provisioned throughput consumption that is returned in 295 | # the response. Valid Values: INDEXES | TOTAL | NONE 296 | ReturnConsumedCapacity ReturnConsumedCapacity?; 297 | # Determines whether item collection metrics are returned. Valid Values: SIZE | NONE 298 | ReturnItemCollectionMetrics ReturnItemCollectionMetrics?; 299 | # Use ReturnValues if you want to get the item attributes as they appeared before they were deleted. 300 | # For DeleteItem, the valid values are: NONE | ALL_OLD 301 | ReturnValues ReturnValues?; 302 | |}; 303 | 304 | # Represents the response of `GetItem` operation. 305 | public type ItemGetOutput record { 306 | # The capacity units consumed by the GetItem operation 307 | ConsumedCapacity? ConsumedCapacity?; 308 | # A map of attribute names to AttributeValue objects, as specified by ProjectionExpression 309 | map? Item?; 310 | }; 311 | 312 | # Represents the request payload to get an Item. 313 | public type ItemGetInput record {| 314 | # A map of attribute names to AttributeValue objects, representing the primary key of the item to retrieve 315 | map Key; 316 | # The name of the table containing the requested item 317 | string TableName; 318 | # This is a legacy parameter. Use ProjectionExpression instead 319 | string[] AttributesToGet?; 320 | # Determines the read consistency model: If set to true, then the operation uses strongly consistent 321 | # reads; otherwise, the operation uses eventually consistent reads 322 | boolean ConsistentRead?; 323 | # One or more substitution tokens for attribute names in an expression 324 | map ExpressionAttributeNames?; 325 | # A string that identifies one or more attributes to retrieve from the table 326 | string ProjectionExpression?; 327 | # Determines the level of detail about provisioned throughput consumption that is returned in 328 | # the response. Valid Values: INDEXES | TOTAL | NONE 329 | ReturnConsumedCapacity ReturnConsumedCapacity?; 330 | |}; 331 | 332 | # Represents the response of PutItem operation. 333 | public type ItemDescription record { 334 | # The attribute values as they appeared before the PutItem operation, but only if ReturnValues is 335 | # specified as ALL_OLD in the request. Each element consists of an attribute name and an attribute value 336 | map? Attributes?; 337 | # The capacity units consumed by the PutItem operation 338 | ConsumedCapacity? ConsumedCapacity?; 339 | # Information about item collections, if any, that were affected by the PutItem operation 340 | ItemCollectionMetrics? ItemCollectionMetrics?; 341 | }; 342 | 343 | # Represents the request payload to put item. 344 | public type ItemCreateInput record {| 345 | # A map of attribute name/value pairs, one for each attribute. Only the primary key attributes are required; 346 | # you can optionally provide other attribute name-value pairs for the item 347 | map Item; 348 | # The name of the table to contain the item 349 | string TableName; 350 | # This is a legacy parameter. Use ConditionExpression instead. Valid Values: AND | OR 351 | ConditionalOperator? ConditionalOperator?; 352 | # A condition that must be satisfied in order for a conditional PutItem operation to succeed 353 | string? ConditionExpression?; 354 | # This is a legacy parameter. Use ConditionExpression instead 355 | map? Expected?; 356 | # One or more substitution tokens for attribute names in an expression 357 | map? ExpressionAttributeNames?; 358 | # One or more values that can be substituted in an expression 359 | map? ExpressionAttributeValues?; 360 | # Determines the level of detail about provisioned throughput consumption that is returned in 361 | # the response. Valid Values: INDEXES | TOTAL | NONE 362 | ReturnConsumedCapacity? ReturnConsumedCapacity?; 363 | # Determines whether item collection metrics are returned. Valid Values: SIZE | NONE 364 | ReturnItemCollectionMetrics? ReturnItemCollectionMetrics?; 365 | # Use ReturnValues if you want to get the item attributes as they appeared before they were updated 366 | # with the PutItem request. For PutItem, the valid values are: NONE | ALL_OLD 367 | ReturnValues? ReturnValues?; 368 | |}; 369 | 370 | # Represents the request payload to update table. 371 | public type TableUpdateInput record {| 372 | # The name of the table to be updated 373 | string TableName; 374 | # An array of attributes that describe the key schema for the table and indexes. If you are 375 | # adding a new global secondary index to the table, AttributeDefinitions must include the key 376 | # element(s) of the new index 377 | AttributeDefinition[] AttributeDefinitions?; 378 | # Controls how you are charged for read and write throughput and how you manage capacity 379 | BillingMode BillingMode?; 380 | # An array of one or more global secondary indexes for the table 381 | GlobalSecondaryIndexUpdate[] GlobalSecondaryIndexUpdates?; 382 | # The new provisioned throughput settings for the specified table or index 383 | ProvisionedThroughput ProvisionedThroughput?; 384 | # A list of replica update actions (create, delete, or update) for the table 385 | ReplicationGroupUpdate[] ReplicaUpdates?; 386 | # The new server-side encryption settings for the specified table 387 | SSESpecification SSESpecification?; 388 | # Represents the DynamoDB Streams configuration for the table 389 | StreamSpecification StreamSpecification?; 390 | |}; 391 | 392 | type TableListRequest record { 393 | string? ExclusiveStartTableName?; 394 | int? Limit?; 395 | }; 396 | 397 | # List of Tables. 398 | public type TableList record { 399 | # The name of the last table in the current page of results. Use this value as the ExclusiveStartTableName in a new 400 | # request to obtain the next page of results, until all the table names are returned 401 | string LastEvaluatedTableName?; 402 | # The names of the tables associated with the current account at the current endpoint. The maximum size 403 | # of this array is 100 404 | string[] TableNames?; 405 | }; 406 | 407 | # Represents the request payload to create table. 408 | public type TableCreateInput record {| 409 | # An array of attributes that describe the key schema for the table and indexes 410 | AttributeDefinition[] AttributeDefinitions; 411 | # Specifies the attributes that make up the primary key for a table or an index. The attributes in 412 | # KeySchema must also be defined in the AttributeDefinitions array 413 | KeySchemaElement[] KeySchema; 414 | # The name of the table to create 415 | string TableName; 416 | # Controls how you are charged for read and write throughput and how you manage capacity. Valid Values: 417 | # PROVISIONED | PAY_PER_REQUEST 418 | BillingMode BillingMode?; 419 | # One or more global secondary indexes (the maximum is 20) to be created on the table 420 | GlobalSecondaryIndex[] GlobalSecondaryIndexes?; 421 | # One or more local secondary indexes (the maximum is 5) to be created on the table 422 | LocalSecondaryIndex[] LocalSecondaryIndexes?; 423 | # Represents the provisioned throughput settings for a specified table or index 424 | ProvisionedThroughput ProvisionedThroughput?; 425 | # Represents the settings used to enable server-side encryption 426 | SSESpecification SSESpecification?; 427 | # The settings for DynamoDB Streams on the table 428 | StreamSpecification StreamSpecification?; 429 | # A list of key-value pairs to label the table 430 | Tag[] Tags?; 431 | |}; 432 | 433 | # Represents an attribute for describing the key schema for the table and indexes. 434 | public type AttributeDefinition record { 435 | # A name for the attribute 436 | string AttributeName; 437 | # The data type for the attribute, where: S - the attribute is of type String, N - the attribute is 438 | # of type Number, B - the attribute is of type Binary 439 | AttributeType AttributeType; 440 | }; 441 | 442 | # Represents a single element of a key schema. A key schema specifies the attributes that make up the primary key of a 443 | # table, or the key attributes of an index. 444 | public type KeySchemaElement record { 445 | # The name of a key attribute 446 | string AttributeName; 447 | # The role that this key attribute will assume: HASH - partition key, RANGE - sort key 448 | KeyType KeyType; 449 | }; 450 | 451 | # Represents attributes that are copied (projected) from the table into an index. These are in addition to the primary 452 | # key attributes and index key attributes, which are automatically projected. 453 | public type Projection record { 454 | # Represents the non-key attribute names which will be projected into the index 455 | string[]? NonKeyAttributes?; 456 | # The set of attributes that are projected into the index: KEYS_ONLY - Only the index and primary 457 | # keys are projected into the index, INCLUDE - In addition to the attributes described in KEYS_ONLY, 458 | # the secondary index will include other non-key attributes that you specify, ALL - All of the table 459 | # attributes are projected into the index 460 | ProjectionType? ProjectionType?; 461 | }; 462 | 463 | # Represents the provisioned throughput settings for a specified table or index. The settings can be modified using the 464 | # UpdateTable operation. 465 | public type ProvisionedThroughput record { 466 | # The maximum number of strongly consistent reads consumed per second before DynamoDB returns a `ThrottlingException` 467 | int ReadCapacityUnits; 468 | # The maximum number of writes consumed per second before DynamoDB returns a `ThrottlingException` 469 | int WriteCapacityUnits; 470 | }; 471 | 472 | # Represents the properties of a local secondary index. 473 | public type LocalSecondaryIndex record { 474 | # The name of the local secondary index. The name must be unique among all other indexes on this table 475 | string IndexName; 476 | # The complete key schema for the local secondary index, consisting of one or more pairs of attribute 477 | # names and key types: HASH - partition key, RANGE - sort key 478 | KeySchemaElement[] KeySchema; 479 | # Represents attributes that are copied (projected) from the table into the local secondary index. These 480 | # are in addition to the primary key attributes and index key attributes, which are automatically projected 481 | Projection Projection; 482 | }; 483 | 484 | # Represents the properties of a global secondary index. 485 | public type GlobalSecondaryIndex record { 486 | *LocalSecondaryIndex; 487 | # Represents the provisioned throughput settings for the specified global secondary index 488 | ProvisionedThroughput ProvisionedThroughput; 489 | }; 490 | 491 | # Represents the settings used to enable server-side encryption. 492 | public type SSESpecification record { 493 | # Indicates whether server-side encryption is done using an AWS managed CMK or an AWS owned CMK. If enabled 494 | # (true), server-side encryption type is set to KMS and an AWS managed CMK is used (AWS KMS charges apply). 495 | # If disabled (false) or not specified, server-side encryption is set to AWS owned CMK 496 | boolean? Enabled?; 497 | # The AWS KMS customer master key (CMK) that should be used for the AWS KMS encryption. To specify a 498 | # CMK, use its key ID, Amazon Resource Name (ARN), alias name, or alias ARN. Note that you should 499 | # only provide this parameter if the key is different from the default DynamoDB customer master key 500 | # `alias/aws/dynamodb` 501 | string? KMSMasterKeyId?; 502 | # Server-side encryption type. The only supported value is: KMS - Server-side encryption that uses AWS Key 503 | # Management Service. The key is stored in your account and is managed by AWS KMS (AWS KMS charges apply) 504 | SSEType? SSEType?; 505 | }; 506 | 507 | # Represents the DynamoDB Streams configuration for a table in DynamoDB. 508 | public type StreamSpecification record { 509 | # Indicates whether DynamoDB Streams is enabled (true) or disabled (false) on the table 510 | boolean StreamEnabled; 511 | # When an item in the table is modified, StreamViewType determines what information is written to the 512 | # stream for this table. Valid values for StreamViewType are: 513 | # KEYS_ONLY - Only the key attributes of the modified item are written to the stream. 514 | # NEW_IMAGE - The entire item, as it appears after it was modified, is written to the stream. 515 | # OLD_IMAGE - The entire item, as it appeared before it was modified, is written to the stream. 516 | # NEW_AND_OLD_IMAGES - Both the new and the old item images of the item are written to the stream 517 | StreamViewType? StreamViewType?; 518 | }; 519 | 520 | # Describes a tag. A tag is a key-value pair. You can add up to 50 tags to a single DynamoDB table. 521 | public type Tag record { 522 | # The key of the tag. Tag keys are case sensitive. Each DynamoDB table can only have up to one tag with the same 523 | # key. If you try to add an existing tag (same key), the existing tag value will be updated to the new value 524 | string Key; 525 | # The value of the tag. Tag values are case-sensitive and can be null 526 | string? Value; 527 | }; 528 | 529 | # Contains details of a table archival operation. 530 | public type ArchivalSummary record { 531 | # The Amazon Resource Name (ARN) of the backup the table was archived to, when applicable in the 532 | # archival reason. If you wish to restore this backup to the same table name, you will need to 533 | # delete the original table 534 | string? ArchivalBackupArn?; 535 | # The date and time when table archival was initiated by DynamoDB, in UNIX epoch time format 536 | int? ArchivalDateTime?; 537 | # The reason DynamoDB archived the table. Currently, the only possible value is: 538 | # INACCESSIBLE_ENCRYPTION_CREDENTIALS - The table was archived due to the table's AWS KMS key being 539 | # inaccessible for more than seven days. An On-Demand backup was created at the archival time 540 | string? ArchivalReason?; 541 | }; 542 | 543 | # Contains the details for the read/write capacity mode. 544 | public type BillingModeSummary record { 545 | # Controls how you are charged for read and write throughput and how you manage capacity. This setting 546 | # can be changed later. 547 | # PROVISIONED - Sets the read/write capacity mode to PROVISIONED. We recommend using PROVISIONED for 548 | # predictable workloads. 549 | # PAY_PER_REQUEST - Sets the read/write capacity mode to PAY_PER_REQUEST. We recommend using 550 | # PAY_PER_REQUEST for unpredictable workloads. 551 | BillingMode? BillingMode?; 552 | # Represents the time when PAY_PER_REQUEST was last set as the read/write capacity mode 553 | int? LastUpdateToPayPerRequestDateTime?; 554 | }; 555 | 556 | # Represents the properties of a global secondary index. 557 | public type GlobalSecondaryIndexDescription record { 558 | *LocalSecondaryIndexDescription; 559 | # Indicates whether the index is currently backfilling 560 | boolean? Backfilling?; 561 | # The current state of the global secondary index: CREATING - The index is being created, UPDATING - The 562 | # index is being updated, DELETING - The index is being deleted, ACTIVE - The index is ready for use 563 | IndexStatus? IndexStatus?; 564 | # Represents the provisioned throughput settings for the specified global secondary index 565 | ProvisionedThroughput? ProvisionedThroughput?; 566 | }; 567 | 568 | # Represents the properties of a local secondary index. 569 | public type LocalSecondaryIndexDescription record { 570 | # The Amazon Resource Name (ARN) that uniquely identifies the index 571 | string? IndexArn?; 572 | # Represents the name of the local secondary index 573 | string? IndexName?; 574 | # The total size of the specified index, in bytes. DynamoDB updates this value approximately every 575 | # six hours. Recent changes might not be reflected in this value 576 | int? IndexSizeBytes?; 577 | # The number of items in the specified index. DynamoDB updates this value approximately every six hours. 578 | # Recent changes might not be reflected in this value 579 | int? ItemCount?; 580 | # The complete key schema for the local secondary index, consisting of one or more pairs of attribute 581 | # names and key types: HASH - partition key, RANGE - sort key 582 | KeySchemaElement[]? KeySchema?; 583 | # Represents attributes that are copied (projected) from the table into the global secondary index. These 584 | # are in addition to the primary key attributes and index key attributes, which are automatically projected 585 | Projection? Projection?; 586 | }; 587 | 588 | # Represents the provisioned throughput settings for the table, consisting of read and write capacity units, along with 589 | # data about increases and decreases. 590 | public type ProvisionedThroughputDescription record { 591 | # The date and time of the last provisioned throughput decrease for this table 592 | int? LastDecreaseDateTime?; 593 | # The date and time of the last provisioned throughput increase for this table 594 | int? LastIncreaseDateTime?; 595 | # The number of provisioned throughput decreases for this table during this UTC calendar day 596 | int? NumberOfDecreasesToday?; 597 | # The maximum number of strongly consistent reads consumed per second before DynamoDB returns a `ThrottlingException` 598 | int? ReadCapacityUnits?; 599 | # The maximum number of writes consumed per second before DynamoDB returns a `ThrottlingException` 600 | int? WriteCapacityUnits?; 601 | }; 602 | 603 | # Replica-specific provisioned throughput settings. If not specified, uses the source table's provisioned throughput 604 | # settings. 605 | public type ProvisionedThroughputOverride record { 606 | # Replica-specific read capacity units. If not specified, uses the source table's read capacity settings 607 | int? ReadCapacityUnits?; 608 | }; 609 | 610 | # Represents the properties of a replica global secondary index. 611 | public type ReplicaGlobalSecondaryIndexDescription record { 612 | # The name of the global secondary index 613 | string? IndexName?; 614 | # If not described, uses the source table GSI's read capacity settings 615 | ProvisionedThroughputOverride? ProvisionedThroughputOverride?; 616 | }; 617 | 618 | # Contains the details of the replica. 619 | public type ReplicaDescription record { 620 | # Replica-specific global secondary index settings 621 | ReplicaGlobalSecondaryIndexDescription[]? GlobalSecondaryIndexes?; 622 | # The AWS KMS customer master key (CMK) of the replica that will be used for AWS KMS encryption 623 | string? KMSMasterKeyArn?; 624 | # Replica-specific provisioned throughput. If not described, uses the source table's provisioned throughput settings 625 | ProvisionedThroughputOverride? ProvisionedThroughputOverride?; 626 | # The name of the Region 627 | string? RegionName?; 628 | # The time at which the replica was first detected as inaccessible. To determine cause of inaccessibility check the ReplicaStatus property 629 | int? ReplicaInaccessibleDateTime?; 630 | # The current state of the replica. Valid Values: CREATING | CREATION_FAILED | UPDATING | DELETING | 631 | # ACTIVE | REGION_DISABLED | INACCESSIBLE_ENCRYPTION_CREDENTIALS 632 | ReplicaStatus? ReplicaStatus?; 633 | # Detailed information about the replica status 634 | string? ReplicaStatusDescription?; 635 | # Specifies the progress of a Create, Update, or Delete action on the replica as a percentage 636 | string? ReplicaStatusPercentProgress?; 637 | }; 638 | 639 | # Contains details for the restore. 640 | public type RestoreSummary record { 641 | # Point in time or source backup time 642 | int RestoreDateTime; 643 | # Indicates if a restore is in progress or not 644 | boolean RestoreInProgress; 645 | # The Amazon Resource Name (ARN) of the backup from which the table was restored 646 | string? SourceBackupArn?; 647 | # The ARN of the source table of the backup that is being restored 648 | string? SourceTableArn?; 649 | }; 650 | 651 | # The description of the server-side encryption status on the specified table. 652 | public type SSEDescription record { 653 | # Indicates the time, in UNIX epoch date format, when DynamoDB detected that the table's AWS KMS key was inaccessible 654 | int? InaccessibleEncryptionDateTime?; 655 | # The AWS KMS customer master key (CMK) ARN used for the AWS KMS encryption 656 | string? KMSMasterKeyArn?; 657 | # Server-side encryption type. The only supported value is: KMS - Server-side encryption that uses AWS Key 658 | # Management Service. The key is stored in your account and is managed by AWS KMS (AWS KMS charges apply) 659 | SSEType? SSEType?; 660 | # Represents the current state of server-side encryption. The only supported values are: 661 | # ENABLED - Server-side encryption is enabled, UPDATING - Server-side encryption is being updated 662 | Status? Status?; 663 | }; 664 | 665 | # Represents the properties of a table. 666 | public type TableDescription record { 667 | # Contains information about the table archive 668 | ArchivalSummary? ArchivalSummary?; 669 | # An array of AttributeDefinition objects. Each of these objects describes one attribute in 670 | # the table and index key schema 671 | AttributeDefinition[]? AttributeDefinitions?; 672 | # Contains the details for the read/write capacity mode 673 | BillingModeSummary? BillingModeSummary?; 674 | # The date and time when the table was created, in UNIX epoch time format 675 | int? CreationDateTime?; 676 | # The global secondary indexes, if any, on the table. Each index is scoped to a given partition key value 677 | GlobalSecondaryIndexDescription[]? GlobalSecondaryIndexes?; 678 | # Represents the version of global tables in use, if the table is replicated across AWS Regions 679 | string? GlobalTableVersion?; 680 | # The number of items in the specified table 681 | int? ItemCount?; 682 | # The primary key structure for the table 683 | KeySchemaElement[]? KeySchema?; 684 | # The Amazon Resource Name (ARN) that uniquely identifies the latest stream for this table 685 | string? LastDecreaseDateTimeatestStreamArn?; 686 | # A timestamp, in ISO 8601 format, for this stream 687 | string? LatestStreamLabel?; 688 | # Represents one or more local secondary indexes on the table 689 | LocalSecondaryIndexDescription[]? LocalSecondaryIndexes?; 690 | # The provisioned throughput settings for the table, consisting of read and write capacity 691 | # units, along with data about increases and decreases 692 | ProvisionedThroughputDescription? ProvisionedThroughput?; 693 | # Represents replicas of the table 694 | ReplicaDescription[]? Replicas?; 695 | # Contains details for the restore 696 | RestoreSummary? RestoreSummary?; 697 | # The description of the server-side encryption status on the specified table 698 | SSEDescription? SSEDescription?; 699 | # The current DynamoDB Streams configuration for the table 700 | StreamSpecification? StreamSpecification?; 701 | # The Amazon Resource Name (ARN) that uniquely identifies the table 702 | string? TableArn?; 703 | # Unique identifier for the table for which the backup was created 704 | string? TableId?; 705 | # The name of the table 706 | string? TableName?; 707 | # The total size of the specified table, in bytes 708 | int? TableSizeBytes?; 709 | # The current state of the table. Valid Values: CREATING | UPDATING | DELETING | ACTIVE | 710 | # INACCESSIBLE_ENCRYPTION_CREDENTIALS | ARCHIVING | ARCHIVED 711 | TableStatus? TableStatus?; 712 | }; 713 | 714 | # Represents a new global secondary index to be added to an existing table. 715 | public type CreateGlobalSecondaryIndexAction record { 716 | # The name of the global secondary index to be created 717 | string IndexName; 718 | # The key schema for the global secondary index 719 | KeySchemaElement[] KeySchema; 720 | # Represents attributes that are copied (projected) from the table into an index 721 | Projection Projection; 722 | # Represents the provisioned throughput settings for the specified global secondary index 723 | ProvisionedThroughput? ProvisionedThroughput?; 724 | }; 725 | 726 | # Represents a global secondary index to be deleted from an existing table. 727 | public type DeleteGlobalSecondaryIndexAction record { 728 | # The name of the global secondary index to be deleted 729 | string IndexName; 730 | }; 731 | 732 | # Represents the new provisioned throughput settings to be applied to a global secondary index. 733 | public type UpdateGlobalSecondaryIndexAction record { 734 | # The name of the global secondary index to be updated 735 | string IndexName; 736 | # Represents the provisioned throughput settings for the specified global secondary index 737 | ProvisionedThroughput ProvisionedThroughput; 738 | }; 739 | 740 | # Represents one of the following: A new global secondary index to be added to an existing table, New provisioned 741 | # throughput parameters for an existing global secondary index, An existing global secondary index to be removed from 742 | # an existing table. 743 | public type GlobalSecondaryIndexUpdate record { 744 | # The parameters required for creating a global secondary index on an existing table 745 | CreateGlobalSecondaryIndexAction? Create?; 746 | # The name of an existing global secondary index to be removed 747 | DeleteGlobalSecondaryIndexAction? Delete?; 748 | # The name of an existing global secondary index, along with new provisioned throughput settings to be 749 | # applied to that index 750 | UpdateGlobalSecondaryIndexAction? Update?; 751 | }; 752 | 753 | # Represents the properties of a replica global secondary index. 754 | public type ReplicaGlobalSecondaryIndex record { 755 | # The name of the global secondary index 756 | string IndexName; 757 | # Replica table GSI-specific provisioned throughput. If not specified, uses the source 758 | # table GSI's read capacity settings 759 | ProvisionedThroughputOverride? ProvisionedThroughputOverride?; 760 | }; 761 | 762 | # Represents a replica to be created. 763 | public type CreateReplicationGroupMemberAction record { 764 | # The Region where the new replica will be created 765 | string RegionName; 766 | # Replica-specific global secondary index settings 767 | ReplicaGlobalSecondaryIndex[]? GlobalSecondaryIndexes?; 768 | # The AWS KMS customer master key (CMK) that should be used for AWS KMS encryption in the new replica 769 | string? KMSMasterKeyId?; 770 | # Replica-specific provisioned throughput. If not specified, uses the source table's 771 | # provisioned throughput settings 772 | ProvisionedThroughputOverride? ProvisionedThroughputOverride?; 773 | }; 774 | 775 | # Represents a replica to be deleted. 776 | public type DeleteReplicationGroupMemberAction record { 777 | # The Region where the replica exists 778 | string RegionName; 779 | }; 780 | 781 | # Represents a replica to be modified. 782 | public type UpdateReplicationGroupMemberAction record { 783 | *CreateReplicationGroupMemberAction; 784 | }; 785 | 786 | # Represents one of the following: A new replica to be added to an existing regional table or global table. This request 787 | # invokes the CreateTableReplica action in the destination Region, New parameters for an existing replica. This request 788 | # invokes the UpdateTable action in the destination Region. An existing replica to be deleted. The request invokes the 789 | # DeleteTableReplica action in the destination Region, deleting the replica and all if its items in the destination 790 | # Region. 791 | public type ReplicationGroupUpdate record { 792 | # The parameters required for creating a replica for the table 793 | CreateReplicationGroupMemberAction? Create?; 794 | # The parameters required for deleting a replica for the table 795 | DeleteReplicationGroupMemberAction? Delete?; 796 | # The parameters required for updating a replica for the table 797 | UpdateReplicationGroupMemberAction? Update?; 798 | }; 799 | 800 | # Represents the data for an attribute. Each attribute value is described as a name-value pair. The name is the data 801 | # type, and the value is the data itself. 802 | public type AttributeValue record { 803 | # An attribute of type Binary 804 | string? B?; 805 | # An attribute of type Boolean 806 | boolean? BOOL?; 807 | # An attribute of type Binary Set 808 | string[]? BS?; 809 | # An attribute of type List 810 | AttributeValue[]? L?; 811 | # An attribute of type Map 812 | map? M?; 813 | # An attribute of type Number 814 | string? N?; 815 | # An attribute of type Number Set 816 | string[]? NS?; 817 | # An attribute of type Null 818 | boolean? NULL?; 819 | # An attribute of type String 820 | string? S?; 821 | # An attribute of type String Set 822 | string[]? SS?; 823 | }; 824 | 825 | # Represents a condition to be compared with an attribute value 826 | public type ExpectedAttributeValue record { 827 | # One or more values to evaluate against the supplied attribute 828 | AttributeValue[]? AttributeValueList?; 829 | # A comparator for evaluating attributes in the AttributeValueList. Valid Values: EQ | NE | IN | 830 | # LE | LT | GE | GT | BETWEEN | NOT_NULL | NULL | CONTAINS | NOT_CONTAINS | BEGINS_WITH 831 | ComparisonOperator? ComparisonOperator?; 832 | # Causes DynamoDB to evaluate the value before attempting a conditional operation 833 | boolean? Exists?; 834 | # Represents the data for the expected attribute 835 | AttributeValue? Value?; 836 | }; 837 | 838 | # Represents the amount of provisioned throughput capacity consumed on a table or an index. 839 | public type Capacity record { 840 | # The total number of capacity units consumed on a table or an index 841 | float? CapacityUnits?; 842 | # The total number of read capacity units consumed on a table or an index 843 | float? ReadCapacityUnits?; 844 | # The total number of write capacity units consumed on a table or an index 845 | float? WriteCapacityUnits?; 846 | }; 847 | 848 | # The capacity units consumed by an operation. The data returned includes the total provisioned throughput consumed, 849 | # along with statistics for the table and any indexes involved in the operation. 850 | public type ConsumedCapacity record { 851 | # The total number of capacity units consumed by the operation 852 | float? CapacityUnits?; 853 | # The amount of throughput consumed on each global index affected by the operation 854 | map? GlobalSecondaryIndexes?; 855 | # The amount of throughput consumed on each local index affected by the operation 856 | map? LocalSecondaryIndexes?; 857 | # The total number of read capacity units consumed by the operation 858 | float? ReadCapacityUnits?; 859 | # The amount of throughput consumed on the table affected by the operation 860 | Capacity? Table?; 861 | # The name of the table that was affected by the operation 862 | string? TableName?; 863 | # The total number of write capacity units consumed by the operation 864 | float? WriteCapacityUnits?; 865 | }; 866 | 867 | # Information about item collections, if any, that were affected by the operation. 868 | public type ItemCollectionMetrics record { 869 | # The partition key value of the item collection. This value is the same as the partition key 870 | # value of the item 871 | map? ItemCollectionKey?; 872 | # An estimate of item collection size, in gigabytes. This value is a two-element array 873 | # containing a lower bound and an upper bound for the estimate. The estimate includes the size 874 | # of all the items in the table, plus the size of all attributes projected into all of the local 875 | # secondary indexes on that table. Use this estimate to measure whether a local secondary index 876 | # is approaching its size limit 877 | float[]? SizeEstimateRangeGB?; 878 | }; 879 | 880 | # For the UpdateItem operation, represents the attributes to be modified, the action to perform on each, and the new 881 | # value for each. 882 | public type AttributeValueUpdate record { 883 | # Specifies how to perform the update. Valid values are PUT (default), DELETE, and ADD. The behavior depends 884 | # on whether the specified primary key already exists in the table 885 | Action? Action?; 886 | # Represents the data for an attribute 887 | AttributeValue? Value?; 888 | }; 889 | 890 | # Represents the selection criteria for a Query or Scan operation. For a Query operation, Condition is used for 891 | # specifying the KeyConditions to use when querying table or an index. For KeyConditions, only the following comparison 892 | # operators are supported: EQ | LE | LT | GE | GT | BEGINS_WITH | BETWEEN. For a Scan operation, Condition is used in a 893 | # ScanFilter, which evaluates the scan results and returns only the desired values 894 | public type Condition record { 895 | # A comparator for evaluating attributes. Valid Values: EQ | NE | IN | LE | LT | GE | GT | 896 | # BETWEEN | NOT_NULL | NULL | CONTAINS | NOT_CONTAINS | BEGINS_WITH 897 | ComparisonOperator ComparisonOperator; 898 | # One or more values to evaluate against the supplied attribute. The number of values in the list 899 | # depends on the ComparisonOperator being used 900 | AttributeValue[]? AttributeValueList?; 901 | }; 902 | 903 | # Represents a set of primary keys and, for each key, the attributes to retrieve from the table. 904 | public type KeysAndAttributes record { 905 | # The primary key attribute values that define the items and the attributes associated with the items 906 | map[] Keys; 907 | # This is a legacy parameter. Use ProjectionExpression instead 908 | string[]? AttributesToGet?; 909 | # The consistency of a read operation. If set to true, then a strongly consistent read is used; 910 | # otherwise, an eventually consistent read is used 911 | boolean? ConsistentRead?; 912 | # One or more substitution tokens for attribute names in an expression 913 | map? ExpressionAttributeNames?; 914 | # A string that identifies one or more attributes to retrieve from the table 915 | string? ProjectionExpression?; 916 | }; 917 | 918 | # Represents a request to perform a DeleteItem operation on an item. 919 | public type DeleteRequest record { 920 | # A map of attribute name to attribute values, representing the primary key of the item to delete. All of the 921 | # table's primary key attributes must be specified, and their data types must match those of the table's key schema 922 | map Key; 923 | }; 924 | 925 | # Represents a request to perform a PutItem operation on an item. 926 | public type PutRequest record { 927 | # A map of attribute name to attribute values, representing the primary key of an item to be processed by 928 | # `PutItem`. All of the table's primary key attributes must be specified, and their data types must match those 929 | # of the table's key schema. If any attributes are present in the item that are part of an index key schema 930 | # for the table, their types must match the index key schema 931 | map Item; 932 | }; 933 | 934 | # Represents an operation to perform - either DeleteItem or PutItem. You can only request one of these operations, not 935 | # both, in a single WriteRequest. If you do need to perform both of these operations, you need to provide two separate 936 | # WriteRequest objects. 937 | public type WriteRequest record { 938 | # A request to perform a DeleteItem operation 939 | DeleteRequest? DeleteRequest?; 940 | # A request to perform a PutItem operation 941 | PutRequest? PutRequest?; 942 | }; 943 | 944 | # Represents an request to perform a CreateBackup operation on a table. 945 | public type BackupCreateInput record {| 946 | # Name for the backup 947 | string BackupName; 948 | # Name of the table 949 | string TableName; 950 | |}; 951 | 952 | # Contains the details of the backup created for the table. 953 | public type BackupDetails record { 954 | # ARN associated with the backup 955 | string BackupArn; 956 | # Time at which the backup was created. This is the request time of the backup 957 | decimal BackupCreationDateTime; 958 | # Name of the requested backup 959 | string BackupName; 960 | # Backup can be in one of the following states: CREATING, ACTIVE, DELETED 961 | string BackupStatus; 962 | # BackupType. One of USER, SYSTEM, AWS_BACKUP 963 | string BackupType; 964 | # Time at which the automatic on-demand backup created by DynamoDB will expire. This SYSTEM on-demand backup 965 | # expires automatically 35 days after its creation 966 | decimal BackupExpiryDateTime?; 967 | # Size of the backup in bytes. DynamoDB updates this value approximately every six hours. Recent changes might 968 | # not be reflected in this value 969 | decimal BackupSizeBytes?; 970 | }; 971 | 972 | # Represents a response after performing a CreateBackup operation on a table. 973 | public type BackupDescription record { 974 | # Contains the details of the backup created for the table 975 | BackupDetails BackupDetails?; 976 | # Contains the details of the table when the backup was created 977 | SourceTableDetails SourceTableDetails?; 978 | # Contains the details of the features enabled on the table when the backup was created 979 | SourceTableFeatureDetails SourceTableFeatureDetails?; 980 | }; 981 | 982 | # Contains the details of the table when the backup was created. 983 | public type SourceTableDetails record { 984 | # Schema of the table 985 | KeySchemaElement[] KeySchema?; 986 | # Read IOPs and Write IOPS on the table when the backup was created 987 | ProvisionedThroughput ProvisionedThroughput?; 988 | # Time when the source table was created 989 | decimal TableCreationDateTime?; 990 | # Unique identifier for the table for which the backup was created 991 | string TableId?; 992 | # The name of the table for which the backup was created 993 | string TableName?; 994 | # Controls how you are charged for read and write throughput and how you manage capacity 995 | BillingMode BillingMode?; 996 | # Number of items in the table. Note that this is an approximate value 997 | float ItemCount?; 998 | # ARN of the table for which backup was created 999 | string TableArn?; 1000 | # Size of the table in bytes. Note that this is an approximate value 1001 | float TableSizeBytes?; 1002 | }; 1003 | 1004 | # Represents the properties of a global secondary index for the table when the backup was created. 1005 | public type GlobalSecondaryIndexInfo record { 1006 | # The name of the global secondary index 1007 | string IndexName?; 1008 | # The complete key schema for a global secondary index, which consists of one or more pairs of attribute 1009 | # names and key types: HASH - partition key and RANGE - sort key 1010 | KeySchemaElement[] KeySchema?; 1011 | # Represents attributes that are copied (projected) from the table into the global secondary index 1012 | Projection Projection?; 1013 | # Represents the provisioned throughput settings for the specified global secondary index 1014 | ProvisionedThroughput ProvisionedThroughput?; 1015 | }; 1016 | 1017 | # Represents the properties of a local secondary index for the table when the backup was created. 1018 | public type LocalSecondaryIndexInfo record { 1019 | # The name of the global secondary index 1020 | string IndexName?; 1021 | # The complete key schema for a global secondary index, which consists of one or more pairs of attribute names 1022 | # and key types: HASH - partition key and RANGE - sort key 1023 | KeySchemaElement[] KeySchema?; 1024 | # Represents attributes that are copied (projected) from the table into the global secondary index 1025 | Projection Projection?; 1026 | }; 1027 | 1028 | # The description of the Time to Live (TTL) status on the specified table 1029 | public type TTLDescription record { 1030 | # The name of the TTL attribute for items in the table 1031 | string AttributeName?; 1032 | # The TTL status for the table 1033 | TimeToLiveStatus TimeToLiveStatus?; 1034 | }; 1035 | 1036 | # Contains the details of the features enabled on the table when the backup was created. For example, LSIs, GSIs, 1037 | # streams, TTL. 1038 | public type SourceTableFeatureDetails record { 1039 | # Represents the GSI properties for the table when the backup was created. It includes the IndexName, KeySchema, 1040 | # Projection, and ProvisionedThroughput for the GSIs on the table at the time of backup 1041 | GlobalSecondaryIndexInfo GlobalSecondaryIndexInfo?; 1042 | # Represents the LSI properties for the table when the backup was created. It includes the IndexName, KeySchema 1043 | # and Projection for the LSIs on the table at the time of backup 1044 | LocalSecondaryIndexInfo LocalSecondaryIndexInfo?; 1045 | # The description of the server-side encryption status on the table when the backup was created 1046 | SSEDescription SSEDescription?; 1047 | # Stream settings on the table when the backup was created 1048 | StreamSpecification StreamSpecification?; 1049 | # Time to Live settings on the table when the backup was created 1050 | TTLDescription TimeToLiveDescription?; 1051 | }; 1052 | --------------------------------------------------------------------------------