# Gelly Reference  This reference complements the [Gelly Guide](https://docs.gadget.dev/guides/data-access/gelly) which provides general overview of the language. ## Built-in data types  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. `Integer`s and `Number`s are written out as the digits of the number: ```gelly query { anInteger: 5 aDecimal: 10.5 } ``` `Boolean`s are written as `true` or `false`: ```gelly query { yes: true no: false } ``` `String`s are written with the characters between double quotes, and using `\"` to escape quote characters within the string: ```gelly query { aString: "foo" withAQuoteInIt: "when she said \"yes\", it was incredible!" } ``` `DateTime`s 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](https://www.postgresql.org/docs/14/functions-datetime.html#OPERATORS-DATETIME-TABLE). If not specified, timestamps are assumed to be in UTC. ```gelly query { aTimestamp: timestamp("2021-05-01 15:00:00") anISO8601Timestamp: timestamp("2021-05-01T15:00:00Z") } ``` If input timestamps are not in UTC, they will be converted to UTC. ```gelly query { aTimestamp: timestamp("2021-05-01 15:00:00+05:00") // will be converted to UTC and returned as 2021-05-01T10:00:00.000Z } ``` Gelly (and Gadget) represent all timestamps as moments in time in the UTC timezone. If you want to work with timestamps in a different timezone, convert timestamps to UTC when writing data, and convert timestamps returned from Gelly to the desired timezone using client side code. `Date`s 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](https://www.postgresql.org/docs/14/functions-datetime.html#OPERATORS-DATETIME-TABLE). ```gelly query { anISO8601Date: date("2021-05-01") aDate: date("January 8, 1999") } ``` `Interval`s 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](https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-INTERVAL-INPUT). 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](https://www.postgresql.org/docs/14/functions-datetime.html#OPERATORS-DATETIME-TABLE). 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. ```gelly query { interval1: interval("3 days 4 hours") interval2: interval("P3YT2H") interval3: date("2021-05-01") - timestamp("2021-05-01 15:00:00") } ``` `null`s are written as `null`. There's no `undefined` in Gelly. `Array`s are written between square brackets with commas (`,`) separating the elements. ```gelly query { someNumbers: [1, 2, 3] someStrings: ["foo", "bar", "baz"] myStuff: [1, "foo", true, null] } ``` `Object`s are written between curly brackets with the keys on the left-hand side of a colon (`:`) and commas (`,`) separating the elements. ```gelly query { anObject: {foo: "bar", baz: true} } ``` ## Built-in operators  Gelly has several built-in operators for arithmetic, comparison, and boolean logic. ### Boolean logic  Prefix a boolean expression with an exclamation mark to inverse the boolean value. ```gelly query { !false # returns true } ``` Test if two booleans are both true with `&&`, or if either boolean is true with `||` ```gelly query { true && true # returns true true && false # returns false true || false # returns true false || false # returns false } ``` ### Equality and inequality  Test if two expressions are equal with two equal signs, like `==`. ```gelly query { 1 == 1 # returns true 1 == 2 # returns false true == true # returns true true == false # returns false } ``` Test if two expressions are not equal with `!=`. ```gelly query { 1 != 1 # returns false 1 != 2 # returns true true != true # returns false true != false # returns true } ``` ### Numeric ordering  Test how two numbers relate to each other with `>`, `>=`, `<`, and `<=`. ```gelly query { 1 > 1 # returns false 1 >= 1 # returns true 10 > 1 # returns true } ``` ### Arithmetic  Add, subtract, multiply or divide numbers with `+`, `-`, `*`, or `/`: ```gelly query { 1 + 1 # returns 2 2 * 10 # returns 20 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. ```gelly query { 10 / 3 # returns 3.3 repeating } ``` Use the `%` operator for a modulus (integer division remainder). ```gelly query { 10 % 3 # returns 1 } ``` ## Comments  You can write comments in Gelly by starting a line with `//`. ```gelly query { // this is a comment 1 } ``` You can also add block comments with `/*` and `*/`. ```gelly query { /* * this is a block comment * with multiple lines */ 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. ```gelly query { isNull(null) # returns true isNull({apple: "red"}.apple) # returns false isNull({apple: "red"}.orange) # returns true } ``` ### String functions  #### `concat(string: [String!]!, delimiter: String): String!`  Returns a new string built by stringing each input `string` together, optionally with a `delimiter`. ```gelly query { concat(["Hello", "", "world!"]) } ``` ```gelly query { posts { details: concat([title, " by ", author.name]) } } ``` ```gelly query { posts { details: concat(tags, delimiter: ", ") } } ``` #### `leftSlice(string: String!, length: Number): String!`  Returns a substring of the input `string`, starting from the first (leftmost) character position and including `length` characters after. ```gelly query { leftSlice("foobar", length: 3) # returns "foo" } ``` #### `length(string: String!): Integer!`  Returns the number of characters in the passed-in `string`. ```gelly query { length("foobar") # returns 6 } ``` #### `lower(string: String!): String!`  Returns the lower-cased version of the input `string`. ```gelly query { lower("FooBar") # returns "foobar" } ``` #### `rightSlice(string: String!, length: Number): String!`  Returns a substring of the input `string`, starting from the last (rightmost) character position and including a `length` number of previous characters. ```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. ```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. ```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. ```gelly query { slice("foobar", start: 4) # returns "ar" } ``` #### `upper(string: String!): String!`  Returns the upper-cased version of the input string. ```gelly query { upper("FooBar") # returns "FOOBAR" } ``` #### `startsWith(string: String!, prefix: String!): Boolean!`  Returns true if the string starts with the given prefix, and false otherwise. The prefix must be the same case as the input string. ```gelly query { startsWith("FooBar", prefix: "Foo") # returns true startsWith("FooBar", prefix: "foo") # returns false } ``` ### JSON functions  #### `contains(value: JSON!, item: (String | JSON)!): Boolean!`  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: ```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: ```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: ```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 } ``` #### `jsonPathMatch(value: JSON!, condition: String!): Boolean!`  Returns true if the JSON `value` matches the Postgres jsonpath filter expressions in `condition` as described in [https://www.postgresql.org/docs/13/functions-json.html#FUNCTIONS-SQLJSON-FILTER-EX-TABLE](https://www.postgresql.org/docs/13/functions-json.html#FUNCTIONS-SQLJSON-FILTER-EX-TABLE). You can use `$` to refer to the `value` and any valid jsonpath expression to navigate its structure as described in [https://www.postgresql.org/docs/13/functions-json.html#FUNCTIONS-SQLJSON-PATH](https://www.postgresql.org/docs/13/functions-json.html#FUNCTIONS-SQLJSON-PATH). ```gelly 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. ```gelly query { posts { count(id, where: isPublished) } } ``` This is equivalent to running `count` with a `[where]` relational command. ```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. ```gelly query { posts { totalCount: count(id) publishedCount: count(id, where: isPublished) highScoreCount: count(id, where: score > 10) bannedCount: count(id, where: author.banned) } } ``` #### `avg(number: Number!, where: Boolean): Number!`  Averages the given field number across the aggregated set, optionally filtered to only consider values that pass the condition. ```gelly query { posts { avg(score) [group by author.name] } } ``` To do a filtered average easily, you can use the `where` argument to the `avg` function. ```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. ```gelly query { posts { every(published) } } ``` To check if a subset of records match the passed conditions, use a `where` relational command. ```gelly query { posts { every(score > 10) [where published] } } ``` Using `every()` on relationships with no related records will evaluate to `true`. For example, the following snippet will return posts that have no comments. ```gelly // in Using every() across a relationship posts { title [ where every(comments.author.name == "Joe") ] } ``` #### `some(where: Boolean): Boolean!`  Returns `true` if some of the passed values are true themselves, or `false` if there are not any values that are true. ```gelly query { posts { some(published) } } ``` To check if some of a subset of records match the passed conditions, use a `where` relational command. ```gelly query { posts { some(score > 10) [where published] } } ``` `some` can also be aliased as `any` in Gelly. Using `some` is recommended. ```gelly // in Check if some posts have been published, using 'any' query { posts { any(published) } } ``` #### `count(value: Any, where: Boolean): Integer!`  Counts the number of non-null `value`s across the aggregated set, optionally filtered to only consider values which pass the condition. ```gelly query { posts { count(id) } } ``` To do a filtered count easily, you can use the `where` argument to the `count` function. ```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. ```gelly query { posts { count(id) avg(score) [where published] } } ``` Finally, when the counted value is a hasMany relationship, the result will be the count of the related model records for each of the source model records. In this case the source model records are not being aggregated by the count call (the related model records are). ```gelly query { posts { title count(comments) } } ``` #### `countDistinct(value: Any, where: Boolean): Integer!`  Counts the number of distinct non-null `value`s across the aggregated set, optionally filtered to only consider values which pass the condition. ```gelly query { posts { countDistinct(authorId) } } ``` It is also possible to count values of fields from related models. ```gelly query { posts { countDistinct(author.id) } } ``` As with simple counts, distinct counts can be filtered using the `where` argument. ```gelly query { posts { countDistinct(author.id, where: isPublished) } } ``` #### `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 condition. ```gelly query { posts { max(score) [group by author.name] } } ``` To find the maximum value in a subset of records easily, you can use the argument to the `max` function. ```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 condition. ```gelly query { posts { min(score) [group by author.name] } } ``` To find the minimum value in a subset of records easily, you can use the argument to the `min` function. ```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 condition. ```gelly query { posts { sum(voteCount) [group by author.name] } } ``` To sum only the value from a subset of records easily, you can use the argument to the `sum` function. ```gelly query { posts { max(score, where: isPublished) } } ``` ### Time functions  #### `date(input: String!): Date!`  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](https://www.postgresql.org/docs/14/functions-datetime.html#OPERATORS-DATETIME-TABLE). ```gelly query { date("2021-05-05") } ``` ```gelly query { posts { id publishAt [where publishAt > date("2021-05-05")] } } ``` #### `makeDate(year: Integer!, month: Integer, day: Integer): Date!`  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. ```gelly query { posts: { startOfFollowingYear: makeDate(year: datePart("year", date: publishedAt)) } } ``` #### `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. See more details about date\_part [in the Postgres docs](https://www.postgresql.org/docs/14/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT). ```gelly query { datePart("year", date: date("2021-05-05")) } ``` ```gelly 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. See more details about date\_trunc [in the Postgres docs](https://www.postgresql.org/docs/14/functions-datetime.html#FUNCTIONS-DATETIME-TRUNC). ```gelly query { dateTrunc("month", date: now()) } ``` #### `interval(string: String!): Interval!`  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](https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-INTERVAL-INPUT). ```gelly query { short: interval("5 minutes") long: interval("1 year") longer: interval("1 year") + interval("6 months") } ``` ```gelly query { posts { id publishAt [where publishAt > now() - interval("60 days")] } } ``` #### `makeInterval(years: Integer, months: Integer, weeks: Integer, days: Integer, hours: Integer, minutes: Integer, seconds: Number): Interval!`  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. ```gelly query { short: makeInterval(minutes: 5) pastTrial: now() - startedAt > makeInterval(days: trialDays) } ``` #### `now(): DateTime!`  Gets the current system time from the Gelly server. ```gelly query { now() } ``` ```gelly query { posts { id publishAt [where publishAt > now()] } } ``` ```gelly query { posts { id publishAt [where publishAt > now()] } } ``` #### `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](https://www.postgresql.org/docs/14/functions-datetime.html#OPERATORS-DATETIME-TABLE). If not specified, times are assumed to be in UTC. ```gelly query { timestamp("2021-05-05 10:10:00") } ``` ```gelly query { posts { id publishAt [where publishAt > timestamp("2021-05-01T15:00:00Z")] } } ``` #### `makeTimestamp(year: Integer!, month: Integer, day: Integer, hour: Integer, minute: Integer, second: Integer): DateTime!`  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. ```gelly query { makeTimestamp(year: 2021, month: 5, day: 3) } ``` #### `dateFormat(format: String!, date: (DateTime | Date)!): String!`  Format a `DateTime` or `Date` object as a string according to the given format string. The format string uses PostgreSQL's `to_char` formatting patterns -- see more details [in the Postgres docs](https://www.postgresql.org/docs/current/functions-formatting.html). Common format patterns include: * `YYYY` - 4-digit year * `MM` - month number (01-12) * `Mon` - abbreviated month name * `DD` - day of month (01-31) * `HH24` - hour of day (00-23) * `HH12` - hour of day (01-12) * `MI` - minute (00-59) * `SS` - second (00-59) * `AM`, `am`, `PM`, `pm` - meridiem indicator (without periods) * `FM` prefix - fill mode (suppress leading/trailing zeroes and padding blanks) ```gelly query { dateFormat("YYYY-MM-DD", date: date("2021-06-05")) # returns "2021-06-05" } ``` ```gelly query { posts { id publishedDate: dateFormat("Mon DD, YYYY", date: publishedAt) publishedTime: dateFormat("HH24:MI:SS", date: publishedAt) } } ``` ### Numeric functions  #### `abs(number: Number!): Integer!`  Gets the absolute value of a given input number. ```gelly query { abs(-10) # returns 10 abs(10) # returns 10 } ``` #### `ceil(number: Number!): Integer!`  Returns the nearest integer greater than or equal to the input `number`. ```gelly query { ceil(2.5) # returns 3 ceil(3) # returns 3 ceil(-2.5) # returns -2 ceil(-1) # returns -1 } ``` #### `floor(number: Number!): Integer!`  Returns the nearest integer less than or equal to the input `number`. ```gelly query { floor(2.5) # returns 2 floor(3) # returns 3 floor(-2.5) # returns -3 floor(-1) # returns -1 } ``` #### `exp(number: Number!): Number!`  Returns the exponential (the constant `e` raised to the given power) of the input `number`. ```gelly query { exp(1) # returns 2.7182818284590452 } ``` #### `ln(number: Number!): Number!`  Returns the natural logarithm (the logarithm with base `e`) of the input `number`. ```gelly query { ln(1) # returns 0 ln(10) # returns 2.302585092994046 } ``` #### `log(number: Number!, base: Number = 10): Number!`  Returns the logarithm with base `base` of the input `number`. The `base` defaults to `10`. ```gelly query { log(10) # returns 1 log(10, base: 2) # returns 0.1505149978319906 } ``` #### `mod`  There is no `mod` function in Gelly. Instead, use the `%` operator. #### `power(number: Number!, exponent: Number!): Number!`  Returns the given `number` raised to the given `exponent`. ```gelly query { power(10, exponent: 3) # returns 100 power(2, exponent: 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. ```gelly query { round(1) # returns 1 round(1.11111) # returns 1 round(1, precision: 2) # returns 1 round(1.11111, precision: 2) # returns 1.11 } ``` #### `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`. ```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. ```gelly query { trunc(1) # returns 1 trunc(1.11111) # returns 1 trunc(1.111111, precision: 2 # returns 1.11 trunc(1, precision: 2) # returns 1 } ``` #### `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!, 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. | ```gelly query { cast(1, type: "String") # returns "1" cast(-42, type: "String") # returns "-42" } ``` ```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. `cast`ing null always returns null. ### Other functions  #### `coalesce(input: [Any!]!>): Any!`  ```gelly query { coalesce([null, 1, 2]) # returns "1" } ``` Returns the first non-null value in the array.