Skip to main content

Insert

Insert writes one entity or several. Every field is written as it is, so a zero is stored as zero, and generated keys come back on your struct.

One or several​

alice := &User{
Name: "Alice",
Email: "alice@example.com",
Age: 30,
}

err := db.Users.Insert(ctx, alice)
if err != nil {
return err
}

fmt.Println(alice.ID) // set by the database

Several go in together, all or nothing: if one fails, every row is rolled back and the keys it set are cleared.

err := db.Users.Insert(ctx, alice, bob)

// A slice of pointers spreads.
err = db.Users.Insert(ctx, users...)

A whole graph​

Insert also saves the entities a new struct points at, parents first, filling in foreign keys as it goes.

alice := &User{
Name: "Alice",
Email: "alice@example.com",
Posts: []Post{{Title: "Hello"}, {Title: "Second"}},
}

err := db.Users.Insert(ctx, alice)

fmt.Println(alice.Posts[1].UserID == alice.ID) // true

It works from the child too, and an existing parent is linked, not inserted again.

post := &Post{Title: "New", User: alice}

err := db.Posts.Insert(ctx, post)
INSERT INTO "users" (...) VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"
INSERT INTO "posts" (...) VALUES ($1, $2, $3, $4, $5), ($6, $7, $8, $9, $10) RETURNING "id"

New rows that depend on each other in a loop are refused with ant.ErrCycle.

Ignoring relations​

InsertOnly writes the row and leaves its relation fields alone.

err := db.Users.InsertOnly(ctx, alice)

Find or create​

FirstOrCreate returns the first row that matches the conditions, or inserts yours. The bool tells you which happened. If another writer gets there first, a unique constraint stops this insert, and you get the winner's row back.

user, created, err := db.Users.FirstOrCreate(
ctx,
&User{Name: "Ada", Email: "ada@example.com"},
ant.Eq(&U.Email, "ada@example.com"),
)

FirstOrNew is the same without saving. Its bool reports whether a row was found.

user, found, err := db.Users.FirstOrNew(ctx, &User{Name: "Ada"}, ant.Eq(&U.Name, "Ada"))

Copying a row​

ant.Clone copies an entity with its key and relations cleared, ready to insert as a new row.

twin := ant.Clone(alice)
twin.Email = "twin@example.com"

err := db.Users.Insert(ctx, twin)

When a constraint fails​

A constraint failure is the database's own error, and the Is helpers read it on every database.

err := db.Users.Insert(ctx, &User{Email: alice.Email})

if ant.IsUniqueViolation(err) {
return errors.New("that email is taken")
}