alf-sequel 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ # 0.14.0 / 2013-10-01
2
+
3
+ * Added SQL implementation of `page` and `frame`
4
+ * Fix SQL bug on compilation of joins
5
+
1
6
  # 0.13.0 / 2013-07-29
2
7
 
3
8
  The 0.13.0 version is a new birthday for alf. See `alf` main for CHANGELOG
data/Gemfile CHANGED
@@ -1,8 +1,7 @@
1
1
  source 'http://rubygems.org'
2
2
 
3
3
  group :runtime do
4
- #gem "alf-core", :git => "git://github.com/alf-tool/alf-core.git"
5
- gem "alf-core", "~> 0.13.0"
4
+ gem "alf-core", "~> 0.14.0"
6
5
  gem "sequel", "~> 3.48"
7
6
  end
8
7
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- alf-core (0.13.0)
4
+ alf-core (0.14.0)
5
5
  domain (~> 1.0)
6
6
  myrrha (~> 3.0)
7
7
  path (~> 1.3)
@@ -11,7 +11,7 @@ GEM
11
11
  jdbc-sqlite3 (3.7.2.1)
12
12
  myrrha (3.0.0)
13
13
  domain (~> 1.0)
14
- path (1.3.1)
14
+ path (1.3.3)
15
15
  rake (10.1.0)
16
16
  rspec (2.14.1)
17
17
  rspec-core (~> 2.14.0)
@@ -30,7 +30,7 @@ PLATFORMS
30
30
  ruby
31
31
 
32
32
  DEPENDENCIES
33
- alf-core (~> 0.13.0)
33
+ alf-core (~> 0.14.0)
34
34
  jdbc-sqlite3 (~> 3.7)
35
35
  rake (~> 10.1)
36
36
  rspec (~> 2.14)
@@ -3,7 +3,8 @@ module Alf
3
3
  class Cog
4
4
  include Engine::Cog
5
5
 
6
- def initialize(connection, opts)
6
+ def initialize(expr, connection, opts)
7
+ super(expr)
7
8
  @connection = connection
8
9
  @opts = opts
9
10
  end
@@ -24,41 +25,45 @@ module Alf
24
25
 
25
26
  ### Delegation to Dataset, that is, facade over ::Sequel itself
26
27
 
27
- def select(attrs)
28
- branch dataset: dataset.select(*qualify(attrs))
28
+ def select(expr, attrs)
29
+ branch expr, dataset: dataset.select(*qualify(attrs))
29
30
  end
30
31
 
31
- def rename(attrs, opts)
32
- branch dataset: dataset.select(*qualify(attrs)).from_self(opts),
33
- as: opts[:alias]
32
+ def rename(expr, attrs, opts)
33
+ branch expr, dataset: dataset.select(*qualify(attrs)).from_self(opts),
34
+ as: opts[:alias]
34
35
  end
35
36
 
36
- def distinct(*args, &bl)
37
- branch dataset: dataset.distinct(*args, &bl)
37
+ def distinct(expr, *args, &bl)
38
+ branch expr, dataset: dataset.distinct(*args, &bl)
38
39
  end
39
40
 
40
- def order(*args, &bl)
41
- branch dataset: dataset.order(*args, &bl)
41
+ def order(expr, *args, &bl)
42
+ branch expr, dataset: dataset.order(*args, &bl)
42
43
  end
43
44
 
44
- def filter(*args, &bl)
45
- branch dataset: dataset.filter(*args, &bl)
45
+ def filter(expr, *args, &bl)
46
+ branch expr, dataset: dataset.filter(*args, &bl)
46
47
  end
47
48
 
48
- def intersect(other, opts={})
49
- branch dataset: dataset.intersect(other.dataset, opts),
50
- as: opts[:alias]
49
+ def intersect(expr, other, opts={})
50
+ branch expr, dataset: dataset.intersect(other.dataset, opts),
51
+ as: opts[:alias]
51
52
  end
52
53
 
53
- def join(other, cols, opts={})
54
- join = dataset.inner_join(other.dataset, cols, :table_alias => opts[:alias])
55
- branch dataset: join.from_self(opts),
56
- as: opts[:alias]
54
+ def join(expr, other, cols, opts={})
55
+ join = dataset.from_self.inner_join(other.dataset, cols, :table_alias => opts[:alias])
56
+ branch expr, dataset: join.from_self(opts),
57
+ as: opts[:alias]
57
58
  end
58
59
 
59
- def union(other, opts={})
60
- branch dataset: dataset.union(other.dataset, opts),
61
- as: opts[:alias]
60
+ def union(expr, other, opts={})
61
+ branch expr, dataset: dataset.union(other.dataset, opts),
62
+ as: opts[:alias]
63
+ end
64
+
65
+ def limit(expr, *args, &bl)
66
+ branch expr, dataset: dataset.limit(*args, &bl)
62
67
  end
63
68
 
64
69
  ### compilation tools
@@ -79,8 +84,8 @@ module Alf
79
84
  end
80
85
  end
81
86
 
82
- def branch(opts = {})
83
- Cog.new connection, self.opts.merge(opts)
87
+ def branch(expr, opts = {})
88
+ Cog.new expr, connection, self.opts.merge(opts)
84
89
  end
85
90
 
86
91
  def to_s
@@ -14,7 +14,7 @@ module Alf
14
14
 
15
15
  def on_leaf_operand(expr)
16
16
  if Algebra::Operand::Named===expr
17
- expr.connection.cog(expr.name, :alias => next_alias)
17
+ expr.connection.cog(expr.name, expr, :alias => next_alias)
18
18
  else
19
19
  expr.to_cog
20
20
  end
@@ -29,53 +29,61 @@ module Alf
29
29
 
30
30
  def on_clip(expr)
31
31
  rewrite(expr){|rw|
32
- rw.operand.select(expr.stay_attributes)
32
+ rw.operand.select(expr, expr.stay_attributes)
33
33
  }
34
34
  end
35
35
 
36
36
  def on_compact(expr)
37
37
  rewrite(expr){|rw|
38
- rw.operand.distinct
38
+ rw.operand.distinct(expr)
39
39
  }
40
40
  end
41
41
 
42
42
  def on_sort(expr)
43
43
  rewrite(expr){|rw|
44
- operand = rw.operand
45
- ordering = expr.ordering.to_a.map{|(col,dir)|
46
- ::Sequel.send(dir, operand.qualify(col))
47
- }
48
- operand.order(*ordering)
44
+ operand = rw.operand
45
+ ordering = to_sequel_ordering(operand, expr.ordering)
46
+ operand.order(expr, *ordering)
49
47
  }
50
48
  end
51
49
 
52
50
  ### relational
53
51
 
54
52
  alias :on_extend :pass
53
+
54
+ def on_frame(expr)
55
+ rewrite(expr){|rw|
56
+ offset, limit, ordering = expr.offset, expr.limit, expr.total_ordering
57
+ operand = rw.operand
58
+ ordering = to_sequel_ordering(operand, ordering)
59
+ operand.order(expr, *ordering).limit(expr, limit, offset)
60
+ }
61
+ end
62
+
55
63
  alias :on_group :pass
56
64
  alias :on_infer_heading :pass
57
65
 
58
66
  def on_intersect(expr)
59
67
  rewrite(expr){|rw|
60
- rw.left.intersect(rw.right, :alias => next_alias)
68
+ rw.left.intersect(expr, rw.right, {:alias => next_alias})
61
69
  }
62
70
  end
63
71
 
64
72
  def on_join(expr)
65
73
  rewrite(expr){|rw|
66
- rw.left.join(rw.right, expr.common_attributes.to_a, :alias => next_alias)
74
+ rw.left.join(expr, rw.right, expr.common_attributes.to_a, {:alias => next_alias})
67
75
  }
68
76
  end
69
77
 
70
78
  def on_matching(expr)
71
79
  rewrite(expr) do |rw|
72
- rw.left.filter(matching2filter(expr, rw))
80
+ rw.left.filter(expr, matching2filter(expr, rw))
73
81
  end
74
82
  end
75
83
 
76
84
  def on_not_matching(expr)
77
85
  rewrite(expr) do |rw|
78
- rw.left.filter(~matching2filter(expr, rw))
86
+ rw.left.filter(expr, ~matching2filter(expr, rw))
79
87
  end
80
88
  end
81
89
 
@@ -83,7 +91,7 @@ module Alf
83
91
  commons = expr.common_attributes.to_a
84
92
  if commons.size==1
85
93
  # (NOT) IN (SELECT ...)
86
- pred = ::Alf::Predicate.in(commons.first, rw.right.select(commons).dataset)
94
+ pred = ::Alf::Predicate.in(commons.first, rw.right.select(expr, commons).dataset)
87
95
  Predicate.new(:qualifier => rw.left.as).call(pred)
88
96
  elsif commons.size==0
89
97
  # (NOT) EXISTS (SELECT ... no join condition ...)
@@ -92,17 +100,26 @@ module Alf
92
100
  # (NOT) EXISTS (SELECT ...)
93
101
  filter = Hash[rw.left.qualify(commons).zip(rw.right.qualify(commons))]
94
102
  filter = ::Sequel.expr filter
95
- filter = rw.right.filter(filter)
103
+ filter = rw.right.filter(expr, filter)
96
104
  filter.dataset.exists
97
105
  end
98
106
  end
99
107
 
100
108
  alias :on_minus :pass
101
109
 
110
+ def on_page(expr)
111
+ rewrite(expr){|rw|
112
+ index, size, ordering = expr.page_index, expr.page_size, expr.total_ordering
113
+ operand, offset, limit = rw.operand, (index.abs - 1) * size, size
114
+ ordering = to_sequel_ordering(operand, index >= 0 ? ordering : ordering.reverse)
115
+ operand.order(expr, *ordering).limit(expr, offset , limit)
116
+ }
117
+ end
118
+
102
119
  def on_project(expr)
103
120
  rewrite(expr){|rw|
104
- compiled = rw.operand.select(expr.stay_attributes)
105
- compiled = compiled.distinct unless key_preserving?(expr){ false }
121
+ compiled = rw.operand.select(expr, expr.stay_attributes)
122
+ compiled = compiled.distinct(expr) unless key_preserving?(expr){ false }
106
123
  compiled
107
124
  }
108
125
  end
@@ -112,14 +129,14 @@ module Alf
112
129
 
113
130
  def on_rename(expr)
114
131
  rewrite(expr){|rw|
115
- rw.operand.rename(expr.complete_renaming.to_hash, :alias => next_alias)
132
+ rw.operand.rename(expr, expr.complete_renaming.to_hash, :alias => next_alias)
116
133
  }
117
134
  end
118
135
 
119
136
  def on_restrict(expr)
120
137
  rewrite(expr){|rw|
121
138
  filter = Predicate.new(:qualifier => rw.operand.as).call(rw.predicate)
122
- rw.operand.filter(filter)
139
+ rw.operand.filter(expr, filter)
123
140
  }
124
141
  end
125
142
 
@@ -128,7 +145,7 @@ module Alf
128
145
 
129
146
  def on_union(expr)
130
147
  rewrite(expr){|rw|
131
- rw.left.union(rw.right, :alias => next_alias)
148
+ rw.left.union(expr, rw.right, :alias => next_alias)
132
149
  }
133
150
  end
134
151
 
@@ -137,6 +154,13 @@ module Alf
137
154
 
138
155
  private
139
156
 
157
+ def to_sequel_ordering(operand, ordering)
158
+ ordering.to_a.map{|(sel,dir)|
159
+ raise NotSupportedError if sel.composite?
160
+ ::Sequel.send(dir, operand.qualify(sel.outcoerce))
161
+ }
162
+ end
163
+
140
164
  def key_preserving?(expr)
141
165
  expr.key_preserving?
142
166
  rescue NotSupportedError
@@ -146,12 +170,29 @@ module Alf
146
170
  private
147
171
 
148
172
  def rewrite(expr)
149
- rewrited = copy_and_apply(expr)
150
- if block_given? and rewrited.operands.all?{|op| recognized?(op) }
151
- catch(:pass){ rewrited = yield(rewrited) }
173
+ # copy and apply on expr. the result is the same expression, but
174
+ # with cogs instead of operands
175
+ rewritten = copy_and_apply(expr)
176
+
177
+ # Continue compilation process provided all operands are recognized.
178
+ if block_given? and rewritten.operands.all?{|op| recognized?(op) }
179
+ # Compilation of predicates may throw a pass
180
+ catch(:pass){
181
+ rewritten = yield(rewritten)
182
+ }
183
+ end
184
+
185
+ # If the result is itself recognized, proceed
186
+ # Otherwise, give a change to the upper-stage compiler with a proxy
187
+ if recognized?(rewritten)
188
+ rewritten
189
+ else
190
+ operands = rewritten.operands.map{|op|
191
+ Algebra::Operand::Proxy.new(op)
192
+ }
193
+ rewritten = rewritten.with_operands(*operands)
194
+ engine.call(rewritten)
152
195
  end
153
- rewrited = engine.call(rewrited) unless recognized?(rewrited)
154
- rewrited
155
196
  end
156
197
 
157
198
  def recognized?(op)
@@ -11,11 +11,11 @@ module Alf
11
11
  sequel_db[name]
12
12
  end
13
13
 
14
- def cog(name, opts={})
14
+ def cog(name, expr = nil, opts = {})
15
15
  if as = opts[:alias]
16
- Cog.new(self, dataset: dataset(:"#{name}___#{as}"), as: as)
16
+ Cog.new(expr, self, dataset: dataset(:"#{name}___#{as}"), as: as)
17
17
  else
18
- Cog.new(self, dataset: dataset(name))
18
+ Cog.new(expr, self, dataset: dataset(name))
19
19
  end
20
20
  end
21
21
 
@@ -40,8 +40,8 @@ module Alf
40
40
  else
41
41
  filter = mr.tuple_extract.to_hash
42
42
  tuples = connection.cog(@relvar_name)
43
- .filter(filter)
44
- .select(pkey.to_a)
43
+ .filter(nil, filter)
44
+ .select(nil, pkey.to_a)
45
45
  Relation(tuples)
46
46
  end
47
47
  end
@@ -3,7 +3,7 @@ module Alf
3
3
  module Version
4
4
 
5
5
  MAJOR = 0
6
- MINOR = 13
6
+ MINOR = 14
7
7
  TINY = 0
8
8
 
9
9
  def self.to_s
@@ -0,0 +1,89 @@
1
+ require 'compiler_helper'
2
+ module Alf
3
+ module Sequel
4
+ describe Compiler, "frame" do
5
+
6
+ subject{ compile(expr) }
7
+
8
+ let(:expr){
9
+ frame(operand, ordering, offset, limit)
10
+ }
11
+
12
+ context 'when fully compilable' do
13
+ let(:operand){ suppliers }
14
+
15
+ [
16
+ [ [[:name, :asc]], 0, 8, "SELECT * FROM `suppliers` AS 't1' ORDER BY `t1`.`name` ASC LIMIT 8 OFFSET 0" ],
17
+ [ [[:name, :asc]], 2, 8, "SELECT * FROM `suppliers` AS 't1' ORDER BY `t1`.`name` ASC LIMIT 8 OFFSET 2" ],
18
+ [ [[:city, :asc]], 0, 8, "SELECT * FROM `suppliers` AS 't1' ORDER BY `t1`.`city` ASC, `t1`.`sid` ASC LIMIT 8 OFFSET 0" ],
19
+ [ [[:city, :desc]], 2, 8, "SELECT * FROM `suppliers` AS 't1' ORDER BY `t1`.`city` DESC, `t1`.`sid` ASC LIMIT 8 OFFSET 2" ],
20
+ ].each do |(ordering,offset,limit,expected)|
21
+
22
+ context "frame(#{ordering}, #{offset}, #{limit})" do
23
+ let(:ordering){ ordering }
24
+ let(:offset) { offset }
25
+ let(:limit) { limit }
26
+
27
+ it 'should compile as expected' do
28
+ subject.sql.should eq(expected)
29
+ end
30
+ end
31
+
32
+ end
33
+ end # fully compilable
34
+
35
+ context 'when immediately uncompilable yet known keys' do
36
+ let(:operand){
37
+ Algebra::Operand::Fake.new.with_keys([:sid], [:name])
38
+ }
39
+
40
+ [
41
+ [ [[:name, :asc]], 2, 8, [[:name, :asc]] ],
42
+ [ [[:city, :asc]], 2, 8, [[:city, :asc], [:sid, :asc]] ]
43
+ ].each do |ordering, offset, limit, expected|
44
+
45
+ context "frame(#{ordering}, #{offset}, #{limit})" do
46
+ let(:ordering){ ordering }
47
+ let(:offset) { offset }
48
+ let(:limit) { limit }
49
+
50
+ it{ should be_a(Engine::Take) }
51
+
52
+ it 'should have sort with good ordering' do
53
+ subject.operand.should be_a(Engine::Sort)
54
+ subject.operand.ordering.should eq(Ordering.new(expected))
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+
61
+ context 'when immediately uncompilable yet unknown keys' do
62
+ let(:operand){
63
+ Algebra::Operand::Fake.new
64
+ }
65
+
66
+ [
67
+ [ [[:name, :asc]], 2, 8, [[:name, :asc]] ],
68
+ [ [[:city, :asc]], 2, 8, [[:city, :asc]] ]
69
+ ].each do |ordering, offset, limit, expected|
70
+
71
+ context "frame(#{ordering}, #{offset}, #{limit})" do
72
+ let(:ordering){ ordering }
73
+ let(:offset) { offset }
74
+ let(:limit) { limit }
75
+
76
+ it{ should be_a(Engine::Take) }
77
+
78
+ it 'should have sort with good ordering' do
79
+ subject.operand.should be_a(Engine::Sort)
80
+ subject.operand.ordering.should eq(Ordering.new(expected))
81
+ end
82
+ end
83
+
84
+ end
85
+ end
86
+
87
+ end
88
+ end
89
+ end
@@ -9,7 +9,15 @@ module Alf
9
9
  let(:expr){ join(suppliers, supplies) }
10
10
 
11
11
  specify do
12
- subject.sql.should eq("SELECT * FROM (SELECT * FROM `suppliers` AS 't1' INNER JOIN (SELECT * FROM `supplies` AS 't2') AS 't3' USING (`sid`)) AS 't3'")
12
+ subject.sql.should eq("SELECT * FROM (SELECT * FROM (SELECT * FROM `suppliers` AS 't1') AS 't1' INNER JOIN (SELECT * FROM `supplies` AS 't2') AS 't3' USING (`sid`)) AS 't3'")
13
+ end
14
+ end
15
+
16
+ context 'when the left operand is a projection' do
17
+ let(:expr){ join(project(suppliers, [:sid]), supplies) }
18
+
19
+ specify do
20
+ subject.sql.should eq("SELECT * FROM (SELECT * FROM (SELECT `t1`.`sid` FROM `suppliers` AS 't1') AS 't1' INNER JOIN (SELECT * FROM `supplies` AS 't2') AS 't3' USING (`sid`)) AS 't3'")
13
21
  end
14
22
  end
15
23
 
@@ -9,7 +9,7 @@ module Alf
9
9
  let(:expr){ matching(suppliers, project(supplies, [:part_id])) }
10
10
 
11
11
  specify do
12
- subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE (EXISTS (SELECT `t2`.`part_id` FROM `supplies` AS 't2'))")
12
+ subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE (EXISTS (SELECT DISTINCT `t2`.`part_id` FROM `supplies` AS 't2'))")
13
13
  end
14
14
  end
15
15
 
@@ -9,7 +9,7 @@ module Alf
9
9
  let(:expr){ not_matching(suppliers, project(supplies, [:part_id])) }
10
10
 
11
11
  specify do
12
- subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE NOT (EXISTS (SELECT `t2`.`part_id` FROM `supplies` AS 't2'))")
12
+ subject.sql.should eq("SELECT * FROM `suppliers` AS 't1' WHERE NOT (EXISTS (SELECT DISTINCT `t2`.`part_id` FROM `supplies` AS 't2'))")
13
13
  end
14
14
  end
15
15
 
@@ -0,0 +1,86 @@
1
+ require 'compiler_helper'
2
+ module Alf
3
+ module Sequel
4
+ describe Compiler, "page" do
5
+
6
+ subject{ compile(expr) }
7
+
8
+ let(:expr){
9
+ page(operand, ordering, page_index, page_size: 8)
10
+ }
11
+
12
+ context 'when fully compilable' do
13
+ let(:operand){ suppliers }
14
+
15
+ [
16
+ [ [[:name, :asc]], 2, "SELECT * FROM `suppliers` AS 't1' ORDER BY `t1`.`name` ASC LIMIT 8 OFFSET 8" ],
17
+ [ [[:name, :asc]], -2, "SELECT * FROM `suppliers` AS 't1' ORDER BY `t1`.`name` DESC LIMIT 8 OFFSET 8" ],
18
+ [ [[:city, :asc]], 2, "SELECT * FROM `suppliers` AS 't1' ORDER BY `t1`.`city` ASC, `t1`.`sid` ASC LIMIT 8 OFFSET 8" ],
19
+ [ [[:city, :asc]], -2, "SELECT * FROM `suppliers` AS 't1' ORDER BY `t1`.`city` DESC, `t1`.`sid` DESC LIMIT 8 OFFSET 8" ],
20
+ ].each do |(ordering,page_index,expected)|
21
+
22
+ context "page(#{ordering}, #{page_index})" do
23
+ let(:ordering) { ordering }
24
+ let(:page_index){ page_index }
25
+
26
+ it 'should compile as expected' do
27
+ subject.sql.should eq(expected)
28
+ end
29
+ end
30
+
31
+ end
32
+ end # fully compilable
33
+
34
+ context 'when immediately uncompilable yet known keys' do
35
+ let(:operand){
36
+ Algebra::Operand::Fake.new.with_keys([:sid], [:name])
37
+ }
38
+
39
+ [
40
+ [ [[:name, :asc]], 2, [[:name, :asc]] ],
41
+ [ [[:city, :asc]], 2, [[:city, :asc], [:sid, :asc]] ]
42
+ ].each do |ordering, page_index, expected|
43
+
44
+ context "page(#{ordering}, #{page_index})" do
45
+ let(:ordering) { ordering }
46
+ let(:page_index){ page_index }
47
+
48
+ it{ should be_a(Engine::Take) }
49
+
50
+ it 'should have sort with good ordering' do
51
+ subject.operand.should be_a(Engine::Sort)
52
+ subject.operand.ordering.should eq(Ordering.new(expected))
53
+ end
54
+ end
55
+
56
+ end
57
+ end
58
+
59
+ context 'when immediately uncompilable yet unknown keys' do
60
+ let(:operand){
61
+ Algebra::Operand::Fake.new
62
+ }
63
+
64
+ [
65
+ [ [[:name, :asc]], 2, [[:name, :asc]] ],
66
+ [ [[:city, :asc]], 2, [[:city, :asc]] ]
67
+ ].each do |ordering, page_index, expected|
68
+
69
+ context "page(#{ordering}, #{page_index})" do
70
+ let(:ordering) { ordering }
71
+ let(:page_index){ page_index }
72
+
73
+ it{ should be_a(Engine::Take) }
74
+
75
+ it 'should have sort with good ordering' do
76
+ subject.operand.should be_a(Engine::Sort)
77
+ subject.operand.ordering.should eq(Ordering.new(expected))
78
+ end
79
+ end
80
+
81
+ end
82
+ end
83
+
84
+ end
85
+ end
86
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alf-sequel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.14.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-29 00:00:00.000000000 Z
12
+ date: 2013-10-01 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -50,7 +50,7 @@ dependencies:
50
50
  requirements:
51
51
  - - ~>
52
52
  - !ruby/object:Gem::Version
53
- version: 0.13.0
53
+ version: 0.14.0
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,7 +58,7 @@ dependencies:
58
58
  requirements:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
- version: 0.13.0
61
+ version: 0.14.0
62
62
  - !ruby/object:Gem::Dependency
63
63
  name: sequel
64
64
  requirement: !ruby/object:Gem::Requirement
@@ -111,11 +111,13 @@ files:
111
111
  - spec/compiler/test_clip.rb
112
112
  - spec/compiler/test_compact.rb
113
113
  - spec/compiler/test_extend.rb
114
+ - spec/compiler/test_frame.rb
114
115
  - spec/compiler/test_intersect.rb
115
116
  - spec/compiler/test_join.rb
116
117
  - spec/compiler/test_leaf_operand.rb
117
118
  - spec/compiler/test_matching.rb
118
119
  - spec/compiler/test_not_matching.rb
120
+ - spec/compiler/test_page.rb
119
121
  - spec/compiler/test_predicate.rb
120
122
  - spec/compiler/test_project.rb
121
123
  - spec/compiler/test_rename.rb
@@ -158,7 +160,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
158
160
  version: '0'
159
161
  segments:
160
162
  - 0
161
- hash: 2828513476823415639
163
+ hash: 3191817765128165623
162
164
  required_rubygems_version: !ruby/object:Gem::Requirement
163
165
  none: false
164
166
  requirements: