Gelly Query Structure
A query in Gelly declares a bunch of expressions and returns them. Gelly queries are very similar to GraphQL queries or SQL SELECT
statements -- they submit what data they want and then the platform returns it all in a predictable shape. A Gelly query can select fields from the underlying models, and expressions on those fields to manipulate or aggregate them, as well as control which records are returned.
As of right now, there's currently no way to execute a raw Gelly query in Gadget, but that will change soon.
Selecting fields of models
Queries can select fields from the available models by listing each field between curly brackets (a selection set) from the plural name of that model. For example, this query selects the id
and title
fields from the first page of a Blog Post model:
gelly1query {2 posts {3 id4 title5 }6}
This query will return a JSON document containing the selected fields for each blog post that looks like this:
json1{2 "posts": [3 { "id": 1, "title": "Hello World" },4 { "id": 2, "title": "Thoughts on Software Development" }5 ]6}
As many fields as needed can be added to the selection set, and a query can select from more than one model at once if needed. This query selects the first page of Blog Post ids, titles, and publish dates, as well as the current user's name and email:
gelly1query {2 posts {3 id4 title5 }6 currentUser {7 name8 email9 }10}
The underlying Gelly implementation will efficiently query these two models in parallel and return the data for both as a JSON object like this:
json1{2 "posts": [3 { "id": 1, "title": "Example A" },4 { "id": 2, "title": "Example B" }5 ],6 "currentUser": {7 "name": "Jane McGee",8 "email": "[email protected]"9 }10}
Fields in a selection must be separated by at least one whitespace character like a space, a tab, or a newline. Model fields are selected using the API Identifier for that field, not the field name.
Which fields you select is entirely up to you -- none are mandatory, and none require other fields to be selected in order to be selected themselves. Usually, the requirements for which fields are being selected are driven by the specific product experience you're trying to build. It's generally faster to select only the fields you need for a specific screen or component in an application, so developers will write one Gelly query (or fragment) per screen and only execute it when that screen is visited.
Selecting relationships
Gelly allows related data for each record to be selected alongside the containing record. To select related data, add an inner set of curly brackets (a nested selection set) to a root selection.
For example, this query selects the id
and title
of the first page of blog posts, as well as the id
and commentBody
of the first page of comments for each of the posts:
gelly1query {2 posts {3 id4 title5 comments {6 id7 commentBody8 }9 }10}
This query returns a JSON document where each element of the posts
array will have a comments
key holding another array of objects with the fields for each comment:
json1{2 "posts": [3 {4 "id": 1,5 "title": "Hello World",6 "comments": [7 {8 "id": 1,9 "commentBody": "Nice post!"10 },11 {12 "id": 2,13 "commentBody": "Cool blog!"14 }15 ]16 }17 ]18}
Relationship fields can be deeply nested, so you can select relationships of relationships. For example, if Blog Post has many Comments, and then Comments has many Comment Upvotes, you can select all three models at the same time like so:
gelly1query {2 posts {3 id4 title5 comments {6 id7 commentBody8 commentUpvotes {9 id10 createdAt11 }12 }13 }14}
Expressions
Gelly allows selecting arbitrary expressions of fields to ask the server to transform records before returning results to the client. Transformations can be simple string operations or math, complicated expressions with boolean logic, or aggregations that summarize a whole set of records into one value.
For example, we can select the full name for each record of a Customer model by adding the firstName
and lastName
fields together.
gelly1query {2 customers {3 id4 fullName: firstName + " " + lastName5 }6}
This query would produce a result like the one on the right.
json{"customers": [{ "fullName": "Jane McGee" }, { "fullName": "Joe Schmoe" }]}
Expressions are selected right alongside other fields and must be separated from each other with whitespace characters. Expressions can refer to other fields of the record in question, as well as use literals like strings and numbers to do useful work. Expressions can be simple literals, which return value the literal's value.
gellyquery {1}
json{"1": 1}
Expressions can also be complicated, and call functions or use boolean logic.
gelly1query {2 comments {3 id4 isSpam: author.markedAsSpammer || contains(lower(title), "spam") || author.spamScore < (endsWith(author.email, "@gmail.com") ? 10 : 5)5 }6}
Aliasing fields and expressions
You can name an expression (or rename a field) when selecting it by prefixing the selection with a name and a colon. For example, to select the title
field of a Blog Post model but have the resulting JSON blob use the key humanName
to store the field's value, you can run this query:
gellyquery {posts {humanName: title}}
This would produce a JSON result like:
json1{2 "posts": [3 { "humanName": "Hello World!" },4 { "humanName": "Thoughts on Software Development" }5 ]6}
Aliasing works on expressions as well. To select an uppercase version of the title
field from the Blog Post model outputted as the screamingTitle
key, the expression can be aliased by prefixing the selection with an alias identifier and a colon.
gellyquery {posts {screamingTitle: upcase(title)}}
This would produce a JSON result like the one on the right.
json1{2 "posts": [3 { "screamingTitle": "HELLO WORLD!" },4 { "humanName": "THOUGHTS ON SOFTWARE DEVELOPMENT" }5 ]6}
If you don't alias an expression, the expression's source Gelly snippet is used as the output field name. For example, querying for upcase(title)
will return the uppercase title under a field named upcase(title)
gellyquery {posts {upcase(title)}}
This would produce a JSON result like the one on the right.
json1{2 "posts": [3 { "upcase(title)": "HELLO WORLD!" },4 { "upcase(title)": "THOUGHTS ON SOFTWARE DEVELOPMENT" }5 ]6}
Ternary expressions
Gelly supports if-then-else statements using the ?
ternary expression, similar to JavaScript. Put a boolean expression first followed by a ?
symbol, and then two expressions separated by a :
. When the boolean expression is true, the first expression is selected, otherwise, the second expression is selected.
For a simple example, we can select the string "yes" if 10 is greater than 5:
gellyquery {isTenGreaterThanFive: 10 > 5 ? "yes" : "no"}
Which would produce a result JSON like so:
json{"isTenGreaterThanFive": "yes"}
Ternary expressions can also be used within selections of relations alongside other selections just fine.
gelly1query {2 posts {3 id4 title5 recent: createdAt < (now() - interval("60 days")) ? createdAt : "Old"6 }7}
Unlike SQL, ternary expressions don't need to return the same data type from the truthy and falsy expressions on either side of the colon.