Skip to content

Commit

Permalink
feat: try to implement conversion from document to object with circe
Browse files Browse the repository at this point in the history
  • Loading branch information
QuadStingray committed Jan 25, 2025
1 parent 91ed0be commit 968c4b5
Show file tree
Hide file tree
Showing 14 changed files with 122 additions and 49 deletions.
5 changes: 4 additions & 1 deletion src/main/scala/dev/mongocamp/driver/mongodb/MongoDAO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ import better.files.File
import dev.mongocamp.driver.mongodb.bson.{ BsonConverter, DocumentHelper }
import dev.mongocamp.driver.mongodb.database.{ ChangeObserver, CollectionStatus, CompactResult, DatabaseProvider }
import dev.mongocamp.driver.mongodb.operation.Crud
import io.circe.Decoder
import org.bson.json.JsonParseException
import org.mongodb.scala.model.Accumulators._
import org.mongodb.scala.model.Aggregates._
import org.mongodb.scala.model.Filters._
import org.mongodb.scala.model.Projections
import org.mongodb.scala.{ BulkWriteResult, Document, MongoCollection, Observable, SingleObservable }
import dev.mongocamp.driver.mongodb.schema.JsonConverter._
import io.circe.generic.auto._

import java.nio.charset.Charset
import java.util.Date
Expand All @@ -18,7 +21,7 @@ import scala.reflect.ClassTag

/** Created by tom on 20.01.17.
*/
abstract class MongoDAO[A](provider: DatabaseProvider, collectionName: String)(implicit ct: ClassTag[A]) extends Crud[A] {
abstract class MongoDAO[A](provider: DatabaseProvider, collectionName: String)(implicit ct: ClassTag[A], decoder: Decoder[A]) extends Crud[A] {

val databaseName: String = provider.guessDatabaseName(collectionName)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import java.nio.charset.StandardCharsets
import javax.sql.rowset.serial.SerialBlob
import scala.util.Try
import org.mongodb.scala.documentToUntypedDocument
import dev.mongocamp.driver.mongodb.schema.JsonConverter._

class MongoDbResultSet(collectionDao: MongoDAO[Document], data: List[Document], queryTimeOut: Int) extends ResultSet with MongoJdbcCloseable {
private var currentRow: Document = _
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package dev.mongocamp.driver.mongodb.jdbc.resultSet

import dev.mongocamp.driver.mongodb.MongoDAO
import dev.mongocamp.driver.mongodb.{ MongoDAO, _ }
import dev.mongocamp.driver.mongodb.schema.JsonConverter._
import org.mongodb.scala.Document
import org.mongodb.scala.bson.{ BsonBoolean, BsonInt32, BsonInt64, BsonNumber, BsonString }
import dev.mongocamp.driver.mongodb._

import java.sql.{ ResultSetMetaData, SQLException }

Expand Down Expand Up @@ -81,7 +81,7 @@ class MongoDbResultSetMetaData extends ResultSetMetaData {
case _: BsonString => java.sql.Types.VARCHAR
case _: BsonBoolean => java.sql.Types.BOOLEAN
// case _: Document => java.sql.Types.STRUCT // todo: check if this is correct
case _ => java.sql.Types.NULL
case _ => java.sql.Types.NULL
}
}

Expand Down
33 changes: 26 additions & 7 deletions src/main/scala/dev/mongocamp/driver/mongodb/operation/Base.scala
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
package dev.mongocamp.driver.mongodb.operation

import com.typesafe.scalalogging.LazyLogging
import dev.mongocamp.driver.mongodb.bson.BsonConverter
import dev.mongocamp.driver.mongodb.database.MongoIndex
import dev.mongocamp.driver.mongodb.schema.{ CirceSchema, JsonConverter }
import org.mongodb.scala.bson.conversions.Bson
import org.mongodb.scala.model.Sorts._
import org.mongodb.scala.model.{ CountOptions, DropIndexOptions, IndexOptions, Indexes }
import org.mongodb.scala.{ Document, ListIndexesObservable, MongoCollection, Observable, SingleObservable }

import scala.collection.mutable
import scala.concurrent.duration.Duration
import scala.concurrent.duration.durationToPair

abstract class Base[A] extends LazyLogging {

implicit def documentToObject[A](document: Document): A = {
// docment to json
// json to object
null.asInstanceOf[A]
import scala.reflect.ClassTag
import io.circe.generic.auto._
import io.circe.syntax._
import better.files.Resource
import io.circe.{ Decoder, HCursor }
import io.circe.jawn.decode
import io.circe.syntax._
import io.circe.generic.auto._

abstract class Base[A](implicit classTag: ClassTag[A]) extends LazyLogging {
def jsonConverter = new JsonConverter()
def documentToObject[A](document: Document)(implicit decoder: Decoder[A]): A = {
if (classTag.runtimeClass == classOf[Document]) {
document.asInstanceOf[A]
}
else {
val helperMap = mutable.Map[String, Any]()
document.keys.foreach(k => helperMap.put(k, BsonConverter.fromBson(document(k))))
val jsonString = jsonConverter.toJson(helperMap)
val response = jsonConverter.toObject(jsonString)
// val decoder = converter.decodeString[A](jsonString)
response
}
}

protected def coll: MongoCollection[Document]
Expand Down
60 changes: 35 additions & 25 deletions src/main/scala/dev/mongocamp/driver/mongodb/operation/Crud.scala
Original file line number Diff line number Diff line change
@@ -1,55 +1,57 @@
package dev.mongocamp.driver.mongodb.operation

import java.util.Date
import dev.mongocamp.driver.mongodb.database.DatabaseProvider
import dev.mongocamp.driver.mongodb.sync.MongoSyncOperation
import dev.mongocamp.driver.mongodb.{ Converter, _ }
import org.mongodb.scala.bson.conversions.Bson
import org.mongodb.scala.model.Filters._
import org.mongodb.scala.model.{ BulkWriteOptions, _ }
import org.mongodb.scala.model.Updates._
import org.mongodb.scala.model._
import org.mongodb.scala.result.{ DeleteResult, InsertManyResult, InsertOneResult, UpdateResult }
import org.mongodb.scala.{ BulkWriteResult, Observable, SingleObservable }
import org.mongodb.scala.{ BulkWriteResult, Document, Observable, SingleObservable }

import java.util.Date
import scala.collection.mutable.ArrayBuffer
import scala.reflect.ClassTag
import Updates._
import dev.mongocamp.driver.mongodb.bson.BsonConverter
import dev.mongocamp.driver.mongodb.sync.MongoSyncOperation

abstract class Crud[A]()(implicit ct: ClassTag[A]) extends Search[A] {

// create
def insertOne(value: A): Observable[InsertOneResult] = coll.insertOne(Converter.toDocument(value))
def insertOne(value: A): Observable[InsertOneResult] = {
coll.insertOne(Converter.toDocument(value))
}

def insertOne(value: A, options: InsertOneOptions): Observable[InsertOneResult] =
def insertOne(value: A, options: InsertOneOptions): Observable[InsertOneResult] = {
coll.insertOne(Converter.toDocument(value), options)
}

def insertMany(values: Seq[A]): Observable[InsertManyResult] =
def insertMany(values: Seq[A]): Observable[InsertManyResult] = {
coll.insertMany(values.map(Converter.toDocument))
}

def insertMany(values: Seq[A], options: InsertManyOptions): Observable[InsertManyResult] =
def insertMany(values: Seq[A], options: InsertManyOptions): Observable[InsertManyResult] = {
coll.insertMany(values.map(Converter.toDocument), options)
}

// bulk write

def bulkWrite(requests: List[WriteModel[_ <: A]], options: BulkWriteOptions): SingleObservable[BulkWriteResult] = {
// coll.bulkWrite(requests, options)
// todo
???
def bulkWrite(requests: List[WriteModel[Document]], options: BulkWriteOptions): SingleObservable[BulkWriteResult] = {
coll.bulkWrite(requests.map(wM => wM), options)
}

def bulkWrite(requests: List[WriteModel[_ <: A]], ordered: Boolean = true): SingleObservable[BulkWriteResult] = {
def bulkWrite(requests: List[WriteModel[Document]], ordered: Boolean = true): SingleObservable[BulkWriteResult] = {
bulkWrite(requests, BulkWriteOptions().ordered(ordered))
}

def bulkWriteMany(values: Seq[A], options: BulkWriteOptions): SingleObservable[BulkWriteResult] = {
val requests: ArrayBuffer[WriteModel[_ <: A]] = ArrayBuffer()
values.foreach(value => requests.append(InsertOneModel(value)))
val requests: ArrayBuffer[WriteModel[Document]] = ArrayBuffer()
values.foreach(value => requests.append(InsertOneModel(Converter.toDocument(value))))
bulkWrite(requests.toList, options)
}

def bulkWriteMany(values: Seq[A], ordered: Boolean = true): SingleObservable[BulkWriteResult] = {
val requests: ArrayBuffer[WriteModel[_ <: A]] = ArrayBuffer()
values.foreach(value => requests.append(InsertOneModel(value)))
val requests: ArrayBuffer[WriteModel[Document]] = ArrayBuffer()
values.foreach(value => requests.append(InsertOneModel(Converter.toDocument(value))))
bulkWrite(requests.toList, ordered)
}

Expand Down Expand Up @@ -97,25 +99,33 @@ abstract class Crud[A]()(implicit ct: ClassTag[A]) extends Search[A] {

// delete

def deleteOne(filter: Bson): Observable[DeleteResult] = coll.deleteOne(filter)
def deleteOne(filter: Bson): Observable[DeleteResult] = {
coll.deleteOne(filter)
}

def deleteOne(filter: Bson, options: DeleteOptions): Observable[DeleteResult] =
def deleteOne(filter: Bson, options: DeleteOptions): Observable[DeleteResult] = {
coll.deleteOne(filter, options)
}

def deleteOne(value: A): Observable[DeleteResult] = {
val oid = Converter.toDocument(value).get(DatabaseProvider.ObjectIdKey).get
coll.deleteOne(equal(DatabaseProvider.ObjectIdKey, oid))
}

def deleteMany(filter: Bson): Observable[DeleteResult] =
def deleteMany(filter: Bson): Observable[DeleteResult] = {
coll.deleteMany(filter)
}

def deleteMany(filter: Bson, options: DeleteOptions): Observable[DeleteResult] =
def deleteMany(filter: Bson, options: DeleteOptions): Observable[DeleteResult] = {
coll.deleteMany(filter, options)
}

def deleteAll(): Observable[DeleteResult] = deleteMany(Map())
def deleteAll(): Observable[DeleteResult] = {
deleteMany(Map())
}

def deleteAll(options: DeleteOptions): Observable[DeleteResult] =
def deleteAll(options: DeleteOptions): Observable[DeleteResult] = {
deleteMany(Map(), options)
}

}
25 changes: 18 additions & 7 deletions src/main/scala/dev/mongocamp/driver/mongodb/operation/Search.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import dev.mongocamp.driver.mongodb._
import dev.mongocamp.driver.mongodb.bson.BsonConverter
import dev.mongocamp.driver.mongodb.bson.BsonConverter._
import dev.mongocamp.driver.mongodb.database.DatabaseProvider
import io.circe.Decoder.Result
import io.circe.{ Decoder, HCursor }
import org.bson.BsonValue
import org.mongodb.scala.bson.ObjectId
import org.mongodb.scala.bson.conversions.Bson
Expand All @@ -21,20 +23,23 @@ abstract class Search[A]()(implicit ct: ClassTag[A]) extends Base[A] {
sort: Bson = Document(),
projection: Bson = Document(),
limit: Int = 0
): Observable[A] = {
{
)(implicit decoder: Decoder[A]): Observable[A] = {
val findObservable = {
if (limit > 0) {
coll.find(filter).sort(sort).projection(projection).limit(limit)
}
else {
coll.find(filter).sort(sort).projection(projection)
}
}.map(doc => documentToObject[A](doc))
}
findObservable.map(doc => documentToObject[A](doc))
}

def findById(oid: ObjectId): Observable[A] = find(equal(DatabaseProvider.ObjectIdKey, oid))
def findById(oid: ObjectId)(implicit decoder: Decoder[A]): Observable[A] = {
find(equal(DatabaseProvider.ObjectIdKey, oid))
}

def find(name: String, value: Any): Observable[A] = {
def find(name: String, value: Any)(implicit decoder: Decoder[A]): Observable[A] = {
find(equal(name, value))
}

Expand All @@ -46,8 +51,14 @@ abstract class Search[A]()(implicit ct: ClassTag[A]) extends Base[A] {
distinct(fieldName, filter).resultList().map(v => fromBson(v).asInstanceOf[S])
}

def findAggregated(pipeline: Seq[Bson], allowDiskUse: Boolean = false): Observable[A] = {
coll.aggregate(pipeline).allowDiskUse(allowDiskUse).map(doc => documentToObject[A](doc)).asInstanceOf[AggregateObservable[A]]
def findAggregated(pipeline: Seq[Bson], allowDiskUse: Boolean = false)(implicit decoder: Decoder[A]): Observable[A] = {
val aggregateObservable = coll.aggregate(pipeline).allowDiskUse(allowDiskUse)
aggregateObservable.map {
case a: A =>
a
case doc =>
documentToObject[A](doc)
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.mongodb.scala.bson.conversions.Bson
import org.mongodb.scala.model.Aggregates

import scala.jdk.CollectionConverters._
import dev.mongocamp.driver.mongodb.schema.JsonConverter._

case class MongoPaginatedAggregation[A <: Any](
dao: MongoDAO[A],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package dev.mongocamp.driver.mongodb.pagination

import dev.mongocamp.driver.mongodb.exception.MongoCampPaginationException
import dev.mongocamp.driver.mongodb.{ MongoDAO, _ }
import io.circe.Decoder
import io.circe.generic.auto._
import org.mongodb.scala.bson.conversions.Bson

case class MongoPaginatedFilter[A <: Any](dao: MongoDAO[A], filter: Bson = Map(), sort: Bson = Map(), projection: Bson = Map(), maxWait: Int = DefaultMaxWait)
extends MongoPagination[A] {
case class MongoPaginatedFilter[A <: Any](dao: MongoDAO[A], filter: Bson = Map(), sort: Bson = Map(), projection: Bson = Map(), maxWait: Int = DefaultMaxWait)(
implicit decoder: Decoder[A]
) extends MongoPagination[A] {

def paginate(page: Long, rows: Long): PaginationResult[A] = {
val count = countResult
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ package dev.mongocamp.driver.mongodb.relation

import dev.mongocamp.driver.mongodb.{ GenericObservable, MongoDAO }
import dev.mongocamp.driver.mongodb.relation.RelationCache.{ addCachedValue, getCachedValue, hasCachedValue }
import io.circe.Decoder

case class OneToManyRelationship[A](dao: MongoDAO[A], daoKey: String, useCache: Boolean = true) extends Relationship {
case class OneToManyRelationship[A](dao: MongoDAO[A], daoKey: String, useCache: Boolean = true)(implicit decoder: Decoder[A]) extends Relationship {

def relatedRecords(value: Any): List[A] = {
val key = "%s_%s".format(id, value)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package dev.mongocamp.driver.mongodb.relation

import dev.mongocamp.driver.mongodb.{ GenericObservable, MongoDAO }
import dev.mongocamp.driver.mongodb.relation.RelationCache.{ addCachedValue, getCachedValue, hasCachedValue }
import dev.mongocamp.driver.mongodb.{GenericObservable, MongoDAO}
import dev.mongocamp.driver.mongodb.relation.RelationCache.{addCachedValue, getCachedValue, hasCachedValue}
import io.circe.Decoder

case class OneToOneRelationship[A](dao: MongoDAO[A], daoKey: String, useCache: Boolean = true) extends Relationship {
case class OneToOneRelationship[A](dao: MongoDAO[A], daoKey: String, useCache: Boolean = true)(implicit decoder: Decoder[A]) extends Relationship {

def relatedRecord(value: Any): Option[A] = {
val key = "%s_%s".format(id, value)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package dev.mongocamp.driver.mongodb.schema

import better.files.Resource
import io.circe.{ Decoder, HCursor }
import io.circe.jawn.decode
import io.circe.syntax._
import io.circe.generic.auto._
import org.bson.Document

import scala.collection.mutable
class JsonConverter extends CirceSchema {

def toJson(s: Any): String = {
Expand All @@ -20,4 +24,17 @@ class JsonConverter extends CirceSchema {
readJsonMap(fileContent)
}

def toObject[A](jsonString: String)(implicit decoder: Decoder[A]): A = {
decode[A](jsonString).getOrElse(null.asInstanceOf[A])
}

}

object JsonConverter extends CirceSchema {
implicit lazy val decoder: io.circe.Decoder[org.mongodb.scala.Document] = { (c: HCursor) =>
???
}
implicit lazy val decoder2: io.circe.Decoder[Document] = { (c: HCursor) =>
???
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import scala.collection.mutable.ArrayBuffer
import scala.concurrent.duration.DurationInt
import io.circe.parser.decode
import org.mongodb.scala.documentToUntypedDocument
import io.circe.generic.auto._, io.circe.syntax._
import dev.mongocamp.driver.mongodb.schema.JsonConverter._

class SchemaExplorer {
private val NameSeparator: String = "."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import scala.collection.mutable.ArrayBuffer
import scala.jdk.CollectionConverters._
import scala.util.Try
import net.sf.jsqlparser.statement.Statement
import io.circe.generic.auto._, io.circe.syntax._
import dev.mongocamp.driver.mongodb.schema.JsonConverter._

class MongoSqlQueryHolder {
private val aggregatePipeline: ArrayBuffer[Document] = ArrayBuffer()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dev.mongocamp.driver.mongodb.sync
import com.typesafe.scalalogging.LazyLogging
import dev.mongocamp.driver.mongodb._
import dev.mongocamp.driver.mongodb.database.{ ConfigHelper, DatabaseProvider }
import dev.mongocamp.driver.mongodb.schema.JsonConverter._
import dev.mongocamp.driver.mongodb.sync.SyncDirection.SyncDirection
import dev.mongocamp.driver.mongodb.sync.SyncStrategy.SyncStrategy
import org.mongodb.scala.Document
Expand All @@ -13,6 +14,7 @@ import org.mongodb.scala.model.Updates._
import java.util.Date
import org.mongodb.scala.bson.conversions.Bson
import org.mongodb.scala.documentToUntypedDocument
import io.circe.generic.auto._, io.circe.syntax._

case class MongoSyncOperation(
collectionName: String,
Expand Down

0 comments on commit 968c4b5

Please sign in to comment.