dalgo2postgres

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 25, 2026 License: MIT Imports: 14 Imported by: 0

README

dalgo2postgres

PostgreSQL-specific DALgo driver. Wraps github.com/dal-go/dalgo2sql to provide the dal.DB surface, and adds PostgreSQL-native implementations of:

  • dbschema.SchemaReader — schema introspection via information_schema and pg_indexes
  • ddl.Applier — PostgreSQL-flavored CREATE TABLE / CREATE INDEX / DROP TABLE / ALTER TABLE
  • dal.ConcurrencyAware — advertises SupportsConcurrentConnections() = true (PostgreSQL supports concurrent connections from multiple goroutines and processes, unlike SQLite which serializes writers)

Constructor usage

import (
    "github.com/dal-go/dalgo/dal"
    "github.com/dal-go/dalgo2postgres"
    "github.com/dal-go/dalgo2sql"
)

// Minimal — no per-collection primary-key configuration.
db, err := dalgo2postgres.NewDatabase("postgres://user:pass@localhost:5432/mydb?sslmode=disable")

// With per-collection recordset options (required for Insert/Get/Delete with map[string]any data):
db, err := dalgo2postgres.NewDatabaseWithOptions(dsn, dal.NewSchema(nil, nil),
    dalgo2sql.DbOptions{
        Recordsets: map[string]*dalgo2sql.Recordset{
            "widgets": dalgo2sql.NewRecordset("widgets", dalgo2sql.Table,
                []dal.FieldRef{dal.Field("id")}),
        },
    })
if err != nil {
    return err
}
defer db.Close()

Type mapping

dbschema.Type PostgreSQL column type
String TEXT (or VARCHAR(n) when Length is set)
Int BIGINT
Float DOUBLE PRECISION
Bool BOOLEAN
Time TIMESTAMPTZ
Decimal NUMERIC (or NUMERIC(total, scale) when Precision is set)
Bytes BYTEA

Running the tests

The tests that touch a live database are gated on the DALGO2POSTGRES_TEST_DSN environment variable. When it is not set, those tests are skipped so plain CI passes without a database.

Start a local PostgreSQL 17 server (Docker):

docker run -d \
  --name postgres17 \
  -e POSTGRES_USER=ovdb \
  -e POSTGRES_PASSWORD=ovdb \
  -e POSTGRES_DB=ovdb \
  -p 15432:5432 \
  postgres:17

Then run the tests:

DALGO2POSTGRES_TEST_DSN='postgres://ovdb:ovdb@127.0.0.1:15432/ovdb?sslmode=disable' \
    go test ./... -count=1 -v

PostgreSQL driver: github.com/jackc/pgx/v5/stdlib (pure Go, CGO_ENABLED=0)

This package uses github.com/jackc/pgx/v5/stdlib — a pure-Go PostgreSQL driver exposed through the standard database/sql interface (driver name "pgx"). No C toolchain is required; the package compiles with CGO_ENABLED=0.

Placeholder dialect

PostgreSQL requires positional parameter markers $1, $2, … rather than the ? style used by SQLite and MySQL. dalgo2postgres automatically sets dalgo2sql.DbOptions.Placeholder = dalgo2sql.PlaceholderDollar so that all SQL emitted through dalgo2sql uses the correct form. This field was added to dalgo2sql as a minimal backward-compatible extension; the zero value (PlaceholderQuestion) preserves the existing behavior for all other drivers.

Identifier case folding

PostgreSQL folds unquoted identifiers to lower case. dalgo2postgres quotes identifiers (so reserved words and otherwise-illegal names stay usable) but lower-cases them first, so the case-preserving quoted form agrees with the unquoted references that dalgo2sql's DML and dalgo's structured-query rendering emit (which PostgreSQL also folds to lower case). DDL and DML thus always address the same physical identifier.

Consequence: collection (table) and field (column) names are stored lower-cased. Typed clients round-trip transparently because encoding/json unmarshalling is case-insensitive; consumers reading raw records observe lower-cased field names. Fully case-preserving storage would require dalgo's structured-query String() to quote column identifiers, tracked upstream.

Documentation

Overview

Package dalgo2postgres is the PostgreSQL-specific DALgo driver.

It composes github.com/dal-go/dalgo2sql for the dal.DB read/write surface (transactions, recordset reader, Get/Set/Insert/Delete) and adds PostgreSQL-native implementations of:

Index

Constants

View Source
const Version = "0.1.0"

Version is the dalgo2postgres package version. Updated by hand on each release; consumed by Adapter.Version().

Variables

This section is empty.

Functions

This section is empty.

Types

type Database

type Database struct {
	dal.ConcurrencyAvailable // SupportsConcurrentConnections() = true

	dal.DB // delegate for the dal.DB surface
	// contains filtered or unexported fields
}

Database is the dalgo2postgres driver instance. It implements dal.DB by embedding a dal.DB obtained from dalgo2sql.NewDatabase, and adds PostgreSQL-specific dbschema, ddl, and concurrency surfaces.

The embedded dal.DB (rather than a named field) is what lets Database satisfy dal.DB itself: dal.DB is sealed by an unexported marker method, and embedding is the only way for that method to be promoted onto a decorating type — see dal.NewDB's doc comment.

Construct via NewDatabase. Database values are safe for concurrent use — the underlying PostgreSQL server and pgx connection pool both support concurrent connections from multiple goroutines.

func NewDatabase

func NewDatabase(dsn string) (*Database, error)

NewDatabase opens a connection to the PostgreSQL server identified by dsn using github.com/jackc/pgx/v5/stdlib (pure Go, CGO_ENABLED=0), pings to surface connectivity errors at construction time, wraps the *sql.DB via dalgo2sql.NewDatabase for the dal.DB surface, and returns a *Database that satisfies dal.DB + dal.ConcurrencyAware.

Use NewDatabaseWithOptions when you need to supply per-collection primary-key metadata (required for Insert/Get/Delete with map[string]any data).

func NewDatabaseWithOptions

func NewDatabaseWithOptions(dsn string, schema dal.Schema, opts dalgo2sql.DbOptions) (*Database, error)

NewDatabaseWithOptions is like NewDatabase but accepts a dal.Schema and dalgo2sql.DbOptions so callers can configure per-collection primary-key mappings required by Insert/Get/Delete operations.

Example — open a DB whose "widgets" table has "id" as its primary key:

db, err := dalgo2postgres.NewDatabaseWithOptions(dsn, dal.NewSchema(nil, nil),
    dalgo2sql.DbOptions{
        Recordsets: map[string]*dalgo2sql.Recordset{
            "widgets": dalgo2sql.NewRecordset("widgets", dalgo2sql.Table,
                []dal.FieldRef{dal.Field("id")}),
        },
    })

func (*Database) Adapter

func (d *Database) Adapter() dal.Adapter

Adapter returns the driver/version identifier.

func (*Database) AlterCollection

func (d *Database) AlterCollection(ctx context.Context, name string, ops ...ddl.AlterOp) error

AlterCollection applies ops in order inside a single transaction. Partial failures roll back and leave the collection untouched.

func (*Database) Close

func (d *Database) Close() error

Close closes the underlying *sql.DB. After Close the Database value is unusable; further method calls will fail with an error from database/sql.

func (*Database) CreateCollection

func (d *Database) CreateCollection(ctx context.Context, c dbschema.CollectionDef, opts ...ddl.Option) error

CreateCollection creates a table and its inline indexes transactionally. On any error, the transaction rolls back and no schema state remains.

func (*Database) Delete

func (d *Database) Delete(ctx context.Context, key *dalrecord.Key) error

func (*Database) DeleteMulti

func (d *Database) DeleteMulti(ctx context.Context, keys []*dalrecord.Key) error

func (*Database) DescribeCollection

func (d *Database) DescribeCollection(ctx context.Context, ref *dal.CollectionRef) (*dbschema.CollectionDef, error)

DescribeCollection returns the full schema definition for the named table. It queries information_schema for columns and primary-key membership.

func (*Database) DropCollection

func (d *Database) DropCollection(ctx context.Context, name string, opts ...ddl.Option) error

DropCollection drops the table and all its indexes (Postgres cascades automatically).

func (*Database) ExecuteQueryToRecordsReader

func (d *Database) ExecuteQueryToRecordsReader(ctx context.Context, query dal.Query) (dal.RecordsReader, error)

func (*Database) ExecuteQueryToRecordsetReader

func (d *Database) ExecuteQueryToRecordsetReader(ctx context.Context, query dal.Query, opts ...recordset.Option) (dal.RecordsetReader, error)

func (*Database) Exists

func (d *Database) Exists(ctx context.Context, key *dalrecord.Key) (bool, error)

func (*Database) Get

func (d *Database) Get(ctx context.Context, record dalrecord.Record) error

func (*Database) GetMulti

func (d *Database) GetMulti(ctx context.Context, records []dalrecord.Record) error

func (*Database) ID

func (d *Database) ID() string

ID returns the driver-issued database ID (delegated to dalgo2sql).

func (*Database) Insert

func (d *Database) Insert(ctx context.Context, record dalrecord.Record, opts ...dal.InsertOption) error

func (*Database) ListCollections

func (d *Database) ListCollections(ctx context.Context, parent *dalrecord.Key) ([]dal.CollectionRef, error)

ListCollections returns user-defined tables in the current schema ('public') in alphabetical order. The parent *dalrecord.Key is ignored — Postgres has a flat table namespace within a schema.

func (*Database) ListConstraints

func (d *Database) ListConstraints(ctx context.Context, ref *dal.CollectionRef) ([]dbschema.ConstraintDef, error)

ListConstraints returns a best-effort survey of constraints on the table via information_schema:

  • PRIMARY KEY constraint (one row if any PK columns exist)
  • UNIQUE constraints
  • FOREIGN KEY constraints

CHECK constraints are NOT enumerated here; read them from DescribeCollection if needed.

func (*Database) ListIndexes

func (d *Database) ListIndexes(ctx context.Context, ref *dal.CollectionRef) ([]dbschema.IndexDef, error)

ListIndexes returns the non-primary-key indexes on the named table via pg_indexes.

func (*Database) ListReferrers

func (d *Database) ListReferrers(ctx context.Context, ref *dal.CollectionRef) ([]dbschema.Referrer, error)

ListReferrers returns the collections that reference ref via foreign keys. It queries information_schema.referential_constraints for tables that have a FOREIGN KEY pointing to the named table.

func (*Database) RunReadonlyTransaction

func (d *Database) RunReadonlyTransaction(ctx context.Context, f dal.ROTxWorker, opts ...dal.TransactionOption) error

func (*Database) RunReadwriteTransaction

func (d *Database) RunReadwriteTransaction(ctx context.Context, f dal.RWTxWorker, opts ...dal.TransactionOption) error

func (*Database) Schema

func (d *Database) Schema() dal.Schema

Schema returns the dal-level Schema (delegated to dalgo2sql).

func (*Database) Set

func (d *Database) Set(ctx context.Context, record dalrecord.Record) error

func (*Database) SetMulti

func (d *Database) SetMulti(ctx context.Context, records []dalrecord.Record) error

func (*Database) SupportsConcurrentConnections added in v0.2.0

func (d *Database) SupportsConcurrentConnections() bool

SupportsConcurrentConnections reports PostgreSQL's own concurrency behaviour (always true — see dal.ConcurrencyAvailable), not dalgo2sql's. An explicit method is required here: dal.ConcurrencyAvailable and the embedded dal.DB (whose Backend requirement embeds dal.ConcurrencyAware) both declare this method at the same promotion depth, which Go otherwise treats as an ambiguous selector.

func (*Database) SupportsTransactionalDDL

func (d *Database) SupportsTransactionalDDL() bool

SupportsTransactionalDDL reports that PostgreSQL supports transactional DDL — every CREATE / DROP / ALTER statement can be wrapped in a BEGIN/COMMIT and is rolled back atomically on commit failure.

func (*Database) Update

func (d *Database) Update(ctx context.Context, key *dalrecord.Key, updates []update.Update, preconditions ...dal.Precondition) error

func (*Database) UpdateMulti

func (d *Database) UpdateMulti(ctx context.Context, keys []*dalrecord.Key, updates []update.Update, preconditions ...dal.Precondition) error

func (*Database) UpdateRecord

func (d *Database) UpdateRecord(ctx context.Context, record dalrecord.Record, updates []update.Update, preconditions ...dal.Precondition) error

UpdateRecord is not supported at the database level by dalgo2sql; use Update with an explicit key instead, or call UpdateRecord inside a RunReadwriteTransaction where the transaction object does support it.

func (*Database) Upsert

func (d *Database) Upsert(ctx context.Context, record dalrecord.Record) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL