Skip to content

Commit

Permalink
Cache MacroBsonFormat.flds in MCcMeta (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
SakulK authored Sep 26, 2024
1 parent 90fa751 commit 8378608
Show file tree
Hide file tree
Showing 18 changed files with 172 additions and 277 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,3 @@ trait BaseBsonFormat[T] extends BsonFormat[T] with BsonArrayReader[T]
trait BasicBsonFormat[T] extends BaseBsonFormat[T] {
override val flds: Map[String, BsonFormat[_]] = Map.empty
}

2 changes: 1 addition & 1 deletion bsonmacros/src/test/scala/me/sgrouples/testtags.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ object testtags {
opaque type Tagged[+V, +Tag] = Any
type @@[+V, +Tag] = V & Tagged[V, Tag]

def tag[Tag]: [V] => V => V @@ Tag =
def tag[Tag]: [V] => V => V @@ Tag =
[V] => (v: V) => v
}
1 change: 0 additions & 1 deletion cc/src/main/scala/me/sgrouples/rogue/Fields.scala
Original file line number Diff line number Diff line change
Expand Up @@ -279,4 +279,3 @@ class OptCClassArrayField[C: ClassTag, MC <: CcMeta[C], O](
with HasChildMeta[C, MC]
class OptMapField[V, O](name: String, o: O)
extends OCField[Map[String, V], O](name, o)

179 changes: 1 addition & 178 deletions cc/src/main/scala/me/sgrouples/rogue/cc/CcMeta.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
package me.sgrouples.rogue.cc

import org.mongodb.scala._
import org.mongodb.scala.model.IndexOptions
import io.fsq.field.Field
import io.fsq.rogue.index.MongoIndex
import me.sgrouples.rogue.BsonFormat
import me.sgrouples.rogue.naming.{LowerCase, NamingStrategy}
import org.bson.{BsonDocument, BsonInt32, BsonValue}

import scala.concurrent.Future
import scala.reflect.ClassTag
import org.bson.{BsonDocument, BsonValue}

trait CcMetaLike[-T] {
type R
Expand All @@ -28,174 +22,3 @@ trait CcMeta[T] extends CcMetaLike[T] {

def reader(field: Field[_, _]): BsonFormat[_]
}

class RCcMeta[T](collName: String)(implicit f: BsonFormat[T])
extends CcMeta[T] {

def this(
namingStrategy: NamingStrategy = LowerCase
)(implicit f: BsonFormat[T], classTag: ClassTag[T]) = {
this(namingStrategy[T])
}
import Waiter._

override def collectionName: String = collName

override def reader(field: Field[_, _]): BsonFormat[_] = {
val fieldName = field.name.replaceAll("\\.\\$", "")
// if field.isInstanceOf[]
val r = f.flds.get(fieldName)
r.orElse(starReader(fieldName)).getOrElse {
throw new RuntimeException(
s"No reader for field ${fieldName}, available keys ${f.flds.keys.mkString(",")}"
)
}
}

//special case for Map formats
private[this] def starReader(fieldName: String): Option[BsonFormat[_]] = {
val i = fieldName.lastIndexOf('.')
if (i > 0) {
val newName = fieldName.substring(0, i + 1) + "*"
f.flds.get(newName)
} else None
}

override def read(b: BsonValue): T = f.read(b)

override def write(t: T): BsonValue = f.write(t)

override def writeAnyRef(t: AnyRef): BsonDocument =
f.write(t.asInstanceOf[T]).asDocument()

/** @param indexTuples
* sequence of (name, int)
* @param opts
* IndexOptions- from mongo
* @return
* - index name
*/
@deprecated("Use `MongoIndex` version instead", "2019/02/15")
def createIndex(indexTuples: Seq[(String, Int)], opts: IndexOptions)(implicit
dbs: MongoDatabase
): String = {
val keys = new BsonDocument()
indexTuples.foreach { case (k, v) => keys.append(k, new BsonInt32(v)) }
waitForFuture(
dbs.getCollection(collectionName).createIndex(keys, opts).toFuture()
)
}

/** @param indexTuples
* sequence of (name, int)
* @param opts
* IndexOptions- from mongo
* @return
* - index name
*/
@deprecated("Use `MongoIndex` version instead", "2019/02/15")
def createIndexAsync(indexTuples: Seq[(String, Int)], opts: IndexOptions)(
implicit dba: MongoDatabase
): Future[String] = {
val keys = new BsonDocument()
indexTuples.foreach { case (k, v) => keys.append(k, new BsonInt32(v)) }
dba.getCollection(collectionName).createIndex(keys, opts).toFuture()
}

/** @param indexTuple
* - field, order tuple
* @param opts
* - IndexOptions
* @return
* index name (string)
*/
@deprecated("Use `MongoIndex` version instead", "2019/02/15")
def createIndex(
indexTuple: (String, Int),
opts: IndexOptions = new IndexOptions()
)(implicit dbs: MongoDatabase): String =
createIndex(Seq(indexTuple), opts)

@deprecated("Use `MongoIndex` version instead", "2019/02/15")
def createIndexAsync(
indexTuple: (String, Int),
opts: IndexOptions = new IndexOptions()
)(implicit dba: MongoDatabase): Future[String] =
createIndexAsync(Seq(indexTuple), opts)

@deprecated("Use `MongoIndex` version instead", "2019/02/15")
def createIndex(indexTuples: Seq[(String, Int)])(implicit
dbs: MongoDatabase
): String = createIndex(indexTuples, new IndexOptions())

@deprecated("Use `MongoIndex` version instead", "2019/02/15")
def createIndexAsync(indexTuples: Seq[(String, Int)])(implicit
dba: MongoDatabase
): Future[String] =
createIndexAsync(indexTuples, new IndexOptions())

/** Index creation without any checks or enforcements - might lock entire
* collection if `background` flag is not specified
* @param index
* MongoIndex to create
* @param opts
* IndexOptions- from mongo
* @return
* - index name
*/
def createIndexUnsafe[M <: CcMeta[T]](
index: MongoIndex[M],
opts: IndexOptions = new IndexOptions()
)(implicit dbs: MongoDatabase): String = {
val indexBson = index.asBsonDocument
waitForFuture(
dbs.getCollection(collectionName).createIndex(indexBson, opts).toFuture()
)
}

/** Index creation without any checks or enforcements - might lock entire
* collection if `background` flag is not specified
* @param index
* MongoIndex to create
* @param opts
* IndexOptions- from mongo
* @return
* - index name
*/
def createIndexUnsafeAsync[M <: CcMeta[T]](
index: MongoIndex[M],
opts: IndexOptions = new IndexOptions()
)(implicit dba: MongoDatabase): Future[String] = {
val indexBson = index.asBsonDocument
dba.getCollection(collectionName).createIndex(indexBson, opts).toFuture()
}

/** "Safe" version of index creation - it forces index to be created in the
* background
*/
def createIndex[M <: CcMeta[T]](index: MongoIndex[M], opts: IndexOptions)(
implicit dbs: MongoDatabase
): String = {
createIndexUnsafe(index, opts.background(true))
}
def createIndex[M <: CcMeta[T]](index: MongoIndex[M])(implicit
dbs: MongoDatabase
): String = createIndex(index, new IndexOptions())

/** "Safe" version of index creation - it forces index to be created in the
* background
*/
def createIndexAsync[M <: CcMeta[T]](
index: MongoIndex[M],
opts: IndexOptions
)(implicit dba: MongoDatabase): Future[String] = {
createIndexUnsafeAsync(index, opts.background(true))
}
def createIndexAsync[M <: CcMeta[T]](
index: MongoIndex[M]
)(implicit dba: MongoDatabase): Future[String] = {
createIndexAsync(index, new IndexOptions())
}

}

8 changes: 5 additions & 3 deletions cc/src/main/scala/me/sgrouples/rogue/cc/macros/MCcMeta.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ class MCcMeta[RecordType, OwnerType <: CcMeta[RecordType]](collName: String)(

override def collectionName: String = collName

private val flds = bsonFormat.flds

override def reader(field: Field[_, _]): BsonFormat[_] = {
val fieldName = field.name.replaceAll("\\.\\$", "")
val r = bsonFormat.flds.get(fieldName)
val r = flds.get(fieldName)
r.orElse(starReader(fieldName)).getOrElse {
throw new RuntimeException(
s"No reader for field ${fieldName}, available keys ${bsonFormat.flds.keys.mkString(",")}"
s"No reader for field ${fieldName}, available keys ${flds.keys.mkString(",")}"
)
}
}
Expand All @@ -44,7 +46,7 @@ class MCcMeta[RecordType, OwnerType <: CcMeta[RecordType]](collName: String)(
val i = fieldName.lastIndexOf('.')
if (i > 0) {
val newName = fieldName.substring(0, i + 1) + "*"
bsonFormat.flds.get(newName)
flds.get(newName)
} else None
}

Expand Down
30 changes: 19 additions & 11 deletions cc/src/test/scala/me/sgrouples/rogue/cc/ArrayListTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,41 @@ import me.sgrouples.rogue.cc.CcRogue._
import scala.concurrent.Future

case class ArrayOfListWrapper(
arrayOfList: Array[List[String]],
_id: Int = 1
)
arrayOfList: Array[List[String]],
_id: Int = 1
)

class ArrayOfListWrapperMeta extends MCcMeta[ArrayOfListWrapper, ArrayOfListWrapperMeta]() {
class ArrayOfListWrapperMeta
extends MCcMeta[ArrayOfListWrapper, ArrayOfListWrapperMeta]() {
val id = IntField("id")
val arrayOfList = ArrayField[List[String]]("arrayOfList")
}
class ArrayOfListRepository()(implicit db:MongoDatabase) {
class ArrayOfListRepository()(implicit db: MongoDatabase) {
private val Repo = new ArrayOfListWrapperMeta
def load(): Future[Option[Array[List[String]]]] = Repo.where(_.id eqs 1).select(_.arrayOfList).getAsync()
def load(): Future[Option[Array[List[String]]]] =
Repo.where(_.id eqs 1).select(_.arrayOfList).getAsync()

def addWords(words: Seq[String]) = {
Repo.where(_.id eqs 1).modify(_.arrayOfList addToSet words.sorted.toList).upsertOneAsync()
Repo
.where(_.id eqs 1)
.modify(_.arrayOfList addToSet words.sorted.toList)
.upsertOneAsync()
}

def removeWords(words: Seq[String]) = {
Repo.where(_.id eqs 1).modify(_.arrayOfList pull words.sorted.toList).updateOneAsync()
Repo
.where(_.id eqs 1)
.modify(_.arrayOfList pull words.sorted.toList)
.updateOneAsync()
}
}

class ArrayListTests extends FunSuite {
test("nested array list"){
test("nested array list") {
//it should just compile
implicit val db:MongoDatabase=null
implicit val db: MongoDatabase = null

val repo=new ArrayOfListRepository()
val repo = new ArrayOfListRepository()
assert(true)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,26 @@ object GroupModelType extends Enumeration {
val one = Value
val two = Value

given MacroBsonFormat[GroupModelType.Value] = EnumMacroFormats.enumNameMacroFormat(GroupModelType)
given MacroBsonFormat[GroupModelType.Value] =
EnumMacroFormats.enumNameMacroFormat(GroupModelType)
}

object RoleName extends Enumeration {
type RoleName = Value
val one = Value
val two = Value

given MacroBsonFormat[RoleName.Value] = EnumMacroFormats.enumNameMacroFormat(RoleName)
given MacroBsonFormat[RoleName.Value] =
EnumMacroFormats.enumNameMacroFormat(RoleName)
}

object Permission extends Enumeration {
type Permission = Value
val one = Value
val two = Value

given MacroBsonFormat[Permission.Value] = EnumMacroFormats.enumNameMacroFormat(Permission)
given MacroBsonFormat[Permission.Value] =
EnumMacroFormats.enumNameMacroFormat(Permission)
}

trait AnyTag
Expand Down
20 changes: 16 additions & 4 deletions cc/src/test/scala/me/sgrouples/rogue/cc/EndToEndBsonTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class EndToEndBsonTest extends FunSuite {
}

private var dbOpt: Option[MongoDatabase] = None
implicit def db:MongoDatabase =
implicit def db: MongoDatabase =
dbOpt.getOrElse(throw new RuntimeException("UninitializedError"))

override def beforeAll(): Unit = {
Expand Down Expand Up @@ -211,7 +211,10 @@ class EndToEndBsonTest extends FunSuite {
VenueR.insertOne(v)

val base = VenueR.where(_.id eqs v._id)
assertEquals(base.selectCase(_.legacyid, V1.apply).fetch(), List(V1(v.legId)))
assertEquals(
base.selectCase(_.legacyid, V1.apply).fetch(),
List(V1(v.legId))
)
assertEquals(
base.selectCase(_.legacyid, _.userId, V2.apply).fetch(),
List(V2(v.legId, v.userId))
Expand All @@ -221,12 +224,21 @@ class EndToEndBsonTest extends FunSuite {
List(V3(v.legId, v.userId, v.mayor))
)
assertEquals(
base.selectCase(_.legacyid, _.userId, _.mayor, _.mayor_count, V4.apply).fetch(),
base
.selectCase(_.legacyid, _.userId, _.mayor, _.mayor_count, V4.apply)
.fetch(),
List(V4(v.legId, v.userId, v.mayor, v.mayor_count))
)
assertEquals(
base
.selectCase(_.legacyid, _.userId, _.mayor, _.mayor_count, _.closed, V5.apply)
.selectCase(
_.legacyid,
_.userId,
_.mayor,
_.mayor_count,
_.closed,
V5.apply
)
.fetch(),
List(V5(v.legId, v.userId, v.mayor, v.mayor_count, v.closed))
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import me.sgrouples.rogue.cc.CcRogue.*
object EnumIdFieldEnum extends Enumeration {
val one: Value = Value
val two: Value = Value
given MacroBsonFormat[EnumIdFieldEnum.Value] = EnumMacroFormats.enumValueMacroFormat(EnumIdFieldEnum)
given MacroBsonFormat[EnumIdFieldEnum.Value] =
EnumMacroFormats.enumValueMacroFormat(EnumIdFieldEnum)
}

case class EnumIdFieldClass(`enum`: EnumIdFieldEnum.Value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import org.bson.types.ObjectId
import com.softwaremill.tagging.*
import me.sgrouples.rogue.cc.CcRogue.*


case class CustomKey(value: Long) extends AnyVal
case class StringMap(value: Map[String, Long])
case class ObjectIdMap(value: Map[ObjectId, Long])
Expand Down
Loading

0 comments on commit 8378608

Please sign in to comment.