OpaDo (a port of the TodoMVC app to Opa) now persists todo items to the Opa database. The new version is up on dotcloud, http://opado-tristan.sloughter.dotcloud.com/

I've added a todoitem_ type which stores the item's value and two other attributes we won't use until the next post when we have user accounts for their own todoitem_ stores.

type todo_item = { user_id : string  
                 ; value : string  
                 ; created_at : string  
                 }

To tell Opa where to store the records we'll create, we provide a path to the Opa db function and set its type. For our todo items we use a stringmap since currently the id's are randomly generated strings (I know, I know, but its just an example!). We can then reference a record in the database with the path /todoitem[someid_string].

db /todo_items : stringmap(todo_item)

Now we can insert todoitem_'s to this db path as so:

/todo_items[id] <- { value=x user_id="" created_at="" }

For now userid_ and createdat_ are empty, but I'll be updating that when I add user accounts.

Since we are storing each item, we need to populate the list on page load with whats already stored:

add_todos() =  
  items = /todo_items  
  StringMap.iter((x, y -> add_todo_to_page(x, y.value)), items)

The first line of the function sets the variable items to all the todoitem_ records in the database. We use StringMap.iter to take each todoitem_ and add it to the page. The first argument to the anonymous function is the id the item is stored in the database with (the id we will use in the HTML as well) and the second is the actual todoitem, so we take its value field and pass that to the _addtodotopage_ function along with the id.

To have the addtodos_ function when the list element is ready we add an onready_ attribute that will call add_todos:

<ul id=#todo_list onready={_ -> add_todos() } ></ul>

Lastly, we want to be able to delete a todoitem_ from the database:

remove_item(id: string) =  
  do Dom.remove(Dom.select_parent_one(#{id}))  
  do Db.remove(@/todo_items[id])  
  update_counts()  

remove_all_done() =  
  Dom.iter(x -> remove_item(Dom.get_id(x)), Dom.select_class("done"))

The main piece to notice here is @/todoitems[id]_ in Db.remove(). The @ is saying that we are passing the path itself to remove() and not the value at that path.

Nice and easy! No database to setup or deploy, just Opa. Next time we'll add user accounts, so we don't have to all share the same todo list.