From 104eff54fa9a66f4855a67b9725a652bdee85862 Mon Sep 17 00:00:00 2001 From: Aleksei Lebedev <1329824+LastDragon-ru@users.noreply.github.com> Date: Thu, 2 May 2024 11:36:42 +0400 Subject: [PATCH] `@stream` `Offset` scalar extracted from type definition. --- .../DirectiveTest/Implicit.expected.graphql | 2 +- .../DirectiveTest/Implicit.expected.graphql | 2 +- .../DirectiveTest~schema-expected.graphql | 2 +- .../DirectiveTest~scout-expected.graphql | 2 +- .../graphql/src/Stream/Scalars/Offset.php | 169 ++++++++++++++++++ .../Stream/{Types => Scalars}/OffsetTest.php | 2 +- packages/graphql/src/Stream/Types/Offset.php | 147 +-------------- 7 files changed, 178 insertions(+), 148 deletions(-) create mode 100644 packages/graphql/src/Stream/Scalars/Offset.php rename packages/graphql/src/Stream/{Types => Scalars}/OffsetTest.php (98%) diff --git a/packages/graphql/src/SearchBy/Directives/DirectiveTest/Implicit.expected.graphql b/packages/graphql/src/SearchBy/Directives/DirectiveTest/Implicit.expected.graphql index 976e80d80..b2f14d1ea 100644 --- a/packages/graphql/src/SearchBy/Directives/DirectiveTest/Implicit.expected.graphql +++ b/packages/graphql/src/SearchBy/Directives/DirectiveTest/Implicit.expected.graphql @@ -1075,7 +1075,7 @@ pagination). """ scalar StreamOffset @type( - class: "LastDragon_ru\\LaraASP\\GraphQL\\Stream\\Types\\Offset" + class: "LastDragon_ru\\LaraASP\\GraphQL\\Stream\\Scalars\\Offset" ) type A { diff --git a/packages/graphql/src/SortBy/Directives/DirectiveTest/Implicit.expected.graphql b/packages/graphql/src/SortBy/Directives/DirectiveTest/Implicit.expected.graphql index 19386dcfe..76e14a553 100644 --- a/packages/graphql/src/SortBy/Directives/DirectiveTest/Implicit.expected.graphql +++ b/packages/graphql/src/SortBy/Directives/DirectiveTest/Implicit.expected.graphql @@ -523,7 +523,7 @@ pagination). """ scalar StreamOffset @type( - class: "LastDragon_ru\\LaraASP\\GraphQL\\Stream\\Types\\Offset" + class: "LastDragon_ru\\LaraASP\\GraphQL\\Stream\\Scalars\\Offset" ) type A { diff --git a/packages/graphql/src/Stream/Directives/DirectiveTest~schema-expected.graphql b/packages/graphql/src/Stream/Directives/DirectiveTest~schema-expected.graphql index 39acc84b2..bfa462a9f 100644 --- a/packages/graphql/src/Stream/Directives/DirectiveTest~schema-expected.graphql +++ b/packages/graphql/src/Stream/Directives/DirectiveTest~schema-expected.graphql @@ -303,7 +303,7 @@ pagination). """ scalar StreamOffset @type( - class: "LastDragon_ru\\LaraASP\\GraphQL\\Stream\\Types\\Offset" + class: "LastDragon_ru\\LaraASP\\GraphQL\\Stream\\Scalars\\Offset" ) type Query diff --git a/packages/graphql/src/Stream/Directives/DirectiveTest~scout-expected.graphql b/packages/graphql/src/Stream/Directives/DirectiveTest~scout-expected.graphql index 27d1d2046..df4bf13e3 100644 --- a/packages/graphql/src/Stream/Directives/DirectiveTest~scout-expected.graphql +++ b/packages/graphql/src/Stream/Directives/DirectiveTest~scout-expected.graphql @@ -232,7 +232,7 @@ pagination). """ scalar StreamOffset @type( - class: "LastDragon_ru\\LaraASP\\GraphQL\\Stream\\Types\\Offset" + class: "LastDragon_ru\\LaraASP\\GraphQL\\Stream\\Scalars\\Offset" ) type Query diff --git a/packages/graphql/src/Stream/Scalars/Offset.php b/packages/graphql/src/Stream/Scalars/Offset.php new file mode 100644 index 000000000..f57132d83 --- /dev/null +++ b/packages/graphql/src/Stream/Scalars/Offset.php @@ -0,0 +1,169 @@ + + // ========================================================================= + protected function getEncrypter(): StringEncrypter { + return Container::getInstance()->make(StringEncrypter::class); + } + + protected function getSerializer(): Serializer { + return Container::getInstance()->make(Serializer::class); + } + // + + // + // ========================================================================= + /** + * @return string|int<0, max> + */ + #[Override] + public function serialize(mixed $value): string|int { + $value = $this->validate($value, InvariantViolation::class); + + if ($value instanceof StreamOffset) { + $value = $this->getSerializer()->serialize($value, 'json'); + $value = $this->encrypt($value); + } + + return $value; + } + + /** + * @return StreamOffset|int<0, max> + */ + #[Override] + public function parseValue(mixed $value): StreamOffset|int { + if (is_string($value)) { + try { + $value = $this->decrypt($value); + $value = $this->getSerializer()->deserialize(StreamOffset::class, $value, 'json'); + } catch (Exception) { + throw new Error('The cursor is not valid.'); + } + } else { + $value = $this->validate($value, Error::class); + } + + return $value; + } + + /** + * @inheritDoc + * @return StreamOffset|int<0, max> + */ + #[Override] + public function parseLiteral(Node $valueNode, array $variables = null): StreamOffset|int { + $value = null; + + if ($valueNode instanceof StringValueNode) { + $value = $this->parseValue($valueNode->value); + } elseif ($valueNode instanceof IntValueNode) { + $value = filter_var($valueNode->value, FILTER_VALIDATE_INT); + $value = $this->parseValue($value); + } else { + throw new Error( + sprintf( + 'The `%s`/`%s` value expected, `%s` given.', + NodeKind::STRING, + NodeKind::INT, + $valueNode->kind, + ), + ); + } + + return $value; + } + + /** + * @param class-string $error + * + * @phpstan-assert StreamOffset|int<0, max> $value + */ + protected function validate(mixed $value, string $error): StreamOffset|int { + if ($value instanceof StreamOffset) { + // ok + } elseif (is_int($value)) { + if ($value < 0) { + throw new $error('The offset must be greater or equal to 0.'); + } + } else { + throw new $error( + sprintf( + 'The valid cursor/offset expected, `%s` given.', + Utils::printSafe($value), + ), + ); + } + + return $value; + } + + protected function encrypt(string $value): string { + return $this->getEncrypter()->encryptString($value); + } + + protected function decrypt(string $value): string { + return Cast::toString($this->getEncrypter()->decryptString($value)); + } + // + + // + // ========================================================================= + #[Override] + public function getTypeName(TypeSource $source, Context $context): string { + return $this->name(); + } + + #[Override] + public function getTypeDefinition( + Manipulator $manipulator, + TypeSource $source, + Context $context, + string $name, + ): TypeDefinitionNode|string|null { + return self::class; + } + // +} diff --git a/packages/graphql/src/Stream/Types/OffsetTest.php b/packages/graphql/src/Stream/Scalars/OffsetTest.php similarity index 98% rename from packages/graphql/src/Stream/Types/OffsetTest.php rename to packages/graphql/src/Stream/Scalars/OffsetTest.php index 0d4e3c7d6..d0e03f710 100644 --- a/packages/graphql/src/Stream/Types/OffsetTest.php +++ b/packages/graphql/src/Stream/Scalars/OffsetTest.php @@ -1,6 +1,6 @@ - // ========================================================================= - protected function getEncrypter(): StringEncrypter { - return Container::getInstance()->make(StringEncrypter::class); - } - - protected function getSerializer(): Serializer { - return Container::getInstance()->make(Serializer::class); - } - // - - // - // ========================================================================= - /** - * @return string|int<0, max> - */ - #[Override] - public function serialize(mixed $value): string|int { - $value = $this->validate($value, InvariantViolation::class); - - if ($value instanceof StreamOffset) { - $value = $this->getSerializer()->serialize($value, 'json'); - $value = $this->encrypt($value); - } - - return $value; - } - - /** - * @return StreamOffset|int<0, max> - */ - #[Override] - public function parseValue(mixed $value): StreamOffset|int { - if (is_string($value)) { - try { - $value = $this->decrypt($value); - $value = $this->getSerializer()->deserialize(StreamOffset::class, $value, 'json'); - } catch (Exception) { - throw new Error('The cursor is not valid.'); - } - } else { - $value = $this->validate($value, Error::class); - } - - return $value; - } - - /** - * @inheritDoc - * @return StreamOffset|int<0, max> - */ - #[Override] - public function parseLiteral(Node $valueNode, array $variables = null): StreamOffset|int { - $value = null; - - if ($valueNode instanceof StringValueNode) { - $value = $this->parseValue($valueNode->value); - } elseif ($valueNode instanceof IntValueNode) { - $value = filter_var($valueNode->value, FILTER_VALIDATE_INT); - $value = $this->parseValue($value); - } else { - throw new Error( - sprintf( - 'The `%s`/`%s` value expected, `%s` given.', - NodeKind::STRING, - NodeKind::INT, - $valueNode->kind, - ), - ); - } - - return $value; - } - - /** - * @param class-string $error - * - * @phpstan-assert StreamOffset|int<0, max> $value - */ - protected function validate(mixed $value, string $error): StreamOffset|int { - if ($value instanceof StreamOffset) { - // ok - } elseif (is_int($value)) { - if ($value < 0) { - throw new $error('The offset must be greater or equal to 0.'); - } - } else { - throw new $error( - sprintf( - 'The valid cursor/offset expected, `%s` given.', - Utils::printSafe($value), - ), - ); - } - - return $value; - } - - protected function encrypt(string $value): string { - return $this->getEncrypter()->encryptString($value); - } - - protected function decrypt(string $value): string { - return Cast::toString($this->getEncrypter()->decryptString($value)); - } - // - - // - // ========================================================================= +class Offset implements TypeDefinition { #[Override] public function getTypeName(TypeSource $source, Context $context): string { - return $this->name(); + return Directive::Name.'Offset'; } #[Override] @@ -163,7 +24,7 @@ public function getTypeDefinition( Context $context, string $name, ): TypeDefinitionNode|string|null { - return self::class; + return OffsetScalar::class; } // }