For​

for–compute a union of subsets based on values of another set

  1. [ with with-item [, ...] ]
  2. for variable in iterator-expr
  3. union output-expr ;

for variable in iterator-expr

The for clause has this general form:

  1. for variable in iterator-expr

union output-expr

The union clause of the for statement has this general form:

  1. union output-expr

Here, output-expr is an arbitrary expression that is evaluated for every element in a set produced by evaluating the for clause. The results of the evaluation are appended to the result set.

Usage of for statement​

for statement has some powerful features that deserve to be considered in detail separately. However, the common core is that for iterates over elements of some arbitrary expression. Then for each element of the iterator some set is computed and combined via a union with the other such computed sets.

The simplest use case is when the iterator is given by a set expression and it follows the general form of for x in A ...:

  1. with module example
  2. # the iterator is an explicit set of tuples, so x is an
  3. # element of this set, i.e. a single tuple
  4. for x in {
  5. (name := 'Alice', theme := 'fire'),
  6. (name := 'Bob', theme := 'rain'),
  7. (name := 'Carol', theme := 'clouds'),
  8. (name := 'Dave', theme := 'forest')
  9. }
  10. # typically this is used with an INSERT, DELETE or UPDATE
  11. union (
  12. insert
  13. User {
  14. name := x.name,
  15. theme := x.theme,
  16. }
  17. );

Since x is an element of a set it is guaranteed to be a non-empty singleton in all of the expressions used by the union and later clauses of for.

Another variation this usage of for is a bulk update. There are cases when a bulk update involves a lot of external data that cannot be derived from the objects being updated. That is a good use-case when a for statement is appropriate.

  1. # Here's an example of an update that is awkward to
  2. # express without the use of FOR statement
  3. with module example
  4. update User
  5. filter .name in {'Alice', 'Bob', 'Carol', 'Dave'}
  6. set {
  7. theme := 'red' if .name = 'Alice' else
  8. 'star' if .name = 'Bob' else
  9. 'dark' if .name = 'Carol' else
  10. 'strawberry'
  11. };
  12. # Using a FOR statement, the above update becomes simpler to
  13. # express or review for a human.
  14. with module example
  15. for x in {
  16. (name := 'Alice', theme := 'red'),
  17. (name := 'Bob', theme := 'star'),
  18. (name := 'Carol', theme := 'dark'),
  19. (name := 'Dave', theme := 'strawberry')
  20. }
  21. union (
  22. update User
  23. filter .name = x.name
  24. set {
  25. theme := x.theme
  26. }
  27. );

When updating data that mostly or completely depends on the objects being updated there’s no need to use the for statement and it is not advised to use it for performance reasons.

  1. with module example
  2. update User
  3. filter .name in {'Alice', 'Bob', 'Carol', 'Dave'}
  4. set {
  5. theme := 'halloween'
  6. };
  7. # The above can be accomplished with a for statement,
  8. # but it is not recommended.
  9. with module example
  10. for x in {'Alice', 'Bob', 'Carol', 'Dave'}
  11. union (
  12. update User
  13. filter .name = x
  14. set {
  15. theme := 'halloween'
  16. }
  17. );

Another example of using a for statement is working with link properties. Specifying the link properties either at creation time or in a later step with an update is often simpler with a for statement helping to associate the link target to the link property in an intuitive manner.

  1. # Expressing this without for statement is fairly tedious.
  2. with
  3. module example,
  4. U2 := User
  5. for x in {
  6. (
  7. name := 'Alice',
  8. friends := [('Bob', 'coffee buff'),
  9. ('Carol', 'dog person')]
  10. ),
  11. (
  12. name := 'Bob',
  13. friends := [('Alice', 'movie buff'),
  14. ('Dave', 'cat person')]
  15. )
  16. }
  17. union (
  18. update User
  19. filter .name = x.name
  20. set {
  21. friends := assert_distinct(
  22. (
  23. for f in array_unpack(x.friends)
  24. union (
  25. select U2 {@nickname := f.1}
  26. filter U2.name = f.0
  27. )
  28. )
  29. )
  30. }
  31. );

See also

EdgeQL > For