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. The input string is formatted according to Postgres' timestamp literal syntax, which is documented in the Postgres docs. If not specified, times are assumed to be in UTC.
Dates are written using the date function which accepts a date string as input. The input string is formatted according to Postgres' date literal syntax, which is documented in the Postgres docs.
Intervals represent durations and can be created using the interval function that allows a verbose way of describing the value, e.g. 3 weeks 7 hours or a more concise (SQL standard format YY-MM DD HH:MM:SS) 21 7: or even a few variations of the ISO standard P3WT7H. More details on the supported syntaxes can be found in the Postgres docs.
Intervals can also result from subtracting Dates or DateTimes. Intervals can be added or subtracted from Dates and DateTimes as well. For more details on math with dates see Postgres docs.
Note that interval values are not automatically normalized, e.g. "60 hours" doesn't immediately become "2 days 12 hours". Consequently retrieving parts of an interval may sometime seem counterintuitive. However Gelly does normalize the interval value when it is returned as a result.
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
}
Functions
When working with functions, it is important to remember that argument keys are required. However, if a function accepts more than one argument, you may choose to omit the key for the first argument.
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 is 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.
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.
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.
Returns true if the given item is a subset of the given JSON value, and false otherwise. The value to be searched must be a JSON object or array, and the item can be a JSON object, array, string, or number. Corresponds to the @> operator in Postgres.
contains can be used to check if a JSON object contains a subset of another JSON object:
Matching objects
gelly
query {
contains({ foo: "bar", other: true }, item: { foo: "bar" }) # returns true, as the item is a subset of the value
}
contains can be used to check if an array contains an item:
Matching objects
gelly
query {
contains(["a", "b", "c"], item: "a") # returns true, as "a" is contained within the array
}
contains can be used to check if an object has a key:
Matching objects
gelly
query {
contains({foo: "1"}, item: "foo") # returns true, as the object has the foo key
contains({foo: "1"}, item: "bar") # returns false, as the object doesn't have the foo key
}
query {
jsonPathMatch(value: [1,2,3], condition: "$[0] == 2") # false, first element is 1
jsonPathMatch([1,2,3], condition: "$[*] == 2") # true, one of the elements is 2
jsonPathMatch([1,2,3], condition: "!($[*] == 5)") # true, none of the elements is 5
jsonPathMatch({a: 1}, condition: "$.a == 1") # true, property a has value 1
jsonPathMatch({a: [{b: 1}, {b: 2}]}, condition: "$.a[1].b == 2") # true
jsonPathMatch({a: [{b: 1}, {b: 2}]}, condition: "$.a[*].b == 2") # true
}
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
query {
posts {
count(id)
[where isPublished]
}
}
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.
Create a Date object from an input string representing a date (without a time). Uses the Postgres date formatting syntax -- see more details in the Postgres docs.
Create a Date object
gelly
query {
date("2021-05-05")
}
Posts scheduled for publishing after a certain threshold
Create a Date object from numbers representing the year, month and day. If not specified, both day and month default to 1. The numbers do not have to be literal, they can come from arbitrary expressions.
datePart(part: String!, date: (DateTime | Date | Interval)!): Number!
Retrieve a given component of a DateTime, Date or Interval 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 (Plural versions of these are also permitted as they suite the Interval type better). Only sensible combinations of types and part names will execute successfully.
query {
posts {
id
publishDay: datePart("dow", publishAt)
}
}
dateTrunc(part: String!, date: (DateTime | Date | Interval)!): (DateTime | Date | Interval)!
Rounds down a DateTime, Date or Interval object to the 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 (Plural versions of these are also permitted as they suite the Interval type better). Only sensible combinations of types and part names will execute successfully.
Create an Interval object from an input string representing a specific duration of time. interval uses the Postgres interval input 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")
}
Create an Interval object from number of years, months, weeks, days, hours, minutes, seconds. If not specified, all arguments default to 0. The seconds argument can be a decimal number representing fractional seconds. The numbers do not have to be literal, they can come from arbitrary expressions.
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
Create a DateTime object from numbers representing year, month, day, hour, minute, second. If not specified, month and day default to 1, the rest of the arguments default to 0. The seconds argument can be a decimal number representing fractional seconds. The numbers do not have to be literal, they can come from arbitrary expressions.
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.
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.
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!, type: 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.