Globals​
Schemas in Gel can contain typed global variables. These create a mechanism
for specifying session-level context that can be referenced in queries,
access policies, triggers, and elsewhere with the global
keyword.
Here's a very common example of a global variable representing the current user ID:
global current_user_id: uuid;
select User {
id,
posts: { title, content }
}
filter .id = global current_user_id;
# In a non-trivial example, `global current_user_id` would
# be used indirectly in an access policy or some other context.
await client.with_globals({'user_id': user_id}).qeury('''
select User {
id,
posts: { title, content }
}
filter .id = global current_user_id;
''')
// In a non-trivial example, `global current_user_id` would
// be used indirectly in an access policy or some other context.
await client.withGlobals({user_id}).qeury('''
select User {
id,
posts: { title, content }
}
filter .id = global current_user_id;
''')
Setting global variables​
Global variables are set at session level or when initializing a client. The exact API depends on which client library you're using, but the general behavior and principles are the same across all libraries.
import createClient from 'gel';
const baseClient = createClient();
// returns a new Client instance, that shares the underlying
// network connection with `baseClient` , but sends the configured
// globals along with all queries run through it:
const clientWithGlobals = baseClient.withGlobals({
current_user_id: '2141a5b4-5634-4ccc-b835-437863534c51',
});
const result = await clientWithGlobals.query(
`select global current_user_id;`
);
from gel import create_client
base_client = create_client()
# returns a new Client instance, that shares the underlying
# network connection with `base_client` , but sends the configured
# globals along with all queries run through it:
client = base_client.with_globals({
'current_user_id': '580cc652-8ab8-4a20-8db9-4c79a4b1fd81'
})
result = client.query("""
select global current_user_id;
""")
package main
import (
"context"
"fmt"
"log"
"github.com/geldata/gel-go"
)
func main() {
ctx := context.Background()
client, err := gel.CreateClient(ctx, gel.Options{})
if err != nil {
log.Fatal(err)
}
defer client.Close()
id, err := gel.ParseUUID("2141a5b4-5634-4ccc-b835-437863534c51")
if err != nil {
log.Fatal(err)
}
var result gel.UUID
err = client.
WithGlobals(map[string]interface{}{"current_user": id}).
QuerySingle(ctx, "SELECT global current_user;", &result)
if err != nil {
log.Fatal(err)
}
fmt.Println(result)
}
use uuid::Uuid;
let client = gel_tokio::create_client().await.expect("Client init");
let client_with_globals = client.with_globals_fn(|c| {
c.set(
"current_user_id",
Value::Uuid(
Uuid::parse_str("2141a5b4-5634-4ccc-b835-437863534c51")
.expect("Uuid should have parsed"),
),
)
});
let val: Uuid = client_with_globals
.query_required_single("select global current_user_id;", &())
.await
.expect("Returning value");
println!("Result: {val}");
set global current_user_id :=
<uuid>'2141a5b4-5634-4ccc-b835-437863534c51';
Cardinality​
A global variable can be declared with one of two cardinalities:
-
single
(the default): At most one value. -
multi
: A set of values. Only valid for computed global variables.
In addition, a global can be marked required
or optional
(the default).
If marked required
, a default value must be provided.
Computed globals​
Global variables can also be computed. The value of computed globals is dynamically computed when they are referenced in queries.
required global now := datetime_of_transaction();
The provided expression will be computed at the start of each query in which the global is referenced. There's no need to provide an explicit type; the type is inferred from the computed expression.
Computed globals can also be object-typed and have multi
cardinality.
For example:
global current_user_id: uuid;
# object-typed global
global current_user := (
select User filter .id = global current_user_id
);
# multi global
global current_user_friends := (global current_user).friends;
Referencing globals​
Unlike query parameters, globals can be referenced inside your schema declarations:
type User {
name: str;
is_self := (.id = global current_user_id)
};
This is particularly useful when declaring access policies:
type Person {
required name: str;
access policy my_policy allow all
using (.id = global current_user_id);
}
Refer to Access Policies for complete documentation.
Declaring globals​
This section describes the syntax to declare a global variable in your schema.
Syntax​
Define a new global variable in SDL, corresponding to the more explicit DDL commands described later:
Global variable declaration:
[{required | optional}] [single]
global name: type
[ "{"
[ default := expression ; ]
[ annotation-declarations ]
...
"}" ]
Computed global variable declaration:
[{required | optional}] [{single | multi}]
global name := expression;
Description​
There are two different forms of global
declarations, as shown in the
syntax synopsis above:
-
A settable global (defined with
: <type>
) which can be changed using a session-level set command. -
A computed global (defined with
:= <expression>
), which cannot be directly set but instead derives its value from the provided expression.
The following options are available:
- required
-
If specified, the global variable is considered required. It is an error for this variable to have an empty value. If a global variable is declared required, it must also declare a default value.
- optional
-
The global variable is considered optional, i.e. it is possible for the variable to have an empty value. (This is the default.)
- multi
-
Specifies that the global variable may have a set of values. Only computed global variables can have this qualifier.
- single
-
Specifies that the global variable must have at most a single value. It is assumed that a global variable is
single
if neithermulti
norsingle
is specified. All non-computed global variables must be single. - name
-
The name of the global variable. It can be fully-qualified with the module name, or it is assumed to belong to the module in which it appears.
- type
-
The type must be a valid type expression denoting a non-abstract scalar or a container type.
- name := expression
-
Defines a computed global variable. The provided expression must be a Stable EdgeQL expression. It can refer to other global variables. The type of a computed global variable is not limited to scalar and container types; it can also be an object type.
The valid SDL sub-declarations are:
- default := expression
-
Specifies the default value for the global variable as an EdgeQL expression. The default value is used in a session if the value was not explicitly specified by the client, or was reset with the reset command.
- annotation-declarations
-
Set global variable annotation to a given value.
Examples​
Declare a new global variable:
global current_user_id: uuid;
global current_user := (
select User filter .id = global current_user_id
);
Set the global variable to a specific value using session-level commands:
set global current_user_id :=
<uuid>'00ea8eaa-02f9-11ed-a676-6bd11cc6c557';
Use the computed global variable that is based on the value that was just set:
select global current_user { name };
Reset the global variable to its default value:
reset global user_id;
DDL commands​
This section describes the low-level DDL commands for creating, altering, and dropping globals. You typically don't need to use these commands directly, but knowing about them is useful for reviewing migrations.
Create global​
Declare a new global variable using DDL.
[ with with-item [, ...] ]
create [{required | optional}] [single]
global name: type
[ "{" subcommand; [...] "}" ] ;
Computed global variable form:
[ with with-item [, ...] ]
create [{required | optional}] [{single | multi}]
global name := expression;
where subcommand is one of
set default := expression
create annotation annotation-name := value
Description​
As with SDL, there are two different forms of global
declaration:
-
A global variable that can be set in a session.
-
A computed global that is derived from an expression (and so cannot be directly set in a session).
The subcommands mirror those in SDL:
- set default := expression
-
Specifies the default value for the global variable as an EdgeQL expression. The default value is used by the session if the value was not explicitly specified or was reset with the reset command.
- create annotation annotation-name := value
-
Assign an annotation to the global variable. See
create annotation
for details.
Alter global​
Change the definition of a global variable.
[ with with-item [, ...] ]
alter global name
[ "{" subcommand; [...] "}" ] ;
where subcommand is one of
set default := expression
reset default
rename to newname
set required
set optional
reset optionalily
set single
set multi
reset cardinality
set type typename reset to default
using (computed-expr)
create annotation annotation-name := value
alter annotation annotation-name := value
drop annotation annotation-name
Description​
The command alter global changes the definition of a global variable. It can modify default values, rename the global, or change other attributes like optionality, cardinality, computed expressions, etc.
Examples​
Set the description
annotation of global variable current_user
:
alter global current_user
create annotation description :=
'Current User as specified by the global ID';
Make the current_user_id
global variable required
:
alter global current_user_id {
set required;
# A required global variable MUST have a default value.
set default := <uuid>'00ea8eaa-02f9-11ed-a676-6bd11cc6c557';
}