Light
Dark
System
v4latest
v4latest
v3
v2
v1

Boolean Functions and Operators

bool

Boolean type

bool or bool

Evaluates true if either boolean is true.

bool and bool

Evaluates true if both booleans are true.

not bool

Logically negates a given boolean value.

= != ?= ?!= < > <= >=

Comparison operators

all()

Returns true if none of the values in the given set are false.

any()

Returns true if any of the values in the given set is true.

assert()

Checks that the input bool is true.

type

bool
bool

A boolean type of either true or false.

EdgeQL has case-insensitive keywords and that includes the boolean literals:

Copy
db> 
select (True, true, TRUE);
{(true, true, true)}
Copy
db> 
select (False, false, FALSE);
{(false, false, false)}

These basic operators will always result in a boolean type value (although, for some of them, that value may be the empty set if an operand is the empty set):

These operators will result in a boolean type value even if the right operand is the empty set:

These operators will always result in a boolean true or false value, even if either operand is the empty set:

These operators will produce the empty set if either operand is the empty set:

If you need to use these operators and it’s possible one or both operands will be the empty set, you can ensure a bool product by coalescing. With = and !=, you can use their respective dedicated coalescing operators, ?= and ?!=. See each individual operator for an example.

Some boolean operator examples:

Copy
db> 
select true and 2 < 3;
{true}
Copy
db> 
select '!' IN {'hello', 'world'};
{false}

It’s possible to get a boolean by casting a str or json value into it:

Copy
db> 
select <bool>('true');
{true}
Copy
db> 
select <bool>to_json('false');
{false}

Filter clauses must always evaluate to a boolean:

Copy
select User
filter .name ilike 'alice';

operator

bool or bool
bool or bool -> bool

Evaluates true if either boolean is true.

Copy
db> 
select false or true;
{true}

When either operand in an or is an empty set, the result will not be a bool but instead an empty set.

Copy
db> 
select true or <bool>{};
{}

If one of the operands in an or operation could be an empty set, you may want to use the coalesce operator (??) on that side to ensure you will still get a bool result.

Copy
db> 
select true or (<bool>{} ?? false);
{true}

operator

bool and bool
bool and bool -> bool

Evaluates true if both booleans are true.

Copy
db> 
select false and true;
{false}

When either operand in an and is an empty set, the result will not be a bool but instead an empty set.

Copy
db> 
select true and <bool>{};
{}

If one of the operands in an and operation could be an empty set, you may want to use the coalesce operator (??) on that side to ensure you will still get a bool result.

Copy
db> 
select true and (<bool>{} ?? false);
{false}

operator

not bool
not bool -> bool

Logically negates a given boolean value.

Copy
db> 
select not false;
{true}

When the operand in a not is an empty set, the result will not be a bool but instead an empty set.

Copy
db> 
select not <bool>{};
{}

If the operand in a not operation could be an empty set, you may want to use the coalesce operator (??) on that side to ensure you will still get a bool result.

Copy
db> 
select not (<bool>{} ?? false);
{true}

The and and or operators are commutative.

The truth tables are as follows:

a

b

a and b

a or b

not a

true

true

true

true

false

true

false

false

true

false

false

true

false

true

true

false

false

false

false

true

The operators and/or and the functions all()/any() differ in the way they handle an empty set ({}). Both and and or operators apply to the cross-product of their operands. If either operand is an empty set, the result will also be an empty set. For example:

Copy
db> 
select {true, false} and <bool>{};
{}
Copy
db> 
select true and <bool>{};
{}

Operating on an empty set with all()/any() does not return an empty set:

Copy
db> 
select all(<bool>{});
{true}
Copy
db> 
select any(<bool>{});
{false}

all() returns true because the empty set contains no false values.

any() returns false because the empty set contains no true values.

The all() and any() functions are generalized to apply to sets of values, including {}. Thus they have the following truth table:

a

b

all({a, b})

any({a, b})

true

true

true

true

true

false

false

true

{}

true

true

true

{}

false

false

false

false

true

false

true

false

false

false

false

true

{}

true

true

false

{}

false

false

{}

{}

true

false

Since all() and any() apply to sets as a whole, missing values (represented by {}) are just that - missing. They don’t affect the overall result.

To understand the last line in the above truth table it’s useful to remember that all({a, b}) = all(a) and all(b) and any({a, b}) = any(a) or any(b).

For more customized handling of {}, use the ?? operator.

function

assert()
std::assert( input: bool, named only message: optional str = <str>{} ) -> bool

Checks that the input bool is true.

If the input bool is false, assert raises a QueryAssertionError. Otherwise, this function returns true.

Copy
db> 
select assert(true);
{true}
Copy
db> 
select assert(false);
edgedb error: QueryAssertionError: assertion failed
Copy
db> 
select assert(false, message := 'value is not true');
edgedb error: QueryAssertionError: value is not true

assert can be used in triggers to create more powerful constraints. In this schema, the Person type has both friends and enemies links. You may not want a Person to be both a friend and an enemy of the same Person. assert can be used inside a trigger to easily prohibit this.

Copy
type Person {
  required name: str;
  multi friends: Person;
  multi enemies: Person;

  trigger prohibit_frenemies after insert, update for each do (
    assert(
      not exists (__new__.friends intersect __new__.enemies),
      message := "Invalid frenemies",
    )
  )
}

With this trigger in place, it is impossible to link the same Person as both a friend and an enemy of any other person.

Copy
db> 
insert Person {name := 'Quincey Morris'};
{default::Person {id: e4a55480-d2de-11ed-93bd-9f4224fc73af}}
Copy
db> 
insert Person {name := 'Dracula'};
{default::Person {id: e7f2cff0-d2de-11ed-93bd-279780478afb}}
Copy
db> 
... 
... 
... 
... 
... 
... 
update Person
filter .name = 'Quincey Morris'
set {
  enemies := (
    select detached Person filter .name = 'Dracula'
  )
};
{default::Person {id: e4a55480-d2de-11ed-93bd-9f4224fc73af}}
Copy
db> 
... 
... 
... 
... 
... 
... 
update Person
filter .name = 'Quincey Morris'
set {
  friends := (
    select detached Person filter .name = 'Dracula'
  )
};
edgedb error: EdgeDBError: Invalid frenemies

In the following examples, the size properties of the File objects are 1024, 1024, and 131,072.

Copy
db> 
... 
for obj in (select File)
union (assert(obj.size <= 128*1024, message := 'file too big'));
{true, true, true}
Copy
db> 
... 
for obj in (select File)
union (assert(obj.size <= 64*1024, message := 'file too big'));
edgedb error: QueryAssertionError: file too big

You may call assert in the order by clause of your select statement. This will ensure it is called only on objects that pass your filter.

Copy
db> 
... 
select File { name, size }
order by assert(.size <= 128*1024, message := "file too big");
{
  default::File {name: 'File 2', size: 1024},
  default::File {name: 'Asdf 3', size: 1024},
  default::File {name: 'File 1', size: 131072},
}
Copy
db> 
... 
select File { name, size }
order by assert(.size <= 64*1024, message := "file too big");
edgedb error: QueryAssertionError: file too big
Copy
db> 
... 
... 
select File { name, size }
filter .size <= 64*1024
order by assert(.size <= 64*1024, message := "file too big");
{
  default::File {name: 'File 2', size: 1024},
  default::File {name: 'Asdf 3', size: 1024}
}
Light
Dark
System

We use ChatGPT with additional context from our documentation to answer your questions. Not all answers will be accurate. Please join our Discord if you need more help.