Module: Stal

Defined in:
lib/stal.rb

Defined Under Namespace

Classes: InvalidCommand

Constant Summary collapse

COMMANDS =
{
  :SDIFF  => 'SDIFFSTORE',
  :SINTER => 'SINTERSTORE',
  :SUNION => 'SUNIONSTORE',
}

Class Method Summary collapse

Class Method Details

.command(term) ⇒ Object


14
15
16
17
18
# File 'lib/stal.rb', line 14

def self.command(term)
  COMMANDS.fetch(term) do
    raise(InvalidCommand, term)
  end
end

.compile(expr, ids, ops) ⇒ Object

Compile expression into Redis commands


21
22
23
24
25
26
27
28
29
# File 'lib/stal.rb', line 21

def self.compile(expr, ids, ops)
  expr.map do |item|
    if Array === item
      convert(item, ids, ops)
    else
      item
    end
  end
end

.convert(expr, ids, ops) ⇒ Object

Transform :SDIFF, :SINTER and :SUNION commands into SDIFFSTORE, SINTERSTORE and SUNIONSTORE.


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/stal.rb', line 33

def self.convert(expr, ids, ops)
  head, *tail = expr

  # Key where partial results will be stored
  id = sprintf("stal:%s", ids.size)

  # Keep a reference to clean it up later
  ids.push(id)

  # Translate into command and destination key
  op = [command(head), id]

  # Compile the rest recursively
  op.concat(compile(tail, ids, ops))

  # Append the outermost operation
  ops.push(op)

  return id
end

.explain(expr) ⇒ Object

Return commands without any wrapping added by `solve`


55
56
57
58
59
60
61
62
# File 'lib/stal.rb', line 55

def self.explain(expr)
  ids = []
  ops = []

  ops.push(compile(expr, ids, ops))

  return ops
end

.solve(c, expr) ⇒ Object

Evaluate expression `expr` in the Redis client `c`.


65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/stal.rb', line 65

def self.solve(c, expr)
  ids = []
  ops = []

  ops.push(compile(expr, ids, ops))

  if ops.one?
    c.call(*ops[0])
  else
    c.queue("MULTI")

    ops.each do |op|
      c.queue(*op)
    end

    c.queue("DEL", *ids)
    c.queue("EXEC")
    c.commit[-1][-2]
  end
end