Scala casbah DSL-запросы

Я изучаю Scala и тоже пробую Mongo. Я создаю функцию, которая получает Map[String, Any] в качестве параметра, и я хотел бы вернуть для нее правильный MongoDBObject:

def parse(query: Map[String, Any]): MongoDBObject = {
  val result = query("operation") match {
    case "all" => query("field").toString $all query("value").asInstanceOf[List[String]]
    case "in" => query("field").toString $in query("value").asInstanceOf[List[String]]
    case "regex" => query("field").toString $regex query("value")
    case "eq" => query("field").toString $eq query("value")
    case "gt" => query("field").toString $gt query("value")
    case "gte" => query("field").toString $gte query("value")
    case "lt" => query("field").toString $lt query("value")
    case "lte" => query("field").toString $lte query("value")
    case "exists" => query("field").toString $exists query("value").asInstanceOf[Boolean]
    case "size" => query("field").toString $size query("value").asInstanceOf[Int]
    case "where" => $where(query("value").toString)
    case _ => throw new NotImplementedError("Unknown operation")
  }
}

У меня есть некоторые проблемы.

  • компилятор говорит, что $regex не является членом String. Я не знаю почему.
  • компилятор говорит, что Any не является допустимым параметром запроса. Я полагаю, что я должен привести к типу int, string, date или любому другому допустимому типу Mongo. Есть ли способ исправить это без размышлений, чтобы решить, какой тип имеет значение?
  • для операции $mod я должен указать два числовых значения в качестве параметров. Должен ли я использовать List в качестве значения для карты и получить первый и второй элементы?

person Augusto    schedule 18.09.2013    source источник


Ответы (1)


Он жалуется на $regex, потому что он не находит с правой стороны объекта, поддерживающего регулярное выражение, для применения преобразования, используемого для синтаксического анализа метода $regex — это проблема, с которой вы столкнетесь и со всеми следующими вызовами.

Могу ли я предложить другой подход к проблеме с Any (а также $mod)? У вас нет информации о типе с Any, поэтому вы не можете обойти приведение во время выполнения (и я не уверен, как отражение поможет вам). Таким образом, вы не получаете никаких преимуществ системы статического типа. Вот набросок одного из способов реализации подобного метода с использованием иерархии типов для обеспечения безопасности типов:

sealed trait Query

case class All(field: String, value: List[String]) extends Query 
...
case class GreaterThan(field: String, value: Int) extends Query 
...
case class Mod(field: String, divisor: Int, remainder: Int) extends Query

def parse(q: Query): MongoDBObject = {
   q match {
      case All(f, v) => f $all v
      ...
      case GreaterThan(f, v) => f $gt v
      ...
      case Mod(f, d, r) => f $mod (d, r)
   }
}

В качестве альтернативы вы можете определить абстрактный метод выполнения в Query и переопределить его в каждом расширяющемся классе вместо выполнения оператора match в parse. Оттуда вы можете абстрагироваться дальше, используя параметры типа или общие типы, чтобы, например, GreaterThan принять любой тип Numeric.

person Kelsey Gilmore-Innis    schedule 18.09.2013
comment
Гораздо лучший подход. Но все же мне придется привести свой Any к типу. Я использую эту карту [String, Any], потому что я анализирую JSON с помощью встроенных парсеров scala. И это дает мне Map[String, Any], так что мне придется привести это Any к нужному типу. Я подумал об отражении, чтобы проверить, какой это тип, и вернуть его с правильным приведением. Что касается проблемы $regex, я использовал учебник в документации, который указывает мне на использование SBT, поэтому я думаю, что он загрузил последнюю банку. Я просмотрел банку и нашел там функцию $regex... Я понятия не имею, почему компилятор жалуется на это - person Augusto; 18.09.2013
comment
Если у вас есть контроль над форматом сообщения JSON, вы можете использовать json4s (github.com/json4s/json4s ), чтобы легко сериализовать и десериализовать классы case. Даже если вы этого не сделаете, используя эту библиотеку, вы можете извлечь тип запроса, а затем соответствующим образом десериализовать. - person Kelsey Gilmore-Innis; 18.09.2013
comment
Привет еще раз... Я пробую примеры с их веб-сайта, и я всегда получаю ошибку (неверное имя класса) - person Augusto; 19.09.2013
comment
Я сделал это с помощью Lift-json. Но у меня все еще есть сомнения. В случае, когда $eq поддерживает несколько типов, как я могу решить проблему? У меня не может быть двух классов с одинаковым именем. Поэтому у меня не может быть Eq (поле: строка, значение: Int) и Eq (поле: строка, значение: строка) - person Augusto; 19.09.2013
comment
Классы могут называться как угодно. Если вы чувствуете себя особенно продвинутым, вы можете посмотреть, как авторы библиотеки casbah справились с этой проблемой, поскольку она с открытым исходным кодом: github.com/mongodb/casbah/blob/master/casbah-query/src/main/ github.com/mongodb/casbah/blob/master/ casbah-query/src/main/ - person Kelsey Gilmore-Innis; 19.09.2013