bmg 0.12.0 → 0.13.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.
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.