Wednesday, 13 May 2009
Data Persistence in GAE with Clojure
If you want to persist stuff in Java, you've got a bewildering amount of choice
There's even an entire book about making the right decision! (Persistence in the Enterprise)
Google App Engine has gone with JDO using the Data Nucleus platform. In GAE this is split again into two APIs, the high-level one for persisting objects, and a lower-level one which allows you to persist raw data.
When using Clojure it makes more sense to go with the lower-level api. The higher-level one would require using annotations on objects which isn't supported at the moment in Clojure (as far as I know!).
So how do we store data in GAE? The example below saves a story to disk (as a learning exercise, I'm writing a quick and dirty reddit clone).
Retrieving the data is much the same.
So now I know how to authenticate users, next step is to get some basic UI together. There's a number of choices here (JSP, server side HTML generation in Clojure or just go with Ajax). I'm leaning towards the Ajax!
There's even an entire book about making the right decision! (Persistence in the Enterprise)
Google App Engine has gone with JDO using the Data Nucleus platform. In GAE this is split again into two APIs, the high-level one for persisting objects, and a lower-level one which allows you to persist raw data.
When using Clojure it makes more sense to go with the lower-level api. The higher-level one would require using annotations on objects which isn't supported at the moment in Clojure (as far as I know!).
So how do we store data in GAE? The example below saves a story to disk (as a learning exercise, I'm writing a quick and dirty reddit clone).
(ns news.savestory
(:use (news appengine))
(:gen-class :extends javax.servlet.http.HttpServlet)
(:import (com.google.appengine.api.datastore DatastoreServiceFactory Entity Key Query)))
(defn store
[data type]
(let [entity (Entity. (.toString type))]
(doseq [[k v] data]
(.setProperty entity (.toString k) v))
(.put (DatastoreServiceFactory/getDatastoreService) entity)
(.getKey entity)))
(defn -doGet
[_ request response]
(let [body (.getParameter request "storyLink")
title (.getParameter request "storyTitle")]
(let [w (.getWriter response)]
(.println w (store {:body body :title title} :story)))))
store
takes a map and a type and persists it in the database and returns the key associated with this entity. Visiting the URL persists the data in the URL and returns the key.Retrieving the data is much the same.
(ns news.viewstory
(:use (news appengine))
(:gen-class :extends javax.servlet.http.HttpServlet)
(:import (com.google.appengine.api.datastore DatastoreServiceFactory Entity Key Query KeyFactory)))
(defn entity-to-map
[entity]
(into (hash-map) (.getProperties entity)))
(defn getEntity
[id type]
(let [k (KeyFactory/createKey (.toString type) (Long/valueOf id))]
(entity-to-map
(.get (DatastoreServiceFactory/getDatastoreService) k))))
(defn -doGet
[_ request response]
(let [id (.getParameter request "storyId")
story (getEntity id :story)
w (.getWriter response)]
(doseq [[k v] story]
(.println w (str k "=" v)))))
entity-to-map
just converts the properties of the entity into a friendly Clojure type. So now I know how to authenticate users, next step is to get some basic UI together. There's a number of choices here (JSP, server side HTML generation in Clojure or just go with Ajax). I'm leaning towards the Ajax!
Comments:
Links to this post:
<< Home
The theme is Ubuntu's Dust theme. It's available on most versions, but in 9.04 it comes as standard. It's available here and it looks awesome.
The IDE is Emacs and I'm using the Color Theme package and the scheme "arjen".
Post a Comment
The IDE is Emacs and I'm using the Color Theme package and the scheme "arjen".
Links to this post:
<< Home
Subscribe to Posts [Atom]