@@ -735,6 +735,75 @@ public function testUpsertDocumentsNoop(): void
735735 $ this ->assertEquals (0 , $ count );
736736 }
737737
738+ public function testUpsertDuplicateIds (): void
739+ {
740+ $ db = static ::getDatabase ();
741+ if (!$ db ->getAdapter ()->getSupportForUpserts ()) {
742+ $ this ->expectNotToPerformAssertions ();
743+ return ;
744+ }
745+
746+ $ db ->createCollection (__FUNCTION__ );
747+ $ db ->createAttribute (__FUNCTION__ , 'num ' , Database::VAR_INTEGER , 0 , true );
748+
749+ $ doc1 = new Document (['$id ' => 'dup ' , 'num ' => 1 ]);
750+ $ doc2 = new Document (['$id ' => 'dup ' , 'num ' => 2 ]);
751+
752+ try {
753+ $ db ->createOrUpdateDocuments (__FUNCTION__ , [$ doc1 , $ doc2 ]);
754+ $ this ->fail ('Failed to throw exception ' );
755+ } catch (\Throwable $ e ) {
756+ $ this ->assertInstanceOf (DuplicateException::class, $ e , $ e ->getMessage ());
757+ }
758+ }
759+
760+ public function testUpsertMixedPermissionDelta (): void
761+ {
762+ $ db = static ::getDatabase ();
763+ if (!$ db ->getAdapter ()->getSupportForUpserts ()) {
764+ $ this ->expectNotToPerformAssertions ();
765+ return ;
766+ }
767+
768+ $ db ->createCollection (__FUNCTION__ );
769+ $ db ->createAttribute (__FUNCTION__ , 'v ' , Database::VAR_INTEGER , 0 , true );
770+
771+ $ d1 = $ db ->createDocument (__FUNCTION__ , new Document ([
772+ '$id ' => 'a ' ,
773+ 'v ' => 0 ,
774+ '$permissions ' => [
775+ Permission::update (Role::any ())
776+ ]
777+ ]));
778+ $ d2 = $ db ->createDocument (__FUNCTION__ , new Document ([
779+ '$id ' => 'b ' ,
780+ 'v ' => 0 ,
781+ '$permissions ' => [
782+ Permission::update (Role::any ())
783+ ]
784+ ]));
785+
786+ // d1 adds write, d2 removes update
787+ $ d1 ->setAttribute ('$permissions ' , [
788+ Permission::read (Role::any ()),
789+ Permission::update (Role::any ())
790+ ]);
791+ $ d2 ->setAttribute ('$permissions ' , [
792+ Permission::read (Role::any ())
793+ ]);
794+
795+ $ db ->createOrUpdateDocuments (__FUNCTION__ , [$ d1 , $ d2 ]);
796+
797+ $ this ->assertEquals ([
798+ Permission::read (Role::any ()),
799+ Permission::update (Role::any ()),
800+ ], $ db ->getDocument (__FUNCTION__ , 'a ' )->getPermissions ());
801+
802+ $ this ->assertEquals ([
803+ Permission::read (Role::any ()),
804+ ], $ db ->getDocument (__FUNCTION__ , 'b ' )->getPermissions ());
805+ }
806+
738807 public function testRespectNulls (): Document
739808 {
740809 static ::getDatabase ()->createCollection ('documents_nulls ' );
@@ -3978,4 +4047,38 @@ public function testEmptyOperatorValues(): void
39784047 $ this ->assertEquals ('Invalid query: Contains queries require at least one value. ' , $ e ->getMessage ());
39794048 }
39804049 }
4050+
4051+ public function testCrossTenantDuplicateId (): void
4052+ {
4053+ $ db = static ::getDatabase ();
4054+ if (!$ db ->getAdapter ()->getSharedTables ()) {
4055+ $ this ->expectNotToPerformAssertions ();
4056+ return ;
4057+ }
4058+
4059+ $ db ->createCollection (__FUNCTION__ );
4060+ $ db ->createAttribute (__FUNCTION__ , 'v ' , Database::VAR_STRING , 64 , true );
4061+
4062+ // tenant A
4063+ $ db ->withTenant ('A ' , fn () => $ db ->createDocument (
4064+ __FUNCTION__ ,
4065+ new Document ([
4066+ '$id ' => 'x ' ,
4067+ 'v ' => 'A '
4068+ ])
4069+ ));
4070+ // tenant B
4071+ $ db ->withTenant ('B ' , fn () => $ db ->createDocument (
4072+ __FUNCTION__ ,
4073+ new Document ([
4074+ '$id ' => 'x ' ,
4075+ 'v ' => 'B '
4076+ ])
4077+ ));
4078+
4079+ $ this ->assertEquals ('A ' , $ db ->withTenant ('A ' , fn () =>
4080+ $ db ->getDocument (__FUNCTION__ , 'x ' )->getAttribute ('v ' )));
4081+ $ this ->assertEquals ('B ' , $ db ->withTenant ('B ' , fn () =>
4082+ $ db ->getDocument (__FUNCTION__ , 'x ' )->getAttribute ('v ' )));
4083+ }
39814084}
0 commit comments