2016-11-26 11:17:01 +09:00
/ *
Utilities to generate the app ' s GraphQL schema
* /
2016-11-10 22:18:51 +01:00
import Telescope from './config.js' ;
2016-11-03 21:39:09 +09:00
import deepmerge from 'deepmerge' ;
2016-12-06 15:51:59 +09:00
import GraphQLJSON from 'graphql-type-json' ;
2016-11-03 21:39:09 +09:00
2016-11-26 11:17:01 +09:00
// convert a JSON schema to a GraphQL schema
2016-11-08 14:56:39 +09:00
const jsTypeToGraphQLType = typeName => {
switch ( typeName ) {
case "Date" :
return "String" ;
case "Number" :
return "Float" ;
// assume all arrays contains strings for now
case "Array" :
return "[String]" ;
case "Object" :
return "???" ;
default :
return typeName ;
}
}
2016-10-29 16:37:33 +09:00
Telescope . graphQL = {
2016-11-08 14:56:39 +09:00
// collections used to auto-generate schemas
collections : [ ] ,
2016-11-08 15:12:23 +09:00
addCollection ( collection ) {
this . collections . push ( collection ) ;
2016-11-08 14:56:39 +09:00
} ,
2016-11-26 11:17:01 +09:00
// generate GraphQL schemas for all registered collections
2016-11-08 12:58:53 +01:00
getCollectionsSchemas ( ) {
const collectionsSchemas = this . collections . map ( collection => {
2016-11-08 15:12:23 +09:00
return this . generateSchema ( collection ) ;
2016-11-08 14:56:39 +09:00
} ) . join ( '\n' ) ;
2016-11-08 12:58:53 +01:00
return collectionsSchemas ;
2016-11-08 14:56:39 +09:00
} ,
// additional schemas
2016-10-29 16:37:33 +09:00
schemas : [ ] ,
addSchema ( schema ) {
this . schemas . push ( schema ) ;
} ,
2016-11-26 11:17:01 +09:00
// get extra schemas defined manually
2016-11-08 14:56:39 +09:00
getAdditionalSchemas ( ) {
const additionalSchemas = this . schemas . join ( '\n' ) ;
return additionalSchemas ;
} ,
// queries
2016-10-29 16:37:33 +09:00
queries : [ ] ,
addQuery ( query ) {
this . queries . push ( query ) ;
2016-10-31 16:19:37 +01:00
} ,
2016-11-08 14:56:39 +09:00
// mutations
2016-10-31 16:19:37 +01:00
mutations : [ ] ,
addMutation ( mutation ) {
this . mutations . push ( mutation ) ;
} ,
2016-11-08 14:56:39 +09:00
// add resolvers
2016-12-06 15:51:59 +09:00
resolvers : {
JSON : GraphQLJSON ,
} ,
2016-11-03 21:39:09 +09:00
addResolvers ( resolvers ) {
this . resolvers = deepmerge ( this . resolvers , resolvers ) ;
} ,
2016-11-08 14:56:39 +09:00
// add objects to context
2016-11-03 21:39:09 +09:00
context : { } ,
addToContext ( object ) {
this . context = deepmerge ( this . context , object ) ;
2016-11-07 17:45:17 +09:00
} ,
2016-11-08 14:56:39 +09:00
2016-11-26 11:17:01 +09:00
// generate a GraphQL schema corresponding to a given collection
2016-11-08 15:12:23 +09:00
generateSchema ( collection ) {
2016-11-08 14:56:39 +09:00
const collectionName = collection . _name ;
2016-11-08 15:12:23 +09:00
const mainTypeName = collection . typeName ? collection . typeName : Telescope . utils . camelToSpaces ( _ . initial ( collectionName ) . join ( '' ) ) ; // default to posts -> Post
2016-11-08 14:56:39 +09:00
2016-11-10 16:53:06 +01:00
// backward-compatibility code: we do not want user.telescope fields in the graphql schema
2016-11-10 22:18:51 +01:00
const schema = Telescope . utils . stripTelescopeNamespace ( collection . simpleSchema ( ) . _schema ) ;
2016-11-10 16:53:06 +01:00
2016-11-08 14:56:39 +09:00
let mainSchema = [ ] , inputSchema = [ ] , unsetSchema = [ ] ;
_ . forEach ( schema , ( field , key ) => {
// console.log(field, key)
const fieldType = jsTypeToGraphQLType ( field . type . name ) ;
if ( key . indexOf ( '$' ) === - 1 && fieldType !== "???" ) { // skip fields with "$" and unknown fields
// 1. main schema
2016-11-08 15:16:58 +09:00
mainSchema . push ( ` ${ key } : ${ fieldType } ` ) ;
// if field has a resolver, also push it to schema
if ( field . resolveAs ) {
mainSchema . push ( field . resolveAs ) ;
}
2016-11-08 14:56:39 +09:00
if ( field . insertableIf || field . editableIf ) {
const isRequired = field . optional ? '' : '!' ;
// 2. input schema
inputSchema . push ( ` ${ key } : ${ fieldType } ${ isRequired } ` ) ;
// 3. unset schema
unsetSchema . push ( ` ${ key } : Boolean ` ) ;
}
}
} ) ;
2016-11-27 19:12:54 +09:00
let graphQLSchema = `
2016-12-06 15:51:59 +09:00
scalar JSON
2016-11-27 19:12:54 +09:00
type $ { mainTypeName } {
$ { mainSchema . join ( '\n ' ) }
}
`
2016-11-08 14:56:39 +09:00
2016-11-27 19:12:54 +09:00
if ( inputSchema . length ) {
graphQLSchema += `
input $ { collectionName } Input {
$ { inputSchema . join ( '\n ' ) }
}
input $ { collectionName } Unset {
$ { unsetSchema . join ( '\n ' ) }
}
`
}
2016-11-08 14:56:39 +09:00
return graphQLSchema ;
}
2016-10-29 16:37:33 +09:00
} ;