-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
297 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# `JsonString` | ||
|
||
Represents [JSON](https://json.org) string. | ||
|
||
Please note that the scalar doesn't encode/decode value to/from JSON, it just contains a valid JSON string. If you want automatically convert value to/from JSON, you can use the `JSON` type from [`mll-lab/graphql-php-scalars`](https://github.com/mll-lab/graphql-php-scalars) package. If you need something more typesafe, consider using [`Serializer`][pkg:serializer]. | ||
|
||
[include:file]: ../../../../docs/shared/Links.md | ||
[//]: # (start: a170145c7adc0561ead408b0ea3a4b46e2e8f45ebc2744984ceb8c1b49822cd1) | ||
[//]: # (warning: Generated automatically. Do not edit.) | ||
|
||
[pkg:serializer]: https://github.com/LastDragon-ru/lara-asp/tree/main/packages/serializer | ||
|
||
[//]: # (end: a170145c7adc0561ead408b0ea3a4b46e2e8f45ebc2744984ceb8c1b49822cd1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace LastDragon_ru\LaraASP\GraphQL\Scalars; | ||
|
||
use Exception; | ||
use GraphQL\Error\Error; | ||
use GraphQL\Error\InvariantViolation; | ||
use GraphQL\Language\AST\Node; | ||
use GraphQL\Language\AST\NodeKind; | ||
use GraphQL\Language\AST\StringValueNode; | ||
use GraphQL\Language\AST\TypeDefinitionNode; | ||
use GraphQL\Type\Definition\StringType; | ||
use GraphQL\Type\Definition\Type; | ||
use GraphQL\Utils\Utils; | ||
use LastDragon_ru\LaraASP\GraphQL\Builder\BuilderInfo; | ||
use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeDefinition; | ||
use LastDragon_ru\LaraASP\GraphQL\Builder\Contracts\TypeSource; | ||
use LastDragon_ru\LaraASP\GraphQL\Builder\Manipulator; | ||
|
||
use function is_string; | ||
use function json_validate; | ||
use function sprintf; | ||
|
||
class JsonString extends StringType implements TypeDefinition { | ||
public string $name = 'JsonString'; | ||
public ?string $description = 'Represents JSON string.'; | ||
|
||
// <editor-fold desc="ScalarType"> | ||
// ========================================================================= | ||
public function serialize(mixed $value): string { | ||
if ($value instanceof JsonStringable) { | ||
$value = (string) $value; | ||
} else { | ||
$value = $this->validate($value, InvariantViolation::class); | ||
} | ||
|
||
return $value; | ||
} | ||
|
||
public function parseValue(mixed $value): string { | ||
return $this->validate($value, Error::class); | ||
} | ||
|
||
/** | ||
* @inheritDoc | ||
*/ | ||
public function parseLiteral(Node $valueNode, array $variables = null): string { | ||
if (!($valueNode instanceof StringValueNode)) { | ||
throw new Error( | ||
sprintf( | ||
'The `%s` value expected, `%s` given.', | ||
NodeKind::STRING, | ||
$valueNode->kind, | ||
), | ||
); | ||
} | ||
|
||
return $this->parseValue($valueNode->value); | ||
} | ||
|
||
/** | ||
* @param class-string<Exception> $error | ||
* | ||
* @phpstan-assert string $value | ||
*/ | ||
protected function validate(mixed $value, string $error): string { | ||
if (is_string($value) && json_validate($value)) { | ||
// ok | ||
} else { | ||
throw new $error( | ||
sprintf( | ||
'The valid JSON string expected, `%s` given.', | ||
Utils::printSafe($value), | ||
), | ||
); | ||
} | ||
|
||
return $value; | ||
} | ||
// </editor-fold> | ||
|
||
// <editor-fold desc="TypeDefinition"> | ||
// ========================================================================= | ||
public function getTypeName(Manipulator $manipulator, BuilderInfo $builder, TypeSource $source): string { | ||
return $this->name(); | ||
} | ||
|
||
public function getTypeDefinition( | ||
Manipulator $manipulator, | ||
string $name, | ||
TypeSource $source, | ||
): TypeDefinitionNode|Type|null { | ||
return $this; | ||
} | ||
// </editor-fold> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace LastDragon_ru\LaraASP\GraphQL\Scalars; | ||
|
||
use Exception; | ||
use GraphQL\Error\Error; | ||
use GraphQL\Error\InvariantViolation; | ||
use GraphQL\Language\AST\IntValueNode; | ||
use GraphQL\Language\AST\Node; | ||
use GraphQL\Language\AST\StringValueNode; | ||
use GraphQL\Language\AST\ValueNode; | ||
use LastDragon_ru\LaraASP\GraphQL\Testing\Package\TestCase; | ||
use PHPUnit\Framework\Attributes\CoversClass; | ||
|
||
/** | ||
* @internal | ||
*/ | ||
#[CoversClass(JsonString::class)] | ||
class JsonStringTest extends TestCase { | ||
// <editor-fold desc="Tests"> | ||
// ========================================================================= | ||
/** | ||
* @dataProvider dataProviderSerialize | ||
*/ | ||
public function testSerialize(?Exception $expected, mixed $value): void { | ||
if ($expected instanceof Exception) { | ||
self::expectExceptionObject($expected); | ||
} | ||
|
||
$scalar = new JsonString(); | ||
$actual = $scalar->serialize($value); | ||
|
||
if ($value instanceof JsonStringable) { | ||
self::assertEquals((string) $value, $actual); | ||
} else { | ||
self::assertEquals($value, $actual); | ||
} | ||
} | ||
|
||
/** | ||
* @dataProvider dataProviderParseValue | ||
*/ | ||
public function testParseValue(?Exception $expected, mixed $value): void { | ||
if ($expected instanceof Exception) { | ||
self::expectExceptionObject($expected); | ||
} | ||
|
||
$scalar = new JsonString(); | ||
$actual = $scalar->parseValue($value); | ||
|
||
self::assertIsString($value); | ||
self::assertEquals($value, $actual); | ||
} | ||
|
||
/** | ||
* @dataProvider dataProviderParseLiteral | ||
*/ | ||
public function testParseLiteral(?Exception $expected, Node&ValueNode $value): void { | ||
if ($expected instanceof Exception) { | ||
self::expectExceptionObject($expected); | ||
} | ||
|
||
$scalar = new JsonString(); | ||
$actual = $scalar->parseLiteral($value); | ||
|
||
self::assertInstanceOf(StringValueNode::class, $value); | ||
self::assertEquals($value->value, $actual); | ||
} | ||
// </editor-fold> | ||
|
||
// <editor-fold desc="DataProviders"> | ||
// ========================================================================= | ||
/** | ||
* @return array<string, array{?Exception, mixed}> | ||
*/ | ||
public static function dataProviderSerialize(): array { | ||
return [ | ||
'not a string' => [ | ||
new InvariantViolation('The valid JSON string expected, `123` given.'), | ||
123, | ||
], | ||
'string but not a valid json' => [ | ||
new InvariantViolation('The valid JSON string expected, `"invalid json"` given.'), | ||
'invalid json', | ||
], | ||
'string and a valid json' => [ | ||
null, | ||
'{"a": 123, "b": {"c": 45}}', | ||
], | ||
JsonStringable::class => [ | ||
null, | ||
new class('{"a": 123, "b": {"c": 45}}') implements JsonStringable { | ||
public function __construct( | ||
private readonly string $json, | ||
) { | ||
// empty | ||
} | ||
|
||
public function __toString(): string { | ||
return $this->json; | ||
} | ||
}, | ||
], | ||
]; | ||
} | ||
|
||
/** | ||
* @return array<string, array{?Exception, mixed}> | ||
*/ | ||
public static function dataProviderParseValue(): array { | ||
return [ | ||
'not a string' => [ | ||
new Error('The valid JSON string expected, `123` given.'), | ||
123, | ||
], | ||
'string but not a valid json' => [ | ||
new Error('The valid JSON string expected, `"invalid json"` given.'), | ||
'invalid json', | ||
], | ||
'string and a valid json' => [ | ||
null, | ||
'{"a": 123, "b": {"c": 45}}', | ||
], | ||
]; | ||
} | ||
|
||
/** | ||
* @return array<string, array{?Exception, Node&ValueNode}> | ||
*/ | ||
public static function dataProviderParseLiteral(): array { | ||
return [ | ||
'not a string' => [ | ||
new Error('The `StringValue` value expected, `IntValue` given.'), | ||
new IntValueNode(['value' => '123']), | ||
], | ||
'string but not a valid json' => [ | ||
new Error('The valid JSON string expected, `"invalid json"` given.'), | ||
new StringValueNode(['value' => 'invalid json']), | ||
], | ||
'string and a valid json' => [ | ||
null, | ||
new StringValueNode(['value' => '{"a": 123, "b": {"c": 45}}']), | ||
], | ||
]; | ||
} | ||
// </editor-fold> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?php declare(strict_types = 1); | ||
|
||
namespace LastDragon_ru\LaraASP\GraphQL\Scalars; | ||
|
||
use Stringable; | ||
|
||
/** | ||
* Marks that string representation of the class is already a valid JSON string, | ||
* so validation can be omitted. | ||
*/ | ||
interface JsonStringable extends Stringable { | ||
// empty | ||
} |