diff --git a/README.md b/README.md index 4357b5e..3aab48a 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,10 @@ Now that your global configuration is set, you can define the cost calculation f | useMultipliers | Defines if the field's cost depends on the parent multipliers and field's multipliers. | Boolean | true | no | | complexity | The level of complexity to resolve the current field.
If the field needs to call an expensive service to resolve itself, then the complexity should be at a high level but if the field is easy to resolve and not an expensive operation, the complexity should be at a low level. | Object {min: number, max: number} | {min: 1} | no | +### Default multipliers + +It's possible to define `multipliers` as an object of the form `{limit: 100}`, where the number is the default value of the "limit" argument, used in cost analysis. This is different from adding a default value to the actual GraphQL argument, because it's only used for cost analysis. If the query happens to return more items, the result is not truncated. + ## Defining the Cost Settings via Directives To define the cost settings of fields for which you want a custom cost calculation, just add a `cost` directive to the concerned fields directly to your GraphQL schema. diff --git a/package.json b/package.json index 792183d..d9d058c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "graphql-cost-analysis", - "version": "1.0.3", + "version": "1.1.0-smartdok1", "description": "Graphql query cost analyzer. Use it to protect your GraphQL servers against DoS attacks, compute data consumption per user and limit it.", "main": "dist/index.js", "files": [ diff --git a/src/costAnalysis.js b/src/costAnalysis.js index 0dfab35..dcd665b 100644 --- a/src/costAnalysis.js +++ b/src/costAnalysis.js @@ -19,6 +19,7 @@ import type { DirectiveNode, GraphQLNamedType, ValueNode, + ObjectFieldNode, ArgumentNode, SelectionNode } from 'graphql' @@ -209,6 +210,22 @@ export default class CostAnalysis { } } + getMultipliersFromObjectNode ( + objectNode: $ReadOnlyArray, + fieldArgs: { [argument: string]: mixed } + ) { + const multipliers = [] + objectNode.forEach(field => { + if (field.value.kind === Kind.INT) { + multipliers.push([field.name.value, Number(field.value.value)]) + } else { + multipliers.push(field.name.value) + } + }) + + return this.getMultipliersFromString(multipliers, fieldArgs) + } + getMultipliersFromListNode ( listNode: $ReadOnlyArray, fieldArgs: { [argument: string]: mixed } @@ -224,19 +241,24 @@ export default class CostAnalysis { } getMultipliersFromString ( - multipliers: Array = [], + multipliers: Array = [], fieldArgs: { [argument: string]: mixed } ): Array { // get arguments values, convert to integer and delete 0 values from list return multipliers .map(multiplier => { + let defVal = 0 + if (Array.isArray(multiplier)) { + defVal = multiplier[1] + multiplier = multiplier[0] + } const value = selectn(multiplier, fieldArgs) // if the argument is an array, the multiplier will be the length of it if (Array.isArray(value)) { return value.length } - return Number(value) || 0 + return Number(value) || defVal }) .filter(multiplier => multiplier !== 0) } @@ -281,7 +303,16 @@ export default class CostAnalysis { multipliersArg.value.values, fieldArgs ) - : [] + : ( + multipliersArg && + multipliersArg.value && + multipliersArg.value.kind === Kind.OBJECT + ? this.getMultipliersFromObjectNode( + multipliersArg.value.fields, + fieldArgs + ) + : [] + ) const multiplier: ?number = multiplierArg && multiplierArg.value.value diff --git a/src/index.js b/src/index.js index 4895223..1e478cf 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,6 @@ // @flow import CostAnalysis from './costAnalysis' -import type { CostAnalysisOptions } from './CostAnalysis' +import type { CostAnalysisOptions } from './costAnalysis' import type { ValidationContext } from 'graphql'