Skip to content
Search

    Expression Notation (CXN)

    Expressions in CDS definitions and queries can be one of:

    expr = // one of...
      val    |   // [literal values]: #literal-values
      ref    |   // references or functions
      xpr    |   // operator expressions
      func   |   // function calls
      list   |   // lists/tupels
      param  |   // binding parameters
      sym    |   // enum symbol
      SELECT     // subqueries
    

    Literal Values

    Literal values are represented as {val:...} with property val holding the actual literal value as specified in JSON.

    val = {val:literal}
    literal = string | number | true | false | null
    

    Examples:

    cds.parse.expr(`'a string'`)  == {val:'a string'}
    cds.parse.expr(`11`)  == {val:11}
    cds.parse.expr(`true`)  == {val:true}
    cds.parse.expr(`null`)  == {val:null}
    

    References

    A reference is represented as {ref:...} with property ref holding an array of reference segments as plain identifier strings, or in case of infix filters and/or arguments an object {id:identifier, ...} as follows:

    ref = {ref:[..._segment]}
    _segment = string | { id:string, args:_named, where:_xpr }
    _named = { ... <name>:expr }
    

    Examples:

    let cqn4 = cds.parse.expr
    cqn4(`![keyword]`) == {ref:['keyword']}
    cqn4(`foo.bar`) == {ref:['foo','bar']}
    cqn4(`foo[9].bar`) == {ref:[{ id:'foo', where:[{val:9}] }, 'bar' ]}
    cqn4(`foo(p:x).bar`) == {ref:[{ id:'foo', args:{p:{ref:['x']}} }, 'bar' ]}
    

    Function Calls

    Function calls are represented as follows:

    func = { func:string, args: _positional | _named, xpr:_xpr }
    _positional = [ ...expr ]
    _named = { ... <name>:expr }
    

    The optional attribute xpr is used for the over clause of SQL window functions.

    Examples:

    let cqn4 = cds.parse.expr
    cqn4(`foo(p=>x)`) == {func:'foo', args:{p:{ref:['x']}}}
    cqn4(`sum(x)`)   == {func:'sum', args:[{ref:['x']}]}
    cqn4(`count(*)`) == {func:'count', args:['*']}
    cqn4(`rank() over (...)`) == {func:'rank', args:[], xpr:['over', {xpr:[...]}]}
    

    Method style function calls and instantiation syntax for spatial functions are represented as {xpr:...} with . and new as operators:

    cqn4(`shape.ST_Area()`)
      == {xpr: [{ref: ['shape']}, '.', {func: 'ST_Area', 'args': []}]}
    cqn4(`new ST_Point(2, 3)`)
      == {xpr: ['new', {func: 'ST_Point', args: [{val: 2}, {val: 3}]}]}
    

    Lists

    Lists or tupels are represented as {list:...}, with property list holding an array of the list entries.

    Examples:

    cds.parse.expr(`(1, 2, 3)`) == {list: [{val: 1}, {val: 2}, {val: 3}]}
    cds.parse.expr(`(foo, bar)`) == {list: [{ref: ['foo']}, {ref: ['bar']}]}
    

    Operator Expressions

    Operators join one or more expressions into complex ones, represented as {xpr:...}. The property xpr holds a sequence of operators and operands.

    xpr = {xpr:_xpr}
    _xpr = [...( _operand | _operator )]
    _operand = expr
    _operator = string
    
    • Operands can be any kind of expression
    • Operators are represented as plain strings, like '=' or 'and'
    • Parentheses ( ... ) around sub-expressions are represented as nested xpr

    Examples:

    cds.parse.expr(`x<9`)  ==//> returns:
    {xpr:[ {ref:['x']}, '<', {val:9} ]}
    
    cds.parse.expr(`x<9 and (y=1 or z=2)`)  ==//> returns:
    {xpr:[
      {ref:['x']}, '<', {val:9}, 'and', {xpr:[
        {ref:['y']}, '=', {val:1}, 'or', {ref:['z']}, '=', {val:2}
      ]}
    ]}
    
    cds.parse.expr(`exists books[year = 2000]`)  ==//> returns:
    {xpr:[
      'exists',
      {ref: [ {id:'books', where:[ {'ref':['year']}, '=', {'val': 2000} ]}]}
    ]}
    

    CQN intentionally doesn’t aim to understand the individual operators and related expressions. It captures them as arbitrary sequences, in the same lexical structure and order they’re written in the source. This ‘ignorance’ allows us to stay open to any kind of operators and keywords. For example, we can easily express native extensions of underlying database dialects.

    As an exception to that rule, CDS supports the ternary conditional operator on source level, but immediately converts it to the corresponding CASE expression in CXN:

    cds.parse.expr(`x<10 ? y : z`)  ==//> returns:
    {xpr:['case', 'when', {ref:['x']}, '<', {val:10},
          'then', {ref:['y']}, 'else', {ref:['z']}, 'end']}
    

    Binding Parameters

    Binding parameters for prepared statements are represented as {ref:..., param:true} with values for ref as follows.

    param = { ref:[ '?' | number | name ], param:true }
    

    Examples:

    cds.parse.expr(`x=:1`) == [{ref:['x']}, '=', {ref:[1], param:true}]
    cds.parse.expr(`x=:y`) == [{ref:['x']}, '=', {ref:['y'], param:true}]
    cds.parse.expr(`x=?`)  == [{ref:['x']}, '=', {ref:['?'], param:true}]
    

    Sub Queries → see CQN