Skip to content

Commit 5305a2b

Browse files
anwesham-labclaude
andauthored
fix(databases-on-aws): correct DSQL type guidance, add cluster-lifecycle troubleshooting (#155)
* fix(databases-on-aws): correct DSQL type guidance, add cluster-lifecycle troubleshooting Update DSQL skill to reflect current DSQL type support: JSON is a supported column type (1 MiB, auto-compressed), while JSONB, arrays, and INET remain runtime-only. Replace the narrow quick-reference type list with a pointer to the canonical AWS docs and an awsknowledge verify-query row, so the skill does not drift as DSQL's type surface evolves. Add troubleshooting entries for the INACTIVE-cluster wake error and the FailedPrecondition returned when backing up an IDLE/INACTIVE cluster, with a pointer to the cluster-lifecycle documentation. Extend the Tier 2 functional eval suite with four new evals covering the updated behaviors — JSON column storage, array-column rejection, the INACTIVE-cluster wake flow, and FailedPrecondition backup-on-idle — plus grader clauses they need and an --eval-ids flag on the runner for targeted subset runs. Verified against live cluster: JSON accepted as column type; JSONB and TEXT[] rejected with "datatype not supported"; ::jsonb cast + ->> / @> operators work as expected. node-postgres auto-serializes JS objects for both JSON and TEXT columns. All four new evals pass 11/11 expectations when run against the updated skill. Co-Authored-By: anwesham-lab <64298192+anwesham-lab@users.noreply.github.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(databases-on-aws): bump version to 1.1.0 Ships the DSQL skill updates from this branch: corrected type guidance (JSON supported, JSONB/arrays/INET runtime-only), cluster-lifecycle troubleshooting (INACTIVE wake, FailedPrecondition on IDLE/INACTIVE backup), and the expanded Tier 2 eval suite (evals 6-9) with LLM-judge grading and the --eval-ids/--judge-model runner flags. Co-Authored-By: anwesham-lab <64298192+anwesham-lab@users.noreply.github.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent d6faaf5 commit 5305a2b

14 files changed

Lines changed: 283 additions & 65 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@
123123
"name": "databases-on-aws",
124124
"source": "./plugins/databases-on-aws",
125125
"tags": ["aws", "database", "aurora", "dsql", "serverless", "postgresql"],
126-
"version": "1.0.0"
126+
"version": "1.1.0"
127127
},
128128
{
129129
"category": "deployment",

plugins/databases-on-aws/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@
2222
"license": "Apache-2.0",
2323
"name": "databases-on-aws",
2424
"repository": "https://github.com/awslabs/agent-plugins",
25-
"version": "1.0.0"
25+
"version": "1.1.0"
2626
}

plugins/databases-on-aws/.codex-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "databases-on-aws",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"description": "Expert database guidance for the AWS database portfolio. Design schemas, execute queries, handle migrations, and choose the right database for your workload.",
55
"author": {
66
"name": "Amazon Web Services",

plugins/databases-on-aws/skills/dsql/SKILL.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,11 @@ defaults that may change — when a user's decision depends on an exact limit, v
153153
| Max indexes per table | 24 | `aurora dsql index limits` |
154154
| Max columns per index | 8 | `aurora dsql index limits` |
155155
| IDENTITY/SEQUENCE CACHE values | 1 or >= 65536 | `aurora dsql sequence cache` |
156+
| Supported column data types | See docs | `aurora dsql supported data types` |
156157

157-
**When to verify:** Before recommending batch sizes, connection pool settings, or schema designs
158-
where hitting a limit would cause failures. No need to verify for general guidance or when
159-
the exact number doesn't affect the user's decision.
158+
**When to verify:** Before recommending batch sizes, connection pool settings, or schema designs where hitting a limit would cause failures; any time the exact number can affect user decision.
160159

161-
**Fallback:** If `awsknowledge` is unavailable, use the defaults above and note to the user
162-
that limits should be verified against [DSQL documentation](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/).
160+
**Fallback:** If `awsknowledge` is unavailable, use the defaults above and flag that limits should be verified against [DSQL documentation](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/).
163161

164162
## CLI Scripts Available
165163

@@ -208,7 +206,7 @@ ALTER COLUMN TYPE, DROP COLUMN, DROP CONSTRAINT → Table Recreation Pattern (Wo
208206
- MUST include tenant_id in all tables
209207
- MUST use `CREATE INDEX ASYNC` exclusively
210208
- MUST issue each DDL in its own transact call: `transact(["CREATE TABLE ..."])`
211-
- MUST store arrays/JSON as TEXT
209+
- MUST serialize arrays as TEXT or JSON; cast back at query time (`string_to_array(text, ',')` or `jsonb_array_elements_text(json::jsonb)`)
212210

213211
### Workflow 2: Safe Data Migration
214212

plugins/databases-on-aws/skills/dsql/references/development-guide.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ effortless scaling, multi-region viability, among other advantages.
1313
- **REQUIRED: Follow DDL Guidelines** - Refer to [DDL Rules](#schema-ddl-rules)
1414
- **SHALL repeatedly generate fresh tokens** - Refer to [Connection Limits](auth/authentication-guide.md#connection-rules)
1515
- **ALWAYS use ASYNC indexes** - `CREATE INDEX ASYNC` is mandatory
16-
- **MUST Serialize arrays/JSON as TEXT** - Store arrays/JSON as TEXT (comma separated, JSON.stringify)
16+
- **MUST serialize arrays as TEXT or JSON** - see [Schema Design Rules](#schema-design-rules)
17+
- **MUST cast to `JSONB` at query time** for JSONB operators — see [Supported Data Types](#supported-data-types)
1718
- **ALWAYS Batch within row limit** - maintain transaction limits (verify via `awsknowledge`: `aurora dsql transaction limits`)
1819
- **REQUIRED: Build and sanitize all SQL with `safe_query.build()`** - See [Input Validation](../mcp/tools/input-validation.md#required-pattern)
1920
- **MUST follow correct Application Layer Patterns** - when multi-tenant isolation or application referential integrity are required; refer to [Application Layer Patterns](#application-layer-patterns)
@@ -53,9 +54,8 @@ effortless scaling, multi-region viability, among other advantages.
5354

5455
### Schema Design Rules
5556

56-
- MUST use **simple PostgreSQL types:** VARCHAR, TEXT, INTEGER, BOOLEAN, TIMESTAMP
57-
- MUST store arrays as TEXT (comma-separated is recommended)
58-
- MUST store JSON objects as TEXT (JSON.stringify)
57+
- MUST verify column types via `awsknowledge`: `aurora dsql supported data types` or the [DSQL supported data types list](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-postgresql-compatibility-supported-data-types.html)
58+
- MUST serialize arrays as TEXT or JSON; cast back at query time via `string_to_array(text, ',')` or `jsonb_array_elements_text(json::jsonb)`
5959
- ALWAYS include tenant_id in tables for multi-tenant isolation
6060
- SHOULD create async indexes for tenant_id and common query patterns
6161

@@ -124,9 +124,9 @@ UPDATE table SET c = 'default' WHERE c IS NULL; ← AFTER ADD COLUMN
124124

125125
### Supported Data Types
126126

127-
```
128-
VARCHAR, TEXT, INTEGER, DECIMAL, BOOLEAN, TIMESTAMP, UUID
129-
```
127+
**MUST verify** column types against the [DSQL supported data types docs](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-postgresql-compatibility-supported-data-types.html) or via `awsknowledge`: `aurora dsql supported data types` — the supported set evolves, so do not treat any static list as exhaustive.
128+
129+
`JSONB`, arrays, and `INET` are **[runtime-only](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-postgresql-compatibility-supported-data-types.html#working-with-postgresql-compatibility-query-runtime)** — cast at query time
130130

131131
### Supported Key
132132

plugins/databases-on-aws/skills/dsql/references/examples/data-operations.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ async function batchInsert(pool, tenantId, items) {
5454
await client.query(
5555
`INSERT INTO entities (tenant_id, name, metadata)
5656
VALUES ($1, $2, $3)`,
57-
[tenantId, item.name, JSON.stringify(item.metadata)]
57+
[tenantId, item.name, item.metadata]
5858
);
5959
}
6060

@@ -105,7 +105,7 @@ async function processBatches(pool, tenantId, batches, startIdx, step) {
105105
for (const item of batch) {
106106
await client.query(
107107
'INSERT INTO entities (tenant_id, name, metadata) VALUES ($1, $2, $3)',
108-
[tenantId, item.name, JSON.stringify(item.metadata)]
108+
[tenantId, item.name, item.metadata]
109109
);
110110
}
111111

plugins/databases-on-aws/skills/dsql/references/examples/patterns.md

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,12 @@ INSERT INTO distributors VALUES (nextval('order_seq'), 'nothing');
129129

130130
---
131131

132-
## Data Serialization
132+
## Runtime-Only Types
133133

134-
**Pattern:** MUST store arrays and JSON as TEXT (runtime-only types). Per [DSQL docs](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-postgresql-compatibility-supported-data-types.html), cast to JSON at query time.
134+
`JSONB`, arrays, and `INET` are [runtime-only](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-postgresql-compatibility-supported-data-types.html#working-with-postgresql-compatibility-query-runtime) — not valid as column types.
135+
136+
- **MUST** serialize arrays as `TEXT` or `JSON` — use `TEXT` (comma-separated) for homogeneous short strings; use `JSON` when elements may contain commas or aren't homogeneous
137+
- **MUST** cast back at query time — `string_to_array(text, ',')` for TEXT, `jsonb_array_elements_text(json::jsonb)` for JSON
135138

136139
```javascript
137140
function toTextArray(values) {
@@ -142,32 +145,21 @@ function fromTextArray(textValue) {
142145
return textValue ? textValue.split(',').map(v => v.trim()) : [];
143146
}
144147

145-
function toTextJSON(object) {
146-
return JSON.stringify(object);
147-
}
148-
149-
function fromTextJSON(textValue) {
150-
if (!textValue) return null;
151-
try {
152-
return JSON.parse(textValue);
153-
} catch (err) {
154-
console.warn('Invalid JSON in column:', err.message);
155-
return null;
156-
}
157-
}
158-
159148
const categoriesText = toTextArray(['backend', 'api', 'database']);
160149
await pool.query('INSERT INTO projects (project_id, categories) VALUES ($1, $2)', [projectId, categoriesText]);
161150

162-
const configText = toTextJSON({ theme: 'dark', notifications: true });
163-
await pool.query('INSERT INTO user_settings (user_id, preferences) VALUES ($1, $2)', [userId, configText]);
151+
await pool.query(
152+
'INSERT INTO user_settings (user_id, preferences) VALUES ($1, $2)',
153+
[userId, { theme: 'dark', notifications: true }],
154+
);
164155
```
165156

166157
Query-time operations:
167158

168159
```sql
169-
SELECT user_id, preferences::jsonb->>'theme' as theme
170-
FROM user_settings WHERE preferences::jsonb->>'notifications' = 'true';
160+
SELECT user_id, preferences::jsonb->>'theme' AS theme
161+
FROM user_settings
162+
WHERE preferences::jsonb->>'notifications' = 'true';
171163

172-
SELECT project_id, string_to_array(categories, ',') as category_array FROM projects;
164+
SELECT project_id, string_to_array(categories, ',') AS category_array FROM projects;
173165
```

plugins/databases-on-aws/skills/dsql/references/mysql-migrations/full-example.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ transact([
4545
price DECIMAL(10,2) NOT NULL,
4646
category VARCHAR(255) DEFAULT 'other' CHECK (category IN ('electronics', 'clothing', 'food', 'other')),
4747
tags TEXT,
48-
metadata TEXT,
48+
metadata JSON,
4949
stock INTEGER DEFAULT 0 CHECK (stock >= 0),
5050
is_active BOOLEAN DEFAULT true,
5151
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
@@ -70,7 +70,7 @@ transact(["CREATE INDEX ASYNC idx_products_category ON products(tenant_id, categ
7070
| `MEDIUMTEXT` | `TEXT` |
7171
| `ENUM(...)` | `VARCHAR(255)` with `CHECK` constraint |
7272
| `SET(...)` | `TEXT` (comma-separated) |
73-
| `JSON` | `TEXT` (JSON.stringify) |
73+
| `JSON` | `JSON` |
7474
| `UNSIGNED` | `CHECK (col >= 0)` |
7575
| `TINYINT(1)` | `BOOLEAN` |
7676
| `DATETIME` | `TIMESTAMP` |
@@ -99,7 +99,6 @@ transact(["CREATE INDEX ASYNC idx_products_category ON products(tenant_id, categ
9999
- **MUST convert** AUTO_INCREMENT to UUID with gen_random_uuid(), IDENTITY column with `GENERATED AS IDENTITY (CACHE ...)`, or explicit SEQUENCE -- ALWAYS use `GENERATED AS IDENTITY` for auto-incrementing columns (see [AUTO_INCREMENT Migration](ddl-auto-increment.md#auto_increment-migration))
100100
- **MUST replace** ENUM with VARCHAR and CHECK constraint
101101
- **MUST replace** SET with TEXT (comma-separated)
102-
- **MUST replace** JSON columns with TEXT
103102
- **MUST replace** FOREIGN KEY constraints with application-layer referential integrity
104103
- **MUST replace** ON UPDATE CURRENT_TIMESTAMP with application-layer updates
105104
- **MUST convert** all index creation to use CREATE INDEX ASYNC

plugins/databases-on-aws/skills/dsql/references/mysql-migrations/type-mapping.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ Map MySQL data types to their DSQL equivalents.
9797

9898
| MySQL Type | DSQL Equivalent | Notes |
9999
| -------------- | --------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
100-
| JSON | TEXT | MUST store as TEXT |
100+
| JSON | `JSON` | Direct equivalent |
101101
| AUTO_INCREMENT | UUID with gen_random_uuid(), IDENTITY column, or SEQUENCE | See [AUTO_INCREMENT Migration](ddl-auto-increment.md#auto_increment-migration) for all three options |
102102

103103
---

plugins/databases-on-aws/skills/dsql/references/onboarding.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ These guidelines apply when users say "Get started with DSQL" or similar phrases
3535
- Example:
3636
- "What column names would you like in this table?"
3737
- "What is the column name of the primary key?"
38-
- "JSON must be serialized. Would you like to stringify the JSON to serialize it as TEXT?"
38+
- "Would you like to store this in a `JSON` column, or serialize as TEXT?"
3939

4040
**Examples:**
4141

@@ -252,7 +252,9 @@ cargo add aws-sdk-dsql tokio --features full
252252
- If yes, MUST verify DSQL compatibility:
253253
- No SERIAL types (use `GENERATED AS IDENTITY` with sequences, or UUID)
254254
- No foreign keys (implement in application)
255-
- No array/JSON column types (serialize as TEXT)
255+
- Serialize arrays as TEXT or JSON; cast back at query time (`string_to_array(text, ',')` / `jsonb_array_elements_text(json::jsonb)`)
256+
- Cast to `JSONB` at query time for JSONB operators (`JSONB` is not a valid column type)
257+
- Verify column types against the [supported data types list](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/working-with-postgresql-compatibility-supported-data-types.html)
256258
- Reference [`./development-guide.md`](./development-guide.md) for full constraints
257259

258260
**If no schema found:**
@@ -349,7 +351,7 @@ Let them know you're ready to help with more:
349351
**ALWAYS follow these rules:**
350352

351353
1. **Indexes:** Use `CREATE INDEX ASYNC` - synchronous index creation not supported
352-
2. **Serialization:** Store arrays/JSON as TEXT (comma-separated or JSON.stringify)
354+
2. **Runtime-only types:** Serialize arrays as TEXT or JSON; cast to `JSONB` at query time for JSONB operators
353355
3. **Referential Integrity:** Implement foreign key validation in application code
354356
4. **DDL Operations:** Execute one DDL per transaction, no mixing with DML
355357
5. **Transaction Limits:** Maximum 3,000 row modifications, 10 MiB data size per transaction

0 commit comments

Comments
 (0)