Skip to content

Commit

Permalink
Add lazy array and document models with codecs
Browse files Browse the repository at this point in the history
  • Loading branch information
alcaeus committed Apr 12, 2023
1 parent a436b81 commit 8e27a3c
Show file tree
Hide file tree
Showing 10 changed files with 1,261 additions and 1 deletion.
68 changes: 68 additions & 0 deletions src/Codec/LazyBSONArrayCodec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?php

namespace MongoDB\Codec;

use MongoDB\BSON\PackedArray;
use MongoDB\Exception\UnexpectedValueException;
use MongoDB\Model\LazyBSONArray;

use function array_values;
use function sprintf;

/**
* Codec for lazy decoding of BSON PackedArray instances
*
* @template-implements Codec<PackedArray, LazyBSONArray>
*/
class LazyBSONArrayCodec implements Codec, KnowsCodecLibrary
{
/** @var CodecLibrary|null */
private $library = null;

public function attachLibrary(CodecLibrary $library): void
{
$this->library = $library;
}

/** @inheritDoc */
public function canDecode($value): bool
{
return $value instanceof PackedArray;
}

/** @inheritDoc */
public function canEncode($value): bool
{
return $value instanceof LazyBSONArray;
}

/** @inheritDoc */
public function decode($value): LazyBSONArray
{
if (! $value instanceof PackedArray) {
throw new UnexpectedValueException(sprintf('"%s" can only decode from "%s" instances', self::class, PackedArray::class));
}

return new LazyBSONArray($value, $this->getLibrary());
}

/** @inheritDoc */
public function encode($value): PackedArray
{
if (! $value instanceof LazyBSONArray) {
throw new UnexpectedValueException(sprintf('"%s" can only encode "%s" instances', self::class, LazyBSONArray::class));
}

$return = [];
foreach ($value as $offset => $offsetValue) {
$return[$offset] = $this->getLibrary()->canEncode($offsetValue) ? $this->getLibrary()->encode($offsetValue) : $offsetValue;
}

return PackedArray::fromPHP(array_values($return));
}

private function getLibrary(): CodecLibrary
{
return $this->library ?? $this->library = new CodecLibrary(new LazyBSONDocumentCodec(), $this);
}
}
67 changes: 67 additions & 0 deletions src/Codec/LazyBSONDocumentCodec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace MongoDB\Codec;

use MongoDB\BSON\Document;
use MongoDB\Exception\UnexpectedValueException;
use MongoDB\Model\LazyBSONDocument;

use function sprintf;

/**
* Codec for lazy decoding of BSON Document instances
*
* @template-implements Codec<Document, LazyBSONDocument>
*/
class LazyBSONDocumentCodec implements Codec, KnowsCodecLibrary
{
/** @var CodecLibrary|null */
private $library = null;

public function attachLibrary(CodecLibrary $library): void
{
$this->library = $library;
}

/** @inheritDoc */
public function canDecode($value): bool
{
return $value instanceof Document;
}

/** @inheritDoc */
public function canEncode($value): bool
{
return $value instanceof LazyBSONDocument;
}

/** @inheritDoc */
public function decode($value): LazyBSONDocument
{
if (! $value instanceof Document) {
throw new UnexpectedValueException(sprintf('"%s" can only decode from "%s" instances', self::class, Document::class));
}

return new LazyBSONDocument($value, $this->getLibrary());
}

/** @inheritDoc */
public function encode($value): Document
{
if (! $value instanceof LazyBSONDocument) {
throw new UnexpectedValueException(sprintf('"%s" can only encode "%s" instances', self::class, LazyBSONDocument::class));
}

$return = [];
foreach ($value as $field => $fieldValue) {
$return[$field] = $this->getLibrary()->canEncode($fieldValue) ? $this->getLibrary()->encode($fieldValue) : $fieldValue;
}

return Document::fromPHP($return);
}

private function getLibrary(): CodecLibrary
{
return $this->library ?? $this->library = new CodecLibrary($this, new LazyBSONArrayCodec());
}
}
39 changes: 39 additions & 0 deletions src/Model/AsListIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace MongoDB\Model;

use IteratorIterator;
use Traversable;

/**
* @internal
* @template TKey as int
* @template TValue
* @template TIterator as Traversable<TKey, TValue>
*
* @template-extends IteratorIterator<TKey, TValue, TIterator>
*/
final class AsListIterator extends IteratorIterator
{
/** @var int */
private $index = 0;

public function rewind(): void
{
$this->index = 0;

parent::rewind();
}

public function key(): ?int
{
return $this->valid() ? $this->index : null;
}

public function next(): void
{
$this->index++;

parent::next();
}
}
2 changes: 1 addition & 1 deletion src/Model/CallbackIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public function __construct(Traversable $traversable, Closure $callback)
#[ReturnTypeWillChange]
public function current()
{
return ($this->callback)($this->iterator->current());
return ($this->callback)($this->iterator->current(), $this->iterator->key());
}

/**
Expand Down
Loading

0 comments on commit 8e27a3c

Please sign in to comment.