1+ import {
2+ GraphQLArgument ,
3+ GraphQLEnumType ,
4+ GraphQLFieldMap ,
5+ GraphQLInterfaceType ,
6+ GraphQLList ,
7+ GraphQLNamedType ,
8+ GraphQLNonNull ,
9+ GraphQLObjectType ,
10+ GraphQLOutputType ,
11+ GraphQLScalarType ,
12+ GraphQLUnionType ,
13+ isCompositeType ,
14+ } from 'graphql' ;
15+ import { Maybe } from 'graphql/jsutils/Maybe' ;
116import { GraphQLSchema } from 'graphql/type/schema' ;
217
18+ const KEYWORDS = [ 'first' , 'last' , 'limit' ] ;
19+
320/**
421 * Default TypeWeight Configuration:
522 * mutation: 10
623 * object: 1
724 * scalar: 0
825 * connection: 2
926 */
27+ const DEFAULT_MUTATION_WEIGHT = 10 ;
28+ const DEFAULT_OBJECT_WEIGHT = 1 ;
29+ const DEFAULT_SCALAR_WEIGHT = 0 ;
30+ const DEFAULT_CONNECTION_WEIGHT = 2 ;
31+ const DEFAULT_QUERY_WEIGHT = 1 ;
32+
1033export const defaultTypeWeightsConfig : TypeWeightConfig = {
11- mutation : 10 ,
12- object : 1 ,
13- scalar : 0 ,
14- connection : 2 ,
34+ mutation : DEFAULT_MUTATION_WEIGHT ,
35+ object : DEFAULT_OBJECT_WEIGHT ,
36+ scalar : DEFAULT_SCALAR_WEIGHT ,
37+ connection : DEFAULT_CONNECTION_WEIGHT ,
1538} ;
1639
1740/**
@@ -20,8 +43,8 @@ export const defaultTypeWeightsConfig: TypeWeightConfig = {
2043 * back on shopifys settings. We can change this later.
2144 *
2245 * This function should
23- * - itreate through the schema object and create the typeWeightObject as described in the tests
24- * - validate that the typeWeightsConfig parameter has no negative values (throw an error if it does)
46+ * - TODO: iterate through the schema object and create the typeWeightObject as described in the tests
47+ * - TODO: validate that the typeWeightsConfig parameter has no negative values (throw an error if it does)
2548 *
2649 * @param schema
2750 * @param typeWeightsConfig Defaults to {mutation: 10, object: 1, field: 0, connection: 2}
@@ -30,6 +53,120 @@ function buildTypeWeightsFromSchema(
3053 schema : GraphQLSchema ,
3154 typeWeightsConfig : TypeWeightConfig = defaultTypeWeightsConfig
3255) : TypeWeightObject {
33- throw Error ( `getTypeWeightsFromSchema is not implemented.` ) ;
56+ // Iterate each key in the schema object
57+ // this includes scalars, types, interfaces, unions, enums etc.
58+ // check the type of each add set the appropriate weight.
59+ // iterate through that types fields and set the appropriate weight
60+ // this is kind of only relevant for things like Query or Mutation
61+ // that have functions(?) as fields for which we should set the weight as a function
62+ // that take any required params.
63+
64+ if ( ! schema ) throw new Error ( 'Must provide schema' ) ;
65+
66+ // Merge the provided type weights with the default to account for missing values
67+ const typeWeights : TypeWeightConfig = {
68+ ...defaultTypeWeightsConfig ,
69+ ...typeWeightsConfig ,
70+ } ;
71+
72+ // Confirm that any custom weights are positive
73+ Object . entries ( typeWeights ) . forEach ( ( value : [ string , number ] ) => {
74+ if ( value [ 1 ] < 0 ) {
75+ throw new Error ( `Type weights cannot be negative. Received: ${ value [ 0 ] } : ${ value [ 1 ] } ` ) ;
76+ }
77+ } ) ;
78+
79+ const result : TypeWeightObject = { } ;
80+
81+ // Iterate through __typeMap and set weights of all object types?
82+
83+ const typeMap = schema . getTypeMap ( ) ;
84+
85+ Object . keys ( typeMap ) . forEach ( ( type ) => {
86+ const currentType : GraphQLNamedType = typeMap [ type ] ;
87+ // Limit to object types for now
88+ // Get all types that aren't Query or Mutation and don't start with __
89+ if (
90+ currentType . name !== 'Query' &&
91+ currentType . name !== 'Mutation' &&
92+ ! currentType . name . startsWith ( '__' )
93+ ) {
94+ if (
95+ currentType instanceof GraphQLObjectType ||
96+ currentType instanceof GraphQLInterfaceType
97+ ) {
98+ // Add the type to the result
99+ result [ type ] = {
100+ fields : { } ,
101+ weight : typeWeights . object || DEFAULT_OBJECT_WEIGHT ,
102+ } ;
103+
104+ const fields = currentType . getFields ( ) ;
105+ Object . keys ( fields ) . forEach ( ( field : string ) => {
106+ const fieldType : GraphQLOutputType = fields [ field ] . type ;
107+ if (
108+ fieldType instanceof GraphQLScalarType ||
109+ ( fieldType instanceof GraphQLNonNull &&
110+ fieldType . ofType instanceof GraphQLScalarType )
111+ ) {
112+ result [ type ] . fields [ field ] = typeWeights . scalar || DEFAULT_SCALAR_WEIGHT ;
113+ }
114+ // FIXME: Do any other types need to be included?
115+ } ) ;
116+ } else if ( currentType instanceof GraphQLEnumType ) {
117+ result [ currentType . name ] = {
118+ fields : { } ,
119+ weight : 0 ,
120+ } ;
121+ } else if ( currentType instanceof GraphQLUnionType ) {
122+ result [ currentType . name ] = {
123+ fields : { } ,
124+ weight : 1 , // FIXME: Use the correct weight
125+ } ;
126+ }
127+ }
128+ } ) ;
129+
130+ // Get any Query fields (these are the queries that the API exposes)
131+ const queryType : Maybe < GraphQLObjectType > = schema . getQueryType ( ) ;
132+
133+ if ( queryType ) {
134+ result . Query = {
135+ weight : typeWeights . query || DEFAULT_QUERY_WEIGHT ,
136+ fields : {
137+ // This object gets populated with the query fields and associated weights.
138+ } ,
139+ } ;
140+ const queryFields : GraphQLFieldMap < any , any > = queryType . getFields ( ) ;
141+ Object . keys ( queryFields ) . forEach ( ( field ) => {
142+ const resolveType : GraphQLOutputType = queryFields [ field ] . type ;
143+
144+ queryFields [ field ] . args . forEach ( ( arg : GraphQLArgument ) => {
145+ // check if any of our keywords 'first', 'last', 'limit' exist in the arglist
146+ if ( KEYWORDS . includes ( arg . name ) && resolveType instanceof GraphQLList ) {
147+ const defaultVal : number = < number > arg . defaultValue ;
148+ // FIXME: How can we provide the complexity analysis algo with name of the argument to use?
149+ const listType = resolveType . ofType ;
150+ if ( isCompositeType ( listType ) ) {
151+ result . Query . fields [ field ] = ( multiplier : number = defaultVal ) =>
152+ multiplier * result [ listType . name ] . weight ;
153+ }
154+ }
155+ } ) ;
156+
157+ // if the field is a scalars set weight accordingly
158+ // FIXME: Enums shouldn't be here???
159+ if (
160+ resolveType instanceof GraphQLScalarType ||
161+ resolveType instanceof GraphQLEnumType
162+ ) {
163+ result . Query . fields [ field ] = typeWeights . scalar || DEFAULT_SCALAR_WEIGHT ;
164+ }
165+ } ) ;
166+ }
167+
168+ // get the type of the field
169+
170+ return result ;
34171}
35172export default buildTypeWeightsFromSchema ;
0 commit comments