Skip to content

feat(typegen): add functions setof type introspection #971

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

avallete
Copy link
Member

@avallete avallete commented Aug 5, 2025

What kind of change does this PR introduce?

  • Add all the necessary informations for embeded functions type inferences to work in postgrest-js (see: feat(types): add embeded functions type inference postgrest-js#632 )

  • Canary tested that it's mostly retro-compatible by generating the types on the infrastructure codebase. The new type definition didn't raised much type errors but we don't use a lot of functions/rpc calls in it. So there is still a chance for this to break some codebases. Best approach might be to release this one as an -rc release so it can be opt-in via local cli echo "vXX-rc" > supabase/.temp/postgres-meta-version && supabase gen types

That way with a canary release of the postgrest-js and the supabase-js we might release gradually with a way for people to opt-out if it causes issue.

I'm open to suggestion about how to release this !

Closes: PGMETA-61

- Introspect the setof function fields for functions
- Restore functions as unions of args + returns
@avallete avallete force-pushed the feat/add-functions-setof-type-introspection-v2 branch from 317219e to 64a1afc Compare August 5, 2025 15:39
@coveralls
Copy link

coveralls commented Aug 6, 2025

Pull Request Test Coverage Report for Build 16782706401

Details

  • 324 of 326 (99.39%) changed or added relevant lines in 4 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.8%) to 76.959%

Changes Missing Coverage Covered Lines Changed/Added Lines %
src/server/templates/typescript.ts 317 319 99.37%
Totals Coverage Status
Change from base Build 16720965330: 0.8%
Covered Lines: 5374
Relevant Lines: 6904

💛 - Coveralls

@@ -33,7 +33,7 @@ export default class PostgresMetaTypes {
t.typrelid = 0
or (
select
c.relkind ${includeTableTypes ? `in ('c', 'r')` : `= 'c'`}
c.relkind ${includeTableTypes ? `in ('c', 'r', 'v')` : `= 'c'`}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment

Include functions that loops to a view for embedded functions.

select 1 from pg_class c
where c.oid = rt.typrelid
-- exclude custom types relation from what is considered a set of table
and c.relkind in ('r', 'p', 'v', 'm', 'f')
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment

All possible function embeding relations:

r | ordinary table
p | partitioned table
v | view
m | materialized view
f | foreign table

Comment on lines +38 to +42
for (const column of columns) {
if (column.table_id in columnsByTableId) {
columnsByTableId[column.table_id].push(column)
}
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment

Use traditional for loop to avoid the need to loop twice for filter then foreach/push.

Comment on lines +129 to +135
for (const schema in introspectionBySchema) {
introspectionBySchema[schema].tables.sort((a, b) => a.name.localeCompare(b.name))
introspectionBySchema[schema].views.sort((a, b) => a.name.localeCompare(b.name))
introspectionBySchema[schema].functions.sort((a, b) => a.fn.name.localeCompare(b.fn.name))
introspectionBySchema[schema].enums.sort((a, b) => a.name.localeCompare(b.name))
introspectionBySchema[schema].compositeTypes.sort((a, b) => a.name.localeCompare(b.name))
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment

Group the place where we sort things for consistency to dedup the places where sorts are needed.

// OR if the function takes a table row but doesn't qualify as embedded (for error reporting)
(inArgs[0].table_name && !func.return_table_name)))
) {
introspectionBySchema[func.schema].functions.push({ fn: func, inArgs })
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment

We save the inArgs along with the function definition as it'll be needed in many places when generating the function return types. Since it's already available keep it along for re-use.

if (conflictingFns.length > 0) {
const conflictingFn = conflictingFns[0]
const returnTypeName = typesById[conflictingFn.fn.return_type_id]?.name || 'unknown'
return `Could not choose the best candidate function between: ${schema.name}.${fn.name}(), ${schema.name}.${fn.name}( => ${returnTypeName}). Try renaming the parameters or the function itself in the database so function overloading can be resolved`
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment

This'll be used to warn the user at compile time that his function won't be available in postgrest due to conflicts.

}
${
'is_updatable' in view && view.is_updatable
view.is_updatable
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +619 to +623
for (const fnName in schemaFunctionsGroupedByName) {
schemaFunctionsGroupedByName[fnName].sort((a, b) =>
b.fn.definition.localeCompare(a.fn.definition)
)
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment

With functions having multiple definition overrides (same name) we sort them by definition text value. We might want to do another approach to have more stability 🤔

@avallete avallete marked this pull request as ready for review August 6, 2025 17:27
@avallete avallete requested review from a team as code owners August 6, 2025 17:27
@avallete avallete requested a review from soedirgo August 7, 2025 08:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants