1import * as rdsdata from "@distilled.cloud/aws/rds-data";
2import * as Effect from "effect/Effect";
3import * as Binding from "../../Binding.ts";
4import type { RuntimeContext } from "../../RuntimeContext.ts";
5import type { DBCluster } from "../RDS/DBCluster.ts";
6import type { Secret } from "../SecretsManager/Secret.ts";
7
8export interface ExecuteStatementOptions {
9 secret: Secret;
10 database?: string;
11 schema?: string;
12}
13
14export interface ExecuteStatementRequest extends Omit<
15 rdsdata.ExecuteStatementRequest,
16 "resourceArn" | "secretArn" | "database" | "schema"
17> {}
18
19/**
20 * Runtime binding for `rds-data:ExecuteStatement` — run a SQL statement
21 * against an Aurora cluster over the HTTP Data API (no VPC attachment or
22 * database socket required).
23 *
24 * Bind it to a `DBCluster` (with the Data API enabled via
25 * `enableHttpEndpoint: true`) and the Secrets Manager secret holding the
26 * database credentials. The cluster ARN, secret ARN, and database name are
27 * injected automatically, and the function is granted
28 * `rds-data:ExecuteStatement` plus `secretsmanager:GetSecretValue` on the
29 * secret. Provide the implementation with
30 * `Effect.provide(AWS.RDSData.ExecuteStatementHttp)`.
31 * ### Executing Statements
32 * **Example:** Query with Named Parameters
33 * ```typescript
34 * export default MyFunction.make(
35 * { main: import.meta.url, functionUrl: true },
36 * Effect.gen(function* () {
37 * const db = yield* AWS.RDS.Aurora("AppDb", {
38 * subnetIds: [subnetA.subnetId, subnetB.subnetId],
39 * securityGroupIds: [dbSecurityGroup.groupId],
40 * });
41 * // init — bind the operation to the cluster + admin secret
42 * const executeStatement = yield* AWS.RDSData.ExecuteStatement(db.cluster, {
43 * secret: db.secret,
44 * database: "app",
45 * });
46 *
47 * return {
48 * fetch: Effect.gen(function* () {
49 * // runtime — parameterized SQL over the Data API
50 * const result = yield* executeStatement({
51 * sql: "SELECT id, title FROM todos WHERE id = :id",
52 * parameters: [{ name: "id", value: { longValue: 1 } }],
53 * });
54 * return yield* HttpServerResponse.json({ records: result.records ?? [] });
55 * }).pipe(Effect.orDie),
56 * };
57 * }).pipe(Effect.provide(AWS.RDSData.ExecuteStatementHttp)),
58 * );
59 * ```
60 *
61 * **Example:** Write Inside a Transaction
62 * ```typescript
63 * // pass a transactionId from AWS.RDSData.BeginTransaction to make the
64 * // statement part of that transaction
65 * yield* executeStatement({
66 * sql: "INSERT INTO todos (id, title) VALUES (:id, :title)",
67 * parameters: [
68 * { name: "id", value: { longValue: 42 } },
69 * { name: "title", value: { stringValue: "ship it" } },
70 * ],
71 * transactionId: tx.transactionId,
72 * });
73 * ```
74 *
75 * @binding
76 */
77export interface ExecuteStatement extends Binding.Service<
78 ExecuteStatement,
79 "AWS.RDSData.ExecuteStatement",
80 (
81 cluster: DBCluster,
82 options: ExecuteStatementOptions,
83 ) => Effect.Effect<
84 (
85 request: ExecuteStatementRequest,
86 ) => Effect.Effect<
87 rdsdata.ExecuteStatementResponse,
88 rdsdata.ExecuteStatementError,
89 RuntimeContext
90 >
91 >
92> {}
93
94export const ExecuteStatement = Binding.Service<ExecuteStatement>(
95 "AWS.RDSData.ExecuteStatement",
96);