Skip to content

feat: support schema-qualified table names for multi-schema databases#89

Open
Daniel230196 wants to merge 1 commit into
tkcrm:masterfrom
Daniel230196:feat/schema-qualified-table-names
Open

feat: support schema-qualified table names for multi-schema databases#89
Daniel230196 wants to merge 1 commit into
tkcrm:masterfrom
Daniel230196:feat/schema-qualified-table-names

Conversation

@Daniel230196
Copy link
Copy Markdown

Summary

Adds support for schema-qualified table names (e.g. shop.orders) in pgxgen.yaml, enabling CRUD, models, constants, and sqlc config generation for tables in non-default PostgreSQL schemas.

Motivation

PostgreSQL supports organizing objects into schemas — a common pattern for multi-tenant apps, domain separation, and large codebases. Previously,
pgxgen only worked with tables in the default public schema. Users with multi-schema databases had to either:

  • Maintain separate configs per schema
  • Manually write SQL for non-public tables
  • Avoid using schemas altogether

This PR brings pgxgen's behavior in line with sqlc's schema-qualified naming convention, where objects in non-default schemas are prefixed with the schema
name (e.g. shop.orders → Go type ShopOrder).

Usage

tables:
  users:              # public schema — no prefix needed
    primary_column: id
    crud:
      methods:
        get: {}

  shop.orders:        # "shop" schema — dot notation
    primary_column: id
    crud:
      methods:
        get: {}
        create: { returning: "*" }

┌───────────────────┬───────────────────────┬───────────────────────────────┐
│      Aspect       │    orders (public)    │   shop.orders (non-default)   │
├───────────────────┼───────────────────────┼───────────────────────────────┤
│ SQL               │ SELECT * FROM orders  │ SELECT * FROM shop.orders     │
├───────────────────┼───────────────────────┼───────────────────────────────┤
│ Go identifiers    │ CreateOrder, GetOrder │ CreateShopOrder, GetShopOrder │
├───────────────────┼───────────────────────┼───────────────────────────────┤
│ File paths        │ sql/queries/orders/   │ sql/queries/shop_orders/      │
├───────────────────┼───────────────────────┼───────────────────────────────┤
│ Go types (models) │ Order                 │ ShopOrder                     │
├───────────────────┼───────────────────────┼───────────────────────────────┤
│ Enum types        │ OrderStatus           │ ShopOrderStatus               │
└───────────────────┴───────────────────────┴───────────────────────────────┘

Backward compatibility

- No breaking changes — plain table keys (users, orders) behave exactly as before
- Tables in the default schema (public for PostgreSQL, main for SQLite) are never prefixed
- The DefaultSchema is derived from the catalog (not hardcoded), so engine-specific defaults are respected
- All existing tests pass unchanged

Key design decisions

1. Single ParseTableKey() entry point — all generators (CRUD, constants, models, sqlc config) use the same TableKeyParts struct, ensuring consistent naming across the entire pipeline
2. SQL name vs Go name separation — SQLTableName() returns shop.orders for SQL statements, GoName() returns shop_orders for file paths and Go identifiers
3. Two-pass enum matching — schema-qualified column types (e.g. shop.order_status) first match by exact schema+name, then fall back to bare name matching for backward compatibility
4. Matches sqlc convention — generated Go type names follow https://docs.sqlc.dev/en/latest/reference/config.html of prefixing non-default schema objects

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.

1 participant