Documentation
¶
Overview ¶
Package gormseed loads JSON (or custom-format) fixtures into a GORM database with idempotent, conflict-aware inserts — Rails-style db:seed for GORM.
Unlike test-fixture loaders that truncate and reload, gormseed is built for repeatable seeding of reference, demo, and initial data: by default it uses INSERT ... ON CONFLICT DO NOTHING, so running it twice is a no-op rather than a duplicate-key error.
Register fixtures, then run them against any fs.FS (a directory or an embed.FS):
seeder := gormseed.New(db, gormseed.WithAutoOrder()).
Add("users.json", &[]User{}).
Add("posts.json", &[]Post{}, gormseed.OnConflict(gormseed.UpdateAll()))
res, err := seeder.Run(ctx, gormseed.Dir("fixtures"))
// or: res, err := seeder.Run(ctx, embeddedFS)
Features:
- Idempotent inserts with selectable conflict strategy (Skip, Update, UpdateAll, Error), per spec or as a seeder-wide default.
- Foreign-key-safe ordering: WithAutoOrder loads parents before children by inspecting belongs-to and has-many relationships; After adds explicit edges.
- Profiles (dev/demo/test), dry runs, transactional runs, and a per-spec Result report.
- Pluggable decoders (JSON built in; add YAML or others without the core taking on the dependency).
- Batch inserts for large fixture files via WithBatchSize.
- Table cleanup via Clean, for resetting data between runs.
- Before/after seed hooks for monitoring and instrumentation.
- Optional logger for progress output.
Index ¶
- func Dir(path string) fs.FS
- type Conflict
- type Logger
- type Option
- func WithAfterSeedHook(hook SeedHook) Option
- func WithAutoOrder() Option
- func WithBatchSize(n int) Option
- func WithBeforeSeedHook(hook SeedHook) Option
- func WithContinueOnError() Option
- func WithDecoder(ext string, fn func(data []byte, dest any) error) Option
- func WithDecoderContext(ext string, fn func(ctx context.Context, data []byte, dest any) error) Option
- func WithDefaultConflict(c Conflict) Option
- func WithDryRun() Option
- func WithLogger(l Logger) Option
- func WithProfiles(profiles ...string) Option
- func WithSkipMissing() Option
- func WithTransaction() Option
- type Result
- type SeedHook
- type Seeder
- type SpecOption
- type SpecResult
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Conflict ¶
type Conflict struct {
// contains filtered or unexported fields
}
Conflict describes what to do when a seeded row collides with an existing one on its conflict target (the model's primary key by default).
func Error ¶
func Error() Conflict
Error performs a plain insert with no conflict handling, so a duplicate row surfaces as an error. Use it when fixtures are expected to apply to a fresh database.
func Skip ¶
func Skip() Conflict
Skip keeps the existing row untouched on conflict (INSERT ... DO NOTHING). This is the default and makes seeding idempotent.
type Logger ¶ added in v0.2.0
Logger is the interface used for logging within the seeder. Implementations must be safe for concurrent use. Set it with WithLogger.
type Option ¶
type Option func(*Seeder)
Option configures a Seeder.
func WithAfterSeedHook ¶ added in v0.2.0
WithAfterSeedHook registers a hook that is called after each spec is seeded (after insert). Multiple hooks are called in registration order.
func WithAutoOrder ¶
func WithAutoOrder() Option
WithAutoOrder enables automatic, foreign-key-safe load ordering. The seeder inspects each model's belongs-to and has-many relationships and loads parents before children. Explicit After dependencies are always honored on top of this. A dependency cycle makes Run fail; break it with explicit ordering.
func WithBatchSize ¶ added in v0.2.0
WithBatchSize sets the number of rows inserted in each batch when creating records. Use this when seeding large fixture files to avoid excessive memory usage or statement-size limits. A value of 0 (default) inserts all rows in a single Create call.
func WithBeforeSeedHook ¶ added in v0.2.0
WithBeforeSeedHook registers a hook that is called before each spec is seeded (after decoding, before insert). Multiple hooks are called in registration order.
func WithContinueOnError ¶
func WithContinueOnError() Option
WithContinueOnError records a failing spec's error in its SpecResult and proceeds with the remaining specs instead of aborting the run.
func WithDecoder ¶
WithDecoder registers a decoder for files with the given extension (including the leading dot, e.g. ".yaml"). The function unmarshals the file bytes into a pointer to a slice of models. JSON (".json") is registered by default; use this to add formats such as YAML without the core taking on the dependency.
func WithDecoderContext ¶ added in v0.2.0
func WithDecoderContext(ext string, fn func(ctx context.Context, data []byte, dest any) error) Option
WithDecoderContext registers a context-aware decoder for files with the given extension. This is like WithDecoder but the function also receives the context from Run, allowing cancellation and tracing.
func WithDefaultConflict ¶
WithDefaultConflict sets the conflict strategy used by specs that do not specify their own. The built-in default is Skip (idempotent seeding).
func WithDryRun ¶
func WithDryRun() Option
WithDryRun decodes and plans every spec but writes nothing. SpecResult.Planned reports how many rows would have been inserted.
func WithLogger ¶ added in v0.2.0
WithLogger sets a logger on the seeder. The logger receives informational messages about seeding progress (spec start, rows inserted, etc.).
func WithProfiles ¶
WithProfiles activates the named profiles. Specs tagged with Profile load only when at least one of their profiles is active; untagged specs always load. With no active profiles, tagged specs are skipped.
func WithSkipMissing ¶
func WithSkipMissing() Option
WithSkipMissing treats a registered spec whose file is absent as a skip rather than an error. Useful for optional, directory-based seed sets.
func WithTransaction ¶
func WithTransaction() Option
WithTransaction wraps the entire run in a single database transaction, so a failure rolls back every spec. Note some databases (e.g. MySQL) do not support transactional DDL; this only affects the data writes seeding does.
type Result ¶
type Result struct {
Specs []SpecResult
}
Result reports what a Run did, one entry per registered spec in load order.
type Seeder ¶
type Seeder struct {
// contains filtered or unexported fields
}
Seeder loads JSON (or custom-format) fixtures into a GORM database with idempotent, conflict-aware inserts. Build one with New, register fixtures with Add, then call Run. A Seeder is not safe for concurrent Add calls, but Run may be called repeatedly (seeding is idempotent under the default Skip strategy).
func (*Seeder) Add ¶
func (s *Seeder) Add(name string, dest any, opts ...SpecOption) *Seeder
Add registers a fixture: file name (read from the fs.FS passed to Run) and a pointer to a slice of models it decodes into, e.g. &[]User{}. Specs load in registration order unless WithAutoOrder or After reorders them. Add returns the Seeder for chaining.
type SpecOption ¶
type SpecOption func(*spec)
SpecOption configures a single registered fixture.
func After ¶
func After(names ...string) SpecOption
After declares that this spec must load after the named specs. It is honored regardless of WithAutoOrder.
func ConflictTarget ¶
func ConflictTarget(columns ...string) SpecOption
ConflictTarget overrides the conflict-target columns for this spec. By default the model's primary key is used.
func OnConflict ¶
func OnConflict(c Conflict) SpecOption
OnConflict sets the conflict strategy for this spec, overriding the seeder default.
func Profile ¶
func Profile(profiles ...string) SpecOption
Profile tags this spec with one or more profiles. It then loads only when one of those profiles is active (see WithProfiles).
type SpecResult ¶
type SpecResult struct {
// Name is the fixture file name.
Name string
// Inserted is the number of rows the database reported as affected.
Inserted int64
// Planned is the number of rows decoded from the file. With a dry run it is
// what would have been written; otherwise it equals the input row count.
Planned int
// Skipped is true when the spec was not loaded (filtered by profile, file
// missing with WithSkipMissing, or empty file).
Skipped bool
// Reason explains a skip ("profile", "missing", "empty"), when Skipped.
Reason string
// Err is set when the spec failed and WithContinueOnError was enabled.
Err error
}
SpecResult is the outcome of loading one spec.
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
basic
command
Command basic seeds an in-memory SQLite database from embedded JSON fixtures, demonstrating foreign-key-safe ordering and idempotent re-runs.
|
Command basic seeds an in-memory SQLite database from embedded JSON fixtures, demonstrating foreign-key-safe ordering and idempotent re-runs. |
|
profiles
command
Command profiles demonstrates profile-based seeding.
|
Command profiles demonstrates profile-based seeding. |
|
transaction
command
Command transaction demonstrates transactional seeding.
|
Command transaction demonstrates transactional seeding. |