Implement most of monger.convertion.ConvertFromDBObject

This commit is contained in:
Michael S. Klishin 2011-08-13 21:18:21 +04:00
parent b38b357f50
commit 3a431bf1e0
2 changed files with 108 additions and 6 deletions

View file

@ -1,5 +1,5 @@
(ns monger.convertion
(:import (com.mongodb DBObject BasicDBObject)
(:import (com.mongodb DBObject BasicDBObject BasicDBList)
(clojure.lang IPersistentMap Keyword)
(java.util List Map)))
@ -27,10 +27,46 @@
List
(to-db-object [#^List input] (map to-db-object input)))
(declare associate-pairs)
(defprotocol ConvertFromDBObject
(from-db-object [input] "Converts given DBObject instance to a piece of Clojure data"))
(from-db-object [input keywordize] "Converts given DBObject instance to a piece of Clojure data"))
(extend-protocol ConvertFromDBObject
nil
(from-db-object [input keywordize] input)
Object
(from-db-object [input keywordize] input)
Map
(from-db-object [#^Map input keywordize]
(associate-pairs (.entrySet input) keywordize))
List
(from-db-object [#^List input keywordize]
(vec (map #(from-db-object % keywordize) input)))
DBObject
(from-db-object [#^DBObject input keywordize]
;; DBObject provides .toMap, but the implementation in
;; subclass GridFSFile unhelpfully throws
;; UnsupportedOperationException
(associate-pairs (for [key-set (.keySet input)] [key-set (.get input key-set)])
keywordize)))
(defn- associate-pairs [pairs keywordize]
;; Taking the keywordize test out of the fn reduces derefs
;; dramatically, which was the main barrier to matching pure-Java
;; performance for this marshalling
(reduce (if keywordize
(fn [m [#^String k v]]
(assoc m (keyword k) (from-db-object v true)))
(fn [m [#^String k v]]
(assoc m k (from-db-object v false))))
{} (reverse pairs)))

View file

@ -1,7 +1,13 @@
(ns monger.test.convertion
(:require [monger core collection convertion])
(:import (com.mongodb DBObject BasicDBObject BasicDBList) (java.util List ArrayList))
(:use [clojure.test]))
;;
;; DBObject to Clojure
;;
(deftest convert-nil-to-dbobject
(let [input nil
output (monger.convertion/to-db-object input)]
@ -32,6 +38,66 @@
(deftest convert-nested-map-to-dbobject
(let [input { :int 1, :string "Mongo", :float 22.23, :map { :int 10, :string "Clojure", :float 11.9, :list '(1 "a" :b) } }
output (monger.convertion/to-db-object input)]
(is (= 10 (.get (.get output "map") "int")))))
(let [input { :int 1, :string "Mongo", :float 22.23, :map { :int 10, :string "Clojure", :float 11.9, :list '(1 "a" :b), :map { :key "value" } } }
output (monger.convertion/to-db-object input)
inner (.get output "map")]
(is (= 10 (.get inner "int")))
(is (= "Clojure" (.get inner "string")))
(is (= 11.9 (.get inner "float")))
(is (= '(1 "a" "b") (.get inner "list")))
(is (= { "key" "value" } (.get inner "map")))))
;;
;; Clojure to DBObject
;;
(deftest convert-nil-from-db-object
(is (nil? (monger.convertion/from-db-object nil false)))
(is (nil? (monger.convertion/from-db-object nil true))))
(deftest convert-integer-from-dbobject
(is (= 2 (monger.convertion/from-db-object 2 false)))
(is (= 2 (monger.convertion/from-db-object 2 true))))
(deftest convert-float-from-dbobject
(is (= 3.3 (monger.convertion/from-db-object 3.3 false)))
(is (= 3.3 (monger.convertion/from-db-object 3.3 true))))
(deftest convert-flat-db-object-to-map-without-keywordizing
(let [name "Michael"
age 26
input (doto (BasicDBObject.)
(.put "name" name)
(.put "age" age))
output (monger.convertion/from-db-object input false)]
(is (= (output { "name" name, "age" age })))
(is (= (output "name") name))
(is (nil? (output :name)))
(is (= (output "age") age))
(is (nil? (output "points")))
))
(deftest convert-flat-db-object-to-map-without-keywordizing
(let [name "Michael"
age 26
input (doto (BasicDBObject.)
(.put "name" name)
(.put "age" age))
output (monger.convertion/from-db-object input true)]
(is (= (output { :name name, :age age })))
(is (= (output :name) name))
(is (nil? (output "name")))
(is (= (output :age) age))
(is (nil? (output "points")))))
(deftest convert-flat-db-object-to-nested-map
(let [did "b38b357f5014a3250d813a16376ca2ff4837e8e1"
nested (doto (BasicDBObject.) (.put "int" 101) (.put "dblist" (doto (BasicDBList.) (.put "0" 0) (.put "1" 1))) (.put "list" (ArrayList. ["red" "green" "blue"])) (.put "nil" nil))
input (doto (BasicDBObject.)
(.put "_id" did)
(.put "nested" nested))]
(is (= (monger.convertion/from-db-object input false) { "_id" did, "nested" { "int" 101, "dblist" {"0" 0, "1" 1}, "list" ["red" "green" "blue"], "nil" nil } }))
(is (= (monger.convertion/from-db-object input true) { :_id did, :nested { :int 101, :dblist {:0 0, :1 1}, :list ["red" "green" "blue"], :nil nil } }))
))