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 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).
Index ¶
- func Dir(path string) fs.FS
- type Conflict
- type Option
- func WithAutoOrder() Option
- func WithContinueOnError() Option
- func WithDecoder(ext string, fn func(data []byte, dest any) error) Option
- func WithDefaultConflict(c Conflict) Option
- func WithDryRun() Option
- func WithProfiles(profiles ...string) Option
- func WithSkipMissing() Option
- func WithTransaction() Option
- type Result
- 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 Option ¶
type Option func(*Seeder)
Option configures a Seeder.
func WithAutoOrder ¶
func WithAutoOrder() Option
WithAutoOrder enables automatic, foreign-key-safe load ordering. The seeder inspects each model's belongs-to 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 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 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 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. |