/**
  * Finds objects by a set of criteria.
  *
  * Optionally sorting and limiting details can be passed. An implementation may throw
  * an UnexpectedValueException if certain values of the sorting or limiting details are
  * not supported.
  *
  * @param array      $criteria
  * @param array|null $orderBy
  * @param int|null   $limit
  * @param int|null   $offset
  * @param string     $fetchPlan
  *
  * @return ArrayCollection The objects.
  * @throws OrientDBException
  */
 public function findBy(array $criteria, array $orderBy = [], $limit = null, $offset = null, $fetchPlan = '*:0')
 {
     $parts[] = sprintf('SELECT FROM %s', $this->metadata->getOrientClass());
     if ($criteria) {
         $where = [];
         foreach ($criteria as $key => $value) {
             $value = json_encode($value);
             $where[] = "{$key} = {$value}";
         }
         $parts[] = sprintf('WHERE %s', implode(' AND ', $where));
     }
     if ($orderBy) {
         $orders = [];
         foreach ($orderBy as $key => $order) {
             $orders[] = "{$key} {$order}";
         }
         $parts[] = sprintf('ORDER BY %s', implode(', ', $orders));
     }
     if ($limit) {
         $parts[] = "LIMIT " . $limit;
     }
     $select = implode(' ', $parts);
     $collection = $this->dm->query($select, $fetchPlan);
     if (!$collection instanceof ArrayCollection) {
         throw new OrientDBException("Problems executing the query \"{$select}\". " . "The server returned {$collection} instead of ArrayCollection.");
     }
     return $collection;
 }
 /**
  * Prepares the array that is ready to be inserted to mongodb for a given object document.
  *
  * @param ClassMetadata $class
  * @param UnitOfWork    $uow
  * @param object        $document
  *
  * @return \stdClass $insertData
  * @throws ODMOrientDbException
  */
 public function prepareData(ClassMetadata $class, UnitOfWork $uow, $document)
 {
     $insertData = new \stdClass();
     if ($class->isEmbeddedDocument()) {
         $insertData->{'@type'} = 'd';
         $insertData->{'@class'} = $class->getOrientClass();
         $cs = $uow->getDocumentActualData($document);
     } else {
         $cs = $uow->getDocumentChangeSet($document);
         array_Walk($cs, function (&$val) {
             $val = $val[1];
         });
     }
     $mappings =& $class->fieldMappings;
     foreach ($cs as $name => $new) {
         $mapping = isset($mappings[$name]) ? $mappings[$name] : null;
         if ($mapping === null) {
             // don't store arbitrary values for now
             continue;
         }
         // Don't store null values unless nullable === true
         if ($new === null && $mapping['nullable'] === false) {
             continue;
         }
         $value = null;
         if ($new !== null) {
             switch (true) {
                 // @Property
                 case !isset($mapping['association']):
                     $value = Type::getType($mapping['type'])->convertToDatabaseValue($new);
                     break;
                 case $mapping['association'] & ClassMetadata::LINK:
                     $value = $this->getDocReference($new);
                     break;
                 case $mapping['association'] & ClassMetadata::LINK_MANY:
                     // initialize the link collection
                     if ($mapping['association'] & ClassMetadata::LINK_MAP) {
                         $value = new \stdClass();
                     } else {
                         $value = [];
                     }
                     break;
                 case $mapping['association'] & ClassMetadata::EMBED:
                     /** @var ClassMetadata $rmd */
                     $rmd = $this->metadataFactory->getMetadataFor(get_class($new));
                     $value = $this->prepareData($rmd, $uow, $new);
                     break;
                 case $mapping['association'] & ClassMetadata::EMBED_MANY:
                     $value = [];
                     if ($mapping['association'] & ClassMetadata::EMBED_MAP) {
                         foreach ($new as $k => $item) {
                             /** @var ClassMetadata $rmd */
                             $rmd = $this->metadataFactory->getMetadataFor(get_class($item));
                             $value[$k] = $this->prepareData($rmd, $uow, $item);
                         }
                     } else {
                         foreach ($new as $k => $item) {
                             /** @var ClassMetadata $rmd */
                             $rmd = $this->metadataFactory->getMetadataFor(get_class($item));
                             $value[] = $this->prepareData($rmd, $uow, $item);
                         }
                     }
                     break;
             }
         }
         $insertData->{$mapping['name']} = $value;
     }
     return $insertData;
 }