bmg 0.12.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 67347fd77660f79d3e4d4bfa09199881b03e94ae
4
- data.tar.gz: c3f52c0219760d8382738106e78bf997633abf93
3
+ metadata.gz: b7cf04c07c2f88598d086c9eb174c857995a3646
4
+ data.tar.gz: 368fdda422f043d57c7da57f5019b4682e9d37eb
5
5
  SHA512:
6
- metadata.gz: b4e91ccd011024741b24b84d31e6b4e23feda9a9b6e7398cf4ad2f534b05205f1f4fef6003635fe31232d9dfabc8852d81642b76535a046aa1f309132b770a61
7
- data.tar.gz: c9ed01a662aec36ba2b77ca315051d512950fa008c09fd9b3abc8f30dba1d2bb4d881856d0d39919084461141756bbced69afe7a58c365382b34626fc35ec4fe
6
+ metadata.gz: 9ef7574e4dfe6e30619310daf922e16ca20f5721f2d4f339a13fd8077520316215d8306f6b7150a3df5648944163fc5bb9329d40663b6ccf4be1eeba7d26af4c
7
+ data.tar.gz: a5c71d8cfb1b9e52ab360b3deaffc6c9986b7388154b78141256a83b949300b329c433f7a265cf97d6ab1ba7433ebd08f15e0a549fb39f2b02f19cb2d5cd5a7b
data/lib/bmg/algebra.rb CHANGED
@@ -2,6 +2,7 @@ module Bmg
2
2
  module Algebra
3
3
 
4
4
  def allbut(butlist = [])
5
+ return self if butlist.empty?
5
6
  _allbut self.type.allbut(butlist), butlist
6
7
  end
7
8
 
@@ -142,6 +143,7 @@ module Bmg
142
143
  protected :_restrict
143
144
 
144
145
  def union(other, options = {})
146
+ return self if other.is_a?(Relation::Empty)
145
147
  _union self.type.union(other.type), other, options
146
148
  end
147
149
 
@@ -44,6 +44,10 @@ module Bmg
44
44
  Empty.new(type)
45
45
  end
46
46
 
47
+ def _constants(type, cs)
48
+ Empty.new(type)
49
+ end
50
+
47
51
  def _extend(type, *args)
48
52
  Empty.new(type)
49
53
  end
data/lib/bmg/sequel.rb CHANGED
@@ -7,9 +7,13 @@ module Bmg
7
7
 
8
8
  def sequel(*args, &bl)
9
9
  source, sequel_db, type = sequel_params(*args, &bl)
10
- builder = Sql::Builder.new
11
- sexpr = builder.select_all(type.to_attrlist, source)
12
- Sequel::Relation.new(type, builder, sexpr, sequel_db).spied(Bmg.main_spy)
10
+ if type
11
+ builder = Sql::Builder.new
12
+ sexpr = builder.select_all(type.to_attrlist, source)
13
+ Sequel::Relation.new(type, builder, sexpr, sequel_db).spied(Bmg.main_spy)
14
+ else
15
+ Bmg::Relation.new(source)
16
+ end
13
17
  end
14
18
  module_function :sequel
15
19
 
@@ -18,16 +22,15 @@ module Bmg
18
22
  sequel_db = source.db if sequel_db.nil? and source.is_a?(::Sequel::Dataset)
19
23
  raise ArgumentError, "A Sequel::Database object is required" if sequel_db.nil?
20
24
  raise ArgumentError, "Type's attrlist must be known (#{type})" if type && !type.knows_attrlist?
21
- type = infer_type!(sequel_db, source) if type.nil?
25
+ type = infer_type(sequel_db, source) if type.nil?
22
26
  [source, sequel_db, type]
23
27
  end
24
28
  module_function :sequel_params
25
29
 
26
- def infer_type!(sequel_db, source)
27
- raise "Sequel::Relation requires a type for `#{source}`" unless source.is_a?(Symbol)
28
- TypeInference.new(sequel_db).call(source)
30
+ def infer_type(sequel_db, source)
31
+ TypeInference.new(sequel_db).call(source) if source.is_a?(Symbol)
29
32
  end
30
- module_function :infer_type!
33
+ module_function :infer_type
31
34
 
32
35
  end
33
36
 
@@ -28,9 +28,9 @@ module Bmg
28
28
  end
29
29
 
30
30
  def on_set_operator(sexpr)
31
- left, right = apply(sexpr.left), apply(sexpr.right)
32
- left = left.from_self if sexpr.left.set_operator?
33
- left.send(sexpr.first, right, all: sexpr.all?, from_self: false)
31
+ sexpr.tail_exprs.inject(apply(sexpr.head_expr)) do |left,right|
32
+ left.send(sexpr.first, apply(right), all: sexpr.all?, from_self: false)
33
+ end
34
34
  end
35
35
  alias :on_union :on_set_operator
36
36
  alias :on_intersect :on_set_operator
@@ -65,10 +65,13 @@ module Bmg
65
65
  def on_select_item(sexpr)
66
66
  left = apply(sexpr.left)
67
67
  right = apply(sexpr.right)
68
- if left.column == right.value
69
- left
70
- else
68
+ case kind = sexpr.left.first
69
+ when :qualified_name
70
+ left.column == right.value ? left : ::Sequel.as(left, right)
71
+ when :literal
71
72
  ::Sequel.as(left, right)
73
+ else
74
+ raise NotImplementedError, "Unexpected select item `#{kind}`"
72
75
  end
73
76
  end
74
77
 
@@ -85,7 +88,7 @@ module Bmg
85
88
  end
86
89
 
87
90
  def on_table_name(sexpr)
88
- ::Sequel.identifier(sexpr.last)
91
+ ::Sequel.expr(sexpr.last.to_sym)
89
92
  end
90
93
 
91
94
  def on_cross_join(sexpr)
@@ -102,7 +105,7 @@ module Bmg
102
105
  end
103
106
 
104
107
  def on_table_as(sexpr)
105
- ::Sequel.as(::Sequel.identifier(sexpr.table_name), ::Sequel.identifier(sexpr.as_name))
108
+ ::Sequel.as(::Sequel.expr(sexpr.table_name.to_sym), ::Sequel.identifier(sexpr.as_name))
106
109
  end
107
110
 
108
111
  def on_subquery_as(sexpr)
@@ -67,6 +67,13 @@ module Bmg
67
67
  end
68
68
  builder :select_list
69
69
 
70
+ def select_literal_item(literal, as)
71
+ [:select_item,
72
+ literal(literal),
73
+ column_name(as.to_s)]
74
+ end
75
+ builder :select_literal_item
76
+
70
77
  def select_item(qualifier, name, as = name)
71
78
  [:select_item,
72
79
  qualified_name(qualifier, name.to_s),
@@ -158,6 +165,11 @@ module Bmg
158
165
  end
159
166
  builder :offset_clause
160
167
 
168
+ def literal(lit)
169
+ [:literal, lit]
170
+ end
171
+ builder :literal
172
+
161
173
  def from_self(sexpr)
162
174
  Processor::FromSelf.new(self).call(sexpr)
163
175
  end
@@ -14,13 +14,13 @@ rules:
14
14
  - intersect
15
15
  - select_exp
16
16
  union:
17
- - [ all, nonjoin_exp, nonjoin_exp ]
17
+ - [ all, nonjoin_exp+ ]
18
18
  all:
19
19
  - truth_value
20
20
  except:
21
- - [ set_quantifier, nonjoin_exp, nonjoin_exp ]
21
+ - [ set_quantifier, nonjoin_exp+ ]
22
22
  intersect:
23
- - [ set_quantifier, nonjoin_exp, nonjoin_exp ]
23
+ - [ set_quantifier, nonjoin_exp+ ]
24
24
  join_exp:
25
25
  - cross_join
26
26
  - inner_join
@@ -79,8 +79,8 @@ module Bmg
79
79
  find_child(:offset_clause)
80
80
  end
81
81
 
82
- def desaliaser
83
- select_list.desaliaser
82
+ def desaliaser(*args, &bl)
83
+ select_list.desaliaser(*args, &bl)
84
84
  end
85
85
 
86
86
  ### to_xxx
@@ -3,10 +3,19 @@ module Bmg
3
3
  module SelectList
4
4
  include Expr
5
5
 
6
- def desaliaser
6
+ def desaliaser(for_predicate = false)
7
7
  ->(a){
8
8
  item = sexpr_body.find{|item| item.as_name.to_s == a.to_s }
9
- item && item.left
9
+ return nil unless left = item && item.left
10
+ return left unless for_predicate
11
+ case left.first
12
+ when :literal
13
+ Predicate::Grammar.sexpr([:literal, left.last])
14
+ when :qualified_name
15
+ Predicate::Grammar.sexpr([:qualified_identifier, left.qualifier.to_sym, left.as_name.to_sym])
16
+ else
17
+ raise "Unexpected select_item `#{left}`"
18
+ end
10
19
  }
11
20
  end
12
21
 
@@ -5,7 +5,7 @@ module Bmg
5
5
 
6
6
  STAR = "*".freeze
7
7
 
8
- def desaliaser
8
+ def desaliaser(*args, &bl)
9
9
  ->(a){
10
10
  Predicate::Grammar.sexpr [ :qualified_identifier, last[1], a.to_s ]
11
11
  }
@@ -3,12 +3,12 @@ module Bmg
3
3
  module SetOperator
4
4
  include Expr
5
5
 
6
- def left
6
+ def head_expr
7
7
  self[2]
8
8
  end
9
9
 
10
- def right
11
- self[3]
10
+ def tail_exprs
11
+ self[3..-1]
12
12
  end
13
13
 
14
14
  def set_quantifier
@@ -70,6 +70,7 @@ end
70
70
  require_relative 'processor/distinct'
71
71
  require_relative 'processor/all'
72
72
  require_relative 'processor/clip'
73
+ require_relative 'processor/constants'
73
74
  require_relative 'processor/star'
74
75
  require_relative 'processor/rename'
75
76
  require_relative 'processor/order_by'
@@ -0,0 +1,32 @@
1
+ module Bmg
2
+ module Sql
3
+ class Processor
4
+ class Constants < Processor
5
+
6
+ def initialize(constants, builder)
7
+ super(builder)
8
+ @constants = constants
9
+ end
10
+ attr_reader :constants
11
+
12
+ def on_set_operator(sexpr)
13
+ apply(builder.from_self(sexpr))
14
+ end
15
+ alias :on_union :on_set_operator
16
+ alias :on_except :on_set_operator
17
+ alias :on_intersect :on_set_operator
18
+
19
+ def on_select_star(sexpr)
20
+ raise NotImplementedError, "Constants on * is not supported"
21
+ end
22
+
23
+ def on_select_list(sexpr)
24
+ sexpr + constants.each_pair.map{|(k,v)|
25
+ builder.select_literal_item(v, k)
26
+ }
27
+ end
28
+
29
+ end # class Constants
30
+ end # class Processor
31
+ end # module Sql
32
+ end # module Bmg
@@ -13,12 +13,10 @@ module Bmg
13
13
  private
14
14
 
15
15
  def join_predicate(left, right, commons)
16
- left_d, right_d = left.desaliaser, right.desaliaser
16
+ left_d, right_d = left.desaliaser(true), right.desaliaser(true)
17
17
  commons.to_a.inject(tautology){|cond, attr|
18
18
  left_attr, right_attr = left_d[attr], right_d[attr]
19
- left_p = Predicate::Factory.qualified_identifier(left_attr.qualifier, left_attr.as_name)
20
- right_p = Predicate::Factory.qualified_identifier(right_attr.qualifier, right_attr.as_name)
21
- cond &= Predicate::Factory.eq(left_p, right_p)
19
+ cond &= Predicate::Factory.eq(left_attr, right_attr)
22
20
  }
23
21
  end
24
22
 
@@ -23,11 +23,19 @@ module Bmg
23
23
  end
24
24
 
25
25
  def on_nonjoin_exp(sexpr)
26
+ left_attrs = sexpr.to_attr_list.map(&:to_s).sort
27
+ right_attrs = @right.to_attr_list.map(&:to_s).sort
28
+ unless left_attrs == right_attrs
29
+ raise "Operands are not union compatible: #{left_attrs.inspect} vs. #{right_attrs.inspect}"
30
+ end
31
+
26
32
  reordered = Reorder.new(sexpr.to_attr_list, builder).call(@right)
27
33
  if @right.with_exp?
28
34
  [ :with_exp,
29
35
  reordered.with_spec,
30
36
  [ @kind, modifier, sexpr, reordered.select_exp ] ]
37
+ elsif sexpr.first == @kind && sexpr.set_quantifier == modifier
38
+ sexpr.dup + [ reordered ]
31
39
  else
32
40
  [ @kind, modifier, sexpr, reordered ]
33
41
  end
@@ -40,9 +40,8 @@ module Bmg
40
40
  if commons.size == 0
41
41
  builder.exists(subquery)
42
42
  elsif commons.size == 1
43
- identifier = left.desaliaser[commons.to_a.first]
44
- qualified = Predicate::Factory.qualified_identifier(identifier.qualifier, identifier.as_name)
45
- Predicate::Factory.in(qualified, subquery)
43
+ identifier = left.desaliaser(true)[commons.to_a.first]
44
+ Predicate::Factory.in(identifier, subquery)
46
45
  else
47
46
  join_pre = join_predicate(left, subquery, commons)
48
47
  subquery = expand_where_clause(subquery, join_pre)
@@ -8,17 +8,37 @@ module Bmg
8
8
  @predicate = predicate
9
9
  end
10
10
 
11
+ def on_union(sexpr)
12
+ non_falsy = sexpr[2..-1].reject{|expr| falsy?(expr) }
13
+ if non_falsy.empty?
14
+ apply(sexpr.head_expr)
15
+ elsif non_falsy.size == 1
16
+ apply(non_falsy.first)
17
+ else
18
+ [sexpr[0], sexpr[1]] + non_falsy.map{|nf| apply(nf) }
19
+ end
20
+ end
21
+
11
22
  def on_select_exp(sexpr)
12
- pred = @predicate.rename(sexpr.desaliaser).sexpr
23
+ pred = @predicate.rename(sexpr.desaliaser(true))
13
24
  if sexpr.where_clause
14
- anded = [:and, sexpr.where_clause.predicate, pred ]
15
- anded = Predicate::Grammar.sexpr(anded)
16
- sexpr.with_update(:where_clause, [ :where_clause, anded ])
25
+ sexpr_p = Predicate.new(sexpr.where_clause.predicate)
26
+ sexpr.with_update(:where_clause, [ :where_clause, (sexpr_p & pred).sexpr ])
17
27
  else
18
- sexpr.with_insert(4, [ :where_clause, pred ])
28
+ sexpr.with_insert(4, [ :where_clause, pred.sexpr ])
19
29
  end
20
30
  end
21
31
 
32
+ private
33
+
34
+ def falsy?(sexpr)
35
+ return false unless sexpr.respond_to?(:predicate)
36
+ return false if sexpr.predicate.nil?
37
+ left = Predicate.new(Predicate::Grammar.sexpr(sexpr.predicate))
38
+ right = Predicate.new(Predicate::Grammar.sexpr(@predicate.sexpr))
39
+ return (left & right).contradiction?
40
+ end
41
+
22
42
  end # class Where
23
43
  end # class Processor
24
44
  end # module Sql
@@ -44,6 +44,12 @@ module Bmg
44
44
  _instance(type, builder, expr)
45
45
  end
46
46
 
47
+ def _constants(type, cs)
48
+ expr = before_use(self.expr)
49
+ expr = Processor::Constants.new(cs, builder).call(expr)
50
+ _instance(type, builder, expr)
51
+ end
52
+
47
53
  def _join(type, right, on)
48
54
  if right_expr = extract_compatible_sexpr(right)
49
55
  right_expr = Processor::Requalify.new(builder).call(right_expr)
data/lib/bmg/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Bmg
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 12
4
+ MINOR = 13
5
5
  TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bmg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-29 00:00:00.000000000 Z
11
+ date: 2018-05-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: predicate
@@ -66,20 +66,6 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '1.3'
69
- - !ruby/object:Gem::Dependency
70
- name: roo
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '2.7'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '2.7'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: sequel
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -209,6 +195,7 @@ files:
209
195
  - lib/bmg/sql/processor.rb
210
196
  - lib/bmg/sql/processor/all.rb
211
197
  - lib/bmg/sql/processor/clip.rb
198
+ - lib/bmg/sql/processor/constants.rb
212
199
  - lib/bmg/sql/processor/distinct.rb
213
200
  - lib/bmg/sql/processor/flatten.rb
214
201
  - lib/bmg/sql/processor/from_self.rb
@@ -252,7 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
252
239
  version: '0'
253
240
  requirements: []
254
241
  rubyforge_project:
255
- rubygems_version: 2.6.14
242
+ rubygems_version: 2.5.2
256
243
  signing_key:
257
244
  specification_version: 4
258
245
  summary: Bmg is Alf's successor.