Skip to content

Commit

Permalink
feat: generate types for foreign tables
Browse files Browse the repository at this point in the history
  • Loading branch information
soedirgo committed Mar 22, 2024
1 parent dd47c6d commit 1a52837
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 70 deletions.
14 changes: 13 additions & 1 deletion src/lib/PostgresMetaForeignTables.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { literal } from 'pg-format'
import { coalesceRowsToArray } from './helpers.js'
import { coalesceRowsToArray, filterByList } from './helpers.js'
import { columnsSql, foreignTablesSql } from './sql/index.js'
import { PostgresMetaResult, PostgresForeignTable } from './types.js'

Expand All @@ -11,25 +11,37 @@ export default class PostgresMetaForeignTables {
}

async list(options: {
includedSchemas?: string[]
excludedSchemas?: string[]
limit?: number
offset?: number
includeColumns: false
}): Promise<PostgresMetaResult<(PostgresForeignTable & { columns: never })[]>>
async list(options?: {
includedSchemas?: string[]
excludedSchemas?: string[]
limit?: number
offset?: number
includeColumns?: boolean
}): Promise<PostgresMetaResult<(PostgresForeignTable & { columns: unknown[] })[]>>
async list({
includedSchemas,
excludedSchemas,
limit,
offset,
includeColumns = true,
}: {
includedSchemas?: string[]
excludedSchemas?: string[]
limit?: number
offset?: number
includeColumns?: boolean
} = {}): Promise<PostgresMetaResult<PostgresForeignTable[]>> {
let sql = generateEnrichedForeignTablesSql({ includeColumns })
const filter = filterByList(includedSchemas, excludedSchemas)
if (filter) {
sql += ` where schema ${filter}`
}
if (limit) {
sql += ` limit ${limit}`
}
Expand Down
12 changes: 12 additions & 0 deletions src/lib/generators.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import PostgresMeta from './PostgresMeta.js'
import {
PostgresColumn,
PostgresForeignTable,
PostgresFunction,
PostgresMaterializedView,
PostgresRelationship,
Expand All @@ -14,6 +15,7 @@ import { PostgresMetaResult } from './types.js'
export type GeneratorMetadata = {
schemas: PostgresSchema[]
tables: Omit<PostgresTable, 'columns'>[]
foreignTables: Omit<PostgresForeignTable, 'columns'>[]
views: Omit<PostgresView, 'columns'>[]
materializedViews: Omit<PostgresMaterializedView, 'columns'>[]
columns: PostgresColumn[]
Expand Down Expand Up @@ -46,6 +48,15 @@ export async function getGeneratorMetadata(
return { data: null, error: tablesError }
}

const { data: foreignTables, error: foreignTablesError } = await pgMeta.foreignTables.list({
includedSchemas: includedSchemas.length > 0 ? includedSchemas : undefined,
excludedSchemas,
includeColumns: false,
})
if (foreignTablesError) {
return { data: null, error: foreignTablesError }
}

const { data: views, error: viewsError } = await pgMeta.views.list({
includedSchemas: includedSchemas.length > 0 ? includedSchemas : undefined,
excludedSchemas,
Expand Down Expand Up @@ -104,6 +115,7 @@ export async function getGeneratorMetadata(
(includedSchemas.length === 0 || includedSchemas.includes(name))
),
tables,
foreignTables,
views,
materializedViews,
columns,
Expand Down
10 changes: 10 additions & 0 deletions src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ if (EXPORT_DOCS) {
const [
{ data: schemas, error: schemasError },
{ data: tables, error: tablesError },
{ data: foreignTables, error: foreignTablesError },
{ data: views, error: viewsError },
{ data: materializedViews, error: materializedViewsError },
{ data: columns, error: columnsError },
Expand All @@ -54,6 +55,11 @@ if (EXPORT_DOCS) {
GENERATE_TYPES_INCLUDED_SCHEMAS.length > 0 ? GENERATE_TYPES_INCLUDED_SCHEMAS : undefined,
includeColumns: false,
}),
pgMeta.foreignTables.list({
includedSchemas:
GENERATE_TYPES_INCLUDED_SCHEMAS.length > 0 ? GENERATE_TYPES_INCLUDED_SCHEMAS : undefined,
includeColumns: false,
}),
pgMeta.views.list({
includedSchemas:
GENERATE_TYPES_INCLUDED_SCHEMAS.length > 0 ? GENERATE_TYPES_INCLUDED_SCHEMAS : undefined,
Expand Down Expand Up @@ -86,6 +92,9 @@ if (EXPORT_DOCS) {
if (tablesError) {
throw new Error(tablesError.message)
}
if (foreignTablesError) {
throw new Error(foreignTablesError.message)
}
if (viewsError) {
throw new Error(viewsError.message)
}
Expand Down Expand Up @@ -113,6 +122,7 @@ if (EXPORT_DOCS) {
GENERATE_TYPES_INCLUDED_SCHEMAS.includes(name)
),
tables: tables!,
foreignTables: foreignTables!,
views: views!,
materializedViews: materializedViews!,
columns: columns!,
Expand Down
5 changes: 3 additions & 2 deletions src/server/templates/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type { GeneratorMetadata } from '../../lib/generators.js'
export const apply = async ({
schemas,
tables,
foreignTables,
views,
materializedViews,
columns,
Expand All @@ -23,7 +24,7 @@ export const apply = async ({
detectOneToOneRelationships: boolean
}): Promise<string> => {
const columnsByTableId = Object.fromEntries<PostgresColumn[]>(
[...tables, ...views, ...materializedViews].map((t) => [t.id, []])
[...tables, ...foreignTables, ...views, ...materializedViews].map((t) => [t.id, []])
)
columns
.filter((c) => c.table_id in columnsByTableId)
Expand All @@ -37,7 +38,7 @@ export type Database = {
${schemas
.sort(({ name: a }, { name: b }) => a.localeCompare(b))
.map((schema) => {
const schemaTables = tables
const schemaTables = [...tables, ...foreignTables]
.filter((table) => table.schema === schema.name)
.sort(({ name: a }, { name: b }) => a.localeCompare(b))
const schemaViews = [...views, ...materializedViews]
Expand Down
2 changes: 1 addition & 1 deletion test/db/00-init.sql
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ create extension postgres_fdw;
create server foreign_server foreign data wrapper postgres_fdw options (host 'localhost', port '5432', dbname 'postgres');
create user mapping for postgres server foreign_server options (user 'postgres', password 'postgres');
create foreign table foreign_table (
id int8,
id int8 not null,
name text,
status user_status
) server foreign_server options (schema_name 'public', table_name 'users');
Expand Down
132 changes: 66 additions & 66 deletions test/lib/foreign-tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,71 +22,71 @@ test('list', async () => {
const res = await pgMeta.foreignTables.list()
expect(cleanNondetFromResponse(res).data?.find(({ name }) => name === 'foreign_table'))
.toMatchInlineSnapshot(`
{
"columns": [
{
"check": null,
"comment": null,
"data_type": "bigint",
"default_value": null,
"enums": [],
"format": "int8",
"identity_generation": null,
"is_generated": false,
"is_identity": false,
"is_nullable": true,
"is_unique": false,
"is_updatable": true,
"name": "id",
"ordinal_position": 1,
"schema": "public",
"table": "foreign_table",
},
{
"check": null,
"comment": null,
"data_type": "text",
"default_value": null,
"enums": [],
"format": "text",
"identity_generation": null,
"is_generated": false,
"is_identity": false,
"is_nullable": true,
"is_unique": false,
"is_updatable": true,
"name": "name",
"ordinal_position": 2,
"schema": "public",
"table": "foreign_table",
},
{
"check": null,
"comment": null,
"data_type": "USER-DEFINED",
"default_value": null,
"enums": [
"ACTIVE",
"INACTIVE",
],
"format": "user_status",
"identity_generation": null,
"is_generated": false,
"is_identity": false,
"is_nullable": true,
"is_unique": false,
"is_updatable": true,
"name": "status",
"ordinal_position": 3,
"schema": "public",
"table": "foreign_table",
},
],
"comment": null,
"name": "foreign_table",
"schema": "public",
}
`)
{
"columns": [
{
"check": null,
"comment": null,
"data_type": "bigint",
"default_value": null,
"enums": [],
"format": "int8",
"identity_generation": null,
"is_generated": false,
"is_identity": false,
"is_nullable": false,
"is_unique": false,
"is_updatable": true,
"name": "id",
"ordinal_position": 1,
"schema": "public",
"table": "foreign_table",
},
{
"check": null,
"comment": null,
"data_type": "text",
"default_value": null,
"enums": [],
"format": "text",
"identity_generation": null,
"is_generated": false,
"is_identity": false,
"is_nullable": true,
"is_unique": false,
"is_updatable": true,
"name": "name",
"ordinal_position": 2,
"schema": "public",
"table": "foreign_table",
},
{
"check": null,
"comment": null,
"data_type": "USER-DEFINED",
"default_value": null,
"enums": [
"ACTIVE",
"INACTIVE",
],
"format": "user_status",
"identity_generation": null,
"is_generated": false,
"is_identity": false,
"is_nullable": true,
"is_unique": false,
"is_updatable": true,
"name": "status",
"ordinal_position": 3,
"schema": "public",
"table": "foreign_table",
},
],
"comment": null,
"name": "foreign_table",
"schema": "public",
}
`)
})

test('list without columns', async () => {
Expand Down Expand Up @@ -117,7 +117,7 @@ test('retrieve', async () => {
"identity_generation": null,
"is_generated": false,
"is_identity": false,
"is_nullable": true,
"is_nullable": false,
"is_unique": false,
"is_updatable": true,
"name": "id",
Expand Down
36 changes: 36 additions & 0 deletions test/server/typegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,24 @@ test('typegen', async () => {
Update: {}
Relationships: []
}
foreign_table: {
Row: {
id: number
name: string | null
status: Database["public"]["Enums"]["user_status"] | null
}
Insert: {
id: number
name?: string | null
status?: Database["public"]["Enums"]["user_status"] | null
}
Update: {
id?: number
name?: string | null
status?: Database["public"]["Enums"]["user_status"] | null
}
Relationships: []
}
memes: {
Row: {
category: number | null
Expand Down Expand Up @@ -519,6 +537,24 @@ test('typegen w/ one-to-one relationships', async () => {
Update: {}
Relationships: []
}
foreign_table: {
Row: {
id: number
name: string | null
status: Database["public"]["Enums"]["user_status"] | null
}
Insert: {
id: number
name?: string | null
status?: Database["public"]["Enums"]["user_status"] | null
}
Update: {
id?: number
name?: string | null
status?: Database["public"]["Enums"]["user_status"] | null
}
Relationships: []
}
memes: {
Row: {
category: number | null
Expand Down

0 comments on commit 1a52837

Please sign in to comment.