Skip to content

Commit 175e313

Browse files
committed
fix(types): include views types
1 parent 3b3ea92 commit 175e313

File tree

5 files changed

+333
-12
lines changed

5 files changed

+333
-12
lines changed

src/lib/PostgresMetaTypes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export default class PostgresMetaTypes {
3333
t.typrelid = 0
3434
or (
3535
select
36-
c.relkind ${includeTableTypes ? `in ('c', 'r')` : `= 'c'`}
36+
c.relkind ${includeTableTypes ? `in ('c', 'r', 'v')` : `= 'c'`}
3737
from
3838
pg_class c
3939
where

src/server/templates/typescript.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ export const apply = async ({
2727
const columnsByTableId = Object.fromEntries<PostgresColumn[]>(
2828
[...tables, ...foreignTables, ...views, ...materializedViews].map((t) => [t.id, []])
2929
)
30+
// group types by id for quicker lookup
31+
const typesById = types.reduce(
32+
(acc, type) => {
33+
acc[type.id] = type
34+
return acc
35+
},
36+
{} as Record<string, (typeof types)[number]>
37+
)
3038
columns
3139
.filter((c) => c.table_id in columnsByTableId)
3240
.sort(({ name: a }, { name: b }) => a.localeCompare(b))
@@ -45,6 +53,7 @@ export type Database = {
4553
const schemaViews = [...views, ...materializedViews]
4654
.filter((view) => view.schema === schema.name)
4755
.sort(({ name: a }, { name: b }) => a.localeCompare(b))
56+
4857
const schemaFunctions = functions
4958
.filter((func) => {
5059
if (func.schema !== schema.name) {
@@ -94,7 +103,7 @@ export type Database = {
94103
...schemaFunctions
95104
.filter((fn) => fn.argument_types === table.name)
96105
.map((fn) => {
97-
const type = types.find(({ id }) => id === fn.return_type_id)
106+
const type = typesById[fn.return_type_id]
98107
let tsType = 'unknown'
99108
if (type) {
100109
tsType = pgTypeToTsType(type.name, { types, schemas, tables, views })
@@ -285,9 +294,8 @@ export type Database = {
285294
if (inArgs.length === 0) {
286295
return 'Record<PropertyKey, never>'
287296
}
288-
289297
const argsNameAndType = inArgs.map(({ name, type_id, has_default }) => {
290-
const type = types.find(({ id }) => id === type_id)
298+
const type = typesById[type_id]
291299
let tsType = 'unknown'
292300
if (type) {
293301
tsType = pgTypeToTsType(type.name, { types, schemas, tables, views })
@@ -351,10 +359,15 @@ export type Database = {
351359
? `SetofOptions: {
352360
from: ${fns
353361
// if the function take a row as first parameter
354-
.filter((fnd) => fnd.args.length === 1 && fnd.args[0].table_name)
362+
.filter(
363+
(fnd) =>
364+
fnd.args.length === 1 &&
365+
fnd.args[0].table_name &&
366+
typesById[fnd.args[0].type_id]
367+
)
355368
.map((fnd) => {
356-
const arg_type = types.find((t) => t.id === fnd.args[0].type_id)
357-
return JSON.stringify(arg_type?.format)
369+
const tableType = typesById[fnd.args[0].type_id]
370+
return JSON.stringify(tableType.format)
358371
})
359372
.join(' | ')}
360373
to: ${JSON.stringify(fns[0].return_table_name)}

test/db/00-init.sql

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ $$ language plpgsql;
5555
CREATE VIEW todos_view AS SELECT * FROM public.todos;
5656
-- For testing typegen on view-to-view relationships
5757
create view users_view as select * from public.users;
58+
-- Create a more complex view for testing
59+
CREATE VIEW user_todos_summary_view AS
60+
SELECT
61+
u.id as user_id,
62+
u.name as user_name,
63+
u.status as user_status,
64+
COUNT(t.id) as todo_count,
65+
array_agg(t.details) FILTER (WHERE t.details IS NOT NULL) as todo_details
66+
FROM public.users u
67+
LEFT JOIN public.todos t ON t."user-id" = u.id
68+
GROUP BY u.id, u.name, u.status;
5869

5970
create materialized view todos_matview as select * from public.todos;
6071

@@ -210,3 +221,52 @@ LANGUAGE SQL STABLE
210221
AS $$
211222
SELECT id FROM public.users;
212223
$$;
224+
225+
226+
-- Function returning view using scalar as input
227+
CREATE OR REPLACE FUNCTION public.get_single_user_summary_from_view(search_user_id bigint)
228+
RETURNS SETOF user_todos_summary_view
229+
LANGUAGE SQL STABLE
230+
ROWS 1
231+
AS $$
232+
SELECT * FROM user_todos_summary_view WHERE user_id = search_user_id;
233+
$$;
234+
-- Function returning view using table row as input
235+
CREATE OR REPLACE FUNCTION public.get_single_user_summary_from_view(user_row users)
236+
RETURNS SETOF user_todos_summary_view
237+
LANGUAGE SQL STABLE
238+
ROWS 1
239+
AS $$
240+
SELECT * FROM user_todos_summary_view WHERE user_id = user_row.id;
241+
$$;
242+
-- Function returning view using another view row as input
243+
CREATE OR REPLACE FUNCTION public.get_single_user_summary_from_view(userview_row users_view)
244+
RETURNS SETOF user_todos_summary_view
245+
LANGUAGE SQL STABLE
246+
ROWS 1
247+
AS $$
248+
SELECT * FROM user_todos_summary_view WHERE user_id = userview_row.id;
249+
$$;
250+
251+
252+
-- Function returning view using scalar as input
253+
CREATE OR REPLACE FUNCTION public.get_todos_from_user(search_user_id bigint)
254+
RETURNS SETOF todos
255+
LANGUAGE SQL STABLE
256+
AS $$
257+
SELECT * FROM todos WHERE "user-id" = search_user_id;
258+
$$;
259+
-- Function returning view using table row as input
260+
CREATE OR REPLACE FUNCTION public.get_todos_from_user(user_row users)
261+
RETURNS SETOF todos
262+
LANGUAGE SQL STABLE
263+
AS $$
264+
SELECT * FROM todos WHERE "user-id" = user_row.id;
265+
$$;
266+
-- Function returning view using another view row as input
267+
CREATE OR REPLACE FUNCTION public.get_todos_from_user(userview_row users_view)
268+
RETURNS SETOF todos
269+
LANGUAGE SQL STABLE
270+
AS $$
271+
SELECT * FROM todos WHERE "user-id" = userview_row.id;
272+
$$;

test/lib/functions.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ test('list set-returning function with single object limit', async () => {
8080
"definition": "
8181
SELECT * FROM public.users_audit WHERE user_id = user_row.id;
8282
",
83-
"id": 16498,
83+
"id": 16502,
8484
"identity_argument_types": "user_row users",
8585
"is_set_returning_function": true,
8686
"language": "sql",
@@ -126,7 +126,7 @@ test('list set-returning function with multiples definitions', async () => {
126126
"definition": "
127127
SELECT * FROM public.todos WHERE "user-id" = user_row.id;
128128
",
129-
"id": 16499,
129+
"id": 16503,
130130
"identity_argument_types": "user_row users",
131131
"is_set_returning_function": true,
132132
"language": "sql",
@@ -164,7 +164,7 @@ test('list set-returning function with multiples definitions', async () => {
164164
"definition": "
165165
SELECT * FROM public.todos WHERE "user-id" = todo_row."user-id";
166166
",
167-
"id": 16500,
167+
"id": 16504,
168168
"identity_argument_types": "todo_row todos",
169169
"is_set_returning_function": true,
170170
"language": "sql",

0 commit comments

Comments
 (0)