Skip to content

Commit c002e66

Browse files
dima koushhajenkins-bot
authored andcommitted
GQL: Enable Statements with value
Bug: T404834 Change-Id: I12701efe6f142d2031d2ed084a30f2a918d9bf7c
1 parent 0637b52 commit c002e66

File tree

15 files changed

+278
-11
lines changed

15 files changed

+278
-11
lines changed

docs/topics/datatypes.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ Each key is associated with a map that provides the following fields:
5353
* A callable that returns one or more [DataValueNormalizer]s (a single instance or an array of them) for use with this data type. Data values are normalized on save according to the normalizers for the property data type and value type (which are combined, rather than overriding one another).
5454
Normalization takes place between parsing and validation (which are defined using other callbacks, see above). While parsing is based on string input, is usually interactive, and can be fairly lenient (e.g. trimming whitespace), normalization is based on already parsed data values and applied whenever a data value is saved, including non-interactively; normalization should therefore be more conservative than parsing. Validation afterwards ensures that the (normalized) value is valid before it is saved.
5555
Wikibase currently does not normalize values at any other stage (e.g. post-save, when loading an item), because some normalizations are too expensive to apply when dumping large numbers of entities.
56+
* graphql-value-type (repo)
57+
* A callable that returns the GraphQL type used for values of this data type. This maps a data type
58+
to a GraphQL value type name the GraphQL schema layer will expose.
5659

5760
Since for each property data type the associated value type is known, this provides a convenient fallback mechanism: If a desired callback field isn't defined for a given property data type, we can fall back to using the callback that is defined for the value type. For example, if there is no formatter-factory-callback field associated with the PT:url key, we may use the one defined for VT:string, since the url property data type is based on the string value type.
5861

lib/includes/DataTypeDefinitions.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,4 +408,12 @@ public function getNormalizerFactoryCallbacks(): array {
408408
return $this->getMapForDefinitionField( 'normalizer-factory-callback' );
409409
}
410410

411+
/**
412+
* Get the GraphQL type to be used for values of different data types and value types
413+
* @return callable[] List of callbacks, with keys having "VT:" and "PT:" prefixes.
414+
*/
415+
public function getGraphqlValueTypes(): array {
416+
return $this->getMapForDefinitionField( 'graphql-value-type' );
417+
}
418+
411419
}

repo/WikibaseRepo.datatypes.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
use DataValues\StringValue;
3232
use DataValues\TimeValue;
3333
use DataValues\UnboundedQuantityValue;
34+
use GraphQL\Type\Definition\ObjectType;
35+
use GraphQL\Type\Definition\Type;
3436
use MediaWiki\Logger\LoggerFactory;
3537
use MediaWiki\MediaWikiServices;
3638
use ValueFormatters\FormatterOptions;
@@ -45,6 +47,7 @@
4547
use Wikibase\Lib\Formatters\SnakFormatter;
4648
use Wikibase\Lib\Store\FieldPropertyInfoProvider;
4749
use Wikibase\Lib\Store\PropertyInfoStore;
50+
use Wikibase\Repo\Domains\Reuse\Domain\Model\Value;
4851
use Wikibase\Repo\Parsers\EntityIdValueParser;
4952
use Wikibase\Repo\Parsers\MediaWikiNumberUnlocalizer;
5053
use Wikibase\Repo\Parsers\MonolingualTextParser;
@@ -300,6 +303,21 @@
300303
'normalizer-factory-callback' => static function () {
301304
return WikibaseRepo::getStringValueNormalizer();
302305
},
306+
'graphql-value-type' => static function () {
307+
return new ObjectType( [
308+
'name' => 'StringValue',
309+
'fields' => [
310+
'type' => [
311+
'type' => Type::nonNull( Type::string() ),
312+
'resolve' => fn() => 'value',
313+
],
314+
'content' => [
315+
'type' => Type::nonNull( Type::string() ),
316+
'resolve' => fn( Value $v ) => $v->content->getValue(),
317+
],
318+
],
319+
] );
320+
},
303321
],
304322
'VT:time' => [
305323
'expert-module' => 'jquery.valueview.experts.TimeInput',
@@ -453,6 +471,29 @@
453471
'rdf-data-type' => function() {
454472
return PropertySpecificComponentsRdfBuilder::OBJECT_PROPERTY;
455473
},
474+
'graphql-value-type' => static function() {
475+
return new ObjectType( [
476+
'name' => 'ItemValue',
477+
'fields' => [
478+
'type' => [
479+
'type' => Type::nonNull( Type::string() ),
480+
'resolve' => fn() => 'value',
481+
],
482+
'content' => [
483+
'type' => Type::nonNull( new ObjectType( [
484+
'name' => 'ValueItem',
485+
'fields' => [
486+
'id' => [
487+
'type' => Type::nonNull( Type::string() ),
488+
'resolve' => fn( EntityIdValue $content ) => $content->getEntityId()->getSerialization(),
489+
],
490+
],
491+
] ) ),
492+
'resolve' => fn( Value $v ) => $v->content,
493+
],
494+
],
495+
] );
496+
},
456497
],
457498
'PT:wikibase-property' => [
458499
'expert-module' => 'wikibase.experts.Property',

repo/domains/reuse/src/Domain/Model/PropertyValuePair.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
*/
88
class PropertyValuePair {
99

10-
// will add the value in upcoming patches
11-
public function __construct( public readonly PredicateProperty $property ) {
10+
public function __construct( public readonly PredicateProperty $property, public readonly Value $value ) {
1211
}
1312

1413
}

repo/domains/reuse/src/Domain/Model/Statement.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public function __construct(
1414
public readonly Rank $rank,
1515
public readonly Qualifiers $qualifiers,
1616
public readonly PredicateProperty $property,
17+
public readonly Value $value
1718
) {
1819
}
1920

repo/domains/reuse/src/Domain/Model/Statements.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ public function __construct( Statement ...$statements ) {
1919
* @return Statement[]
2020
*/
2121
public function getStatementsByPropertyId( PropertyId $id ): array {
22-
return array_filter(
22+
return array_values( array_filter(
2323
$this->statements,
2424
fn( Statement $s ) => $s->property->id->equals( $id )
25-
);
25+
) );
2626
}
2727

2828
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php declare( strict_types=1 );
2+
3+
namespace Wikibase\Repo\Domains\Reuse\Domain\Model;
4+
5+
use DataValues\DataValue;
6+
use InvalidArgumentException;
7+
8+
/**
9+
* @license GPL-2.0-or-later
10+
*/
11+
class Value {
12+
13+
public const TYPE_VALUE = 'value';
14+
public const TYPE_NO_VALUE = 'novalue';
15+
public const TYPE_SOME_VALUE = 'somevalue';
16+
17+
/**
18+
* @param string $valueType
19+
* @param DataValue|null $content Guaranteed to be non-null if value type is "value", always null otherwise.
20+
*/
21+
public function __construct( public readonly string $valueType, public readonly ?DataValue $content = null ) {
22+
if ( !in_array( $valueType, [ self::TYPE_VALUE, self::TYPE_SOME_VALUE, self::TYPE_NO_VALUE ] ) ) {
23+
throw new InvalidArgumentException( '$valueType must be one of "value", "somevalue", "novalue"' );
24+
}
25+
if ( $valueType === self::TYPE_VALUE && !$content ) {
26+
throw new InvalidArgumentException( '$value must not be null if $valueType is "value"' );
27+
}
28+
if ( $valueType !== self::TYPE_VALUE && $content ) {
29+
throw new InvalidArgumentException( "There must not be a value if \$valueType is '$valueType'" );
30+
}
31+
}
32+
33+
}

repo/domains/reuse/src/Domain/Services/StatementReadModelConverter.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookup;
77
use Wikibase\DataModel\Services\Lookup\PropertyDataTypeLookupException;
88
use Wikibase\DataModel\Services\Statement\StatementGuidParser;
9+
use Wikibase\DataModel\Snak\PropertyValueSnak;
910
use Wikibase\DataModel\Snak\Snak;
1011
use Wikibase\DataModel\Snak\SnakList;
1112
use Wikibase\DataModel\Statement\Statement as StatementWriteModel;
@@ -14,6 +15,7 @@
1415
use Wikibase\Repo\Domains\Reuse\Domain\Model\Qualifiers;
1516
use Wikibase\Repo\Domains\Reuse\Domain\Model\Rank;
1617
use Wikibase\Repo\Domains\Reuse\Domain\Model\Statement;
18+
use Wikibase\Repo\Domains\Reuse\Domain\Model\Value;
1719

1820
/**
1921
* @license GPL-2.0-or-later
@@ -39,6 +41,7 @@ public function convert( StatementWriteModel $inputStatement ): Statement {
3941
new Rank( $inputStatement->getRank() ),
4042
$this->convertQualifiers( $inputStatement->getQualifiers() ),
4143
$mainPropertyValuePair->property,
44+
$mainPropertyValuePair->value,
4245
);
4346
}
4447

@@ -58,7 +61,13 @@ private function convertSnakToPropertyValuePair( Snak $snak ): PropertyValuePair
5861
$dataType = null;
5962
}
6063

61-
return new PropertyValuePair( new PredicateProperty( $snak->getPropertyId(), $dataType ) );
64+
return new PropertyValuePair(
65+
new PredicateProperty( $snak->getPropertyId(), $dataType ),
66+
new Value(
67+
$snak->getType(),
68+
$snak instanceof PropertyValueSnak ? $snak->getDataValue() : null
69+
)
70+
);
6271
}
6372

6473
}

repo/domains/reuse/src/Infrastructure/GraphQL/Schema/PropertyValuePairType.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@
1111
*/
1212
class PropertyValuePairType extends ObjectType {
1313

14-
// Include the value during property value implementation.
15-
public function __construct( PredicatePropertyType $predicateType ) {
14+
public function __construct( PredicatePropertyType $predicateType, ValueType $valueType ) {
1615
$config = [
1716
'fields' => [
1817
'property' => [
1918
'type' => Type::nonNull( $predicateType ),
2019
'resolve' => fn( PropertyValuePair $rootValue ) => $rootValue->property,
2120
],
21+
'value' => [
22+
'type' => Type::nonNull( $valueType ),
23+
'resolve' => fn( PropertyValuePair $rootValue ) => $rootValue->value,
24+
],
2225
],
2326
];
2427
parent::__construct( $config );

repo/domains/reuse/src/Infrastructure/GraphQL/Schema/Schema.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public function __construct(
2323
private readonly LanguageCodeType $languageCodeType,
2424
private readonly PredicatePropertyType $predicatePropertyType,
2525
private readonly PropertyValuePairType $propertyValuePairType,
26+
private readonly ValueType $valueType,
2627
) {
2728
parent::__construct( [
2829
'query' => new ObjectType( [
@@ -130,6 +131,7 @@ private function statementType(): ObjectType {
130131
'type' => Type::nonNull( $this->predicatePropertyType ),
131132
'resolve' => fn( Statement $statement ) => $statement->property,
132133
],
134+
'value' => Type::nonNull( $this->valueType ),
133135
],
134136
] );
135137
}

0 commit comments

Comments
 (0)