Help us shape the future of Go! Take the 2026 Go Developer Survey

postgres

package module
v0.0.0-...-e29b97a Latest Latest
Warning

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

Go to latest
Published: Oct 25, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package postgres は authengine.Store の PostgreSQL Adapter である。

pgx/v5 の database/sql ドライバー(stdlib)を使い、スキーマは埋め込んだ SQL マイグレーションを goose ライブラリで適用する。goose CLI は不要。

原子性の保証(docs/adr/0005-storage-port.md):

  • 複合操作は 1 つの DB トランザクション(READ COMMITTED)で行い、前提となる行を SELECT ... FOR UPDATE でロックしてから検査・更新する。SQLite Adapter と違いプロセス内の Mutex は使わず、複数プロセス・複数接続の競合も DB の行ロックで直列化する。
  • 状態遷移は UPDATE ... WHERE status = <from> の更新行数で判定する(CAS)。
  • 単一行の作成は INSERT ... ON CONFLICT DO NOTHING の更新行数で重複を判定する。

時刻は UTC の Unix ナノ秒(BIGINT)で保存し、配列・マップは JSONB で保存する。 SQLite Adapter と列の意味を揃えてあるので、両者を読み比べると方言の差だけが見える。

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Migrate

func Migrate(ctx context.Context, db *sql.DB) error

Migrate は埋め込んだマイグレーションを適用する。何度呼んでも安全。

Types

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store は PostgreSQL 上の authengine.Store 実装。

func New

func New(db *sql.DB) *Store

New は利用者が用意した *sql.DB から Store を作る。スキーマは Migrate で適用済みであること。

Example

ExampleNew は接続プールの設定を利用者が持つ場合に、用意した *sql.DB から Store を作る。 New はマイグレーションを適用しないので、先に Migrate を呼ぶ(デプロイ時のジョブで 1 度だけ流してもよい)。

package main

import (
	"context"
	"database/sql"
	"log"
	"os"
	"time"

	_ "github.com/jackc/pgx/v5/stdlib"
	authengine "github.com/u-masato/auth-engine"
	"github.com/u-masato/auth-engine/adapters/postgres"
)

// database/sql の "pgx" ドライバー

func main() {
	ctx := context.Background()
	db, err := sql.Open("pgx", os.Getenv("DATABASE_URL"))
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()
	db.SetMaxOpenConns(20)
	db.SetConnMaxIdleTime(5 * time.Minute)

	if err := postgres.Migrate(ctx, db); err != nil {
		log.Fatal(err)
	}
	store := postgres.New(db)
	var _ authengine.Store = store
}

func Open

func Open(ctx context.Context, dsn string) (*Store, error)

Open は DSN(postgres://user:pass@host/db?sslmode=... または key=value 形式)で接続し、 マイグレーションを適用して Store を返す。

Example

ExampleOpen は DSN から接続し、マイグレーションを適用した Store を作る。 複数プロセスで同じ DB を共有してよい(競合は行ロックで直列化する)。

package main

import (
	"context"
	"log"
	"os"

	_ "github.com/jackc/pgx/v5/stdlib"
	authengine "github.com/u-masato/auth-engine"
	"github.com/u-masato/auth-engine/adapters/postgres"
)

func main() {
	ctx := context.Background()
	store, err := postgres.Open(ctx, os.Getenv("DATABASE_URL")) // 例: postgres://auth:secret@db:5432/auth?sslmode=verify-full
	if err != nil {
		log.Fatal(err)
	}
	defer store.Close()

	var _ authengine.Store = store // Config.Store にそのまま渡せる
}

func (*Store) Close

func (s *Store) Close() error

Close は DB を閉じる。

func (*Store) ConsumeAuthorizationCode

func (s *Store) ConsumeAuthorizationCode(ctx context.Context, codeHash string, now time.Time) (*authorization.AuthorizationCode, error)

ConsumeAuthorizationCode は 1 文の UPDATE ... RETURNING で原子的に消費する。 0 行なら SELECT で「消費済み」と「不明・期限切れ」を区別する。

func (*Store) CreateAuthorizationCode

func (s *Store) CreateAuthorizationCode(ctx context.Context, code *authorization.AuthorizationCode) error

func (*Store) CreateClient

func (s *Store) CreateClient(ctx context.Context, c *client.Client) error

func (*Store) CreateTransaction

func (s *Store) CreateTransaction(ctx context.Context, txn *authorization.Transaction) error

func (*Store) DB

func (s *Store) DB() *sql.DB

DB は内部の *sql.DB を返す(テストや運用ツール向け)。

func (*Store) FindGrant

func (s *Store) FindGrant(ctx context.Context, clientID, subject string) (*grant.Grant, error)

func (*Store) GetClient

func (s *Store) GetClient(ctx context.Context, id string) (*client.Client, error)

func (*Store) GetGrant

func (s *Store) GetGrant(ctx context.Context, id string) (*grant.Grant, error)

func (*Store) GetTokenFamily

func (s *Store) GetTokenFamily(ctx context.Context, id string) (*token.Family, error)

func (*Store) GetTransaction

func (s *Store) GetTransaction(ctx context.Context, id string) (*authorization.Transaction, error)

func (*Store) IssueTokens

func (s *Store) IssueTokens(ctx context.Context, family *token.Family, access *token.AccessToken, refresh *token.RefreshToken) error

IssueTokens は Grant 行を FOR UPDATE でロックして active を確認してから挿入する。 同時に走る RevokeGrant とはこの行ロックで直列化される。

func (*Store) ListGrantsBySubject

func (s *Store) ListGrantsBySubject(ctx context.Context, subject string) ([]*grant.Grant, error)

func (*Store) LookupAccessToken

func (s *Store) LookupAccessToken(ctx context.Context, hash string) (*token.AccessToken, *grant.Grant, error)

func (*Store) LookupRefreshToken

func (s *Store) LookupRefreshToken(ctx context.Context, hash string) (*token.RefreshToken, error)

func (*Store) Purge

func (s *Store) Purge(ctx context.Context, now time.Time) error

Purge は期限切れの行を削除する。消費済み Code も期限が過ぎれば削除する。

func (*Store) RevokeAccessToken

func (s *Store) RevokeAccessToken(ctx context.Context, hash string, now time.Time) error

func (*Store) RevokeGrant

func (s *Store) RevokeGrant(ctx context.Context, id string, now time.Time) error

RevokeGrant は Grant 行を CAS で失効させ、同じトランザクションで配下の Family・全トークンを失効させる。 Grant 行の更新が行ロックになるので、同時に走る IssueTokens(FOR UPDATE)はこの後に順番が来て ErrGrantRevoked になるか、先に挿入を終えていてここで巻き込まれるかのどちらかになる。

func (*Store) RevokeTokenFamily

func (s *Store) RevokeTokenFamily(ctx context.Context, familyID string, now time.Time) error

func (*Store) RotateRefreshToken

func (s *Store) RotateRefreshToken(ctx context.Context, oldHash string, next *token.RefreshToken, access *token.AccessToken, now time.Time) error

RotateRefreshToken は旧トークン行を FOR UPDATE でロックし、active のときだけ rotated にして 後継と Access Token を挿入する。同じトークンの同時提示は行ロックで直列化され、2 番目以降は rotated を見て ErrTokenReused になる。

func (*Store) TransitionTransaction

func (s *Store) TransitionTransaction(ctx context.Context, id string, from, to authorization.Status, patch authorization.Patch) error

TransitionTransaction は CAS。UPDATE の WHERE に from を含め、更新行数で成否を判定する。

func (*Store) UpsertGrant

func (s *Store) UpsertGrant(ctx context.Context, candidate *grant.Grant) (*grant.Grant, error)

UpsertGrant は (client_id, subject) の既存行を FOR UPDATE でロックしてから grant.Merge の結果で 更新する。なければ INSERT する。2 つの要求が同時に同じ (client_id, subject) を初めて作ろうとすると 片方が unique_violation になるので、その場合はやり直して既存行への更新にする。

Jump to

Keyboard shortcuts

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