With block​

keyword

with

With block - 图1

The with block in EdgeQL is used to define aliases.

The expression aliases are evaluated in the lexical scope they appear in, not the scope where their alias is used. This means that refactoring queries using aliases must be done with care so as not to alter the query semantics.

Specifying a module​

keyword

module

With block - 图2

Used inside a with block to specify module names.

One of the more basic and common uses of the with block is to specify the default module that is used in a query. with module <name> construct indicates that whenever an identifier is used without any module specified explicitly, the module will default to <name> and then fall back to built-ins from std module.

The following queries are exactly equivalent:

  1. with module example
  2. select User {
  3. name,
  4. owned := (select
  5. User.<owner[is Issue] {
  6. number,
  7. body
  8. }
  9. )
  10. }
  11. filter User.name like 'Alice%';
  12. select example::User {
  13. name,
  14. owned := (select
  15. example::User.<owner[is example::Issue] {
  16. number,
  17. body
  18. }
  19. )
  20. }
  21. filter example::User.name like 'Alice%';

It is also possible to define aliased modules in the with block. Consider the following query that needs to compare objects corresponding to concepts defined in two different modules.

  1. with
  2. module example,
  3. f as module foo
  4. select User {
  5. name
  6. }
  7. filter .name = f::Foo.name;

Another use case is for giving short aliases to long module names (especially if module names contain .).

  1. with
  2. module example,
  3. fbz as module foo.bar.baz
  4. select User {
  5. name
  6. }
  7. filter .name = fbz::Baz.name;

Local Expression Aliases​

It is possible to define an alias for an arbitrary expression. The result set of an alias expression behaves as a completely independent set of a given name. The contents of the set are determined by the expression at the point where the alias is defined. In terms of scope, the alias expression in the with block is in a sibling scope to the rest of the query.

It may be useful to factor out a common sub-expression from a larger complex query. This can be done by assigning the sub-expression a new symbol in the with block. However, care must be taken to ensure that this refactoring doesn’t alter the meaning of the expression due to scope change.

All expression aliases defined in a with block must be referenced in the body of the query.

  1. # Consider a query to get all users that own Issues and the
  2. # comments those users made.
  3. with module example
  4. select Issue.owner {
  5. name,
  6. comments := Issue.owner.<owner[is Comment]
  7. };
  8. # The above query can be refactored like this:
  9. with
  10. module example,
  11. U := Issue.owner
  12. select U {
  13. name,
  14. comments := U.<owner[is Comment]
  15. };

An example of incorrect refactoring would be:

  1. # This query gets a set of tuples of
  2. # issues and their owners.
  3. with
  4. module example
  5. select (Issue, Issue.owner);
  6. # This query gets a set of tuples that
  7. # result from a cartesian product of all issues
  8. # with all owners. This is because ``Issue`` and ``U``
  9. # are considered independent sets.
  10. with
  11. module example,
  12. U := Issue.owner
  13. select (Issue, U);

Detached​

keyword

detached

With block - 图3

The detached keyword marks an expression as not belonging to any scope.

A detached expression allows referring to some set as if it were defined in the top-level with block. Basically, detached expressions ignore all current scopes they are nested in and only take into account module aliases. The net effect is that it is possible to refer to an otherwise related set as if it were unrelated:

  1. with module example
  2. update User
  3. filter .name = 'Dave'
  4. set {
  5. friends := (select detached User filter .name = 'Alice'),
  6. coworkers := (select detached User filter .name = 'Bob')
  7. };

Here you can use the detached User expression, rather than having to define U := User in the with block just to allow it to be used in the body of the update. The goal is to indicate that the User in the update body is not in any way related to the User that’s being updated.

See also

EdgeQL > With