Skip to content

Commit

Permalink
Handle correctly MongoDb ObjectId type
Browse files Browse the repository at this point in the history
Signed-off-by: Uberto Barbini <[email protected]>
  • Loading branch information
uberto committed Aug 30, 2023
1 parent b1821aa commit 02d150e
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 81 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.ubertob.kondor.mongo.json

import com.ubertob.kondor.json.JAny
import com.ubertob.kondor.json.JField
import com.ubertob.kondor.json.jsonnode.JsonNodeObject
import com.ubertob.kondor.json.str
import org.bson.types.ObjectId

object JObjectId : JAny<ObjectId>() {

val `$oid` by str(ObjectId::toHexString)
override fun JsonNodeObject.deserializeOrThrow() =
ObjectId(+`$oid`)

}


@JvmName("bindObjectId")
fun <PT : Any> str(binder: PT.() -> ObjectId) = JField(binder, JObjectId)
Original file line number Diff line number Diff line change
Expand Up @@ -48,32 +48,13 @@ object KondorBson {
// }

fun convertJsonNodeToBson(jn: JsonNodeObject): BsonDocument {

val writer = BsonDocumentWriter(BsonDocument())

encodeValue(writer, jn)

return writer.document
}

fun encodeObjectId(writer: BsonDocumentWriter, value: JsonNode) {
when (value) {
is JsonNodeArray -> error("Wrong Field type for ObjectId $value")
is JsonNodeBoolean -> writer.writeBoolean(value.boolean)
is JsonNodeNull -> writer.writeObjectId(ObjectId())
is JsonNodeNumber -> writer.writeDouble(value.num.toDouble())
is JsonNodeObject -> writeAsObjectIdIfPossible(value, writer)
is JsonNodeString -> writer.writeString(value.text)
}
}

private fun writeAsObjectIdIfPossible(value: JsonNodeObject, writer: BsonDocumentWriter) {
if (value._fieldMap.keys.contains("objectId"))
writer.writeObjectId(ObjectId(value._fieldMap["objectId"].asStringValue()))
else
error("Wrong Field type for ObjectId $value")
}

fun encodeValue(writer: BsonDocumentWriter, value: JsonNode) {
when (value) {
is JsonNodeNull -> writer.writeNull()
Expand All @@ -88,24 +69,25 @@ object KondorBson {
is JsonNodeBoolean -> writer.writeBoolean(value.boolean)
is JsonNodeNumber -> writer.writeDouble(value.num.toDouble())
is JsonNodeObject -> {
writer.writeStartDocument()

value._fieldMap.forEach { (fieldName, node) ->
writer.writeName(fieldName)
when (fieldName) {
"_id" -> encodeObjectId(writer, node)
else -> encodeValue(writer, node)

}
}

writer.writeEndDocument()
if (value._fieldMap.keys.contains("\$oid"))
writer.writeObjectId(ObjectId(value._fieldMap["\$oid"].asStringValue()))
else
encodeNormalObject(writer, value)
}

is JsonNodeString -> writer.writeString(value.text)
}
}

private fun encodeNormalObject(writer: BsonDocumentWriter, value: JsonNodeObject) {
writer.writeStartDocument()
value._fieldMap.forEach { (fieldName, node) ->
writer.writeName(fieldName)
encodeValue(writer, node)
}
writer.writeEndDocument()
}

}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import com.ubertob.kondor.mongo.core.*
import com.ubertob.kondortools.expectFailure
import com.ubertob.kondortools.expectSuccess
import org.bson.types.ObjectId
import org.junit.jupiter.api.Test
import org.testcontainers.junit.jupiter.Testcontainers
import strikt.api.expectThat
import strikt.assertions.contains
import strikt.assertions.isEqualTo

@Testcontainers
class MongoObjectIdTest {


private val localMongo = MongoExecutorDbClient.fromConnectionString(
connection = MongoTableTest.mongoConnection,
databaseName = "mongoCollTest"
)

object keyValueStoreTable : TypedTable<KeyValueStore>(JKeyValueStore) {
override val collectionName: String = "simpleDocs"
}

val id1 = ObjectId()
val id2 = ObjectId()
val id3 = ObjectId()

private val storeThreeKV = mongoOperation {
keyValueStoreTable.insertOne(KeyValueStore(id1, "first", 0.0))
keyValueStoreTable.insertOne(KeyValueStore(id2, "second", 1.0))
keyValueStoreTable.insertOne(KeyValueStore(id3, "third", 2.0))
}.ignoreValue()

fun queryByKey(id: ObjectId) = mongoOperation {
keyValueStoreTable.findById(id)
}

@Test
fun `query by mongo id`() {

val res = localMongo(storeThreeKV + queryByKey(id2))

expectThat(res.expectSuccess()?.description).isEqualTo("second")
}

@Test
fun `mongo id must be unique`() {
val uniqueId = ObjectId()

val firstTime = mongoOperation {
keyValueStoreTable.insertOne(KeyValueStore(uniqueId, "first", 0.0))
}
val objId = localMongo(firstTime).expectSuccess()

val updateAgain = mongoOperation {
keyValueStoreTable.insertOne(KeyValueStore(uniqueId, "second", 1.0))
keyValueStoreTable.insertOne(KeyValueStore(uniqueId, "third", 2.0))
}

val fail = localMongo(updateAgain).expectFailure()
expectThat(fail.msg).contains("duplicate key error")

val res = localMongo(queryByKey(uniqueId))

expectThat(res.expectSuccess()?.description).isEqualTo("first")
}

@Test
fun `store objectId`() {
val uniqueId = ObjectId()

val storeOne = mongoOperation {
keyValueStoreTable.insertOne(KeyValueStore(uniqueId, "first", 0.0))
}
val objId = localMongo(storeOne).expectSuccess()

expectThat(objId?.asObjectId()?.value).isEqualTo(uniqueId)

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.ubertob.kondor.mongo.core

import com.mongodb.client.MongoCollection
import com.mongodb.client.model.*
import com.ubertob.kondortools.expectFailure
import com.ubertob.kondortools.expectSuccess
import org.bson.BsonDocument
import org.junit.jupiter.api.BeforeEach
Expand Down Expand Up @@ -36,9 +35,6 @@ class MongoTableTest {
}
}

object keyValueStoreTable : TypedTable<KeyValueStore>(JKeyValueStore) {
override val collectionName: String = "simpleDocs"
}

object testConnectionTable : TypedTable<SmallClass>(JSmallClass) {
val counter = AtomicInteger(0)
Expand Down Expand Up @@ -262,51 +258,6 @@ class MongoTableTest {
expectThat(res.expectSuccess()).isEqualTo("a=SmallClass(string=SmallClass12, int=12, double=12.0, boolean=true), b=SmallClass(string=SmallClass3, int=3, double=3.0, boolean=false), c=SmallClass(string=SmallClass9, int=9, double=9.0, boolean=false), d=SmallClass(string=SmallClass6, int=6, double=6.0, boolean=true)")
}

private val storeThreeKV = mongoOperation {
keyValueStoreTable.insertOne(KeyValueStore("0000", "first", 0.0))
keyValueStoreTable.insertOne(KeyValueStore("0001", "second", 1.0))
keyValueStoreTable.insertOne(KeyValueStore("0002", "third", 2.0))
}.ignoreValue()

fun queryByKey(id: String) = mongoOperation {
keyValueStoreTable.findById(id)
}

@Test
fun `use mongo id`() {

val res = localMongo(storeThreeKV + queryByKey("0001"))

expectThat(res.expectSuccess()?.description).isEqualTo("second")
}

@Test
fun `mongo id must be unique`() {

val firstTime = mongoOperation {
keyValueStoreTable.insertOne(KeyValueStore("0042", "first", 0.0))
}
val objId = localMongo(firstTime).expectSuccess()

expectThat(objId?.asString()?.value).isEqualTo("0042")

val updateAgain = mongoOperation {
keyValueStoreTable.insertOne(KeyValueStore("0042", "second", 1.0))
keyValueStoreTable.insertOne(KeyValueStore("0042", "third", 2.0))
}

val fail = localMongo(updateAgain).expectFailure()
expectThat(fail.msg).contains("duplicate key error")

val res = localMongo(queryByKey("0042"))

expectThat(res.expectSuccess()?.description).isEqualTo("first")
}

@Test
fun `mongo id using the pk index`() {

}

}

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package com.ubertob.kondor.mongo.core
import com.ubertob.kondor.json.*
import com.ubertob.kondor.json.datetime.str
import com.ubertob.kondor.json.jsonnode.JsonNodeObject
import com.ubertob.kondor.mongo.json.str
import org.bson.types.ObjectId
import java.time.Instant


Expand Down Expand Up @@ -71,9 +73,10 @@ fun buildSealedClass(index: Int): SealedClass =
else -> ClassWithArray(name = "ClassWithArray$index", (0..(index % 10)).map { it.toString() })
}

data class KeyValueStore(val id: String, val description: String, val value: Double)
data class KeyValueStore(val id: ObjectId, val description: String, val value: Double)

object JKeyValueStore : JAny<KeyValueStore>() {

val _id by str(KeyValueStore::id)
val description by str(KeyValueStore::description)
val value by num(KeyValueStore::value)
Expand Down

0 comments on commit 02d150e

Please sign in to comment.