feat: defining a custom scalar DateTime

This commit is contained in:
Kristof Van Miegem 2019-02-09 16:02:08 +01:00
parent 971e366a1b
commit 7ce4e4a7bc
3 changed files with 75 additions and 6 deletions

View File

@ -1,5 +1,6 @@
const { UserInputError } = require('apollo-server'); const { UserInputError } = require('apollo-server');
const yup = require('yup'); const yup = require('yup');
const dateTimeScalar = require('./scalars/dateTime');
const data = require('./data'); const data = require('./data');
const uuidSchema = yup.string().min(36).max(36); const uuidSchema = yup.string().min(36).max(36);
@ -76,5 +77,6 @@ module.exports = {
const { reservationProducts } = input; const { reservationProducts } = input;
return data.createReservation({ reservationProducts }); return data.createReservation({ reservationProducts });
} }
} },
DateTime: dateTimeScalar,
}; };

65
src/scalars/dateTime.js Normal file
View File

@ -0,0 +1,65 @@
const { GraphQLScalarType } = require('graphql');
const { GraphQLError } = require('graphql/error')
const { Kind } = require('graphql/language');
module.exports = new GraphQLScalarType({
name: 'DateTime',
description: 'Use JavaScript Date object for date/time fields.',
serialize(value) {
let v = value;
if (!(v instanceof Date) && typeof v !== 'string' && typeof v !== 'number') {
throw new TypeError(
`Value is not an instance of Date, Date string or number: ${v}`,
);
}
if (typeof v === 'string') {
v = new Date();
v.setTime(Date.parse(value));
} else if (typeof v === 'number') {
v = new Date(v);
}
if (Number.isNaN(v.getTime())) {
throw new TypeError(`Value is not a valid Date: ${v}`);
}
return v.toJSON();
},
parseValue(value) {
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
throw new TypeError(`Value is not a valid Date: ${value}`);
}
return date;
},
parseLiteral(ast) {
if (ast.kind !== Kind.STRING && ast.kind !== Kind.INT) {
throw new GraphQLError(
`Can only parse strings & integers to dates but got a: ${ast.kind}`,
);
}
const result = new Date(ast.kind === Kind.INT ? Number(ast.value) : ast.value);
if (Number.isNaN(result.getTime())) {
throw new GraphQLError(`Value is not a valid Date: ${ast.value}`);
}
if (ast.kind === Kind.STRING && ast.value !== result.toJSON()) {
throw new GraphQLError(
`Value is not a valid Date format (YYYY-MM-DDTHH:MM:SS.SSSZ): ${
ast.value
}`,
);
}
return result;
},
});

View File

@ -3,11 +3,13 @@ const { gql } = require('apollo-server');
// Type definitions define the "shape" of your data and specify // Type definitions define the "shape" of your data and specify
// which ways the data can be fetched from the GraphQL server. // which ways the data can be fetched from the GraphQL server.
module.exports = gql` module.exports = gql`
scalar DateTime
# Comments in GraphQL are defined with the hash (#) symbol. # Comments in GraphQL are defined with the hash (#) symbol.
type Product { type Product {
description: String description: String
id: String id: ID
name: String name: String
price: Float price: Float
} }
@ -15,7 +17,7 @@ module.exports = gql`
# This "Store" type can be used in other type declarations. # This "Store" type can be used in other type declarations.
type Store { type Store {
city: String city: String
id: String id: ID
name: String name: String
number: Int number: Int
postalCode: String postalCode: String
@ -29,8 +31,8 @@ module.exports = gql`
} }
type Reservation { type Reservation {
date: String date: DateTime
id: String id: ID
reservationProducts: [ReservationProduct] reservationProducts: [ReservationProduct]
} }
@ -38,7 +40,7 @@ module.exports = gql`
# (A "Mutation" type will be covered later on.) # (A "Mutation" type will be covered later on.)
type Query { type Query {
stores: [Store] stores: [Store]
store(id: String): Store store(id: ID): Store
} }
input StoreInput { input StoreInput {