Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions elixir/postgrex/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
inputs: ["{mix,.formatter}.exs", "{lib,test}/**/*.{ex,exs}"]
]
9 changes: 9 additions & 0 deletions elixir/postgrex/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/_build/
/deps/
/doc/
/.fetch
erl_crash.dump
*.ez
*.beam
/config/*.secret.exs
.elixir_ls/
87 changes: 87 additions & 0 deletions elixir/postgrex/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Aurora DSQL with Postgrex

## Overview

This code example demonstrates how to use Postgrex with Amazon Aurora DSQL. The example shows you how to connect to an Aurora DSQL cluster and perform basic database operations.

Aurora DSQL is a distributed SQL database service that provides high availability and scalability for your PostgreSQL-compatible applications. Postgrex is the PostgreSQL driver for Elixir that allows you to interact with PostgreSQL databases.

## About the code example

The example demonstrates a flexible connection approach that works for both admin and non-admin users:

* When connecting as an **admin user**, the example uses the `public` schema and generates an admin authentication token.
* When connecting as a **non-admin user**, the example uses a custom `myschema` schema and generates a standard authentication token.

The code automatically detects the user type and adjusts its behavior accordingly.

## ⚠️ Important

* Running this code might result in charges to your AWS account.
* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege).
* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services).

## Run the example

### Prerequisites

* You must have an AWS account, and have your default credentials and AWS Region configured as described in the [Globally configuring AWS SDKs and tools](https://docs.aws.amazon.com/credref/latest/refdocs/creds-config-files.html) guide.
* [Elixir 1.14+](https://elixir-lang.org/install.html) installed.

```bash
elixir --version
```
* Install required Elixir dependencies.

mix deps.get
* AWS CLI installed and configured for token generation.
* You must have an Aurora DSQL cluster. For information about creating an Aurora DSQL cluster, see the [Getting started with Aurora DSQL](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/getting-started.html) guide.
* If connecting as a non-admin user, ensure the user is linked to an IAM role and is granted access to the `myschema` schema. See the [Using database roles with IAM roles](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/using-database-and-iam-roles.html) guide.

### Run the code

The example demonstrates the following operations:

- Opening a connection to an Aurora DSQL cluster
- Creating a table
- Inserting and querying data

The example is designed to work with both admin and non-admin users:

- When run as an admin user, it uses the `public` schema
- When run as a non-admin user, it uses the `myschema` schema

**Note:** running the example will use actual resources in your AWS account and may incur charges.

Set environment variables for your cluster details:

```bash
# e.g. "admin"
export CLUSTER_USER="<your user>"

# e.g. "foo0bar1baz2quux3quuux4.dsql.us-east-1.on.aws"
export CLUSTER_ENDPOINT="<your endpoint>"

# e.g. "us-east-1"
export REGION="<your region>"
```

Install dependencies and run the example:

```bash
mix run -e "AuroraDsqlExample.run()"
```

The example contains comments explaining the code and the operations being performed.

## Additional resources

* [Amazon Aurora DSQL Documentation](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/what-is-aurora-dsql.html)
* [Postgrex Documentation](https://hexdocs.pm/postgrex/)
* [Elixir Documentation](https://elixir-lang.org/docs.html)

---

Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.

SPDX-License-Identifier: MIT-0
84 changes: 84 additions & 0 deletions elixir/postgrex/lib/example.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
defmodule AuroraDsqlExample do
@moduledoc """
Example demonstrating Aurora DSQL connectivity with Elixir using Postgrex.
"""

def run do
cluster_endpoint = System.get_env("CLUSTER_ENDPOINT") || raise "CLUSTER_ENDPOINT not set"
cluster_user = System.get_env("CLUSTER_USER") || raise "CLUSTER_USER not set"
region = System.get_env("REGION") || raise "REGION not set"

token = generate_auth_token(cluster_endpoint, cluster_user, region)
schema = if cluster_user == "admin", do: "public", else: "myschema"

opts = [
hostname: cluster_endpoint,
port: 5432,
username: cluster_user,
password: token,
database: "postgres",
ssl: true,
ssl_opts: [
verify: :verify_peer,
cacerts: :public_key.cacerts_get(),
customize_hostname_check: [
match_fun: :public_key.pkix_verify_hostname_match_fun(:https)
]
]
]

{:ok, conn} = Postgrex.start_link(opts)

try do
Postgrex.query!(conn, "SET search_path = #{schema}", [])
exercise_connection(conn)
IO.puts("Connection exercised successfully")
after
GenServer.stop(conn)
end
end

defp generate_auth_token(endpoint, user, region) do
action = if user == "admin", do: "generate-db-connect-admin-auth-token", else: "generate-db-connect-auth-token"

{output, 0} = System.cmd("aws", [
"dsql",
action,
"--hostname", endpoint,
"--region", region
])

String.trim(output)
end

defp exercise_connection(conn) do
Postgrex.query!(conn, """
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)
)
""", [])

Postgrex.query!(conn,
"INSERT INTO owner (name, city, telephone) VALUES ($1, $2, $3)",
["John Doe", "Anytown", "555-555-1999"]
)

result = Postgrex.query!(conn,
"SELECT * FROM owner WHERE name = $1",
["John Doe"]
)

[row] = result.rows
[_id, name, city, telephone] = row

unless name == "John Doe" and city == "Anytown" and telephone == "555-555-1999" do
raise "Unexpected data retrieved"
end

Postgrex.query!(conn, "DELETE FROM owner WHERE name = $1", ["John Doe"])
end
end
25 changes: 25 additions & 0 deletions elixir/postgrex/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
defmodule AuroraDsqlExample.MixProject do
use Mix.Project

def project do
[
app: :aurora_dsql_example,
version: "0.1.0",
elixir: "~> 1.14",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end

def application do
[
extra_applications: [:logger, :crypto, :public_key]
]
end

defp deps do
[
{:postgrex, "~> 0.19"}
]
end
end
6 changes: 6 additions & 0 deletions elixir/postgrex/mix.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
%{
"db_connection": {:hex, :db_connection, "2.8.1", "9abdc1e68c34c6163f6fb96a96532272d13ad7ca45262156ae8b7ec6d9dc4bec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61a3d489b239d76f326e03b98794fb8e45168396c925ef25feb405ed09da8fd"},
"decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"},
"postgrex": {:hex, :postgrex, "0.21.1", "2c5cc830ec11e7a0067dd4d623c049b3ef807e9507a424985b8dcf921224cd88", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "27d8d21c103c3cc68851b533ff99eef353e6a0ff98dc444ea751de43eb48bdac"},
"telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"},
}
Loading