Initial lookbook implementation
Pinterest-style visual bookmarking app with: - URL metadata extraction (OG/Twitter meta, oEmbed fallback) - Image caching in Postgres with 480px thumbnails - Multi-tag filtering with Ctrl/Cmd for OR mode - Fuzzy tag suggestions and inline tag editing - Browser console auth() with first-use password setup - Brutalist UI with Commit Mono font and Pico CSS - Light/dark mode via browser preference
This commit is contained in:
commit
fc625fb9cf
486 changed files with 195373 additions and 0 deletions
280
vendor/github.com/pressly/goose/v3/provider_options.go
generated
vendored
Normal file
280
vendor/github.com/pressly/goose/v3/provider_options.go
generated
vendored
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
package goose
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"github.com/pressly/goose/v3/database"
|
||||
"github.com/pressly/goose/v3/lock"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultTablename is the default name of the database table used to track history of applied
|
||||
// migrations.
|
||||
DefaultTablename = "goose_db_version"
|
||||
)
|
||||
|
||||
// ProviderOption is a configuration option for a goose goose.
|
||||
type ProviderOption interface {
|
||||
apply(*config) error
|
||||
}
|
||||
|
||||
// WithStore configures the provider with a custom [database.Store], allowing users to bring their
|
||||
// own implementation of the store interface. When this option is used, the dialect parameter of
|
||||
// [NewProvider] must be set to [DialectCustom].
|
||||
//
|
||||
// This option cannot be used together with [WithTableName], since the table name is set on the
|
||||
// store.
|
||||
//
|
||||
// By default, the provider uses the [database.NewStore] function to create a store backed by one of
|
||||
// the officially supported dialects.
|
||||
func WithStore(store database.Store) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
if c.store != nil {
|
||||
return fmt.Errorf("store already set: %T", c.store)
|
||||
}
|
||||
if store == nil {
|
||||
return errors.New("store must not be nil")
|
||||
}
|
||||
if store.Tablename() == "" {
|
||||
return errors.New("store implementation must set the table name")
|
||||
}
|
||||
c.store = store
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithTableName sets the name of the database table used to track history of applied migrations.
|
||||
// This option cannot be used together with [WithStore], since the table name is set on the store.
|
||||
//
|
||||
// Default is "goose_db_version".
|
||||
func WithTableName(name string) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
if name == "" {
|
||||
return errors.New("table name must not be empty")
|
||||
}
|
||||
c.tableName = name
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithVerbose enables verbose logging.
|
||||
func WithVerbose(b bool) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
c.verbose = b
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithSessionLocker enables locking using the provided SessionLocker.
|
||||
//
|
||||
// If WithSessionLocker is not called, locking is disabled. Must not be used together with
|
||||
// [WithLocker].
|
||||
func WithSessionLocker(locker lock.SessionLocker) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
if c.lockEnabled {
|
||||
return errors.New("lock already enabled")
|
||||
}
|
||||
if c.sessionLocker != nil {
|
||||
return errors.New("session locker already set")
|
||||
}
|
||||
if c.locker != nil {
|
||||
return errors.New("locker already set; cannot use both SessionLocker and Locker")
|
||||
}
|
||||
if locker == nil {
|
||||
return errors.New("session locker must not be nil")
|
||||
}
|
||||
c.lockEnabled = true
|
||||
c.sessionLocker = locker
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithLocker enables locking using the provided Locker.
|
||||
//
|
||||
// If WithLocker is not called, locking is disabled. Must not be used together with
|
||||
// [WithSessionLocker].
|
||||
func WithLocker(locker lock.Locker) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
if c.lockEnabled {
|
||||
return errors.New("lock already enabled")
|
||||
}
|
||||
if c.locker != nil {
|
||||
return errors.New("locker already set")
|
||||
}
|
||||
if c.sessionLocker != nil {
|
||||
return errors.New("session locker already set; cannot use both SessionLocker and Locker")
|
||||
}
|
||||
if locker == nil {
|
||||
return errors.New("locker must not be nil")
|
||||
}
|
||||
c.lockEnabled = true
|
||||
c.locker = locker
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithExcludeNames excludes the given file name from the list of migrations. If called multiple
|
||||
// times, the list of excludes is merged.
|
||||
func WithExcludeNames(excludes []string) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
for _, name := range excludes {
|
||||
if _, ok := c.excludePaths[name]; ok {
|
||||
return fmt.Errorf("duplicate exclude file name: %s", name)
|
||||
}
|
||||
c.excludePaths[name] = true
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithExcludeVersions excludes the given versions from the list of migrations. If called multiple
|
||||
// times, the list of excludes is merged.
|
||||
func WithExcludeVersions(versions []int64) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
for _, version := range versions {
|
||||
if version < 1 {
|
||||
return errInvalidVersion
|
||||
}
|
||||
if _, ok := c.excludeVersions[version]; ok {
|
||||
return fmt.Errorf("duplicate excludes version: %d", version)
|
||||
}
|
||||
c.excludeVersions[version] = true
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithGoMigrations registers Go migrations with the provider. If a Go migration with the same
|
||||
// version has already been registered, an error will be returned.
|
||||
//
|
||||
// Go migrations must be constructed using the [NewGoMigration] function.
|
||||
func WithGoMigrations(migrations ...*Migration) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
for _, m := range migrations {
|
||||
if _, ok := c.registered[m.Version]; ok {
|
||||
return fmt.Errorf("go migration with version %d already registered", m.Version)
|
||||
}
|
||||
if err := checkGoMigration(m); err != nil {
|
||||
return fmt.Errorf("invalid go migration: %w", err)
|
||||
}
|
||||
c.registered[m.Version] = m
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithDisableGlobalRegistry prevents the provider from registering Go migrations from the global
|
||||
// registry. By default, goose will register all Go migrations including those registered globally.
|
||||
func WithDisableGlobalRegistry(b bool) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
c.disableGlobalRegistry = b
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithAllowOutofOrder allows the provider to apply missing (out-of-order) migrations. By default,
|
||||
// goose will raise an error if it encounters a missing migration.
|
||||
//
|
||||
// For example: migrations 1,3 are applied and then version 2,6 are introduced. If this option is
|
||||
// true, then goose will apply 2 (missing) and 6 (new) instead of raising an error. The final order
|
||||
// of applied migrations will be: 1,3,2,6. Out-of-order migrations are always applied first,
|
||||
// followed by new migrations.
|
||||
func WithAllowOutofOrder(b bool) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
c.allowMissing = b
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithDisableVersioning disables versioning. Disabling versioning allows applying migrations
|
||||
// without tracking the versions in the database schema table. Useful for tests, seeding a database
|
||||
// or running ad-hoc queries. By default, goose will track all versions in the database schema
|
||||
// table.
|
||||
func WithDisableVersioning(b bool) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
c.disableVersioning = b
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithLogger will set a custom Logger, which will override the default logger. Cannot be used
|
||||
// together with [WithSlog].
|
||||
func WithLogger(l Logger) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
if l == nil {
|
||||
return errors.New("logger must not be nil")
|
||||
}
|
||||
if c.slogger != nil {
|
||||
return errors.New("cannot use both WithLogger and WithSlog")
|
||||
}
|
||||
c.logger = l
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithSlog will set a custom [*slog.Logger] for structured logging. This enables rich structured
|
||||
// logging with attributes like source, direction, duration, etc. Cannot be used together with
|
||||
// [WithLogger].
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
|
||||
// p, err := goose.NewProvider("postgres", db, fs, goose.WithSlog(logger))
|
||||
func WithSlog(logger *slog.Logger) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
if logger == nil {
|
||||
return errors.New("slog logger must not be nil")
|
||||
}
|
||||
if c.logger != nil {
|
||||
return errors.New("cannot use both WithLogger and WithSlog")
|
||||
}
|
||||
c.slogger = logger
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// WithIsolateDDL executes DDL operations separately from DML operations. This is useful for
|
||||
// databases like AWS Aurora DSQL that don't support mixing DDL and DML within the same transaction.
|
||||
func WithIsolateDDL(b bool) ProviderOption {
|
||||
return configFunc(func(c *config) error {
|
||||
c.isolateDDL = b
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
type config struct {
|
||||
tableName string
|
||||
store database.Store
|
||||
|
||||
verbose bool
|
||||
excludePaths map[string]bool
|
||||
excludeVersions map[int64]bool
|
||||
|
||||
// Go migrations registered by the user. These will be merged/resolved against the globally
|
||||
// registered migrations.
|
||||
registered map[int64]*Migration
|
||||
|
||||
// Locking options
|
||||
lockEnabled bool
|
||||
sessionLocker lock.SessionLocker
|
||||
locker lock.Locker
|
||||
|
||||
// Feature
|
||||
disableVersioning bool
|
||||
allowMissing bool
|
||||
disableGlobalRegistry bool
|
||||
isolateDDL bool
|
||||
|
||||
// Only a single logger can be set, they are mutually exclusive. If neither is set, a default
|
||||
// [Logger] will be set to maintain backward compatibility in /v3.
|
||||
logger Logger
|
||||
slogger *slog.Logger
|
||||
}
|
||||
|
||||
type configFunc func(*config) error
|
||||
|
||||
func (f configFunc) apply(cfg *config) error {
|
||||
return f(cfg)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue