Sunday, December 8, 2013

Part V: Oh, we stored something to the App Engine? But where is it!

Good evening! First of all I have to apologize for my poor english writing.

Todays lesson will be about querying the App Engine Datastore to fetch all entities. Luckily we don't need new imports :) We have all what we need.

However we implement a new function called getAllEntries which gets the request and returns a "pointer" to an Food array. Adding a new template for our query output is also included.

We call this function in the save function.




package mycanteen
   
import(
 "net/http"
 "html/template"
 "strconv"
 "fmt"
 "appengine"
 "appengine/datastore"
)

type Food struct{
 Course string
 Name string 
 Date string
 Price float64
}
   
// No main function. Go App Engine use the init-func
func init() {
    http.HandleFunc("/", root)
    http.HandleFunc("/admin", admin);
    http.HandleFunc("/save", save)
}
   
func root(w http.ResponseWriter, r *http.Request) {    
    // Here we will add the Userpanel, but not know 
}
 
/*********************ADMINPANEL HANDLER**************************/
func admin(w http.ResponseWriter, r *http.Request) {      
    // Execute the parsing. We pass the ResponseWriter and a second value, which should be fill the gaps at the template. 
    // We have no gaps, so we have nothing to fill in. 
    if err := adminPanelTemplate.Execute(w, ""); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }
}
/********************SAVE/PERSIST HANDLER************************/
func save(w http.ResponseWriter, r *http.Request) {    


    // You have to parse the form from our admin panel. It's mandatory!
    if err := r.ParseForm(); err != nil {
     fmt.Fprint(w,err) 
    }
     
    // Now we a readey to get the fish ;-)
    course := r.FormValue("course")
    name := r.FormValue("name")
    date := r.FormValue("date")
    // The form is string based, for later purpose we parse it to float
    price, _ := strconv.ParseFloat(r.FormValue("price"), 64)
    
    f := Food{course,name,date,price,}
    // Persist to Datastore
    // At this moment we cant save the values, hence we setup only this output to check the values.
    if  saveToDatastore(f,r) != true{
     http.Error(w, "Error until persist the meal", http.StatusInternalServerError)
    }

 allMeals := getAllEntries(r)
 if err := saveTemplate.Execute(w,allMeals);err != nil{
  http.Error(w, err.Error(), http.StatusInternalServerError)
 }

}

func saveToDatastore(f Food, r *http.Request) bool{
 // Get context from 
    c := appengine.NewContext(r);

    key := datastore.NewIncompleteKey(c, "Meal", mealStoreKey(c))
    _, err := datastore.Put(c, key, &f)
    if err != nil{
 return false
    }else{
 return true
    }
}

/******************Fetch all Entries from the datastore********************/
func getAllEntries(r *http.Request) []*Food{
 var q *datastore.Query
 var allMeals []*Food

 c := appengine.NewContext(r);
 // Query for all entries in the datastore with the meal store key
 q = datastore.NewQuery("Meal").Ancestor(mealStoreKey(c))
 if _, err := q.GetAll(c, &allMeals); err != nil {  
        return allMeals
    }

    return allMeals
}

// foodKey returns the key used for all food entries.
func mealStoreKey(c appengine.Context) *datastore.Key {
    // The string "default_food" here could be varied to have multiple cantines.
    return datastore.NewKey(c, "MealStore", "meal", 0, nil)
}
 
// Parse the HTMLTemplate, despite it is not neccesary yet.
var adminPanelTemplate = template.Must(template.New("adminPanelHTML").Parse(adminPanelHTML))
var saveTemplate = template.Must(template.New("saveHTML").Parse(saveHTML))
   
// Here you define the HTML which will be parsed.
const adminPanelHTML= `
<html>
<head>
</head>
<body>
Name: Price: Date:
</body> </html> ` const saveHTML=` <html> <head> </head> <body> <table border=1> <tr><th>Course</th><th>Name</th><th>Price</th><th>Date</th></tr> {{range .}} <tr><td>{{.Course}}</td><td>{{.Name}}</td><td>{{.Price}}</td><td>{{.Date}}</td><td><input type="checkbox" /></td></tr> {{end}} </table> <a href="/admin">Back</a> </body> </html> `

For the QueryBuilder look at this page, they describe it very well :)  projectionqueries
The c.getAll function needs a query and a array (slice) to fetch all entities.


The checkbox is for later purpose, so we can delete entries later. :) Maybe in the next post.

See ya!

P.S. Checkout my repository on Bitbucket for the latest code!  https://bitbucket.org/loose11/mycanteen

No comments:

Post a Comment