Skip to content

Commit 185eac0

Browse files
authored
chore(typegen): add canary python types runtime (#1028)
* chore(typegen): add canary python types runtime * chore(ci): test workflow on PR * chore: remove cache * Revert "fix(typegen): python type missing uuid import (#1027)" This reverts commit 2c41dd9. * fix: add uuid to db * chore: use mypy for lint check * Reapply "fix(typegen): python type missing uuid import (#1027)" This reverts commit 0d74cdc. * chore: normalize uuid in tests snapshots
1 parent 2c41dd9 commit 185eac0

File tree

11 files changed

+518
-291
lines changed

11 files changed

+518
-291
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: Validate Python Type Generation
2+
3+
on:
4+
push:
5+
branches: [master]
6+
pull_request:
7+
branches: [master]
8+
9+
jobs:
10+
validate-python-types:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v4
16+
17+
- name: Set up Node.js
18+
uses: actions/setup-node@v4
19+
with:
20+
node-version: '20'
21+
cache: 'npm'
22+
23+
- name: Install dependencies
24+
run: npm ci
25+
26+
- name: Build project
27+
run: npm run build
28+
29+
- name: Set up Python
30+
uses: actions/setup-python@v5
31+
with:
32+
python-version: '3.11'
33+
34+
- name: Install Python dependencies
35+
run: |
36+
pip install pydantic mypy
37+
38+
- name: Start test database
39+
working-directory: test/db
40+
run: |
41+
docker compose up -d --wait
42+
43+
- name: Wait for database to be ready
44+
run: |
45+
# Install PostgreSQL client for health check
46+
sudo apt-get update && sudo apt-get install -y postgresql-client
47+
until pg_isready -h localhost -p 5432 -U postgres; do
48+
echo "Waiting for database..."
49+
sleep 1
50+
done
51+
echo "Database is ready!"
52+
53+
- name: Generate Python types
54+
id: generate-types
55+
run: |
56+
node --loader ts-node/esm scripts/generate-python-types-test.ts > generated_types.py
57+
echo "Generated Python types (first 30 lines):"
58+
head -30 generated_types.py
59+
60+
- name: Validate Python types runtime
61+
run: |
62+
python -c "import generated_types; print('✓ Generated Python types are valid and can be imported')"
63+
64+
- name: Validate Python types with mypy
65+
run: |
66+
mypy generated_types.py --strict
67+
68+
- name: Cleanup
69+
if: always()
70+
working-directory: test/db
71+
run: docker compose down
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Script to generate Python types for CI validation
5+
* This script uses the test database setup to generate Python types
6+
*/
7+
8+
import { build } from '../src/server/app.js'
9+
10+
const TEST_CONNECTION_STRING = 'postgresql://postgres:postgres@localhost:5432'
11+
12+
async function generatePythonTypes() {
13+
const app = build()
14+
15+
try {
16+
const response = await app.inject({
17+
method: 'GET',
18+
url: '/generators/python',
19+
headers: {
20+
pg: TEST_CONNECTION_STRING,
21+
},
22+
query: {
23+
access_control: 'public',
24+
},
25+
})
26+
27+
if (response.statusCode !== 200) {
28+
console.error(`Failed to generate types: ${response.statusCode}`)
29+
console.error(response.body)
30+
process.exit(1)
31+
}
32+
33+
// Write to stdout so it can be captured
34+
process.stdout.write(response.body)
35+
} catch (error) {
36+
console.error('Error generating Python types:', error)
37+
process.exit(1)
38+
} finally {
39+
await app.close()
40+
}
41+
}
42+
43+
generatePythonTypes()
44+

test/db/00-init.sql

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ CREATE TABLE public.users (
99
id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
1010
name text,
1111
status user_status DEFAULT 'ACTIVE',
12-
decimal numeric
12+
decimal numeric,
13+
user_uuid uuid DEFAULT gen_random_uuid()
1314
);
1415
INSERT INTO
1516
public.users (name)

test/lib/functions.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,15 @@ test('list set-returning function with single object limit', async () => {
7575
"definition": "
7676
SELECT * FROM public.users_audit WHERE user_id = user_row.id;
7777
",
78-
"id": 16506,
78+
"id": 16507,
7979
"identity_argument_types": "user_row users",
8080
"is_set_returning_function": true,
8181
"language": "sql",
8282
"name": "get_user_audit_setof_single_row",
8383
"prorows": 1,
8484
"return_type": "SETOF users_audit",
85-
"return_type_id": 16418,
86-
"return_type_relation_id": 16416,
85+
"return_type_id": 16419,
86+
"return_type_relation_id": 16417,
8787
"schema": "public",
8888
"security_definer": false,
8989
},
@@ -118,15 +118,15 @@ test('list set-returning function with multiples definitions', async () => {
118118
"definition": "
119119
SELECT * FROM public.todos WHERE "user-id" = user_row.id;
120120
",
121-
"id": 16509,
121+
"id": 16510,
122122
"identity_argument_types": "user_row users",
123123
"is_set_returning_function": true,
124124
"language": "sql",
125125
"name": "get_todos_setof_rows",
126126
"prorows": 1000,
127127
"return_type": "SETOF todos",
128-
"return_type_id": 16404,
129-
"return_type_relation_id": 16402,
128+
"return_type_id": 16405,
129+
"return_type_relation_id": 16403,
130130
"schema": "public",
131131
"security_definer": false,
132132
},
@@ -136,7 +136,7 @@ test('list set-returning function with multiples definitions', async () => {
136136
"has_default": false,
137137
"mode": "in",
138138
"name": "todo_row",
139-
"type_id": 16404,
139+
"type_id": 16405,
140140
},
141141
],
142142
"argument_types": "todo_row todos",
@@ -153,15 +153,15 @@ test('list set-returning function with multiples definitions', async () => {
153153
"definition": "
154154
SELECT * FROM public.todos WHERE "user-id" = todo_row."user-id";
155155
",
156-
"id": 16510,
156+
"id": 16511,
157157
"identity_argument_types": "todo_row todos",
158158
"is_set_returning_function": true,
159159
"language": "sql",
160160
"name": "get_todos_setof_rows",
161161
"prorows": 1000,
162162
"return_type": "SETOF todos",
163-
"return_type_id": 16404,
164-
"return_type_relation_id": 16402,
163+
"return_type_id": 16405,
164+
"return_type_relation_id": 16403,
165165
"schema": "public",
166166
"security_definer": false,
167167
},

test/lib/tables.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,24 @@ test('list', async () => {
117117
"schema": "public",
118118
"table": "users",
119119
},
120+
{
121+
"check": null,
122+
"comment": null,
123+
"data_type": "uuid",
124+
"default_value": "gen_random_uuid()",
125+
"enums": [],
126+
"format": "uuid",
127+
"identity_generation": null,
128+
"is_generated": false,
129+
"is_identity": false,
130+
"is_nullable": true,
131+
"is_unique": false,
132+
"is_updatable": true,
133+
"name": "user_uuid",
134+
"ordinal_position": 5,
135+
"schema": "public",
136+
"table": "users",
137+
},
120138
],
121139
"comment": null,
122140
"dead_rows_estimate": Any<Number>,

test/lib/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ test('list types with include Table Types', async () => {
7474
"id": Any<Number>,
7575
"name": "todos",
7676
"schema": "public",
77-
"type_relation_id": 16402,
77+
"type_relation_id": 16403,
7878
}
7979
`
8080
)

test/lib/views.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ test('list', async () => {
1515
"default_value": null,
1616
"enums": [],
1717
"format": "int8",
18-
"id": "16423.1",
18+
"id": "16424.1",
1919
"identity_generation": null,
2020
"is_generated": false,
2121
"is_identity": false,
@@ -26,7 +26,7 @@ test('list', async () => {
2626
"ordinal_position": 1,
2727
"schema": "public",
2828
"table": "todos_view",
29-
"table_id": 16423,
29+
"table_id": 16424,
3030
},
3131
{
3232
"check": null,
@@ -35,7 +35,7 @@ test('list', async () => {
3535
"default_value": null,
3636
"enums": [],
3737
"format": "text",
38-
"id": "16423.2",
38+
"id": "16424.2",
3939
"identity_generation": null,
4040
"is_generated": false,
4141
"is_identity": false,
@@ -46,7 +46,7 @@ test('list', async () => {
4646
"ordinal_position": 2,
4747
"schema": "public",
4848
"table": "todos_view",
49-
"table_id": 16423,
49+
"table_id": 16424,
5050
},
5151
{
5252
"check": null,
@@ -55,7 +55,7 @@ test('list', async () => {
5555
"default_value": null,
5656
"enums": [],
5757
"format": "int8",
58-
"id": "16423.3",
58+
"id": "16424.3",
5959
"identity_generation": null,
6060
"is_generated": false,
6161
"is_identity": false,
@@ -66,7 +66,7 @@ test('list', async () => {
6666
"ordinal_position": 3,
6767
"schema": "public",
6868
"table": "todos_view",
69-
"table_id": 16423,
69+
"table_id": 16424,
7070
},
7171
],
7272
"comment": null,
@@ -112,7 +112,7 @@ test('retrieve', async () => {
112112
"default_value": null,
113113
"enums": [],
114114
"format": "int8",
115-
"id": "16423.1",
115+
"id": "16424.1",
116116
"identity_generation": null,
117117
"is_generated": false,
118118
"is_identity": false,
@@ -123,7 +123,7 @@ test('retrieve', async () => {
123123
"ordinal_position": 1,
124124
"schema": "public",
125125
"table": "todos_view",
126-
"table_id": 16423,
126+
"table_id": 16424,
127127
},
128128
{
129129
"check": null,
@@ -132,7 +132,7 @@ test('retrieve', async () => {
132132
"default_value": null,
133133
"enums": [],
134134
"format": "text",
135-
"id": "16423.2",
135+
"id": "16424.2",
136136
"identity_generation": null,
137137
"is_generated": false,
138138
"is_identity": false,
@@ -143,7 +143,7 @@ test('retrieve', async () => {
143143
"ordinal_position": 2,
144144
"schema": "public",
145145
"table": "todos_view",
146-
"table_id": 16423,
146+
"table_id": 16424,
147147
},
148148
{
149149
"check": null,
@@ -152,7 +152,7 @@ test('retrieve', async () => {
152152
"default_value": null,
153153
"enums": [],
154154
"format": "int8",
155-
"id": "16423.3",
155+
"id": "16424.3",
156156
"identity_generation": null,
157157
"is_generated": false,
158158
"is_identity": false,
@@ -163,7 +163,7 @@ test('retrieve', async () => {
163163
"ordinal_position": 3,
164164
"schema": "public",
165165
"table": "todos_view",
166-
"table_id": 16423,
166+
"table_id": 16424,
167167
},
168168
],
169169
"comment": null,

test/server/indexes.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ test('list indexes', async () => {
2222
0,
2323
],
2424
"comment": null,
25-
"id": 16399,
25+
"id": 16400,
2626
"index_attributes": [
2727
{
2828
"attribute_name": "id",
@@ -57,7 +57,7 @@ test('list indexes', async () => {
5757
})
5858

5959
test('retrieve index', async () => {
60-
const res = await app.inject({ method: 'GET', path: '/indexes/16399' })
60+
const res = await app.inject({ method: 'GET', path: '/indexes/16400' })
6161
const index = res.json<PostgresIndex>()
6262
expect(index).toMatchInlineSnapshot(
6363
`
@@ -71,7 +71,7 @@ test('retrieve index', async () => {
7171
0,
7272
],
7373
"comment": null,
74-
"id": 16399,
74+
"id": 16400,
7575
"index_attributes": [
7676
{
7777
"attribute_name": "id",

0 commit comments

Comments
 (0)