Skip to content

Commit

Permalink
Update JsonReader to use less memory (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
loicsapone authored Oct 17, 2023
1 parent 6425fba commit f89fc0d
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 7 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"symfony/console": "^6.1",
"symfony/filesystem": "^6.1",
"symfony/property-access": "^6.1",
"symfony/serializer": "^6.1"
"symfony/serializer": "^6.1",
"halaxa/json-machine": "^1.1"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.13",
Expand Down
32 changes: 28 additions & 4 deletions src/Reader/JsonReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,50 @@

namespace IQ2i\DataImporter\Reader;

use JsonMachine\Items;
use JsonMachine\JsonDecoder\ExtJsonDecoder;

class JsonReader implements ReaderInterface
{
/**
* @var string
*/
final public const POINTER = 'pointer';

private readonly \SplFileInfo $file;

private readonly \ArrayIterator $iterator;
private readonly \Iterator $iterator;

private int $index = 1;

private int $count = 0;

private array $defaultContext = [
self::POINTER => null,
];

public function __construct(
string $filePath,
private readonly ?string $dto = null,
array $defaultContext = [],
) {
$this->file = new \SplFileInfo($filePath);

if (!$this->file->isReadable()) {
throw new \InvalidArgumentException('The file '.$this->file->getFilename().' is not readable.');
}

$array = \json_decode(\file_get_contents($this->file->getRealPath()), true, 512, \JSON_THROW_ON_ERROR);
$this->iterator = new \ArrayIterator($array);
$this->defaultContext = \array_merge($this->defaultContext, $defaultContext);
$options = [
'decoder' => new ExtJsonDecoder(true),
];

if (null !== $this->defaultContext[self::POINTER]) {
$options['pointer'] = $this->defaultContext[self::POINTER];
}

$this->count = \iterator_count(Items::fromFile($this->file->getRealPath(), $options));
$this->iterator = Items::fromFile($this->file->getRealPath(), $options)->getIterator();

$this->rewind();
}
Expand Down Expand Up @@ -89,6 +113,6 @@ public function rewind(): void

public function count(): int
{
return $this->iterator->count();
return $this->count;
}
}
61 changes: 59 additions & 2 deletions tests/Reader/JsonReaderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function testReadJson()
{
// init reader
$reader = new JsonReader(
__DIR__.'/../fixtures/json/books.json',
__DIR__.'/../fixtures/json/books_without_pointer.json',
null,
);

Expand All @@ -31,7 +31,7 @@ public function testReadJson()

// test file
$this->assertEquals(
new \SplFileInfo(__DIR__.'/../fixtures/json/books.json'),
new \SplFileInfo(__DIR__.'/../fixtures/json/books_without_pointer.json'),
$reader->getFile()
);

Expand Down Expand Up @@ -79,4 +79,61 @@ public function testReadJson()
$reader->next();
$this->assertEquals([], $reader->current());
}

public function testReadJsonWithPointer()
{
// init reader
$reader = new JsonReader(
__DIR__.'/../fixtures/json/books_with_pointer.json',
null,
[JsonReader::POINTER => '/author/books']
);

// test denormalization
$this->assertFalse($reader->isDenormalizable());

// test file
$this->assertEquals(
new \SplFileInfo(__DIR__.'/../fixtures/json/books_with_pointer.json'),
$reader->getFile()
);

// test count
$this->assertCount(2, $reader);

// test index
$this->assertEquals(1, $reader->index());
$this->assertEquals(0, $reader->key());

// test headers
$this->assertEquals(
['title', 'genre', 'price', 'description'],
\array_keys($reader->current())
);
$this->assertArrayHasKey('title', $reader->current());
$this->assertNotNull($reader->current()['title']);
$this->assertArrayHasKey('genre', $reader->current());
$this->assertNotNull($reader->current()['genre']);
$this->assertArrayHasKey('price', $reader->current());
$this->assertNotNull($reader->current()['price']);
$this->assertArrayHasKey('description', $reader->current());
$this->assertNotNull($reader->current()['description']);

// test line
$reader->next();
$this->assertEquals(2, $reader->index());
$this->assertEquals(
[
'title' => 'Midnight Rain',
'genre' => 'Fantasy',
'price' => '5.95',
'description' => 'A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world.',
],
$reader->current()
);

// test and of file
$reader->next();
$this->assertEquals([], $reader->current());
}
}
20 changes: 20 additions & 0 deletions tests/fixtures/json/books_with_pointer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"author": {
"firstname": "Kim",
"lastname": "Ralls",
"books": [
{
"title": "XML Developer's Guide",
"genre": "Computer",
"price": 44.95,
"description": "An in-depth look at creating applications with XML."
},
{
"title": "Midnight Rain",
"genre": "Fantasy",
"price": 5.95,
"description": "A former architect battles corporate zombies, an evil sorceress, and her own childhood to become queen of the world."
}
]
}
}
File renamed without changes.

0 comments on commit f89fc0d

Please sign in to comment.