├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── other-issue.md ├── dependabot.yml └── workflows │ ├── master.yml │ ├── pull_request.yml │ └── release.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── main └── java │ └── graphql │ └── scalars │ ├── ExtendedScalars.java │ ├── alias │ └── AliasedScalar.java │ ├── country │ └── code │ │ ├── CountryCode.java │ │ └── CountryCodeScalar.java │ ├── currency │ └── CurrencyScalar.java │ ├── datetime │ ├── DateScalar.java │ ├── DateTimeScalar.java │ ├── LocalTimeCoercing.java │ └── TimeScalar.java │ ├── id │ └── UUIDScalar.java │ ├── java │ └── JavaPrimitives.java │ ├── locale │ └── LocaleScalar.java │ ├── numeric │ ├── FloatCoercing.java │ ├── IntCoercing.java │ ├── NegativeFloatScalar.java │ ├── NegativeIntScalar.java │ ├── NonNegativeFloatScalar.java │ ├── NonNegativeIntScalar.java │ ├── NonPositiveFloatScalar.java │ ├── NonPositiveIntScalar.java │ ├── PositiveFloatScalar.java │ └── PositiveIntScalar.java │ ├── object │ ├── JsonScalar.java │ └── ObjectScalar.java │ ├── regex │ └── RegexScalar.java │ ├── url │ └── UrlScalar.java │ └── util │ └── Kit.java └── test └── groovy └── graphql └── scalars ├── alias └── AliasedScalarTest.groovy ├── country └── code │ └── CountryCodeScalarTest.groovy ├── currency └── CurrencyScalarTest.groovy ├── datetime ├── DateScalarTest.groovy ├── DateTimeScalarTest.groovy ├── LocalTimeScalarTest.groovy └── TimeScalarTest.groovy ├── id └── UUIDScalarTest.groovy ├── java ├── ScalarsBigDecimalTest.groovy ├── ScalarsBigIntegerTest.groovy ├── ScalarsByteTest.groovy ├── ScalarsCharTest.groovy ├── ScalarsLongTest.groovy └── ScalarsShortTest.groovy ├── locale └── LocaleScalarTest.groovy ├── numeric ├── NegativeFloatScalarTest.groovy ├── NegativeIntScalarTest.groovy ├── NonNegativeFloatScalarTest.groovy ├── NonNegativeIntScalarTest.groovy ├── NonPositiveFloatScalarTest.groovy ├── NonPositiveIntScalarTest.groovy ├── PositiveFloatScalarTest.groovy └── PositiveIntScalarTest.groovy ├── object └── ObjectScalarTest.groovy ├── regex └── RegexScalarTest.groovy ├── url └── UrlScalarTest.groovy └── util └── TestKit.groovy /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Please provide a code example or even better a test to reproduce the bug. 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/other-issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Other issue 3 | about: Generic issue 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | If you have a general question or seeking advice how to use something please create a new topic in our GitHub discussions forum: https://github.com/graphql-java/graphql-java/discussions. Thanks. 11 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gradle" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | -------------------------------------------------------------------------------- /.github/workflows/master.yml: -------------------------------------------------------------------------------- 1 | name: Master Build and Publish 2 | # For master push: Builds and publishes the development version to bintray/maven 3 | on: 4 | push: 5 | branches: 6 | - master 7 | jobs: 8 | buildAndPublish: 9 | runs-on: ubuntu-latest 10 | env: 11 | MAVEN_CENTRAL_USER: ${{ secrets.MAVEN_CENTRAL_USER }} 12 | MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} 13 | MAVEN_CENTRAL_PGP_KEY: ${{ secrets.MAVEN_CENTRAL_PGP_KEY }} 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: gradle/wrapper-validation-action@v3 18 | - name: Set up JDK 11 19 | uses: actions/setup-java@v4 20 | with: 21 | java-version: '11' 22 | distribution: 'corretto' 23 | - name: build test and publish 24 | run: ./gradlew assemble && ./gradlew check --info && ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository -x check --info --stacktrace 25 | -------------------------------------------------------------------------------- /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request Build 2 | # For pull requests: builds and test 3 | on: 4 | push: 5 | branches: 6 | - '!master' 7 | pull_request: 8 | branches: 9 | - master 10 | - 20.x 11 | - 19.x 12 | - 18.x 13 | jobs: 14 | buildAndTest: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: gradle/wrapper-validation-action@v3 19 | - name: Set up JDK 11 20 | uses: actions/setup-java@v4 21 | with: 22 | java-version: '11' 23 | distribution: 'corretto' 24 | - name: build and test 25 | run: ./gradlew assemble && ./gradlew check --info --stacktrace 26 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Manual Release Build 2 | # Release builds 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | version: 7 | description: 'the version to be released' 8 | required: true 9 | 10 | jobs: 11 | buildAndPublish: 12 | runs-on: ubuntu-latest 13 | env: 14 | MAVEN_CENTRAL_PGP_KEY: ${{ secrets.MAVEN_CENTRAL_PGP_KEY }} 15 | MAVEN_CENTRAL_USER: ${{ secrets.MAVEN_CENTRAL_USER }} 16 | MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }} 17 | RELEASE_VERSION: ${{ github.event.inputs.version }} 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | - uses: gradle/wrapper-validation-action@v3 22 | - name: Set up JDK 11 23 | uses: actions/setup-java@v4 24 | with: 25 | java-version: '11' 26 | distribution: 'corretto' 27 | - name: build test and publish 28 | run: ./gradlew assemble && ./gradlew check --info && ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository -x check --info --stacktrace 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .gradle 3 | out 4 | *.iml 5 | 6 | build -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Brad Baker and Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files 6 | (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, 7 | publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 13 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 14 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 15 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Extended Scalars for graphql-java 2 | 3 | [![Build Status](https://github.com/graphql-java/graphql-java-extended-scalars/actions/workflows/master.yml/badge.svg)](https://github.com/graphql-java/graphql-java-extended-scalars/actions/workflows/master.yml) 4 | [![Latest Release](https://img.shields.io/maven-central/v/com.graphql-java/graphql-java-extended-scalars?versionPrefix=22.)](https://maven-badges.herokuapp.com/maven-central/com.graphql-java/graphql-java-extended-scalars/) 5 | [![Latest Snapshot](https://img.shields.io/maven-central/v/com.graphql-java/graphql-java-extended-scalars?label=maven-central%20snapshot)](https://maven-badges.herokuapp.com/maven-central/com.graphql-java/graphql-java-extended-scalars/) 6 | [![MIT licensed](https://img.shields.io/badge/license-MIT-green)](https://github.com/graphql-java/graphql-java-extended-scalars/blob/master/LICENSE.md) 7 | 8 | ## Overview 9 | 10 | This library provides extended scalars for [graphql-java](https://github.com/graphql-java/graphql-java) 11 | 12 | [GraphQL Scalars](https://spec.graphql.org/draft/#sec-Scalars) are the primitive leaf values in the GraphQL type system which cannot be queried further via sub-field selections. 13 | 14 | The GraphQL Specification defines `String`, `Int`, `Float`, `Boolean` and `ID` as well-defined [built-in scalars](https://spec.graphql.org/draft/#sec-Scalars.Built-in-Scalars) that must be present in a graphql type 15 | system. Beyond these, it is up to an implementation to decide what [custom scalars](https://spec.graphql.org/draft/#sec-Scalars.Custom-Scalars) are present. 16 | 17 | You would use custom scalars when you want to describe more meaningful behavior or ranges of values. 18 | 19 | # Getting started 20 | 21 | ## How to install 22 | 23 | To use this library put the following into your gradle config 24 | 25 | ```java 26 | implementation 'com.graphql-java:graphql-java-extended-scalars:22.0' 27 | ``` 28 | 29 | or the following into your Maven config 30 | 31 | ```xml 32 | 33 | com.graphql-java 34 | graphql-java-extended-scalars 35 | 22.0 36 | 37 | ``` 38 | 39 | > Note: 40 | > 41 | > use 22.0 or above for graphql-java 22.x and above 42 | > 43 | > use 21.0 for graphql-java 21.x 44 | > 45 | > use 20.2 for graphql-java 20.x 46 | > 47 | 48 | ## How to use extended scalars 49 | 50 | ### Direct use 51 | 52 | Register the scalar with `graphql-java` 53 | 54 | ```java 55 | RuntimeWiring.newRuntimeWiring().scalar(ExtendedScalars.DateTime) 56 | ``` 57 | 58 | ### Spring for GraphQL 59 | 60 | If you are using [Spring for GraphQL](https://docs.spring.io/spring-graphql/docs/current/reference/html/), register the scalar with `RuntimeWiringConfigurer` 61 | 62 | ```java 63 | @Configuration 64 | public class GraphQlConfig { 65 | @Bean 66 | public RuntimeWiringConfigurer runtimeWiringConfigurer() { 67 | return wiringBuilder -> wiringBuilder.scalar(ExtendedScalars.DateTime); 68 | } 69 | } 70 | ``` 71 | 72 | ### Netflix DGS 73 | 74 | Note: Netflix also wraps this library in `com.netflix.graphql.dgs:graphql-dgs-extended-scalars` for [automatic registration](https://netflix.github.io/dgs/scalars/#automatically-register-scalar-extensions-via-graphql-dgs-extended-scalars). 75 | 76 | If you are using [Netflix DGS](https://netflix.github.io/dgs), please see the following docs: 77 | - [registration through runtime wiring](https://netflix.github.io/dgs/scalars/#register-scalar-extensions-via-dgsruntimewiring) 78 | - [configuration documentation](https://netflix.github.io/dgs/configuration/#dgs-extended-scalars-graphql-dgs-extended-scalars) 79 | 80 | ## How to add extended scalars to your schema 81 | 82 | The GraphQL Specification recommends the use of the [@specifiedBy](https://spec.graphql.org/October2021/#sec--specifiedBy) built-in schema directive to provide a scalar specification URL for specifying the behavior of custom scalar types. 83 | 84 | ```graphql 85 | directive @specifiedBy(url: String!) on SCALAR 86 | ``` 87 | 88 | To use a extended scalar in your schema, define the scalar like shown below for `DateTime` 89 | 90 | ```graphql 91 | scalar DateTime 92 | @specifiedBy(url: "https://scalars.graphql.org/andimarek/date-time.html") 93 | 94 | type Something { 95 | someDateTime: DateTime 96 | } 97 | ``` 98 | 99 | # Custom Scalars 100 | 101 | ## Alias Scalars 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 112 | 113 | 114 |
Scalar DefinitionDescription
110 | scalar AliasedScalar
111 | 
You can create aliases for existing scalars to add more semantic meaning to them.
115 | 116 | For example a link to a social media post could be representing by a `String` but the name `SocialMediaLink` is a 117 | more semantically meaningful name for that scalar type. 118 | 119 | For example, you would build it like this: 120 | 121 | ```java 122 | AliasedScalar socialMediaLink = ExtendedScalars.newAliasedScalar("SocialMediaLink") 123 | .aliasedScalar(Scalars.GraphQLString) 124 | .build() 125 | ``` 126 | 127 | And use it in a SDL schema like this : 128 | 129 | ```graphql 130 | type Customer { 131 | name: String 132 | socialMediaLink: SocialMediaLink 133 | } 134 | ``` 135 | 136 | ## Date & Time Scalars 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 150 | 151 | 152 | 153 | 158 | 159 | 160 | 161 | 167 | 168 | 169 | 170 | 173 | 174 | 175 |
Scalar DefinitionDescription
145 | scalar DateTime
146 |   @specifiedBy(url: 
147 |     "https://scalars.graphql.org/andimarek/date-time.html"
148 |   )
149 | 
A RFC-3339 compliant date time scalar that accepts string values like 1996-12-19T16:39:57-08:00 and produces java.time.OffsetDateTime objects at runtime.
154 | scalar Date
155 |   @specifiedBy(url: 
156 |     "https://tools.ietf.org/html/rfc3339"
157 |   )
A RFC-3339 compliant date scalar that accepts string values like 1996-12-19 and produces java.time.LocalDate objects at runtime.
162 | scalar Time
163 |   @specifiedBy(url: 
164 |     "https://tools.ietf.org/html/rfc3339"
165 |   )
166 | 
A RFC-3339 compliant time scalar that accepts string values like 16:39:57-08:00 and produces java.time.OffsetTime objects at runtime.
171 | scalar LocalTime
172 | 
24-hour clock time string in the format hh:mm:ss.sss or hh:mm:ss if partial seconds is zero and produces java.time.LocalTime objects at runtime.
176 | 177 | An example declaration in SDL might be: 178 | 179 | ```graphql 180 | type Customer { 181 | birthDay: Date 182 | workStartTime: Time 183 | bornAt: DateTime 184 | } 185 | 186 | type Query { 187 | customers(bornAfter: DateTime): [Customers] 188 | } 189 | ``` 190 | 191 | And example query might look like: 192 | 193 | ```graphql 194 | query { 195 | customers(bornAfter: "1996-12-19T16:39:57-08:00") { 196 | birthDay 197 | bornAt 198 | } 199 | } 200 | ``` 201 | 202 | ## ID Scalars 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 216 | 217 | 218 |
Scalar DefinitionDescription
211 | scalar UUID
212 |   @specifiedBy(url: 
213 |     "https://tools.ietf.org/html/rfc4122"
214 |   )
215 | 
A universally unique identifier scalar that accepts uuid values like 2423f0a0-3b81-4115-a189-18df8b35e8fc and produces java.util.UUID instances at runtime.
219 | 220 | ## Numeric Scalars 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 |
Scalar DefinitionDescription
scalar PositiveInt
An Int scalar that MUST be greater than zero.
scalar NegativeInt
An Int scalar that MUST be less than zero.
scalar NonPositiveInt
An Int scalar that MUST be less than or equal to zero.
scalar NonNegativeInt
An Int scalar that MUST be greater than or equal to zero.
scalar PositiveFloat
An Float scalar that MUST be greater than zero.
scalar NegativeFloat
An Float scalar that MUST be less than zero.
scalar NonPositiveFloat
An Float scalar that MUST be less than or equal to zero.
scalar NonNegativeFloat
An Float scalar that MUST be greater than or equal to zero.
260 | 261 | The numeric scalars are derivations of the standard GraphQL `Int` and `Float` scalars that enforce range limits. 262 | 263 | An example declaration in SDL might be: 264 | 265 | ```graphql 266 | type Customer { 267 | name: String 268 | currentHeight: PositiveInt 269 | weightLossGoal: NonPositiveInt 270 | averageWeightLoss: NegativeFloat 271 | } 272 | 273 | type Query { 274 | customers(height: PositiveInt): [Customers] 275 | } 276 | ``` 277 | 278 | And example query might look like: 279 | 280 | ```graphql 281 | query { 282 | customers(height: 182) { 283 | name 284 | height 285 | weightLossGoal 286 | } 287 | } 288 | ``` 289 | 290 | ## Java Primitives 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 |
Scalar DefinitionDescription
scalar GraphQLLong
A scalar which represents java.lang.Long
scalar GraphQLShort
A scalar which represents java.lang.Short
scalar GraphQLByte
A scalar which represents java.lang.Byte
scalar GraphQLBigDecimal
A scalar which represents java.math.BigDecimal
scalar GraphQLBigInteger
A scalar which represents java.math.BigInteger
scalar GraphQLChar
A scalar which represents java.lang.Character
322 | 323 | ## Locale Scalar 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 337 | 338 | 339 |
Scalar DefinitionDescription
332 | scalar Locale
333 |   @specifiedBy(url: 
334 |     "https://tools.ietf.org/html/bcp47"
335 |   )
336 | 
The Locale scalar handles IETF BCP 47 language tags via the JDK method Locale.forLanguageTag.
340 | 341 | ```graphql 342 | type Customer { 343 | name: String 344 | locale: Locale 345 | } 346 | 347 | type Query { 348 | customers(inLocale: Locale): [Customers] 349 | } 350 | ``` 351 | 352 | An example query to look for customers in the Romanian locale might look like: 353 | 354 | ```graphql 355 | query { 356 | customers(inLocale: "ro-RO") { 357 | name 358 | locale 359 | } 360 | } 361 | ``` 362 | 363 | ## Country Code Scalar 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 377 | 378 | 379 |
Scalar DefinitionDescription
372 | scalar CountryCode 
373 |   @specifiedBy(url: 
374 |     "https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2"
375 |   )
376 | 
The CountryCode scalar type as defined by ISO 3166-1 alpha-2.
380 | 381 | An example declaration in SDL might be: 382 | 383 | ```graphql 384 | scalar CountryCode 385 | 386 | type Customer { 387 | name: String 388 | countryCode: CountryCode 389 | } 390 | ``` 391 | 392 | And example query might look like: 393 | 394 | ```graphql 395 | query { 396 | customers(code: "US") { 397 | name 398 | countryCode 399 | } 400 | } 401 | ``` 402 | 403 | ## Currency Scalar 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 417 | 418 | 419 |
Scalar DefinitionDescription
412 | scalar Currency
413 |   @specifiedBy(url: 
414 |     "https://en.wikipedia.org/wiki/ISO_4217"
415 |   )
416 | 
A field whose value is an ISO-4217 currency.
420 | 421 | An example declaration in SDL might be: 422 | 423 | ```graphql 424 | scalar Currency 425 | 426 | type Account { 427 | id: String 428 | currency: Currency 429 | accountNumber: String 430 | } 431 | ``` 432 | 433 | And example query might look like: 434 | 435 | ```graphql 436 | query { 437 | accounts(currency: "USD") { 438 | id 439 | currency 440 | accountNumber 441 | } 442 | } 443 | ``` 444 | 445 | ## URL Scalars 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 459 | 460 | 461 |
Scalar DefinitionDescription
454 | scalar URL
455 |   @specifiedBy(url: 
456 |     "https://www.w3.org/Addressing/URL/url-spec.txt"
457 |   )
458 | 
An url scalar that accepts string values like https://www.w3.org/Addressing/URL/url-spec.txt and produces java.net.URL objects at runtime.
462 | 463 | ## Object / JSON Scalars 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 |
Scalar DefinitionDescription
scalar Object
An object scalar that accepts any object as a scalar value.
scalar JSON
A synonym for the Object scalar, it will accept any object as a scalar value.
479 | 480 | One of the design goals of GraphQL, is that the type system describes the shape of the data returned. 481 | 482 | The `Object` / `JSON` scalars work against this some what because they can return compound values outside the type system. As such 483 | they should be used sparingly. In general your should aim to describe the data via the GraphQL type system where you can and only 484 | resort to the `Object` / `JSON` scalars in very rare circumstances. 485 | 486 | An example might be an extensible GraphQL system where systems can input custom metadata objects that cant be known at 487 | schema type design time. 488 | 489 | An example declaration in SDL might be: 490 | 491 | ```graphql 492 | type Customer { 493 | name: String 494 | associatedMetaData: JSON 495 | } 496 | 497 | type Query { 498 | customers(filterSyntax: JSON): [Customers] 499 | } 500 | ``` 501 | 502 | And example query might look like: 503 | 504 | ```graphql 505 | query { 506 | customers( 507 | filterSyntax: { 508 | startSpan: "First" 509 | matchCriteria: { countryCode: "AU", isoCodes: ["27B-34R", "95A-E23"] } 510 | } 511 | ) { 512 | name 513 | associatedMetaData 514 | } 515 | } 516 | ``` 517 | 518 | Note : The `JSON` scalar is a simple alias type to the `Object` scalar because often the returned data is a blob of JSON. They are 519 | all just objects at runtime in `graphql-java` terms and what network serialization protocol is up to you. Choose whichever name you think 520 | adds more semantic readers to your schema consumers. 521 | 522 | ## Regex Scalars 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 |
Scalar NameDescription
RegexScalarAllows you to build a new scalar via a builder pattern using regular expressions.
534 | 535 | The RegexScalar has a builder where you provide one or more regex patterns that control the acceptable values 536 | for a new scalar. 537 | 538 | You name the scalar and it provides an implementation. 539 | 540 | For example, imagine a `phoneNumber` scalar like this : 541 | 542 | ```java 543 | 544 | RegexScalar phoneNumberScalar = ExtendedScalars.newRegexScalar("phoneNumber") 545 | .addPattern(Pattern.compile("\\([0-9]*\\)[0-9]*")) 546 | .build() 547 | 548 | ``` 549 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | import java.text.SimpleDateFormat 2 | 3 | 4 | plugins { 5 | id 'java' 6 | id 'groovy' 7 | id 'java-library' 8 | id 'maven-publish' 9 | id 'signing' 10 | id "io.github.gradle-nexus.publish-plugin" version "2.0.0" 11 | id "biz.aQute.bnd.builder" version "6.4.0" 12 | } 13 | 14 | java { 15 | toolchain { 16 | languageVersion = JavaLanguageVersion.of(11) 17 | } 18 | } 19 | 20 | def getDevelopmentVersion() { 21 | def output = new StringBuilder() 22 | def error = new StringBuilder() 23 | def gitShortHash = "git -C ${projectDir} rev-parse --short HEAD".execute() 24 | gitShortHash.waitForProcessOutput(output, error) 25 | def gitHash = output.toString().trim() 26 | if (gitHash.isEmpty()) { 27 | println "git hash is empty: error: ${error.toString()}" 28 | throw new IllegalStateException("git hash could not be determined") 29 | } 30 | "0.0.0-" + new SimpleDateFormat('yyyy-MM-dd\'T\'HH-mm-ss').format(new Date()) + "-" + gitHash 31 | } 32 | 33 | def releaseVersion = System.env.RELEASE_VERSION 34 | version = releaseVersion ? releaseVersion : getDevelopmentVersion() 35 | println "Building version = " + version 36 | group = 'com.graphql-java' 37 | 38 | repositories { 39 | mavenCentral() 40 | mavenLocal() 41 | } 42 | 43 | dependencies { 44 | implementation "com.graphql-java:graphql-java:22.3" 45 | 46 | testImplementation "org.spockframework:spock-core:2.3-groovy-3.0" 47 | testImplementation "org.codehaus.groovy:groovy:3.0.23" 48 | } 49 | 50 | task sourcesJar(type: Jar, dependsOn: classes) { 51 | archiveClassifier.set("sources") 52 | from sourceSets.main.allSource 53 | } 54 | 55 | task javadocJar(type: Jar, dependsOn: javadoc) { 56 | archiveClassifier.set("javadoc") 57 | from javadoc.destinationDir 58 | } 59 | 60 | artifacts { 61 | archives sourcesJar 62 | archives javadocJar 63 | } 64 | 65 | test { 66 | useJUnitPlatform() 67 | testLogging { 68 | exceptionFormat = 'full' 69 | } 70 | } 71 | 72 | publishing { 73 | publications { 74 | maven(MavenPublication) { 75 | from components.java 76 | groupId group 77 | artifactId 'graphql-java-extended-scalars' 78 | version version 79 | 80 | artifact sourcesJar 81 | artifact javadocJar 82 | 83 | pom.withXml { 84 | asNode().children().last() + { 85 | resolveStrategy = Closure.DELEGATE_FIRST 86 | name 'graphql-java-extended-scalars' 87 | description 'A library of extended scalars for graphql-java' 88 | url 'https://github.com/graphql-java/graphql-java-extended-scalars' 89 | inceptionYear '2018' 90 | 91 | scm { 92 | url 'https://github.com/graphql-java/graphql-java-extended-scalars' 93 | connection 'scm:git@github.com:graphql-java/graphql-java-extended-scalars.git' 94 | developerConnection 'scm:git@github.com:graphql-java/graphql-java-extended-scalars.git' 95 | } 96 | 97 | licenses { 98 | license { 99 | name 'MIT' 100 | url 'https://github.com/graphql-java/graphql-java/blob/master/LICENSE.md' 101 | distribution 'repo' 102 | } 103 | } 104 | 105 | developers { 106 | developer { 107 | id 'bbakerman' 108 | name 'Brad Baker' 109 | email 'bbakerman@gmail.com' 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | 118 | nexusPublishing { 119 | repositories { 120 | sonatype { 121 | username = System.env.MAVEN_CENTRAL_USER 122 | password = System.env.MAVEN_CENTRAL_PASSWORD 123 | } 124 | } 125 | } 126 | 127 | signing { 128 | def signingKey = System.env.MAVEN_CENTRAL_PGP_KEY 129 | useInMemoryPgpKeys(signingKey, "") 130 | sign publishing.publications 131 | } 132 | 133 | // all publish tasks depend on the build task 134 | tasks.withType(PublishToMavenRepository) { 135 | dependsOn build 136 | } 137 | 138 | jar { 139 | manifest { 140 | attributes('Automatic-Module-Name': 'com.graphqljava.extendedscalars', 141 | '-exportcontents': 'graphql.scalars.*', 142 | '-removeheaders': 'Private-Package') 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/graphql-java/graphql-java-extended-scalars/7faaf0b6f11077e28843ab790ecc5096984fbd5c/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'graphql-java-extended-scalars' 2 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/ExtendedScalars.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars; 2 | 3 | import graphql.PublicApi; 4 | import graphql.scalars.alias.AliasedScalar; 5 | import graphql.scalars.country.code.CountryCodeScalar; 6 | import graphql.scalars.currency.CurrencyScalar; 7 | import graphql.scalars.datetime.DateScalar; 8 | import graphql.scalars.datetime.DateTimeScalar; 9 | import graphql.scalars.datetime.LocalTimeCoercing; 10 | import graphql.scalars.datetime.TimeScalar; 11 | import graphql.scalars.java.JavaPrimitives; 12 | import graphql.scalars.locale.LocaleScalar; 13 | import graphql.scalars.id.UUIDScalar; 14 | import graphql.scalars.numeric.NegativeFloatScalar; 15 | import graphql.scalars.numeric.NegativeIntScalar; 16 | import graphql.scalars.numeric.NonNegativeFloatScalar; 17 | import graphql.scalars.numeric.NonNegativeIntScalar; 18 | import graphql.scalars.numeric.NonPositiveFloatScalar; 19 | import graphql.scalars.numeric.NonPositiveIntScalar; 20 | import graphql.scalars.numeric.PositiveFloatScalar; 21 | import graphql.scalars.numeric.PositiveIntScalar; 22 | import graphql.scalars.object.JsonScalar; 23 | import graphql.scalars.object.ObjectScalar; 24 | import graphql.scalars.regex.RegexScalar; 25 | import graphql.scalars.url.UrlScalar; 26 | import graphql.schema.GraphQLScalarType; 27 | 28 | /** 29 | * This is the API entry point for all the extended scalars 30 | */ 31 | @PublicApi 32 | public class ExtendedScalars { 33 | 34 | /** 35 | * An RFC-3339 compliant date time scalar that accepts string values like `1996-12-19T16:39:57-08:00` and produces 36 | * `java.time.OffsetDateTime` objects at runtime. 37 | *

38 | * Its {@link graphql.schema.Coercing#serialize(java.lang.Object)} and {@link graphql.schema.Coercing#parseValue(java.lang.Object)} methods 39 | * accept OffsetDateTime, ZoneDateTime and formatted Strings as valid objects. 40 | *

41 | * See the rfc3339 spec for more details on the format. 42 | * 43 | * @see java.time.OffsetDateTime 44 | * @see java.time.ZonedDateTime 45 | */ 46 | public static final GraphQLScalarType DateTime = DateTimeScalar.INSTANCE; 47 | 48 | /** 49 | * An RFC-3339 compliant date scalar that accepts string values like `1996-12-19` and produces 50 | * `java.time.LocalDate` objects at runtime. 51 | *

52 | * Its {@link graphql.schema.Coercing#serialize(java.lang.Object)} and {@link graphql.schema.Coercing#parseValue(java.lang.Object)} methods 53 | * accept date {@link java.time.temporal.TemporalAccessor}s and formatted Strings as valid objects. 54 | *

55 | * See the rfc3339 spec for more details on the format. 56 | * 57 | * @see java.time.LocalDate 58 | */ 59 | public static final GraphQLScalarType Date = DateScalar.INSTANCE; 60 | /** 61 | * An RFC-3339 compliant time scalar that accepts string values like `6:39:57-08:00` and produces 62 | * `java.time.OffsetTime` objects at runtime. 63 | *

64 | * Its {@link graphql.schema.Coercing#serialize(java.lang.Object)} and {@link graphql.schema.Coercing#parseValue(java.lang.Object)} methods 65 | * accept time {@link java.time.temporal.TemporalAccessor}s and formatted Strings as valid objects. 66 | *

67 | * See the rfc3339 spec for more details on the format. 68 | * 69 | * @see java.time.OffsetTime 70 | */ 71 | public static final GraphQLScalarType Time = TimeScalar.INSTANCE; 72 | 73 | /** 74 | * A 24-hour local time scalar that accepts strings like `hh:mm:ss` and `hh:mm:ss.sss` and produces 75 | * `java.time.LocalTime` objects at runtime. 76 | *

77 | * Its {@link graphql.schema.Coercing#serialize(java.lang.Object)} and {@link graphql.schema.Coercing#parseValue(java.lang.Object)} methods 78 | * accept time {@link java.time.temporal.TemporalAccessor}s and formatted Strings as valid objects. 79 | * 80 | * @see java.time.LocalTime 81 | */ 82 | public static final GraphQLScalarType LocalTime = GraphQLScalarType.newScalar() 83 | .name("LocalTime") 84 | .description("24-hour clock time value string in the format `hh:mm:ss` or `hh:mm:ss.sss`.") 85 | .coercing(new LocalTimeCoercing()) 86 | .build(); 87 | 88 | /** 89 | * An object scalar allows you to have a multi level data value without defining it in the graphql schema. 90 | *

91 | * It might be useful when you have opaque data coming from a backend system that you want to pass on 92 | * but cant provide the actual graphql schema definition for. 93 | *

94 | * Use this with caution since is breaks one of the key benefits 95 | * of graphql, which is that a schema describes the shape of the data that can be queried. 96 | * 97 | *

98 | * This can be declared as follows : 99 | *

100 |      * {@code
101 |      *
102 |      * type Customer {
103 |      *      name : String
104 |      *      backendDetails : Object
105 |      * }
106 |      * }
107 |      * 
108 | * 109 | * @see #Json 110 | */ 111 | public static final GraphQLScalarType Object = ObjectScalar.INSTANCE; 112 | 113 | /** 114 | * A synonym class for the {@link #Object} scalar, since some people prefer their SDL to look like the following : 115 | * 116 | *
117 |      * {@code
118 |      *
119 |      * type Customer {
120 |      *      name : String
121 |      *      backendDetails : JSON
122 |      * }
123 |      * }
124 |      * 
125 | * 126 | * @see graphql.scalars.ExtendedScalars#Object 127 | */ 128 | public static final GraphQLScalarType Json = JsonScalar.INSTANCE; 129 | 130 | /** 131 | * A URL scalar that accepts URL strings and produces {@link java.net.URL} objects at runtime 132 | */ 133 | public static final GraphQLScalarType Url = UrlScalar.INSTANCE; 134 | 135 | /** 136 | * A Locale scalar that accepts a IETF BCP 47 language tag string and produces {@link 137 | * java.util.Locale} objects at runtime. 138 | */ 139 | public static final GraphQLScalarType Locale = LocaleScalar.INSTANCE; 140 | 141 | /** 142 | * A field whose value is an ISO-4217 currency. 143 | * See the ISO-4217 for more details. 144 | */ 145 | public static final GraphQLScalarType Currency = CurrencyScalar.INSTANCE; 146 | 147 | /** 148 | * The CountryCode scalar type as defined by ISO 3166-1 alpha-2. 149 | * See the ISO 3166-1 alpha-2 for more details. 150 | */ 151 | public static final GraphQLScalarType CountryCode = CountryCodeScalar.INSTANCE; 152 | 153 | /** 154 | * A UUID scalar that accepts a universally unique identifier and produces {@link 155 | * java.util.UUID} objects at runtime. 156 | */ 157 | public static final GraphQLScalarType UUID = UUIDScalar.INSTANCE; 158 | 159 | /** 160 | * An `Int` scalar that MUST be greater than zero 161 | * 162 | * @see graphql.Scalars#GraphQLInt 163 | */ 164 | public static final GraphQLScalarType PositiveInt = PositiveIntScalar.INSTANCE; 165 | /** 166 | * An `Int` scalar that MUST be less than zero 167 | * 168 | * @see graphql.Scalars#GraphQLInt 169 | */ 170 | public static final GraphQLScalarType NegativeInt = NegativeIntScalar.INSTANCE; 171 | /** 172 | * An `Int` scalar that MUST be less than or equal to zero 173 | * 174 | * @see graphql.Scalars#GraphQLInt 175 | */ 176 | public static final GraphQLScalarType NonPositiveInt = NonPositiveIntScalar.INSTANCE; 177 | /** 178 | * An `Int` scalar that MUST be greater than or equal to zero 179 | * 180 | * @see graphql.Scalars#GraphQLInt 181 | */ 182 | public static final GraphQLScalarType NonNegativeInt = NonNegativeIntScalar.INSTANCE; 183 | 184 | /** 185 | * An `Float` scalar that MUST be greater than zero 186 | * 187 | * @see graphql.Scalars#GraphQLFloat 188 | */ 189 | public static final GraphQLScalarType PositiveFloat = PositiveFloatScalar.INSTANCE; 190 | /** 191 | * An `Float` scalar that MUST be less than zero 192 | * 193 | * @see graphql.Scalars#GraphQLFloat 194 | */ 195 | public static final GraphQLScalarType NegativeFloat = NegativeFloatScalar.INSTANCE; 196 | /** 197 | * An `Float` scalar that MUST be less than or equal to zero 198 | * 199 | * @see graphql.Scalars#GraphQLFloat 200 | */ 201 | public static final GraphQLScalarType NonPositiveFloat = NonPositiveFloatScalar.INSTANCE; 202 | /** 203 | * An `Float` scalar that MUST be greater than or equal to zero 204 | * 205 | * @see graphql.Scalars#GraphQLFloat 206 | */ 207 | public static final GraphQLScalarType NonNegativeFloat = NonNegativeFloatScalar.INSTANCE; 208 | 209 | 210 | /** 211 | * A builder of a scalar that uses one or more regular expression {@link java.util.regex.Pattern}s to control 212 | * the acceptable values for that scalar. 213 | *

214 | * The scalar converts any passed in objects to Strings first and them matches it against the provided 215 | * scalars to ensure its an acceptable value. 216 | * 217 | * @param name the name of the scalar 218 | * 219 | * @return a builder of a regex scalar 220 | */ 221 | public static RegexScalar.Builder newRegexScalar(String name) { 222 | return new RegexScalar.Builder().name(name); 223 | } 224 | 225 | /** 226 | * This allows an existing scalar to be wrapped and aliased with a new name. 227 | *

228 | * For example you may take a `String` scalar and alias it as `SocialMediaLink` if that helps introduce 229 | * more semantic meaning to your type system. 230 | *

231 |      * {@code
232 |      *
233 |      * type Customer {
234 |      *      name : String
235 |      *      socialMediaLink : SocialMediaLink
236 |      * }
237 |      * }
238 |      * 
239 | *

240 | * A future version of the graphql specification may add this capability but in the meantime you can use this facility. 241 | * 242 | * @param name the name of the aliased scalar 243 | * 244 | * @return a builder of a aliased scalar 245 | */ 246 | public static AliasedScalar.Builder newAliasedScalar(String name) { 247 | return new AliasedScalar.Builder().name(name); 248 | } 249 | 250 | /** 251 | * This represents the "Long" type which is a representation of java.lang.Long 252 | */ 253 | public static final GraphQLScalarType GraphQLLong = JavaPrimitives.GraphQLLong; 254 | 255 | /** 256 | * This represents the "Short" type which is a representation of java.lang.Short 257 | */ 258 | public static final GraphQLScalarType GraphQLShort = JavaPrimitives.GraphQLShort; 259 | 260 | /** 261 | * This represents the "Byte" type which is a representation of java.lang.Byte 262 | */ 263 | public static final GraphQLScalarType GraphQLByte = JavaPrimitives.GraphQLByte; 264 | 265 | /** 266 | * This represents the "BigDecimal" type which is a representation of java.math.BigDecimal 267 | */ 268 | public static final GraphQLScalarType GraphQLBigDecimal = JavaPrimitives.GraphQLBigDecimal; 269 | 270 | /** 271 | * This represents the "BigInteger" type which is a representation of java.math.BigInteger 272 | */ 273 | public static final GraphQLScalarType GraphQLBigInteger = JavaPrimitives.GraphQLBigInteger; 274 | 275 | /** 276 | * This represents the "Char" type which is a representation of java.lang.Character 277 | */ 278 | public static final GraphQLScalarType GraphQLChar = JavaPrimitives.GraphQLChar; 279 | 280 | } 281 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/alias/AliasedScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.alias; 2 | 3 | import graphql.Assert; 4 | import graphql.Internal; 5 | import graphql.language.Value; 6 | import graphql.schema.Coercing; 7 | import graphql.schema.CoercingParseLiteralException; 8 | import graphql.schema.CoercingParseValueException; 9 | import graphql.schema.CoercingSerializeException; 10 | import graphql.schema.GraphQLScalarType; 11 | 12 | import java.util.Map; 13 | 14 | /** 15 | * Access this via {@link graphql.scalars.ExtendedScalars#newAliasedScalar(String)} 16 | */ 17 | @Internal 18 | public final class AliasedScalar { 19 | 20 | private AliasedScalar() {} 21 | 22 | /** 23 | * A builder for {@link graphql.scalars.alias.AliasedScalar} 24 | */ 25 | public static class Builder { 26 | private String name; 27 | private String description; 28 | private GraphQLScalarType aliasedScalar; 29 | 30 | /** 31 | * Sets the name of the aliased scalar 32 | * 33 | * @param name the name of the aliased scalar 34 | * 35 | * @return this builder 36 | */ 37 | public Builder name(String name) { 38 | this.name = name; 39 | return this; 40 | } 41 | 42 | /** 43 | * Sets the description of the aliased scalar 44 | * 45 | * @param description the description of the aliased scalar 46 | * 47 | * @return this builder 48 | */ 49 | public Builder description(String description) { 50 | this.description = description; 51 | return this; 52 | } 53 | 54 | /** 55 | * Sets the scalar that is to be aliased 56 | * 57 | * @param aliasedScalar the scalar that is to be aliased 58 | * 59 | * @return this builder 60 | */ 61 | public Builder aliasedScalar(GraphQLScalarType aliasedScalar) { 62 | this.aliasedScalar = aliasedScalar; 63 | return this; 64 | } 65 | 66 | /** 67 | * @return the built {@link AliasedScalar} 68 | */ 69 | public GraphQLScalarType build() { 70 | Assert.assertNotNull(name); 71 | return aliasedScalarImpl(name, description, aliasedScalar); 72 | } 73 | } 74 | 75 | 76 | private static GraphQLScalarType aliasedScalarImpl(String name, String description, GraphQLScalarType aliasedScalar) { 77 | Assert.assertNotNull(aliasedScalar); 78 | Coercing coercing = new Coercing() { 79 | @Override 80 | public Object serialize(Object input) throws CoercingSerializeException { 81 | return aliasedScalar.getCoercing().serialize(input); 82 | } 83 | 84 | @Override 85 | public Object parseValue(Object input) throws CoercingParseValueException { 86 | return aliasedScalar.getCoercing().parseValue(input); 87 | } 88 | 89 | @Override 90 | public Object parseLiteral(Object input) throws CoercingParseLiteralException { 91 | return aliasedScalar.getCoercing().parseLiteral(input); 92 | } 93 | 94 | @Override 95 | public Object parseLiteral(Object input, Map variables) throws CoercingParseLiteralException { 96 | Coercing c = aliasedScalar.getCoercing(); 97 | return c.parseLiteral(input, variables); 98 | } 99 | 100 | @Override 101 | public Value valueToLiteral(Object input) { 102 | return aliasedScalar.getCoercing().valueToLiteral(input); 103 | } 104 | }; 105 | return GraphQLScalarType.newScalar() 106 | .name(name) 107 | .description(description) 108 | .coercing(coercing) 109 | .build(); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/country/code/CountryCode.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.country.code; 2 | 3 | /** 4 | * The CountryCode list as defined by ISO 3166-1 alpha-2. 5 | * See the ISO 3166-1 alpha-2 for more details. 6 | */ 7 | public enum CountryCode { 8 | AD, AE, AF, AG, AI, AL, AM, AO, AQ, AR, AS, AT, AU, AW, AX, AZ, BA, BB, BD, BE, BF, BG, BH, BI, BJ, BL, BM, BN, BO, 9 | BQ, BR, BS, BT, BV, BW, BY, BZ, CA, CC, CD, CF, CG, CH, CI, CK, CL, CM, CN, CO, CR, CU, CV, CW, CX, CY, CZ, DE, DJ, 10 | DK, DM, DO, DZ, EC, EE, EG, EH, ER, ES, ET, FI, FJ, FK, FM, FO, FR, GA, GB, GD, GE, GF, GG, GH, GI, GL, GM, GN, GP, 11 | GQ, GR, GS, GT, GU, GW, GY, HK, HM, HN, HR, HT, HU, ID, IE, IL, IM, IN, IO, IQ, IR, IS, IT, JE, JM, JO, JP, KE, KG, 12 | KH, KI, KM, KN, KP, KR, KW, KY, KZ, LA, LB, LC, LI, LK, LR, LS, LT, LU, LV, LY, MA, MC, MD, ME, MF, MG, MH, MK, ML, 13 | MM, MN, MO, MP, MQ, MR, MS, MT, MU, MV, MW, MX, MY, MZ, NA, NC, NE, NF, NG, NI, NL, NO, NP, NR, NU, NZ, OM, PA, PE, 14 | PF, PG, PH, PK, PL, PM, PN, PR, PS, PT, PW, PY, QA, RE, RO, RS, RU, RW, SA, SB, SC, SD, SE, SG, SH, SI, SJ, SK, SL, 15 | SM, SN, SO, SR, SS, ST, SV, SX, SY, SZ, TC, TD, TF, TG, TH, TJ, TK, TL, TM, TN, TO, TR, TT, TV, TW, TZ, UA, UG, UM, 16 | US, UY, UZ, VA, VC, VE, VG, VI, VN, VU, WF, WS, YE, YT, ZA, ZM, ZW 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/country/code/CountryCodeScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.country.code; 2 | 3 | import graphql.Internal; 4 | import graphql.language.StringValue; 5 | import graphql.language.Value; 6 | import graphql.schema.*; 7 | 8 | import java.util.function.Function; 9 | 10 | import static graphql.scalars.util.Kit.typeName; 11 | 12 | /** 13 | * Access this via {@link graphql.scalars.ExtendedScalars#CountryCode} 14 | */ 15 | @Internal 16 | public class CountryCodeScalar { 17 | 18 | public static final GraphQLScalarType INSTANCE; 19 | 20 | static { 21 | Coercing coercing = new Coercing() { 22 | 23 | @Override 24 | public String serialize(Object input) throws CoercingSerializeException { 25 | CountryCode countryCode = parseCountryCode(input, CoercingParseValueException::new); 26 | return countryCode.name(); 27 | } 28 | 29 | @Override 30 | public CountryCode parseValue(Object input) throws CoercingParseValueException { 31 | return parseCountryCode(input, CoercingParseValueException::new); 32 | } 33 | 34 | @Override 35 | public CountryCode parseLiteral(Object input) throws CoercingParseLiteralException { 36 | if (!(input instanceof StringValue)) { 37 | throw new CoercingParseLiteralException("Expected AST type 'StringValue' but was '" + typeName(input) + "'."); 38 | } 39 | String stringValue = ((StringValue) input).getValue(); 40 | return parseCountryCode(stringValue, CoercingParseLiteralException::new); 41 | 42 | } 43 | 44 | @Override 45 | public Value valueToLiteral(Object input) { 46 | String s = serialize(input); 47 | return StringValue.newStringValue(s).build(); 48 | } 49 | 50 | private CountryCode parseCountryCode(Object input, Function exceptionMaker) { 51 | final CountryCode result; 52 | if (input instanceof String) { 53 | try { 54 | result = CountryCode.valueOf((String) input); 55 | } catch (NullPointerException | IllegalArgumentException ex) { 56 | throw exceptionMaker.apply("Invalid ISO 3166-1 alpha-2 value : '" + input + "'. because of : '" + ex.getMessage() + "'"); 57 | } 58 | } else if (input instanceof CountryCode) { 59 | result = (CountryCode) input; 60 | } else { 61 | throw exceptionMaker.apply("Expected a 'String' or 'CountryCode' but was '" + typeName(input) + "'."); 62 | } 63 | return result; 64 | } 65 | }; 66 | 67 | INSTANCE = GraphQLScalarType.newScalar() 68 | .name("CountryCode") 69 | .description("The CountryCode scalar type as defined by ISO 3166-1 alpha-2.") 70 | .coercing(coercing).build(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/currency/CurrencyScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.currency; 2 | 3 | import graphql.Internal; 4 | import graphql.language.StringValue; 5 | import graphql.language.Value; 6 | import graphql.schema.*; 7 | 8 | import java.util.Currency; 9 | import java.util.function.Function; 10 | 11 | import static graphql.scalars.util.Kit.typeName; 12 | 13 | /** 14 | * Access this via {@link graphql.scalars.ExtendedScalars#Currency} 15 | */ 16 | @Internal 17 | public class CurrencyScalar { 18 | 19 | public static final GraphQLScalarType INSTANCE; 20 | 21 | static { 22 | Coercing coercing = new Coercing() { 23 | @Override 24 | public String serialize(Object input) throws CoercingSerializeException { 25 | Currency currency = parseCurrency(input, CoercingSerializeException::new); 26 | return currency.getCurrencyCode(); 27 | } 28 | 29 | @Override 30 | public Currency parseValue(Object input) throws CoercingParseValueException { 31 | return parseCurrency(input, CoercingParseValueException::new); 32 | } 33 | 34 | 35 | @Override 36 | public Currency parseLiteral(Object input) throws CoercingParseLiteralException { 37 | if (!(input instanceof StringValue)) { 38 | throw new CoercingParseLiteralException("Expected AST type 'StringValue' but was '" + typeName(input) + "'."); 39 | } 40 | String stringValue = ((StringValue) input).getValue(); 41 | return parseCurrency(stringValue, CoercingParseLiteralException::new); 42 | } 43 | 44 | @Override 45 | public Value valueToLiteral(Object input) { 46 | String serializedInput = serialize(input); 47 | return StringValue.newStringValue(serializedInput).build(); 48 | } 49 | 50 | 51 | private Currency parseCurrency(Object input, Function exceptionMaker) { 52 | final Currency result; 53 | if (input instanceof Currency) { 54 | result = (Currency) input; 55 | } else if (input instanceof String) { 56 | try { 57 | result = Currency.getInstance((String) input); 58 | } catch (NullPointerException | IllegalArgumentException ex) { 59 | throw exceptionMaker.apply("Invalid ISO 4217 value : '" + input + "'. because of : '" + ex.getMessage() + "'"); 60 | } 61 | } else { 62 | throw exceptionMaker.apply("Expected a 'String' or 'Currency' but was '" + typeName(input) + "'."); 63 | } 64 | return result; 65 | } 66 | }; 67 | 68 | INSTANCE = GraphQLScalarType.newScalar() 69 | .name("Currency") 70 | .description("An ISO-4217 compliant Currency Scalar") 71 | .coercing(coercing).build(); 72 | } 73 | } -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/datetime/DateScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.datetime; 2 | 3 | import graphql.Internal; 4 | import graphql.language.StringValue; 5 | import graphql.language.Value; 6 | import graphql.schema.Coercing; 7 | import graphql.schema.CoercingParseLiteralException; 8 | import graphql.schema.CoercingParseValueException; 9 | import graphql.schema.CoercingSerializeException; 10 | import graphql.schema.GraphQLScalarType; 11 | 12 | import java.time.DateTimeException; 13 | import java.time.LocalDate; 14 | import java.time.format.DateTimeFormatter; 15 | import java.time.format.DateTimeParseException; 16 | import java.time.temporal.TemporalAccessor; 17 | import java.util.function.Function; 18 | 19 | import static graphql.scalars.util.Kit.typeName; 20 | 21 | /** 22 | * Access this via {@link graphql.scalars.ExtendedScalars#Date} 23 | */ 24 | @Internal 25 | public final class DateScalar { 26 | 27 | private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); 28 | 29 | public static final GraphQLScalarType INSTANCE; 30 | 31 | private DateScalar() {} 32 | 33 | static { 34 | Coercing coercing = new Coercing() { 35 | @Override 36 | public String serialize(Object input) throws CoercingSerializeException { 37 | TemporalAccessor temporalAccessor; 38 | if (input instanceof TemporalAccessor) { 39 | temporalAccessor = (TemporalAccessor) input; 40 | } else if (input instanceof String) { 41 | temporalAccessor = parseLocalDate(input.toString(), CoercingSerializeException::new); 42 | } else { 43 | throw new CoercingSerializeException( 44 | "Expected a 'String' or 'java.time.temporal.TemporalAccessor' but was '" + typeName(input) + "'." 45 | ); 46 | } 47 | try { 48 | return DATE_FORMATTER.format(temporalAccessor); 49 | } catch (DateTimeException e) { 50 | throw new CoercingSerializeException( 51 | "Unable to turn TemporalAccessor into full date because of : '" + e.getMessage() + "'." 52 | ); 53 | } 54 | } 55 | 56 | @Override 57 | public LocalDate parseValue(Object input) throws CoercingParseValueException { 58 | TemporalAccessor temporalAccessor; 59 | if (input instanceof TemporalAccessor) { 60 | temporalAccessor = (TemporalAccessor) input; 61 | } else if (input instanceof String) { 62 | temporalAccessor = parseLocalDate(input.toString(), CoercingParseValueException::new); 63 | } else { 64 | throw new CoercingParseValueException( 65 | "Expected a 'String' or 'java.time.temporal.TemporalAccessor' but was '" + typeName(input) + "'." 66 | ); 67 | } 68 | try { 69 | return LocalDate.from(temporalAccessor); 70 | } catch (DateTimeException e) { 71 | throw new CoercingParseValueException( 72 | "Unable to turn TemporalAccessor into full date because of : '" + e.getMessage() + "'." 73 | ); 74 | } 75 | } 76 | 77 | @Override 78 | public LocalDate parseLiteral(Object input) throws CoercingParseLiteralException { 79 | if (!(input instanceof StringValue)) { 80 | throw new CoercingParseLiteralException( 81 | "Expected AST type 'StringValue' but was '" + typeName(input) + "'." 82 | ); 83 | } 84 | return parseLocalDate(((StringValue) input).getValue(), CoercingParseLiteralException::new); 85 | } 86 | 87 | @Override 88 | public Value valueToLiteral(Object input) { 89 | String s = serialize(input); 90 | return StringValue.newStringValue(s).build(); 91 | } 92 | 93 | private LocalDate parseLocalDate(String s, Function exceptionMaker) { 94 | try { 95 | TemporalAccessor temporalAccessor = DATE_FORMATTER.parse(s); 96 | return LocalDate.from(temporalAccessor); 97 | } catch (DateTimeParseException e) { 98 | throw exceptionMaker.apply("Invalid RFC3339 full date value : '" + s + "'. because of : '" + e.getMessage() + "'"); 99 | } 100 | } 101 | }; 102 | 103 | INSTANCE = GraphQLScalarType.newScalar() 104 | .name("Date") 105 | .description("An RFC-3339 compliant Full Date Scalar") 106 | .coercing(coercing) 107 | .build(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/datetime/DateTimeScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.datetime; 2 | 3 | import graphql.Internal; 4 | import graphql.language.StringValue; 5 | import graphql.language.Value; 6 | import graphql.schema.Coercing; 7 | import graphql.schema.CoercingParseLiteralException; 8 | import graphql.schema.CoercingParseValueException; 9 | import graphql.schema.CoercingSerializeException; 10 | import graphql.schema.GraphQLScalarType; 11 | 12 | import java.time.DateTimeException; 13 | import java.time.OffsetDateTime; 14 | import java.time.ZonedDateTime; 15 | import java.time.format.DateTimeFormatter; 16 | import java.time.format.DateTimeFormatterBuilder; 17 | import java.time.format.DateTimeParseException; 18 | import java.util.function.Function; 19 | 20 | import static graphql.scalars.util.Kit.typeName; 21 | import static java.time.format.DateTimeFormatter.ISO_LOCAL_DATE; 22 | import static java.time.temporal.ChronoField.HOUR_OF_DAY; 23 | import static java.time.temporal.ChronoField.MINUTE_OF_HOUR; 24 | import static java.time.temporal.ChronoField.NANO_OF_SECOND; 25 | import static java.time.temporal.ChronoField.OFFSET_SECONDS; 26 | import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; 27 | 28 | /** 29 | * Access this via {@link graphql.scalars.ExtendedScalars#DateTime} 30 | */ 31 | @Internal 32 | public final class DateTimeScalar { 33 | 34 | public static final GraphQLScalarType INSTANCE; 35 | 36 | private DateTimeScalar() {} 37 | private static final DateTimeFormatter customOutputFormatter = getCustomDateTimeFormatter(); 38 | 39 | static { 40 | Coercing coercing = new Coercing() { 41 | @Override 42 | public String serialize(Object input) throws CoercingSerializeException { 43 | OffsetDateTime offsetDateTime; 44 | if (input instanceof OffsetDateTime) { 45 | offsetDateTime = (OffsetDateTime) input; 46 | } else if (input instanceof ZonedDateTime) { 47 | offsetDateTime = ((ZonedDateTime) input).toOffsetDateTime(); 48 | } else if (input instanceof String) { 49 | offsetDateTime = parseOffsetDateTime(input.toString(), CoercingSerializeException::new); 50 | } else { 51 | throw new CoercingSerializeException( 52 | "Expected something we can convert to 'java.time.OffsetDateTime' but was '" + typeName(input) + "'." 53 | ); 54 | } 55 | try { 56 | return customOutputFormatter.format(offsetDateTime); 57 | } catch (DateTimeException e) { 58 | throw new CoercingSerializeException( 59 | "Unable to turn TemporalAccessor into OffsetDateTime because of : '" + e.getMessage() + "'." 60 | ); 61 | } 62 | } 63 | 64 | @Override 65 | public OffsetDateTime parseValue(Object input) throws CoercingParseValueException { 66 | OffsetDateTime offsetDateTime; 67 | if (input instanceof OffsetDateTime) { 68 | offsetDateTime = (OffsetDateTime) input; 69 | } else if (input instanceof ZonedDateTime) { 70 | offsetDateTime = ((ZonedDateTime) input).toOffsetDateTime(); 71 | } else if (input instanceof String) { 72 | offsetDateTime = parseOffsetDateTime(input.toString(), CoercingParseValueException::new); 73 | } else { 74 | throw new CoercingParseValueException( 75 | "Expected a 'String' but was '" + typeName(input) + "'." 76 | ); 77 | } 78 | return offsetDateTime; 79 | } 80 | 81 | @Override 82 | public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralException { 83 | if (!(input instanceof StringValue)) { 84 | throw new CoercingParseLiteralException( 85 | "Expected AST type 'StringValue' but was '" + typeName(input) + "'." 86 | ); 87 | } 88 | return parseOffsetDateTime(((StringValue) input).getValue(), CoercingParseLiteralException::new); 89 | } 90 | 91 | @Override 92 | public Value valueToLiteral(Object input) { 93 | String s = serialize(input); 94 | return StringValue.newStringValue(s).build(); 95 | } 96 | 97 | private OffsetDateTime parseOffsetDateTime(String s, Function exceptionMaker) { 98 | try { 99 | OffsetDateTime parse = OffsetDateTime.parse(s, DateTimeFormatter.ISO_OFFSET_DATE_TIME); 100 | if (parse.get(OFFSET_SECONDS) == 0 && s.endsWith("-00:00")) { 101 | throw exceptionMaker.apply("Invalid value : '" + s + "'. Negative zero offset is not allowed"); 102 | } 103 | return parse; 104 | } catch (DateTimeParseException e) { 105 | throw exceptionMaker.apply("Invalid RFC3339 value : '" + s + "'. because of : '" + e.getMessage() + "'"); 106 | } 107 | } 108 | }; 109 | 110 | INSTANCE = GraphQLScalarType.newScalar() 111 | .name("DateTime") 112 | .description("A slightly refined version of RFC-3339 compliant DateTime Scalar") 113 | .specifiedByUrl("https://scalars.graphql.org/andimarek/date-time") // TODO: Change to .specifiedByURL when builder added to graphql-java 114 | .coercing(coercing) 115 | .build(); 116 | } 117 | 118 | private static DateTimeFormatter getCustomDateTimeFormatter() { 119 | return new DateTimeFormatterBuilder() 120 | .parseCaseInsensitive() 121 | .append(ISO_LOCAL_DATE) 122 | .appendLiteral('T') 123 | .appendValue(HOUR_OF_DAY, 2) 124 | .appendLiteral(':') 125 | .appendValue(MINUTE_OF_HOUR, 2) 126 | .appendLiteral(':') 127 | .appendValue(SECOND_OF_MINUTE, 2) 128 | .appendFraction(NANO_OF_SECOND, 3, 3, true) 129 | .appendOffset("+HH:MM", "Z") 130 | .toFormatter(); 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/datetime/LocalTimeCoercing.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.datetime; 2 | 3 | import graphql.language.StringValue; 4 | import graphql.schema.Coercing; 5 | import graphql.schema.CoercingParseLiteralException; 6 | import graphql.schema.CoercingParseValueException; 7 | import graphql.schema.CoercingSerializeException; 8 | 9 | import java.time.DateTimeException; 10 | import java.time.LocalTime; 11 | import java.time.format.DateTimeFormatter; 12 | import java.time.format.DateTimeParseException; 13 | import java.time.temporal.TemporalAccessor; 14 | import java.util.function.Function; 15 | 16 | import static graphql.scalars.util.Kit.typeName; 17 | 18 | public class LocalTimeCoercing implements Coercing { 19 | 20 | private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ISO_LOCAL_TIME; 21 | 22 | @Override 23 | public String serialize(final Object input) throws CoercingSerializeException { 24 | TemporalAccessor temporalAccessor; 25 | if (input instanceof TemporalAccessor) { 26 | temporalAccessor = (TemporalAccessor) input; 27 | } else if (input instanceof String) { 28 | temporalAccessor = parseTime(input.toString(), CoercingSerializeException::new); 29 | } else { 30 | throw new CoercingSerializeException( 31 | "Expected a 'String' or 'java.time.temporal.TemporalAccessor' but was '" + typeName(input) + "'." 32 | ); 33 | } 34 | try { 35 | return DATE_FORMATTER.format(temporalAccessor); 36 | } catch (DateTimeException e) { 37 | throw new CoercingSerializeException( 38 | "Unable to turn TemporalAccessor into full time because of : '" + e.getMessage() + "'." 39 | ); 40 | } 41 | } 42 | 43 | @Override 44 | public LocalTime parseValue(final Object input) throws CoercingParseValueException { 45 | TemporalAccessor temporalAccessor; 46 | if (input instanceof TemporalAccessor) { 47 | temporalAccessor = (TemporalAccessor) input; 48 | } else if (input instanceof String) { 49 | temporalAccessor = parseTime(input.toString(), CoercingParseValueException::new); 50 | } else { 51 | throw new CoercingParseValueException( 52 | "Expected a 'String' or 'java.time.temporal.TemporalAccessor' but was '" + typeName(input) + "'." 53 | ); 54 | } 55 | try { 56 | return LocalTime.from(temporalAccessor); 57 | } catch (DateTimeException e) { 58 | throw new CoercingParseValueException( 59 | "Unable to turn TemporalAccessor into full time because of : '" + e.getMessage() + "'." 60 | ); 61 | } 62 | } 63 | 64 | @Override 65 | public LocalTime parseLiteral(final Object input) throws CoercingParseLiteralException { 66 | if (!(input instanceof StringValue)) { 67 | throw new CoercingParseLiteralException( 68 | "Expected AST type 'StringValue' but was '" + typeName(input) + "'." 69 | ); 70 | } 71 | return parseTime(((StringValue) input).getValue(), CoercingParseLiteralException::new); 72 | } 73 | 74 | private static LocalTime parseTime(String s, Function exceptionMaker) { 75 | try { 76 | TemporalAccessor temporalAccessor = DATE_FORMATTER.parse(s); 77 | return LocalTime.from(temporalAccessor); 78 | } catch (DateTimeParseException e) { 79 | throw exceptionMaker.apply("Invalid local time value : '" + s + "'. because of : '" + e.getMessage() + "'"); 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/datetime/TimeScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.datetime; 2 | 3 | import graphql.Internal; 4 | import graphql.language.StringValue; 5 | import graphql.language.Value; 6 | import graphql.schema.Coercing; 7 | import graphql.schema.CoercingParseLiteralException; 8 | import graphql.schema.CoercingParseValueException; 9 | import graphql.schema.CoercingSerializeException; 10 | import graphql.schema.GraphQLScalarType; 11 | 12 | import java.time.DateTimeException; 13 | import java.time.OffsetTime; 14 | import java.time.format.DateTimeFormatter; 15 | import java.time.format.DateTimeParseException; 16 | import java.time.temporal.TemporalAccessor; 17 | import java.util.function.Function; 18 | 19 | import static graphql.scalars.util.Kit.typeName; 20 | 21 | /** 22 | * Access this via {@link graphql.scalars.ExtendedScalars#Time} 23 | */ 24 | @Internal 25 | public final class TimeScalar { 26 | 27 | private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ISO_OFFSET_TIME; 28 | 29 | public static final GraphQLScalarType INSTANCE; 30 | 31 | private TimeScalar() {} 32 | 33 | static { 34 | Coercing coercing = new Coercing() { 35 | @Override 36 | public String serialize(Object input) throws CoercingSerializeException { 37 | TemporalAccessor temporalAccessor; 38 | if (input instanceof TemporalAccessor) { 39 | temporalAccessor = (TemporalAccessor) input; 40 | } else if (input instanceof String) { 41 | temporalAccessor = parseOffsetTime(input.toString(), CoercingSerializeException::new); 42 | } else { 43 | throw new CoercingSerializeException( 44 | "Expected a 'String' or 'java.time.temporal.TemporalAccessor' but was '" + typeName(input) + "'." 45 | ); 46 | } 47 | try { 48 | return dateFormatter.format(temporalAccessor); 49 | } catch (DateTimeException e) { 50 | throw new CoercingSerializeException( 51 | "Unable to turn TemporalAccessor into full time because of : '" + e.getMessage() + "'." 52 | ); 53 | } 54 | } 55 | 56 | @Override 57 | public OffsetTime parseValue(Object input) throws CoercingParseValueException { 58 | TemporalAccessor temporalAccessor; 59 | if (input instanceof TemporalAccessor) { 60 | temporalAccessor = (TemporalAccessor) input; 61 | } else if (input instanceof String) { 62 | temporalAccessor = parseOffsetTime(input.toString(), CoercingParseValueException::new); 63 | } else { 64 | throw new CoercingParseValueException( 65 | "Expected a 'String' or 'java.time.temporal.TemporalAccessor' but was '" + typeName(input) + "'." 66 | ); 67 | } 68 | try { 69 | return OffsetTime.from(temporalAccessor); 70 | } catch (DateTimeException e) { 71 | throw new CoercingParseValueException( 72 | "Unable to turn TemporalAccessor into full time because of : '" + e.getMessage() + "'." 73 | ); 74 | } 75 | } 76 | 77 | @Override 78 | public OffsetTime parseLiteral(Object input) throws CoercingParseLiteralException { 79 | if (!(input instanceof StringValue)) { 80 | throw new CoercingParseLiteralException( 81 | "Expected AST type 'StringValue' but was '" + typeName(input) + "'." 82 | ); 83 | } 84 | return parseOffsetTime(((StringValue) input).getValue(), CoercingParseLiteralException::new); 85 | } 86 | 87 | @Override 88 | public Value valueToLiteral(Object input) { 89 | String s = serialize(input); 90 | return StringValue.newStringValue(s).build(); 91 | } 92 | 93 | private OffsetTime parseOffsetTime(String s, Function exceptionMaker) { 94 | try { 95 | TemporalAccessor temporalAccessor = dateFormatter.parse(s); 96 | return OffsetTime.from(temporalAccessor); 97 | } catch (DateTimeParseException e) { 98 | throw exceptionMaker.apply("Invalid RFC3339 full time value : '" + s + "'. because of : '" + e.getMessage() + "'"); 99 | } 100 | } 101 | }; 102 | 103 | INSTANCE = GraphQLScalarType.newScalar() 104 | .name("Time") 105 | .description("An RFC-3339 compliant Full Time Scalar") 106 | .coercing(coercing) 107 | .build(); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/id/UUIDScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.id; 2 | 3 | import graphql.Internal; 4 | import graphql.language.StringValue; 5 | import graphql.language.Value; 6 | import graphql.scalars.util.Kit; 7 | import graphql.schema.Coercing; 8 | import graphql.schema.CoercingParseLiteralException; 9 | import graphql.schema.CoercingParseValueException; 10 | import graphql.schema.CoercingSerializeException; 11 | import graphql.schema.GraphQLScalarType; 12 | 13 | import java.util.UUID; 14 | 15 | import static graphql.scalars.util.Kit.typeName; 16 | 17 | /** 18 | * Access this via {@link graphql.scalars.ExtendedScalars#UUID} 19 | */ 20 | @Internal 21 | public class UUIDScalar { 22 | 23 | public static GraphQLScalarType INSTANCE; 24 | 25 | static { 26 | Coercing coercing = new Coercing() { 27 | private UUID convertImpl(Object input) { 28 | if (input instanceof String) { 29 | try { 30 | return (UUID.fromString((String) input)); 31 | } catch (IllegalArgumentException ex) { 32 | return null; 33 | } 34 | } else if (input instanceof UUID) { 35 | return (UUID) input; 36 | } 37 | return null; 38 | } 39 | 40 | @Override 41 | public String serialize(Object input) throws CoercingSerializeException { 42 | UUID result = convertImpl(input); 43 | if (result == null) { 44 | throw new CoercingSerializeException( 45 | "Expected type 'UUID' but was '" + Kit.typeName(input) + "'." 46 | ); 47 | } 48 | return result.toString(); 49 | } 50 | 51 | @Override 52 | public UUID parseValue(Object input) throws CoercingParseValueException { 53 | UUID result = convertImpl(input); 54 | if (result == null) { 55 | throw new CoercingParseValueException( 56 | "Expected type 'UUID' but was '" + Kit.typeName(input) + "'." 57 | ); 58 | } 59 | return result; 60 | } 61 | 62 | @Override 63 | public UUID parseLiteral(Object input) throws CoercingParseLiteralException { 64 | if (!(input instanceof StringValue)) { 65 | throw new CoercingParseLiteralException( 66 | "Expected a 'java.util.UUID' AST type object but was '" + typeName(input) + "'." 67 | ); 68 | } 69 | try { 70 | return UUID.fromString(((StringValue) input).getValue()); 71 | } catch (IllegalArgumentException ex) { 72 | throw new CoercingParseLiteralException( 73 | "Expected something that we can convert to a UUID but was invalid" 74 | ); 75 | } 76 | } 77 | 78 | @Override 79 | public Value valueToLiteral(Object input) { 80 | String s = serialize(input); 81 | return StringValue.newStringValue(s).build(); 82 | } 83 | }; 84 | 85 | 86 | INSTANCE = GraphQLScalarType.newScalar() 87 | .name("UUID") 88 | .description("A universally unique identifier compliant UUID Scalar") 89 | .coercing(coercing) 90 | .build(); 91 | 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/locale/LocaleScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.locale; 2 | 3 | import graphql.Internal; 4 | import graphql.language.StringValue; 5 | import graphql.language.Value; 6 | import graphql.schema.Coercing; 7 | import graphql.schema.CoercingParseLiteralException; 8 | import graphql.schema.CoercingParseValueException; 9 | import graphql.schema.CoercingSerializeException; 10 | import graphql.schema.GraphQLScalarType; 11 | 12 | import java.util.Locale; 13 | 14 | import static graphql.scalars.util.Kit.typeName; 15 | 16 | /** 17 | * Access this via {@link graphql.scalars.ExtendedScalars#Locale} 18 | */ 19 | @Internal 20 | public final class LocaleScalar { 21 | 22 | private LocaleScalar() {} 23 | 24 | public static final GraphQLScalarType INSTANCE; 25 | 26 | static { 27 | Coercing coercing = new Coercing() { 28 | 29 | @Override 30 | public String serialize(Object input) throws CoercingSerializeException { 31 | if (input instanceof String) { 32 | try { 33 | return Locale.forLanguageTag((String) input).toLanguageTag(); 34 | } catch (Exception e) { 35 | throw new CoercingSerializeException( 36 | "Expected a valid language tag string but was but was " + typeName(input)); 37 | } 38 | } 39 | if (input instanceof Locale) { 40 | return ((Locale) input).toLanguageTag(); 41 | } else { 42 | throw new CoercingSerializeException( 43 | "Expected a 'java.util.Locale' object but was " + typeName(input)); 44 | } 45 | } 46 | 47 | @Override 48 | public Locale parseValue(Object input) throws CoercingParseValueException { 49 | if (input instanceof String) { 50 | try { 51 | return Locale.forLanguageTag(input.toString()); 52 | } catch (Exception e) { 53 | throw new CoercingParseValueException( 54 | "Unable to parse value to 'java.util.Locale' because of: " + e.getMessage()); 55 | } 56 | } else if (input instanceof Locale) { 57 | return (Locale) input; 58 | } else { 59 | throw new CoercingParseValueException( 60 | "Expected a 'java.lang.String' object but was " + typeName(input)); 61 | } 62 | } 63 | 64 | @Override 65 | public Locale parseLiteral(Object input) throws CoercingParseLiteralException { 66 | if (input instanceof StringValue) { 67 | return Locale.forLanguageTag(((StringValue) input).getValue()); 68 | } else { 69 | throw new CoercingParseLiteralException( 70 | "Expected a 'java.lang.String' object but was " + typeName(input)); 71 | } 72 | } 73 | 74 | @Override 75 | public Value valueToLiteral(Object input) { 76 | String s = serialize(input); 77 | return StringValue.newStringValue(s).build(); 78 | } 79 | }; 80 | 81 | INSTANCE = GraphQLScalarType.newScalar() 82 | .name("Locale") 83 | .description("A IETF BCP 47 language tag") 84 | .coercing(coercing) 85 | .build(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/numeric/FloatCoercing.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric; 2 | 3 | import graphql.Internal; 4 | import graphql.language.Value; 5 | import graphql.schema.Coercing; 6 | import graphql.schema.CoercingParseLiteralException; 7 | import graphql.schema.CoercingParseValueException; 8 | import graphql.schema.CoercingSerializeException; 9 | 10 | import java.util.function.Function; 11 | 12 | import static graphql.Scalars.GraphQLFloat; 13 | 14 | @Internal 15 | abstract class FloatCoercing implements Coercing { 16 | 17 | protected abstract Double check(Double d, Function exceptionMaker); 18 | 19 | @Override 20 | public Double serialize(Object input) throws CoercingSerializeException { 21 | Double d = (Double) GraphQLFloat.getCoercing().serialize(input); 22 | return check(d, CoercingSerializeException::new); 23 | } 24 | 25 | @Override 26 | public Double parseValue(Object input) throws CoercingParseValueException { 27 | Double d = (Double) GraphQLFloat.getCoercing().parseValue(input); 28 | return check(d, CoercingParseValueException::new); 29 | } 30 | 31 | @Override 32 | public Double parseLiteral(Object input) throws CoercingParseLiteralException { 33 | Double d = (Double) GraphQLFloat.getCoercing().parseLiteral(input); 34 | return check(d, CoercingParseLiteralException::new); 35 | } 36 | 37 | @Override 38 | public Value valueToLiteral(Object input) { 39 | return GraphQLFloat.getCoercing().valueToLiteral(input); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/numeric/IntCoercing.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric; 2 | 3 | import graphql.Internal; 4 | import graphql.language.Value; 5 | import graphql.schema.Coercing; 6 | import graphql.schema.CoercingParseLiteralException; 7 | import graphql.schema.CoercingParseValueException; 8 | import graphql.schema.CoercingSerializeException; 9 | 10 | import java.util.function.Function; 11 | 12 | import static graphql.Scalars.GraphQLInt; 13 | 14 | @Internal 15 | abstract class IntCoercing implements Coercing { 16 | 17 | protected abstract Integer check(Integer i, Function exceptionMaker); 18 | 19 | @Override 20 | public Integer serialize(Object input) throws CoercingSerializeException { 21 | Integer i = (Integer) GraphQLInt.getCoercing().serialize(input); 22 | return check(i, CoercingSerializeException::new); 23 | } 24 | 25 | @Override 26 | public Integer parseValue(Object input) throws CoercingParseValueException { 27 | Integer i = (Integer) GraphQLInt.getCoercing().parseValue(input); 28 | return check(i, CoercingParseValueException::new); 29 | } 30 | 31 | @Override 32 | public Integer parseLiteral(Object input) throws CoercingParseLiteralException { 33 | Integer i = (Integer) GraphQLInt.getCoercing().parseLiteral(input); 34 | return check(i, CoercingParseLiteralException::new); 35 | } 36 | 37 | @Override 38 | public Value valueToLiteral(Object input) { 39 | return GraphQLInt.getCoercing().valueToLiteral(input); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/numeric/NegativeFloatScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric; 2 | 3 | import graphql.Internal; 4 | import graphql.schema.GraphQLScalarType; 5 | 6 | import java.util.function.Function; 7 | 8 | /** 9 | * Access this via {@link graphql.scalars.ExtendedScalars#NegativeFloat} 10 | */ 11 | @Internal 12 | public final class NegativeFloatScalar { 13 | 14 | private NegativeFloatScalar() {} 15 | 16 | public static final GraphQLScalarType INSTANCE = GraphQLScalarType.newScalar() 17 | .name("NegativeFloat") 18 | .description("An Float scalar that must be a negative value") 19 | .coercing(new FloatCoercing() { 20 | @Override 21 | protected Double check(Double d, Function exceptionMaker) { 22 | if (d >= 0.0d) { 23 | throw exceptionMaker.apply("The value must be a negative value"); 24 | } 25 | return d; 26 | } 27 | }) 28 | .build(); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/numeric/NegativeIntScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric; 2 | 3 | import graphql.Internal; 4 | import graphql.schema.GraphQLScalarType; 5 | 6 | import java.util.function.Function; 7 | 8 | /** 9 | * Access this via {@link graphql.scalars.ExtendedScalars#NegativeInt} 10 | */ 11 | @Internal 12 | public final class NegativeIntScalar { 13 | 14 | private NegativeIntScalar() {} 15 | 16 | public static final GraphQLScalarType INSTANCE = GraphQLScalarType.newScalar() 17 | .name("NegativeInt") 18 | .description("An Int scalar that must be a negative value") 19 | .coercing(new IntCoercing() { 20 | @Override 21 | protected Integer check(Integer i, Function exceptionMaker) { 22 | if (i >= 0) { 23 | throw exceptionMaker.apply("The value must be a negative integer"); 24 | } 25 | return i; 26 | } 27 | }) 28 | .build(); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/numeric/NonNegativeFloatScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric; 2 | 3 | import graphql.Internal; 4 | import graphql.schema.GraphQLScalarType; 5 | 6 | import java.util.function.Function; 7 | 8 | /** 9 | * Access this via {@link graphql.scalars.ExtendedScalars#NonNegativeFloat} 10 | */ 11 | @Internal 12 | public final class NonNegativeFloatScalar { 13 | 14 | private NonNegativeFloatScalar() {} 15 | 16 | public static final GraphQLScalarType INSTANCE = GraphQLScalarType.newScalar() 17 | .name("NonNegativeFloat") 18 | .description("An Float scalar that must be greater than or equal to zero") 19 | .coercing(new FloatCoercing() { 20 | @Override 21 | protected Double check(Double d, Function exceptionMaker) { 22 | if (d < 0.0d) { 23 | throw exceptionMaker.apply("The value must be greater than or equal to zero"); 24 | } 25 | return d; 26 | } 27 | }) 28 | .build(); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/numeric/NonNegativeIntScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric; 2 | 3 | import graphql.Internal; 4 | import graphql.schema.GraphQLScalarType; 5 | 6 | import java.util.function.Function; 7 | 8 | /** 9 | * Access this via {@link graphql.scalars.ExtendedScalars#NonNegativeInt} 10 | */ 11 | @Internal 12 | public final class NonNegativeIntScalar { 13 | 14 | private NonNegativeIntScalar() {} 15 | 16 | public static final GraphQLScalarType INSTANCE = GraphQLScalarType.newScalar() 17 | .name("NonNegativeInt") 18 | .description("An Int scalar that must be greater than or equal to zero") 19 | .coercing(new IntCoercing() { 20 | @Override 21 | protected Integer check(Integer i, Function exceptionMaker) { 22 | if (i < 0) { 23 | throw exceptionMaker.apply("The value must be greater than or equal to zero"); 24 | } 25 | return i; 26 | } 27 | }) 28 | .build(); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/numeric/NonPositiveFloatScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric; 2 | 3 | import graphql.Internal; 4 | import graphql.schema.GraphQLScalarType; 5 | 6 | import java.util.function.Function; 7 | 8 | /** 9 | * Access this via {@link graphql.scalars.ExtendedScalars#NonPositiveFloat} 10 | */ 11 | @Internal 12 | public final class NonPositiveFloatScalar { 13 | 14 | private NonPositiveFloatScalar() {} 15 | 16 | public static final GraphQLScalarType INSTANCE = GraphQLScalarType.newScalar() 17 | .name("NonPositiveFloat").description("An Float scalar that must be less than or equal to zero") 18 | .coercing(new FloatCoercing() { 19 | @Override 20 | protected Double check(Double d, Function exceptionMaker) { 21 | if (d > 0) { 22 | throw exceptionMaker.apply("The value must be less than or equal to zero"); 23 | } 24 | return d; 25 | } 26 | }) 27 | .build(); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/numeric/NonPositiveIntScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric; 2 | 3 | import graphql.Internal; 4 | import graphql.schema.GraphQLScalarType; 5 | 6 | import java.util.function.Function; 7 | 8 | /** 9 | * Access this via {@link graphql.scalars.ExtendedScalars#NonPositiveInt} 10 | */ 11 | @Internal 12 | public final class NonPositiveIntScalar { 13 | 14 | private NonPositiveIntScalar() {} 15 | 16 | public static final GraphQLScalarType INSTANCE = GraphQLScalarType.newScalar() 17 | .name("NonPositiveInt") 18 | .description("An Int scalar that must be less than or equal to zero") 19 | .coercing(new IntCoercing() { 20 | @Override 21 | protected Integer check(Integer i, Function exceptionMaker) { 22 | if (i > 0) { 23 | throw exceptionMaker.apply("The value must be less than or equal to zero"); 24 | } 25 | return i; 26 | } 27 | }) 28 | .build(); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/numeric/PositiveFloatScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric; 2 | 3 | import graphql.Internal; 4 | import graphql.schema.GraphQLScalarType; 5 | 6 | import java.util.function.Function; 7 | 8 | /** 9 | * Access this via {@link graphql.scalars.ExtendedScalars#PositiveFloat} 10 | */ 11 | @Internal 12 | public final class PositiveFloatScalar { 13 | 14 | private PositiveFloatScalar() {} 15 | 16 | public static final GraphQLScalarType INSTANCE = GraphQLScalarType.newScalar() 17 | .name("PositiveFloat") 18 | .description("An Float scalar that must be a positive value") 19 | .coercing(new FloatCoercing() { 20 | @Override 21 | protected Double check(Double d, Function exceptionMaker) { 22 | if (d <= 0) { 23 | throw exceptionMaker.apply("The value must be a positive value"); 24 | } 25 | return d; 26 | } 27 | }) 28 | .build(); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/numeric/PositiveIntScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric; 2 | 3 | import graphql.Internal; 4 | import graphql.schema.GraphQLScalarType; 5 | 6 | import java.util.function.Function; 7 | 8 | /** 9 | * Access this via {@link graphql.scalars.ExtendedScalars#PositiveInt} 10 | */ 11 | @Internal 12 | public final class PositiveIntScalar { 13 | 14 | private PositiveIntScalar() {} 15 | 16 | public static final GraphQLScalarType INSTANCE = GraphQLScalarType.newScalar() 17 | .name("PositiveInt") 18 | .description("An Int scalar that must be a positive value") 19 | .coercing(new IntCoercing() { 20 | @Override 21 | protected Integer check(Integer i, Function exceptionMaker) { 22 | if (i <= 0) { 23 | throw exceptionMaker.apply("The value must be a positive integer"); 24 | } 25 | return i; 26 | } 27 | }) 28 | .build(); 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/object/JsonScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.object; 2 | 3 | import graphql.Internal; 4 | import graphql.schema.GraphQLScalarType; 5 | 6 | import static graphql.scalars.object.ObjectScalar.OBJECT_COERCING; 7 | 8 | /** 9 | * A synonym class for {@link graphql.scalars.object.ObjectScalar} 10 | * 11 | * Access this via {@link graphql.scalars.ExtendedScalars#Json} 12 | */ 13 | @Internal 14 | public final class JsonScalar { 15 | 16 | private JsonScalar() {} 17 | 18 | public static final GraphQLScalarType INSTANCE = GraphQLScalarType.newScalar() 19 | .name("JSON") 20 | .description("A JSON scalar") 21 | .coercing(OBJECT_COERCING) 22 | .build(); 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/object/ObjectScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.object; 2 | 3 | import graphql.Assert; 4 | import graphql.Internal; 5 | import graphql.language.ArrayValue; 6 | import graphql.language.BooleanValue; 7 | import graphql.language.EnumValue; 8 | import graphql.language.FloatValue; 9 | import graphql.language.IntValue; 10 | import graphql.language.NullValue; 11 | import graphql.language.ObjectField; 12 | import graphql.language.ObjectValue; 13 | import graphql.language.StringValue; 14 | import graphql.language.Value; 15 | import graphql.language.VariableReference; 16 | import graphql.schema.Coercing; 17 | import graphql.schema.CoercingParseLiteralException; 18 | import graphql.schema.CoercingParseValueException; 19 | import graphql.schema.CoercingSerializeException; 20 | import graphql.schema.GraphQLScalarType; 21 | import graphql.util.FpKit; 22 | 23 | import java.math.BigDecimal; 24 | import java.math.BigInteger; 25 | import java.util.ArrayList; 26 | import java.util.Collections; 27 | import java.util.LinkedHashMap; 28 | import java.util.List; 29 | import java.util.Map; 30 | import java.util.stream.Collectors; 31 | 32 | import static graphql.language.ObjectField.newObjectField; 33 | import static graphql.scalars.util.Kit.typeName; 34 | 35 | /** 36 | * Access this via {@link graphql.scalars.ExtendedScalars#Object} 37 | */ 38 | @Internal 39 | public final class ObjectScalar { 40 | 41 | private ObjectScalar() {} 42 | 43 | static final Coercing OBJECT_COERCING = new Coercing() { 44 | @Override 45 | public Object serialize(Object input) throws CoercingSerializeException { 46 | return input; 47 | } 48 | 49 | @Override 50 | public Object parseValue(Object input) throws CoercingParseValueException { 51 | return input; 52 | } 53 | 54 | @Override 55 | public Object parseLiteral(Object input) throws CoercingParseLiteralException { 56 | // on purpose - object scalars can be null 57 | return parseLiteral(input, Collections.emptyMap()); 58 | } 59 | 60 | @Override 61 | public Object parseLiteral(Object input, Map variables) throws CoercingParseLiteralException { 62 | if (!(input instanceof Value)) { 63 | throw new CoercingParseLiteralException( 64 | "Expected AST type 'Value' but was '" + typeName(input) + "'." 65 | ); 66 | } 67 | if (input instanceof FloatValue) { 68 | return ((FloatValue) input).getValue(); 69 | } 70 | if (input instanceof StringValue) { 71 | return ((StringValue) input).getValue(); 72 | } 73 | if (input instanceof IntValue) { 74 | return ((IntValue) input).getValue(); 75 | } 76 | if (input instanceof BooleanValue) { 77 | return ((BooleanValue) input).isValue(); 78 | } 79 | if (input instanceof EnumValue) { 80 | return ((EnumValue) input).getName(); 81 | } 82 | if (input instanceof VariableReference) { 83 | String varName = ((VariableReference) input).getName(); 84 | return variables.get(varName); 85 | } 86 | if (input instanceof ArrayValue) { 87 | List values = ((ArrayValue) input).getValues(); 88 | return values.stream() 89 | .map(v -> parseLiteral(v, variables)) 90 | .collect(Collectors.toList()); 91 | } 92 | if (input instanceof ObjectValue) { 93 | List values = ((ObjectValue) input).getObjectFields(); 94 | Map parsedValues = new LinkedHashMap<>(); 95 | values.forEach(fld -> { 96 | Object parsedValue; 97 | if (fld.getValue() instanceof NullValue) { // Nested NullValue inside ObjectValue 98 | parsedValue = null; 99 | } else { 100 | parsedValue = parseLiteral(fld.getValue(), variables); 101 | } 102 | parsedValues.put(fld.getName(), parsedValue); 103 | }); 104 | return parsedValues; 105 | } 106 | return Assert.assertShouldNeverHappen("We have covered all Value types"); 107 | } 108 | 109 | @Override 110 | public Value valueToLiteral(Object input) { 111 | if (input == null) { 112 | return NullValue.newNullValue().build(); 113 | } 114 | if (input instanceof String) { 115 | return new StringValue((String) input); 116 | } 117 | if (input instanceof Float) { 118 | return new FloatValue(BigDecimal.valueOf((Float) input)); 119 | } 120 | if (input instanceof Double) { 121 | return new FloatValue(BigDecimal.valueOf((Double) input)); 122 | } 123 | if (input instanceof BigDecimal) { 124 | return new FloatValue((BigDecimal) input); 125 | } 126 | if (input instanceof BigInteger) { 127 | return new IntValue((BigInteger) input); 128 | } 129 | if (input instanceof Number) { 130 | long l = ((Number) input).longValue(); 131 | return new IntValue(BigInteger.valueOf(l)); 132 | } 133 | if (input instanceof Boolean) { 134 | return new BooleanValue((Boolean) input); 135 | } 136 | if (FpKit.isIterable(input)) { 137 | return handleIterable(FpKit.toIterable(input)); 138 | } 139 | if (input instanceof Map) { 140 | return handleMap((Map) input); 141 | } 142 | throw new UnsupportedOperationException("The ObjectScalar cant handle values of type : " + input.getClass()); 143 | } 144 | 145 | private Value handleMap(Map map) { 146 | ObjectValue.Builder builder = ObjectValue.newObjectValue(); 147 | for (Map.Entry entry : map.entrySet()) { 148 | String name = String.valueOf(entry.getKey()); 149 | Value value = valueToLiteral(entry.getValue()); 150 | 151 | builder.objectField( 152 | newObjectField().name(name).value(value).build() 153 | ); 154 | } 155 | return builder.build(); 156 | } 157 | 158 | @SuppressWarnings("rawtypes") 159 | private Value handleIterable(Iterable input) { 160 | List values = new ArrayList<>(); 161 | for (Object val : input) { 162 | values.add(valueToLiteral(val)); 163 | } 164 | return ArrayValue.newArrayValue().values(values).build(); 165 | } 166 | }; 167 | 168 | public static GraphQLScalarType INSTANCE = GraphQLScalarType.newScalar() 169 | .name("Object") 170 | .description("An object scalar") 171 | .coercing(OBJECT_COERCING) 172 | .build(); 173 | } 174 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/regex/RegexScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.regex; 2 | 3 | import graphql.Assert; 4 | import graphql.PublicApi; 5 | import graphql.language.StringValue; 6 | import graphql.language.Value; 7 | import graphql.schema.Coercing; 8 | import graphql.schema.CoercingParseLiteralException; 9 | import graphql.schema.CoercingParseValueException; 10 | import graphql.schema.CoercingSerializeException; 11 | import graphql.schema.GraphQLScalarType; 12 | 13 | import java.util.ArrayList; 14 | import java.util.Collections; 15 | import java.util.List; 16 | import java.util.function.Function; 17 | import java.util.regex.Matcher; 18 | import java.util.regex.Pattern; 19 | 20 | import static graphql.scalars.util.Kit.typeName; 21 | 22 | /** 23 | * This is really a scalar factory for creating new scalar String types that are based on a value matching 24 | * a regular expression. 25 | */ 26 | @PublicApi 27 | public final class RegexScalar { 28 | 29 | private RegexScalar() {} 30 | 31 | /** 32 | * A builder for {@link graphql.scalars.regex.RegexScalar} 33 | */ 34 | public static class Builder { 35 | private String name; 36 | private String description; 37 | private List patterns = new ArrayList<>(); 38 | 39 | /** 40 | * Sets the name of the regex scalar 41 | * 42 | * @param name the name of the regex scalar 43 | * 44 | * @return this builder 45 | */ 46 | public Builder name(String name) { 47 | this.name = name; 48 | return this; 49 | } 50 | 51 | /** 52 | * Sets the description of the regex scalar 53 | * 54 | * @param description the description of the regex scalar 55 | * 56 | * @return this builder 57 | */ 58 | public Builder description(String description) { 59 | this.description = description; 60 | return this; 61 | } 62 | 63 | /** 64 | * Adds a {@link java.util.regex.Pattern} that controls the acceptable value for this scalar 65 | * 66 | * @param pattern the regex pattern 67 | * 68 | * @return this builder 69 | */ 70 | public Builder addPattern(Pattern pattern) { 71 | this.patterns.add(pattern); 72 | return this; 73 | } 74 | 75 | /** 76 | * Adds a {@link java.util.regex.Pattern} that controls the acceptable value for this scalar 77 | * 78 | * @param patterns one of more regex patterns 79 | * 80 | * @return this builder 81 | */ 82 | public Builder addPatterns(Pattern... patterns) { 83 | Collections.addAll(this.patterns, patterns); 84 | return this; 85 | } 86 | 87 | /** 88 | * @return the built {@link graphql.scalars.regex.RegexScalar} 89 | */ 90 | public GraphQLScalarType build() { 91 | Assert.assertNotNull(name); 92 | return regexScalarImpl(name, description, patterns); 93 | } 94 | } 95 | 96 | private static GraphQLScalarType regexScalarImpl(String name, String description, List patterns) { 97 | Assert.assertNotNull(patterns); 98 | 99 | Coercing coercing = new Coercing() { 100 | @Override 101 | public String serialize(Object input) throws CoercingSerializeException { 102 | String value = String.valueOf(input); 103 | return matches(value, CoercingSerializeException::new); 104 | } 105 | 106 | @Override 107 | public String parseValue(Object input) throws CoercingParseValueException { 108 | String value = String.valueOf(input); 109 | return matches(value, CoercingParseValueException::new); 110 | } 111 | 112 | @Override 113 | public String parseLiteral(Object input) throws CoercingParseLiteralException { 114 | if (!(input instanceof StringValue)) { 115 | throw new CoercingParseLiteralException( 116 | "Expected AST type 'StringValue' but was '" + typeName(input) + "'." 117 | ); 118 | } 119 | String value = ((StringValue) input).getValue(); 120 | return matches(value, CoercingParseLiteralException::new); 121 | } 122 | 123 | @Override 124 | public Value valueToLiteral(Object input) { 125 | String s = serialize(input); 126 | return StringValue.newStringValue(s).build(); 127 | } 128 | 129 | 130 | private String matches(String value, Function exceptionMaker) { 131 | for (Pattern pattern : patterns) { 132 | Matcher matcher = pattern.matcher(value); 133 | if (matcher.matches()) { 134 | return value; 135 | } 136 | } 137 | throw exceptionMaker.apply("Unable to accept a value into the '" + name + "' scalar. It does not match the regular expressions."); 138 | } 139 | }; 140 | 141 | return GraphQLScalarType.newScalar() 142 | .name(name) 143 | .description(description) 144 | .coercing(coercing) 145 | .build(); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/url/UrlScalar.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.url; 2 | 3 | import graphql.Internal; 4 | import graphql.language.StringValue; 5 | import graphql.language.Value; 6 | import graphql.schema.Coercing; 7 | import graphql.schema.CoercingParseLiteralException; 8 | import graphql.schema.CoercingParseValueException; 9 | import graphql.schema.CoercingSerializeException; 10 | import graphql.schema.GraphQLScalarType; 11 | 12 | import java.io.File; 13 | import java.net.MalformedURLException; 14 | import java.net.URI; 15 | import java.net.URL; 16 | import java.util.Optional; 17 | import java.util.function.Function; 18 | 19 | import static graphql.scalars.util.Kit.typeName; 20 | 21 | @Internal 22 | public final class UrlScalar { 23 | 24 | private UrlScalar() {} 25 | 26 | public static final GraphQLScalarType INSTANCE; 27 | 28 | static { 29 | Coercing coercing = new Coercing() { 30 | @Override 31 | public URL serialize(Object input) throws CoercingSerializeException { 32 | Optional url; 33 | if (input instanceof String) { 34 | url = Optional.of(parseURL(input.toString(), CoercingSerializeException::new)); 35 | } else { 36 | url = toURL(input); 37 | } 38 | if (url.isPresent()) { 39 | return url.get(); 40 | } 41 | throw new CoercingSerializeException( 42 | "Expected a 'URL' like object but was '" + typeName(input) + "'." 43 | ); 44 | } 45 | 46 | @Override 47 | public URL parseValue(Object input) throws CoercingParseValueException { 48 | String urlStr; 49 | if (input instanceof String) { 50 | urlStr = String.valueOf(input); 51 | } else { 52 | Optional url = toURL(input); 53 | if (!url.isPresent()) { 54 | throw new CoercingParseValueException( 55 | "Expected a 'URL' like object but was '" + typeName(input) + "'." 56 | ); 57 | } 58 | return url.get(); 59 | } 60 | return parseURL(urlStr, CoercingParseValueException::new); 61 | } 62 | 63 | @Override 64 | public URL parseLiteral(Object input) throws CoercingParseLiteralException { 65 | if (!(input instanceof StringValue)) { 66 | throw new CoercingParseLiteralException( 67 | "Expected AST type 'StringValue' but was '" + typeName(input) + "'." 68 | ); 69 | } 70 | return parseURL(((StringValue) input).getValue(), CoercingParseLiteralException::new); 71 | } 72 | 73 | @Override 74 | public Value valueToLiteral(Object input) { 75 | URL url = serialize(input); 76 | return StringValue.newStringValue(url.toExternalForm()).build(); 77 | } 78 | 79 | 80 | private URL parseURL(String input, Function exceptionMaker) { 81 | try { 82 | return new URL(input); 83 | } catch (MalformedURLException e) { 84 | throw exceptionMaker.apply("Invalid URL value : '" + input + "'."); 85 | } 86 | } 87 | }; 88 | 89 | INSTANCE = GraphQLScalarType.newScalar() 90 | .name("Url") 91 | .description("A Url scalar") 92 | .coercing(coercing) 93 | .build(); 94 | } 95 | 96 | private static Optional toURL(Object input) { 97 | if (input instanceof URL) { 98 | return Optional.of((URL) input); 99 | } else if (input instanceof URI) { 100 | try { 101 | return Optional.of(((URI) input).toURL()); 102 | } catch (MalformedURLException ignored) { 103 | } 104 | } else if (input instanceof File) { 105 | try { 106 | return Optional.of(((File) input).toURI().toURL()); 107 | } catch (MalformedURLException ignored) { 108 | } 109 | } 110 | return Optional.empty(); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /src/main/java/graphql/scalars/util/Kit.java: -------------------------------------------------------------------------------- 1 | package graphql.scalars.util; 2 | 3 | public class Kit { 4 | 5 | public static String typeName(Object input) { 6 | if (input == null) { 7 | return "null"; 8 | } 9 | return input.getClass().getSimpleName(); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/alias/AliasedScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.alias 2 | 3 | import graphql.Scalars 4 | import graphql.language.StringValue 5 | import graphql.scalars.ExtendedScalars 6 | import graphql.schema.GraphQLScalarType 7 | import spock.lang.Specification 8 | 9 | class AliasedScalarTest extends Specification { 10 | 11 | GraphQLScalarType socialMediaLink = ExtendedScalars.newAliasedScalar("SocialMediaLink") 12 | .aliasedScalar(Scalars.GraphQLString) 13 | .build() 14 | 15 | def "basic wrapping"() { 16 | 17 | when: 18 | def result = socialMediaLink.coercing.serialize("ABC") 19 | then: 20 | result == "ABC" 21 | 22 | when: 23 | result = socialMediaLink.coercing.parseValue("ABC") 24 | then: 25 | result == "ABC" 26 | 27 | when: 28 | result = socialMediaLink.coercing.parseLiteral(new StringValue("ABC")) 29 | then: 30 | result == "ABC" 31 | 32 | when: 33 | result = socialMediaLink.coercing.parseLiteral(new StringValue("ABC"), [:]) 34 | then: 35 | result == "ABC" 36 | 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/country/code/CountryCodeScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.country.code 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseValueException 6 | import spock.lang.Specification 7 | import spock.lang.Unroll 8 | 9 | import static graphql.scalars.util.TestKit.mkCountryCode 10 | import static graphql.scalars.util.TestKit.mkStringValue 11 | 12 | class CountryCodeScalarTest extends Specification { 13 | 14 | def coercing = ExtendedScalars.CountryCode.getCoercing() 15 | 16 | @Unroll 17 | def "invoke parseValue for countryCode"() { 18 | when: 19 | def result = coercing.parseValue(input) 20 | then: 21 | result == expectedValue 22 | where: 23 | input | expectedValue 24 | "US" | mkCountryCode("US") 25 | "IN" | mkCountryCode("IN") 26 | mkCountryCode("US") | mkCountryCode("US") 27 | } 28 | 29 | 30 | @Unroll 31 | def "invoke parseLiteral for countryCode"() { 32 | 33 | when: 34 | def result = coercing.parseLiteral(input) 35 | then: 36 | result == expectedValue 37 | where: 38 | input | expectedValue 39 | new StringValue("GB") | mkCountryCode("GB") 40 | new StringValue("US") | mkCountryCode("US") 41 | new StringValue("IN") | mkCountryCode("IN") 42 | } 43 | 44 | @Unroll 45 | def "invoke serialize with countryCode"() { 46 | when: 47 | def result = coercing.serialize(input) 48 | then: 49 | result == expectedValue 50 | where: 51 | input | expectedValue 52 | "GB" | "GB" 53 | "US" | "US" 54 | "IN" | "IN" 55 | mkCountryCode("US") | "US" 56 | } 57 | 58 | @Unroll 59 | def "invoke valueToLiteral with countryCode"() { 60 | 61 | when: 62 | def result = coercing.valueToLiteral(input) 63 | then: 64 | result.isEqualTo(expectedValue) 65 | where: 66 | input | expectedValue 67 | "GB" | mkStringValue("GB") 68 | "US" | mkStringValue("US") 69 | "IN" | mkStringValue("IN") 70 | mkCountryCode("US") | mkStringValue("US") 71 | } 72 | 73 | @Unroll 74 | def "parseValue throws exception for invalid input #value"() { 75 | when: 76 | coercing.parseValue(value) 77 | then: 78 | thrown(CoercingParseValueException) 79 | 80 | where: 81 | value | _ 82 | "" | _ 83 | "US(UNITED STATES)" | _ 84 | "not a countryCode " | _ 85 | "42.3" | _ 86 | new Double(42.3) | _ 87 | new Float(42.3) | _ 88 | new Object() | _ 89 | } 90 | 91 | 92 | @Unroll 93 | def "invoke parseValue with all countryCode list"() { 94 | when: 95 | def result = coercing.parseValue(input) 96 | then: 97 | result == expectedValue 98 | where: 99 | input | expectedValue 100 | "GB" | mkCountryCode("GB") 101 | "US" | mkCountryCode("US") 102 | "IN" | mkCountryCode("IN") 103 | "AF" | mkCountryCode("AF") 104 | "AX" | mkCountryCode("AX") 105 | "AL" | mkCountryCode("AL") 106 | "DZ" | mkCountryCode("DZ") 107 | "AS" | mkCountryCode("AS") 108 | "AD" | mkCountryCode("AD") 109 | "AO" | mkCountryCode("AO") 110 | "AI" | mkCountryCode("AI") 111 | "AQ" | mkCountryCode("AQ") 112 | "AG" | mkCountryCode("AG") 113 | "AR" | mkCountryCode("AR") 114 | "AM" | mkCountryCode("AM") 115 | "AW" | mkCountryCode("AW") 116 | "AU" | mkCountryCode("AU") 117 | "AT" | mkCountryCode("AT") 118 | "AZ" | mkCountryCode("AZ") 119 | "BS" | mkCountryCode("BS") 120 | "BH" | mkCountryCode("BH") 121 | "BD" | mkCountryCode("BD") 122 | "BB" | mkCountryCode("BB") 123 | "BY" | mkCountryCode("BY") 124 | "BE" | mkCountryCode("BE") 125 | "BZ" | mkCountryCode("BZ") 126 | "BJ" | mkCountryCode("BJ") 127 | "BM" | mkCountryCode("BM") 128 | "BT" | mkCountryCode("BT") 129 | "BO" | mkCountryCode("BO") 130 | "BQ" | mkCountryCode("BQ") 131 | "BA" | mkCountryCode("BA") 132 | "BW" | mkCountryCode("BW") 133 | "BV" | mkCountryCode("BV") 134 | "BR" | mkCountryCode("BR") 135 | "IO" | mkCountryCode("IO") 136 | "BN" | mkCountryCode("BN") 137 | "BG" | mkCountryCode("BG") 138 | "BF" | mkCountryCode("BF") 139 | "BI" | mkCountryCode("BI") 140 | "KH" | mkCountryCode("KH") 141 | "CM" | mkCountryCode("CM") 142 | "CA" | mkCountryCode("CA") 143 | "CV" | mkCountryCode("CV") 144 | "KY" | mkCountryCode("KY") 145 | "CF" | mkCountryCode("CF") 146 | "TD" | mkCountryCode("TD") 147 | "CL" | mkCountryCode("CL") 148 | "CN" | mkCountryCode("CN") 149 | "CX" | mkCountryCode("CX") 150 | "CC" | mkCountryCode("CC") 151 | "CO" | mkCountryCode("CO") 152 | "KM" | mkCountryCode("KM") 153 | "CG" | mkCountryCode("CG") 154 | "CD" | mkCountryCode("CD") 155 | "CK" | mkCountryCode("CK") 156 | "CR" | mkCountryCode("CR") 157 | "CI" | mkCountryCode("CI") 158 | "HR" | mkCountryCode("HR") 159 | "CU" | mkCountryCode("CU") 160 | "CW" | mkCountryCode("CW") 161 | "CY" | mkCountryCode("CY") 162 | "CZ" | mkCountryCode("CZ") 163 | "DK" | mkCountryCode("DK") 164 | "DJ" | mkCountryCode("DJ") 165 | "DM" | mkCountryCode("DM") 166 | "DO" | mkCountryCode("DO") 167 | "EC" | mkCountryCode("EC") 168 | "EG" | mkCountryCode("EG") 169 | "SV" | mkCountryCode("SV") 170 | "GQ" | mkCountryCode("GQ") 171 | "ER" | mkCountryCode("ER") 172 | "EE" | mkCountryCode("EE") 173 | "ET" | mkCountryCode("ET") 174 | "FK" | mkCountryCode("FK") 175 | "FO" | mkCountryCode("FO") 176 | "FJ" | mkCountryCode("FJ") 177 | "FI" | mkCountryCode("FI") 178 | "FR" | mkCountryCode("FR") 179 | "GF" | mkCountryCode("GF") 180 | "PF" | mkCountryCode("PF") 181 | "TF" | mkCountryCode("TF") 182 | "GA" | mkCountryCode("GA") 183 | "GM" | mkCountryCode("GM") 184 | "GE" | mkCountryCode("GE") 185 | "DE" | mkCountryCode("DE") 186 | "GH" | mkCountryCode("GH") 187 | "GI" | mkCountryCode("GI") 188 | "GR" | mkCountryCode("GR") 189 | "GL" | mkCountryCode("GL") 190 | "GD" | mkCountryCode("GD") 191 | "GP" | mkCountryCode("GP") 192 | "GU" | mkCountryCode("GU") 193 | "GT" | mkCountryCode("GT") 194 | "GG" | mkCountryCode("GG") 195 | "GN" | mkCountryCode("GN") 196 | "GW" | mkCountryCode("GW") 197 | "GY" | mkCountryCode("GY") 198 | "HT" | mkCountryCode("HT") 199 | "HM" | mkCountryCode("HM") 200 | "VA" | mkCountryCode("VA") 201 | "HN" | mkCountryCode("HN") 202 | "HK" | mkCountryCode("HK") 203 | "HU" | mkCountryCode("HU") 204 | "IS" | mkCountryCode("IS") 205 | "ID" | mkCountryCode("ID") 206 | "IR" | mkCountryCode("IR") 207 | "IQ" | mkCountryCode("IQ") 208 | "IE" | mkCountryCode("IE") 209 | "IM" | mkCountryCode("IM") 210 | "IL" | mkCountryCode("IL") 211 | "IT" | mkCountryCode("IT") 212 | "JM" | mkCountryCode("JM") 213 | "JP" | mkCountryCode("JP") 214 | "JE" | mkCountryCode("JE") 215 | "JO" | mkCountryCode("JO") 216 | "KZ" | mkCountryCode("KZ") 217 | "KE" | mkCountryCode("KE") 218 | "KI" | mkCountryCode("KI") 219 | "KP" | mkCountryCode("KP") 220 | "KR" | mkCountryCode("KR") 221 | "KW" | mkCountryCode("KW") 222 | "KG" | mkCountryCode("KG") 223 | "LA" | mkCountryCode("LA") 224 | "LV" | mkCountryCode("LV") 225 | "LB" | mkCountryCode("LB") 226 | "LS" | mkCountryCode("LS") 227 | "LR" | mkCountryCode("LR") 228 | "LY" | mkCountryCode("LY") 229 | "LI" | mkCountryCode("LI") 230 | "LT" | mkCountryCode("LT") 231 | "LU" | mkCountryCode("LU") 232 | "MO" | mkCountryCode("MO") 233 | "MK" | mkCountryCode("MK") 234 | "MG" | mkCountryCode("MG") 235 | "MW" | mkCountryCode("MW") 236 | "MY" | mkCountryCode("MY") 237 | "MV" | mkCountryCode("MV") 238 | "ML" | mkCountryCode("ML") 239 | "MT" | mkCountryCode("MT") 240 | "MH" | mkCountryCode("MH") 241 | "MQ" | mkCountryCode("MQ") 242 | "MR" | mkCountryCode("MR") 243 | "MU" | mkCountryCode("MU") 244 | "YT" | mkCountryCode("YT") 245 | "MX" | mkCountryCode("MX") 246 | "FM" | mkCountryCode("FM") 247 | "MD" | mkCountryCode("MD") 248 | "MC" | mkCountryCode("MC") 249 | "MN" | mkCountryCode("MN") 250 | "ME" | mkCountryCode("ME") 251 | "MS" | mkCountryCode("MS") 252 | "MA" | mkCountryCode("MA") 253 | "MZ" | mkCountryCode("MZ") 254 | "MM" | mkCountryCode("MM") 255 | "NA" | mkCountryCode("NA") 256 | "NR" | mkCountryCode("NR") 257 | "NP" | mkCountryCode("NP") 258 | "NL" | mkCountryCode("NL") 259 | "NC" | mkCountryCode("NC") 260 | "NZ" | mkCountryCode("NZ") 261 | "NI" | mkCountryCode("NI") 262 | "NE" | mkCountryCode("NE") 263 | "NG" | mkCountryCode("NG") 264 | "NU" | mkCountryCode("NU") 265 | "NF" | mkCountryCode("NF") 266 | "MP" | mkCountryCode("MP") 267 | "NO" | mkCountryCode("NO") 268 | "OM" | mkCountryCode("OM") 269 | "PK" | mkCountryCode("PK") 270 | "PW" | mkCountryCode("PW") 271 | "PS" | mkCountryCode("PS") 272 | "PA" | mkCountryCode("PA") 273 | "PG" | mkCountryCode("PG") 274 | "PY" | mkCountryCode("PY") 275 | "PE" | mkCountryCode("PE") 276 | "PH" | mkCountryCode("PH") 277 | "PN" | mkCountryCode("PN") 278 | "PL" | mkCountryCode("PL") 279 | "PT" | mkCountryCode("PT") 280 | "PR" | mkCountryCode("PR") 281 | "QA" | mkCountryCode("QA") 282 | "RE" | mkCountryCode("RE") 283 | "RO" | mkCountryCode("RO") 284 | "RU" | mkCountryCode("RU") 285 | "RW" | mkCountryCode("RW") 286 | "BL" | mkCountryCode("BL") 287 | "SH" | mkCountryCode("SH") 288 | "KN" | mkCountryCode("KN") 289 | "LC" | mkCountryCode("LC") 290 | "MF" | mkCountryCode("MF") 291 | "PM" | mkCountryCode("PM") 292 | "VC" | mkCountryCode("VC") 293 | "WS" | mkCountryCode("WS") 294 | "SM" | mkCountryCode("SM") 295 | "ST" | mkCountryCode("ST") 296 | "SA" | mkCountryCode("SA") 297 | "SN" | mkCountryCode("SN") 298 | "RS" | mkCountryCode("RS") 299 | "SC" | mkCountryCode("SC") 300 | "SL" | mkCountryCode("SL") 301 | "SG" | mkCountryCode("SG") 302 | "SX" | mkCountryCode("SX") 303 | "SK" | mkCountryCode("SK") 304 | "SI" | mkCountryCode("SI") 305 | "SB" | mkCountryCode("SB") 306 | "SO" | mkCountryCode("SO") 307 | "ZA" | mkCountryCode("ZA") 308 | "GS" | mkCountryCode("GS") 309 | "SS" | mkCountryCode("SS") 310 | "ES" | mkCountryCode("ES") 311 | "LK" | mkCountryCode("LK") 312 | "SD" | mkCountryCode("SD") 313 | "SR" | mkCountryCode("SR") 314 | "SJ" | mkCountryCode("SJ") 315 | "SZ" | mkCountryCode("SZ") 316 | "SE" | mkCountryCode("SE") 317 | "CH" | mkCountryCode("CH") 318 | "SY" | mkCountryCode("SY") 319 | "TW" | mkCountryCode("TW") 320 | "TJ" | mkCountryCode("TJ") 321 | "TZ" | mkCountryCode("TZ") 322 | "TH" | mkCountryCode("TH") 323 | "TL" | mkCountryCode("TL") 324 | "TG" | mkCountryCode("TG") 325 | "TK" | mkCountryCode("TK") 326 | "TO" | mkCountryCode("TO") 327 | "TT" | mkCountryCode("TT") 328 | "TN" | mkCountryCode("TN") 329 | "TR" | mkCountryCode("TR") 330 | "TM" | mkCountryCode("TM") 331 | "TC" | mkCountryCode("TC") 332 | "TV" | mkCountryCode("TV") 333 | "UG" | mkCountryCode("UG") 334 | "UA" | mkCountryCode("UA") 335 | "AE" | mkCountryCode("AE") 336 | "UM" | mkCountryCode("UM") 337 | "UY" | mkCountryCode("UY") 338 | "UZ" | mkCountryCode("UZ") 339 | "VU" | mkCountryCode("VU") 340 | "VE" | mkCountryCode("VE") 341 | "VN" | mkCountryCode("VN") 342 | "VG" | mkCountryCode("VG") 343 | "VI" | mkCountryCode("VI") 344 | "WF" | mkCountryCode("WF") 345 | "EH" | mkCountryCode("EH") 346 | "YE" | mkCountryCode("YE") 347 | "ZM" | mkCountryCode("ZM") 348 | "ZW" | mkCountryCode("ZW") 349 | } 350 | 351 | } 352 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/currency/CurrencyScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.currency 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseValueException 6 | import spock.lang.Specification 7 | import spock.lang.Unroll 8 | 9 | import static graphql.scalars.util.TestKit.mkCurrency 10 | import static graphql.scalars.util.TestKit.mkStringValue 11 | 12 | class CurrencyScalarTest extends Specification { 13 | 14 | 15 | def coercing = ExtendedScalars.Currency.getCoercing() 16 | 17 | @Unroll 18 | def "currency parseValue cases"() { 19 | 20 | when: 21 | def result = coercing.parseValue(input) 22 | then: 23 | result == expectedValue 24 | where: 25 | input | expectedValue 26 | 27 | "USD" | mkCurrency("USD") 28 | mkCurrency("USD") | mkCurrency("USD") 29 | "GBP" | mkCurrency("GBP") 30 | "EUR" | mkCurrency("EUR") 31 | "CNY" | mkCurrency("CNY") 32 | "ARS" | mkCurrency("ARS") 33 | mkCurrency("ARS") | mkCurrency("ARS") 34 | mkCurrency("ALL") | mkCurrency("ALL") 35 | mkCurrency("AMD") | mkCurrency("AMD") 36 | mkCurrency("ANG") | mkCurrency("ANG") 37 | mkCurrency("AOA") | mkCurrency("AOA") 38 | } 39 | 40 | 41 | @Unroll 42 | def "currency parseLiteral"() { 43 | 44 | when: 45 | def result = coercing.parseLiteral(input) 46 | then: 47 | result == expectedValue 48 | where: 49 | input | expectedValue 50 | new StringValue("EUR") | mkCurrency("EUR") 51 | new StringValue("USD") | mkCurrency("USD") 52 | new StringValue("GBP") | mkCurrency("GBP") 53 | } 54 | 55 | @Unroll 56 | def "currency serialize"() { 57 | 58 | when: 59 | def result = coercing.serialize(input) 60 | then: 61 | result == expectedValue 62 | where: 63 | input | expectedValue 64 | "USD" | "USD" 65 | mkCurrency("USD") | "USD" 66 | } 67 | 68 | @Unroll 69 | def "currency valueToLiteral"() { 70 | 71 | when: 72 | def result = coercing.valueToLiteral(input) 73 | then: 74 | result.isEqualTo(expectedValue) 75 | where: 76 | input | expectedValue 77 | "USD" | mkStringValue("USD") 78 | mkCurrency("USD") | mkStringValue("USD") 79 | } 80 | 81 | @Unroll 82 | def "parseValue throws exception for invalid input #value"() { 83 | when: 84 | coercing.parseValue(value) 85 | then: 86 | thrown(CoercingParseValueException) 87 | 88 | where: 89 | value | _ 90 | "" | _ 91 | "US_DOLLAR" | _ 92 | "not a currency " | _ 93 | "42.3" | _ 94 | new Double(42.3) | _ 95 | new Float(42.3) | _ 96 | new Object() | _ 97 | } 98 | 99 | 100 | @Unroll 101 | def "all currency ISO list parseValue"() { 102 | 103 | when: 104 | def result = coercing.parseValue(input) 105 | then: 106 | result == expectedValue 107 | where: 108 | input | expectedValue 109 | 110 | "USD" | mkCurrency("USD") 111 | "EUR" | mkCurrency("EUR") 112 | "GBP" | mkCurrency("GBP") 113 | "CNY" | mkCurrency("CNY") 114 | "AED" | mkCurrency("AED") 115 | "AFN" | mkCurrency("AFN") 116 | "ALL" | mkCurrency("ALL") 117 | "AMD" | mkCurrency("AMD") 118 | "ANG" | mkCurrency("ANG") 119 | "AOA" | mkCurrency("AOA") 120 | "ARS" | mkCurrency("ARS") 121 | "AUD" | mkCurrency("AUD") 122 | "AWG" | mkCurrency("AWG") 123 | "AZN" | mkCurrency("AZN") 124 | "BAM" | mkCurrency("BAM") 125 | "BBD" | mkCurrency("BBD") 126 | "BDT" | mkCurrency("BDT") 127 | "BGN" | mkCurrency("BGN") 128 | "BHD" | mkCurrency("BHD") 129 | "BIF" | mkCurrency("BIF") 130 | "BMD" | mkCurrency("BMD") 131 | "BND" | mkCurrency("BND") 132 | "BOB" | mkCurrency("BOB") 133 | "BOV" | mkCurrency("BOV") 134 | "BRL" | mkCurrency("BRL") 135 | "BSD" | mkCurrency("BSD") 136 | "BTN" | mkCurrency("BTN") 137 | "BWP" | mkCurrency("BWP") 138 | "BYN" | mkCurrency("BYN") 139 | "BZD" | mkCurrency("BZD") 140 | "CAD" | mkCurrency("CAD") 141 | "CDF" | mkCurrency("CDF") 142 | "CHE" | mkCurrency("CHE") 143 | "CHF" | mkCurrency("CHF") 144 | "CHW" | mkCurrency("CHW") 145 | "CLF" | mkCurrency("CLF") 146 | "CLP" | mkCurrency("CLP") 147 | "COP" | mkCurrency("COP") 148 | "COU" | mkCurrency("COU") 149 | "CRC" | mkCurrency("CRC") 150 | "CUC" | mkCurrency("CUC") 151 | "CUP" | mkCurrency("CUP") 152 | "CVE" | mkCurrency("CVE") 153 | "CZK" | mkCurrency("CZK") 154 | "DJF" | mkCurrency("DJF") 155 | "DKK" | mkCurrency("DKK") 156 | "DOP" | mkCurrency("DOP") 157 | "DZD" | mkCurrency("DZD") 158 | "EGP" | mkCurrency("EGP") 159 | "ERN" | mkCurrency("ERN") 160 | "ETB" | mkCurrency("ETB") 161 | "FJD" | mkCurrency("FJD") 162 | "FKP" | mkCurrency("FKP") 163 | "GEL" | mkCurrency("GEL") 164 | "GHS" | mkCurrency("GHS") 165 | "GIP" | mkCurrency("GIP") 166 | "GMD" | mkCurrency("GMD") 167 | "GNF" | mkCurrency("GNF") 168 | "GTQ" | mkCurrency("GTQ") 169 | "GYD" | mkCurrency("GYD") 170 | "HKD" | mkCurrency("HKD") 171 | "HNL" | mkCurrency("HNL") 172 | "HRK" | mkCurrency("HRK") 173 | "HTG" | mkCurrency("HTG") 174 | "HUF" | mkCurrency("HUF") 175 | "IDR" | mkCurrency("IDR") 176 | "ILS" | mkCurrency("ILS") 177 | "INR" | mkCurrency("INR") 178 | "IQD" | mkCurrency("IQD") 179 | "IRR" | mkCurrency("IRR") 180 | "ISK" | mkCurrency("ISK") 181 | "JMD" | mkCurrency("JMD") 182 | "JOD" | mkCurrency("JOD") 183 | "JPY" | mkCurrency("JPY") 184 | "KES" | mkCurrency("KES") 185 | "KGS" | mkCurrency("KGS") 186 | "KHR" | mkCurrency("KHR") 187 | "KMF" | mkCurrency("KMF") 188 | "KPW" | mkCurrency("KPW") 189 | "KRW" | mkCurrency("KRW") 190 | "KWD" | mkCurrency("KWD") 191 | "KYD" | mkCurrency("KYD") 192 | "KZT" | mkCurrency("KZT") 193 | "LAK" | mkCurrency("LAK") 194 | "LBP" | mkCurrency("LBP") 195 | "LKR" | mkCurrency("LKR") 196 | "LRD" | mkCurrency("LRD") 197 | "LSL" | mkCurrency("LSL") 198 | "LYD" | mkCurrency("LYD") 199 | "MAD" | mkCurrency("MAD") 200 | "MDL" | mkCurrency("MDL") 201 | "MGA" | mkCurrency("MGA") 202 | "MKD" | mkCurrency("MKD") 203 | "MMK" | mkCurrency("MMK") 204 | "MNT" | mkCurrency("MNT") 205 | "MOP" | mkCurrency("MOP") 206 | "MRU" | mkCurrency("MRU") 207 | "MUR" | mkCurrency("MUR") 208 | "MVR" | mkCurrency("MVR") 209 | "MWK" | mkCurrency("MWK") 210 | "MXN" | mkCurrency("MXN") 211 | "MXV" | mkCurrency("MXV") 212 | "MYR" | mkCurrency("MYR") 213 | "MZN" | mkCurrency("MZN") 214 | "NAD" | mkCurrency("NAD") 215 | "NGN" | mkCurrency("NGN") 216 | "NIO" | mkCurrency("NIO") 217 | "NOK" | mkCurrency("NOK") 218 | "NPR" | mkCurrency("NPR") 219 | "NZD" | mkCurrency("NZD") 220 | "OMR" | mkCurrency("OMR") 221 | "PAB" | mkCurrency("PAB") 222 | "PEN" | mkCurrency("PEN") 223 | "PGK" | mkCurrency("PGK") 224 | "PHP" | mkCurrency("PHP") 225 | "PKR" | mkCurrency("PKR") 226 | "PLN" | mkCurrency("PLN") 227 | "PYG" | mkCurrency("PYG") 228 | "QAR" | mkCurrency("QAR") 229 | "RON" | mkCurrency("RON") 230 | "RSD" | mkCurrency("RSD") 231 | "RWF" | mkCurrency("RWF") 232 | "RUB" | mkCurrency("RUB") 233 | "SAR" | mkCurrency("SAR") 234 | "SBD" | mkCurrency("SBD") 235 | "SCR" | mkCurrency("SCR") 236 | "SDG" | mkCurrency("SDG") 237 | "SEK" | mkCurrency("SEK") 238 | "SGD" | mkCurrency("SGD") 239 | "SHP" | mkCurrency("SHP") 240 | "SLL" | mkCurrency("SLL") 241 | "SOS" | mkCurrency("SOS") 242 | "SRD" | mkCurrency("SRD") 243 | "SSP" | mkCurrency("SSP") 244 | "STN" | mkCurrency("STN") 245 | "SVC" | mkCurrency("SVC") 246 | "SYP" | mkCurrency("SYP") 247 | "SZL" | mkCurrency("SZL") 248 | "THB" | mkCurrency("THB") 249 | "TJS" | mkCurrency("TJS") 250 | "TMT" | mkCurrency("TMT") 251 | "TND" | mkCurrency("TND") 252 | "TOP" | mkCurrency("TOP") 253 | "TRY" | mkCurrency("TRY") 254 | "TTD" | mkCurrency("TTD") 255 | "TWD" | mkCurrency("TWD") 256 | "TZS" | mkCurrency("TZS") 257 | "UAH" | mkCurrency("UAH") 258 | "UGX" | mkCurrency("UGX") 259 | "USN" | mkCurrency("USN") 260 | "UYI" | mkCurrency("UYI") 261 | "UYU" | mkCurrency("UYU") 262 | "UZS" | mkCurrency("UZS") 263 | "VEF" | mkCurrency("VEF") 264 | "VND" | mkCurrency("VND") 265 | "VUV" | mkCurrency("VUV") 266 | "WST" | mkCurrency("WST") 267 | "XAF" | mkCurrency("XAF") 268 | "XCD" | mkCurrency("XCD") 269 | "XDR" | mkCurrency("XDR") 270 | "XOF" | mkCurrency("XOF") 271 | "XPF" | mkCurrency("XPF") 272 | "XSU" | mkCurrency("XSU") 273 | "XUA" | mkCurrency("XUA") 274 | "YER" | mkCurrency("YER") 275 | "ZAR" | mkCurrency("ZAR") 276 | "ZMW" | mkCurrency("ZMW") 277 | "ZWL" | mkCurrency("ZWL") 278 | } 279 | 280 | 281 | } 282 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/datetime/DateScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.datetime 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import spock.lang.Specification 6 | import spock.lang.Unroll 7 | 8 | import static graphql.scalars.util.TestKit.mkLocalDate 9 | import static graphql.scalars.util.TestKit.mkOffsetDT 10 | import static graphql.scalars.util.TestKit.mkStringValue 11 | import static graphql.scalars.util.TestKit.mkZonedDT 12 | 13 | class DateScalarTest extends Specification { 14 | 15 | def coercing = ExtendedScalars.Date.getCoercing() 16 | 17 | @Unroll 18 | def "full date parseValue"() { 19 | 20 | when: 21 | def result = coercing.parseValue(input) 22 | then: 23 | result == expectedValue 24 | where: 25 | input | expectedValue 26 | "1937-01-01" | mkLocalDate("1937-01-01") 27 | mkOffsetDT(year: 1980, hour: 3) | mkLocalDate("1980-08-08") 28 | mkZonedDT(year: 1980, hour: 3) | mkLocalDate("1980-08-08") 29 | } 30 | 31 | @Unroll 32 | def "full date parseLiteral"() { 33 | 34 | when: 35 | def result = coercing.parseLiteral(input) 36 | then: 37 | result == expectedValue 38 | where: 39 | input | expectedValue 40 | new StringValue("1937-01-01") | mkLocalDate("1937-01-01") 41 | } 42 | 43 | @Unroll 44 | def "full date serialize"() { 45 | 46 | when: 47 | def result = coercing.serialize(input) 48 | then: 49 | result == expectedValue 50 | where: 51 | input | expectedValue 52 | "1937-01-01" | "1937-01-01" 53 | mkOffsetDT(year: 1980, hour: 3) | "1980-08-08" 54 | mkZonedDT(year: 1980, hour: 3) | "1980-08-08" 55 | } 56 | 57 | @Unroll 58 | def "full date valueToLiteral"() { 59 | 60 | when: 61 | def result = coercing.valueToLiteral(input) 62 | then: 63 | result.isEqualTo(expectedValue) 64 | where: 65 | input | expectedValue 66 | "1937-01-01" | mkStringValue("1937-01-01") 67 | mkOffsetDT(year: 1980, hour: 3) | mkStringValue("1980-08-08") 68 | mkZonedDT(year: 1980, hour: 3) | mkStringValue("1980-08-08") 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/datetime/DateTimeScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.datetime 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseLiteralException 6 | import graphql.schema.CoercingParseValueException 7 | import graphql.schema.CoercingSerializeException 8 | import spock.lang.Specification 9 | import spock.lang.Unroll 10 | 11 | import static graphql.scalars.util.TestKit.mkLocalDT 12 | import static graphql.scalars.util.TestKit.mkOffsetDT 13 | import static graphql.scalars.util.TestKit.mkStringValue 14 | import static graphql.scalars.util.TestKit.mkZonedDT 15 | 16 | class DateTimeScalarTest extends Specification { 17 | 18 | def coercing = ExtendedScalars.DateTime.getCoercing() 19 | 20 | @Unroll 21 | def "datetime parseValue"() { 22 | 23 | when: 24 | def result = coercing.parseValue(input) 25 | then: 26 | result == expectedValue 27 | where: 28 | input | expectedValue 29 | "1985-04-12T23:20:50.52Z" | mkOffsetDT("1985-04-12T23:20:50.52Z") 30 | "1996-12-19T16:39:57-08:00" | mkOffsetDT("1996-12-19T16:39:57-08:00") 31 | "1937-01-01T12:00:27.87+00:20" | mkOffsetDT("1937-01-01T12:00:27.87+00:20") 32 | "2022-11-24T01:00:01.02+00:00" | mkOffsetDT("2022-11-24T01:00:01.02+00:00") 33 | mkOffsetDT(year: 1980, hour: 3) | mkOffsetDT("1980-08-08T03:10:09+10:00") 34 | mkZonedDT(year: 1980, hour: 3) | mkOffsetDT("1980-08-08T03:10:09+10:00") 35 | } 36 | 37 | @Unroll 38 | def "datetime valueToLiteral"() { 39 | 40 | when: 41 | def result = coercing.valueToLiteral(input) 42 | then: 43 | result.isEqualTo(expectedValue) 44 | where: 45 | input | expectedValue 46 | "1985-04-12T23:20:50.52Z" | mkStringValue("1985-04-12T23:20:50.520Z") 47 | "1996-12-19T16:39:57-08:00" | mkStringValue("1996-12-19T16:39:57.000-08:00") 48 | "1937-01-01T12:00:27.87+00:20" | mkStringValue("1937-01-01T12:00:27.870+00:20") 49 | "1937-01-01T12:00+00:20" | mkStringValue("1937-01-01T12:00:00.000+00:20") 50 | "2022-11-24T01:00:01.02+00:00" | mkStringValue("2022-11-24T01:00:01.020Z") 51 | mkOffsetDT(year: 1980, hour: 3) | mkStringValue("1980-08-08T03:10:09.000+10:00") 52 | mkZonedDT(year: 1980, hour: 3) | mkStringValue("1980-08-08T03:10:09.000+10:00") 53 | } 54 | 55 | @Unroll 56 | def "datetime parseValue bad inputs"() { 57 | 58 | when: 59 | coercing.parseValue(input) 60 | then: 61 | thrown(expectedValue) 62 | where: 63 | input | expectedValue 64 | "1985-04-12" | CoercingParseValueException // No time provided 65 | "2022-11-24T01:00:01.02-00:00" | CoercingParseValueException // -00:00 is not a valid offset in specification 66 | mkLocalDT(year: 1980, hour: 3) | CoercingParseValueException // LocalDateTime has no time zone 67 | 666 | CoercingParseValueException // A random number 68 | "2011-08-30T13:22:53.108" | CoercingParseValueException // No offset provided 69 | "2011-08-30T24:22:53.108Z" | CoercingParseValueException // 24 is not allowed as hour of the time 70 | "2010-02-30T21:22:53.108Z" | CoercingParseValueException // 30th of February is not a valid date 71 | "2010-02-11T21:22:53.108Z+25:11" | CoercingParseValueException // 25 is not a valid hour for offset 72 | } 73 | 74 | def "datetime AST literal"() { 75 | 76 | when: 77 | def result = coercing.parseLiteral(input) 78 | then: 79 | result == expectedValue 80 | where: 81 | input | expectedValue 82 | new StringValue("1985-04-12T23:20:50.52Z") | mkOffsetDT("1985-04-12T23:20:50.52Z") 83 | } 84 | 85 | def "datetime serialisation"() { 86 | 87 | when: 88 | def result = coercing.serialize(input) 89 | then: 90 | result == expectedValue 91 | where: 92 | input | expectedValue 93 | "1985-04-12T23:20:50.52Z" | "1985-04-12T23:20:50.520Z" 94 | "1996-12-19T16:39:57-08:00" | "1996-12-19T16:39:57.000-08:00" 95 | "1937-01-01T12:00:27.87+00:20" | "1937-01-01T12:00:27.870+00:20" 96 | "2022-11-24T01:00:01.02+00:00" | "2022-11-24T01:00:01.020Z" 97 | mkOffsetDT(year: 1980, hour: 3) | "1980-08-08T03:10:09.000+10:00" 98 | mkZonedDT(year: 1980, hour: 3) | "1980-08-08T03:10:09.000+10:00" 99 | } 100 | 101 | def "datetime serialisation bad inputs"() { 102 | 103 | when: 104 | coercing.serialize(input) 105 | then: 106 | thrown(expectedValue) 107 | where: 108 | input | expectedValue 109 | "1985-04-12" | CoercingSerializeException // No time provided 110 | "2022-11-24T01:00:01.02-00:00" | CoercingSerializeException // -00:00 is not a valid offset in specification 111 | mkLocalDT(year: 1980, hour: 3) | CoercingSerializeException // LocalDateTime has no time zone 112 | 666 | CoercingSerializeException // A random number 113 | "2011-08-30T13:22:53.108" | CoercingSerializeException // No offset provided 114 | "2011-08-30T24:22:53.108Z" | CoercingSerializeException // 24 is not allowed as hour of the time 115 | "2010-02-30T21:22:53.108Z" | CoercingSerializeException // 30th of February is not a valid date 116 | "2010-02-11T21:22:53.108Z+25:11" | CoercingSerializeException // 25 is not a valid hour for offset 117 | } 118 | 119 | @Unroll 120 | def "datetime parseLiteral bad inputs"() { 121 | 122 | when: 123 | coercing.parseLiteral(input) 124 | then: 125 | thrown(expectedValue) 126 | where: 127 | input | expectedValue 128 | "2022-11-24T01:00:01.02-00:00" | CoercingParseLiteralException // -00:00 is not a valid offset in specification 129 | "1985-04-12" | CoercingParseLiteralException // No time provided 130 | "2022-11-24T01:00:01.02-00:00" | CoercingParseLiteralException // -00:00 is not a valid offset in specification 131 | mkLocalDT(year: 1980, hour: 3) | CoercingParseLiteralException // LocalDateTime has no time zone 132 | 666 | CoercingParseLiteralException // A random number 133 | "2011-08-30T13:22:53.108" | CoercingParseLiteralException // No offset provided 134 | "2011-08-30T24:22:53.108Z" | CoercingParseLiteralException // 24 is not allowed as hour of the time 135 | "2010-02-30T21:22:53.108Z" | CoercingParseLiteralException // 30th of February is not a valid date 136 | "2010-02-11T21:22:53.108Z+25:11" | CoercingParseLiteralException // 25 is not a valid hour for offset 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/datetime/LocalTimeScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.datetime 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseValueException 6 | import graphql.schema.CoercingSerializeException 7 | import spock.lang.Specification 8 | import spock.lang.Unroll 9 | 10 | import static graphql.scalars.util.TestKit.mkLocalT 11 | 12 | class LocalTimeScalarTest extends Specification { 13 | 14 | def coercing = ExtendedScalars.LocalTime.getCoercing() 15 | 16 | @Unroll 17 | def "localtime parseValue"() { 18 | 19 | when: 20 | def result = coercing.parseValue(input) 21 | then: 22 | result == expectedValue 23 | where: 24 | input | expectedValue 25 | "23:20:50.123456789" | mkLocalT("23:20:50.123456789") 26 | "16:39:57.000000000" | mkLocalT("16:39:57") 27 | "16:39:57.0" | mkLocalT("16:39:57") 28 | "16:39:57" | mkLocalT("16:39:57") 29 | } 30 | 31 | @Unroll 32 | def "localtime parseValue bad inputs"() { 33 | 34 | when: 35 | coercing.parseValue(input) 36 | then: 37 | thrown(expectedValue) 38 | where: 39 | input | expectedValue 40 | "23:20:50.52Z" | CoercingParseValueException 41 | "16:39:57-08:00" | CoercingParseValueException 42 | 666 || CoercingParseValueException 43 | } 44 | 45 | def "localtime AST literal"() { 46 | 47 | when: 48 | def result = coercing.parseLiteral(input) 49 | then: 50 | result == expectedValue 51 | where: 52 | input | expectedValue 53 | new StringValue("23:20:50.123456789") | mkLocalT("23:20:50.123456789") 54 | new StringValue("16:39:57.000000000") | mkLocalT("16:39:57") 55 | new StringValue("16:39:57.0") | mkLocalT("16:39:57") 56 | new StringValue("16:39:57") | mkLocalT("16:39:57") 57 | } 58 | 59 | def "localtime serialisation"() { 60 | 61 | when: 62 | def result = coercing.serialize(input) 63 | then: 64 | result == expectedValue 65 | where: 66 | input | expectedValue 67 | "23:20:50.123456789" | "23:20:50.123456789" 68 | "23:20:50" | "23:20:50" 69 | mkLocalT("16:39:57") | "16:39:57" 70 | mkLocalT("16:39:57.1") | "16:39:57.1" 71 | } 72 | 73 | def "datetime serialisation bad inputs"() { 74 | 75 | when: 76 | coercing.serialize(input) 77 | then: 78 | thrown(expectedValue) 79 | where: 80 | input | expectedValue 81 | "23:20:50.52Z" | CoercingSerializeException 82 | "16:39:57-08:00" | CoercingSerializeException 83 | 666 || CoercingSerializeException 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/datetime/TimeScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.datetime 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseValueException 6 | import graphql.schema.CoercingSerializeException 7 | import spock.lang.Specification 8 | import spock.lang.Unroll 9 | 10 | import static graphql.scalars.util.TestKit.mkLocalDT 11 | import static graphql.scalars.util.TestKit.mkOffsetDT 12 | import static graphql.scalars.util.TestKit.mkOffsetT 13 | import static graphql.scalars.util.TestKit.mkStringValue 14 | import static graphql.scalars.util.TestKit.mkZonedDT 15 | 16 | class TimeScalarTest extends Specification { 17 | 18 | def coercing = ExtendedScalars.Time.getCoercing() 19 | 20 | @Unroll 21 | def "datetime parseValue"() { 22 | 23 | when: 24 | def result = coercing.parseValue(input) 25 | then: 26 | result == expectedValue 27 | where: 28 | input | expectedValue 29 | "23:20:50.52Z" | mkOffsetT("23:20:50.52Z") 30 | "16:39:57-08:00" | mkOffsetT("16:39:57-08:00") 31 | "12:00:27.87+00:20" | mkOffsetT("12:00:27.87+00:20") 32 | mkOffsetDT(year: 1980, hour: 3) | mkOffsetT("03:10:09+10:00") 33 | mkZonedDT(year: 1980, hour: 3) | mkOffsetT("03:10:09+10:00") 34 | } 35 | 36 | @Unroll 37 | def "datetime parseValue bad inputs"() { 38 | 39 | when: 40 | coercing.parseValue(input) 41 | then: 42 | thrown(expectedValue) 43 | where: 44 | input | expectedValue 45 | "1985-04-12" | CoercingParseValueException 46 | mkLocalDT(year: 1980, hour: 3) | CoercingParseValueException 47 | 666 || CoercingParseValueException 48 | } 49 | 50 | def "datetime AST literal"() { 51 | 52 | when: 53 | def result = coercing.parseLiteral(input) 54 | then: 55 | result == expectedValue 56 | where: 57 | input | expectedValue 58 | new StringValue("23:20:50.52Z") | mkOffsetT("23:20:50.52Z") 59 | } 60 | 61 | def "datetime serialisation"() { 62 | 63 | when: 64 | def result = coercing.serialize(input) 65 | then: 66 | result == expectedValue 67 | where: 68 | input | expectedValue 69 | "23:20:50.52Z" | "23:20:50.52Z" 70 | "16:39:57-08:00" | "16:39:57-08:00" 71 | "12:00:27.87+00:20" | "12:00:27.87+00:20" 72 | mkOffsetDT(year: 1980, hour: 3) | "03:10:09+10:00" 73 | mkZonedDT(year: 1980, hour: 3) | "03:10:09+10:00" 74 | } 75 | 76 | def "datetime valueToLiteral"() { 77 | 78 | when: 79 | def result = coercing.valueToLiteral(input) 80 | then: 81 | result.isEqualTo(expectedValue) 82 | where: 83 | input | expectedValue 84 | "23:20:50.52Z" | mkStringValue("23:20:50.52Z") 85 | "16:39:57-08:00" | mkStringValue("16:39:57-08:00") 86 | "12:00:27.87+00:20" | mkStringValue("12:00:27.87+00:20") 87 | mkOffsetDT(year: 1980, hour: 3) | mkStringValue("03:10:09+10:00") 88 | mkZonedDT(year: 1980, hour: 3) | mkStringValue("03:10:09+10:00") 89 | } 90 | 91 | def "datetime serialisation bad inputs"() { 92 | 93 | when: 94 | coercing.serialize(input) 95 | then: 96 | thrown(expectedValue) 97 | where: 98 | input | expectedValue 99 | "1985-04-12" | CoercingSerializeException 100 | mkLocalDT(year: 1980, hour: 3) | CoercingSerializeException 101 | 666 || CoercingSerializeException 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/id/UUIDScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.id 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseLiteralException 6 | import graphql.schema.CoercingParseValueException 7 | import graphql.schema.CoercingSerializeException 8 | import spock.lang.Specification 9 | import spock.lang.Unroll 10 | 11 | import static graphql.scalars.util.TestKit.mkStringValue 12 | import static graphql.scalars.util.TestKit.mkUUIDValue 13 | 14 | class UUIDScalarTest extends Specification { 15 | 16 | def coercing = ExtendedScalars.UUID.getCoercing() 17 | 18 | @Unroll 19 | def "UUID parseValue"() { 20 | 21 | when: 22 | def result = coercing.parseValue(input) 23 | then: 24 | result == expectedValue 25 | where: 26 | input | expectedValue 27 | "43f20307-603c-4ad1-83c6-6010d224fabf" | mkUUIDValue("43f20307-603c-4ad1-83c6-6010d224fabf") 28 | "787dbc2b-3ddb-4098-ad1d-63d026bac111" | mkUUIDValue("787dbc2b-3ddb-4098-ad1d-63d026bac111") 29 | } 30 | 31 | @Unroll 32 | def "UUID parseValue bad inputs"() { 33 | 34 | when: 35 | coercing.parseValue(input) 36 | then: 37 | thrown(expectedValue) 38 | where: 39 | input | expectedValue 40 | "a-string-that-is-not-uuid" | CoercingParseValueException 41 | 100 | CoercingParseValueException 42 | "1985-04-12" | CoercingParseValueException 43 | } 44 | 45 | def "UUID AST literal"() { 46 | 47 | when: 48 | def result = coercing.parseLiteral(input) 49 | then: 50 | result == expectedValue 51 | where: 52 | input | expectedValue 53 | new StringValue("6972117d-3963-4214-ab2c-fa973d7e996b") | mkUUIDValue("6972117d-3963-4214-ab2c-fa973d7e996b") 54 | } 55 | 56 | def "UUID AST literal bad inputs"() { 57 | 58 | when: 59 | coercing.parseLiteral(input) 60 | then: 61 | thrown(expectedValue) 62 | where: 63 | input | expectedValue 64 | new StringValue("a-string-that-us-not-uuid") | CoercingParseLiteralException 65 | } 66 | 67 | def "UUID serialization"() { 68 | 69 | when: 70 | def result = coercing.serialize(input) 71 | then: 72 | result == expectedValue 73 | where: 74 | input | expectedValue 75 | "42287d47-c5bd-45e4-b470-53e426d3d503" | "42287d47-c5bd-45e4-b470-53e426d3d503" 76 | "423df0f3-cf05-4eb5-b708-ae2f4b4a052d" | "423df0f3-cf05-4eb5-b708-ae2f4b4a052d" 77 | mkUUIDValue("6a90b1e6-20f3-43e5-a7ba-34db8010c071") | "6a90b1e6-20f3-43e5-a7ba-34db8010c071" 78 | } 79 | 80 | def "UUID serialization bad inputs"() { 81 | 82 | when: 83 | coercing.serialize(input) 84 | then: 85 | thrown(expectedValue) 86 | where: 87 | input | expectedValue 88 | "1985-04-12" | CoercingSerializeException 89 | 100 | CoercingSerializeException 90 | } 91 | 92 | @Unroll 93 | def "UUID valueToLiteral"() { 94 | 95 | when: 96 | def result = coercing.valueToLiteral(input) 97 | then: 98 | result.isEqualTo(expectedValue) 99 | where: 100 | input | expectedValue 101 | "42287d47-c5bd-45e4-b470-53e426d3d503" | mkStringValue("42287d47-c5bd-45e4-b470-53e426d3d503") 102 | "423df0f3-cf05-4eb5-b708-ae2f4b4a052d" | mkStringValue("423df0f3-cf05-4eb5-b708-ae2f4b4a052d") 103 | mkUUIDValue("6a90b1e6-20f3-43e5-a7ba-34db8010c071") | mkStringValue("6a90b1e6-20f3-43e5-a7ba-34db8010c071") 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/java/ScalarsBigDecimalTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.java 2 | 3 | import graphql.language.BooleanValue 4 | import graphql.language.FloatValue 5 | import graphql.language.IntValue 6 | import graphql.language.StringValue 7 | import graphql.scalars.ExtendedScalars 8 | import graphql.schema.CoercingParseLiteralException 9 | import graphql.schema.CoercingParseValueException 10 | import graphql.schema.CoercingSerializeException 11 | import spock.lang.Specification 12 | import spock.lang.Unroll 13 | 14 | import java.util.concurrent.atomic.AtomicInteger 15 | 16 | class ScalarsBigDecimalTest extends Specification { 17 | 18 | @Unroll 19 | def "BigDecimal parse literal #literal.value as #result"() { 20 | expect: 21 | ExtendedScalars.GraphQLBigDecimal.getCoercing().parseLiteral(literal) == result 22 | 23 | where: 24 | literal | result 25 | new IntValue(12345678910 as BigInteger) | new BigDecimal("12345678910") 26 | new StringValue("12345678911.12") | new BigDecimal("12345678911.12") 27 | new FloatValue(new BigDecimal("42.42")) | new BigDecimal("42.42") 28 | 29 | } 30 | 31 | @Unroll 32 | def "BigDecimal returns null for invalid #literal"() { 33 | when: 34 | ExtendedScalars.GraphQLBigDecimal.getCoercing().parseLiteral(literal) 35 | then: 36 | thrown(CoercingParseLiteralException) 37 | 38 | where: 39 | literal | _ 40 | new BooleanValue(true) | _ 41 | new StringValue("not a number") | _ 42 | } 43 | 44 | @Unroll 45 | def "BigDecimal serialize #value into #result (#result.class)"() { 46 | expect: 47 | ExtendedScalars.GraphQLBigDecimal.getCoercing().serialize(value) == result 48 | ExtendedScalars.GraphQLBigDecimal.getCoercing().parseValue(value) == result 49 | 50 | where: 51 | value | result 52 | "42" | new BigDecimal("42") 53 | "42.123" | new BigDecimal("42.123") 54 | 42.0000d | new BigDecimal("42.000") 55 | new Integer(42) | new BigDecimal("42") 56 | "-1" | new BigDecimal("-1") 57 | new BigInteger(42) | new BigDecimal("42") 58 | new BigDecimal("42") | new BigDecimal("42") 59 | 42.3f | new BigDecimal("42.3") 60 | 42.0d | new BigDecimal("42") 61 | new Byte("42") | new BigDecimal("42") 62 | new Short("42") | new BigDecimal("42") 63 | 1234567l | new BigDecimal("1234567") 64 | new AtomicInteger(42) | new BigDecimal("42") 65 | } 66 | 67 | @Unroll 68 | def "serialize throws exception for invalid input #value"() { 69 | when: 70 | ExtendedScalars.GraphQLBigDecimal.getCoercing().serialize(value) 71 | then: 72 | thrown(CoercingSerializeException) 73 | 74 | where: 75 | value | _ 76 | "" | _ 77 | "not a number " | _ 78 | new Object() | _ 79 | } 80 | 81 | @Unroll 82 | def "parseValue throws exception for invalid input #value"() { 83 | when: 84 | ExtendedScalars.GraphQLBigDecimal.getCoercing().parseValue(value) 85 | then: 86 | thrown(CoercingParseValueException) 87 | 88 | where: 89 | value | _ 90 | "" | _ 91 | "not a number " | _ 92 | new Object() | _ 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/java/ScalarsBigIntegerTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.java 2 | 3 | import graphql.Scalars 4 | import graphql.language.BooleanValue 5 | import graphql.language.FloatValue 6 | import graphql.language.IntValue 7 | import graphql.language.StringValue 8 | import graphql.scalars.ExtendedScalars 9 | import graphql.schema.CoercingParseLiteralException 10 | import graphql.schema.CoercingParseValueException 11 | import graphql.schema.CoercingSerializeException 12 | import spock.lang.Specification 13 | import spock.lang.Unroll 14 | 15 | import java.util.concurrent.atomic.AtomicInteger 16 | 17 | class ScalarsBigIntegerTest extends Specification { 18 | 19 | @Unroll 20 | def "BigInteger parse literal #literal.value as #result"() { 21 | expect: 22 | ExtendedScalars.GraphQLBigInteger.getCoercing().parseLiteral(literal) == result 23 | 24 | where: 25 | literal | result 26 | new IntValue(12345678910 as BigInteger) | new BigInteger("12345678910") 27 | new StringValue("12345678911") | new BigInteger("12345678911") 28 | new FloatValue(new BigDecimal("42")) | new BigInteger("42") 29 | } 30 | 31 | @Unroll 32 | def "BigInteger returns null for invalid #literal"() { 33 | when: 34 | ExtendedScalars.GraphQLBigInteger.getCoercing().parseLiteral(literal) 35 | then: 36 | thrown(CoercingParseLiteralException) 37 | 38 | where: 39 | literal | _ 40 | new BooleanValue(true) | _ 41 | new StringValue("42.3") | _ 42 | new FloatValue(new BigDecimal("12.12")) | _ 43 | new StringValue("not a number") | _ 44 | } 45 | 46 | @Unroll 47 | def "BigInteger serialize #value into #result (#result.class)"() { 48 | expect: 49 | ExtendedScalars.GraphQLBigInteger.getCoercing().serialize(value) == result 50 | ExtendedScalars.GraphQLBigInteger.getCoercing().parseValue(value) == result 51 | 52 | where: 53 | value | result 54 | "42" | new BigInteger("42") 55 | new Integer(42) | new BigInteger("42") 56 | "-1" | new BigInteger("-1") 57 | new BigInteger("42") | new BigInteger("42") 58 | 42.0d | new BigInteger("42") 59 | new Byte("42") | new BigInteger("42") 60 | new Short("42") | new BigInteger("42") 61 | 1234567l | new BigInteger("1234567") 62 | new AtomicInteger(42) | new BigInteger("42") 63 | } 64 | 65 | @Unroll 66 | def "serialize throws exception for invalid input #value"() { 67 | when: 68 | ExtendedScalars.GraphQLBigInteger.getCoercing().serialize(value) 69 | then: 70 | thrown(CoercingSerializeException) 71 | 72 | where: 73 | value | _ 74 | "" | _ 75 | "not a number " | _ 76 | new BigDecimal("12.12") | _ 77 | "12.12" | _ 78 | new Object() | _ 79 | } 80 | 81 | @Unroll 82 | def "parseValue throws exception for invalid input #value"() { 83 | when: 84 | ExtendedScalars.GraphQLBigInteger.getCoercing().parseValue(value) 85 | then: 86 | thrown(CoercingParseValueException) 87 | 88 | where: 89 | value | _ 90 | "" | _ 91 | "not a number " | _ 92 | new BigDecimal("12.12") | _ 93 | "12.12" | _ 94 | new Object() | _ 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/java/ScalarsByteTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.java 2 | 3 | import graphql.scalars.ExtendedScalars 4 | import graphql.language.FloatValue 5 | import graphql.language.IntValue 6 | import graphql.language.StringValue 7 | import graphql.schema.CoercingParseLiteralException 8 | import graphql.schema.CoercingParseValueException 9 | import graphql.schema.CoercingSerializeException 10 | import spock.lang.Specification 11 | import spock.lang.Unroll 12 | 13 | import java.util.concurrent.atomic.AtomicInteger 14 | 15 | class ScalarsByteTest extends Specification { 16 | 17 | @Unroll 18 | def "Byte parse literal #literal.value as #result"() { 19 | expect: 20 | ExtendedScalars.GraphQLByte.getCoercing().parseLiteral(literal) == result 21 | 22 | where: 23 | literal | result 24 | new IntValue(42 as BigInteger) | 42 25 | new IntValue(Byte.MAX_VALUE as BigInteger) | Byte.MAX_VALUE 26 | new IntValue(Byte.MIN_VALUE as BigInteger) | Byte.MIN_VALUE 27 | 28 | } 29 | 30 | @Unroll 31 | def "Byte returns null for invalid #literal"() { 32 | when: 33 | ExtendedScalars.GraphQLByte.getCoercing().parseLiteral(literal) 34 | then: 35 | thrown(CoercingParseLiteralException) 36 | 37 | where: 38 | literal | _ 39 | new IntValue(12345678910 as BigInteger) | _ 40 | new StringValue("-1") | _ 41 | new FloatValue(42.3) | _ 42 | new IntValue(Byte.MAX_VALUE + 1l as BigInteger) | _ 43 | new IntValue(Byte.MIN_VALUE - 1l as BigInteger) | _ 44 | new StringValue("-1") | _ 45 | new FloatValue(42.3) | _ 46 | 47 | } 48 | 49 | @Unroll 50 | def "Byte serialize #value into #result (#result.class)"() { 51 | expect: 52 | ExtendedScalars.GraphQLByte.getCoercing().serialize(value) == result 53 | ExtendedScalars.GraphQLByte.getCoercing().parseValue(value) == result 54 | 55 | where: 56 | value | result 57 | "42" | 42 58 | "42.0000" | 42 59 | 42.0000d | 42 60 | new Integer(42) | 42 61 | "-1" | -1 62 | new BigInteger(42) | 42 63 | new BigDecimal("42") | 42 64 | 42.0f | 42 65 | 42.0d | 42 66 | new Byte("42") | 42 67 | new Short("42") | 42 68 | 123l | 123 69 | new AtomicInteger(42) | 42 70 | Byte.MAX_VALUE | Byte.MAX_VALUE 71 | Byte.MIN_VALUE | Byte.MIN_VALUE 72 | } 73 | 74 | @Unroll 75 | def "serialize throws exception for invalid input #value"() { 76 | when: 77 | ExtendedScalars.GraphQLByte.getCoercing().serialize(value) 78 | then: 79 | thrown(CoercingSerializeException) 80 | 81 | where: 82 | value | _ 83 | "" | _ 84 | "not a number " | _ 85 | "42.3" | _ 86 | new Long(42345784398534785l) | _ 87 | new Double(42.3) | _ 88 | new Float(42.3) | _ 89 | Byte.MAX_VALUE + 1l | _ 90 | Byte.MIN_VALUE - 1l | _ 91 | new Object() | _ 92 | 93 | } 94 | 95 | @Unroll 96 | def "parseValue throws exception for invalid input #value"() { 97 | when: 98 | ExtendedScalars.GraphQLByte.getCoercing().parseValue(value) 99 | then: 100 | thrown(CoercingParseValueException) 101 | 102 | where: 103 | value | _ 104 | "" | _ 105 | "not a number " | _ 106 | "42.3" | _ 107 | new Long(42345784398534785l) | _ 108 | new Double(42.3) | _ 109 | new Float(42.3) | _ 110 | Byte.MAX_VALUE + 1l | _ 111 | Byte.MIN_VALUE - 1l | _ 112 | new Object() | _ 113 | 114 | } 115 | 116 | } 117 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/java/ScalarsCharTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.java 2 | 3 | import graphql.scalars.ExtendedScalars 4 | import graphql.language.IntValue 5 | import graphql.language.StringValue 6 | import graphql.schema.CoercingParseLiteralException 7 | import graphql.schema.CoercingParseValueException 8 | import graphql.schema.CoercingSerializeException 9 | import spock.lang.Specification 10 | import spock.lang.Unroll 11 | 12 | class ScalarsCharTest extends Specification { 13 | 14 | @Unroll 15 | def "Char parse literal #literal.value as #result"() { 16 | expect: 17 | ExtendedScalars.GraphQLChar.getCoercing().parseLiteral(literal) == result 18 | 19 | where: 20 | literal | result 21 | new StringValue("a") | 'a' 22 | new StringValue("b") | 'b' 23 | 24 | } 25 | 26 | @Unroll 27 | def "Short returns null for invalid #literal"() { 28 | when: 29 | ExtendedScalars.GraphQLChar.getCoercing().parseLiteral(literal) 30 | then: 31 | thrown(CoercingParseLiteralException) 32 | 33 | where: 34 | literal | _ 35 | new StringValue("aa") | _ 36 | new IntValue(12 as BigInteger) | _ 37 | } 38 | 39 | @Unroll 40 | def "Short serialize #value into #result (#result.class)"() { 41 | expect: 42 | ExtendedScalars.GraphQLChar.getCoercing().serialize(value) == result 43 | ExtendedScalars.GraphQLChar.getCoercing().parseValue(value) == result 44 | 45 | where: 46 | value | result 47 | "a" | 'a' 48 | 'z' | 'z' 49 | } 50 | 51 | @Unroll 52 | def "serialize throws exception for invalid input #value"() { 53 | when: 54 | ExtendedScalars.GraphQLChar.getCoercing().serialize(value) 55 | then: 56 | thrown(CoercingSerializeException) 57 | 58 | where: 59 | value | _ 60 | "" | _ 61 | "aa" | _ 62 | new Object() | _ 63 | 64 | } 65 | 66 | @Unroll 67 | def "parseValue throws exception for invalid input #value"() { 68 | when: 69 | ExtendedScalars.GraphQLChar.getCoercing().parseValue(value) 70 | then: 71 | thrown(CoercingParseValueException) 72 | 73 | where: 74 | value | _ 75 | "" | _ 76 | "aa" | _ 77 | new Object() | _ 78 | 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/java/ScalarsLongTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.java 2 | 3 | import graphql.scalars.ExtendedScalars 4 | import graphql.language.FloatValue 5 | import graphql.language.IntValue 6 | import graphql.language.StringValue 7 | import graphql.schema.CoercingParseLiteralException 8 | import graphql.schema.CoercingParseValueException 9 | import graphql.schema.CoercingSerializeException 10 | import spock.lang.Shared 11 | import spock.lang.Specification 12 | import spock.lang.Unroll 13 | 14 | import java.util.concurrent.atomic.AtomicInteger 15 | 16 | class ScalarsLongTest extends Specification { 17 | 18 | @Shared 19 | def tooBig = new BigInteger(Long.toString(Long.MAX_VALUE)).add(new BigInteger("1")) 20 | @Shared 21 | def tooSmall = new BigInteger(Long.toString(Long.MIN_VALUE)).subtract(new BigInteger("1")) 22 | 23 | @Unroll 24 | def "Long parse literal #literal.value as #result"() { 25 | expect: 26 | ExtendedScalars.GraphQLLong.getCoercing().parseLiteral(literal) == result 27 | 28 | where: 29 | literal | result 30 | new IntValue(42 as BigInteger) | 42 31 | new IntValue(Long.MAX_VALUE as BigInteger) | Long.MAX_VALUE 32 | new IntValue(Long.MIN_VALUE as BigInteger) | Long.MIN_VALUE 33 | new StringValue("12345678910") | 12345678910 34 | new StringValue("-1") | -1 35 | 36 | } 37 | 38 | @Unroll 39 | def "Long returns null for invalid #literal"() { 40 | when: 41 | ExtendedScalars.GraphQLLong.getCoercing().parseLiteral(literal) 42 | then: 43 | thrown(CoercingParseLiteralException) 44 | 45 | where: 46 | literal | _ 47 | new StringValue("not a number") | _ 48 | new FloatValue(42.3) | _ 49 | tooBig | null 50 | tooSmall | null 51 | new FloatValue(42.3) | null 52 | } 53 | 54 | @Unroll 55 | def "Long serialize #value into #result (#result.class)"() { 56 | expect: 57 | ExtendedScalars.GraphQLLong.getCoercing().serialize(value) == result 58 | ExtendedScalars.GraphQLLong.getCoercing().parseValue(value) == result 59 | 60 | where: 61 | value | result 62 | "42" | 42 63 | "42.0000" | 42 64 | 42.0000d | 42 65 | new Integer(42) | 42 66 | "-1" | -1 67 | new BigInteger(42) | 42 68 | new BigDecimal("42") | 42 69 | 42.0f | 42 70 | 42.0d | 42 71 | new Byte("42") | 42 72 | new Short("42") | 42 73 | 12345678910l | 12345678910l 74 | new AtomicInteger(42) | 42 75 | Long.MAX_VALUE | Long.MAX_VALUE 76 | Long.MIN_VALUE | Long.MIN_VALUE 77 | new Long(42345784398534785l) | 42345784398534785l 78 | } 79 | 80 | @Unroll 81 | def "serialize throws exception for invalid input #value"() { 82 | when: 83 | ExtendedScalars.GraphQLLong.getCoercing().serialize(value) 84 | then: 85 | thrown(CoercingSerializeException) 86 | 87 | where: 88 | value | _ 89 | "" | _ 90 | "not a number " | _ 91 | "42.3" | _ 92 | new Double(42.3) | _ 93 | new Float(42.3) | _ 94 | tooBig | _ 95 | tooSmall | _ 96 | new Object() | _ 97 | } 98 | 99 | @Unroll 100 | def "parseValue throws exception for invalid input #value"() { 101 | when: 102 | ExtendedScalars.GraphQLLong.getCoercing().parseValue(value) 103 | then: 104 | thrown(CoercingParseValueException) 105 | 106 | where: 107 | value | _ 108 | "" | _ 109 | "not a number " | _ 110 | "42.3" | _ 111 | new Double(42.3) | _ 112 | new Float(42.3) | _ 113 | tooBig | _ 114 | tooSmall | _ 115 | new Object() | _ 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/java/ScalarsShortTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.java 2 | 3 | import graphql.language.FloatValue 4 | import graphql.language.IntValue 5 | import graphql.language.StringValue 6 | import graphql.scalars.ExtendedScalars 7 | import graphql.schema.CoercingParseLiteralException 8 | import graphql.schema.CoercingParseValueException 9 | import graphql.schema.CoercingSerializeException 10 | import spock.lang.Specification 11 | import spock.lang.Unroll 12 | 13 | import java.util.concurrent.atomic.AtomicInteger 14 | 15 | class ScalarsShortTest extends Specification { 16 | 17 | @Unroll 18 | def "Short parse literal #literal.value as #result"() { 19 | expect: 20 | ExtendedScalars.GraphQLShort.getCoercing().parseLiteral(literal) == result 21 | 22 | where: 23 | literal | result 24 | new IntValue(42 as BigInteger) | 42 25 | new IntValue(Short.MAX_VALUE as BigInteger) | Short.MAX_VALUE 26 | new IntValue(Short.MIN_VALUE as BigInteger) | Short.MIN_VALUE 27 | 28 | } 29 | 30 | @Unroll 31 | def "Short returns null for invalid #literal"() { 32 | when: 33 | ExtendedScalars.GraphQLShort.getCoercing().parseLiteral(literal) 34 | then: 35 | thrown(CoercingParseLiteralException) 36 | 37 | where: 38 | literal | _ 39 | new IntValue(12345678910 as BigInteger) | _ 40 | new StringValue("-1") | _ 41 | new FloatValue(42.3) | _ 42 | new IntValue(Short.MAX_VALUE + 1l as BigInteger) | null 43 | new IntValue(Short.MIN_VALUE - 1l as BigInteger) | null 44 | new StringValue("-1") | null 45 | new FloatValue(42.3) | null 46 | } 47 | 48 | @Unroll 49 | def "Short serialize #value into #result (#result.class)"() { 50 | expect: 51 | ExtendedScalars.GraphQLShort.getCoercing().serialize(value) == result 52 | ExtendedScalars.GraphQLShort.getCoercing().parseValue(value) == result 53 | 54 | where: 55 | value | result 56 | "42" | 42 57 | "42.0000" | 42 58 | 42.0000d | 42 59 | new Integer(42) | 42 60 | "-1" | -1 61 | new BigInteger(42) | 42 62 | new BigDecimal("42") | 42 63 | 42.0f | 42 64 | 42.0d | 42 65 | new Byte("42") | 42 66 | new Short("42") | 42 67 | 1234l | 1234 68 | new AtomicInteger(42) | 42 69 | Short.MAX_VALUE | Short.MAX_VALUE 70 | Short.MIN_VALUE | Short.MIN_VALUE 71 | } 72 | 73 | @Unroll 74 | def "serialize throws exception for invalid input #value"() { 75 | when: 76 | ExtendedScalars.GraphQLShort.getCoercing().serialize(value) 77 | then: 78 | thrown(CoercingSerializeException) 79 | 80 | where: 81 | value | _ 82 | "" | _ 83 | "not a number " | _ 84 | "42.3" | _ 85 | new Long(42345784398534785l) | _ 86 | new Double(42.3) | _ 87 | new Float(42.3) | _ 88 | Short.MAX_VALUE + 1l | _ 89 | Short.MIN_VALUE - 1l | _ 90 | new Object() | _ 91 | 92 | } 93 | 94 | @Unroll 95 | def "parseValue throws exception for invalid input #value"() { 96 | when: 97 | ExtendedScalars.GraphQLShort.getCoercing().parseValue(value) 98 | then: 99 | thrown(CoercingParseValueException) 100 | 101 | where: 102 | value | _ 103 | "" | _ 104 | "not a number " | _ 105 | "42.3" | _ 106 | new Long(42345784398534785l) | _ 107 | new Double(42.3) | _ 108 | new Float(42.3) | _ 109 | Short.MAX_VALUE + 1l | _ 110 | Short.MIN_VALUE - 1l | _ 111 | new Object() | _ 112 | 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/locale/LocaleScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.locale 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import spock.lang.Specification 6 | import spock.lang.Unroll 7 | 8 | import static graphql.scalars.util.TestKit.mkLocale 9 | import static graphql.scalars.util.TestKit.mkStringValue 10 | 11 | class LocaleScalarTest extends Specification { 12 | 13 | def coercing = ExtendedScalars.Locale.getCoercing() 14 | 15 | @Unroll 16 | def "full locale parseValue"() { 17 | 18 | when: 19 | def result = coercing.parseValue(input) 20 | then: 21 | result == expectedValue 22 | where: 23 | input | expectedValue 24 | "en" | mkLocale("en") 25 | "ro-RO" | mkLocale("ro-RO") 26 | "zh-hakka" | mkLocale("zh-hakka") 27 | mkLocale("en") | mkLocale("en") 28 | } 29 | 30 | @Unroll 31 | def "full Locale parseLiteral"() { 32 | when: 33 | def result = coercing.parseLiteral(input) 34 | then: 35 | result == expectedValue 36 | where: 37 | input | expectedValue 38 | new StringValue("ro-RO") | mkLocale("ro-RO") 39 | } 40 | 41 | @Unroll 42 | def "full Locale serialization"() { 43 | when: 44 | def result = coercing.serialize(input) 45 | then: 46 | result == expectedValue 47 | where: 48 | input | expectedValue 49 | "ro-RO" | "ro-RO" 50 | mkLocale("ro-RO") | "ro-RO" 51 | mkLocale("en") | "en" 52 | } 53 | 54 | @Unroll 55 | def "full Locale valueToLiteral"() { 56 | when: 57 | def result = coercing.valueToLiteral(input) 58 | then: 59 | result.isEqualTo(expectedValue) 60 | where: 61 | input | expectedValue 62 | "ro-RO" | mkStringValue("ro-RO") 63 | mkLocale("ro-RO") | mkStringValue("ro-RO") 64 | mkLocale("en") | mkStringValue("en") 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/numeric/NegativeFloatScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric 2 | 3 | 4 | import graphql.language.StringValue 5 | import graphql.scalars.ExtendedScalars 6 | import graphql.schema.CoercingParseLiteralException 7 | import graphql.schema.CoercingParseValueException 8 | import graphql.schema.CoercingSerializeException 9 | import spock.lang.Specification 10 | import spock.lang.Unroll 11 | 12 | import static graphql.scalars.util.TestKit.assertValueOrException 13 | import static graphql.scalars.util.TestKit.mkFloatValue 14 | import static graphql.scalars.util.TestKit.mkIntValue 15 | 16 | class NegativeFloatScalarTest extends Specification { 17 | def coercing = ExtendedScalars.NegativeFloat.getCoercing() 18 | 19 | @Unroll 20 | def "serialize"() { 21 | def result 22 | when: 23 | try { 24 | result = coercing.serialize(input) 25 | } catch (Exception e) { 26 | result = e 27 | } 28 | then: 29 | assertValueOrException(result, expectedResult) 30 | where: 31 | input || expectedResult 32 | "NaN" || CoercingSerializeException 33 | 1 || CoercingSerializeException 34 | 0 || CoercingSerializeException 35 | 66.6 || CoercingSerializeException 36 | 37 | -666 || -666 38 | -66.6 || -66.6 39 | } 40 | 41 | @Unroll 42 | def "parseValue"() { 43 | def result 44 | when: 45 | try { 46 | result = coercing.parseValue(input) 47 | } catch (Exception e) { 48 | result = e 49 | } 50 | then: 51 | assertValueOrException(result, expectedResult) 52 | where: 53 | input || expectedResult 54 | "NaN" || CoercingParseValueException 55 | 1 || CoercingParseValueException 56 | 0 || CoercingParseValueException 57 | 66.6 || CoercingParseValueException 58 | 59 | -666 || -666 60 | -66.6 || -66.6 61 | } 62 | 63 | @Unroll 64 | def "parseLiteral"() { 65 | def result 66 | when: 67 | try { 68 | result = coercing.parseLiteral(input) 69 | } catch (Exception e) { 70 | result = e 71 | } 72 | then: 73 | assertValueOrException(result, expectedResult) 74 | where: 75 | input || expectedResult 76 | new StringValue("NaN") || CoercingParseLiteralException 77 | mkIntValue(1) || CoercingParseLiteralException 78 | mkIntValue(0) || CoercingParseLiteralException 79 | mkFloatValue(66.6) || CoercingParseLiteralException 80 | 81 | mkIntValue(-666) || -666 82 | mkFloatValue(-66.6) || -66.6 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/numeric/NegativeIntScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseLiteralException 6 | import graphql.schema.CoercingParseValueException 7 | import graphql.schema.CoercingSerializeException 8 | import spock.lang.Specification 9 | import spock.lang.Unroll 10 | 11 | import static graphql.scalars.util.TestKit.assertValueOrException 12 | import static graphql.scalars.util.TestKit.mkIntValue 13 | 14 | class NegativeIntScalarTest extends Specification { 15 | def coercing = ExtendedScalars.NegativeInt.getCoercing() 16 | 17 | @Unroll 18 | def "serialize"() { 19 | def result 20 | when: 21 | try { 22 | result = coercing.serialize(input) 23 | } catch (Exception e) { 24 | result = e 25 | } 26 | then: 27 | assertValueOrException(result, expectedResult) 28 | where: 29 | input || expectedResult 30 | "NaN" || CoercingSerializeException 31 | 1 || CoercingSerializeException 32 | 0 || CoercingSerializeException 33 | 34 | -666 || -666 35 | } 36 | 37 | @Unroll 38 | def "parseValue"() { 39 | def result 40 | when: 41 | try { 42 | result = coercing.parseValue(input) 43 | } catch (Exception e) { 44 | result = e 45 | } 46 | then: 47 | assertValueOrException(result, expectedResult) 48 | where: 49 | input || expectedResult 50 | "NaN" || CoercingParseValueException 51 | 1 || CoercingParseValueException 52 | 0 || CoercingParseValueException 53 | 54 | -666 || -666 55 | } 56 | 57 | @Unroll 58 | def "parseLiteral"() { 59 | def result 60 | when: 61 | try { 62 | result = coercing.parseLiteral(input) 63 | } catch (Exception e) { 64 | result = e 65 | } 66 | then: 67 | assertValueOrException(result, expectedResult) 68 | where: 69 | input || expectedResult 70 | new StringValue("NaN") || CoercingParseLiteralException 71 | mkIntValue(1) || CoercingParseLiteralException 72 | mkIntValue(0) || CoercingParseLiteralException 73 | 74 | mkIntValue(-666) || -666 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/numeric/NonNegativeFloatScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseLiteralException 6 | import graphql.schema.CoercingParseValueException 7 | import graphql.schema.CoercingSerializeException 8 | import spock.lang.Specification 9 | import spock.lang.Unroll 10 | 11 | import static graphql.scalars.util.TestKit.assertValueOrException 12 | import static graphql.scalars.util.TestKit.mkFloatValue 13 | import static graphql.scalars.util.TestKit.mkIntValue 14 | 15 | class NonNegativeFloatScalarTest extends Specification { 16 | def coercing = ExtendedScalars.NonNegativeFloat.getCoercing() 17 | 18 | @Unroll 19 | def "serialize"() { 20 | def result 21 | when: 22 | try { 23 | result = coercing.serialize(input) 24 | } catch (Exception e) { 25 | result = e 26 | } 27 | then: 28 | assertValueOrException(result, expectedResult) 29 | where: 30 | input || expectedResult 31 | "NaN" || CoercingSerializeException 32 | -1 || CoercingSerializeException 33 | -66.6 || CoercingSerializeException 34 | 35 | 0 || 0 36 | 666 || 666 37 | 66.6 || 66.6 38 | } 39 | 40 | @Unroll 41 | def "parseValue"() { 42 | def result 43 | when: 44 | try { 45 | result = coercing.parseValue(input) 46 | } catch (Exception e) { 47 | result = e 48 | } 49 | then: 50 | assertValueOrException(result, expectedResult) 51 | where: 52 | input || expectedResult 53 | "NaN" || CoercingParseValueException 54 | -1 || CoercingParseValueException 55 | -66.6 || CoercingParseValueException 56 | 57 | 0 || 0 58 | 666 || 666 59 | 66.6 || 66.6 60 | } 61 | 62 | @Unroll 63 | def "parseLiteral"() { 64 | def result 65 | when: 66 | try { 67 | result = coercing.parseLiteral(input) 68 | } catch (Exception e) { 69 | result = e 70 | } 71 | then: 72 | assertValueOrException(result, expectedResult) 73 | where: 74 | input || expectedResult 75 | new StringValue("NaN") || CoercingParseLiteralException 76 | mkIntValue(-1) || CoercingParseLiteralException 77 | mkFloatValue(-66.6) || CoercingParseLiteralException 78 | 79 | mkIntValue(0) || 0 80 | mkIntValue(666) || 666 81 | mkFloatValue(66.6) || 66.6 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/numeric/NonNegativeIntScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseLiteralException 6 | import graphql.schema.CoercingParseValueException 7 | import graphql.schema.CoercingSerializeException 8 | import spock.lang.Specification 9 | import spock.lang.Unroll 10 | 11 | import static graphql.scalars.util.TestKit.assertValueOrException 12 | import static graphql.scalars.util.TestKit.mkIntValue 13 | 14 | class NonNegativeIntScalarTest extends Specification { 15 | def coercing = ExtendedScalars.NonNegativeInt.getCoercing() 16 | 17 | @Unroll 18 | def "serialize"() { 19 | def result 20 | when: 21 | try { 22 | result = coercing.serialize(input) 23 | } catch (Exception e) { 24 | result = e 25 | } 26 | then: 27 | assertValueOrException(result, expectedResult) 28 | where: 29 | input || expectedResult 30 | "NaN" || CoercingSerializeException 31 | -1 || CoercingSerializeException 32 | 33 | 0 || 0 34 | 666 || 666 35 | } 36 | 37 | @Unroll 38 | def "parseValue"() { 39 | def result 40 | when: 41 | try { 42 | result = coercing.parseValue(input) 43 | } catch (Exception e) { 44 | result = e 45 | } 46 | then: 47 | assertValueOrException(result, expectedResult) 48 | where: 49 | input || expectedResult 50 | "NaN" || CoercingParseValueException 51 | -1 || CoercingParseValueException 52 | 53 | 0 || 0 54 | 666 || 666 55 | } 56 | 57 | @Unroll 58 | def "parseLiteral"() { 59 | def result 60 | when: 61 | try { 62 | result = coercing.parseLiteral(input) 63 | } catch (Exception e) { 64 | result = e 65 | } 66 | then: 67 | assertValueOrException(result, expectedResult) 68 | where: 69 | input || expectedResult 70 | new StringValue("NaN") || CoercingParseLiteralException 71 | mkIntValue(-1) || CoercingParseLiteralException 72 | mkIntValue(0) || 0 73 | 74 | mkIntValue(666) || 666 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/numeric/NonPositiveFloatScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseLiteralException 6 | import graphql.schema.CoercingParseValueException 7 | import graphql.schema.CoercingSerializeException 8 | import spock.lang.Specification 9 | import spock.lang.Unroll 10 | 11 | import static graphql.scalars.util.TestKit.assertValueOrException 12 | import static graphql.scalars.util.TestKit.mkFloatValue 13 | import static graphql.scalars.util.TestKit.mkIntValue 14 | 15 | class NonPositiveFloatScalarTest extends Specification { 16 | def coercing = ExtendedScalars.NonPositiveFloat.getCoercing() 17 | 18 | @Unroll 19 | def "serialize"() { 20 | def result 21 | when: 22 | try { 23 | result = coercing.serialize(input) 24 | } catch (Exception e) { 25 | result = e 26 | } 27 | then: 28 | assertValueOrException(result, expectedResult) 29 | where: 30 | input || expectedResult 31 | "NaN" || CoercingSerializeException 32 | 1 || CoercingSerializeException 33 | 34 | 0 || 0 35 | -666 || -666 36 | -66.6 || -66.6 37 | } 38 | 39 | @Unroll 40 | def "parseValue"() { 41 | def result 42 | when: 43 | try { 44 | result = coercing.parseValue(input) 45 | } catch (Exception e) { 46 | result = e 47 | } 48 | then: 49 | assertValueOrException(result, expectedResult) 50 | where: 51 | input || expectedResult 52 | "NaN" || CoercingParseValueException 53 | 1 || CoercingParseValueException 54 | 55 | 0 || 0 56 | -666 || -666 57 | -66.6 || -66.6 58 | } 59 | 60 | @Unroll 61 | def "parseLiteral"() { 62 | def result 63 | when: 64 | try { 65 | result = coercing.parseLiteral(input) 66 | } catch (Exception e) { 67 | result = e 68 | } 69 | then: 70 | assertValueOrException(result, expectedResult) 71 | where: 72 | input || expectedResult 73 | new StringValue("NaN") || CoercingParseLiteralException 74 | mkIntValue(1) || CoercingParseLiteralException 75 | mkFloatValue(66.6) || CoercingParseLiteralException 76 | 77 | mkIntValue(0) || 0 78 | mkIntValue(-666) || -666 79 | mkFloatValue(-66.6) || -66.6 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/numeric/NonPositiveIntScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseLiteralException 6 | import graphql.schema.CoercingParseValueException 7 | import graphql.schema.CoercingSerializeException 8 | import spock.lang.Specification 9 | import spock.lang.Unroll 10 | 11 | import static graphql.scalars.util.TestKit.assertValueOrException 12 | import static graphql.scalars.util.TestKit.mkIntValue 13 | 14 | class NonPositiveIntScalarTest extends Specification { 15 | def coercing = ExtendedScalars.NonPositiveInt.getCoercing() 16 | 17 | @Unroll 18 | def "serialize"() { 19 | def result 20 | when: 21 | try { 22 | result = coercing.serialize(input) 23 | } catch (Exception e) { 24 | result = e 25 | } 26 | then: 27 | assertValueOrException(result, expectedResult) 28 | where: 29 | input || expectedResult 30 | "NaN" || CoercingSerializeException 31 | 1 || CoercingSerializeException 32 | 33 | 0 || 0 34 | -666 || -666 35 | } 36 | 37 | @Unroll 38 | def "parseValue"() { 39 | def result 40 | when: 41 | try { 42 | result = coercing.parseValue(input) 43 | } catch (Exception e) { 44 | result = e 45 | } 46 | then: 47 | assertValueOrException(result, expectedResult) 48 | where: 49 | input || expectedResult 50 | "NaN" || CoercingParseValueException 51 | 1 || CoercingParseValueException 52 | 53 | 0 || 0 54 | -666 || -666 55 | } 56 | 57 | @Unroll 58 | def "parseLiteral"() { 59 | def result 60 | when: 61 | try { 62 | result = coercing.parseLiteral(input) 63 | } catch (Exception e) { 64 | result = e 65 | } 66 | then: 67 | assertValueOrException(result, expectedResult) 68 | where: 69 | input || expectedResult 70 | new StringValue("NaN") || CoercingParseLiteralException 71 | mkIntValue(1) || CoercingParseLiteralException 72 | 73 | mkIntValue(0) || 0 74 | mkIntValue(-666) || -666 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/numeric/PositiveFloatScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseLiteralException 6 | import graphql.schema.CoercingParseValueException 7 | import graphql.schema.CoercingSerializeException 8 | import spock.lang.Specification 9 | import spock.lang.Unroll 10 | 11 | import static graphql.scalars.util.TestKit.assertValueOrException 12 | import static graphql.scalars.util.TestKit.mkFloatValue 13 | import static graphql.scalars.util.TestKit.mkIntValue 14 | 15 | class PositiveFloatScalarTest extends Specification { 16 | def coercing = ExtendedScalars.PositiveFloat.getCoercing() 17 | 18 | @Unroll 19 | def "serialize"() { 20 | def result 21 | when: 22 | try { 23 | result = coercing.serialize(input) 24 | } catch (Exception e) { 25 | result = e 26 | } 27 | then: 28 | assertValueOrException(result, expectedResult) 29 | where: 30 | input || expectedResult 31 | "NaN" || CoercingSerializeException 32 | -1 || CoercingSerializeException 33 | 0 || CoercingSerializeException 34 | -66.6 || CoercingSerializeException 35 | 36 | 666 || 666 37 | 66.6 || 66.6 38 | } 39 | 40 | @Unroll 41 | def "parseValue"() { 42 | def result 43 | when: 44 | try { 45 | result = coercing.parseValue(input) 46 | } catch (Exception e) { 47 | result = e 48 | } 49 | then: 50 | assertValueOrException(result, expectedResult) 51 | where: 52 | input || expectedResult 53 | "NaN" || CoercingParseValueException 54 | -1 || CoercingParseValueException 55 | 0 || CoercingParseValueException 56 | -66.6 || CoercingParseValueException 57 | 58 | 666 || 666 59 | 66.6 || 66.6 60 | } 61 | 62 | @Unroll 63 | def "parseLiteral"() { 64 | def result 65 | when: 66 | try { 67 | result = coercing.parseLiteral(input) 68 | } catch (Exception e) { 69 | result = e 70 | } 71 | then: 72 | assertValueOrException(result, expectedResult) 73 | where: 74 | input || expectedResult 75 | new StringValue("NaN") || CoercingParseLiteralException 76 | mkIntValue(-1) || CoercingParseLiteralException 77 | mkIntValue(0) || CoercingParseLiteralException 78 | mkFloatValue(-66.6) || CoercingParseLiteralException 79 | 80 | mkIntValue(666) || 666 81 | mkFloatValue(66.6) || 66.6 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/numeric/PositiveIntScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.numeric 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseLiteralException 6 | import graphql.schema.CoercingParseValueException 7 | import graphql.schema.CoercingSerializeException 8 | import spock.lang.Specification 9 | import spock.lang.Unroll 10 | 11 | import static graphql.scalars.util.TestKit.assertValueOrException 12 | import static graphql.scalars.util.TestKit.mkIntValue 13 | 14 | class PositiveIntScalarTest extends Specification { 15 | def coercing = ExtendedScalars.PositiveInt.getCoercing() 16 | 17 | @Unroll 18 | def "serialize"() { 19 | def result 20 | when: 21 | try { 22 | result = coercing.serialize(input) 23 | } catch (Exception e) { 24 | result = e 25 | } 26 | then: 27 | assertValueOrException(result, expectedResult) 28 | where: 29 | input || expectedResult 30 | "NaN" || CoercingSerializeException 31 | -1 || CoercingSerializeException 32 | 0 || CoercingSerializeException 33 | 666 || 666 34 | } 35 | 36 | @Unroll 37 | def "parseValue"() { 38 | def result 39 | when: 40 | try { 41 | result = coercing.parseValue(input) 42 | } catch (Exception e) { 43 | result = e 44 | } 45 | then: 46 | assertValueOrException(result, expectedResult) 47 | where: 48 | input || expectedResult 49 | "NaN" || CoercingParseValueException 50 | -1 || CoercingParseValueException 51 | 0 || CoercingParseValueException 52 | 666 || 666 53 | } 54 | 55 | @Unroll 56 | def "parseLiteral"() { 57 | def result 58 | when: 59 | try { 60 | result = coercing.parseLiteral(input) 61 | } catch (Exception e) { 62 | result = e 63 | } 64 | then: 65 | assertValueOrException(result, expectedResult) 66 | where: 67 | input || expectedResult 68 | new StringValue("NaN") || CoercingParseLiteralException 69 | mkIntValue(-1) || CoercingParseLiteralException 70 | mkIntValue(0) || CoercingParseLiteralException 71 | mkIntValue(666) || 666 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/object/ObjectScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.object 2 | 3 | import graphql.language.ArrayValue 4 | import graphql.language.BooleanValue 5 | import graphql.language.EnumValue 6 | import graphql.language.FloatValue 7 | import graphql.language.IntValue 8 | import graphql.language.NullValue 9 | import graphql.language.ObjectField 10 | import graphql.language.ObjectValue 11 | import graphql.language.StringValue 12 | import graphql.language.Value 13 | import graphql.language.VariableReference 14 | import graphql.scalars.ExtendedScalars 15 | import spock.lang.Specification 16 | import spock.lang.Unroll 17 | 18 | class ObjectScalarTest extends Specification { 19 | 20 | def variables = [ 21 | "varRef1": "value1" 22 | ] 23 | 24 | def coercing = ExtendedScalars.Object.getCoercing() 25 | 26 | @Unroll 27 | def "test AST parsing"() { 28 | 29 | when: 30 | def result = coercing.parseLiteral(input, variables) 31 | then: 32 | result == expectedResult 33 | where: 34 | input | expectedResult 35 | mkStringValue("s") | "s" 36 | mkFloatValue("99.9") | new BigDecimal("99.9") 37 | mkIntValue(666) | 666 38 | mkBooleanValue(true) | true 39 | mkEnumValue("enum") | "enum" 40 | mkVarRef("varRef1") | "value1" 41 | mkArrayValue([ 42 | mkStringValue("s"), mkIntValue(666) 43 | ] as List) | ["s", 666] 44 | } 45 | 46 | @Unroll 47 | def "test AST object parsing"() { 48 | 49 | when: 50 | def result = coercing.parseLiteral(input, variables) 51 | then: 52 | result == expectedResult 53 | where: 54 | input | expectedResult 55 | mkObjectValue([ 56 | fld1: mkStringValue("s"), 57 | fld2: mkIntValue(99), 58 | fld3: mkObjectValue([ 59 | childFld1: mkStringValue("child1"), 60 | childFl2 : mkVarRef("varRef1") 61 | ] as Map) 62 | ] as Map) | [fld1: "s", fld2: 99, fld3: [childFld1: "child1", childFl2: "value1"]] 63 | 64 | mkObjectValue([ 65 | field1: mkNullValue() 66 | ] as Map) | [field1: null] // Nested NullValue inside ObjectValue 67 | } 68 | 69 | @Unroll 70 | def "test serialize is always in and out"() { 71 | when: 72 | def result = coercing.serialize(input) 73 | then: 74 | result == expectedResult 75 | where: 76 | input | expectedResult 77 | 666 | 666 78 | "same" | "same" 79 | } 80 | 81 | @Unroll 82 | def "test parseValue is always in and out"() { 83 | when: 84 | def result = coercing.parseValue(input) 85 | then: 86 | result == expectedResult 87 | where: 88 | input | expectedResult 89 | 666 | 666 90 | "same" | "same" 91 | } 92 | 93 | @Unroll 94 | def "test valueToLiteral #input"() { 95 | when: 96 | def result = coercing.valueToLiteral(input) 97 | then: 98 | result.isEqualTo(expectedResult) 99 | where: 100 | input | expectedResult 101 | "cba" | mkStringValue("cba") 102 | 666 | mkIntValue(666) 103 | 666.99 | mkFloatValue("666.99") 104 | true | mkBooleanValue(true) 105 | null | mkNullValue() 106 | 107 | [l1: [l2: [l3: "x"]]] | mkObjectValue( 108 | [l1: mkObjectValue( 109 | [l2: mkObjectValue( 110 | [l3: mkStringValue("x")] 111 | )] 112 | )] 113 | ) 114 | ["x", 1, true] | mkArrayValue([ 115 | mkStringValue("x"), 116 | mkIntValue(1), 117 | mkBooleanValue(true)] as List) 118 | } 119 | 120 | 121 | ObjectValue mkObjectValue(Map fields) { 122 | def list = [] 123 | for (String key : fields.keySet()) { 124 | list.add(new ObjectField(key, fields.get(key))) 125 | } 126 | new ObjectValue(list) 127 | } 128 | 129 | VariableReference mkVarRef(String name) { 130 | new VariableReference(name) 131 | } 132 | 133 | ArrayValue mkArrayValue(List values) { 134 | return new ArrayValue(values) 135 | } 136 | 137 | NullValue mkNullValue() { 138 | return NullValue.newNullValue().build() 139 | } 140 | 141 | EnumValue mkEnumValue(String val) { 142 | new EnumValue(val) 143 | } 144 | 145 | BooleanValue mkBooleanValue(boolean val) { 146 | return new BooleanValue(val) 147 | } 148 | 149 | IntValue mkIntValue(int val) { 150 | new IntValue(BigInteger.valueOf(val)) 151 | } 152 | 153 | FloatValue mkFloatValue(String val) { 154 | new FloatValue(new BigDecimal(val)) 155 | } 156 | 157 | StringValue mkStringValue(String val) { 158 | new StringValue(val) 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/regex/RegexScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.regex 2 | 3 | import graphql.language.StringValue 4 | import graphql.scalars.ExtendedScalars 5 | import graphql.schema.CoercingParseLiteralException 6 | import graphql.schema.CoercingParseValueException 7 | import graphql.schema.CoercingSerializeException 8 | import graphql.schema.GraphQLScalarType 9 | import spock.lang.Specification 10 | import spock.lang.Unroll 11 | 12 | import java.util.regex.Pattern 13 | 14 | import static graphql.scalars.util.TestKit.mkStringValue 15 | 16 | class RegexScalarTest extends Specification { 17 | 18 | GraphQLScalarType phoneNumberScalar = ExtendedScalars.newRegexScalar("phoneNumber") 19 | .addPattern(Pattern.compile("\\([0-9]*\\)[0-9]*")) 20 | .build() 21 | 22 | @Unroll 23 | def "basic regex parseValue"() { 24 | 25 | when: 26 | def result = phoneNumberScalar.getCoercing().parseValue(input) 27 | then: 28 | result == expectedResult 29 | where: 30 | input || expectedResult 31 | "(02)998768" || "(02)998768" 32 | } 33 | 34 | @Unroll 35 | def "basic regex parseValue bad input"() { 36 | when: 37 | phoneNumberScalar.getCoercing().parseValue(input) 38 | then: 39 | thrown(expectedResult) 40 | where: 41 | input || expectedResult 42 | "(02)abc123" || CoercingParseValueException 43 | } 44 | 45 | @Unroll 46 | def "basic regex parseLiteral"() { 47 | 48 | when: 49 | def result = phoneNumberScalar.getCoercing().parseLiteral(input) 50 | then: 51 | result == expectedResult 52 | where: 53 | input || expectedResult 54 | new StringValue("(02)998768") || "(02)998768" 55 | } 56 | 57 | @Unroll 58 | def "basic regex parseLiteral bad input"() { 59 | when: 60 | phoneNumberScalar.getCoercing().parseLiteral(input) 61 | then: 62 | thrown(expectedResult) 63 | where: 64 | input || expectedResult 65 | "(02)abc123" || CoercingParseLiteralException 66 | } 67 | 68 | @Unroll 69 | def "basic regex serialize"() { 70 | 71 | when: 72 | def result = phoneNumberScalar.getCoercing().serialize(input) 73 | then: 74 | result == expectedResult 75 | where: 76 | input || expectedResult 77 | "(02)998768" || "(02)998768" 78 | } 79 | 80 | @Unroll 81 | def "basic regex valueToLiteral"() { 82 | 83 | when: 84 | def result = phoneNumberScalar.getCoercing().valueToLiteral(input) 85 | then: 86 | result.isEqualTo(expectedResult) 87 | where: 88 | input || expectedResult 89 | "(02)998768" || mkStringValue("(02)998768") 90 | } 91 | 92 | @Unroll 93 | def "basic regex serialize bad input"() { 94 | when: 95 | phoneNumberScalar.getCoercing().serialize(input) 96 | then: 97 | thrown(expectedResult) 98 | where: 99 | input || expectedResult 100 | "(02)abc123" || CoercingSerializeException 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/url/UrlScalarTest.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.url 2 | 3 | import graphql.language.BooleanValue 4 | import graphql.language.StringValue 5 | import graphql.scalars.ExtendedScalars 6 | import graphql.schema.CoercingParseLiteralException 7 | import graphql.schema.CoercingParseValueException 8 | import graphql.schema.CoercingSerializeException 9 | import spock.lang.Specification 10 | import spock.lang.Unroll 11 | 12 | import static graphql.scalars.util.TestKit.mkStringValue 13 | 14 | class UrlScalarTest extends Specification { 15 | 16 | def coercing = ExtendedScalars.Url.getCoercing() 17 | 18 | @Unroll 19 | def "test serialize"() { 20 | 21 | when: 22 | def result = coercing.serialize(input) 23 | then: 24 | result == expectedResult 25 | where: 26 | input | expectedResult 27 | new URL("http://www.graphql-java.com/") | new URL("http://www.graphql-java.com/") 28 | new URI("http://www.graphql-java.com/") | new URL("http://www.graphql-java.com/") 29 | new File("/this/that") | new URL("file:/this/that") 30 | "http://www.graphql-java.com/" | new URL("http://www.graphql-java.com/") 31 | } 32 | 33 | @Unroll 34 | def "test valueToLiteral"() { 35 | 36 | when: 37 | def result = coercing.valueToLiteral(input) 38 | then: 39 | result.isEqualTo(expectedResult) 40 | where: 41 | input | expectedResult 42 | new URL("http://www.graphql-java.com/") | mkStringValue("http://www.graphql-java.com/") 43 | new URI("http://www.graphql-java.com/") | mkStringValue("http://www.graphql-java.com/") 44 | new File("/this/that") | mkStringValue("file:/this/that") 45 | "http://www.graphql-java.com/" | mkStringValue("http://www.graphql-java.com/") 46 | } 47 | 48 | @Unroll 49 | def "test serialize bad inputs"() { 50 | when: 51 | coercing.serialize(input) 52 | then: 53 | thrown(exceptionClas) 54 | where: 55 | input || exceptionClas 56 | 666 || CoercingSerializeException 57 | "not/a/url" || CoercingSerializeException 58 | } 59 | 60 | @Unroll 61 | def "test parseValue"() { 62 | when: 63 | def result = coercing.parseValue(input) 64 | then: 65 | result == expectedResult 66 | where: 67 | input | expectedResult 68 | new URL("http://www.graphql-java.com/") | new URL("http://www.graphql-java.com/") 69 | new URI("http://www.graphql-java.com/") | new URL("http://www.graphql-java.com/") 70 | new File("/this/that") | new URL("file:/this/that") 71 | "http://www.graphql-java.com/" | new URL("http://www.graphql-java.com/") 72 | } 73 | 74 | @Unroll 75 | def "test parseValue bad inputs"() { 76 | when: 77 | coercing.parseValue(input) 78 | then: 79 | thrown(exceptionClas) 80 | where: 81 | input || exceptionClas 82 | 666 || CoercingParseValueException 83 | "not/a/url" || CoercingParseValueException 84 | } 85 | 86 | @Unroll 87 | def "test parseLiteral"() { 88 | when: 89 | def result = coercing.parseLiteral(input) 90 | then: 91 | result == expectedResult 92 | where: 93 | input | expectedResult 94 | new StringValue("http://www.graphql-java.com/") | new URL("http://www.graphql-java.com/") 95 | } 96 | 97 | @Unroll 98 | def "test parseLiteral bad inputs"() { 99 | when: 100 | coercing.parseLiteral(input) 101 | then: 102 | thrown(exceptionClas) 103 | where: 104 | input | exceptionClas 105 | new BooleanValue(true) | CoercingParseLiteralException 106 | new StringValue("not/a/url") | CoercingParseLiteralException 107 | } 108 | 109 | 110 | } -------------------------------------------------------------------------------- /src/test/groovy/graphql/scalars/util/TestKit.groovy: -------------------------------------------------------------------------------- 1 | package graphql.scalars.util 2 | 3 | import graphql.language.FloatValue 4 | import graphql.language.IntValue 5 | import graphql.language.StringValue 6 | import graphql.scalars.country.code.CountryCode 7 | 8 | import java.time.LocalDate 9 | import java.time.LocalDateTime 10 | import java.time.LocalTime 11 | import java.time.OffsetDateTime 12 | import java.time.OffsetTime 13 | import java.time.ZoneId 14 | import java.time.ZoneOffset 15 | import java.time.ZonedDateTime 16 | 17 | class TestKit { 18 | 19 | static Locale mkLocale(String s) { 20 | Locale.forLanguageTag(s) 21 | } 22 | 23 | static LocalDate mkLocalDate(String s) { 24 | LocalDate.parse(s) 25 | } 26 | 27 | static OffsetDateTime mkOffsetDT(String s) { 28 | OffsetDateTime.parse(s) 29 | } 30 | 31 | static OffsetTime mkOffsetT(String s) { 32 | OffsetTime.parse(s) 33 | } 34 | 35 | static LocalTime mkLocalT(String s) { 36 | LocalTime.parse(s) 37 | } 38 | 39 | static OffsetDateTime mkOffsetDT(args) { 40 | OffsetDateTime.of(args.year ?: 1969, args.month ?: 8, args.day ?: 8, args.hour ?: 11, 41 | args.min ?: 10, args.secs ?: 9, args.nanos ?: 0, ZoneOffset.ofHours(10)) 42 | } 43 | 44 | static LocalDateTime mkLocalDT(args) { 45 | LocalDateTime.of(args.year ?: 1969, args.month ?: 8, args.day ?: 8, args.hour ?: 11, 46 | args.min ?: 10, args.secs ?: 9, args.nanos ?: 0) 47 | } 48 | 49 | static ZonedDateTime mkZonedDT(args) { 50 | ZonedDateTime.of(args.year ?: 1969, args.month ?: 8, args.day ?: 8, args.hour ?: 11, 51 | args.min ?: 10, args.secs ?: 9, args.nanos ?: 0, ZoneId.ofOffset("", ZoneOffset.ofHours(10))) 52 | } 53 | 54 | 55 | static assertValueOrException(result, expectedResult) { 56 | if (result instanceof Exception) { 57 | assert result.class == expectedResult, "was " + result + " but expected exception " + expectedResult 58 | } else { 59 | assert result == expectedResult, "was " + result + " but expected " + expectedResult 60 | } 61 | true 62 | } 63 | 64 | 65 | static IntValue mkIntValue(int i) { 66 | return new IntValue(new BigInteger(String.valueOf(i))) 67 | } 68 | 69 | static IntValue mkIntValue(String s) { 70 | return new IntValue(new BigInteger(String.valueOf(s))) 71 | } 72 | 73 | static FloatValue mkFloatValue(int i) { 74 | return new FloatValue(new BigDecimal(String.valueOf(i))) 75 | } 76 | 77 | static FloatValue mkFloatValue(String s) { 78 | return new FloatValue(new BigDecimal(String.valueOf(s))) 79 | } 80 | 81 | static StringValue mkStringValue(String s) { 82 | return new StringValue(s) 83 | } 84 | 85 | static FloatValue mkFloatValue(double d) { 86 | return new FloatValue(new BigDecimal(d)) 87 | } 88 | 89 | static UUID mkUUIDValue(String s) { 90 | return UUID.fromString(s) 91 | } 92 | 93 | static Currency mkCurrency(String currency) { 94 | return Currency.getInstance(currency) 95 | } 96 | 97 | static CountryCode mkCountryCode(String countryCode) { 98 | return CountryCode.valueOf(countryCode) 99 | } 100 | } 101 | --------------------------------------------------------------------------------