Gelly supports literals for a variety of built-in data types that you can use in your expressions. The syntax is very similar to JavaScript, so you can usually use the same syntax to declare literals as you might in JS within Gelly snippets.
Integers and Numbers are written out as the digits of the number:
Number literals
gelly
query{
anInteger:5
aDecimal:10.5
}
Booleans are written as true or false:
Boolean literals
gelly
query{
yes:true
no:false
}
Strings are written with the characters between double quotes, and using \" to escape quote characters within the string:
String literals
gelly
query{
aString:"foo"
withAQuoteInIt:"when she said \"yes\", it was incredible!"
}
DateTimes are written using the timestamp function which accepts a timestamp string as input, or the date function which accepts a date string as input. The date string is formatted according to Postgres' timestamp and date literal syntax, which is documented in the Postgres docs. If not specified, times are assumed to be in UTC.
Date literals
gelly
query{
aTimestamp: timestamp("2021-05-01 15:00:00")
anISO8601Date: timestamp("2021-05-01T15:00:00Z")
aDate: date("2021-05-01")
}
nulls are written as null. There's no undefined in Gelly.
Arrays are written between square brackets with commas (,) separating the elements.
Array literals
gelly
query{
someNumbers:[1,2,3]
someStrings:["foo","bar","baz"]
myStuff:[1,"foo",true,null]
}
Objects are written between curly brackets with the keys on the left-hand side of a colon (:) and commas (,) separating the elements.
Object literals
gelly
query{
anObject:{foo:"bar",baz:true}
}
Built-in operators
Gelly has a number of built-in operators for arithmetic, comparison, and boolean logic.
Boolean logic
Prefix a boolean expression with an exclamation mark to inverse the boolean value.
Logical not
gelly
query{
!false# returns true
}
Test if two booleans are both true with &&, or if either boolean is true with ||
The number line
gelly
1query{
2true&&true# returns true
3true&&false# returns false
4true||false# returns true
5false||false# returns false
6}
Equality and inequality
Test if two expressions are equal with two equals signs, like ==.
Expression Equality
gelly
1query{
21==1# returns true
31==2# returns false
4true==true# returns true
5true==false# returns false
6}
Test if two expressions are not equal with !=.
Expression Inequality
gelly
1query{
21!=1# returns false
31!=2# returns true
4true!=true# returns false
5true!=false# returns true
6}
Numeric ordering
Test how two numbers relate to each other with >, >=, <, and <=.
The number line
gelly
query{
1>1# returns false
1>=1# returns true
10>1# returns true
}
Arithmetic
Add, subtract, multiply or divide numbers with +, -, *, or /:
Back to elementary school
gelly
query{
1 + 1# returns 2
2*10# returns 10
10 / 2# returns 5
}
Division in Gelly returns decimal numbers with arbitrary precision. There is no integer division operator. This is different than most
SQL engines, which do integer division by default, and ECMAScript, which uses IEEE-754 floating point numbers and thus has limited
precision for mathematics.
Division
gelly
query{
10 / 3# returns 3.3 repeating
}
Use the % operator for a modulus (integer division remainder).
Modulus
gelly
query{
10 % 3# returns 1
}
Boolean functions
isNull(<value:> Any): Boolean!
Returns true if the passed value is null, and false otherwise.
To check if something is null, you must use the isNull function, and not do an equality check like == null. This is because like SQL,
null in Gelly is a special state of a data type that exists for every data type, and not a value itself. This different than JavaScript
or other statement based languages where null == null, in Gelly, anything == null returns null itself. This is called three-valued
logic and allows folks writing Gelly queries to not have to do constant null checks to make sure that a value is not null before
manipulating or selecting it.
Returns a substring of the input string, starting from the last (right most) character position and including length previous characters.
Rightslice a string
gelly
query{
rightSlice("foobar",length:3)# returns "bar"
}
slice(<string:> String!, start: Number = 0, length: Number): String!
Returns a substring of the input string, starting from the start character position, or the first character if no start is passed, and going length characters further, or to the end of the string if length is not passed.
Slice a string from the start
gelly
query{
slice("foobar",length:3)# returns "foo"
}
The start character position is inclusive, so start: 0 would include the first character in the string onwards, or start: 1 would skip the first character but include the second character onwards.
Slice a string in the middle
gelly
query{
slice("foobar",start:2,length:3)# returns "oba"
}
If the start argument is provided and the length argument isn't provided, the remainder of the string from the start position is returned.
Slice a string in the middle
gelly
query{
slice("foobar",start:4)# returns "ar"
}
upper(<string:> String!): String!
Returns the upper-cased version of the input string.
uppercase a string
gelly
query{
upper("FooBar")# returns "FOOBAR"
}
Aggregation functions
The where argument
All aggregate functions in Gelly take a where argument which allows for filtering the set of records for passing through the function. The where argument doesn't filter the returned set of records, or affect other function calls, it only affects the aggregate function to which it is passed. where is a convenient way of quickly filtering records without having to filter the whole record set, but can be used interchangeably with the where relational command.
Using where with the count function allows counting records that match certain criteria.
Count the number of published posts
gelly
query{
posts {
count(id,where: isPublished)
}
}
This is equivalent to running count with a [where] relational command.
Count the number of published posts
gelly
1query{
2 posts {
3 count(id)
4[where isPublished]
5}
6}
Notably, the where argument can be used to issue multiple aggregate calls at once with different filter conditions without having to do many outer selection sets. The [where] relational command filters all records before passing them onto the functions, so all aggregate functions in a selection set are given the same, already filtered list of records to aggregate.
Aggregate posts with different filters
gelly
1query{
2 posts {
3totalCount: count(id)
4publishedCount: count(id,where: isPublished)
5highScoreCount: count(id,where: score >10)
6bannedCount: count(id,where: author.banned)
7}
8}
avg(<number:> Number!, where: Boolean): Number!
Averages the given field number across the aggregated set, optionally filtered to only consider values that pass the where condition.
Average all post scores by author
gelly
1query{
2 posts {
3 avg(score)
4[group by author.name]
5}
6}
To do a filtered average easily, you can use the where argument to the avg function.
Average only published post scores
gelly
query{
posts {
avg(score,where: isPublished)
}
}
every(where: Boolean): Boolean!
Returns true if all the passed values are true themselves, or false if any of the passed values are falsy.
Check if all posts have been published
gelly
query{
posts {
every(published)
}
}
To check if a subset of records match the passed conditions, use a where relational command.
Check if all published posts have a high score
gelly
1query{
2 posts {
3 every(score >10)
4[where published]
5}
6}
count(<value:> Any, where: Boolean): Integer!
Counts the number of non-null values across the aggregated set, optionally filtered to only consider values which pass the where condition.
Count the number of posts
gelly
query{
posts {
count(id)
}
}
To do a filtered count easily, you can use the where argument to the count function.
Count the number of published posts
gelly
query{
posts {
count(id,where: isPublished)
}
}
count is also subject to the relational commands for the query, so you can filter a count aggregate as well as other aggregates at the same time.
Get the average score and count of published posts
gelly
1query{
2 posts {
3 count(id)
4 avg(score)
5[where published]
6}
7}
max(<number:> Number!, where: Boolean): Number!
Finds the maximum value of the number argument across the aggregated set, optionally filtered to only consider values which pass the where condition.
Find the maximum post scores by author
gelly
1query{
2 posts {
3 max(score)
4[group by author.name]
5}
6}
To find the maximum value in a subset of records easily, you can use the where argument to the max function.
Maximum published post score
gelly
query{
posts {
max(score,where: isPublished)
}
}
min(<number:> Number!, where: Boolean): Number!
Finds the minimum value of the number argument across the aggregated set, optionally filtered to only consider values which pass the where condition.
Find the minimum post scores by author
gelly
1query{
2 posts {
3 min(score)
4[group by author.name]
5}
6}
To find the minimum value in a subset of records easily, you can use the where argument to the min function.
Minimum published post score
gelly
query{
posts {
min(score,where: isPublished)
}
}
sum(<number:> Number!, where: Boolean): Number!
Adds the value of the number argument together across the whole aggregated set, optionally adding only values which pass the where condition.
Get the total votes cast by author
gelly
1query{
2 posts {
3 sum(voteCount)
4[group by author.name]
5}
6}
To sum only the value from a subset of records easily, you can use the where argument to the sum function.
Maximum published post score
gelly
query{
posts {
max(score,where: isPublished)
}
}
Time functions
date(input: String!): DateTime!
Create a DateTime object from an input string representing a date (without a time). Uses the Postgres date and time formatting syntax -- see more details in the Postgres docs.
Create a DateTime object
gelly
query{
date("2021-05-05")
}
Posts scheduled for publishing after a certain threshold
gelly
1query{
2 posts {
3 id
4 publishAt
5[where publishAt > date("2021-05-05")]
6}
7}
datePart(part: String!, date: DateTime!): Number!
Retrieve a given component of a DateTime object, like the year, week, or minutes. Uses the Postgres syntax for the date part, and returns it as a number. The valid parts are century, day, decade, dow (day of week), doy (day of year), epoch, hour, isodow, isoyear, microseconds, millennium, milliseconds, minute, month, quarter, second, week, year.
Rounds down a DateTime object to closest date part. Uses the Postgres syntax for the date part. The valid parts are microseconds, milliseconds, second, minute, hour, day, week, month, quarter, year, decade, century, millennium.
Create a Interval object from an input string representing a specific duration of time. Intervals are useful for doing math with dates. interval uses the Postgres interval formatting syntax -- see more details in the Postgres docs.
Create an Interval value
gelly
query{
short: interval("5 minutes")
long: interval("1 year")
longer: interval("1 year") + interval("6 months")
}
Posts published in the last 60 days
gelly
1query{
2 posts {
3 id
4 publishAt
5[where publishAt > now()- interval("60 days")]
6}
7}
now(): DateTime!
Gets the current system time from the Gelly server.
Current Time
gelly
query{
now()
}
Posts scheduled for publishing in the future
gelly
1query{
2 posts {
3 id
4 publishAt
5[where publishAt > now()]
6}
7}
Posts scheduled for publishing in the future
gelly
1query{
2 posts {
3 id
4 publishAt
5[where publishAt > now()]
6}
7}
timestamp(input: String!): DateTime!
Create a DateTime object from an input string representing a specific point in time. Uses the Postgres time formatting syntax -- see more details in the Postgres docs. If not specified, times are assumed to be in UTC.
Create a DateTime value
gelly
query{
timestamp("2021-05-05 10:10:00")
}
Posts scheduled for publishing after a certain threshold
Returns the given number raised to the given exponent.
Natural Logarithm of numbers
gelly
query{
power(10,3)# returns 100
power(2,5)# returns 32
}
round(<number:> Number!, precision: Number = 0): Number!
Rounds the given fractional number to the nearest number of decimal places, counted by precision. Precision defaults to 0, so when not passed round rounds to an integer number.
Rounding numbers
gelly
1query{
2 round(1)# returns 1
3 round(1.11111)# returns 1
4 round(1,precision:2)# returns 1
5 round(1.11111,precision:2)# returns 1.11
6}
sign(<number:> Number!): Number!
Returns 1 if the number is positive, -1 if the number is negative, or 0 if the number is 0.
sqrt(<number:> Number!): Number!
Returns the square root of the given number.
Number square roots
gelly
query{
sqrt(4)# returns 2
sqrt(10)# returns 3.162277660168379
}
trunc(<number:> Number!, precision: Number = 0): Number!
Truncates the given fractional number to the number of decimal places counted by precision. trunc doesn't do any rounding, precision is simply discarded, so if you want to round the number, see round. precision defaults to 0.
Number square roots
gelly
1query{
2 trunc(1)# returns 1
3 trunc(1.11111)# returns 1
4 trunc(1.111111,precision:2# returns 1.11
5 trunc(1,precision:2)# returns 1
6}
random(): Number!
Returns a random number greater than or equal to 0 and less than 1.
Trigonometric functions and constants
acos(<number:> Number!): Number!
Returns the inverse cosine of the input number given in radians, output in radians.
asin(<number:> Number!): Number!
Returns the inverse sine of the input number given in radians, output in radians.
atan(<number:> Number!): Number!
Returns the inverse tangent of the input number given in radians, output in radians.
cos(<number:> Number!): Number!
Returns the cosine of the input number given in radians, output in radians.
cot(<number:> Number!): Number!
Returns the cotangent of the input number given in radians, output in radians.
degrees(<radians:> Number!): Number!
Converts the given input radians in radians to degrees.
pi
Returns the value of pi, accurate to 15 decimal places.
radians(<degrees:> Number!): Number!
Converts the given input degrees in degrees to radians.
sin(<number:> Number!): Number!
Returns the sine of the input number given in radians, output in radians.
tan(<number:> Number!): Number!
Returns the tangent of the input number given in radians, output in radians.
Type conversion functions
cast(<input:> Any!, typeName: String!): Any!
Converts an input expression to a new type if possible. Can fail if the value of the input can't be converted. Expects the destination type's name to be passed as a string literal, and only accepts values from the table of type names below.
Available type names:
Name
Notes
String
Number
Will fail if the input can't be automatically converted to a number. Empty strings, or strings with non-numeric characters will fail.
Boolean
Converts the string "0" or the empty string to false, and any other string to true.
Casting numbers to strings
gelly
query{
cast(1,type:"String")# returns "1"
cast(-42,type:"String")# returns "-42"
}
Casting strings to numbers
gelly
query{
cast("1",type:"Number")# returns 1
cast("-42",type:"Number")# returns -42
cast("apple",type:"Number")# will throw an error as the string can't be converted
}
Note: null values are not changed when casting in Gelly. casting null always returns null.