Skip to content

Commit

Permalink
feat: add support for Decimal scalar (#96)
Browse files Browse the repository at this point in the history
Co-authored-by: Jason Kuhrt <jasonkuhrt@me.com>
  • Loading branch information
iddan and jasonkuhrt authored Jul 28, 2021
1 parent 915d38e commit 74da7c2
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 5 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export const schema = makeSchema({
##### Shortterm

- [x] ([#59](https://github.com/prisma/nexus-prisma/issues/59)) Support for Prisma Model field type `BigInt`
- [ ] ([#94](https://github.com/prisma/nexus-prisma/issues/94)) Support for Prisma Model field type `Decimal`
- [x] ([#94](https://github.com/prisma/nexus-prisma/issues/94)) Support for Prisma Model field type `Decimal`
- [ ] Improved JSDoc for relation 1:1 & 1:n fields

##### Midterm
Expand Down Expand Up @@ -227,8 +227,9 @@ However some of the Prisma scalars do not have a natural standard representation
| `DateTime` | `DateTime` | `dateTime` | [DateTime](https://www.graphql-scalars.dev/docs/scalars/datetime) | |
| `BigInt` | `BigInt` | `bigInt` | [BigInt](https://www.graphql-scalars.dev/docs/scalars/big-int) | [JavaScript BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) |
| `Bytes` | `Bytes` | `bytes` | [Byte](https://www.graphql-scalars.dev/docs/scalars/byte/) | [Node.js Buffer](https://nodejs.org/api/buffer.html#buffer_buffer) |
| `Decimal` | `Decimal` | `decimal` | (internal) | Uses [Decimal.js](https://github.com/MikeMcl/decimal.js) |

> **Note:** Not all Prisma scalar mappings are implemented yet: `Decimal`, `Unsupported`
> **Note:** Not all Prisma scalar mappings are implemented yet: `Unsupported`
> **Note:** BigInt is supported in Node.js since version [10.4.0](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#browser_compatibility) however to support BigInt in `JSON.parse`/`JSON.stringify` you must use [`json-bigint-patch`](https://github.com/ardatan/json-bigint-patch) otherwise BigInt values will be serialized as strings.
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"dependencies": {
"@prisma/generator-helper": "^2.27.0",
"debug": "^4.3.2",
"decimal.js": "^10.3.1",
"dindist": "^1.0.2",
"expand-tilde": "^2.0.2",
"fs-jetpack": "^4.1.0",
Expand Down
6 changes: 5 additions & 1 deletion src/entrypoints/scalars.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BigInt } from '../scalars/BigInt'
import { Bytes } from '../scalars/Bytes'
import { DateTime } from '../scalars/DateTime'
import { Decimal } from '../scalars/Decimal'
import { Json } from '../scalars/Json'

/**
Expand All @@ -13,6 +14,8 @@ import { Json } from '../scalars/Json'
* | `DateTime` | `DateTime` | `dateTime` | [DateTime](https://www.graphql-scalars.dev/docs/scalars/datetime) | |
* | `BigInt` | `BigInt` | `bigInt` | [BigInt](https://www.graphql-scalars.dev/docs/scalars/big-int) | [JavaScript BigInt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) |
* | `Bytes` | `Bytes` | `bytes` | [Byte](https://www.graphql-scalars.dev/docs/scalars/byte/) | [Node.js Buffer](https://nodejs.org/api/buffer.html#buffer_buffer) |
* | `Decimal` | `Decimal` | `decimal` | (internal) | Uses [Decimal.js](https://github.com/MikeMcl/decimal.js)
* |.
*
* @example
*
Expand Down Expand Up @@ -76,9 +79,10 @@ const NexusPrismaScalars = {
BigInt,
Bytes,
DateTime,
Decimal,
Json,
}

export default NexusPrismaScalars

export { BigInt, Bytes, DateTime, Json }
export { BigInt, Bytes, DateTime, Decimal, Json }
2 changes: 1 addition & 1 deletion src/generator/models/declaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ export function fieldTypeToGraphQLType(
return 'Bytes'
}
case 'Decimal': {
return StandardGraphQLScalarTypes.String
return 'Decimal'
}
default: {
return allCasesHandled(typeName)
Expand Down
62 changes: 62 additions & 0 deletions src/scalars/Decimal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { asNexusMethod } from 'nexus'
import * as DecimalJs from 'decimal.js'

import { GraphQLScalarType, Kind } from 'graphql'

/**
* A Nexus scalar type definition for arbitrary-precision Decimal type.
*
* Contributes a scalar to your GraphQL schema called `Decimal`.
*
* Contributes a `t` `[1]` helper method called `decimal`
*
* `[1]` A `t` helper method refers to a method on the argument given to a `definition` method. Helper methods
* here typically help you quickly create new fields.
*
* @example
*
* import { makeSchema, objectType } from 'nexus'
* import { Decimal } from 'nexus-prisma/scalars'
*
* SomeObject = objectType({
* name: 'SomeObject',
* definition(t) {
* t.decimal('someDecimalField')
* },
* })
*
* makeSchema({
* types: [Decimal, SomeObject],
* })
*
*/
export const Decimal = asNexusMethod(
/**
* Copied from prisma-graphql-type-decimal.
*
* @see https://github.com/unlight/prisma-graphql-type-decimal
*/
new GraphQLScalarType({
name: 'Decimal',
description: 'An arbitrary-precision Decimal type',
/**
* Value sent to the client
*/
serialize(value: DecimalJs.Decimal) {
return value.toString()
},
/**
* Value from the client
*/
parseValue(value: DecimalJs.Decimal.Value) {
return new DecimalJs.Decimal(value)
},
parseLiteral(ast) {
if (ast.kind === Kind.INT || ast.kind === Kind.FLOAT || ast.kind === Kind.STRING) {
return new DecimalJs.Decimal(ast.value)
}
return null
},
}),
'decimal'
)
20 changes: 20 additions & 0 deletions tests/e2e/__snapshots__/e2e.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ Object {
"BigIntManually": null,
"BytesManually": null,
"DateTimeManually": null,
"DecimalManually": null,
"JsonManually": null,
"someBigIntField": "9007199254740991",
"someBytesField": Object {
"data": Array [],
"type": "Buffer",
},
"someDateTimeField": "2021-05-10T20:42:46.609Z",
"someDecimalField": "24.454545",
"someEnumA": "alpha",
"someJsonField": Object {},
},
Expand Down Expand Up @@ -46,14 +48,19 @@ A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the \`da
\\"\\"\\"
scalar DateTime
\\"\\"\\"An arbitrary-precision Decimal type\\"\\"\\"
scalar Decimal
type Foo {
BigIntManually: BigInt
BytesManually: Bytes
DateTimeManually: DateTime
DecimalManually: Decimal
JsonManually: Json
someBigIntField: BigInt!
someBytesField: Bytes!
someDateTimeField: DateTime!
someDecimalField: Decimal!
someEnumA: SomeEnumA
someJsonField: Json!
}
Expand Down Expand Up @@ -98,6 +105,10 @@ declare global {
* A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the \`date-time\` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar.
*/
dateTime<FieldName extends string>(fieldName: FieldName, opts?: core.CommonInputFieldConfig<TypeName, FieldName>): void // \\"DateTime\\";
/**
* An arbitrary-precision Decimal type
*/
decimal<FieldName extends string>(fieldName: FieldName, opts?: core.CommonInputFieldConfig<TypeName, FieldName>): void // \\"Decimal\\";
/**
* The \`JSONObject\` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
*/
Expand All @@ -119,6 +130,10 @@ declare global {
* A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the \`date-time\` format outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for representation of dates and times using the Gregorian calendar.
*/
dateTime<FieldName extends string>(fieldName: FieldName, ...opts: core.ScalarOutSpread<TypeName, FieldName>): void // \\"DateTime\\";
/**
* An arbitrary-precision Decimal type
*/
decimal<FieldName extends string>(fieldName: FieldName, ...opts: core.ScalarOutSpread<TypeName, FieldName>): void // \\"Decimal\\";
/**
* The \`JSONObject\` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
*/
Expand Down Expand Up @@ -147,6 +162,7 @@ export interface NexusGenScalars {
BigInt: any
Bytes: any
DateTime: any
Decimal: any
Json: any
}
Expand Down Expand Up @@ -174,10 +190,12 @@ export interface NexusGenFieldTypes {
BigIntManually: NexusGenScalars['BigInt'] | null; // BigInt
BytesManually: NexusGenScalars['Bytes'] | null; // Bytes
DateTimeManually: NexusGenScalars['DateTime'] | null; // DateTime
DecimalManually: NexusGenScalars['Decimal'] | null; // Decimal
JsonManually: NexusGenScalars['Json'] | null; // Json
someBigIntField: NexusGenScalars['BigInt']; // BigInt!
someBytesField: NexusGenScalars['Bytes']; // Bytes!
someDateTimeField: NexusGenScalars['DateTime']; // DateTime!
someDecimalField: NexusGenScalars['Decimal']; // Decimal!
someEnumA: NexusGenEnums['SomeEnumA'] | null; // SomeEnumA
someJsonField: NexusGenScalars['Json']; // Json!
}
Expand All @@ -194,10 +212,12 @@ export interface NexusGenFieldTypeNames {
BigIntManually: 'BigInt'
BytesManually: 'Bytes'
DateTimeManually: 'DateTime'
DecimalManually: 'Decimal'
JsonManually: 'Json'
someBigIntField: 'BigInt'
someBytesField: 'Bytes'
someDateTimeField: 'DateTime'
someDecimalField: 'Decimal'
someEnumA: 'SomeEnumA'
someJsonField: 'Json'
}
Expand Down
8 changes: 7 additions & 1 deletion tests/e2e/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ it('When bundled custom scalars are used the project type checks and generates e
id String @id
someJsonField Json
someDateTimeField DateTime
someDecimalField Decimal
someBytesField Bytes
someBigIntField BigInt
someEnumA SomeEnumA
Expand All @@ -143,7 +144,7 @@ it('When bundled custom scalars are used the project type checks and generates e
{
filePath: `prisma/seed.ts`,
content: dedent/*ts*/ `
import { PrismaClient } from '@prisma/client'
import { PrismaClient, Prisma } from '@prisma/client'
main()
Expand All @@ -155,6 +156,7 @@ it('When bundled custom scalars are used the project type checks and generates e
data: {
id: 'foo1',
someDateTimeField: new Date("2021-05-10T20:42:46.609Z"),
someDecimalField: 24.454545,
someBytesField: Buffer.from([]),
someJsonField: {},
someBigIntField: BigInt(9007199254740991),
Expand Down Expand Up @@ -214,11 +216,13 @@ it('When bundled custom scalars are used the project type checks and generates e
t.json('JsonManually')
t.dateTime('DateTimeManually')
t.bytes('BytesManually')
t.decimal('DecimalManually')
t.bigInt('BigIntManually')
t.field(Foo.someBigIntField)
t.field(Foo.someJsonField)
t.field(Foo.someDateTimeField)
t.field(Foo.someBytesField)
t.field(Foo.someDecimalField)
},
}),
]
Expand Down Expand Up @@ -380,11 +384,13 @@ it('When bundled custom scalars are used the project type checks and generates e
JsonManually
DateTimeManually
BytesManually
DecimalManually
BigIntManually
someEnumA
someJsonField
someDateTimeField
someBytesField
someDecimalField
someBigIntField
}
}
Expand Down
1 change: 1 addition & 0 deletions tests/integration/json.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ testIntegration({
NexusPrismaScalars.Bytes,
NexusPrismaScalars.BigInt,
NexusPrismaScalars.DateTime,
NexusPrismaScalars.Decimal,
NexusPrismaScalars.Json,
objectType({
name: Foo.$name,
Expand Down
2 changes: 2 additions & 0 deletions tests/unit/customScalarsModule.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Array [
"BigInt",
"Bytes",
"DateTime",
"Decimal",
"Json",
"default",
]
Expand All @@ -21,6 +22,7 @@ it('scalars can be accessed via a default import', () => {
"BigInt",
"Bytes",
"DateTime",
"Decimal",
"Json",
]
`)
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2080,6 +2080,11 @@ decimal.js@^10.2.1:
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3"
integrity sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==

decimal.js@^10.3.1:
version "10.3.1"
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783"
integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==

decompress-response@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
Expand Down

0 comments on commit 74da7c2

Please sign in to comment.