Defining Views
A view holds the data that queries read. Define the shape of an item as a struct, and call the NewItemView function to create a view that holds such items in memory:
type BookItem struct {
ID string `json:"id"`
Title string `json:"title"`
Author string `json:"author"`
IsBorrowed bool `json:"isBorrowed"`
BorrowedUntil string `json:"borrowedUntil"`
EventID string `json:"eventId"`
}
catalog := architecturekit.NewItemView[BookItem]()
Keep the ID of the last event in every item, so that a caller can hand it over to a command that uses the NewIsSubjectOnEventIDPrecondition function (see Guarding Against Concurrent Changes).
To add an item, call the Insert function:
catalog.Insert(BookItem{
ID: "42",
Title: "2001 – A Space Odyssey",
Author: "Arthur C. Clarke",
})
To change items, call the Update function with a function that selects the items and a function that changes them. It returns the number of changed items:
isBook42 := func(item BookItem) bool {
return item.ID == "42"
}
changed := catalog.Update(isBook42, func(item *BookItem) {
item.IsBorrowed = true
})
To change items or add an item if none matches, call the Upsert function and additionally hand over the item to add. It returns the number of changed items, which is 0 if the item was added:
changed := catalog.Upsert(isBook42, func(item *BookItem) {
item.IsBorrowed = true
}, BookItem{
ID: "42",
IsBorrowed: true,
})
To remove items, call the Delete function. It returns the number of removed items:
removed := catalog.Delete(isBook42)
To read all items, call the All function. It returns an iterator over a copy of the items, which you can use e.g. inside a for range loop:
items, err := catalog.All(context.TODO())
if err != nil {
// ...
}
for item := range items {
// ...
}
To keep items somewhere else, for example in a database, implement the View interface, which consists of the All function:
type BookTable struct {
// ...
}
func (t *BookTable) All(ctx context.Context) (iter.Seq[BookItem], error) {
// ...
}