Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Currency scalar #375

Merged
merged 1 commit into from Jun 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Expand Up @@ -88,6 +88,8 @@ scalar RGBA

scalar USCurrency

scalar Currency

scalar JSON

scalar JSONObject
Expand Down Expand Up @@ -127,6 +129,7 @@ import {
RGBResolver,
RGBAResolver,
USCurrencyResolver,
CurrencyResolver,
JSONResolver,
JSONObjectResolver,
ObjectIDResolver,
Expand Down Expand Up @@ -176,6 +179,7 @@ const myResolverMap = {
ISBN: ISBNResolver,

USCurrency: USCurrencyResolver,
Currency: CurrencyResolver,
JSON: JSONResolver,
JSONObject: JSONObjectResolver,

Expand Down Expand Up @@ -581,6 +585,10 @@ A US currency string, such as \$21.25.

> Uses [graphql-currency-scalars](https://github.com/abhiaiyer91/graphql-currency-scalars)

### Currency

A field whose value is an [ISO-4217 currency](https://en.wikipedia.org/wiki/ISO_4217).

### JSON

The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf).
Expand Down
4 changes: 4 additions & 0 deletions src/index.ts
Expand Up @@ -33,6 +33,7 @@ export {
RGB as RGBDefinition,
RGBA as RGBADefinition,
USCurrency as USCurrencyDefinition,
Currency as CurrencyDefinition,
JSON as JSONDefinition,
JSONObject as JSONObjectDefinition,
IBAN as IBANTypeDefinition,
Expand Down Expand Up @@ -74,6 +75,7 @@ export {
RGB as RGBResolver,
RGBA as RGBAResolver,
USCurrency as USCurrencyResolver,
Currency as CurrencyResolver,
JSON as JSONResolver,
JSONObject as JSONObjectResolver,
IBAN as IBANResolver,
Expand Down Expand Up @@ -113,6 +115,7 @@ export {
RGB as GraphQLRGB,
RGBA as GraphQLRGBA,
USCurrency as GraphQLUSCurrency,
Currency as GraphQLCurrency,
JSON as GraphQLJSON,
JSONObject as GraphQLJSONObject,
IBAN as GraphQLIBAN,
Expand Down Expand Up @@ -154,6 +157,7 @@ export {
RGB as RGBMock,
RGBA as RGBAMock,
USCurrency as USCurrencyMock,
Currency as CurrencyMock,
JSON as JSONMock,
JSONObject as JSONObjectMock,
IBAN as IBANMock,
Expand Down
1 change: 1 addition & 0 deletions src/mocks.ts
Expand Up @@ -75,6 +75,7 @@ export const RGBA = () =>
)}, ${Math.random()})`;
export const ISBN = () => `978-3-16-148410-0`;
export const USCurrency = () => 1000;
export const Currency = () => 'USD';
export const JSON = () => ({});
export const JSONObject = () => ({});
export const IBAN = () => 'NL55INGB4789170233';
Expand Down
39 changes: 39 additions & 0 deletions src/resolvers/Currency.ts
@@ -0,0 +1,39 @@
import { Kind, GraphQLError, GraphQLScalarType } from 'graphql';

const validate = (value: any) => {
const CURRENCY_REGEX = /^(AED|AFN|ALL|AMD|ANG|AOA|ARS|AUD|AWG|AZN|BAM|BBD|BDT|BGN|BHD|BIF|BMD|BND|BOB|BOV|BRL|BSD|BTN|BWP|BYN|BZD|CAD|CDF|CHE|CHF|CHW|CLF|CLP|CNY|COP|COU|CRC|CUC|CUP|CVE|CZK|DJF|DKK|DOP|DZD|EGP|ERN|ETB|EUR|FJD|FKP|GBP|GEL|GHS|GIP|GMD|GNF|GTQ|GYD|HKD|HNL|HRK|HTG|HUF|IDR|ILS|INR|IQD|IRR|ISK|JMD|JOD|JPY|KES|KGS|KHR|KMF|KPW|KRW|KWD|KYD|KZT|LAK|LBP|LKR|LRD|LSL|LYD|MAD|MDL|MGA|MKD|MMK|MNT|MOP|MRU|MUR|MVR|MWK|MXN|MXV|MYR|MZN|NAD|NGN|NIO|NOK|NPR|NZD|OMR|PAB|PEN|PGK|PHP|PKR|PLN|PYG|QAR|RON|RSD|RUB|RWF|SAR|SBD|SCR|SDG|SEK|SGD|SHP|SLL|SOS|SRD|SSP|STN|SVC|SYP|SZL|THB|TJS|TMT|TND|TOP|TRY|TTD|TWD|TZS|UAH|UGX|USD|USN|UYI|UYU|UYW|UZS|VES|VND|VUV|WST|XAF|XAG|XAU|XBA|XBB|XBC|XBD|XCD|XDR|XOF|XPD|XPF|XPT|XSU|XTS|XUA|XXX|YER|ZAR|ZMW|ZWL)$/i;

if (typeof value !== 'string') {
throw new TypeError(`Value is not string: ${value}`);
}

if (!CURRENCY_REGEX.test(value)) {
throw new TypeError(`Value is not a valid currency value: ${value}`);
}

return value;
};

export default new GraphQLScalarType({
name: `Currency`,

description: `A field whose value is a Currency: https://en.wikipedia.org/wiki/ISO_4217.`,

serialize(value) {
return validate(value);
},

parseValue(value) {
return validate(value);
},

parseLiteral(ast) {
if (ast.kind !== Kind.STRING) {
throw new GraphQLError(
`Can only validate strings as a currency but got a: ${ast.kind}`,
);
}

return validate(ast.value);
},
});
2 changes: 2 additions & 0 deletions src/resolvers/index.ts
Expand Up @@ -26,6 +26,7 @@ import Port from './Port';
import RGB from './RGB';
import RGBA from './RGBA';
import USCurrency from './USCurrency';
import Currency from './Currency';
import { JSON, JSONObject } from './JSON';
import IBAN from './IBAN';
import ObjectID from './ObjectID';
Expand Down Expand Up @@ -72,6 +73,7 @@ export {
RGB,
RGBA,
USCurrency,
Currency,
JSON,
JSONObject,
IBAN,
Expand Down
2 changes: 2 additions & 0 deletions src/typeDefs.ts
Expand Up @@ -29,6 +29,7 @@ export const RGB = `scalar RGB`;
export const RGBA = `scalar RGBA`;
export const URL = 'scalar URL';
export const USCurrency = `scalar USCurrency`;
export const Currency = `scalar Currency`;

export const UnsignedFloat = 'scalar UnsignedFloat';
export const UnsignedInt = 'scalar UnsignedInt';
Expand Down Expand Up @@ -69,6 +70,7 @@ export default [
RGB,
RGBA,
USCurrency,
Currency,
JSON,
JSONObject,
IBAN,
Expand Down
58 changes: 58 additions & 0 deletions tests/Currency.test.ts
@@ -0,0 +1,58 @@
/* global describe, it, expect */
import { Kind } from 'graphql/language';
import Currency from '../src/resolvers/Currency';

describe(`Currency`, () => {
describe(`valid`, () => {
it(`serialize`, () => {
expect(Currency.serialize(`USD`)).toEqual(`USD`);
});

it(`parseValue`, () => {
expect(Currency.parseValue(`USD`)).toEqual(`USD`);
});

it(`parseLiteral`, () => {
expect(
Currency.parseLiteral(
{
value: `USD`,
kind: Kind.STRING,
},
{},
),
).toEqual(`USD`);
});
});

describe(`invalid`, () => {
describe(`not a valid currency value`, () => {
it(`serialize`, () => {
expect(() => Currency.serialize(123)).toThrow(/Value is not string/);
expect(() => Currency.serialize(`this is not a currency`)).toThrow(
/Value is not a valid currency value/,
);
});

it(`parseValue`, () => {
expect(() => Currency.serialize(123)).toThrow(/Value is not string/);
expect(() => Currency.parseValue(`this is not a currency`)).toThrow(
/Value is not a valid currency value/,
);
});

it(`parseLiteral`, () => {
expect(() =>
Currency.parseLiteral({ value: 123, kind: Kind.INT } as any, {}),
).toThrow(/Can only validate strings as a currency but got a/);

expect(() =>
Currency.parseLiteral(
{ value: `this is not a currency`, kind: Kind.STRING },
{},
),
).toThrow(/Value is not a valid currency value/);
});
});
});
});