Home > Tutorials > Opa > Opa tutorial: CRUD application. Create, Read, Update and Delete from database

Opa tutorial: CRUD application. Create, Read, Update and Delete from database

Share on TwitterSubmit to reddit

This Opa tutorial shows how to perform typical operations in a database by using a web user interface. Our example it’s an application to manage a database of “Customers” where the user can:

  • List all the registered customers.
  • Create a new customer in the database.
  • Update an existing customer.
  • Delete a register.

Try a demo of the application at http://crud-semoru.dotcloud.com/

Two files have been created to build this application:

  • main.opa
  • customer.opa

Main.opa

It mainly contains the logic of the application dispatcher, so it will call the right action depending on the URL.

package semoru.crud.dispatcher

import semoru.crud.customer
import stdlib.web.client
import stdlib.core.web.core

/* URL Dispatcher */
start(uri) = (
      match uri with
      | {path = ["edit"] query=[("id", id)] ... } -> Resource.styled_page("CRUD - Edit", [], Customer.edit(id))
      | {path = ["delete"] query=[("id", id)] ... } -> Resource.styled_page("CRUD - Delete", [], Customer.confirmation(id))
      | {path = ["add"] ... } -> Resource.styled_page("CRUD - Add", [], Customer.new())
      | {~path ...} -> Resource.styled_page("CRUD - Welcome", [], Customer.start())
)

server = Server.simple_dispatch(start)

At the top we’re importing the packages, being one of them the Customer package that we will see later. Next we have a comparator, depending on the uri the application will execute Customer.edit, Customer.delete, Customer.add or Customer.start to go the welcome page. In the code above we’re taking into account the variables “path” and “query” from the input parameter “uri” to make the right mapping with the call.

Note: See here more information about URI scheme at http://en.wikipedia.org/wiki/URI_scheme

Customer.opa

This file define the class Customer which contains its type definition (instance variables), methods and database creation. Let’s begin with the definitions:

package semoru.crud.customer

import stdlib.themes.bootstrap
import stdlib.web.client
import stdlib.core.web.core

/* Database object type definition */
type Customer =
{
        sid: int
        name : string
        email: string
}
/* Database object creation */
db /customers : intmap(Customer)

First thing, import the packages. “Bootstrap” will help us with the style of the front end (see more information at http://twitter.github.com/bootstrap/)

Next, we will define the type of the Customer object. In this tutorial a customer will be composed by a sid (system identificator), a name and an email. Following we will create the database using the format intmap.

Once we have defined the structure for the object and the database, let’s define its methods. Let’s see the different actions separately:

List/Read all customers

   getHTMLTable() =
        <table id=#tabla class="zebra-striped">
            <tr>
                <td>
                   Actions
                </td>
                <td>
                   Name
                </td>
                <td>
                   Email
                </td>
            </tr>
           {
              List.map(
                customer ->
                   <tr>
                       <td>
                           <a href="/edit?id={customer.sid}">Edit</a> <b>|</b>
                           <a href="/delete?id={customer.sid}">Delete</a>
                       </td>
                       <td>
                           {customer.name}
                       </td>
                       <td>
                           {customer.email}
                       </td>
                   </tr>,
                IntMap.To.val_list(/customers)
              )
           }
        </table>

The method getHTMLTable() will iterate all the registers from the database (by using List.map() function) to generate a html table.

   start()=
        <div class="container">
             <h1> <a href="http://www.semoru.com">semoru.com</a> CRUD example</h1>
             <table>
                 <tr>
                    <td><h2>Customer list:</h2></td>
                 </tr>
                 <tr>
                    <td><div class="btn primary" onclick={_ -> Client.goto("/add")}>Add new customer</div></td>
                 </tr>
             </table>
             <div>{getHTMLTable()}</div>
        </div>

The method start() is the default action, called when an user enters into the application. It uses the method getHTMLTable() to build the page that displays all the customers in the system.

Create a customer

create() =
        key = Db.fresh_key(@/customers)
        do /customers[key] <- {sid = key; name=Dom.get_value(#name); email=Dom.get_value(#email)}
        Client.goto("/")

The method create() will generate a new key that will be stored as customer’s sid. It registers the sid, name and email in the database. Next it goes to the homepage.

new() =
      <div class="container">
           <h1> <a href="http://www.semoru.com">semoru.com</a> CRUD example</h1>
           <table>
                 <tr>
                    <td><h2>Add a new customer</h2></td>
                 </tr>
                 <tr>
                    <td>
                        <div class="clearfix">
                             <label>Name</label>
                             <div class="input">
                                  <input id=#name />
                             </div>
                        </div>
                        <div class="clearfix">
                             <label>Email</label>
                             <div class="input">
                                  <input id=#email/>
                             </div>
                        </div>
                    </td>
                 </tr>
             </table>
           <div class="btn primary" onclick={_ -> create()}>  Create </div>
           <div class="btn default" onclick={_ -> Client.goto("/")}>  Cancel </div>
      </div>

Method new() build the page to let the user introduces the name and email of the new customer. Clicking on “Create” will call the method create() seen previously.

Update a customer

   update(id:int) =
        do /customers[id] <- {sid = id name=Dom.get_value(#name) email=Dom.get_value(#email)}
        Client.goto("/")

The method update(id) receives and id as argument and updates the information introduced in the form. Next it goes to the homepage.

   edit(id: string)=
      customer : Customer = /customers[String.to_int(id)]
      <div class="container">
           <h1> <a href="http://www.semoru.com">semoru.com</a> CRUD example</h1>
           <table>
                 <tr>
                    <td><h2>Edit customer</h2></td>
                 </tr>
                 <tr>
                    <td>
                        <div class="clearfix">
                             <label>Name</label>
                             <div class="input">
                                  <input id=#name value={customer.name} />
                             </div>
                        </div>
                        <div class="clearfix">
                             <label>Email</label>
                             <div class="input">
                                  <input id=#email value={customer.email} />
                             </div>
                        </div>
                    </td>
                 </tr>
             </table>
           <div class="btn primary" onclick={_ -> update(String.to_int(id))}>  Update </div>
           <div class="btn default" onclick={_ -> Client.goto("/")}>  Cancel </div>
      </div>

The method edit(id) builds the page where the user will edit the information for a previously selected customer. If the user clicks on update, it will execute the method update(id).

DELETE a customer

   delete(id:string)=
      items =  /customers
      do /customers <- IntMap.remove(String.to_int(id), items)
      Client.goto("/")

The method delete(id) will remove a selected customer from the database. Next it goes to the homepage.

   confirmation(id:string)=
      customer : Customer = /customers[String.to_int(id)]
      <div class="container">
           <h1> <a href="http://www.semoru.com">semoru.com</a> CRUD example</h1>
           <div class="alert-message block-message error"> <p> Do you want to delete the following information? </p></div>
           <table>
              <tr>
                  <td>
                        <div class="clearfix">
                             <label>Name:</label>
                             <div class="input">
                                  <input value={customer.name} disabled="true"/>
                             </div>
                        </div>
                        <div class="clearfix">
                             <label>Email:</label>
                             <div class="input">
                                  <input value={customer.email} disabled="true"/>
                             </div>
                        </div>
                  </td>
              </tr>
           </table>
           <div class="btn primary" onclick={_ -> delete(id)}>  Delete </div>
           <div class="btn default" onclick={_ -> Client.goto("/")}>  Cancel </div>
      </div>

The method confirmation(id) builds the page to request the confirmation of deleting a previously selected customer. If yes, it will execute the method delete(id).

Conclusion

We have created a simple application which interacts with the database using a web user interface. However there are a lot of possibilites to continue developing this application. Interest points for future tutorials are:

  • Data validation
  • Javascript integration
  • Database performance optimization

The source code is available at: http://github.com/semoru/opa_crud

Don’t hesitate to leave a comment if you want to share your opinion about this tutorial.

Thanks for visiting semoru.com

 

Share on TwitterSubmit to reddit

3 thoughts on “Opa tutorial: CRUD application. Create, Read, Update and Delete from database

  1. Thanks for the tutorial. Two remarks: the link to GitHub doesn’t work (it should be an absolute not relative link), you may also want to consider using bootstrap.opalang.org to simplify the HTML Bootstrap markup.

  2. Thanks for your comment Adam. The link to GitHub has been fixed, and I will take into consideration using Opa Bootstrapped Widgets in a future edition.

    • My main caintronst is creating web apps for public internet users. I agree IE sucks balls, but it is still the #1 browser on the internet. This has been a caintronst for every application I have ever designed internal and external. Your approach is definitely better if you have that luxury. You are very lucky if you do. I wasn’t trying to knock your approach, but I wanted to make this clear for the 99% of web app developers that have to adhere to IE standards. About 10% of my HTML/CSS development time is spent hacking IE bullshit.. and no doubt I fucking hate that. Post edited to make this clear.

Leave a Reply

Your email address will not be published. Required fields are marked *

*


nine × 3 =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>