/
BsonRecord.scala
130 lines (112 loc) · 4.13 KB
/
BsonRecord.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
* Copyright 2011 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.liftweb
package mongodb
package record
import common._
import scala.collection.JavaConversions._
import net.liftweb.record.{Field, MetaRecord, Record}
import net.liftweb.record.field._
import com.mongodb._
/** Specialized Record that can be encoded and decoded from BSON (DBObject) */
trait BsonRecord[MyType <: BsonRecord[MyType]] extends Record[MyType] {
self: MyType =>
/** Refines meta to require a BsonMetaRecord */
def meta: BsonMetaRecord[MyType]
/**
* Encode a record instance into a DBObject
*/
def asDBObject: DBObject = meta.asDBObject(this)
/**
* Set the fields of this record from the given DBObject
*/
def setFieldsFromDBObject(dbo: DBObject): Unit = meta.setFieldsFromDBObject(this, dbo)
override def toString = {
val fieldList = this.fields.map(f => "%s=%s" format (f.name,
f.valueBox match {
case Full(c: java.util.Calendar) => c.getTime().toString()
case Full(null) => ""
case Full(v) => v.toString
case _ => ""
}))
"%s={%s}" format (this.getClass.toString, fieldList.mkString(", "))
}
}
/** Specialized MetaRecord that deals with BsonRecords */
trait BsonMetaRecord[BaseRecord <: BsonRecord[BaseRecord]] extends MetaRecord[BaseRecord] with JsonFormats {
self: BaseRecord =>
/**
* Create a BasicDBObject from the field names and values.
* - MongoFieldFlavor types (List) are converted to DBObjects
* using asDBObject
*/
def asDBObject(inst: BaseRecord): DBObject = {
import Meta.Reflection._
import field.MongoFieldFlavor
val dbo = BasicDBObjectBuilder.start // use this so regex patterns can be stored.
for (f <- fields(inst)) {
f match {
case field if (field.optional_? && field.valueBox.isEmpty) => // don't add to DBObject
case field: EnumTypedField[Enumeration] =>
field.asInstanceOf[EnumTypedField[Enumeration]].valueBox foreach {
v => dbo.add(f.name, v.id)
}
case field: EnumNameTypedField[Enumeration] =>
field.asInstanceOf[EnumNameTypedField[Enumeration]].valueBox foreach {
v => dbo.add(f.name, v.toString)
}
case field: MongoFieldFlavor[Any] =>
dbo.add(f.name, field.asInstanceOf[MongoFieldFlavor[Any]].asDBObject)
case field => field.valueBox foreach (_.asInstanceOf[AnyRef] match {
case null => dbo.add(f.name, null)
case x if primitive_?(x.getClass) => dbo.add(f.name, x)
case x if mongotype_?(x.getClass) => dbo.add(f.name, x)
case x if datetype_?(x.getClass) => dbo.add(f.name, datetype2dbovalue(x))
case x: BsonRecord[_] => dbo.add(f.name, x.asDBObject)
case o => dbo.add(f.name, o.toString)
})
}
}
dbo.get
}
/**
* Creates a new record, then sets the fields with the given DBObject.
*
* @param dbo - the DBObject
* @return Box[BaseRecord]
*/
def fromDBObject(dbo: DBObject): BaseRecord = {
val inst: BaseRecord = createRecord
setFieldsFromDBObject(inst, dbo)
inst
}
/**
* Populate the inst's fields with the values from a DBObject. Values are set
* using setFromAny passing it the DBObject returned from Mongo.
*
* @param inst - the record that will be populated
* @param obj - The DBObject
* @return Box[BaseRecord]
*/
def setFieldsFromDBObject(inst: BaseRecord, dbo: DBObject): Unit = {
for (k <- dbo.keySet; field <- inst.fieldByName(k.toString)) {
field.setFromAny(dbo.get(k.toString))
}
inst.runSafe {
inst.fields.foreach(_.resetDirty)
}
}
}