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
key
of 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
size
of 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
key
of 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
size
of 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
size
of 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
depth
of 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
key
of 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
key
of 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
key
of 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
key
of 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
key
of 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
key
of 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
size
of 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
size
of 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
size
of 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
key
of 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