Page MenuHomePhabricator

wbsetclaim and wbsetreference return unnormalized data
Closed, ResolvedPublic

Description

When data value normalization is enabled, most API modules that edit data values return the normalized version (what was actually saved), but wbsetclaim and wbsetreference don’t.


Original report:

With data value normalization enabled (T251480, currently on Test Wikidata), if you save a commonsMedia value with underscores (e.g. Douglas_adams_portrait_cropped.jpg), it will be saved with spaces (normalized), but if start to edit the statement again without reloading the page, you’ll still see the unnormalized version (with underscores). The UI should use the normalized value returned by the API.

Event Timeline

Hm, the issue is that the API actually returns the unnormalized datavalue (at least for wbsetclaim), not the value as it was saved.

Yup, if the API returns the normalized value, the JS already updates everything properly:

diff --git a/repo/includes/Api/SetClaim.php b/repo/includes/Api/SetClaim.php
index 2621fe33da..af8b984ff5 100644
--- a/repo/includes/Api/SetClaim.php
+++ b/repo/includes/Api/SetClaim.php
@@ -30,6 +30,7 @@
 use Wikibase\Repo\Diff\ClaimDiffer;
 use Wikibase\Repo\FederatedProperties\FederatedPropertiesException;
 use Wikibase\Repo\SnakFactory;
+use Wikimedia\TestingAccessWrapper;
 
 /**
  * API module for creating or updating an entire Claim.
@@ -203,6 +204,7 @@ private function executeInternal(): void {
 
 		$index = $params['index'] ?? null;
 		$changeop = $this->statementChangeOpFactory->newSetStatementOp( $statement, $index );
+		$statement = TestingAccessWrapper::newFromObject( $changeop )->statement;
 		$this->modificationHelper->applyChangeOp( $changeop, $entity, $summary );
 
 		$status = $this->entitySavingHelper->attemptSaveEntity( $entity, $summary, $params, $this->getContext() );

But obviously we need a better fix for this than rudely reaching into the change op’s private fields.

Okay, but most API modules already return the normalized value:

  • wbcreateclaim returns normalized value
  • wbeditentity returns normalized value
  • wbsetclaim returns unnormalized value
  • wbsetclaimvalue returns normalized value
  • wbsetqualifier returns normalized value
  • wbsetreference returns unnormalized value

So we just need to see how we can make wbsetclaim and wbsetreference behave the same way.

Okay, for wbsetclaim it’s actually trivial to get the statement from the entity after the ChangeOp was applied (which means we get the normalized version):

diff --git a/repo/includes/Api/SetClaim.php b/repo/includes/Api/SetClaim.php
index 2621fe33da..f13b3ab6e2 100644
--- a/repo/includes/Api/SetClaim.php
+++ b/repo/includes/Api/SetClaim.php
@@ -204,6 +204,7 @@ private function executeInternal(): void {
 		$index = $params['index'] ?? null;
 		$changeop = $this->statementChangeOpFactory->newSetStatementOp( $statement, $index );
 		$this->modificationHelper->applyChangeOp( $changeop, $entity, $summary );
+		$statement = $entity->getStatements()->getFirstStatementWithGuid( $guid );
 
 		$status = $this->entitySavingHelper->attemptSaveEntity( $entity, $summary, $params, $this->getContext() );
 		$this->resultBuilder->addRevisionIdFromStatusToResult( $status, 'pageinfo' );

For wbsetreference… not so much, because references, unlike statements, have no stable identifier. wbsetreference can add a new reference or update an existing one, so after applying the ChangeOp, we have no idea which of the references in the target statement is the edited one that we should be returning. If the API request was for updating an existing reference, then it included a hash of the old reference, but the new reference will have a new hash, and the normalized version of that will again have a different hash. So we can’t use the hash to find the edited reference.

I guess we can track all the reference hashes in the statement before applying the ChangeOp, and then get all the references again afterwards, and check which hash (hopefully exactly one) changed, and that’s the edited reference. Or we make StatementChangeOpFactory guarantee that it returns a ChangeOpReference (not just any ChangeOp) and then add some getReference() function to it, so we can get the normalized reference out of the ChangeOp. I don’t really like either of those options, but I haven’t thought of anything else so far.

Change 714539 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@master] Return normalized snaks from SetClaim, SetReference

https://gerrit.wikimedia.org/r/714539

Lucas_Werkmeister_WMDE renamed this task from Show normalized value after save to wbsetclaim and wbsetreference return unnormalized data.Aug 24 2021, 9:44 AM
Lucas_Werkmeister_WMDE updated the task description. (Show Details)

Change 714565 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@master] Test that APIs return normalized data values

https://gerrit.wikimedia.org/r/714565

Change 714539 merged by jenkins-bot:

[mediawiki/extensions/Wikibase@master] Return normalized snaks from SetClaim, SetReference

https://gerrit.wikimedia.org/r/714539

Change 714565 merged by jenkins-bot:

[mediawiki/extensions/Wikibase@master] Test that APIs return normalized data values

https://gerrit.wikimedia.org/r/714565

Change 714677 had a related patch set uploaded (by Lucas Werkmeister (WMDE); author: Lucas Werkmeister (WMDE)):

[mediawiki/extensions/Wikibase@wmf/1.37.0-wmf.20] Return normalized snaks from SetClaim, SetReference

https://gerrit.wikimedia.org/r/714677

I think we should consider backporting the main change to wmf.20, so that people trying out the announced change will see the expected API behavior as soon as possible.

Change 714677 merged by jenkins-bot:

[mediawiki/extensions/Wikibase@wmf/1.37.0-wmf.20] Return normalized snaks from SetClaim, SetReference

https://gerrit.wikimedia.org/r/714677

Mentioned in SAL (#wikimedia-operations) [2021-08-25T17:27:13Z] <lucaswerkmeister-wmde@deploy1002> Synchronized php-1.37.0-wmf.20/extensions/Wikibase: Backport: [[gerrit:714677|Return normalized snaks from SetClaim, SetReference (T289501)]] (duration: 01m 11s)