Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ MongoQuery supports several MongoDB specific literal types.
- ObjectIds. `mq"""{ clientId : ObjectId("01234567890abcdef1234") }"""`
- Booleans. `mq"{ expired : false }"`
- Regular expressions (since 0.5). `mq"{ name : /^joe/i }"`
- ISODates. `mq"""{ createdOn : ISODate("2018-07-06T20:45:00.000") }"""`

### mqt interpolator ###

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@

package com.github.limansky.mongoquery.core.bsonparser

import java.time.{LocalDateTime, ZoneOffset}

import com.github.limansky.mongoquery.core.BSON.Member

import scala.util.parsing.combinator.syntactical.StdTokenParsers
import scala.util.parsing.input.CharArrayReader

Expand Down Expand Up @@ -62,14 +65,17 @@ class Parser extends StdTokenParsers {

override val lexical = new Lexical
lexical.delimiters ++= List("[", "]", "{", "}", ":", ",", "(", ")")
lexical.reserved ++= List("ObjectId", "true", "false", "null")
lexical.reserved ++= List("ObjectId", "true", "false", "null", "ISODate")
lexical.operators ++= queryOperators ++ updateOperators ++ aggregationOperators

// Regular expression for ISO date (2018:07:12T10:27:00.000Z)
val isoDateRegex = """[0-9]{4}-[0-9]{2}-[0-9]{2}[T][0-9]{2}:[0-9]{2}:[0-9]{2}.[0-9]{3}[Z]""".r

val hexDigits = Set[Char]() ++ "0123456789abcdefABCDEF".toArray

import lexical._

def value: Parser[Any] = id | regexLit | int | double | boolean | nullLit | array | variable | obj | stringLit
def value: Parser[Any] = id | dateTime | regexLit | int | double | boolean | nullLit | array | variable | obj | stringLit

def operator: Parser[Operator] = elem("operator", _.isInstanceOf[OperatorLit]) ^^ (o => Operator(o.chars))

Expand All @@ -91,6 +97,10 @@ class Parser extends StdTokenParsers {

def id: Parser[Id] = keyword("ObjectId") ~> "(" ~> objectIdValue <~ ")" ^^ Id

def ISODateValue= acceptIf(t => t.isInstanceOf[StringLit] && isoDateRegex.findFirstIn(t.chars).nonEmpty)(t => "Invalid ISODate: " + t.chars) ^^ (v => parseISODate(v.chars))

def dateTime: Parser[DateTime] = keyword("ISODate") ~> "(" ~> ISODateValue <~ ")"

def regexLit: Parser[Regex] = elem("regex", _.isInstanceOf[RegexLit]) ^^ { case RegexLit(e, o) => Regex(e, o) }

def fields: Parser[Member] = elem("fields", _.isInstanceOf[FieldLit]) ^^ { case FieldLit(p) => Member(p) }
Expand All @@ -116,4 +126,10 @@ class Parser extends StdTokenParsers {
val rs = parts.map(p => new CharArrayReader(p.toCharArray))
phrase(obj)(new lexical.Scanner(rs))
}

def parseISODate(stringDate: String): DateTime = {
val date = stringDate.replaceAll("Z", "") // Java ISODate format
val milli = LocalDateTime.parse(date).toInstant(ZoneOffset.UTC).toEpochMilli
DateTime(milli)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ object BSONParser {
case BSON.Object(m) => wrapObject(m)
case BSON.Id(id) => BSONObjectID.parse(id).getOrElse(throw new IllegalArgumentException(s"Invalid ObjectId $id"))
case BSON.Regex(r, opt) => BSONRegex(r, opt)
case BSON.DateTime(v) => BSONDateTime(v)
case list: List[_] => BSONArray(list.map(wrapValue))
case s: String => BSONString(s)
case n: Double => BSONDouble(n)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.github.limansky.mongoquery.reactive

import org.scalatest.{ FlatSpec, Matchers }
import reactivemongo.bson.{ BSONDocument, BSONNull, BSONObjectID, BSONRegex }
import org.scalatest.{FlatSpec, Matchers}
import reactivemongo.bson.{BSONDateTime, BSONDocument, BSONNull, BSONObjectID, BSONRegex}

class BSONParserTest extends FlatSpec with Matchers {
"ReactiveMongo parser" should "parse valid BSON" in {
Expand Down Expand Up @@ -30,6 +30,12 @@ class BSONParserTest extends FlatSpec with Matchers {
))
}

it should "support ISODate" in {
BSONParser.parse("""{ date : ISODate("2018-07-06T20:45:00.000Z") }""") should equal(BSONDocument(
"date" -> BSONDateTime(1530909900000L)
))
}

it should "support null" in {
BSONParser.parse("{ n : null }") should equal(BSONDocument("n" -> BSONNull))
}
Expand Down