Skip to content

Commit

Permalink
REST: Extract getStatementSubject to a new helper class
Browse files Browse the repository at this point in the history
* As the function is now needed in multiple places, I thought
having it in a seperate class would be a good idea.

Change-Id: I7677486e57b68e5c186e530c5e723272e79ed92e
  • Loading branch information
MuhammadJaziraly authored and outdooracorn committed Aug 8, 2023
1 parent 910c646 commit 33b354d
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@

namespace Wikibase\Repo\RestApi\Infrastructure\DataAccess;

use Wikibase\DataModel\Entity\EntityId;
use Wikibase\DataModel\Entity\StatementListProvidingEntity;
use Wikibase\DataModel\Statement\StatementGuid;
use Wikibase\Lib\Store\EntityRevisionLookup;
use Wikibase\Lib\Store\RevisionedUnresolvedRedirectException;
use Wikibase\Repo\RestApi\Domain\ReadModel\Statement;
use Wikibase\Repo\RestApi\Domain\Services\StatementReadModelConverter;
use Wikibase\Repo\RestApi\Domain\Services\StatementRetriever;
Expand All @@ -16,20 +12,20 @@
*/
class EntityRevisionLookupStatementRetriever implements StatementRetriever {

private EntityRevisionLookup $entityRevisionLookup;
private StatementSubjectRetriever $statementSubjectRetriever;
private StatementReadModelConverter $statementReadModelConverter;

public function __construct(
EntityRevisionLookup $entityRevisionLookup,
StatementSubjectRetriever $statementSubjectRetriever,
StatementReadModelConverter $statementReadModelConverter
) {
$this->entityRevisionLookup = $entityRevisionLookup;
$this->statementSubjectRetriever = $statementSubjectRetriever;
$this->statementReadModelConverter = $statementReadModelConverter;
}

public function getStatement( StatementGuid $statementId ): ?Statement {
$subjectId = $statementId->getEntityId();
$subject = $this->getStatementSubject( $subjectId );
$subject = $this->statementSubjectRetriever->getStatementSubject( $subjectId );

if ( $subject === null ) {
return null;
Expand All @@ -39,23 +35,4 @@ public function getStatement( StatementGuid $statementId ): ?Statement {
return $statement ? $this->statementReadModelConverter->convert( $statement ) : null;
}

private function getStatementSubject( EntityId $subjectId ): ?StatementListProvidingEntity {
try {
$entityRevision = $this->entityRevisionLookup->getEntityRevision( $subjectId );
} catch ( RevisionedUnresolvedRedirectException $e ) {
return null;
}

if ( !$entityRevision ) {
return null;
}

$subject = $entityRevision->getEntity();
if ( !$subject instanceof StatementListProvidingEntity ) {
return null;
}

return $subject;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php declare( strict_types=1 );

namespace Wikibase\Repo\RestApi\Infrastructure\DataAccess;

use LogicException;
use Wikibase\DataModel\Entity\EntityId;
use Wikibase\DataModel\Entity\StatementListProvidingEntity;
use Wikibase\Lib\Store\EntityRevisionLookup;
use Wikibase\Lib\Store\RevisionedUnresolvedRedirectException;

/**
* @license GPL-2.0-or-later
*/
class StatementSubjectRetriever {

private EntityRevisionLookup $entityRevisionLookup;

public function __construct( EntityRevisionLookup $entityRevisionLookup ) {
$this->entityRevisionLookup = $entityRevisionLookup;
}

public function getStatementSubject( EntityId $subjectId ): ?StatementListProvidingEntity {
try {
$entityRevision = $this->entityRevisionLookup->getEntityRevision( $subjectId );
} catch ( RevisionedUnresolvedRedirectException $e ) {
return null;
}

if ( !$entityRevision ) {
return null;
}

$subject = $entityRevision->getEntity();
if ( !$subject instanceof StatementListProvidingEntity ) {
throw new LogicException( 'Entity is not a ' . StatementListProvidingEntity::class );
}

return $subject;
}

}
3 changes: 2 additions & 1 deletion repo/rest-api/src/WbRestApi.ServiceWiring.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
use Wikibase\Repo\RestApi\Infrastructure\DataAccess\EntityRevisionLookupStatementRetriever;
use Wikibase\Repo\RestApi\Infrastructure\DataAccess\MediaWikiEditEntityFactoryItemUpdater;
use Wikibase\Repo\RestApi\Infrastructure\DataAccess\PrefetchingTermLookupAliasesRetriever;
use Wikibase\Repo\RestApi\Infrastructure\DataAccess\StatementSubjectRetriever;
use Wikibase\Repo\RestApi\Infrastructure\DataAccess\TermLookupItemDataRetriever;
use Wikibase\Repo\RestApi\Infrastructure\DataAccess\WikibaseEntityPermissionChecker;
use Wikibase\Repo\RestApi\Infrastructure\DataAccess\WikibaseEntityRevisionLookupItemRevisionMetadataRetriever;
Expand Down Expand Up @@ -473,7 +474,7 @@

'WbRestApi.StatementRetriever' => function( MediaWikiServices $services ): EntityRevisionLookupStatementRetriever {
return new EntityRevisionLookupStatementRetriever(
WikibaseRepo::getEntityRevisionLookup( $services ),
new StatementSubjectRetriever( WikibaseRepo::getEntityRevisionLookup( $services ) ),
new StatementReadModelConverter(
WikibaseRepo::getStatementGuidParser( $services ),
WikibaseRepo::getPropertyDataTypeLookup()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,16 @@
use Wikibase\DataModel\Entity\NumericPropertyId;
use Wikibase\DataModel\Entity\Property;
use Wikibase\DataModel\Entity\StatementListProvidingEntity as StatementSubject;
use Wikibase\DataModel\Fixtures\CustomEntityId;
use Wikibase\DataModel\Services\Fixtures\FakeEntityDocument;
use Wikibase\DataModel\Statement\StatementGuid;
use Wikibase\DataModel\Statement\StatementList;
use Wikibase\DataModel\Term\Fingerprint;
use Wikibase\DataModel\Tests\NewItem;
use Wikibase\DataModel\Tests\NewStatement;
use Wikibase\Lib\Store\EntityRevision;
use Wikibase\Lib\Store\EntityRevisionLookup;
use Wikibase\Lib\Store\RevisionedUnresolvedRedirectException;
use Wikibase\Repo\RestApi\Domain\ReadModel\Statement;
use Wikibase\Repo\RestApi\Infrastructure\DataAccess\EntityRevisionLookupStatementRetriever;
use Wikibase\Repo\RestApi\Infrastructure\DataAccess\StatementSubjectRetriever;

/**
* @covers \Wikibase\Repo\RestApi\Infrastructure\DataAccess\EntityRevisionLookupStatementRetriever
Expand Down Expand Up @@ -93,14 +91,6 @@ public function provideSubjectId(): Generator {
yield 'Property ID' => [ new NumericPropertyId( 'P123' ) ];
}

public function testGivenItemRedirected_getStatementReturnsNull(): void {
$itemId = new ItemId( 'Q321' );
$statementId = new StatementGuid( $itemId, 'c48c32c3-42b5-498f-9586-84608b88747c' );
$this->entityRevisionLookup = $this->newLookupForIdWithRedirect( $itemId );

$this->assertNull( $this->newRetriever()->getStatement( $statementId ) );
}

/**
* @dataProvider provideStatementSubjectWithoutStatement
*/
Expand All @@ -121,15 +111,6 @@ public function provideStatementSubjectWithoutStatement(): Generator {
];
}

public function testGivenEntityIsNotStatementSubject_getStatementReturnsNull(): void {
$subjectId = new CustomEntityId( 'A123' );
$subject = new FakeEntityDocument( $subjectId );
$statementId = new StatementGuid( $subjectId, '69460e7f-4c45-d417-9420-9431a47969a8' );
$this->entityRevisionLookup = $this->newLookupForIdWithReturnValue( $subjectId, $subject );

$this->assertNull( $this->newRetriever()->getStatement( $statementId ) );
}

private function newLookupForIdWithReturnValue( EntityId $id, ?EntityDocument $returnValue ): EntityRevisionLookup {
$entityRevisionLookup = $this->createMock( EntityRevisionLookup::class );
$entityRevisionLookup->expects( $this->once() )
Expand All @@ -140,19 +121,9 @@ private function newLookupForIdWithReturnValue( EntityId $id, ?EntityDocument $r
return $entityRevisionLookup;
}

private function newLookupForIdWithRedirect( EntityId $id ): EntityRevisionLookup {
$entityRevisionLookup = $this->createMock( EntityRevisionLookup::class );
$entityRevisionLookup->expects( $this->once() )
->method( 'getEntityRevision' )
->with( $id )
->willThrowException( $this->createStub( RevisionedUnresolvedRedirectException::class ) );

return $entityRevisionLookup;
}

private function newRetriever(): EntityRevisionLookupStatementRetriever {
return new EntityRevisionLookupStatementRetriever(
$this->entityRevisionLookup,
new StatementSubjectRetriever( $this->entityRevisionLookup ),
$this->newStatementReadModelConverter()
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?php declare( strict_types=1 );

namespace Wikibase\Repo\Tests\RestApi\Infrastructure\DataAccess;

use Generator;
use LogicException;
use PHPUnit\Framework\TestCase;
use Wikibase\DataModel\Entity\EntityDocument;
use Wikibase\DataModel\Entity\EntityId;
use Wikibase\DataModel\Entity\ItemId;
use Wikibase\DataModel\Entity\NumericPropertyId;
use Wikibase\DataModel\Entity\Property;
use Wikibase\DataModel\Entity\StatementListProvidingEntity;
use Wikibase\DataModel\Fixtures\CustomEntityId;
use Wikibase\DataModel\Services\Fixtures\FakeEntityDocument;
use Wikibase\DataModel\Statement\StatementGuid;
use Wikibase\DataModel\Statement\StatementList;
use Wikibase\DataModel\Term\Fingerprint;
use Wikibase\DataModel\Tests\NewItem;
use Wikibase\DataModel\Tests\NewStatement;
use Wikibase\Lib\Store\EntityRevision;
use Wikibase\Lib\Store\EntityRevisionLookup;
use Wikibase\Lib\Store\RevisionedUnresolvedRedirectException;
use Wikibase\Repo\RestApi\Infrastructure\DataAccess\StatementSubjectRetriever;

/**
* @covers \Wikibase\Repo\RestApi\Infrastructure\DataAccess\StatementSubjectRetriever
*
* @group Wikibase
*
* @license GPL-2.0-or-later
*/
class StatementSubjectRetrieverTest extends TestCase {

private EntityRevisionLookup $entityRevisionLookup;

protected function setUp(): void {
parent::setUp();

$this->entityRevisionLookup = $this->createStub( EntityRevisionLookup::class );
}

/**
* @dataProvider provideSubjectAndSubjectId
*/
public function testGetStatementSubject( EntityId $subjectId, EntityDocument $expectedSubject ): void {
$this->entityRevisionLookup = $this->newLookupForIdWithReturnValue( $subjectId, $expectedSubject );
$subject = $this->newStatementSubjectRetriever()->getStatementSubject( $subjectId );

$this->assertEquals( $expectedSubject, $subject );
}

/**
* @dataProvider provideSubjectId
*/
public function testGivenSubjectDoesNotExist_getStatementSubjectReturnsNull( EntityId $subjectId ): void {
$this->entityRevisionLookup = $this->newLookupForIdWithReturnValue( $subjectId, null );

$this->assertNull( $this->newStatementSubjectRetriever()->getStatementSubject( $subjectId ) );
}

public function testGivenEntityIsNotStatementSubject_getStatementSubjectThrows(): void {
$subjectId = new CustomEntityId( 'A123' );
$subject = new FakeEntityDocument( $subjectId );
$this->entityRevisionLookup = $this->newLookupForIdWithReturnValue( $subjectId, $subject );

try {
$this->newStatementSubjectRetriever()->getStatementSubject( $subjectId );
$this->fail( 'Expected exception not thrown' );
} catch ( LogicException $e ) {
$this->assertEquals( 'Entity is not a ' . StatementListProvidingEntity::class, $e->getMessage() );
}
}

public function testGivenItemRedirected_getStatementSubjectReturnsNull(): void {
$itemId = new ItemId( 'Q321' );
$this->entityRevisionLookup = $this->newLookupForIdWithRedirect( $itemId );

$this->assertNull( $this->newStatementSubjectRetriever()->getStatementSubject( $itemId ) );
}

public function provideSubjectAndSubjectId(): Generator {
$itemId = new ItemId( 'Q123' );
$statementId = new StatementGuid( $itemId, 'c48c32c3-42b5-498f-9586-84608b88747c' );
$statement = NewStatement::forProperty( 'P123' )
->withValue( 'potato' )
->withGuid( $statementId )
->build();

yield 'Item' => [ $itemId, NewItem::withId( $itemId )->andStatement( $statement )->build() ];

$propertyId = new NumericPropertyId( 'P567' );
$statementId = new StatementGuid( $propertyId, 'c48c32c3-42b5-498f-9586-84608b88747c' );
$statement = NewStatement::forProperty( 'P123' )
->withValue( 'potato' )
->withGuid( $statementId )
->build();

yield 'Property' => [
$propertyId,
new Property( $propertyId, new Fingerprint(), 'string', new StatementList( $statement ) ),
];
}

public function provideSubjectId(): Generator {
yield 'Item ID' => [ new ItemId( 'Q123' ) ];
yield 'Property ID' => [ new NumericPropertyId( 'P123' ) ];
}

private function newLookupForIdWithRedirect( EntityId $id ): EntityRevisionLookup {
$entityRevisionLookup = $this->createMock( EntityRevisionLookup::class );
$entityRevisionLookup->expects( $this->once() )
->method( 'getEntityRevision' )
->with( $id )
->willThrowException( $this->createStub( RevisionedUnresolvedRedirectException::class ) );

return $entityRevisionLookup;
}

private function newLookupForIdWithReturnValue( EntityId $id, ?EntityDocument $returnValue ): EntityRevisionLookup {
$entityRevisionLookup = $this->createMock( EntityRevisionLookup::class );
$entityRevisionLookup->expects( $this->once() )
->method( 'getEntityRevision' )
->with( $id )
->willReturn( $returnValue ? new EntityRevision( $returnValue ) : null );

return $entityRevisionLookup;
}

private function newStatementSubjectRetriever(): StatementSubjectRetriever {
return new StatementSubjectRetriever( $this->entityRevisionLookup );
}

}

0 comments on commit 33b354d

Please sign in to comment.