Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 71 additions & 0 deletions tests/e2e/Adapter/Scopes/DocumentTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -4934,6 +4934,77 @@ public function testSum(): void
$this->assertEquals(round(39.50 + 25.99, 2), round($sum, 2));
}

public function testIntegersBeyondInt32(): void
{
/** @var Database $database */
$database = $this->getDatabase();

$database->createCollection(__FUNCTION__, attributes: [
new Document([
'$id' => 'amount',
'type' => Database::VAR_INTEGER,
'size' => 8,
'required' => true,
'signed' => true,
'array' => false,
'filters' => [],
]),
new Document([
'$id' => 'amounts',
'type' => Database::VAR_INTEGER,
'size' => 8,
'required' => true,
'signed' => true,
'array' => true,
'filters' => [],
]),
], permissions: [
Permission::read(Role::any()),
Permission::create(Role::any()),
], documentSecurity: false);

// Small values encode as int32, large ones as int64. Mongo hands the
// latter back wrapped, so both widths have to appear in one row.
$database->createDocument(__FUNCTION__, new Document([
'$id' => 'row1',
'amount' => 2000000000,
'amounts' => [-3408048000, -42, 3408048000, Database::MAX_BIG_INT],
]));
$database->createDocument(__FUNCTION__, new Document([
'$id' => 'row2',
'amount' => 2000000000,
'amounts' => [-42],
]));

foreach (['getDocument' => $database->getDocument(__FUNCTION__, 'row1'), 'find' => $database->find(__FUNCTION__, [Query::equal('$id', ['row1'])])[0]] as $path => $document) {
$this->assertIsInt($document->getAttribute('amount'), $path . ' returned a non-int scalar');

$amounts = $document->getAttribute('amounts');
foreach ($amounts as $index => $amount) {
$this->assertIsInt($amount, $path . ' returned a non-int at amounts[' . $index . ']');
}

$this->assertSame([-3408048000, -42, 3408048000, Database::MAX_BIG_INT], $amounts);

// An Int64 wrapper survives assertSame above but serialises as
// {"$numberLong":"..."}, which is what reaches an API client.
$this->assertSame(
'{"amount":2000000000,"amounts":[-3408048000,-42,3408048000,' . Database::MAX_BIG_INT . ']}',
\json_encode([
'amount' => $document->getAttribute('amount'),
'amounts' => $amounts,
]),
$path . ' did not serialise as plain JSON numbers'
);
}

// sum() declares float|int, so a total past int32 is a return type
// violation unless the adapter hands back a native integer.
$sum = $database->sum(__FUNCTION__, 'amount');
$this->assertIsInt($sum);
$this->assertSame(4000000000, $sum);
}

public function testEncodeDecode(): void
{
$collection = new Document([
Expand Down
45 changes: 45 additions & 0 deletions tests/e2e/Adapter/Scopes/ObjectAttributeTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -964,6 +964,51 @@ public function testObjectAttributeDefaults(): void
$database->deleteCollection($collectionId);
}

public function testObjectAttributeIntegersBeyondInt32(): void
{
/** @var Database $database */
$database = static::getDatabase();

if (!$database->getAdapter()->getSupportForObject()) {
$this->markTestSkipped('Adapter does not support object attributes');
}

$collectionId = ID::unique();
$database->createCollection($collectionId);
$this->createAttribute($database, $collectionId, 'meta', Database::VAR_OBJECT, 0, false);

// An object attribute has no per-key schema, so there is no typed cast
// to lean on: whatever the adapter decodes is what reaches the client.
$database->createDocument($collectionId, new Document([
'$id' => 'bigInts',
'$permissions' => [Permission::read(Role::any())],
'meta' => [
'small' => -42,
'count' => -3408048000,
'nested' => ['deep' => 3408048000],
],
]));

$database->purgeCachedDocument($collectionId, 'bigInts');
$meta = $database->getDocument($collectionId, 'bigInts')->getAttribute('meta');

$this->assertIsInt($meta['small']);
$this->assertIsInt($meta['count']);
$this->assertIsInt($meta['nested']['deep']);
$this->assertEquals([
'small' => -42,
'count' => -3408048000,
'nested' => ['deep' => 3408048000],
], $meta);

// A BSON wrapper serialises as {"$numberLong":"..."}, which is what
// would reach an API client. Key order is not asserted because jsonb
// does not preserve it.
$this->assertStringNotContainsString('$numberLong', json_encode($meta, JSON_THROW_ON_ERROR));

$database->deleteCollection($collectionId);
}

public function testObjectAttributeEmptyObject(): void
{
/** @var Database $database */
Expand Down
Loading