All files / src/elm query.coffee

100% Statements 95/95
90.91% Branches 30/33
100% Functions 28/28
100% Lines 92/92

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 19472x 1x 1x 1x 1x       544x 544x       1x 1x   1x   40x 40x 40x 40x   12x 12x 12x 12x 12x 12x       1x   20x         1x   1x   56x 56x 56x 56x                   1x   73x 73x 73x 73x 73x     67x 67x 67x 67x                 1x   28x 28x             336x 336x       129x         125x 250x   125x 125x     1x 68x 68x 218x 218x 190x     1x   511x 1022x 1022x 511x 511x 511x 511x 511x     86x 86x 640x 3x   640x 12x   320x 320x     205x                 86x 68x         1x   364x 364x         1x   1x         544x 544x 544x 544x   33x     544x   33x             92x 92x 92x 92x 326x 326x          
{ Expression, UnimplementedExpression } = require './expression'
{ Context } = require '../runtime/context'
{ build } = require './builder'
{ typeIsArray , allTrue} = require '../util/util'
{ equals } = require '../util/comparison'
 
module.exports.AliasedQuerySource = class AliasedQuerySource
  constructor: (json) ->
    @alias = json.alias
    @expression = build json.expression
 
module.exports.LetClause = class LetClause
  constructor: (json) ->
    @identifier = json.identifier
    @expression = build json.expression
 
module.exports.With = class With extends Expression
  constructor: (json) ->
    super
    @alias = json.alias
    @expression = build json.expression
    @suchThat = build json.suchThat
  exec: (ctx) ->
    records = @expression.execute(ctx)
    @isList = typeIsArray(records)
    records = if @isList then records else [records]
    returns = for rec in records
      childCtx = ctx.childContext()
      childCtx.set @alias, rec
      @suchThat.execute(childCtx)
    returns.some (x) -> x
 
module.exports.Without = class Without extends With
  constructor: (json) ->
    super
  exec: (ctx) ->
    !super(ctx)
 
# ELM-only, not a product of CQL
module.exports.Sort = class Sort extends UnimplementedExpression
 
module.exports.ByDirection = class ByDirection extends Expression
  constructor: (json) ->
    super
    @direction = json.direction
    @low_order = if @direction == "asc" then -1 else 1
    @high_order = @low_order * -1
 
  exec: (ctx,a,b) ->
    if a == b
      0
    else if a < b
      @low_order
    else
      @high_order
 
module.exports.ByExpression = class ByExpression extends Expression
  constructor: (json) ->
    super
    @expression = build json.expression
    @direction = json.direction
    @low_order = if @direction == "asc" then -1 else 1
    @high_order = @low_order * -1
 
  exec: (ctx,a,b) ->
    sctx = ctx.childContext(a)
    a_val = @expression.execute(sctx)
    sctx = ctx.childContext(b)
    b_val = @expression.execute(sctx)
 
    if a_val == b_val
      0
    else if a_val < b_val
      @low_order
    else
      @high_order
 
module.exports.ByColumn = class ByColumn extends ByExpression
  constructor: (json) ->
    super
    @expression = build {
      "name" : json.path,
      "type" : "IdentifierRef"
    }
 
module.exports.ReturnClause = ReturnClause = class ReturnClause
  constructor:(json) ->
    @expression = build json.expression
    @distinct = json.distinct ? true
 
module.exports.SortClause = SortClause = class SortClause
  constructor:(json) ->
    @by = build json?.by
 
  sort: (ctx, values) ->
    if @by
      values.sort (a,b) =>
        order = 0
        for item in @by
          # Do not use execute here because the value of the sort order is not important.
          order = item.exec(ctx,a,b)
          if order != 0 then break
        order
 
toDistinctList = (xList) ->
  yList = []
  for x in xList
    inYList = false
    inYList = true for y in yList when equals(x, y)
    unless inYList then yList.push x
  yList
 
module.exports.Query = class Query extends Expression
  constructor: (json) ->
    super
    @sources = new MultiSource((new AliasedQuerySource(s) for s in json.source))
    @letClauses = (new LetClause(d) for d in (json.let ? []))
    @relationship = if json.relationship? then build json.relationship else []
    @where = build json.where
    @returnClause = if json.return? then new ReturnClause(json.return) else null
    @aliases = @sources.aliases()
    @sortClause = if json.sort? then new SortClause(json.sort) else null
 
  exec: (ctx) ->
    returnedValues = []
    @sources.forEach(ctx, (rctx) =>
      for def in @letClauses
        rctx.set def.identifier, def.expression.execute(rctx)
 
      relations = for rel in @relationship
        child_ctx = rctx.childContext()
        rel.execute(child_ctx)
      passed = allTrue(relations)
      passed = passed && if @where then @where.execute(rctx) else passed
      if passed
        if @returnClause?
          val = @returnClause.expression.execute(rctx)
          returnedValues.push val
        else
          if @aliases.length == 1
            returnedValues.push rctx.get(@aliases[0])
          else
            returnedValues.push rctx.context_values
    )
 
    distinct = if @returnClause? then @returnClause.distinct else true
    if distinct then returnedValues = toDistinctList(returnedValues)
 
    @sortClause?.sort(ctx, returnedValues)
    return if @sources.returnsList() then returnedValues else returnedValues[0]
 
module.exports.AliasRef = class AliasRef extends Expression
  constructor: (json) ->
    super
    @name = json.name
 
  exec: (ctx) ->
    ctx?.get(@name)
 
module.exports.QueryLetRef = class QueryLetRef extends AliasRef
  constructor: (json) ->
    super
 
# The following is not defined by ELM but is helpful for execution
 
class MultiSource
  constructor: (@sources) ->
    @alias = @sources[0].alias
    @expression = @sources[0].expression
    @isList = true
    if @sources.length > 1
      @rest = new MultiSource(@sources.slice(1))
 
  aliases: ->
    a = [@alias]
    if @rest
      a = a.concat @rest.aliases()
    a
 
  returnsList: ->
    @isList || (@rest && @rest.returnsList())
 
  forEach: (ctx, func) ->
    records = @expression.execute(ctx)
    @isList = typeIsArray(records)
    records = if @isList then records else [records]
    for rec in records
      rctx = new Context(ctx)
      rctx.set(@alias,rec)
      if @rest
        @rest.forEach(rctx,func)
      else
        func(rctx)