Skip to content

Commit c2a38af

Browse files
authored
Add a new abstract scalar IntRange
1 parent 019584c commit c2a38af

File tree

8 files changed

+176
-28
lines changed

8 files changed

+176
-28
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
## Unreleased
1111

12+
## v6.3.0
13+
14+
### Added
15+
16+
- Add a new abstract scalar `IntRange`
17+
1218
## v6.2.0
1319

1420
### Added

README.md

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
A collection of custom scalar types for usage with https://github.com/webonyx/graphql-php
44

5-
[![Continuous Integration](https://github.com/mll-lab/graphql-php-scalars/workflows/Continuous%20Integration/badge.svg)](https://github.com/mll-lab/graphql-php-scalars/actions)
5+
[![Validate](https://github.com/mll-lab/graphql-php-scalars/workflows/Validate/badge.svg)](https://github.com/mll-lab/graphql-php-scalars/actions)
66
[![codecov](https://codecov.io/gh/mll-lab/graphql-php-scalars/branch/master/graph/badge.svg)](https://codecov.io/gh/mll-lab/graphql-php-scalars)
77

88
[![GitHub license](https://img.shields.io/github/license/mll-lab/graphql-php-scalars.svg)](https://github.com/mll-lab/graphql-php-scalars/blob/master/LICENSE)
@@ -11,7 +11,9 @@ A collection of custom scalar types for usage with https://github.com/webonyx/gr
1111

1212
## Installation
1313

14-
composer require mll-lab/graphql-php-scalars
14+
```sh
15+
composer require mll-lab/graphql-php-scalars
16+
```
1517

1618
## Usage
1719

@@ -43,6 +45,27 @@ A datetime string with format `Y-m-d\TH:i:s.uP`, e.g. `2020-04-20T16:20:04+04:00
4345

4446
A [RFC 5321](https://tools.ietf.org/html/rfc5321) compliant email.
4547

48+
### [IntRange](src/IntRange.php)
49+
50+
Allows defining numeric scalars where the values must lie between a defined minimum and maximum.
51+
52+
```php
53+
use MLL\GraphQLScalars\IntRange;
54+
55+
final class UpToADozen extends IntRange
56+
{
57+
protected static function min(): int
58+
{
59+
return 1;
60+
}
61+
62+
protected static function max(): int
63+
{
64+
return 12;
65+
}
66+
}
67+
```
68+
4669
### [JSON](src/JSON.php)
4770

4871
Arbitrary data encoded in JavaScript Object Notation. See https://www.json.org.
@@ -131,13 +154,11 @@ use MLL\GraphQLScalars\Regex;
131154
// The name is implicitly set through the class name here
132155
class HexValue extends Regex
133156
{
134-
/**
135-
* The description that is used for schema introspection.
136-
*/
137-
public ?string $description = <<<'DESCRIPTION'
138-
A hexadecimal color is specified with: `#RRGGBB`, where `RR` (red), `GG` (green) and `BB` (blue)
139-
are hexadecimal integers between `00` and `FF` specifying the intensity of the color.
140-
DESCRIPTION;
157+
/** The description that is used for schema introspection. */
158+
public ?string $description = /** @lang Markdown */<<<'MARKDOWN'
159+
A hexadecimal color is specified with: `#RRGGBB`, where `RR` (red), `GG` (green) and `BB` (blue)
160+
are hexadecimal integers between `00` and `FF` specifying the intensity of the color.
161+
MARKDOWN;
141162

142163
public static function regex(): string
143164
{
@@ -160,13 +181,11 @@ use MLL\GraphQLScalars\StringScalar;
160181
$coolName = StringScalar::make(
161182
'CoolName',
162183
'A name that is most definitely cool.',
163-
static function (string $name): bool {
164-
return in_array($name, [
165-
'Vladar',
166-
'Benedikt',
167-
'Christopher',
168-
]);
169-
}
184+
static fn (string $name): bool => in_array($name, [
185+
'Vladar',
186+
'Benedikt',
187+
'Christopher',
188+
]),
170189
);
171190
```
172191

src/IntRange.php

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\GraphQLScalars;
4+
5+
use GraphQL\Error\Error;
6+
use GraphQL\Language\AST\IntValueNode;
7+
use GraphQL\Language\AST\Node;
8+
use GraphQL\Language\Printer;
9+
use GraphQL\Type\Definition\ScalarType;
10+
use GraphQL\Utils\Utils;
11+
12+
abstract class IntRange extends ScalarType
13+
{
14+
/** The minimum allowed value. */
15+
abstract protected static function min(): int;
16+
17+
/** The maximum allowed value. */
18+
abstract protected static function max(): int;
19+
20+
public function serialize($value)
21+
{
22+
if (is_int($value) && $this->isValueInExpectedRange($value)) {
23+
return $value;
24+
}
25+
26+
$notInRange = Utils::printSafe($value);
27+
throw new \InvalidArgumentException("Value not in range {$this->rangeDescription()}: {$notInRange}.");
28+
}
29+
30+
public function parseValue($value)
31+
{
32+
if (is_int($value) && $this->isValueInExpectedRange($value)) {
33+
return $value;
34+
}
35+
36+
$notInRange = Utils::printSafe($value);
37+
throw new Error("Value not in range {$this->rangeDescription()}: {$notInRange}.");
38+
}
39+
40+
public function parseLiteral(Node $valueNode, ?array $variables = null)
41+
{
42+
if ($valueNode instanceof IntValueNode) {
43+
$value = (int) $valueNode->value;
44+
if ($this->isValueInExpectedRange($value)) {
45+
return $value;
46+
}
47+
}
48+
49+
$notInRange = Printer::doPrint($valueNode);
50+
throw new Error("Value not in range {$this->rangeDescription()}: {$notInRange}.", $valueNode);
51+
}
52+
53+
private function isValueInExpectedRange(int $value): bool
54+
{
55+
return $value <= static::max() && $value >= static::min();
56+
}
57+
58+
private function rangeDescription(): string
59+
{
60+
$min = static::min();
61+
$max = static::max();
62+
63+
return "{$min}-{$max}";
64+
}
65+
}

tests/IntRangeTest.php

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\GraphQLScalars\Tests;
4+
5+
use GraphQL\Error\Error;
6+
use PHPUnit\Framework\TestCase;
7+
8+
final class IntRangeTest extends TestCase
9+
{
10+
public function testSerializeThrowsIfNotAnInt(): void
11+
{
12+
$this->expectException(\InvalidArgumentException::class);
13+
$this->expectExceptionMessage('Value not in range 1-12: "12".');
14+
15+
(new UpToADozen())->serialize('12');
16+
}
17+
18+
public function testSerializeThrowsIfInvalid(): void
19+
{
20+
$this->expectException(\InvalidArgumentException::class);
21+
$this->expectExceptionMessage('Value not in range 1-12: 13.');
22+
23+
(new UpToADozen())->serialize(13);
24+
}
25+
26+
public function testSerializePassesWhenValid(): void
27+
{
28+
$serializedResult = (new UpToADozen())->serialize(12);
29+
30+
self::assertSame(12, $serializedResult);
31+
}
32+
33+
public function testParseValueThrowsIfInvalid(): void
34+
{
35+
$this->expectException(Error::class);
36+
$this->expectExceptionMessage('Value not in range 1-12: 13.');
37+
38+
(new UpToADozen())->parseValue(13);
39+
}
40+
41+
public function testParseValuePassesIfValid(): void
42+
{
43+
self::assertSame(
44+
12,
45+
(new UpToADozen())->parseValue(12)
46+
);
47+
}
48+
}

tests/MixedScalarTest.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,7 @@ public function setUp(): void
2727
'fields' => [
2828
'foo' => [
2929
'type' => $mixed,
30-
'resolve' => function ($root, array $args) {
31-
return reset($args);
32-
},
30+
'resolve' => fn ($root, array $args) => reset($args),
3331
'args' => [
3432
'bar' => $mixed,
3533
],

tests/NullScalarTest.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,14 @@ public function setUp(): void
3030
'fields' => [
3131
'foo' => [
3232
'type' => $null,
33-
'resolve' => function ($root, array $args) {
34-
return reset($args);
35-
},
33+
'resolve' => fn ($root, array $args) => reset($args),
3634
'args' => [
3735
'bar' => $null,
3836
],
3937
],
4038
'mixed' => [
4139
'type' => $null,
42-
'resolve' => function () {
43-
return $this->return;
44-
},
40+
'resolve' => fn () => $this->return,
4541
],
4642
],
4743
])

tests/StringScalarTest.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,7 @@ protected function isValid(string $stringValue): bool
4646
StringScalar::make(
4747
'MyStringScalar',
4848
'Bar',
49-
function (string $string) {
50-
return $string === 'foo';
51-
}
49+
fn (string $string) => $string === 'foo'
5250
),
5351
];
5452
}

tests/UpToADozen.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace MLL\GraphQLScalars\Tests;
4+
5+
use MLL\GraphQLScalars\IntRange;
6+
7+
final class UpToADozen extends IntRange
8+
{
9+
protected static function min(): int
10+
{
11+
return 1;
12+
}
13+
14+
protected static function max(): int
15+
{
16+
return 12;
17+
}
18+
}

0 commit comments

Comments
 (0)