GraphQL Aggregation Directives
1Operations
1.1Map
Directive
directive @map(key: String!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@map can be applied to objects or list of objects of any depth. If @map is applied on an object, it pulls the field key up. If @map is applied on a list, the algorithm is applied for each element of this list.
Given the following data:
Example № 1{
"list": [
{
"string": "a"
},
{
"string": "b"
},
{
"string": "c"
}
]
}
The execution of the following query:
Example № 2{
list @map(key: "string"){
string
}
}
will retrun the following result:
Example № 3{
"list": [
"a",
"b",
"c"
]
}
Execution
node is the value node where the directive is applied
- Let key be the value of the argument
keyof the directive - If node is ObjectValue
- Otherwise If node is ListValue
- Let listResult be a empty list
- For each element in node
- Let rewritten be the result of RewriteMap(element)
- If rewritten is NOT null
- Add rewritten to listResult
- Return listResult
- Otherwise
- Assert: AG0002
1.2Chunk
Directive
directive @chunk(size: Int! = 1) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@chunk can be applied on list values of any depth. @chunk splits the list into groups the length of size. If the list cannot be split evenly, the final chunk will contain the remaining elements.
Given the following data:
Example № 4{
"list": [
{
"string": "a"
},
{
"string": "b"
},
{
"string": "c"
}
]
}
The execution of the following query:
Example № 5{
list @chunk(size: 2){
string
}
}
will retrun the following result:
Example № 6{
"list": [
[
{
"string": "a"
},
{
"string": "b"
}
],
[
{
"string": "c"
}
]
]
}
Execution
node is the value node where the directive is applied
- Let size be the value of the argument
sizeof the directive - If size is < 1
- Assert: AG0005
- If node is ObjectValue
- Assert: AG0001
- If node is ScalarValue
- Assert: AG0004
- Otherwise
- Let chunks be an empty list
- Let currentChunk be an empty list
- While count of node is NOT 0
- Let element be the value of the first element of node
- Remove the first element of node
- Add element to currentChunk
- If count of currentChunk is size
- Add currentChunk to chunks
- Let currentChunk be an empty list
- If count of currentChunk is NOT 0
- Add currentChunk to chunks
- Retrun chunks
1.3CountBy
Directive
directive @countBy(key: String!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@countBy can only be applied list of objects of depth 1. Nested lists can be flattened with @flatten first. @countBy returns an object where the keys are the values of the field selected with key. The values are the number of times the key was found.
Given the following data:
Example № 7{
"list": [
{
"string": "a"
},
{
"string": "a"
},
{
"string": "c"
}
]
}
The execution of the following query:
Example № 8{
list @countBy(key: "string"){
string
}
}
will retrun the following result:
Example № 9{
"list": {
"a": 2,
"c": 1
}
}
Execution
node is the value node where the directive is applied
- Let key be the value of the argument
keyof the directive - If node is ObjectValue
- Assert: AG0001
- Otherwise If node is ScalarValue
- Assert: AG0004
- Otherwise
- Return RewriteCountByArray(node)
- Let result be a unordered map
- For each element in value
- If element is ListValue
- Assert: AG0003
- Otherwise If element is ScalarValue
- Assert: AG0002
- Otherwise If element is ObjectValue
- If Exists(element, key)
- Let fieldValue be Get(element, key)
- If IsConvertibleToString(fieldValue)
- Let convertedValue be ConvertToString(fieldValue)
- If NOT Exists(result, convertedValue)
- Set value of convertedValue in result to 0
- Increase convertedValue in result by 1
- If Exists(element, key)
- If element is ListValue
- Return result
1.4Drop
Directive
directive @drop(count: Int!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@drop can be applied a list any depth. @drop removes the first count elements of the list. If there are less elements than count a empty list is returned.
Given the following data:
Example № 10{
"list": [
{
"string": "a"
},
{
"string": "a"
},
{
"string": "c"
}
]
}
The execution of the following query:
Example № 11{
list @drop(count: 2){
string
}
}
will retrun the following result:
Example № 12{
"list": [
{
"string": "c"
}
]
}
Execution
node is the value node where the directive is applied
- Let size be the value of the argument
sizeof the directive - If node is ObjectValue
- Assert: AG0001
- Otherwise If node is ScalarValue
- Assert: AG0004
- Otherwise
- Remove size elements from the beginning of node
- Return node
1.5DropRight
Directive
directive @dropRight(count: Int!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@dropRight can be applied a list any depth. @dropRight removes the last count elements of the list. If there are less elements than count a empty list is returned.
Given the following data:
Example № 13{
"list": [
{
"string": "a"
},
{
"string": "a"
},
{
"string": "c"
}
]
}
The execution of the following query:
Example № 14{
list @dropRight(count: 2){
string
}
}
will retrun the following result:
Example № 15{
"list": [
{
"string": "a"
}
]
}
Execution
node is the value node where the directive is applied
- Let size be the value of the argument
sizeof the directive - If node is ObjectValue
- Assert: AG0001
- Otherwise If node is ScalarValue
- Assert: AG0004
- Otherwise
- Remove size elements from the end of node
- Return node
1.6Flatten
Directive
directive @flatten(depth: Int! = 1) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@flatten can be applied to all value nodes. @flatten recursivly flattens an array depth times.
Given the following data:
Example № 16{
"nestedList": [
[
{
"string": "b"
}
],
[
{
"string": "d"
}
],
[
{
"string": "d"
}
],
]
}
The execution of the following query:
Example № 17{
nestedList @flatten(depth: 1){
string
}
}
will retrun the following result:
Example № 18{
"list": [
{
"string": "b"
},
{
"string": "d"
} ,
{
"string": "d"
}
]
}
Execution
node is the value node where the directive is applied
- Let depth be the value of the argument
depthof the directive - If dpeth is lower than 1
- Assert: AG0006
- Otherwise
- Let result be a empty list
- Let initialDepth be 0
- RewriteFlattenList(node, initialDepth, result)
- Return result
- Otherwise
- Assert: AG0002
- If node is ListValue
- For each element in node
- Let nextDepth be currentDepth + 1
- RewriteFlattenList(node, nextDepth, result)
- For each element in node
- Otherwise
- Add node to result
1.7GroupBy
Directive
directive @groupBy(key: String!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@groupBy can only be applied list of objects of depth 1. Nested lists can be flattened with @flatten first. @groupBy returns an object where the keys are the values of the field selected with key. The values of the object are lists with the corresponding elements.
Given the following data:
Example № 19{
"list": [
{
"string": "a"
},
{
"string": "a"
},
{
"string": "b"
}
]
}
The execution of the following query:
Example № 20{
list @groupBy(key: "string"){
string
}
}
will retrun the following result:
Example № 21{
"list": {
"a": [
{
"string": "a"
},
{
"string": "a"
}
],
"b": [
{
"string": "b"
}
]
}
}
Execution
node is the value node where the directive is applied
- Let key be the value of the argument
keyof the directive - If node is ObjectValue
- Assert: AG0001
- Otherwise If node is ScalarValue
- Assert: AG0004
- Otherwise
- Return RewriteGroupByArray(node)
- Let result be a unordered map
- For each element in value
- If element is ListValue
- Assert: AG0003
- Otherwise If element is ScalarValue
- Assert: AG0002
- Otherwise If element is ObjectValue
- If Exists(element, key)
- Let fieldValue be Get(element, key)
- If IsConvertibleToString(fieldValue)
- Let convertedValue be ConvertToString(fieldValue)
- If NOT Exists(result, convertedValue)
- Set value of convertedValue in result to a empty list
- Add element to the list of convertedValue in result
- If Exists(element, key)
- If element is ListValue
- Return result
1.8KeyBy
Directive
directive @keyBy(key: String!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@keyBy can only be applied list of objects of depth 1. Nested lists can be flattened with @flatten first. @keyBy returns an object where the keys are the values of the field selected with key. The values are the first element with the corresponding key.
Given the following data:
Example № 22{
"list": [
{
"id": 1,
"string": "a"
},
{
"id": 2,
"string": "a"
},
{
"id": 3,
"string": "b"
}
]
}
The execution of the following query:
Example № 23{
list @keyBy(key: "string"){
string
}
}
will retrun the following result:
Example № 24{
"list": {
"a": {
"id": 1,
"string": "a"
},
"b": {
"id": 3,
"string": "b"
}
}
}
Execution
node is the value node where the directive is applied
- Let key be the value of the argument
keyof the directive - If node is ObjectValue
- Assert: AG0001
- Otherwise If node is ScalarValue
- Assert: AG0004
- Otherwise
- Return RewriteKeyByArray(node)
- Let result be a unordered map
- For each element in value
- If element is ListValue
- Assert: AG0003
- Otherwise If element is ScalarValue
- Assert: AG0002
- Otherwise If element is ObjectValue
- If Exists(element, key)
- Let fieldValue be Get(element, key)
- If IsConvertibleToString(fieldValue)
- Let convertedValue be ConvertToString(fieldValue)
- If NOT Exists(result, convertedValue)
- Set value of convertedValue in result to element
- If Exists(element, key)
- If element is ListValue
- Return result
1.9Keys
Directive
directive @keys repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@keys can only be to objects. @keys returns a list of all fields in this object.
Given the following data:
Example № 25{
"single": {
"id": 1,
"string": "a"
}
}
The execution of the following query:
Example № 26{
single @keys {
id
string
}
}
will retrun the following result:
Example № 27{
"single": [
"id",
"string",
]
}
Execution
node is the value node where the directive is applied
- If node is ListValue
- Assert: AG0003
- Otherwise If node is ScalarValue
- Assert: AG0002
- Otherwise
- Let result be a empty list
- For each key in keys of value
- Add key to result
- Return result
1.10MaxBy
Directive
directive @maxBy(key: String!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@maxBy can only be applied list of objects of depth 1. Nested lists can be flattened with @flatten first. @maxBy returns the object where the value of the field with name key is the highest. If no value was found, @maxBy retruns the first element of the list.
Given the following data:
Example № 28{
"list": [
{
"string": "a",
"int": 1
},
{
"string": "b",
"int": 2
},
{
"string": "c",
"int": 3
}
]
}
The execution of the following query:
Example № 29{
list @maxBy(key: "int"){
string
int
}
}
will retrun the following result:
Example № 30{
"list": {
"string": "c",
"int": 3
}
}
Execution
node is the value node where the directive is applied
- Let key be the value of the argument
keyof the directive - If node is ObjectValue
- Assert: AG0001
- Otherwise If node is ScalarValue
- Assert: AG0004
- Otherwise
- Return RewriteMaxByArray(node)
- If value has 0 elements
- Return null
- Let lastValue be a null
- Let result be a null
- If the first element of value is ObjectValue
- Set result to the first element of value
- For each element in value
- If element is ListValue
- Assert: AG0003
- Otherwise If element is ScalarValue
- Assert: AG0002
- Otherwise If element is ObjectValue
- If Exists(element, key)
- Let fieldValue be Get(element, key)
- If IsConvertibleToComparable(fieldValue)
- Let convertedValue be ConvertToComparable(fieldValue)
- If result is null OR lastValue is null OR convertedValue is greater than lastValue
- Set value of result to element
- Set value of lastValue to convertedValue
- If Exists(element, key)
- If element is ListValue
- Return result
1.11MeanBy
Directive
directive @meanBy(key: String!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@meanBy can only be applied list of objects of depth 1. Nested lists can be flattened with @flatten first. @meanBy returns mean of all values of the fields with name key. If no value was found, @meanBy retruns null.
Given the following data:
Example № 31{
"list": [
{
"int": 1
},
{
"int": 2
},
{
"int": 3
}
]
}
The execution of the following query:
Example № 32{
list @meanBy(key: "int"){
int
}
}
will retrun the following result:
Example № 33{
"list": 2
}
Execution
node is the value node where the directive is applied
- Let key be the value of the argument
keyof the directive - If node is ObjectValue
- Assert: AG0001
- Otherwise If node is ScalarValue
- Assert: AG0004
- Otherwise
- Return RewriteMeanByArray(node)
- Let divisor be 0
- Let sum be 0
- For Each element in value
- If element is ListValue
- Assert: AG0003
- Otherwise If element is ScalarValue
- Assert: AG0002
- Otherwise If element is ObjectValue
- If element is ListValue
- If divisor is 0
- Return null
- Return sum / divisor
1.12MinBy
Directive
directive @minBy(key: String!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@minBy can only be applied list of objects of depth 1. Nested lists can be flattened with @flatten first. @minBy returns the object where the value of the field with name key is the lowest. If no value was found, @minBy retruns the first element of the list.
Given the following data:
Example № 34{
"list": [
{
"string": "a",
"int": 1
},
{
"string": "b",
"int": 2
},
{
"string": "c",
"int": 3
}
]
}
The execution of the following query:
Example № 35{
list @minBy(key: "int"){
string
int
}
}
will retrun the following result:
Example № 36{
"list": {
"string": "a",
"int": 1
}
}
Execution
node is the value node where the directive is applied
- Let key be the value of the argument
keyof the directive - If node is ObjectValue
- Assert: AG0001
- Otherwise If node is ScalarValue
- Assert: AG0004
- Otherwise
- Return RewriteMinByArray(node)
- If value has 0 elements
- Return null
- Let lastValue be a null
- Let result be a null
- If the first element of value is ObjectValue
- Set result to the first element of value
- For each element in value
- If element is ListValue
- Assert: AG0003
- Otherwise If element is ScalarValue
- Assert: AG0002
- Otherwise If element is ObjectValue
- If Exists(element, key)
- Let fieldValue be Get(element, key)
- If IsConvertibleToComparable(fieldValue)
- Let convertedValue be ConvertToComparable(fieldValue)
- If result is null OR lastValue is null OR convertedValue is lower than lastValue
- Set value of result to element
- Set value of lastValue to convertedValue
- If Exists(element, key)
- If element is ListValue
- Return result
1.13SumBy
Directive
directive @sumBy(key: String!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@sumBy can only be applied list of objects of depth 1. Nested lists can be flattened with @flatten first. @sumBy returns the sum of all values of the fields with name key. If no value was found, @sumBy retruns null.
Given the following data:
Example № 37{
"list": [
{
"int": 1
},
{
"int": 2
},
{
"int": 3
}
]
}
The execution of the following query:
Example № 38{
list @sumBy(key: "int"){
int
}
}
will retrun the following result:
Example № 39{
"list": 6
}
Execution
node is the value node where the directive is applied
- Let key be the value of the argument
keyof the directive - If node is ObjectValue
- Assert: AG0001
- Otherwise If node is ScalarValue
- Assert: AG0004
- Otherwise
- Return RewriteSumByArray(node)
- Let sum be null
- For Each element in value
- If element is ListValue
- Assert: AG0003
- Otherwise If element is ScalarValue
- Assert: AG0002
- Otherwise If element is ObjectValue
- If element is ListValue
- Return sum
1.14Take
Directive
directive @take(count: Int!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@take can be applied a list any depth. @take returns the first count elements of the list. If there are less elements than count the list does not change.
Given the following data:
Example № 40{
"list": [
{
"string": "a"
},
{
"string": "b"
},
{
"string": "c"
}
]
}
The execution of the following query:
Example № 41{
list @take(count: 2){
string
}
}
will retrun the following result:
Example № 42{
"list": [
{
"string": "a"
},
{
"string": "b"
},
]
}
Execution
node is the value node where the directive is applied
- Let size be the value of the argument
sizeof the directive - If node is ObjectValue
- Assert: AG0001
- Otherwise If node is ScalarValue
- Assert: AG0004
- Otherwise
- Let result be the a list of the first size elements from the beginning of node
- Return result
1.15TakeRight
Directive
directive @takeRight(count: Int!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@takeRight can be applied a list any depth. @takeRight returns the last count elements of the list. If there are less elements than count the list does not change.
Given the following data:
Example № 43{
"list": [
{
"string": "a"
},
{
"string": "b"
},
{
"string": "c"
}
]
}
The execution of the following query:
Example № 44{
list @takeRight(count: 2){
string
}
}
will retrun the following result:
Example № 45{
"list": [
{
"string": "b"
},
{
"string": "c"
}
]
}
Execution
node is the value node where the directive is applied
- Let size be the value of the argument
sizeof the directive - If node is ObjectValue
- Assert: AG0001
- Otherwise If node is ScalarValue
- Assert: AG0004
- Otherwise
- Let result be the a list of the first size elements from the end of node
- Return node
1.16Uniq
Directive
directive @uniq(count: Int!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@uniq can be applied a list any depth. @uniq returns a duplicate-free version of the list.
Given the following data:
Example № 46{
"stringList": [ "a", "a", "b" ]
}
The execution of the following query:
Example № 47{
stringList @uniq
}
will retrun the following result:
Example № 48{
"stringList": [ "a", "b" ]
}
Execution
node is the value node where the directive is applied
- Let size be the value of the argument
sizeof the directive - If node is ObjectValue
- Assert: AG0001
- Otherwise If node is ScalarValue
- Assert: AG0004
- Otherwise
- Return RewriteUniqArray(node)
- Let result be a ordered set
- For each element in value
- If IsConvertibleToComparable(element)
- Let convertedValue be ConvertToComparable(fieldValue)
- If convertedValue does NOT exist in result
- Add convertedValue to result
- Otherwise
- Add element to result
- If IsConvertibleToComparable(element)
- Return result
1.17UniqBy
Directive
directive @uniqBy(key: String!) repeatable on QUERY | MUTATION | SUBSCRIPTION | FIELD
@uniqBy can be applied to a list of objects of depth 1. @uniqBy returns a duplicate-free version of the list based on the the values of the field selected with key.
Given the following data:
Example № 49{
"list": [
{
"string": "a"
},
{
"string": "a"
},
{
"string": "c"
}
]
}
The execution of the following query:
Example № 50{
list @uniqBy(key: "string"){
string
}
}
will retrun the following result:
Example № 51{
"list": {
{
"string": "a"
},
{
"string": "c"
}
}
}
Execution
node is the value node where the directive is applied
- Let key be the value of the argument
keyof the directive - If node is ObjectValue
- Assert: AG0001
- Otherwise If node is ScalarValue
- Assert: AG0004
- Otherwise
- Return RewriteUniqByArray(node)
- Let result be a empty list
- Let values be a ordered set
- For each element in value
- If element is ListValue
- Assert: AG0003
- Otherwise If element is ScalarValue
- Assert: AG0002
- Otherwise If element is ObjectValue
- If Exists(element, key)
- Let fieldValue be Get(element, key)
- If IsConvertibleToComparable(element)
- Let convertedValue be ConvertToComparable(fieldValue)
- If convertedValue does NOT exist in values
- Add element to result
- If Exists(element, key)
- Otherwise
- Add element to result
- If element is ListValue
- Return result
2Transformations
- If node is ObjectValue AND field key exists in node
- return true
- Otherwise
- return false
- If Exists(node, key)
- return value of field key in node
- Otherwise
- Assert: Field key is not present in node
- If node is string
- return node
- Otherwise If node is number
- return number as string
- Otherwise If node is boolean
- return boolean as string
- Otherwise If node is null
- return
"null"
- return
- Otherwise
- return null
- If node is string
- return true
- Otherwise If node is number
- return true
- Otherwise If node is boolean
- return true
- Otherwise If node is null
- return true
- Otherwise
- return false
- If node is number
- return number
- Otherwise If node is boolean
- return boolean
- Otherwise
- return null
- If node is number
- return true
- Otherwise If node is boolean
- return true
- Otherwise
- return false
- If node is number
- return true
- Otherwise
- return false
3Definitions
- ObjectValue
- Key Value pair
Example № 52{
"string": "string",
"int": 1,
"float": 2,
}
- ScalarValue
- A primitive leaf value
Example № 53"string"
Example № 541
- ListValue
- A collection of either ObjectValue, ScalarValue or ListValue
Example № 55[
{
"string": "string",
},
1,
[
{
"string": "string",
},
]
]
4Errors
- AG0001
- The field path expects a list but received an object
- AG0002
- The field path expects a object but received a scalar
- AG0003
- The field path expects a object but received an list
- AG0004
- The field path expects a list but received a scalar
- AG0005
- The argument size of chunk on field path must be greater than 0
- AG0006
- The argument size of flatten on field path must be greater than 0,
§Index
- @chunk
- @countBy
- @drop
- @dropRight
- @flatten
- @groupBy
- @keyBy
- @keys
- @map
- @maxBy
- @meanBy
- @minBy
- @sumBy
- @take
- @takeRight
- @uniq
- @uniqBy
- AG0001
- AG0002
- AG0003
- AG0004
- AG0005
- AG0006
- ConvertToComparable
- ConvertToString
- Exists
- Get
- IsConvertibleToComparable
- IsConvertibleToString
- IsNumber
- ListValue
- ObjectValue
- RewriteChunk
- RewriteCountBy
- RewriteCountByArray
- RewriteDrop
- RewriteDropRight
- RewriteFlatten
- RewriteFlattenList
- RewriteGroupBy
- RewriteGroupByArray
- RewriteKeyBy
- RewriteKeyByArray
- RewriteKeys
- RewriteMap
- RewriteMaxBy
- RewriteMaxByArray
- RewriteMeanBy
- RewriteMeanByArray
- RewriteMinBy
- RewriteMinByArray
- RewriteSumBy
- RewriteSumByArray
- RewriteTake
- RewriteTakeRight
- RewriteUniq
- RewriteUniqArray
- RewriteUniqBy
- RewriteUniqByArray
- ScalarValue