/**
  * Convert a comparison expression into the target query language output.
  *
  * @param Comparison $comparison
  *
  * @return callable
  *
  * @throws ExpressionException
  */
 public function walkComparison(Comparison $comparison)
 {
     $field = $comparison->getField();
     $value = $comparison->getValue();
     switch ($comparison->getOperator()) {
         case Comparison::EQUAL:
         case Comparison::IS_NULL:
             return function ($object) use($field, $value) {
                 return ClosureExpressionVisitor::getObjectFieldValue($object, $field) === $value;
             };
         case Comparison::NOT_EQUAL:
         case Comparison::IS_NOT_NULL:
             return function ($object) use($field, $value) {
                 return ClosureExpressionVisitor::getObjectFieldValue($object, $field) !== $value;
             };
         case Comparison::LOWER_THAN:
             return function ($object) use($field, $value) {
                 return ClosureExpressionVisitor::getObjectFieldValue($object, $field) < $value;
             };
         case Comparison::LOWER_THAN_EQUAL:
             return function ($object) use($field, $value) {
                 return ClosureExpressionVisitor::getObjectFieldValue($object, $field) <= $value;
             };
         case Comparison::GREATER_THAN:
             return function ($object) use($field, $value) {
                 return ClosureExpressionVisitor::getObjectFieldValue($object, $field) > $value;
             };
         case Comparison::GREATER_THAN_EQUAL:
             return function ($object) use($field, $value) {
                 return ClosureExpressionVisitor::getObjectFieldValue($object, $field) >= $value;
             };
         case Comparison::IN:
             return function ($object) use($field, $value) {
                 return in_array(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value);
             };
         case Comparison::NOT_IN:
             return function ($object) use($field, $value) {
                 return !in_array(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value);
             };
         case Comparison::EXISTS:
             return function ($object) use($value) {
                 foreach ($value as $row) {
                     if ($row !== $object || serialize($row) === serialize($object)) {
                         return true;
                     }
                 }
                 return false;
             };
         case Comparison::NOT_EXISTS:
             return function ($object) use($value) {
                 foreach ($value as $row) {
                     if ($row !== $object || serialize($row) === serialize($object)) {
                         return false;
                     }
                 }
                 return true;
             };
         case Comparison::LIKE:
             return function ($object) use($field, $value) {
                 return ClosureExpressionVisitor::findString(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value);
             };
         case Comparison::NOT_LIKE:
             return function ($object) use($field, $value) {
                 return !ClosureExpressionVisitor::findString(ClosureExpressionVisitor::getObjectFieldValue($object, $field), $value);
             };
         default:
             throw ExpressionException::unknownExpressionOperator($comparison);
     }
 }
 /**
  * {@inheritdoc}
  *
  * @return Collection
  */
 public function matching(Criteria $criteria)
 {
     $elements = $this->elements;
     if ($expression = $criteria->getExpression()) {
         $visitor = new ClosureExpressionVisitor();
         $filter = $visitor->dispatch($expression);
         $elements = array_filter($elements, $filter);
     }
     if ($orderings = $criteria->getOrderings()) {
         $next = null;
         foreach (array_reverse($orderings) as $field => $ordering) {
             $next = ClosureExpressionVisitor::sortByField($field, $ordering == Criteria::ORDER_DESC ? -1 : 1, $next);
         }
         usort($elements, $next);
     }
     $offset = $criteria->getFirstResult();
     $length = $criteria->getMaxResults();
     if ($offset || $length) {
         $elements = array_splice($elements, (int) $offset, $length);
     }
     return new static($elements);
 }