bmg 0.15.0 → 0.16.0.pre.rc1

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: 9962e2754e1fc6f09c4f041e49ca8aa3d37281dd
4
- data.tar.gz: 2533b9118e9cd1a5e5f79cabeb2570823b5c1c20
3
+ metadata.gz: d34f68bbc40a7dd25495cc9964074e20567c8d66
4
+ data.tar.gz: 9f6beb3a44b9da0a89e1bf523e9b02543e0ea136
5
5
  SHA512:
6
- metadata.gz: '097cf9919f5cdef7d1475be3006410796025fa1ac93e009011531816d55d5c6366eeb00bdebdeeb53bf02a1224286d5fb83a46d0fe3985d39d518ab93f50b86d'
7
- data.tar.gz: b8a2d75c371e620ca9784decaacf872c687748ca2c6d19dafbd19eccde242c7c1cafa8d8d4053e60faa7cad0cc9e988edf2144ead579257af50742330813f868
6
+ metadata.gz: cd37f8ad39cd7c05e7a725dfb305b8f8a3d74364d5abab1771f4a598c70d1b643b0b7046907f15fba7788645bfab5e302a4f48285b8ae1f6a7f3b7994a6f727b
7
+ data.tar.gz: ecd95510bde8bc27ed111a917a3e38add365db53faaf62df6f21d2ea2703f8e6d60ffb8428819af31862971cda7fa99112efbe04a610b61d590db1d8dca5c3ef
@@ -38,7 +38,7 @@ module Bmg
38
38
 
39
39
  def on_select_exp(sexpr)
40
40
  dataset = sequel_db.select(1)
41
- dataset = dataset(apply(sexpr.from_clause)) if sexpr.from_clause
41
+ dataset = apply(sexpr.from_clause) if sexpr.from_clause
42
42
  #
43
43
  selection = apply(sexpr.select_list)
44
44
  predicate = apply(sexpr.predicate) if sexpr.predicate
@@ -84,24 +84,28 @@ module Bmg
84
84
  end
85
85
 
86
86
  def on_from_clause(sexpr)
87
- apply(sexpr.table_spec)
87
+ orderer = Sql::Support::FromClauseOrderer.new
88
+ ordering = orderer.call(sexpr)
89
+ ordering.inject(nil) do |ds,(kind,table,on)|
90
+ if ds.nil?
91
+ dataset(apply(table))
92
+ elsif kind == :cross_join
93
+ ds.cross_join(apply(table))
94
+ elsif kind == :inner_join
95
+ options = { qualify: false, table_alias: false }
96
+ ds.join_table(:inner, apply(table), nil, options){|*args|
97
+ apply(on)
98
+ }
99
+ end
100
+ end
88
101
  end
89
102
 
90
103
  def on_table_name(sexpr)
91
104
  ::Sequel.expr(sexpr.last.to_sym)
92
105
  end
93
106
 
94
- def on_cross_join(sexpr)
95
- left, right = apply(sexpr.left), apply(sexpr.right)
96
- dataset(left).cross_join(right)
97
- end
98
-
99
- def on_inner_join(sexpr)
100
- left, right = apply(sexpr.left), apply(sexpr.right)
101
- options = {qualify: false, table_alias: false}
102
- dataset(left).join_table(:inner, right, nil, options){|*args|
103
- apply(sexpr.predicate)
104
- }
107
+ def on_native_table_as(sexpr)
108
+ sexpr[1].from_self(:alias => sexpr.as_name)
105
109
  end
106
110
 
107
111
  def on_table_as(sexpr)
@@ -112,10 +116,6 @@ module Bmg
112
116
  ::Sequel.as(apply(sexpr.subquery), ::Sequel.identifier(sexpr.as_name))
113
117
  end
114
118
 
115
- def on_native_table_as(sexpr)
116
- sexpr[1].from_self(:alias => sexpr.as_name)
117
- end
118
-
119
119
  def on_order_by_clause(sexpr)
120
120
  sexpr.sexpr_body.map{|c| apply(c)}
121
121
  end
data/lib/bmg/sql.rb CHANGED
@@ -18,3 +18,4 @@ require_relative 'sql/processor'
18
18
  require_relative 'sql/builder'
19
19
  require_relative 'sql/dialect'
20
20
  require_relative 'sql/relation'
21
+ require_relative 'sql/support/from_clause_orderer'
@@ -14,7 +14,7 @@ module Bmg
14
14
  def call(sexpr)
15
15
  if unjoinable?(sexpr)
16
16
  call(builder.from_self(sexpr))
17
- elsif unjoinable?(right) or right.join?
17
+ elsif unjoinable?(right)
18
18
  Join.new(builder.from_self(right), on, builder).call(sexpr)
19
19
  else
20
20
  super(sexpr)
@@ -0,0 +1,120 @@
1
+ module Bmg
2
+ module Sql
3
+ module Support
4
+ class FromClauseOrderer
5
+
6
+ # Takes a from_clause AST as input and generates an relationally
7
+ # equivalent list of (type,table,predicate) triplets, where:
8
+ #
9
+ # - type is :base, :cross_join or :inner_join
10
+ # - table is table_as, native_table_as or subquery_as
11
+ # - predicate is a join predicate
12
+ #
13
+ # The types are observed in strict increasing order
14
+ # (one :base, zero or more :cross_join, zero or more
15
+ # :inner_join). The list is such that it can be safely
16
+ # written as an expression of the following SQL form:
17
+ #
18
+ # t1 # [ :base, t1, nil ]
19
+ # cross_join t2 # [ :cross_join, t2, nil ]
20
+ # cross_join t3 # [ :cross_join, t3, nil ]
21
+ # inner_join t4 ON p4 # [ :inner_join, t4, p4 ]
22
+ # inner_join t5 ON p5 # [ :inner_join, t5, p5 ]
23
+ #
24
+ # A NotImplementedError may be raised if no linearization can
25
+ # be found.
26
+ #
27
+ def call(sexpr)
28
+ tables, joins = collect(sexpr)
29
+ order_all(tables, joins)
30
+ end
31
+
32
+ protected
33
+
34
+ def order_all(tables, joins, result = [])
35
+ if tables.empty? and joins.empty?
36
+ result
37
+ elsif tables.empty?
38
+ raise NotImplementedError, "Orphan joins: `#{joins.inspect}`"
39
+ else
40
+ table, tables_tail = tables.first, tables[1..-1]
41
+ on, joins_tail = split_joins(joins, table, tables_tail)
42
+ join_kind = result.empty? ? :base : (on.empty? ? :cross_join : :inner_join)
43
+ predicate = on.inject(nil){|p,clause|
44
+ p.nil? ? clause : Predicate::Factory.and(p, clause)
45
+ }
46
+ clause = [ join_kind, table, predicate ]
47
+ order_all(tables_tail, joins_tail, result + [clause])
48
+ end
49
+ end
50
+
51
+ def split_joins(joins, table, tables_tail)
52
+ joins.partition{|j|
53
+ uses?(j, table) && !tables_tail.find{|t|
54
+ uses?(j, t)
55
+ }
56
+ }
57
+ end
58
+
59
+ protected
60
+
61
+ def collect(sexpr)
62
+ tables = []
63
+ joins = []
64
+ _collect(sexpr, tables, joins)
65
+ tables.sort!{|t1,t2|
66
+ t1js = joins.select{|j| uses?(j, t1) }.size
67
+ t2js = joins.select{|j| uses?(j, t2) }.size
68
+ t1js == 0 ? (t2js == 0 ? 0 : -1) : (t2js == 0 ? 1 : 0)
69
+ }
70
+ [ tables, joins ]
71
+ end
72
+
73
+ def _collect(sexpr, tables, joins)
74
+ case sexpr.first
75
+ when :from_clause
76
+ _collect(sexpr.table_spec, tables, joins)
77
+ when :table_as, :native_table_as, :subquery_as
78
+ tables << sexpr
79
+ when :inner_join
80
+ _collect_joins(sexpr.predicate, joins)
81
+ _collect(sexpr.left, tables, joins)
82
+ _collect(sexpr.right, tables, joins)
83
+ when :cross_join
84
+ _collect(sexpr.left, tables, joins)
85
+ _collect(sexpr.right, tables, joins)
86
+ end
87
+ end
88
+
89
+ def _collect_joins(sexpr, joins)
90
+ case sexpr.first
91
+ when :and
92
+ _collect_joins(sexpr[1], joins)
93
+ _collect_joins(sexpr[2], joins)
94
+ when :eq
95
+ joins << sexpr
96
+ else
97
+ raise NotImplementedError, "Unexpected predicate `#{sexpr.inspect}`"
98
+ end
99
+ end
100
+
101
+ def uses?(join, table)
102
+ name = table.as_name.to_s
103
+ left_name = var_name(join[1])
104
+ right_name = var_name(join[2])
105
+ (left_name == name) or (right_name == name)
106
+ end
107
+
108
+ def var_name(qualified)
109
+ case qualified.first
110
+ when :qualified_identifier then qualified[1].to_s
111
+ when :qualified_name then qualified[1][1].to_s
112
+ else
113
+ raise NotImplementedError, "Unexpected qualified name `#{qualified.inspect}`"
114
+ end
115
+ end
116
+
117
+ end # class FromClauseOrderer
118
+ end # module Support
119
+ end # module Sql
120
+ end # module Bmg
data/lib/bmg/version.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  module Bmg
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 15
5
- TINY = 0
4
+ MINOR = 16
5
+ TINY = "0-rc1"
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
8
8
  end
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.15.0
4
+ version: 0.16.0.pre.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-30 00:00:00.000000000 Z
11
+ date: 2019-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: predicate
@@ -213,6 +213,7 @@ files:
213
213
  - lib/bmg/sql/processor/star.rb
214
214
  - lib/bmg/sql/processor/where.rb
215
215
  - lib/bmg/sql/relation.rb
216
+ - lib/bmg/sql/support/from_clause_orderer.rb
216
217
  - lib/bmg/sql/version.rb
217
218
  - lib/bmg/support.rb
218
219
  - lib/bmg/support/keys.rb
@@ -236,9 +237,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
236
237
  version: '0'
237
238
  required_rubygems_version: !ruby/object:Gem::Requirement
238
239
  requirements:
239
- - - ">="
240
+ - - ">"
240
241
  - !ruby/object:Gem::Version
241
- version: '0'
242
+ version: 1.3.1
242
243
  requirements: []
243
244
  rubyforge_project:
244
245
  rubygems_version: 2.5.2