slicknode/graphql-query-complexity

Counting type complexity only once

dragonfriend0013 opened this issue · 4 comments

I have a query
{ inqAcctGeneralInfo { clientId acctId field1 field2 } }

for schema
Query { inqAcctGeneralInfo: AcctGeneralInfo } type AcctGeneralInfo { clientId: Int acctId: String field1: String field2: String }

and i would like to count the type and assign it a complexity of 5, and have it still count its subfields as 1. So my above query would have a total complexity of 9. I am seeing that the estimators are called per field and i am currently getting complexity of 5 (4 returned fields plus 1 for the query itself). is there any way to be able to count the type once in a custom estimator?

ivome commented

Not sure I fully understand the issue here. You could assign the inqAcctGeneralInfo field a complexity of 5 via one of the estimators and the other fields a complexity of 1. That should give you the result of 9.

ok i think i can make that work. in a large schema where the same type is used in multiple places, being able to code for the type would be easier, than coding for each field that references that type. I am using a large federated schema, so having to pull all those fields could take time, vs just coding for the types once.

ivome commented

@dragonfriend0013 You could just create a custom estimator that returns values for specific types and add that to your chain:

import queryComplexity, {
  simpleEstimator
} from 'graphql-query-complexity';

const rule = queryComplexity({
  // ...
  estimators: [
    ({field}) => {
      switch(field.type.name) {
        case 'AcctGeneralInfo': return 5;
      }
      // Typename not defined in here, let next estimator in chain continue calculation
    }
    // Add more estimators here...
    
    // Fallback
    simpleEstimator({
      defaultComplexity: 1
    })
  ]
});

i wound up creating a class as i do not want to count the type more than once. I am also using a complexity map to store my complexity values.
`
import lodashClonedeep from 'lodash.clonedeep';
import pointsMap from './pointsMap.mjs';

export default class SpecificEstimator {
constructor() {
this.PointsMap = lodashClonedeep(pointsMap);
}

getSpecificComplexity() {
return (args) => {
const type = this.PointsMap[args.type.name];
let points = 0;
if (args.type.name === 'Query'
|| args.type.name === 'Mutation') {
points += args.childComplexity
+ this.PointsMap.defaultPoints;
return points;
if (type) {
if (!type.beenVisited) {
this.PointsMap[args.type.name].beenVisited = true;
points += args.childComplexity
+ (type.complexity || this.PointsMap.defaultComplexity);
}
const field = type[args.field.name];
if (field) {
points += args.childComplexity
+ (type.complexity || this.PointsMap.defaultComplexity);
} else {
points += args.childComplexity
+ this.PointsMap.defaultComplexity;
}
} else {
points += args.childComplexity
+ this.PointsMap.defaultComplexity;
}
return points;
};
}
}
`