Skip to content

Mutations

Basic Mutator

REL uses mutator to define inserts and updates operation. Using basic mutator won't update created_at and updated_at fields.

Mutator Description
Dec(field string) Decrement a field value by 1
DecBy(field string, n int) Decrement a field value by n
Inc(field string) Increase a field value by 1
IncBy(field string, n int) Increase a field value by n
Set(field string, value interface{}) Set a value to a field
SetFragment(raw string, args ...interface{}) Set a value of a field using SQL fragment

Set title and category values:

err := repo.Update(ctx, &book,
    rel.Set("title", "REL for Dummies"),
    rel.Set("category", "technology"),
)
repo.ExpectUpdate(
    rel.Set("title", "REL for Dummies"),
    rel.Set("category", "technology"),
).For(&book)

Decrement stock:

err := repo.Update(ctx, &book, rel.DecBy("stock", 2))
repo.ExpectUpdate(rel.DecBy("stock", 2)).For(&book)

Update title using SQL fragment:

err := repo.Update(ctx, &book, rel.SetFragment("title=?", "REL for dummies"))
repo.ExpectUpdate(rel.SetFragment("title=?", "REL for dummies")).For(&book)

Structset

Structset is a mutator that generates list of Set mutators based on a struct value. Using Structset will result in replacing the intire record in the database using provided struct, It'll always clear a has many association and re-insert it on updates if it's loaded. Changeset can be used to avoid clearing has many association on updates.

Note

Structset is the default mutator used when none is provided explicitly.

Inserting a struct using structset mutator:

structset := rel.NewStructset(&book, false)
err := repo.Insert(ctx, &book, structset)
repo.ExpectInsert().For(&book)

Changeset

Changeset allows you to track and update only updated values and asssociation to database. This is very efficient when dealing with a complex struct that contains a lot of fields and associations.

Update only price and discount field using changeset:

changeset := rel.NewChangeset(&book)
book.Price = 10
if changeset.FieldChanged("price") {
    book.Discount = false
}

err := repo.Update(ctx, &book, changeset)
repo.ExpectUpdate().ForType("main.Book")

Map

Map allows to define group of Set mutator, this is intended to be use internally and not to be exposed directly to user. Mutation defined in the map will be applied to the struct passed as the first argument. Insert/Update using map wont update created_at or updated_at field.

Insert books and its author using Map:

data := rel.Map{
    "title":    "Rel for dummies",
    "category": "education",
    "author": rel.Map{
        "name": "CZ2I28 Delta",
    },
}

// Insert using map.
err := repo.Insert(ctx, &book, data)
data := rel.Map{
    "title":    "Rel for dummies",
    "category": "education",
    "author": rel.Map{
        "name": "CZ2I28 Delta",
    },
}

repo.ExpectInsert(data).ForType("main.Book")

Reloading Updated Struct

By default, only Inc, IncBy, Dec, DecBy and SetFragment will reload struct from database, Reload mutator can be used to manually trigger reload after inserts/update operations.

Update title and force reload:

err := repo.Update(ctx, &book,
    rel.Set("title", "REL for Dummies"),
    rel.Reload(true),
)
repo.ExpectUpdate(
    rel.Set("title", "REL for Dummies"),
    rel.Reload(true),
).For(&book)

Cascade Operations

REL supports insert/update/delete record and it's associations.

Disable cascade insert (default enabled):

err := repo.Insert(ctx, &book, rel.Cascade(false))
repo.ExpectInsert(rel.Cascade(false)).For(&book)

Enable cascade delete (default disabled):

err := repo.Delete(ctx, &book, rel.Cascade(true))
repo.ExpectDelete(rel.Cascade(true)).For(&book)

Last update: 2024-12-19