bmg 0.15.0 → 0.16.0.pre.rc1

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: 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