From b904f9bfe74e79d27ae76e7913765618e940aa93 Mon Sep 17 00:00:00 2001 From: Andrii Lashchenko Date: Mon, 22 Jul 2024 01:23:14 +0300 Subject: [PATCH] Update README.md --- README.md | 112 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 96 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 06ad2da..d635224 100644 --- a/README.md +++ b/README.md @@ -5,10 +5,11 @@ [![green-leaf-mongo-core](https://index.scala-lang.org/greenleafoss/green-leaf-mongo/green-leaf-mongo-core/latest-by-scala-version.svg)](https://index.scala-lang.org/greenleafoss/green-leaf-mongo/green-leaf-mongo-core) [![green-leaf-mongo-spray](https://index.scala-lang.org/greenleafoss/green-leaf-mongo/green-leaf-mongo-spray/latest-by-scala-version.svg)](https://index.scala-lang.org/greenleafoss/green-leaf-mongo/green-leaf-mongo-spray) [![green-leaf-mongo-play](https://index.scala-lang.org/greenleafoss/green-leaf-mongo/green-leaf-mongo-play/latest-by-scala-version.svg)](https://index.scala-lang.org/greenleafoss/green-leaf-mongo/green-leaf-mongo-play) +[![green-leaf-mongo-circe](https://index.scala-lang.org/greenleafoss/green-leaf-mongo/green-leaf-mongo-circe/latest-by-scala-version.svg)](https://index.scala-lang.org/greenleafoss/green-leaf-mongo/green-leaf-mongo-circe) ## Short description -This extension created on top of official [MongoDB Scala Driver](https://mongodb.github.io/mongo-scala-driver) and allows to fully utilize [Spray JSON](https://github.com/spray/spray-json) or [Play JSON](https://github.com/playframework/play-json) to represent bidirectional serialization for case classes in BSON, as well as flexible DSL for [MongoDB query operators](https://www.mongodb.com/docs/manual/reference/operator/query/), documents and collections. +This extension created on top of official [MongoDB Scala Driver](https://mongodb.github.io/mongo-scala-driver) and allows to fully utilize [Spray JSON](https://github.com/spray/spray-json), [Play JSON](https://github.com/playframework/play-json) or [Circe JSON](https://circe.github.io/circe/) to represent bidirectional serialization for case classes in BSON, as well as flexible DSL for [MongoDB query operators](https://www.mongodb.com/docs/manual/reference/operator/query/), documents and collections. It was introduced in 2019 - [Andrii Lashchenko at #ScalaUA - Spray JSON and MongoDB Queries: Insights and Simple Tricks ](https://www.youtube.com/watch?v=NBgKkQtydAo) @@ -25,10 +26,13 @@ Related slides available at https://www.slideshare.net/lashchenko/spray-json-and // `green-leaf-mongo-core` can be used if you want to create your own extension // https://mvnrepository.com/artifact/io.github.greenleafoss/green-leaf-mongo-spray -libraryDependencies += "io.github.greenleafoss" %% "green-leaf-mongo-spray" % "3.0" +libraryDependencies += "io.github.greenleafoss" %% "green-leaf-mongo-spray" % "3.1" // https://mvnrepository.com/artifact/io.github.greenleafoss/green-leaf-mongo-play -libraryDependencies += "io.github.greenleafoss" %% "green-leaf-mongo-play" % "3.0" +libraryDependencies += "io.github.greenleafoss" %% "green-leaf-mongo-play" % "3.1" + +// https://mvnrepository.com/artifact/io.github.greenleafoss/green-leaf-mongo-circe +libraryDependencies += "io.github.greenleafoss" %% "green-leaf-mongo-circe" % "3.1" ``` ## JSON and BSON protocols @@ -36,34 +40,71 @@ libraryDependencies += "io.github.greenleafoss" %% "green-leaf-mongo-play" % "3. `GreenLeafMongoJsonBasicFormats` based on DefaultJsonProtocol from Spray JSON and allows to override predefined JsonFormats to make possible use custom serialization in BSON format. This trait also includes a few additional JsonFormats for _LocalDate_, _LocalDateTime_, _ZonedDateTime_, _ObjectId_, _scala Enumeration_ and _UUID_. -`PlayJsonProtocol` is a related extension for the Play JSON library and `SprayJsonProtocol` for the Spray JSON library. +`CirceJsonProtocol` is a related extension for the Circe JSON library, `PlayJsonProtocol` is for the Play JSON library and `SprayJsonProtocol` for the Spray JSON library. -`SprayBsonProtocol`/`PlayBsonProtocol` extends related JsonProtocols and overrides _Int_, _Long_, _BigDecimal_, _LocalDate_, _LocalDateTime_, _ZonedDateTime_, _ObjectId_, _scala Enumeration_, _UUID_ and _Regex_ JSON formats to represent them in related BSON (MongoDB Extended JSON V2) formats https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/#mongodb-extended-json-v2-usage. +`SprayBsonProtocol`/`PlayBsonProtocol`/`CirceBsonProtocol` extends related JsonProtocols and overrides _Int_, _Long_, _BigDecimal_, _LocalDate_, _LocalDateTime_, _ZonedDateTime_, _ObjectId_, _scala Enumeration_, _UUID_ and _Regex_ JSON formats to represent them in related BSON (MongoDB Extended JSON V2) formats https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/#mongodb-extended-json-v2-usage. These base protocols allow to simply (de)serialize this instance to and from both JSON and BSON the same way as in Spray JSON: ```scala 3 // MODEL -case class Test(_id: ObjectId, i: Int, l: Long, b: Boolean, zdt: ZonedDateTime) +final case class Test(_id: ObjectId, i: Int, l: Long, b: Boolean, zdt: ZonedDateTime) // JSON trait TestJsonProtocol extends SprayJsonProtocol: - given testJsonFormat = jsonFormat5(Test) + given testJsonFormat: JsonFormat[Test] = jsonFormat5(Test) object TestJsonProtocol extends TestJsonProtocol // BSON object TestBsonProtocol extends TestJsonProtocol with SprayBsonProtocol ``` +or Play JSON +```scala 3 +// MODEL +final case class Test(_id: ObjectId, i: Int, l: Long, b: Boolean, zdt: ZonedDateTime) + +// JSON +trait TestJsonProtocol extends PlayJsonProtocol: + given testJsonFormat: Format[Test] = Json.format[Test] + +object TestJsonProtocol extends TestJsonProtocol + +// BSON +object TestBsonProtocol extends TestJsonProtocol with PlayBsonProtocol +``` +or Circe +```scala 3 +// MODEL +final case class Test(_id: ObjectId, i: Int, l: Long, b: Boolean, zdt: ZonedDateTime) + +// JSON +trait TestJsonProtocol extends CirceJsonProtocol: + given testJsonFormat: Codec[Test] = deriveCodec + +object TestJsonProtocol extends TestJsonProtocol + +// BSON +object TestBsonProtocol extends TestJsonProtocol with CirceBsonProtocol +``` Once protocols defined, we can make instance of Test case class and use TestJsonProtocol to print related JSON: ```scala -val obj = Test(new ObjectId("5c72b799306e355b83ef3c86"), 1, 0x123456789L, true, "1970-01-01") +Test(new ObjectId("5c72b799306e355b83ef3c86"), 1, 0x123456789L, true, "1970-01-01T00:00:00Z".parseZonedDateTime) +// Spray JSON import TestJsonProtocol.given println(obj.toJson.prettyPrint) + +// Play JSON +import TestJsonProtocol.given +println(Json.prettyPrint(Json.toJson(obj))) + +// Circe JSON +import TestJsonProtocol.given +println(obj.asJson) ``` Output in this case will be: -```js +```json { "_id": "5c72b799306e355b83ef3c86", "i": 1, @@ -76,14 +117,23 @@ Output in this case will be: Changing single line of import `TestJsonProtocol` to `TestBsonProtocol` allows us to (de)serialize this instance to and from BSON: ```scala -val obj = Test(new ObjectId("5c72b799306e355b83ef3c86"), 1, 0x123456789L, true, "1970-01-01") +Test(new ObjectId("5c72b799306e355b83ef3c86"), 1, 0x123456789L, true, "1970-01-01T00:00:00Z".parseZonedDateTime) +// Spray JSON import TestBsonProtocol.given println(obj.toJson.prettyPrint) + +// Play JSON +import TestBsonProtocol.given +println(Json.prettyPrint(Json.toJson(obj))) + +// Circe JSON +import TestBsonProtocol.given +println(obj.asJson) ``` Output in this case will be: -```js +```json { "_id": { "$oid": "5c72b799306e355b83ef3c86" @@ -103,27 +153,57 @@ Output in this case will be: } ``` -More examples available in implementation of **JsonProtocolSpec**/**BsonProtocolSpec** in Spray and Play project modules. +More examples available in implementation of **JsonProtocolSpec**/**BsonProtocolSpec** in Spray, Play and Circe project modules. ## GreenLeafMongoDsl `GreenLeafMongoFilterOps` makes it possible to write queries with a syntax that is more close to real queries in MongoDB, as was implemented in [Casbah Query DSL](http://mongodb.github.io/casbah/3.1/reference/query_dsl/). ```scala -"size" $all ("S", "M", "L") +"size" $all Seq("S", "M", "L") +// {"size": {"$all": ["S", "M", "L"]}} + "price" $eq 10 +// {"price": {"$eq": 10}} + "price" $gt 10 +// {"price": {"$gt": 10}} + "price" $gte 10 -"size" $in ("S", "M", "L") +// {"price": {"$gte": 10}} + +"size" $in Seq("S", "M", "L") +// {"size": {"$in": ["S", "M", "L"]}} + "price" $lt 100 +// {"price": {"$lt": 100}} + "price" $lte 100 +// {"price": {"$lte": 100}} + "price" $ne 1000 -"size" $nin ("S", "XXL") +// {"price": {"$ne": 1000}} + +"size" $nin Seq("S", "XXL") +// {"size": {"$nin": ["S", "XXL"]}} + $or( "price" $lt 5, "price" $gt 1, "promotion" $eq true ) +// {"$or": [{"price": {"$lt": 5}}, {"price": {"$gt": 1}}, {"promotion": {"$eq": true}}]} + $and( "price" $lt 5, "price" $gt 1, "stock" $gte 1 ) -"price" $not { $gte (5.1) } +// {"$and": [{"price": {"$lt": 5}}, {"price": {"$gt": 1}}, {"stock": {"$gte": 1}}]} + +"price" $not { $gte (5.1) } +// {"price": {"$not": {"$gte": 5.1}}} + $nor( "price" $eq 1.99 , "qty" $lt 20, "sale" $eq true ) +// {"$nor": [{"price": {"$eq": 1.99}}, {"qty": {"$lt": 20}}, {"sale": {"$eq": true}}]} + "qty" $exists true +// {"qty": {"$exists": true}} + "results" $elemMatch $and("product" $eq "xyz", "score" $gte 8) +// {"results": {"$elemMatch": {"$and": [{"product": {"$eq": "xyz"}}, {"score": {"$gte": 8}}]}}} + // ... ```