Skip to content

Commit ed076f8

Browse files
committed
Writers weakteam#14
1 parent d54b40f commit ed076f8

File tree

4 files changed

+169
-9
lines changed

4 files changed

+169
-9
lines changed

core/src/main/scala/io/github/weakteam/mongo/bson/BsonWriter.scala

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,71 @@
11
package io.github.weakteam.mongo.bson
22

3+
import java.util.regex.Pattern
4+
35
import cats.Contravariant
6+
import io.github.weakteam.mongo.bson.BsonSubtype.UserDefinedSubtype
7+
import io.github.weakteam.mongo.bson.BsonValue.{
8+
BsonArray,
9+
BsonBinary,
10+
BsonBoolean,
11+
BsonDocument,
12+
BsonFloat,
13+
BsonInt,
14+
BsonLong,
15+
BsonNull,
16+
BsonRegex,
17+
BsonString
18+
}
419
import simulacrum.typeclass
520

21+
import scala.util.matching.Regex
22+
623
@typeclass
724
trait BsonWriter[-T] { self =>
825
def writeBson(arg: T): BsonValue
926
}
1027

11-
object BsonWriter {
28+
trait Instances {
29+
implicit val identityWriter: BsonWriter[BsonValue] = identity(_)
30+
implicit val intWriter: BsonWriter[Int] = BsonInt(_)
31+
implicit val stringWriter: BsonWriter[String] = BsonString(_)
32+
implicit val longWriter: BsonWriter[Long] = BsonLong(_)
33+
implicit val doubleWriter: BsonWriter[Double] = BsonFloat(_)
34+
implicit val floatWriter: BsonWriter[Float] = float => BsonFloat(float.toDouble)
35+
implicit val booleanWriter: BsonWriter[Boolean] = BsonBoolean(_)
36+
implicit val regexWriter: BsonWriter[Regex] = reg => BsonRegex(reg.regex)
37+
implicit val patternWriter: BsonWriter[Pattern] = reg => BsonRegex(reg.pattern())
38+
}
39+
40+
trait LowPriorityInstances {
41+
42+
implicit def optionWriter[A](implicit W: BsonWriter[A]): BsonWriter[Option[A]] = {
43+
case Some(value) => W.writeBson(value)
44+
case _ => BsonNull
45+
}
46+
47+
implicit def eitherWriter[L, R](implicit LW: BsonWriter[L], RW: BsonWriter[R]): BsonWriter[Either[L, R]] = {
48+
_.fold(LW.writeBson, RW.writeBson)
49+
}
50+
51+
implicit def listWriter[A](implicit W: BsonWriter[A]): BsonWriter[List[A]] = { list =>
52+
BsonArray(list.map(W.writeBson))
53+
}
54+
55+
implicit def setWriter[A](implicit W: BsonWriter[A]): BsonWriter[Set[A]] = { set =>
56+
BsonArray(set.map(W.writeBson).toList)
57+
}
58+
59+
implicit def mapWriter[K, V](implicit K: BsonKeyWriter[K], W: BsonWriter[V]): BsonWriter[Map[K, V]] = { map =>
60+
BsonDocument(map.map { case (k, v) => (K.writeKey(k), W.writeBson(v)) })
61+
}
62+
63+
implicit def enum[T <: Enumeration](e: T): BsonWriter[e.Value] = { e =>
64+
BsonBinary(UserDefinedSubtype(0x05), e.id.toString.getBytes("UTF-8"))
65+
}
66+
}
67+
68+
object BsonWriter extends Instances with LowPriorityInstances {
1269
def instance[A](f: A => BsonValue): BsonWriter[A] = f(_)
1370

1471
implicit val bsonWriterContravariantInstance: Contravariant[BsonWriter] = new Contravariant[BsonWriter] {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import scala.collection.generic.CanBuildFrom
2+
import scala.collection.mutable.Builder
3+
4+
/**
5+
* Shim for compatibility between scala 2.11/2.12 and 2.13
6+
*/
7+
class CollectionFactory[-A, +C](private val cbf: CanBuildFrom[_, A, C]) extends AnyVal {
8+
def newBuilder: Builder[A, C] = cbf()
9+
}
10+
11+
object CollectionFactory {
12+
implicit def factory[A, C](implicit cbf: CanBuildFrom[_, A, C]) = new CollectionFactory(cbf)
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import scala.collection.Factory
2+
import scala.collection.mutable.Builder
3+
4+
/**
5+
* Shim for compatibility between scala 2.11/2.12 and 2.13
6+
*/
7+
class CollectionFactory[-A, +C](private val f: Factory[A,C]) extends AnyVal {
8+
def newBuilder: Builder[A, C] = f.newBuilder
9+
}
10+
11+
object CollectionFactory {
12+
implicit def factory[A, C](implicit f: Factory[A, C]): CollectionFactory[A, C] = new CollectionFactory(f)
13+
}
Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
package io.github.weakteam.mongo.bson
22

3-
import io.github.weakteam.mongo.bson.BsonValue.BsonInt
3+
import java.util.regex.Pattern
4+
5+
import io.github.weakteam.mongo.bson.BsonValue._
46
import org.scalatest.matchers.must.Matchers
57
import org.scalatest.wordspec.AnyWordSpec
68
import io.github.weakteam.mongo.implicits._
79
import cats.syntax.contravariant._
810

11+
import scala.util.matching.Regex
12+
913
class BsonWriterSpec extends AnyWordSpec with Matchers {
1014
"BsonWriter" should {
1115
"return right value" in {
12-
implicit val intBsonWriter: BsonWriter[Int] = BsonInt(_)
13-
14-
1.writeBson mustBe BsonInt(1)
16+
BsonWriter.instance(BsonInt).writeBson(1) mustBe BsonInt(1)
1517
}
1618

1719
"return right value with contramap" in {
18-
implicit val intBsonWriter: BsonWriter[Int] = BsonInt(_)
19-
implicit val anyBsonWriter: BsonWriter[Any] = intBsonWriter.contramap {
20+
implicit val anyBsonWriter: BsonWriter[Any] = BsonWriter.intWriter.contramap {
2021
case i: Int => i
2122
case _ => 0
2223
}
@@ -27,9 +28,85 @@ class BsonWriterSpec extends AnyWordSpec with Matchers {
2728
}
2829

2930
"return right value with manual instance creation" in {
30-
implicit val intBsonWriter: BsonWriter[Int] = BsonWriter.instance(BsonInt)
31+
val intBsonWriter: BsonWriter[Int] = BsonWriter.instance(BsonInt)
3132

32-
1.writeBson mustBe BsonInt(1)
33+
intBsonWriter.writeBson(1) mustBe BsonInt(1)
3334
}
3435
}
36+
37+
"BsonWriter#instances" should {
38+
"write identity" in {
39+
BsonWriter[BsonValue].writeBson(BsonString("bson")) mustBe BsonString("bson")
40+
}
41+
42+
"write int" in {
43+
BsonWriter[Int].writeBson(42) mustBe BsonInt(42)
44+
}
45+
46+
"write long" in {
47+
BsonWriter[Long].writeBson(42L) mustBe BsonLong(42L)
48+
}
49+
50+
"write boolean" in {
51+
BsonWriter[Boolean].writeBson(true) mustBe BsonBoolean(true)
52+
}
53+
54+
"write double" in {
55+
BsonWriter[Double].writeBson(42.52d) mustBe BsonFloat(42.52d)
56+
}
57+
58+
"write float" in {
59+
BsonWriter[Float].writeBson(42.52f) mustBe BsonFloat(42.52f)
60+
}
61+
62+
"write regex" in {
63+
BsonWriter[Regex].writeBson("foo".r) mustBe BsonRegex("foo")
64+
}
65+
66+
"write pattern" in {
67+
BsonWriter[Pattern].writeBson("foo".r.pattern) mustBe BsonRegex("foo")
68+
}
69+
}
70+
71+
"BsonWriter#wrapped-instances" should {
72+
implicit def implConv[A: BsonWriter](value: A): BsonValue = value.writeBson
73+
74+
"write option" in {
75+
BsonWriter[Option[Int]].writeBson(Some(4)) mustBe BsonInt(4)
76+
BsonWriter[Option[Int]].writeBson(None) mustBe BsonNull
77+
}
78+
79+
"write either" in {
80+
BsonWriter[Either[Boolean, String]].writeBson(Right("foo")) mustBe BsonString("foo")
81+
BsonWriter[Either[Boolean, String]].writeBson(Left(true)) mustBe BsonBoolean(true)
82+
}
83+
84+
"write list" in {
85+
BsonWriter[List[Int]].writeBson(List(1, 4, 5)) mustBe BsonArray(1, 4, 5)
86+
}
87+
88+
"write set" in {
89+
BsonWriter[Set[String]].writeBson(Set("foo", "foo", "bar")) mustBe BsonArray("foo", "bar")
90+
}
91+
92+
"write map" in {
93+
implicit val stringBsonKeyWriter: BsonKeyWriter[String] = identity(_)
94+
95+
BsonWriter[Map[String, Int]]
96+
.writeBson(Map("foo" -> 3, "foo" -> 4, "bar" -> 5)) mustBe BsonDocument("foo" := 4, "bar" := 5)
97+
}
98+
99+
// "write Enum" in {
100+
// def wr: BsonWriter[TestEnum.Value] = TestEnum
101+
// wr.writeBson(TestEnum.A) mustBe BsonBinary(UserDefinedSubtype(0x05), 1.toString.getBytes("UTF-8"))
102+
//
103+
// wr.writeBson(TestEnum.B) mustBe BsonBinary(UserDefinedSubtype(0x05), 2.toString.getBytes("UTF-8"))
104+
// }
105+
}
35106
}
107+
108+
//object BsonWriterSpec {
109+
// object TestEnum extends Enumeration {
110+
// val A, B = Value
111+
// }
112+
//}

0 commit comments

Comments
 (0)