diff --git a/src/lib/PostgresMetaTypes.ts b/src/lib/PostgresMetaTypes.ts index bcf5b609..35371d55 100644 --- a/src/lib/PostgresMetaTypes.ts +++ b/src/lib/PostgresMetaTypes.ts @@ -11,6 +11,7 @@ export default class PostgresMetaTypes { } async list({ + includeTableTypes = false, includeArrayTypes = false, includeSystemSchemas = false, includedSchemas, @@ -18,6 +19,7 @@ export default class PostgresMetaTypes { limit, offset, }: { + includeTableTypes?: boolean includeArrayTypes?: boolean includeSystemSchemas?: boolean includedSchemas?: string[] @@ -25,7 +27,20 @@ export default class PostgresMetaTypes { limit?: number offset?: number } = {}): Promise> { - let sql = typesSql + let sql = `${typesSql} + where + ( + t.typrelid = 0 + or ( + select + c.relkind ${includeTableTypes ? `in ('c', 'r')` : `= 'c'`} + from + pg_class c + where + c.oid = t.typrelid + ) + ) + ` if (!includeArrayTypes) { sql += ` and not exists ( select diff --git a/src/lib/generators.ts b/src/lib/generators.ts index 58c39a26..c916a44c 100644 --- a/src/lib/generators.ts +++ b/src/lib/generators.ts @@ -4,13 +4,13 @@ import { PostgresForeignTable, PostgresFunction, PostgresMaterializedView, + PostgresMetaResult, PostgresRelationship, PostgresSchema, PostgresTable, PostgresType, PostgresView, } from './types.js' -import { PostgresMetaResult } from './types.js' export type GeneratorMetadata = { schemas: PostgresSchema[] @@ -98,6 +98,7 @@ export async function getGeneratorMetadata( } const { data: types, error: typesError } = await pgMeta.types.list({ + includeTableTypes: true, includeArrayTypes: true, includeSystemSchemas: true, }) diff --git a/src/lib/sql/types.sql b/src/lib/sql/types.sql index d0974012..7a628ed1 100644 --- a/src/lib/sql/types.sql +++ b/src/lib/sql/types.sql @@ -33,15 +33,3 @@ from group by c.oid ) as t_attributes on t_attributes.oid = t.typrelid -where - ( - t.typrelid = 0 - or ( - select - c.relkind = 'c' - from - pg_class c - where - c.oid = t.typrelid - ) - ) diff --git a/src/server/server.ts b/src/server/server.ts index 7d0ae129..f30d8d30 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -77,6 +77,7 @@ async function getTypeOutput(): Promise { GENERATE_TYPES_INCLUDED_SCHEMAS.length > 0 ? GENERATE_TYPES_INCLUDED_SCHEMAS : undefined, }), pgMeta.types.list({ + includeTableTypes: true, includeArrayTypes: true, includeSystemSchemas: true, }), diff --git a/test/db/00-init.sql b/test/db/00-init.sql index e28a0b16..07fdecfe 100644 --- a/test/db/00-init.sql +++ b/test/db/00-init.sql @@ -137,3 +137,7 @@ create table table_with_primary_key_other_than_id ( other_id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name text ); + +create type composite_type_with_record_attribute as ( + todo todos +); diff --git a/test/lib/types.ts b/test/lib/types.ts index 0c77966a..fb8c8f30 100644 --- a/test/lib/types.ts +++ b/test/lib/types.ts @@ -57,6 +57,37 @@ test('list types with excluded schemas and include System Schemas', async () => }) }) +test('list types with include Table Types', async () => { + const res = await pgMeta.types.list({ + includeTableTypes: true, + }) + + expect(res.data?.find(({ name }) => name === 'todos')).toMatchInlineSnapshot( + { id: expect.any(Number) }, + ` + { + "attributes": [], + "comment": null, + "enums": [], + "format": "todos", + "id": Any, + "name": "todos", + "schema": "public", + } + ` + ) +}) + +test('list types without Table Types', async () => { + const res = await pgMeta.types.list({ + includeTableTypes: false, + }) + + res.data?.forEach((type) => { + expect(type.name).not.toBe('todos') + }) +}) + test('composite type attributes', async () => { await pgMeta.query(`create type test_composite as (id int8, data text);`) diff --git a/test/server/typegen.ts b/test/server/typegen.ts index 63569fb8..9f53b1a9 100644 --- a/test/server/typegen.ts +++ b/test/server/typegen.ts @@ -333,31 +333,31 @@ test('typegen: typescript', async () => { Functions: { blurb: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: string } blurb_varchar: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: string } details_is_long: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: boolean } details_length: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: number } details_words: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: string[] } @@ -424,6 +424,9 @@ test('typegen: typescript', async () => { composite_type_with_array_attribute: { my_text_array: string[] | null } + composite_type_with_record_attribute: { + todo: Database["public"]["Tables"]["todos"]["Row"] | null + } } } } @@ -877,31 +880,31 @@ test('typegen w/ one-to-one relationships', async () => { Functions: { blurb: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: string } blurb_varchar: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: string } details_is_long: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: boolean } details_length: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: number } details_words: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: string[] } @@ -968,6 +971,9 @@ test('typegen w/ one-to-one relationships', async () => { composite_type_with_array_attribute: { my_text_array: string[] | null } + composite_type_with_record_attribute: { + todo: Database["public"]["Tables"]["todos"]["Row"] | null + } } } } @@ -1421,31 +1427,31 @@ test('typegen: typescript w/ one-to-one relationships', async () => { Functions: { blurb: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: string } blurb_varchar: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: string } details_is_long: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: boolean } details_length: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: number } details_words: { Args: { - "": unknown + "": Database["public"]["Tables"]["todos"]["Row"] } Returns: string[] } @@ -1512,6 +1518,9 @@ test('typegen: typescript w/ one-to-one relationships', async () => { composite_type_with_array_attribute: { my_text_array: string[] | null } + composite_type_with_record_attribute: { + todo: Database["public"]["Tables"]["todos"]["Row"] | null + } } } } @@ -1803,6 +1812,10 @@ test('typegen: go', async () => { type PublicCompositeTypeWithArrayAttribute struct { MyTextArray interface{} \`json:"my_text_array"\` + } + + type PublicCompositeTypeWithRecordAttribute struct { + Todo interface{} \`json:"todo"\` }" `) }) @@ -2144,6 +2157,12 @@ test('typegen: swift', async () => { case MyTextArray = "my_text_array" } } + internal struct CompositeTypeWithRecordAttribute: Codable, Hashable, Sendable { + internal let Todo: TodosSelect + internal enum CodingKeys: String, CodingKey { + case Todo = "todo" + } + } }" `) }) @@ -2489,6 +2508,12 @@ test('typegen: swift w/ public access control', async () => { case MyTextArray = "my_text_array" } } + public struct CompositeTypeWithRecordAttribute: Codable, Hashable, Sendable { + public let Todo: TodosSelect + public enum CodingKeys: String, CodingKey { + case Todo = "todo" + } + } }" `) })