From 177a6e1f68af9b6f537c2fa3bf017b8fcd5a4eb1 Mon Sep 17 00:00:00 2001 From: praba2210 <32615066+praba2210@users.noreply.github.com> Date: Wed, 22 Apr 2026 00:29:41 +0000 Subject: [PATCH 1/2] Sync examples from connectors --- .../alternatives/websocket/package-lock.json | 82 ++++----- .../src/alternatives/websocket/package.json | 6 +- php/pdo-pgsql/src/example_preferred.php | 11 ++ .../example_no_connection_pool.rs | 61 +++++++ rust/sqlx/src/example_preferred.rs | 111 +++++++++++++ rust/sqlx/src/main.rs | 157 ------------------ .../example_no_connection_pool_test.rs | 29 ++++ rust/sqlx/tests/example_preferred_test.rs | 35 ++++ 8 files changed, 291 insertions(+), 201 deletions(-) create mode 100644 rust/sqlx/src/alternatives/no_connection_pool/example_no_connection_pool.rs create mode 100644 rust/sqlx/src/example_preferred.rs delete mode 100644 rust/sqlx/src/main.rs create mode 100644 rust/sqlx/tests/alternatives/no_connection_pool/example_no_connection_pool_test.rs create mode 100644 rust/sqlx/tests/example_preferred_test.rs diff --git a/javascript/postgres-js/src/alternatives/websocket/package-lock.json b/javascript/postgres-js/src/alternatives/websocket/package-lock.json index f7fe0078..32417fab 100644 --- a/javascript/postgres-js/src/alternatives/websocket/package-lock.json +++ b/javascript/postgres-js/src/alternatives/websocket/package-lock.json @@ -8,8 +8,8 @@ "name": "aurora-dsql-query-editor-sample", "version": "1.0.0", "dependencies": { - "@aws-sdk/client-sts": "^3.1001.0", - "@aws-sdk/types": "^3.973.5", + "@aws-sdk/client-sts": "^3.1021.0", + "@aws-sdk/types": "^3.973.8", "@aws/aurora-dsql-postgresjs-connector": "^0.2.1", "buffer": "^6.0.3", "net-browserify": "^0.2.4", @@ -17,7 +17,7 @@ "postgres": "^3.4.7", "process": "^0.11.10", "react": "^19.2.4", - "react-dom": "^19.2.4", + "react-dom": "^19.2.5", "setimmediate": "^1.0.5", "timers-browserify": "^2.0.12" }, @@ -1091,12 +1091,12 @@ } }, "node_modules/@aws-sdk/types": { - "version": "3.973.6", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.6.tgz", - "integrity": "sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw==", + "version": "3.973.8", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.973.8.tgz", + "integrity": "sha512-gjlAdtHMbtR9X5iIhVUvbVcy55KnznpC6bkDUWW9z915bi0ckdUr5cjf16Kp6xq0bP5HBD2xzgbL9F9Quv5vUw==", "license": "Apache-2.0", "dependencies": { - "@smithy/types": "^4.13.1", + "@smithy/types": "^4.14.1", "tslib": "^2.6.2" }, "engines": { @@ -1645,9 +1645,9 @@ } }, "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -1719,9 +1719,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -2847,9 +2847,9 @@ } }, "node_modules/@smithy/types": { - "version": "4.13.1", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.13.1.tgz", - "integrity": "sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g==", + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.14.1.tgz", + "integrity": "sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg==", "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" @@ -3866,9 +3866,9 @@ } }, "node_modules/ajv": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.14.0.tgz", - "integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", "dependencies": { @@ -3901,9 +3901,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { @@ -4330,9 +4330,9 @@ "license": "MIT" }, "node_modules/brace-expansion": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz", - "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5537,9 +5537,9 @@ } }, "node_modules/eslint-plugin-react/node_modules/brace-expansion": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -5591,9 +5591,9 @@ } }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", - "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -8516,24 +8516,24 @@ } }, "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz", + "integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz", + "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==", "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.4" + "react": "^19.2.5" } }, "node_modules/react-is": { @@ -8892,9 +8892,9 @@ } }, "node_modules/schema-utils/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { diff --git a/javascript/postgres-js/src/alternatives/websocket/package.json b/javascript/postgres-js/src/alternatives/websocket/package.json index e5d20af5..8a1d81a5 100644 --- a/javascript/postgres-js/src/alternatives/websocket/package.json +++ b/javascript/postgres-js/src/alternatives/websocket/package.json @@ -8,8 +8,8 @@ "lint:fix": "eslint . --fix" }, "dependencies": { - "@aws-sdk/client-sts": "^3.1001.0", - "@aws-sdk/types": "^3.973.5", + "@aws-sdk/client-sts": "^3.1021.0", + "@aws-sdk/types": "^3.973.8", "@aws/aurora-dsql-postgresjs-connector": "^0.2.1", "buffer": "^6.0.3", "net-browserify": "^0.2.4", @@ -17,7 +17,7 @@ "postgres": "^3.4.7", "process": "^0.11.10", "react": "^19.2.4", - "react-dom": "^19.2.4", + "react-dom": "^19.2.5", "setimmediate": "^1.0.5", "timers-browserify": "^2.0.12" }, diff --git a/php/pdo-pgsql/src/example_preferred.php b/php/pdo-pgsql/src/example_preferred.php index 5358a35c..cdf91085 100644 --- a/php/pdo-pgsql/src/example_preferred.php +++ b/php/pdo-pgsql/src/example_preferred.php @@ -10,18 +10,29 @@ use Aws\AuroraDsql\PdoPgsql\AuroraDsql; use Aws\AuroraDsql\PdoPgsql\DsqlConfig; +// Works with both admin and non-admin users: +// - Admin users operate in the default "public" schema +// - Non-admin users operate in a custom "myschema" schema function main(): void { $clusterEndpoint = getenv('CLUSTER_ENDPOINT') ?: throw new RuntimeException( 'CLUSTER_ENDPOINT environment variable is required' ); + $clusterUser = getenv('CLUSTER_USER') ?: 'admin'; + + // Determine schema based on user type + $schema = $clusterUser === 'admin' ? 'public' : 'myschema'; $config = new DsqlConfig( host: $clusterEndpoint, + user: $clusterUser, occMaxRetries: 3, ); $pdo = AuroraDsql::connect($config); + // Set search_path for the appropriate schema + $pdo->exec("SET search_path = '{$schema}'"); + // Simple read $stmt = $pdo->query('SELECT 1 AS result'); $row = $stmt->fetch(PDO::FETCH_ASSOC); diff --git a/rust/sqlx/src/alternatives/no_connection_pool/example_no_connection_pool.rs b/rust/sqlx/src/alternatives/no_connection_pool/example_no_connection_pool.rs new file mode 100644 index 00000000..482c2b4c --- /dev/null +++ b/rust/sqlx/src/alternatives/no_connection_pool/example_no_connection_pool.rs @@ -0,0 +1,61 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use aurora_dsql_sqlx_connector::{txn, OCCRetryExt}; +use sqlx::{Executor, Row}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let cluster_endpoint = std::env::var("CLUSTER_ENDPOINT") + .expect("CLUSTER_ENDPOINT environment variable is not set"); + let cluster_user = std::env::var("CLUSTER_USER").unwrap_or_else(|_| "admin".to_string()); + + let conn_str = format!("postgres://{}@{}/postgres", cluster_user, cluster_endpoint); + + let mut conn = aurora_dsql_sqlx_connector::connection::connect(&conn_str).await?; + + // Create table + conn.execute( + "CREATE TABLE IF NOT EXISTS owner( + id uuid NOT NULL DEFAULT gen_random_uuid(), + name varchar(30) NOT NULL, + city varchar(80) NOT NULL, + PRIMARY KEY (id))", + ) + .await?; + + // -- Transactional write WITH OCC retry -- + conn.transaction_with_retry(None, |tx| { + txn!({ + sqlx::query("INSERT INTO owner(name, city) VALUES($1, $2)") + .bind("John Doe") + .bind("Anytown") + .execute(&mut **tx) + .await?; + Ok(()) + }) + }) + .await?; + + // Query it back + let row = sqlx::query("SELECT * FROM owner WHERE name = $1") + .bind("John Doe") + .fetch_one(&mut conn) + .await?; + + let name: &str = row.get("name"); + let city: &str = row.get("city"); + println!("name={}, city={}", name, city); + + assert_eq!(name, "John Doe"); + assert_eq!(city, "Anytown"); + + // Clean up + sqlx::query("DELETE FROM owner WHERE name = $1") + .bind("John Doe") + .execute(&mut conn) + .await?; + + println!("Connection exercised successfully"); + Ok(()) +} diff --git a/rust/sqlx/src/example_preferred.rs b/rust/sqlx/src/example_preferred.rs new file mode 100644 index 00000000..462185d7 --- /dev/null +++ b/rust/sqlx/src/example_preferred.rs @@ -0,0 +1,111 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use aurora_dsql_sqlx_connector::{txn, DsqlConnectOptions, OCCRetryExt}; +use sqlx::postgres::PgPoolOptions; +use sqlx::{Executor, Row}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let cluster_endpoint = std::env::var("CLUSTER_ENDPOINT") + .expect("CLUSTER_ENDPOINT environment variable is not set"); + let cluster_user = std::env::var("CLUSTER_USER").unwrap_or_else(|_| "admin".to_string()); + + let conn_str = format!("postgres://{}@{}/postgres", cluster_user, cluster_endpoint); + + // Admin users operate in the default "public" schema. + // Non-admin users operate in a custom "myschema" schema. + let schema = if cluster_user == "admin" { + "public" + } else { + "myschema" + }; + + // Build config and create a pool with custom options. + // connect_with() verifies connectivity and spawns a background token refresh task. + let config = DsqlConnectOptions::from_connection_string(&conn_str)?; + let schema_owned = schema.to_string(); + let mut pool = aurora_dsql_sqlx_connector::pool::connect_with( + &config, + PgPoolOptions::new() + .max_connections(10) + .after_connect(move |conn, _meta| { + let schema = schema_owned.clone(); + Box::pin(async move { + conn.execute(format!("SET search_path = '{}'", schema).as_str()) + .await?; + Ok(()) + }) + }), + ) + .await?; + + // -- Concurrent read queries -- + let mut handles = Vec::new(); + for i in 0..5 { + let pool = pool.clone(); + handles.push(tokio::spawn(async move { + let row = sqlx::query("SELECT $1::int as value") + .bind(i) + .fetch_one(&pool) + .await?; + Ok::(row.get("value")) + })); + } + + for handle in handles { + let result = handle.await??; + println!("Worker result: {}", result); + } + + println!("Concurrent pool operations completed successfully"); + + // -- Setup table -- + pool.execute( + "CREATE TABLE IF NOT EXISTS owner( + id uuid NOT NULL DEFAULT gen_random_uuid(), + name varchar(30) NOT NULL, + city varchar(80) NOT NULL, + PRIMARY KEY (id))", + ) + .await?; + + // -- Transactional write WITH OCC retry (using trait and txn! macro) -- + pool.transaction_with_retry(None, |tx| { + txn!({ + sqlx::query("INSERT INTO owner(name, city) VALUES($1, $2)") + .bind("John Doe") + .bind("Anytown") + .execute(&mut **tx) + .await?; + Ok(()) + }) + }) + .await?; + + // Verify the write + let row = sqlx::query("SELECT name, city FROM owner WHERE name = $1") + .bind("John Doe") + .fetch_one(&pool) + .await?; + + let name: &str = row.get("name"); + let city: &str = row.get("city"); + println!("Inserted: name={}, city={}", name, city); + + // -- Transactional write WITHOUT OCC retry (opt-out) -- + // For operations that don't need retry, use sqlx directly + let mut tx = pool.begin().await?; + sqlx::query("DELETE FROM owner WHERE name = $1") + .bind("John Doe") + .execute(&mut *tx) + .await?; + tx.commit().await?; + + println!("Transactional write completed successfully"); + + // Closing the pool stops the background refresh task. + pool.close().await; + + Ok(()) +} diff --git a/rust/sqlx/src/main.rs b/rust/sqlx/src/main.rs deleted file mode 100644 index 9a0c1c6e..00000000 --- a/rust/sqlx/src/main.rs +++ /dev/null @@ -1,157 +0,0 @@ -use aws_config::{BehaviorVersion, Region, SdkConfig}; -use aws_sdk_dsql::auth_token::{AuthToken, AuthTokenGenerator, Config}; -use sqlx::postgres::{PgConnectOptions, PgPoolOptions}; -use sqlx::{Pool, Postgres, Row}; -use std::time::Duration; -use tokio::time; - -const SECONDS_PER_MINUTE: u64 = 60; - -const TOKEN_EXPIRATION_MINUTES: u64 = 15; -const TOKEN_EXPIRATION_SECONDS: u64 = TOKEN_EXPIRATION_MINUTES * SECONDS_PER_MINUTE; - -const TOKEN_REFRESH_MINUTES: u64 = TOKEN_EXPIRATION_MINUTES - 5; -const TOKEN_REFRESH_SECONDS: u64 = TOKEN_REFRESH_MINUTES * SECONDS_PER_MINUTE; - -const _: () = assert!( - TOKEN_EXPIRATION_MINUTES > TOKEN_REFRESH_MINUTES, - "Token expiration time must be greater than refresh time" -); - -async fn generate_password_token( - cluster_user: &str, - signer: &AuthTokenGenerator, - sdk_config: &SdkConfig, -) -> AuthToken { - if cluster_user == "admin" { - signer - .db_connect_admin_auth_token(sdk_config) - .await - .unwrap() - } else { - signer.db_connect_auth_token(sdk_config).await.unwrap() - } -} - -/// Established a pooled connection with periodic credential refresh. -async fn establish_connection( - cluster_user: String, - cluster_endpoint: String, - region: String, -) -> anyhow::Result> { - let sdk_config = aws_config::load_defaults(BehaviorVersion::latest()).await; - let signer = AuthTokenGenerator::new( - Config::builder() - .hostname(&cluster_endpoint) - .region(Region::new(region)) - .expires_in(TOKEN_EXPIRATION_SECONDS) - .build() - .unwrap(), - ); - - let password_token = generate_password_token(&cluster_user, &signer, &sdk_config).await; - let schema = match cluster_user.as_str() { - "admin" => "public", - _ => "myschema", - }; - - let connection_options = PgConnectOptions::new() - .host(&cluster_endpoint) - .port(5432) - .database("postgres") - .username(&cluster_user) - .password(password_token.as_str()) - .ssl_mode(sqlx::postgres::PgSslMode::VerifyFull); - - let pool = PgPoolOptions::new() - .max_connections(10) - .after_connect(move |conn, _meta| { - Box::pin(async move { - sqlx::query(format!("SET search_path = {}", schema).as_str()) - .execute(conn) - .await - .map(|_| ()) - }) - }) - .connect_with(connection_options.clone()) - .await?; - - // Periodically refresh the password by regenerating the token. This runs every - // TOKEN_REFRESH_MINUTES and provides a token valid for TOKEN_EXPIRATION_MINUTES. - let _pool = pool.clone(); // Pool uses an Arc internally - tokio::spawn(async move { - loop { - time::sleep(Duration::from_secs(TOKEN_REFRESH_SECONDS)).await; - - let password_token = generate_password_token(&cluster_user, &signer, &sdk_config).await; - let connect_options_with_new_token = - connection_options.clone().password(password_token.as_str()); - _pool.set_connect_options(connect_options_with_new_token); - } - }); - - Ok(pool) -} - -/// Run some example operations against the provided pool. -async fn exercise_connection(pool: &Pool) -> anyhow::Result<()> { - sqlx::query( - r#" - CREATE TABLE IF NOT EXISTS owner ( - id UUID NOT NULL DEFAULT gen_random_uuid(), - name VARCHAR(30) NOT NULL, - city VARCHAR(80) NOT NULL, - telephone VARCHAR(20) DEFAULT NULL, - PRIMARY KEY (id) - )"#, - ) - .execute(pool) - .await?; - - // Insert some data - sqlx::query("INSERT INTO owner (name, city, telephone) VALUES ($1, $2, $3)") - .bind("John Doe") - .bind("Anytown") - .bind("555-555-1999") - .execute(pool) - .await?; - - let rows = sqlx::query("SELECT * FROM owner WHERE name=$1") - .bind("John Doe") - .fetch_all(pool) - .await?; - - // Verify the result is what we inserted before - assert_eq!(rows.len(), 1); - let row = &rows[0]; - assert_eq!(row.try_get::<&str, _>("name")?, "John Doe"); - assert_eq!(row.try_get::<&str, _>("city")?, "Anytown"); - assert_eq!(row.try_get::<&str, _>("telephone")?, "555-555-1999"); - - // Clean up the table after the example. If we run the example again we do not have to worry - // about data inserted by previous runs - sqlx::query("DELETE FROM owner WHERE name = 'John Doe'") - .execute(pool) - .await?; - - Ok(()) -} - -#[tokio::main] -pub async fn main() -> Result<(), anyhow::Result<()>> { - let cluster_user = - std::env::var("CLUSTER_USER").expect("env variable `CLUSTER_USER` should be set"); - let cluster_endpoint = - std::env::var("CLUSTER_ENDPOINT").expect("env variable `CLUSTER_ENDPOINT` should be set"); - let region = std::env::var("REGION").expect("env variable `REGION` should be set"); - - let pool = establish_connection(cluster_user, cluster_endpoint, region) - .await - .unwrap(); - exercise_connection(&pool).await.unwrap(); - pool.close().await; - - println!("Connection exercised successfully"); - - Ok(()) -} diff --git a/rust/sqlx/tests/alternatives/no_connection_pool/example_no_connection_pool_test.rs b/rust/sqlx/tests/alternatives/no_connection_pool/example_no_connection_pool_test.rs new file mode 100644 index 00000000..e48e0355 --- /dev/null +++ b/rust/sqlx/tests/alternatives/no_connection_pool/example_no_connection_pool_test.rs @@ -0,0 +1,29 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use std::process::Command; + +#[test] +fn test_no_connection_pool_example() { + let output = Command::new("cargo") + .args(["run", "--bin", "example_no_connection_pool"]) + .current_dir(env!("CARGO_MANIFEST_DIR")) + .output() + .expect("Failed to run example_no_connection_pool"); + + let stdout = String::from_utf8_lossy(&output.stdout); + let stderr = String::from_utf8_lossy(&output.stderr); + + assert!( + output.status.success(), + "example_no_connection_pool failed.\nstdout: {}\nstderr: {}", + stdout, + stderr + ); + + assert!( + stdout.contains("Connection exercised successfully"), + "Expected success message in stdout: {}", + stdout + ); +} diff --git a/rust/sqlx/tests/example_preferred_test.rs b/rust/sqlx/tests/example_preferred_test.rs new file mode 100644 index 00000000..c079145f --- /dev/null +++ b/rust/sqlx/tests/example_preferred_test.rs @@ -0,0 +1,35 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use std::process::Command; + +#[test] +fn test_example_preferred() { + let output = Command::new("cargo") + .args(["run", "--bin", "example_preferred"]) + .current_dir(env!("CARGO_MANIFEST_DIR")) + .output() + .expect("Failed to run example_preferred"); + + let stdout = String::from_utf8_lossy(&output.stdout); + let stderr = String::from_utf8_lossy(&output.stderr); + + assert!( + output.status.success(), + "example_preferred failed.\nstdout: {}\nstderr: {}", + stdout, + stderr + ); + + assert!( + stdout.contains("Concurrent pool operations completed successfully"), + "Expected success message in stdout: {}", + stdout + ); + + assert!( + stdout.contains("Transactional write completed successfully"), + "Expected transactional write message in stdout: {}", + stdout + ); +} From 20e00a563f962687b752a76636cdb6937c4a8f26 Mon Sep 17 00:00:00 2001 From: Prabakaran Annadurai Date: Tue, 21 Apr 2026 19:55:46 -0700 Subject: [PATCH 2/2] Update Cargo.toml to match connector structure Update rust/sqlx binary and test configuration to match the connector repo structure with example_preferred.rs instead of main.rs --- .github/workflows/rust-sqlx-integ-test.yml | 2 +- rust/sqlx/Cargo.toml | 28 ++++++++++++++-------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/.github/workflows/rust-sqlx-integ-test.yml b/.github/workflows/rust-sqlx-integ-test.yml index 19a0c0eb..602b72b3 100644 --- a/.github/workflows/rust-sqlx-integ-test.yml +++ b/.github/workflows/rust-sqlx-integ-test.yml @@ -47,7 +47,7 @@ jobs: CLUSTER_ENDPOINT: ${{ needs.create-cluster.outputs.cluster-endpoint }} REGION: ${{ needs.create-cluster.outputs.region }} run: | - cargo run + cargo test delete-cluster: if: always() && needs.create-cluster.result == 'success' diff --git a/rust/sqlx/Cargo.toml b/rust/sqlx/Cargo.toml index eb625cd0..f2fde5a1 100644 --- a/rust/sqlx/Cargo.toml +++ b/rust/sqlx/Cargo.toml @@ -5,16 +5,24 @@ edition = "2021" include = ["/src"] [dependencies] -tokio = { version = "1.52", features = ["full"] } -sqlx = { version = "0.8", features = [ "runtime-tokio", "tls-rustls" , "postgres", "uuid"] } -anyhow = { version = "1", features = ["backtrace"] } -aws-config = "1.8" -aws-sdk-dsql = "1.55" -rand = "0.10" -uuid = { version = "1.23", features = ["v4"] } -log = "0.4.29" +aurora-dsql-sqlx-connector = { version = "0.1", features = ["pool", "occ"] } +anyhow = "1" +tokio = { version = "1", features = ["full"] } +sqlx = { version = "0.8", features = ["runtime-tokio", "postgres"] } [[bin]] -name = "sqlx" -path = "src/main.rs" +name = "example_preferred" +path = "src/example_preferred.rs" + +[[bin]] +name = "example_no_connection_pool" +path = "src/alternatives/no_connection_pool/example_no_connection_pool.rs" + +[[test]] +name = "example_preferred_test" +path = "tests/example_preferred_test.rs" + +[[test]] +name = "example_no_connection_pool_test" +path = "tests/alternatives/no_connection_pool/example_no_connection_pool_test.rs"