Skip to content

Commit 8a1a739

Browse files
committed
Merge branch 'main' of github.com:utopia-php/database into document-nulls
2 parents 0d398a2 + d52f74b commit 8a1a739

8 files changed

Lines changed: 995 additions & 134 deletions

File tree

src/Database/Database.php

Lines changed: 135 additions & 131 deletions
Large diffs are not rendered by default.

src/Database/Mirror.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -713,6 +713,7 @@ public function updateDocuments(
713713
array $queries = [],
714714
int $batchSize = self::INSERT_BATCH_SIZE,
715715
?callable $onNext = null,
716+
?callable $onError = null,
716717
): int {
717718
$modified = 0;
718719

@@ -724,7 +725,8 @@ public function updateDocuments(
724725
function ($doc) use ($onNext, &$modified) {
725726
$onNext && $onNext($doc);
726727
$modified++;
727-
}
728+
},
729+
$onError
728730
);
729731

730732
if (
@@ -827,6 +829,7 @@ public function deleteDocuments(
827829
array $queries = [],
828830
int $batchSize = self::DELETE_BATCH_SIZE,
829831
?callable $onNext = null,
832+
?callable $onError = null,
830833
): int {
831834
$modified = 0;
832835

@@ -838,6 +841,7 @@ function ($doc) use (&$modified, $onNext) {
838841
$onNext && $onNext($doc);
839842
$modified++;
840843
},
844+
$onError
841845
);
842846

843847
if (

tests/e2e/Adapter/Scopes/DocumentTests.php

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3427,6 +3427,7 @@ public function testUpdateDocument(Document $document): Document
34273427
return $document;
34283428
}
34293429

3430+
34303431
/**
34313432
* @depends testUpdateDocument
34323433
*/
@@ -3691,6 +3692,102 @@ public function testUpdateDocuments(): void
36913692
Authorization::cleanRoles();
36923693
Authorization::setRole(Role::any()->toString());
36933694
}
3695+
3696+
public function testUpdateDocumentsWithCallbackSupport(): void
3697+
{
3698+
/** @var Database $database */
3699+
$database = static::getDatabase();
3700+
3701+
if (!$database->getAdapter()->getSupportForBatchOperations()) {
3702+
$this->expectNotToPerformAssertions();
3703+
return;
3704+
}
3705+
3706+
$collection = 'update_callback';
3707+
Authorization::cleanRoles();
3708+
Authorization::setRole(Role::any()->toString());
3709+
3710+
$database->createCollection($collection, attributes: [
3711+
new Document([
3712+
'$id' => ID::custom('string'),
3713+
'type' => Database::VAR_STRING,
3714+
'format' => '',
3715+
'size' => 100,
3716+
'signed' => true,
3717+
'required' => false,
3718+
'default' => null,
3719+
'array' => false,
3720+
'filters' => [],
3721+
]),
3722+
new Document([
3723+
'$id' => ID::custom('integer'),
3724+
'type' => Database::VAR_INTEGER,
3725+
'format' => '',
3726+
'size' => 10000,
3727+
'signed' => true,
3728+
'required' => false,
3729+
'default' => null,
3730+
'array' => false,
3731+
'filters' => [],
3732+
]),
3733+
], permissions: [
3734+
Permission::read(Role::any()),
3735+
Permission::create(Role::any()),
3736+
Permission::update(Role::any()),
3737+
Permission::delete(Role::any())
3738+
], documentSecurity: false);
3739+
3740+
for ($i = 0; $i < 10; $i++) {
3741+
$database->createDocument($collection, new Document([
3742+
'$id' => 'doc' . $i,
3743+
'string' => 'text📝 ' . $i,
3744+
'integer' => $i
3745+
]));
3746+
}
3747+
// Test onNext is throwing the error without the onError
3748+
// a non existent document to test the error thrown
3749+
try {
3750+
$results = [];
3751+
$count = $database->updateDocuments($collection, new Document([
3752+
'string' => 'text📝 updated',
3753+
]), [
3754+
Query::greaterThanEqual('integer', 100),
3755+
], onNext: function ($doc) use (&$results) {
3756+
$results[] = $doc;
3757+
throw new Exception("Error thrown to test that update doesn't stop and error is caught");
3758+
});
3759+
} catch (Exception $e) {
3760+
$this->assertInstanceOf(Exception::class, $e);
3761+
$this->assertEquals("Error thrown to test that update doesn't stop and error is caught", $e->getMessage());
3762+
}
3763+
3764+
// Test Update half of the documents
3765+
$results = [];
3766+
$count = $database->updateDocuments($collection, new Document([
3767+
'string' => 'text📝 updated',
3768+
]), [
3769+
Query::greaterThanEqual('integer', 5),
3770+
], onNext: function ($doc) use (&$results) {
3771+
$results[] = $doc;
3772+
throw new Exception("Error thrown to test that update doesn't stop and error is caught");
3773+
}, onError:function ($e) {
3774+
$this->assertInstanceOf(Exception::class, $e);
3775+
$this->assertEquals("Error thrown to test that update doesn't stop and error is caught", $e->getMessage());
3776+
});
3777+
3778+
$this->assertEquals(5, $count);
3779+
3780+
foreach ($results as $document) {
3781+
$this->assertEquals('text📝 updated', $document->getAttribute('string'));
3782+
}
3783+
3784+
$updatedDocuments = $database->find($collection, [
3785+
Query::greaterThanEqual('integer', 5),
3786+
]);
3787+
3788+
$this->assertCount(5, $updatedDocuments);
3789+
}
3790+
36943791
/**
36953792
* @depends testCreateDocument
36963793
*/
@@ -4117,6 +4214,130 @@ public function testDeleteBulkDocumentsQueries(): void
41174214
$database->deleteCollection('bulk_delete_queries');
41184215
}
41194216

4217+
public function testDeleteBulkDocumentsWithCallbackSupport(): void
4218+
{
4219+
/** @var Database $database */
4220+
$database = static::getDatabase();
4221+
4222+
if (!$database->getAdapter()->getSupportForBatchOperations()) {
4223+
$this->expectNotToPerformAssertions();
4224+
return;
4225+
}
4226+
4227+
$database->createCollection(
4228+
'bulk_delete_with_callback',
4229+
attributes: [
4230+
new Document([
4231+
'$id' => 'text',
4232+
'type' => Database::VAR_STRING,
4233+
'size' => 100,
4234+
'required' => true,
4235+
]),
4236+
new Document([
4237+
'$id' => 'integer',
4238+
'type' => Database::VAR_INTEGER,
4239+
'size' => 10,
4240+
'required' => true,
4241+
])
4242+
],
4243+
permissions: [
4244+
Permission::create(Role::any()),
4245+
Permission::read(Role::any()),
4246+
Permission::delete(Role::any())
4247+
],
4248+
documentSecurity: false
4249+
);
4250+
4251+
$this->propagateBulkDocuments('bulk_delete_with_callback');
4252+
4253+
$docs = $database->find('bulk_delete_with_callback');
4254+
$this->assertCount(10, $docs);
4255+
4256+
/**
4257+
* Test Short select query, test pagination as well, Add order to select
4258+
*/
4259+
$selects = ['$sequence', '$id', '$collection', '$permissions', '$updatedAt'];
4260+
4261+
try {
4262+
// a non existent document to test the error thrown
4263+
$database->deleteDocuments(
4264+
collection: 'bulk_delete_with_callback',
4265+
queries: [
4266+
Query::select([...$selects, '$createdAt']),
4267+
Query::lessThan('$createdAt', '1800-01-01'),
4268+
Query::orderAsc('$createdAt'),
4269+
Query::orderAsc(),
4270+
Query::limit(1),
4271+
],
4272+
batchSize: 1,
4273+
onNext: function () {
4274+
throw new Exception("Error thrown to test that deletion doesn't stop and error is caught");
4275+
}
4276+
);
4277+
} catch (Exception $e) {
4278+
$this->assertInstanceOf(Exception::class, $e);
4279+
$this->assertEquals("Error thrown to test that deletion doesn't stop and error is caught", $e->getMessage());
4280+
}
4281+
4282+
$docs = $database->find('bulk_delete_with_callback');
4283+
$this->assertCount(10, $docs);
4284+
4285+
$count = $database->deleteDocuments(
4286+
collection: 'bulk_delete_with_callback',
4287+
queries: [
4288+
Query::select([...$selects, '$createdAt']),
4289+
Query::cursorAfter($docs[6]),
4290+
Query::greaterThan('$createdAt', '2000-01-01'),
4291+
Query::orderAsc('$createdAt'),
4292+
Query::orderAsc(),
4293+
Query::limit(2),
4294+
],
4295+
batchSize: 1,
4296+
onNext: function () {
4297+
// simulating error throwing but should not stop deletion
4298+
throw new Exception("Error thrown to test that deletion doesn't stop and error is caught");
4299+
},
4300+
onError:function ($e) {
4301+
$this->assertInstanceOf(Exception::class, $e);
4302+
$this->assertEquals("Error thrown to test that deletion doesn't stop and error is caught", $e->getMessage());
4303+
}
4304+
);
4305+
4306+
$this->assertEquals(2, $count);
4307+
4308+
// TEST: Bulk Delete All Documents without passing callbacks
4309+
$this->assertEquals(8, $database->deleteDocuments('bulk_delete_with_callback'));
4310+
4311+
$docs = $database->find('bulk_delete_with_callback');
4312+
$this->assertCount(0, $docs);
4313+
4314+
// TEST: Bulk delete documents with queries with callbacks
4315+
$this->propagateBulkDocuments('bulk_delete_with_callback');
4316+
4317+
$results = [];
4318+
$count = $database->deleteDocuments('bulk_delete_with_callback', [
4319+
Query::greaterThanEqual('integer', 5)
4320+
], onNext: function ($doc) use (&$results) {
4321+
$results[] = $doc;
4322+
throw new Exception("Error thrown to test that deletion doesn't stop and error is caught");
4323+
}, onError:function ($e) {
4324+
$this->assertInstanceOf(Exception::class, $e);
4325+
$this->assertEquals("Error thrown to test that deletion doesn't stop and error is caught", $e->getMessage());
4326+
});
4327+
4328+
$this->assertEquals(5, $count);
4329+
4330+
foreach ($results as $document) {
4331+
$this->assertGreaterThanOrEqual(5, $document->getAttribute('integer'));
4332+
}
4333+
4334+
$docs = $database->find('bulk_delete_with_callback');
4335+
$this->assertEquals(5, \count($docs));
4336+
4337+
// Teardown
4338+
$database->deleteCollection('bulk_delete_with_callback');
4339+
}
4340+
41204341
public function testUpdateDocumentsQueries(): void
41214342
{
41224343
/** @var Database $database */

tests/e2e/Adapter/Scopes/RelationshipTests.php

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -931,14 +931,17 @@ public function testSelectRelationshipAttributes(): void
931931
$database->createCollection('model');
932932

933933
$database->createAttribute('make', 'name', Database::VAR_STRING, 255, true);
934+
$database->createAttribute('make', 'origin', Database::VAR_STRING, 255, true);
934935
$database->createAttribute('model', 'name', Database::VAR_STRING, 255, true);
935936
$database->createAttribute('model', 'year', Database::VAR_INTEGER, 0, true);
936937

937938
$database->createRelationship(
938939
collection: 'make',
939940
relatedCollection: 'model',
940941
type: Database::RELATION_ONE_TO_MANY,
941-
id: 'models'
942+
twoWay: true,
943+
id: 'models',
944+
twoWayKey: 'make',
942945
);
943946

944947
$database->createDocument('make', new Document([
@@ -947,6 +950,7 @@ public function testSelectRelationshipAttributes(): void
947950
Permission::read(Role::any()),
948951
],
949952
'name' => 'Ford',
953+
'origin' => 'USA',
950954
'models' => [
951955
[
952956
'$id' => 'fiesta',
@@ -1143,9 +1147,68 @@ public function testSelectRelationshipAttributes(): void
11431147
if ($make->isEmpty()) {
11441148
throw new Exception('Make not found');
11451149
}
1146-
11471150
$this->assertEquals('Ford', $make['name']);
11481151
$this->assertArrayNotHasKey('models', $make);
1152+
1153+
// Select some parent attributes, all child attributes
1154+
$make = $database->findOne('make', [
1155+
Query::select(['name', 'models.*']),
1156+
]);
1157+
1158+
$this->assertEquals('Ford', $make['name']);
1159+
$this->assertEquals(2, \count($make['models']));
1160+
1161+
/*
1162+
* FROM CHILD TO PARENT
1163+
*/
1164+
1165+
// Select some parent attributes, some child attributes
1166+
$model = $database->findOne('model', [
1167+
Query::select(['name', 'make.name']),
1168+
]);
1169+
1170+
$this->assertEquals('Fiesta', $model['name']);
1171+
$this->assertEquals('Ford', $model['make']['name']);
1172+
$this->assertArrayNotHasKey('origin', $model['make']);
1173+
$this->assertArrayNotHasKey('year', $model);
1174+
$this->assertArrayHasKey('name', $model);
1175+
1176+
// Select all parent attributes, some child attributes
1177+
$model = $database->findOne('model', [
1178+
Query::select(['*', 'make.name']),
1179+
]);
1180+
1181+
$this->assertEquals('Fiesta', $model['name']);
1182+
$this->assertEquals('Ford', $model['make']['name']);
1183+
$this->assertArrayHasKey('year', $model);
1184+
1185+
// Select all parent attributes, all child attributes
1186+
$model = $database->findOne('model', [
1187+
Query::select(['*', 'make.*']),
1188+
]);
1189+
1190+
$this->assertEquals('Fiesta', $model['name']);
1191+
$this->assertEquals('Ford', $model['make']['name']);
1192+
$this->assertArrayHasKey('year', $model);
1193+
$this->assertArrayHasKey('name', $model['make']);
1194+
1195+
// Select all parent attributes, no child attributes
1196+
$model = $database->findOne('model', [
1197+
Query::select(['*']),
1198+
]);
1199+
1200+
$this->assertEquals('Fiesta', $model['name']);
1201+
$this->assertArrayHasKey('make', $model);
1202+
$this->assertArrayHasKey('year', $model);
1203+
1204+
// Select some parent attributes, all child attributes
1205+
$model = $database->findOne('model', [
1206+
Query::select(['name', 'make.*']),
1207+
]);
1208+
1209+
$this->assertEquals('Fiesta', $model['name']);
1210+
$this->assertEquals('Ford', $model['make']['name']);
1211+
$this->assertEquals('USA', $model['make']['origin']);
11491212
}
11501213

11511214
public function testInheritRelationshipPermissions(): void

0 commit comments

Comments
 (0)