autoseed

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 18, 2026 License: MIT Imports: 10 Imported by: 0

README

autoseed

Seed your database from your ORM model. One call, full referential integrity, realistic distribution. No factories, no YAML files, no ordering files by number to get foreign keys right.

From the author of EFCore.AutoSeed — the same idea, native to Go.

[GIF placeholder — will be recorded from the first real run before launch.]

Status

v1.0.0. Everything under "Works today" below ships in this release — see the roadmap for what's next.

Works today: reading a GORM or ent model, Explain, and Seed on both adapters — real inserts, in dependency order, with long-tail cardinality, single-column and composite unique-field dedup, a cardinality cap that covers a ternary/N-ary "attributed join" as well as the pairwise case, deferred second-pass cycles, WithNilRate for leaving a Nullable field genuinely NULL at a configurable rate, WithLocale("pt_BR") for Brazilian names, cities, streets and phone numbers — tested against real PostgreSQL and MySQL — SeedCoverage on both adapters for the smallest dataset that exercises every field and relationship shape instead of a bulk one, tested against real PostgreSQL so far, and a small CLI (autoseed explain) for reading an ent schema straight from source, no database or generated client needed.

Not built yet: every value-realism knob beyond the ~16 built-in inference rules and the pt_BR locale (dirty data, weekday/business-hour clustering, another locale), and a seed CLI command for either adapter — see Command line below for why. Code blocks below that use them are the design, marked as such inline.

The problem

Every Go seeding tool available today asks you to describe the model again — in YAML fixtures, in seeder structs with hand-written loops, in JSON files named 01_role.json, 02_user.json so the insertion order works out. You already declared all of it in your GORM tags or your ent schema. Then the model changes and your seeder breaks.

The best value generator in the ecosystem says it plainly: gofakeit generates individual data points — interrelated data sets with consistent foreign keys require additional manual logic outside the library. That manual logic is what everybody keeps rewriting. This is it, written once.

And the data you end up with is uniform: every customer with three orders. In production one customer has 500,000. The query planner picks a different plan for each shape, so your performance test passes while lying to you.

Usage

import (
    "github.com/danellalc/autoseed"
    "github.com/danellalc/autoseed/gormseed"
)

err := gormseed.Seed(ctx, db, []any{&Customer{}, &Order{}, &OrderItem{}},
    autoseed.WithSeed(42),
    autoseed.WithScale(1_000),
)

That is the whole API for the common case, and it runs today. GORM keeps no registry of every struct you have used — unlike an EF Core DbContext, a *gorm.DB cannot tell you what it knows — so the model list is the one thing you state; autoseed works out the insertion order, resolves cycles, infers what each field means, and writes referentially valid rows, one entity type at a time, foreign keys copied from the real, already-inserted parent row.

A full, runnable version of this example — real SQLite database, Explain and Seed both — lives in examples/gormseed-basic; go run . there does the whole thing with no setup.

Same seed, same data. Always.

go get github.com/danellalc/autoseed

What makes it different

It reads the ORM model, not the database schema

DDL introspection sees tables and columns. The ORM model also carries associations, embedded structs, polymorphic relations and soft-delete conventions.

autoseed generates data your database accepts and your application can actually read — soft-deleted rows in realistic proportion, embedded structs populated instead of left zero-valued, association tables filled on both sides.

It also works before the database exists.

It works out the order itself

Foreign keys form a graph. autoseed topologically sorts it (stable: ties break on entity name), detects cycles, and resolves the nullable ones with a second pass.

No numbered files. No ordering by hand.

When a cycle is genuinely unsatisfiable — a required foreign key with no nullable link — autoseed names the entities involved and returns an error, instead of letting your database throw a constraint violation.

It generates realistic distributions, not just realistic values

Built on gofakeit for values (it does not replace it), autoseed adds the shape. Related row counts are drawn per parent from an exponential long tail, not a flat average:

Customer:   1,000 rows
Order:      3,847 rows   long tail: mean 3.8, max 512, one customer holds 13%
OrderItem: 19,203 rows

Most customers have one order. A few have hundreds — sometimes zero. Coherent values agree with each other on the same row (FirstName+LastName+Email, Price×Quantity=Total, UpdatedAt at or after CreatedAt). Weekday/business-hour clustering and dirty data are not built yet — see the roadmap.

It explains itself before it writes anything

Works today — the one example on this page that actually runs:

plan, err := gormseed.Explain(db, []any{&Customer{}, &Order{}, &OrderItem{}})
fmt.Println(plan.Report())

Prints the insertion order, which cycles got deferred to a second pass, and which constructs were skipped and why. Nothing is written. GenerationPlan itself already computes row counts for Seed internally; wiring them into Explain's report too is still open — see the roadmap.

Coverage mode

The opposite of bulk. The smallest dataset that exercises everything:

err := gormseed.SeedCoverage(ctx, db, []any{&Customer{}, &Order{}, &OrderItem{}},
    autoseed.WithSeed(42),
)

Every nullable field in both states, every bool-kind field in both states, every sized string field at empty, one character and its declared maximum length, every relationship at zero, one and several children. Usually well under 50 rows. WithScale and WithNilRate are ignored — row counts and null placement come from the model's own shape, not a scale factor or a probability.

Command line

go install github.com/danellalc/autoseed/cmd/autoseed@latest

autoseed explain --schema ./ent/schema

Reads an ent schema straight from source and prints the same report entseed.Explain returns — insertion order, deferred cycles, skipped constructs — with no database connection and no generated *ent.Client needed.

That is also the CLI's entire scope. There is no gormseed equivalent and no seed subcommand for either adapter: a precompiled autoseed binary cannot import an arbitrary caller's own Go types — a GORM model list and a generated ent client both only exist inside the caller's own compiled module. entc.LoadGraph is the one exception, built for exactly this kind of external tooling to read schema source directly. Writing real rows stays a Go API call (gormseed.Seed, entseed.Seed) made from within your own module — see ARCHITECTURE.md for the full reasoning.

Adapters

The core is ORM-agnostic. Each ORM gets an adapter that reads its model:

Adapter Reads Status
autoseed/gormseed GORM struct tags via schema.Parse v1
autoseed/entseed ent's schema, via entc.LoadGraph v1
sqlc, Bun roadmap, on demand

GORM first because it is where most Go codebases are. ent second because its schema is a graph — nodes and edges are exposed by codegen, which made it the technically sweetest target once GORM proved the core contract out. ent has no runtime introspection the way GORM's schema.Parse does — entseed reads the schema source itself through entc.LoadGraph, the same mechanism entc uses during go generate, and has no composite primary keys, so a ternary or N-ary "attributed join" is expressed there as a surrogate ID plus a composite UniqueConstraints entry instead of a composite key.

What it does not do

  • It does not anonymise production data. Not a masking tool.
  • It is not a service. No cloud, no account, no server.
  • GORM and ent only (for now). Not raw database/sql, not every ORM. Adapters are on demand, with traction, never speculatively — two tools in this category died of scope creep.
  • PostgreSQL, MySQL and SQLite only.
  • It refuses models it cannot satisfy, loudly and by name.

Validated

A property-based test asserts that for any model and any mix of nullable/required references, the engine either names an unsatisfiable cycle or produces an order that respects every foreign key; it runs on every commit against the graph and cycle engine directly, no database needed. A second layer of property tests runs gormseed.Seed itself, seed and scale rapid-varied, against a real containerized PostgreSQL and checks every row for orphaned foreign keys and primary key collisions — a linear chain, a diamond of two required principals merging into one dependent, a nullable self-reference, a composite-primary-key junction, a shared-primary-key one-to-one, and a self-referencing many-to-many (a "follows" table, where two foreign keys target the same entity and only their own columns tell them apart).

gormseed.Seed is tested against real, containerized PostgreSQL — never SQLite-only — covering a required-FK chain with long-tail cardinality, a nullable self-reference, a required/nullable two-entity cycle resolved in a second pass, a many-to-many join table, a single-column and a composite unique constraint, a ternary (three-participant) attributed join, and WithNilRate producing real NULLs for both database/sql wrapper and pointer-typed fields without ever touching a plain field the database happens to allow NULL on but Go cannot represent absence for. A combined "MegaMart" model exercises every one of the core shapes together in a single seed run — self-reference, embedded struct, composite and shared primary keys, unique columns, soft-delete bias, a many-to-many join and a correlated derived value — the way a real application model mixes them. MySQL gets its own real-container test for the required-FK path and its LastInsertId batch arithmetic, not yet the same depth.

entseed.Seed and entseed.Explain get the same real-Postgres treatment on their own real ent schemas: a required chain, a nullable self-reference, a many-to-many edge reported as a named skip (not silently dropped), a composite unique index over plain fields and over edge-owned foreign keys, a ternary junction expressed via UniqueConstraints, and WithNilRate clearing an Optional field through ent's own ClearField mechanism. Against real, public schemas is still ahead of launch.

Compared to

Tool Approach
gofakeit generates values for structs; autoseed is built on it and does not replace it
go-faker/faker fills structs by reflection, no relationships
gorm-seeder / gormseeder you write the Seed() loops yourself
populator, testfixtures YAML fixtures you write; ordering is yours to manage
fabricator generics factories you define per type
EF Core / .NET EFCore.AutoSeed, same author, same design

They are all either value generators or manual seeders. None reads the model and derives the order. That is the gap this fills.

License

MIT

Documentation

Overview

Package autoseed reads an ORM model through an adapter's ModelSource and seeds a database from it: full referential integrity, deterministic output, no hand-written ordering or fixtures.

Index

Constants

This section is empty.

Variables

View Source
var ErrDuplicateEntity = errors.New("autoseed: duplicate entity name")

ErrDuplicateEntity is returned when two or more Entity values in a model share the same Name: a ModelSource bug, since the graph cannot tell them apart.

View Source
var ErrInvalidReference = errors.New("autoseed: reference names no fields")

ErrInvalidReference is returned when a Reference names no Fields: there is no column for it to mean anything.

View Source
var ErrInvalidScale = errors.New("autoseed: scale must not be negative")

ErrInvalidScale is returned when Options.Scale is negative: there is no meaningful row count to draw from it.

View Source
var ErrNilSeed = errors.New("autoseed: seed is nil")

ErrNilSeed is returned when a *SeededSource parameter is nil: every random draw in the pipeline must derive from one, so there is nothing safe to do with its absence.

View Source
var ErrUnknownReference = errors.New("autoseed: reference targets an unknown entity")

ErrUnknownReference is returned when an Entity's Reference names a Target that does not match any Entity.Name in the model.

View Source
var ErrUnsatisfiableCycle = errors.New("autoseed: unsatisfiable required foreign key cycle")

ErrUnsatisfiableCycle is returned when a group of entities form a foreign key cycle with no nullable reference to break it: no insertion order can satisfy every required foreign key at once.

View Source
var ErrUnsatisfiableUniqueness = errors.New("autoseed: could not generate a unique value")

ErrUnsatisfiableUniqueness is returned when a duplicate value for a unique field could not be fixed within the retry budget: the value space is too small for the requested row count.

View Source
var ErrUnsupportedField = errors.New("autoseed: no inference rule for field")

ErrUnsupportedField is returned when no inference rule can produce a value for a field: an adapter read a construct value generation does not understand yet, named rather than silently generating the wrong thing or the zero value.

Functions

func ApplyCoverageOverrides

func ApplyCoverageOverrides(entity Entity, rows []map[string]any)

ApplyCoverageOverrides mutates rows in place so entity's own Nullable, bool-kind and sized string fields each cycle through their declared boundary states across the row set PlanCoverage already sized for this — a field never touches more than one axis, Nullable taking priority over bool-kind for a field that happens to be both, so a later axis's write can never silently undo an earlier one's. A reference's own foreign key field is skipped entirely: its real value is assigned separately, during persistence, and overwrites whatever a generated row held for it regardless — touching it here would only risk an adapter treating a placeholder null as if it meant something, for a field that will be overwritten before it ever reaches the database. A primary key field is skipped the same way: it is either database-generated or a natural key GenerateRow already owns, never a field whose boundary states are this feature's business. A Unique bool-kind field only has the override applied to its first two rows — enough to prove both true and false occur — since a bool has only two possible values, and forcing the same alternating pattern past a third row would manufacture a duplicate EnsureUnique cannot repair (it only rewrites string-kind fields); rows beyond the second keep whatever GenerateRow produced for them. GenerateRow's own value for a field no axis here claims is left untouched.

func EnsureUnique

func EnsureUnique(entity Entity, rows []map[string]any, seed *SeededSource) error

EnsureUnique rewrites duplicate values, in row order, for every single-column string field on entity marked Unique, and for every composite tuple in entity.UniqueConstraints with at least one independent string column to rewrite. A constraint that names a foreign key field is left alone here entirely: at this stage a row's reference fields hold only a placeholder value, not the real parent key persistence assigns later, so there is nothing meaningful to deduplicate yet — that shape's uniqueness is guaranteed by construction in the generation plan instead. A constraint with no string field to rewrite is likewise out of scope, the same way a single non-string Unique field already is. The first row to use a value or tuple keeps it; a later duplicate has its rewritable field rewritten with a random numeric suffix, retried up to 20 times. Two constraints that share a rewritable field are resolved together, not independently: rewriting one row's field to satisfy one constraint can change what that same row's tuple looks like under every other constraint containing that field, so every affected constraint is re-checked until a row settles. seed must be scoped to the entity, not a specific row, and must not be nil. It returns ErrUnsatisfiableUniqueness, naming the entity and field(s), if a value cannot be fixed within the retry budget, or ErrNilSeed for a nil seed.

func JunctionIndices

func JunctionIndices(participants []JunctionParticipant, driverTarget string, driverRow, blockLocal int, rows func(target string) int) []int

JunctionIndices returns, for one row at position blockLocal within its driver row's block, the parent row index to pair with for each of participants, in the same order. rows reports how many rows already exist for a given entity name. driverRow is the driver's own row index for this block; a participant whose Target equals driverTarget is self-referencing and skips driverRow itself, since a row can never pair with itself.

The mapping decomposes blockLocal in mixed radix over each participant's own usable row count, in participants' own order: this is injective as long as blockLocal is less than the product of those counts, exactly the guarantee PlanGeneration's cap on ChildCounts already gives every block. Two rows in the same driver block therefore always draw a distinct combination across every participant; two rows in different blocks differ by driverRow alone.

Types

type DeferredReference

type DeferredReference struct {
	Entity string
	Fields []string
	Target string
}

DeferredReference is a nullable reference that participates in a cycle: it must be inserted as null and patched to its real value once every entity in Order has been written.

type DependencyGraph

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

DependencyGraph is the directed graph of foreign key references between an ORM model's entities, built from a ModelSource's Entities.

func NewDependencyGraph

func NewDependencyGraph(entities []Entity) (*DependencyGraph, error)

NewDependencyGraph builds a DependencyGraph from entities. It returns ErrDuplicateEntity if two entities share a Name, ErrUnknownReference if any Reference.Target does not match an Entity.Name in entities, and ErrInvalidReference if a Reference names no Fields.

func (*DependencyGraph) Resolve

func (g *DependencyGraph) Resolve() (*TopologicalSortResult, error)

Resolve resolves every cycle in the graph and returns a stable topological order for the remaining, acyclic references. Ties in the order break on entity name, never on map iteration order, so the same graph always resolves to the same order. It returns ErrUnsatisfiableCycle if a cycle has no nullable reference to break it.

type Entity

type Entity struct {
	Name              string
	Fields            []Field
	References        []Reference
	UniqueConstraints [][]string
}

Entity describes one seedable type read from an ORM model: its name, the fields that hold values, and the foreign key references to other entities. UniqueConstraints holds one entry per composite unique index: two or more field names that, taken together as a tuple, must be unique across every row. A single-column unique constraint is expressed on the Field itself instead — an entry here always has two or more Fields.

type EntityGenerationPlan

type EntityGenerationPlan struct {
	Entity               string
	RowCount             int
	Driver               string
	DriverFields         []string
	ChildCounts          []int
	JunctionParticipants []JunctionParticipant
}

EntityGenerationPlan is the row count and cardinality decision for one entity: how many rows to generate and, for a dependent entity, how many of them belong to each row of its driving principal. Driver and DriverFields together identify the specific reference chosen as the driver — Fields disambiguates the case where two references target the same entity (a self-referencing many-to-many). JunctionParticipants is set the same way, only when entity's own primary key, or one of its UniqueConstraints, is exactly covered by the driver reference together with one or more other required references — a many-to-many join table, an explicit composite-key "attributed join" entity like an inventory or order-line row, or a ternary association with three or more participating references — where each driver row can pair with a given combination of JunctionParticipants rows at most once.

type Field

type Field struct {
	Name          string
	Type          reflect.Type
	Size          int
	Nullable      bool
	Unique        bool
	PrimaryKey    bool
	AutoIncrement bool
	SoftDelete    bool
}

Field describes one column-backed value on an Entity. Type is the Go type value generation must produce; Size is the column's maximum length for a string type, zero when the column has no declared limit. Nullable reports whether generation may leave this field's value out entirely and have persistence turn that into a real database NULL — not merely whether the underlying column's schema allows NULL. A column that allows NULL but whose Go representation has no way to express absence (a plain, non-pointer field with no database/sql Null* wrapper) is Nullable=false: generation would have nothing meaningful to leave out, only its own zero value.

type GenerationPlan

type GenerationPlan struct {
	Entities []EntityGenerationPlan
}

GenerationPlan is the row count and cardinality decision for every entity, in the same order Resolve produced.

func PlanCoverage

func PlanCoverage(entities []Entity, order []string, deferred []DeferredReference) (*GenerationPlan, error)

PlanCoverage computes the smallest row count and cardinality decision per entity that exercises every axis SeedCoverage promises: a required, non-driver reference target never left at zero rows (the same backstop PlanGeneration itself relies on); a driver row hosting zero, one, and several ("many" — two, enough to prove the relationship isn't capped at one, without inflating row counts further) children for whatever depends on it; and, folded into whatever rows that already produces rather than adding rows of their own, a Nullable field, a bool-kind field, and a sized string field each cycling through their own boundary states across the entity's row set. It shares PlanGeneration's junction, shared-key and backstop rules unchanged through planWithStrategy — only how many rows a root gets, how many children a driver row gets, and the floor a dependent's own row count must reach, differ from the bulk, random-seed path: a dependent entity is itself floored at coverageRowCount too, through planWithStrategy's rowFloor hook, so an entity that is simultaneously a dependent (has a required reference of its own) and a driver target (or carries its own field axes) still gets enough rows for both roles, headroom under any shared-key or junction cap permitting. order and deferred come from DependencyGraph.Resolve().

func PlanGeneration

func PlanGeneration(entities []Entity, order []string, deferred []DeferredReference, seed *SeededSource, options Options) (*GenerationPlan, error)

PlanGeneration computes a row count for every entity in order: a root entity — one with no required, non-deferred reference to another entity — gets options.Scale rows directly. A dependent entity picks a driving principal (its required reference whose Target sorts first, Fields breaking a tie between two references to the same target; only one side of a many-to-many join table ever becomes a driver, by the same rule) and draws a child count per driver row from an Exponential(mean) distribution, long-tailed and occasionally zero, the same shape the .NET sibling uses. seed is the root SeededSource; order and deferred come from DependencyGraph.Resolve(). It returns ErrNilSeed for a nil seed and ErrInvalidScale for a negative options.Scale.

type JunctionParticipant

type JunctionParticipant struct {
	Target string
	Fields []string
}

JunctionParticipant identifies one non-driver reference in a junction shape: a required reference that, together with the driver and zero or more sibling participants, exactly covers a composite key. Target and Fields work like Reference's own.

type ModelSource

type ModelSource interface {
	Entities() ([]Entity, error)
}

ModelSource is the contract every ORM adapter implements: reading an ORM's model and exposing it as entities, fields and references. Everything downstream of this package consumes only what Entities returns.

type Option

type Option func(*Options)

Option configures Options.

func WithLocale

func WithLocale(locale string) Option

WithLocale sets which locale's own rules claim a name, address and phone field before the generic, English-shaped fallback gets a turn — "pt_BR" today, more as demand shows up, the same on-demand bar every adapter and rule in this project ships under. An unrecognized locale, including the empty default, falls back to the generic rules — the same as not setting a locale at all, never an error, matching every other Option's own silent-normalize behavior (WithNilRate clamps rather than rejecting an out-of-range rate).

func WithNilRate

func WithNilRate(rate float64) Option

WithNilRate sets the per-row probability that a Nullable field's value is left out entirely instead of generated — a field the adapter marks Nullable only when persistence can actually turn a missing value into a real database NULL. rate is clamped to [0,1].

func WithScale

func WithScale(scale int) Option

WithScale sets the row count for root entities — those with no required foreign key into another seeded entity. Related entities scale from their principal's row count instead of Scale directly.

func WithSeed

func WithSeed(seed uint64) Option

WithSeed fixes the root seed every random draw derives from. Same seed, same data, always.

type Options

type Options struct {
	Seed    uint64
	Scale   int
	NilRate float64
	Locale  string
}

Options configures Seed (and, once built, the planned SeedCoverage). Build one with NewOptions and functional Option values; the zero value is not meaningful on its own.

func NewOptions

func NewOptions(opts ...Option) Options

NewOptions returns the default Options with every given Option applied. The default seed is 0; the default scale is 100; the default nil rate is 0 (every nullable field always gets a generated value); the default locale is "" (generic, English-shaped values).

type Plan

type Plan struct {
	Order    []string
	Deferred []DeferredReference
	Skipped  []SkipReason
}

Plan is the result of resolving a ModelSource without writing anything: the insertion order, the references deferred to a second pass, and the constructs an adapter left out on purpose.

func Explain

func Explain(source ModelSource, skipped ...SkipReason) (*Plan, error)

Explain resolves source into a Plan without writing to any database. skipped carries adapter-specific constructs — a polymorphic association, say — that source's Entities left out of its references on purpose; Explain folds them into the report instead of discarding them.

func (*Plan) Report

func (p *Plan) Report() string

Report renders p as a human-readable summary: insertion order, deferred references, then skipped constructs. A section with nothing to show is omitted.

type Reference

type Reference struct {
	Fields   []string
	Target   string
	Nullable bool
}

Reference describes a foreign key on an Entity that points at another entity's primary key. Fields are the field names on the owning entity that carry the key, more than one for a composite foreign key, always in the same order as the referenced entity's own key fields. Target is the referenced Entity's Name.

type SeededSource

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

SeededSource derives deterministic randomness for one position in the generation tree — root, entity, row index, field — so that generating row 500 of an entity in isolation produces exactly the value it would produce inside a full batch. Every autoseed.Rand call anywhere in the pipeline must come from a SeededSource, never from math/rand directly.

func NewSeededSource

func NewSeededSource(seed uint64) *SeededSource

NewSeededSource returns the root SeededSource for a seed.

func (*SeededSource) Entity

func (s *SeededSource) Entity(name string) *SeededSource

Entity returns the SeededSource scoped to one entity.

func (*SeededSource) Field

func (s *SeededSource) Field(name string) *SeededSource

Field returns the SeededSource scoped to one field within a row.

func (*SeededSource) Rand

func (s *SeededSource) Rand() *rand.Rand

Rand returns the deterministic *rand.Rand for the current position.

func (*SeededSource) Row

func (s *SeededSource) Row(index int) *SeededSource

Row returns the SeededSource scoped to one row index within an entity.

func (*SeededSource) Seed

func (s *SeededSource) Seed() uint64

Seed returns the raw derived seed for the current position, for callers that need to build their own rand.Source-compatible generator (gofakeit, for one) rather than a *rand.Rand.

type SkipReason

type SkipReason struct {
	Entity string
	Field  string
	Reason string
}

SkipReason names one construct an adapter chose not to translate into the ModelSource contract: an entity, the field involved, and why. Explain reports these by name instead of an adapter silently generating wrong data for them.

type TopologicalSortResult

type TopologicalSortResult struct {
	Order    []string
	Deferred []DeferredReference
}

TopologicalSortResult is the outcome of resolving a DependencyGraph: the insertion order and the references that could not be satisfied on first insert and must be patched in a second pass.

Directories

Path Synopsis
cmd
autoseed command
Command autoseed is a CLI wrapper around entseed.Explain: it reads an ent schema straight from source and prints the same insertion-order and skip report the Go API's Explain returns, with no database connection and no generated *ent.Client needed.
Command autoseed is a CLI wrapper around entseed.Explain: it reads an ent schema straight from source and prints the same insertion-order and skip report the Go API's Explain returns, with no database connection and no generated *ent.Client needed.
Package entseed reads an ent schema via entc.LoadGraph and adapts it to the autoseed.ModelSource contract.
Package entseed reads an ent schema via entc.LoadGraph and adapts it to the autoseed.ModelSource contract.
internal/entfixtures
Package entfixtures holds a small, real ent schema and its generated client, used only by entseed's own tests to exercise the adapter against real ent code (ent has no runtime schema introspection the way GORM does — a genuine client must be generated to test against).
Package entfixtures holds a small, real ent schema and its generated client, used only by entseed's own tests to exercise the adapter against real ent code (ent has no runtime schema introspection the way GORM does — a genuine client must be generated to test against).
internal/entfixtures/schema
Package schema is a small, real ent schema used only to generate a client entseed's own tests exercise the adapter against.
Package schema is a small, real ent schema used only to generate a client entseed's own tests exercise the adapter against.
Package gormseed reads a GORM model through schema.Parse and adapts it to the autoseed.ModelSource contract.
Package gormseed reads a GORM model through schema.Parse and adapts it to the autoseed.ModelSource contract.
Package inference generates field values through gofakeit, seeded hierarchically from an autoseed.SeededSource, so autoseed's core stays testable without a value generator: the same separation the .NET sibling keeps between AutoSeed.Core and AutoSeed.Inference.
Package inference generates field values through gofakeit, seeded hierarchically from an autoseed.SeededSource, so autoseed's core stays testable without a value generator: the same separation the .NET sibling keeps between AutoSeed.Core and AutoSeed.Inference.

Jump to

Keyboard shortcuts

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