Skip to content
Open Saka

Changing data

Each change you enter in the REPL is an action. An action keeps all its changes if it succeeds, and none if any part fails.

+= adds to a number:

visits += 1
visits // {1}

|= adds Values to a Bag, and \= removes them:

tags |= "gift"
tags \= "sale"
tags // {"gift", "new"}

Adding a second count for "pen" fails, because stock allows one Value for each key:

stock |= "pen" -> 11 // error: the key pen occurs more than once

An update block makes several changes at once. Remove the old Value and add the new one together:

update {
stock \= "pen" -> 12
stock |= "pen" -> 11
}
stock // {"book" -> 3, "pen" -> 11}

Name a role and give its properties to add a member:

Book(title: "Dune", pages: 412)
Book(title: "Emma", pages: 474)

The REPL shows each new Book’s ref, its identity in the database, such as <ref:1GpWNsiDASAR18jy33CRep>.

Book.title // {"Dune", "Emma"}

Book::pages holds a Map from each Book to its page count. To change one Book’s count, remove its Map and add a new one:

update {
Book::pages \= Book if .title == "Dune" to .pages
Book::pages |= Book if .title == "Dune" to 415
}

Book if .title == "Dune" finds the Book, and to pairs it with a value; Transforming Bags explains both. Each Book needs a page count, so the two changes must happen in one block.

A procedure names a change so that you can make it again. Its parameters work like a function’s, and : void says it returns nothing:

proc set_author(title! str, author! str): void = {
update {
Book::author \= Book if .title == title to .author
Book::author |= Book if .title == title to author
}
}
set_author("Dune", "Frank Herbert")

The REPL answers ():{}, an empty result. Books without an author have an empty Bag there, and ?? fills it in:

Book map (title: .title, author: .author ?? "unknown")
// {
// (author: "Frank Herbert", title: "Dune")
// (author: "unknown", title: "Emma")
// }

A Flow always reads the current data:

def long_books = Book if .pages > 450
long_books.title // {"Emma"}

Adding a long Book changes its result:

Book(title: "Ulysses", pages: 730)
long_books.title // {"Emma", "Ulysses"}

\= removes members from a role, and they lose their properties:

Book \= Book if .title == "Ulysses"
long_books.title // {"Emma"}

This fails, because a Book needs a title, and it leaves the data unchanged:

Book(pages: 10) // error: Book::title requires exactly 1 value for each member

:undo takes back the last change, which removed Ulysses:

:undo
long_books.title // {"Emma", "Ulysses"}

:redo makes the change again:

:redo

Edit → Undo and Edit → Redo in the menu do the same. Undo goes back one change at a time and stops at a change to declarations, such as def long_books. See Undo and redo.