Permalink
Browse files

Issue 931 - Add better support for primary key field in mongodb

  • Loading branch information...
1 parent cad135a commit bbea5a8446c47c983e7ab95860844526defd4aa8 Tim Nelson committed Mar 10, 2011
@@ -28,7 +28,7 @@ import net.liftweb.json.{Formats, JsonParser}
import net.liftweb.json.JsonAST._
import net.liftweb.mongodb._
import net.liftweb.mongodb.record.field._
-import net.liftweb.record.{MetaRecord, Record}
+import net.liftweb.record.{MandatoryTypedField, MetaRecord, Record}
import net.liftweb.record.FieldHelpers.expectedA
import net.liftweb.record.field._
@@ -41,12 +41,24 @@ trait MongoMetaRecord[BaseRecord <: MongoRecord[BaseRecord]]
self: BaseRecord =>
+ /*
+ * Utility method for determining the value of _id.
+ * This is needed for backwards compatibility with MongoId. This is
+ * due to the fact that MongoRecord.id is of type Any. That will
+ * be changed to type MandatoryTypedField in a future version. When
+ * that happens this will no longer be necessary.
+ */
+ private def idValue(inst: BaseRecord): Any = inst.id match {
+ case f: MandatoryTypedField[_] => f.value
+ case x => x
+ }
+
/**
* Delete the instance from backing store
*/
def delete_!(inst: BaseRecord): Boolean = {
foreachCallback(inst, _.beforeDelete)
- delete("_id", inst.id)
+ delete("_id", idValue(inst))
foreachCallback(inst, _.afterDelete)
true
}
@@ -105,6 +117,11 @@ trait MongoMetaRecord[BaseRecord <: MongoRecord[BaseRecord]]
*/
def find(id: Int): Box[BaseRecord] = find(new BasicDBObject("_id", id))
+ /**
+ * Find a single row by a Long id
+ */
+ def find(id: Long): Box[BaseRecord] = find(new BasicDBObject("_id", id))
+
/**
* Find a single document by a qry using a json value
*/
@@ -294,7 +311,7 @@ trait MongoMetaRecord[BaseRecord <: MongoRecord[BaseRecord]]
*/
def update(obj: BaseRecord, update: DBObject): Unit = {
val query = (BasicDBObjectBuilder.start
- .add("_id", obj.id)
+ .add("_id", idValue(obj))
.get)
this.update(query, update)
}
@@ -29,7 +29,11 @@ trait MongoRecord[MyType <: MongoRecord[MyType]] extends BsonRecord[MyType] {
self: MyType =>
/*
- * every mongo record must have an _id field. Override this with the value of your _id object.
+ * Every MongoRecord must have an _id field. Use a MongoPkField to
+ * satisfy this.
+
+ * This may change to type MandatoryTypedField in the
+ * future (once MongoId is removed.)
*/
def id: Any
@@ -47,7 +51,7 @@ trait MongoRecord[MyType <: MongoRecord[MyType]] extends BsonRecord[MyType] {
}
this
}
-
+
/**
* Save the instance and return the instance
* @param safe - if true will use WriteConcern SAFE else NORMAL
@@ -58,7 +62,7 @@ trait MongoRecord[MyType <: MongoRecord[MyType]] extends BsonRecord[MyType] {
/**
* Save the instance and return the instance
- * WILL NOT RAISE MONGO SERVER ERRORS.
+ * WILL NOT RAISE MONGO SERVER ERRORS.
* Use save(Boolean) or save(WriteConcern) to control error behavior
*/
def save: MyType = save(false)
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2010 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
+package field
+
+import common.{Box, Empty, Full}
+import util.StringHelpers
+
+import scala.util.Random
+import java.util.UUID
+
+import org.bson.types.ObjectId
+import net.liftweb.record.field.{IntField, LongField, StringField}
+
+/*
+ * Trait for creating a "Primary Key" Field. These are all an id field
+ * that is saved as _id in the database. Mix one of these into your
+ * MongoRecord.
+ */
+trait MongoPk[PkType] {
+ def id: PkType
+ /** Override this to set default value of id field */
+ def defaultIdValue: Any
+}
+
+trait ObjectIdPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[ObjectIdField[OwnerType]]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = ObjectId.get
+
+ object id extends ObjectIdField(this.asInstanceOf[OwnerType]) {
+ override def name = "_id"
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
+
+trait UUIDPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[UUIDField[OwnerType]]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = UUID.randomUUID
+
+ object id extends UUIDField(this.asInstanceOf[OwnerType]) {
+ override def name = "_id"
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
+
+trait StringPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[StringField[OwnerType]]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = StringHelpers.randomString(32)
+
+ object id extends StringField(this.asInstanceOf[OwnerType], 12) {
+ override def name = "_id"
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
+
+trait IntPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[IntField[OwnerType]]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = Random.nextInt
+
+ object id extends IntField(this.asInstanceOf[OwnerType]) {
+ override def name = "_id"
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
+
+trait LongPk[OwnerType <: MongoRecord[OwnerType]]
+ extends MongoPk[LongField[OwnerType]]
+{
+ self: OwnerType =>
+
+ def defaultIdValue = Random.nextLong
+
+ object id extends LongField(this.asInstanceOf[OwnerType]) {
+ override def name = "_id"
+ override def defaultValue = defaultIdValue
+ override def shouldDisplay_? = false
+ }
+}
@@ -63,7 +63,7 @@ trait HarnessedLifecycleCallbacks extends LifecycleCallbacks {
override def afterDelete = afterDeleteHarness()
}
-class FieldTypeTestRecord private () extends MongoRecord[FieldTypeTestRecord] with MongoId[FieldTypeTestRecord] {
+class FieldTypeTestRecord private () extends MongoRecord[FieldTypeTestRecord] with ObjectIdPk[FieldTypeTestRecord] {
def meta = FieldTypeTestRecord
object mandatoryBinaryField extends BinaryField(this)
@@ -132,6 +132,7 @@ class FieldTypeTestRecord private () extends MongoRecord[FieldTypeTestRecord] wi
override def equals(other: Any): Boolean = other match {
case that:FieldTypeTestRecord =>
+ this.id.value == that.id.value &&
//this.mandatoryBinaryField.value == that.mandatoryBinaryField.value &&
this.mandatoryBooleanField.value == that.mandatoryBooleanField.value &&
this.mandatoryCountryField.value == that.mandatoryCountryField.value &&
@@ -170,7 +171,7 @@ class DBRefTestRecord private () extends MongoRecord[DBRefTestRecord] with Mongo
}
object DBRefTestRecord extends DBRefTestRecord with MongoMetaRecord[DBRefTestRecord]
-class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTestRecord] with MongoId[MongoFieldTypeTestRecord] {
+class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTestRecord] with ObjectIdPk[MongoFieldTypeTestRecord] {
def meta = MongoFieldTypeTestRecord
object mandatoryDateField extends DateField(this)
@@ -198,6 +199,7 @@ class MongoFieldTypeTestRecord private () extends MongoRecord[MongoFieldTypeTest
override def equals(other: Any): Boolean = other match {
case that:MongoFieldTypeTestRecord =>
+ this.id.value == that.id.value &&
this.mandatoryDateField.value == that.mandatoryDateField.value &&
//this.mandatoryDBRefField.value.getId == that.mandatoryDBRefField.value.getId &&
//this.mandatoryDBRefField.value.getRef == that.mandatoryDBRefField.value.getRef &&
@@ -214,14 +216,14 @@ object MongoFieldTypeTestRecord extends MongoFieldTypeTestRecord with MongoMetaR
override def formats = allFormats
}
-class PasswordTestRecord private () extends MongoRecord[PasswordTestRecord] with MongoId[PasswordTestRecord] {
+class PasswordTestRecord private () extends MongoRecord[PasswordTestRecord] with ObjectIdPk[PasswordTestRecord] {
def meta = PasswordTestRecord
object password extends MongoPasswordField(this, 3)
}
object PasswordTestRecord extends PasswordTestRecord with MongoMetaRecord[PasswordTestRecord]
-class ListTestRecord private () extends MongoRecord[ListTestRecord] with MongoId[ListTestRecord] {
+class ListTestRecord private () extends MongoRecord[ListTestRecord] with UUIDPk[ListTestRecord] {
def meta = ListTestRecord
object mandatoryStringListField extends MongoListField[ListTestRecord, String](this)
@@ -239,6 +241,7 @@ class ListTestRecord private () extends MongoRecord[ListTestRecord] with MongoId
override def equals(other: Any): Boolean = other match {
case that:ListTestRecord =>
+ this.id.value == that.id.value &&
this.mandatoryStringListField.value == that.mandatoryStringListField.value &&
this.mandatoryIntListField.value == that.mandatoryIntListField.value &&
this.mandatoryMongoJsonObjectListField.value == that.mandatoryMongoJsonObjectListField.value
@@ -249,7 +252,7 @@ object ListTestRecord extends ListTestRecord with MongoMetaRecord[ListTestRecord
override def formats = allFormats
}
-class MapTestRecord extends MongoRecord[MapTestRecord] with MongoId[MapTestRecord] {
+class MapTestRecord extends MongoRecord[MapTestRecord] with StringPk[MapTestRecord] {
def meta = MapTestRecord
object mandatoryStringMapField extends MongoMapField[MapTestRecord, String](this)
@@ -262,6 +265,7 @@ class MapTestRecord extends MongoRecord[MapTestRecord] with MongoId[MapTestRecor
override def equals(other: Any): Boolean = other match {
case that:MapTestRecord =>
+ this.id.value == that.id.value &&
this.mandatoryStringMapField.value == that.mandatoryStringMapField.value &&
this.mandatoryIntMapField.value == that.mandatoryIntMapField.value
case _ => false
@@ -331,7 +335,7 @@ object SubSubRecord extends SubSubRecord with BsonMetaRecord[SubSubRecord] {
override def formats = allFormats
}
-class SubRecordTestRecord extends MongoRecord[SubRecordTestRecord] with MongoId[SubRecordTestRecord] {
+class SubRecordTestRecord extends MongoRecord[SubRecordTestRecord] with ObjectIdPk[SubRecordTestRecord] {
def meta = SubRecordTestRecord
object mandatoryBsonRecordField extends BsonRecordField(this, SubRecord)
@@ -359,7 +363,7 @@ case class JsonObj(id: String, name: String) extends JsonObject[JsonObj] {
}
object JsonObj extends JsonObjectMeta[JsonObj]
-class NullTestRecord extends MongoRecord[NullTestRecord] with MongoId[NullTestRecord] {
+class NullTestRecord extends MongoRecord[NullTestRecord] with IntPk[NullTestRecord] {
def meta = NullTestRecord
@@ -381,7 +385,7 @@ extends JsonObject[BoxTestJsonObj] {
}
object BoxTestJsonObj extends JsonObjectMeta[BoxTestJsonObj]
-class BoxTestRecord extends MongoRecord[BoxTestRecord] with MongoId[BoxTestRecord] {
+class BoxTestRecord extends MongoRecord[BoxTestRecord] with LongPk[BoxTestRecord] {
def meta = BoxTestRecord
object jsonobj extends JsonObjectField[BoxTestRecord, BoxTestJsonObj](this, BoxTestJsonObj) {
Oops, something went wrong.

0 comments on commit bbea5a8

Please sign in to comment.