Skip to content

Commit 598d0e2

Browse files
committed
feat: US-023 - Add pg-types e2e-docker fixture for data type coverage
1 parent 7503343 commit 598d0e2

5 files changed

Lines changed: 146 additions & 2 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"entry": "src/index.js",
3+
"expectation": "pass",
4+
"services": ["postgres"]
5+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"name": "e2e-docker-pg-types",
3+
"private": true,
4+
"type": "commonjs",
5+
"dependencies": {
6+
"pg": "8.13.1"
7+
}
8+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
const { Client } = require("pg");
2+
3+
async function main() {
4+
const client = new Client({
5+
host: process.env.PG_HOST,
6+
port: Number(process.env.PG_PORT),
7+
user: "testuser",
8+
password: "testpass",
9+
database: "testdb",
10+
});
11+
12+
await client.connect();
13+
14+
// Create table with diverse column types
15+
await client.query(`
16+
CREATE TABLE IF NOT EXISTS test_types (
17+
id SERIAL PRIMARY KEY,
18+
col_json JSON,
19+
col_jsonb JSONB,
20+
col_timestamptz TIMESTAMPTZ,
21+
col_boolean BOOLEAN,
22+
col_bytea BYTEA,
23+
col_int_arr INTEGER[],
24+
col_text_arr TEXT[],
25+
col_uuid UUID,
26+
col_numeric NUMERIC
27+
)
28+
`);
29+
30+
// Fixed test values for deterministic output
31+
const testJson = { key: "value", nested: { a: 1 } };
32+
const testJsonb = { tags: ["alpha", "beta"], count: 42 };
33+
const testTimestamp = "2024-01-15T12:30:00.000Z";
34+
const testBoolean = true;
35+
const testBytea = Buffer.from("hello bytea world");
36+
const testIntArr = [10, 20, 30];
37+
const testTextArr = ["foo", "bar", "baz"];
38+
const testUuid = "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11";
39+
const testNumeric = "12345.6789";
40+
41+
// Insert row with all types
42+
await client.query(
43+
`INSERT INTO test_types
44+
(col_json, col_jsonb, col_timestamptz, col_boolean, col_bytea,
45+
col_int_arr, col_text_arr, col_uuid, col_numeric)
46+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
47+
[
48+
JSON.stringify(testJson),
49+
JSON.stringify(testJsonb),
50+
testTimestamp,
51+
testBoolean,
52+
testBytea,
53+
testIntArr,
54+
testTextArr,
55+
testUuid,
56+
testNumeric,
57+
],
58+
);
59+
60+
// Read back and verify types
61+
const res = await client.query("SELECT * FROM test_types WHERE id = 1");
62+
const row = res.rows[0];
63+
64+
const results = {
65+
rowCount: res.rowCount,
66+
json: {
67+
value: row.col_json,
68+
type: typeof row.col_json,
69+
isObject: typeof row.col_json === "object" && row.col_json !== null,
70+
},
71+
jsonb: {
72+
value: row.col_jsonb,
73+
type: typeof row.col_jsonb,
74+
isObject: typeof row.col_jsonb === "object" && row.col_jsonb !== null,
75+
},
76+
timestamptz: {
77+
isDate: row.col_timestamptz instanceof Date,
78+
isoString: row.col_timestamptz instanceof Date
79+
? row.col_timestamptz.toISOString()
80+
: String(row.col_timestamptz),
81+
},
82+
boolean: {
83+
value: row.col_boolean,
84+
type: typeof row.col_boolean,
85+
},
86+
bytea: {
87+
isBuffer: Buffer.isBuffer(row.col_bytea),
88+
length: row.col_bytea.length,
89+
decoded: row.col_bytea.toString("utf8"),
90+
},
91+
intArray: {
92+
value: row.col_int_arr,
93+
isArray: Array.isArray(row.col_int_arr),
94+
elemType: typeof row.col_int_arr[0],
95+
},
96+
textArray: {
97+
value: row.col_text_arr,
98+
isArray: Array.isArray(row.col_text_arr),
99+
},
100+
uuid: {
101+
value: row.col_uuid,
102+
type: typeof row.col_uuid,
103+
},
104+
numeric: {
105+
value: row.col_numeric,
106+
type: typeof row.col_numeric,
107+
},
108+
};
109+
110+
// Cleanup
111+
await client.query("DROP TABLE test_types");
112+
await client.end();
113+
114+
console.log(JSON.stringify(results));
115+
}
116+
117+
main().catch((err) => {
118+
console.error(err.message);
119+
process.exit(1);
120+
});

progress.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2751,3 +2751,14 @@ PRD: ralph/kernel-hardening (46 stories)
27512751
- Concurrent queries via Promise.all through the pool work correctly — the sandbox handles multiple simultaneous TCP connections through the net bridge
27522752
- pg-pool fixture follows the exact same pattern as pg-connect (same pg version, same env vars, same error handling)
27532753
---
2754+
2755+
## 2026-03-19 - US-023
2756+
- Added pg-types e2e-docker fixture for data type coverage
2757+
- Fixture creates table with JSON, JSONB, TIMESTAMPTZ, BOOLEAN, BYTEA, INTEGER[], TEXT[], UUID, NUMERIC columns
2758+
- Inserts fixed deterministic values, reads back, verifies JavaScript types (typeof, instanceof, isArray, isBuffer)
2759+
- Files changed: packages/secure-exec/tests/e2e-docker/pg-types/{package.json,fixture.json,src/index.js}
2760+
- **Learnings for future iterations:**
2761+
- pg type parsers work correctly through the sandbox — JSON/JSONB return objects, TIMESTAMPTZ returns Date, BYTEA returns Buffer, arrays return Array, UUID/NUMERIC return strings
2762+
- Buffer round-trip through BYTEA works via parameterized queries ($1) — pg handles Buffer serialization to bytea wire format in user-space JS
2763+
- No additional bridge fixes needed for type parsing — all type coercion happens in pg's JS type parser code
2764+
---

scripts/ralph/prd.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,8 @@
410410
"Tests pass"
411411
],
412412
"priority": 23,
413-
"passes": false,
414-
"notes": "Only TEXT and SERIAL are tested. Type parsing in node-pg relies on Buffer, crypto, and type parser functions that the sandbox may not fully support. JSON/JSONB round-trip is especially important for real-world apps."
413+
"passes": true,
414+
"notes": "Completed. Fixture pg-types creates table with JSON, JSONB, TIMESTAMPTZ, BOOLEAN, BYTEA, INTEGER[], TEXT[], UUID, NUMERIC columns. Inserts fixed test values, reads back, verifies JavaScript types (object for JSON, Date for timestamp, Buffer for bytea, Array for arrays). Host and sandbox produce identical output."
415415
},
416416
{
417417
"id": "US-024",

0 commit comments

Comments
 (0)