supabase/postgres-meta

repository·master·Indexed 22 days ago

https://github.com/supabase/postgres-meta

A RESTful API layer for PostgreSQL that normalizes the system catalog to manage database objects like tables, roles, and functions via HTTP. It serves as a lightweight connection pooler and provides tools for generating type definitions in TypeScript, Go, Swift, and Python. The library includes utilities for parsing SQL strings into ASTs, formatting SQL, and managing database schema metadata.

Tokens
5.5K
Snippets
10
Records
24
Agent score
79%

What's inside postgres-meta

  1. Overview of postgres-meta

    master

    postgres-meta

    postgres-meta is a RESTful API designed for managing PostgreSQL databases. It provides a way to fetch tables, manage roles, and execute SQL queries through HTTP.

    Key Features:

    • Normalization: It normalizes the Postgres system catalog into a more readable format.
    • Connection Pooling: It serves as a lightweight connection pooler.
    • Multi-tenancy: The server supports multiple Postgres databases from a single instance.
    • Type Generation: It provides helpers to generate types for various languages (TypeScript, Go, Swift, Python).
    WARNING

    Security Warning: This service implements no security. It is not intended to be used as a standalone server. It should be deployed behind a proxy in a trusted environment, used locally, or used internally without external access.

  2. Quickstart: Set up postgres-meta

    master

    To run postgres-meta, you must first configure the following environment variables to define the server binding and the target database connection details. After setting these, run any of the binaries provided in the releases.

    Required Environment Variables:

    • PG_META_HOST: The host the API server will bind to.
    • PG_META_PORT: The port the API server will listen on.
    • PG_META_DB_HOST: The hostname of the target Postgres database.
    • PG_META_DB_NAME: The name of the target Postgres database.
    • PG_META_DB_USER: The username for the Postgres database.
    • PG_META_DB_PORT: The port of the target Postgres database.
    • PG_META_DB_PASSWORD: The password for the Postgres database.
    PG_META_HOST="0.0.0.0"
    PG_META_PORT=8080
    PG_META_DB_HOST="postgres"
    PG_META_DB_NAME="postgres"
    PG_META_DB_USER="postgres"
    PG_META_DB_PORT=5432
    PG_META_DB_PASSWORD="postgres"
  3. Generate types for various languages

    master

    You can generate type definitions for your database schema using the /generators endpoints. If you are developing locally, you can use the provided CLI commands to trigger type generation.

    To use a custom database connection string instead of the default test database, set the PG_META_DB_URL environment variable.

    Supported Languages:

    • typescript
    • go
    • swift (beta)
    • python (beta)
  4. Understand the PostgresMetaResult response pattern

    master

    Most API responses in postgres-meta follow a standardized result pattern using the PostgresMetaResult<T> type. This ensures consistent error handling across different metadata queries.

    • Success (PostgresMetaOk<T>): Contains the requested data of type T and a null error.
    • Failure (PostgresMetaErr): Contains null data and an error object containing a message and an optional formattedError.
  5. Format a SQL string with Format()

    master

    Use the Format function to beautify a SQL string using Prettier with the sql-formatter plugin. By default, it is configured for postgresql. You can provide custom FormatterOptions to override default settings.

    Returns an object containing the formatted SQL data or an error.

  6. Initialize the postgres-meta server with build()

    master
    The build function is the primary entrypoint for creating a postgres-meta Fastify application instance. It configures the server with default settings for request logging, body limits, and error handling, and registers core plugins like CORS, Swagger (OpenAPI), and the internal API routes. You can pass custom FastifyServerOptions to override these defaults.
  7. Initialize the Admin API server with build()

    master
    Use the build function to create a FastifyInstance configured for the Admin API. The returned server instance includes integrated Sentry error handling and a /metrics endpoint for monitoring via fastify-metrics. You can pass standard FastifyServerOptions to customize the server behavior.
  8. Define SQL query properties and filters

    master

    When interacting with the SQL execution layer, you can use the following types to define query properties like pagination and filtering.

    • SQLQueryProps: Basic pagination using limit and offset.
    • SQLQueryPropsWithSchemaFilter: Adds a schemaFilter string to control which schema the query applies to.
    • SQLQueryPropsWithIdsFilter: Adds an idsFilter string to filter by specific identifiers.
    • SQLQueryPropsWithSchemaFilterAndIdsFilter: Combines schemaFilter and idsFilter with pagination.
    export type SQLQueryProps = {
      limit?: number
      offset?: number
    }
    
    export type SQLQueryPropsWithSchemaFilter = SQLQueryProps & {
      schemaFilter?: string
    }
    
    export type SQLQueryPropsWithIdsFilter = SQLQueryProps & {
      idsFilter?: string
    }
    
    export type SQLQueryPropsWithSchemaFilterAndIdsFilter = SQLQueryProps & {
      schemaFilter?: string
      idsFilter?: string
    }
  9. Parse a SQL string into an AST with Parse()

    master
    Use the Parse function to convert a raw SQL string into an Abstract Syntax Tree (AST) object. This is useful for programmatic inspection or manipulation of SQL queries. The function returns an object containing either the parsed data or an error.
  10. Update a PostgresColumn

    master

    Use PostgresColumnUpdate to modify existing column properties. Most fields are optional. Note that check constraints can be set to null to remove them.

    export const postgresColumnUpdateSchema = Type.Object({
      name: Type.Optional(Type.String()),
      type: Type.Optional(Type.String()),
      drop_default: Type.Optional(Type.Boolean()),
      default_value: Type.Optional(Type.Unknown()),
      default_value_format: Type.Optional(
        Type.Union([Type.Literal('expression'), Type.Literal('literal')])
      ),
      is_identity: Type.Optional(Type.Boolean()),
      identity_generation: Type.Optional(
        Type.Union([Type.Literal('BY DEFAULT'), Type.Literal('ALWAYS')])
      ),
      is_nullable: Type.Optional(Type.Boolean()),
      is_unique: Type.Optional(Type.Boolean()),
      comment: Type.Optional(Type.String()),
      check: Type.Optional(
        Type.Union(
          // Type.Null() must go first: https://github.com/sinclairzx81/typebox/issues/546
          [Type.Null(), Type.String()]
        )
      ),
    })