bmg 0.5.0 → 0.6.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: 381472a4bb34f2a614c0520261508fb2c6ff6032
4
- data.tar.gz: 562ca2c457720e0b7a12a5e9b9ccd33e1609b778
3
+ metadata.gz: 8485745f67f9a5f3b481e8f8121e57c30f404661
4
+ data.tar.gz: 010a318d9896ae6514c96798230ab564540c788d
5
5
  SHA512:
6
- metadata.gz: 195468c7f66d2aa11d49678effe9dc5122e67aec2fbe3161549f6a351835a11f8957aaca4004143bc00256c121d4638c68d466f6267623d35ac5288855e5d7df
7
- data.tar.gz: 1590b7723bec6a826e88a0eef3e1e659c80c355f41de3d61c5d31d4a6c872398f6698290ac464ea795e8bd67e1e5a4eebaaa4052468e61933a6a36b79df81db7
6
+ metadata.gz: 5aae26e7caca19cf4ae627cde3eb8de7278b48f881d40b6ff72fcb7f67ff9f571246e5bc8220e4576b2e8f25cddfb4ae1cd92f7670fe856d9ef6399b3c0a679b
7
+ data.tar.gz: ff68734d5b561543224dc66c5731f0f89cd9456a3ff94891ce207f18799ceef5d27150b6c848301c0987f7a7a02488d0c9e270a47d01f60689744efc03393a47
data/Gemfile CHANGED
@@ -1,4 +1,2 @@
1
1
  source "https://rubygems.org"
2
2
  gemspec
3
-
4
- gem 'predicate', path: '../predicate'
data/lib/bmg.rb CHANGED
@@ -2,23 +2,45 @@ require 'path'
2
2
  require 'predicate'
3
3
  module Bmg
4
4
 
5
- def csv(path, options = {})
6
- Relation.new Reader::Csv.new path, options
5
+ def in_memory(enumerable, type = Type::ANY)
6
+ Relation::InMemory.new(type, enumerable).spied(main_spy)
7
+ end
8
+ module_function :in_memory
9
+
10
+ def csv(path, options = {}, type = Type::ANY)
11
+ Reader::Csv.new(type, path, options).spied(main_spy)
7
12
  end
8
13
  module_function :csv
9
14
 
10
- def excel(path, options = {})
11
- Relation.new Reader::Excel.new path, options
15
+ def excel(path, options = {}, type = Type::ANY)
16
+ Reader::Excel.new(type, path, options).spied(main_spy)
12
17
  end
13
18
  module_function :excel
14
19
 
20
+ def main_spy
21
+ @main_spy
22
+ end
23
+ module_function :main_spy
24
+
25
+ def main_spy=(spy)
26
+ @main_spy = spy
27
+ end
28
+ module_function :main_spy=
29
+
30
+ require_relative 'bmg/version'
31
+ require_relative 'bmg/error'
32
+ require_relative 'bmg/support'
33
+ require_relative 'bmg/algebra'
34
+ require_relative 'bmg/type'
35
+ require_relative 'bmg/relation'
36
+ require_relative 'bmg/operator'
37
+
38
+ require_relative 'bmg/reader'
39
+
40
+ require_relative 'bmg/relation/empty'
41
+ require_relative 'bmg/relation/in_memory'
42
+ require_relative 'bmg/relation/spied'
43
+
44
+ # Deprecated
45
+ Leaf = Relation::InMemory
15
46
  end
16
- require_relative 'bmg/version'
17
- require_relative 'bmg/error'
18
- require_relative 'bmg/support'
19
- require_relative 'bmg/algebra'
20
- require_relative 'bmg/type'
21
- require_relative 'bmg/relation'
22
- require_relative 'bmg/leaf'
23
- require_relative 'bmg/operator'
24
- require_relative 'bmg/reader'
@@ -1,6 +1,19 @@
1
1
  module Bmg
2
2
  module Algebra
3
3
 
4
+ METHODS = [
5
+ :allbut,
6
+ :autowrap,
7
+ :autosummarize,
8
+ :constants,
9
+ :extend,
10
+ :image,
11
+ :project,
12
+ :rename,
13
+ :restrict,
14
+ :union
15
+ ]
16
+
4
17
  def allbut(butlist = [])
5
18
  _allbut self.type.allbut(butlist), butlist
6
19
  end
@@ -82,7 +95,11 @@ module Bmg
82
95
  if predicate.contradiction?
83
96
  Relation.empty(type)
84
97
  else
85
- _restrict type, predicate
98
+ begin
99
+ _restrict type, predicate
100
+ rescue Predicate::NotSupportedError
101
+ Operator::Restrict.new(type, self, predicate)
102
+ end
86
103
  end
87
104
  end
88
105
  end
@@ -101,5 +118,14 @@ module Bmg
101
118
  end
102
119
  protected :_union
103
120
 
121
+ def spied(spy)
122
+ return self if spy.nil?
123
+ Relation::Spied.new(self, spy)
124
+ end
125
+
126
+ def unspied
127
+ self
128
+ end
129
+
104
130
  end # module Algebra
105
131
  end # module Bmg
@@ -2,6 +2,67 @@ module Bmg
2
2
  module Operator
3
3
  include Relation
4
4
 
5
+ def to_s
6
+ str = "(#{self.class.name.split('::').last.downcase}\n"
7
+ str << operands.map{|op| op.to_s.gsub(/^/m, " ") }.join("\n")
8
+ str << "\n"
9
+ str << args.map{|a| a.to_s.gsub(/^/m, " ") }.join("\n")
10
+ str << ")"
11
+ str
12
+ end
13
+
14
+ def inspect
15
+ str = "(#{self.class.name.split('::').last.downcase}\n"
16
+ str << operands.map{|op| op.inspect.gsub(/^/m, " ") }.join("\n")
17
+ str << "\n"
18
+ str << args.map{|a| a.inspect.gsub(/^/m, " ") }.join("\n")
19
+ str << ")"
20
+ str
21
+ end
22
+
23
+ module Unary
24
+ include Operator
25
+
26
+ attr_reader :type, :operand
27
+
28
+ def _visit(parent, visitor)
29
+ visitor.call(self, parent)
30
+ operand._visit(self, visitor)
31
+ end
32
+
33
+ def operands
34
+ [operand]
35
+ end
36
+
37
+ end
38
+
39
+ module Binary
40
+ include Operator
41
+
42
+ attr_reader :type, :left, :right
43
+
44
+ def _visit(parent, visitor)
45
+ visitor.call(self, parent)
46
+ left._visit(self, visitor)
47
+ right._visit(self, visitor)
48
+ end
49
+
50
+ def operands
51
+ [left, right]
52
+ end
53
+ end
54
+
55
+ module Nary
56
+ include Operator
57
+
58
+ attr_reader :type, :operands
59
+
60
+ def _visit(parent, visitor)
61
+ visitor.call(self, parent)
62
+ operands.each{|op| op._visit(self, visitor) }
63
+ end
64
+ end
65
+
5
66
  end
6
67
  end
7
68
  require_relative 'operator/allbut'
@@ -15,18 +15,17 @@ module Bmg
15
15
  # input tuples.
16
16
  #
17
17
  class Allbut
18
- include Operator
18
+ include Operator::Unary
19
19
 
20
20
  def initialize(type, operand, butlist)
21
21
  @type = type
22
22
  @operand = operand
23
23
  @butlist = butlist
24
24
  end
25
- attr_reader :type
26
25
 
27
26
  protected
28
27
 
29
- attr_reader :operand, :butlist
28
+ attr_reader :butlist
30
29
 
31
30
  public
32
31
 
@@ -68,6 +67,12 @@ module Bmg
68
67
  operand.restrict(predicate).allbut(butlist)
69
68
  end
70
69
 
70
+ protected ### inspect
71
+
72
+ def args
73
+ [ butlist ]
74
+ end
75
+
71
76
  private
72
77
 
73
78
  def tuple_allbut(tuple)
@@ -9,7 +9,7 @@ module Bmg
9
9
  # care...
10
10
  #
11
11
  class Autosummarize
12
- include Operator
12
+ include Operator::Unary
13
13
 
14
14
  def initialize(type, operand, by, sums)
15
15
  @type = type
@@ -17,11 +17,10 @@ module Bmg
17
17
  @by = by
18
18
  @sums = sums.each_with_object({}){|(k,v),h| h[k] = to_summarizer(v) }
19
19
  end
20
- attr_reader :type
21
20
 
22
21
  protected
23
22
 
24
- attr_reader :operand, :by, :sums
23
+ attr_reader :by, :sums
25
24
 
26
25
  public
27
26
 
@@ -57,6 +56,12 @@ module Bmg
57
56
  end
58
57
  end
59
58
 
59
+ protected ### inspect
60
+
61
+ def args
62
+ [ by, sums ]
63
+ end
64
+
60
65
  private
61
66
 
62
67
  # Returns the tuple determinant.
@@ -118,6 +123,11 @@ module Bmg
118
123
  v
119
124
  end
120
125
 
126
+ def inspect
127
+ ":same"
128
+ end
129
+ alias :to_s :inspect
130
+
121
131
  end # class Same
122
132
 
123
133
  #
@@ -145,6 +155,11 @@ module Bmg
145
155
  v
146
156
  end
147
157
 
158
+ def inspect
159
+ ":group"
160
+ end
161
+ alias :to_s :inspect
162
+
148
163
  end # class DistinctList
149
164
 
150
165
  #
@@ -176,6 +191,11 @@ module Bmg
176
191
  h
177
192
  end
178
193
 
194
+ def inspect
195
+ ":#{y}_by_#{x}"
196
+ end
197
+ alias :to_s :inspect
198
+
179
199
  end # class YByX
180
200
 
181
201
  #
@@ -210,6 +230,11 @@ module Bmg
210
230
  h
211
231
  end
212
232
 
233
+ def inspect
234
+ ":#{y}s_by_#{x}"
235
+ end
236
+ alias :to_s :inspect
237
+
213
238
  end # class YsByX
214
239
 
215
240
  end # class Autosummarize
@@ -18,7 +18,7 @@ module Bmg
18
18
  # - `split: String` the seperator to use to split keys, defaults to `_`
19
19
  #
20
20
  class Autowrap
21
- include Operator
21
+ include Operator::Unary
22
22
 
23
23
  DEFAULT_OPTIONS = {
24
24
  :postprocessor => :none,
@@ -32,11 +32,10 @@ module Bmg
32
32
  @options = DEFAULT_OPTIONS.merge(options)
33
33
  @options[:postprocessor] = NoLeftJoinNoise.new(@options[:postprocessor])
34
34
  end
35
- attr_reader :type
36
35
 
37
36
  private
38
37
 
39
- attr_reader :operand, :options
38
+ attr_reader :options
40
39
 
41
40
  public
42
41
 
@@ -50,6 +49,12 @@ module Bmg
50
49
  [ :autowrap, operand.to_ast, @original_options.dup ]
51
50
  end
52
51
 
52
+ protected ### inspect
53
+
54
+ def args
55
+ [ options ]
56
+ end
57
+
53
58
  private
54
59
 
55
60
  def autowrap(tuple)
@@ -93,6 +98,7 @@ module Bmg
93
98
  }
94
99
 
95
100
  def initialize(remover)
101
+ @remover_to_s = remover
96
102
  @remover = case remover
97
103
  when NilClass then REMOVERS[:none]
98
104
  when Proc then remover
@@ -115,6 +121,11 @@ module Bmg
115
121
  tuple.all?{|(k,v)| v.nil? || all_nil?(tuple[k]) }
116
122
  end
117
123
 
124
+ def inspect
125
+ @remover_to_s.inspect
126
+ end
127
+ alias :to_s :inspect
128
+
118
129
  end # NoLeftJoinNoise
119
130
 
120
131
  end # class Autowrap
@@ -8,18 +8,17 @@ module Bmg
8
8
  # statically known.
9
9
  #
10
10
  class Constants
11
- include Operator
11
+ include Operator::Unary
12
12
 
13
13
  def initialize(type, operand, constants)
14
14
  @type = type
15
15
  @operand = operand
16
16
  @constants = constants
17
17
  end
18
- attr_reader :type
19
18
 
20
19
  protected
21
20
 
22
- attr_reader :operand, :constants
21
+ attr_reader :constants
23
22
 
24
23
  public
25
24
 
@@ -94,6 +93,12 @@ module Bmg
94
93
  super
95
94
  end
96
95
 
96
+ protected ### inspect
97
+
98
+ def args
99
+ [ constants ]
100
+ end
101
+
97
102
  private
98
103
 
99
104
  def extend_it(tuple)
@@ -11,18 +11,17 @@ module Bmg
11
11
  # [{ a: 1 }] extend { b: ->(t){ 2 } } => [{ a: 1, b: 2 }]
12
12
  #
13
13
  class Extend
14
- include Operator
14
+ include Operator::Unary
15
15
 
16
16
  def initialize(type, operand, extension)
17
17
  @type = type
18
18
  @operand = operand
19
19
  @extension = extension
20
20
  end
21
- attr_reader :type
22
21
 
23
22
  protected
24
23
 
25
- attr_reader :operand, :extension
24
+ attr_reader :extension
26
25
 
27
26
  public
28
27
 
@@ -69,6 +68,12 @@ module Bmg
69
68
  end
70
69
  end
71
70
 
71
+ protected ### inspect
72
+
73
+ def args
74
+ [ extension ]
75
+ end
76
+
72
77
  private
73
78
 
74
79
  def extend_it(tuple)
@@ -6,7 +6,7 @@ module Bmg
6
6
  # Extends each tuple with its image in right.
7
7
  #
8
8
  class Image
9
- include Operator
9
+ include Operator::Binary
10
10
 
11
11
  DEFAULT_OPTIONS = {
12
12
 
@@ -24,11 +24,10 @@ module Bmg
24
24
  @on = on
25
25
  @options = DEFAULT_OPTIONS.merge(options)
26
26
  end
27
- attr_reader :type
28
27
 
29
28
  private
30
29
 
31
- attr_reader :left, :right, :as, :on, :options
30
+ attr_reader :as, :on, :options
32
31
 
33
32
  public
34
33
 
@@ -93,6 +92,12 @@ module Bmg
93
92
  super
94
93
  end
95
94
 
95
+ protected ### inspect
96
+
97
+ def args
98
+ [ as, on, options ]
99
+ end
100
+
96
101
  private
97
102
 
98
103
  def tuple_project(tuple, on)
@@ -108,7 +113,7 @@ module Bmg
108
113
  end
109
114
 
110
115
  def empty_image
111
- Leaf.new(image_type, Set.new)
116
+ Relation::InMemory.new(image_type, Set.new)
112
117
  end
113
118
 
114
119
  end # class Project
@@ -14,18 +14,17 @@ module Bmg
14
14
  # input tuples.
15
15
  #
16
16
  class Project
17
- include Operator
17
+ include Operator::Unary
18
18
 
19
19
  def initialize(type, operand, attrlist)
20
20
  @type = type
21
21
  @operand = operand
22
22
  @attrlist = attrlist
23
23
  end
24
- attr_reader :type
25
24
 
26
25
  private
27
26
 
28
- attr_reader :operand, :attrlist
27
+ attr_reader :attrlist
29
28
 
30
29
  public
31
30
 
@@ -67,6 +66,12 @@ module Bmg
67
66
  operand.restrict(predicate).project(attrlist)
68
67
  end
69
68
 
69
+ protected ### inspect
70
+
71
+ def args
72
+ [ attrlist ]
73
+ end
74
+
70
75
  private
71
76
 
72
77
  def project(tuple)
@@ -14,18 +14,17 @@ module Bmg
14
14
  # attributes of the input tuples.
15
15
  #
16
16
  class Rename
17
- include Operator
17
+ include Operator::Unary
18
18
 
19
19
  def initialize(type, operand, renaming)
20
20
  @type = type
21
21
  @operand = operand
22
22
  @renaming = renaming
23
23
  end
24
- attr_reader :type
25
24
 
26
25
  private
27
26
 
28
- attr_reader :operand, :renaming
27
+ attr_reader :renaming
29
28
 
30
29
  public
31
30
 
@@ -67,6 +66,12 @@ module Bmg
67
66
  operand.restrict(predicate.rename(reverse_renaming)).rename(renaming)
68
67
  end
69
68
 
69
+ protected ### inspect
70
+
71
+ def args
72
+ [ renaming ]
73
+ end
74
+
70
75
  private
71
76
 
72
77
  def rename(tuple, renaming)
@@ -7,18 +7,17 @@ module Bmg
7
7
  # at construction.
8
8
  #
9
9
  class Restrict
10
- include Operator
10
+ include Operator::Unary
11
11
 
12
12
  def initialize(type, operand, predicate)
13
13
  @type = type
14
14
  @operand = operand
15
15
  @predicate = predicate
16
16
  end
17
- attr_reader :type
18
17
 
19
18
  protected
20
19
 
21
- attr_reader :operand, :predicate
20
+ attr_reader :predicate
22
21
 
23
22
  public
24
23
 
@@ -38,6 +37,12 @@ module Bmg
38
37
  Restrict.new(type, @operand, @predicate & predicate)
39
38
  end
40
39
 
40
+ protected ### inspect
41
+
42
+ def args
43
+ [ predicate ]
44
+ end
45
+
41
46
  end # class Restrict
42
47
  end # module Operator
43
48
  end # module Bmg
@@ -14,7 +14,7 @@ module Bmg
14
14
  # behavior and save execution time.
15
15
  #
16
16
  class Union
17
- include Operator
17
+ include Operator::Nary
18
18
 
19
19
  DEFAULT_OPTIONS = {
20
20
  all: false
@@ -25,11 +25,10 @@ module Bmg
25
25
  @operands = operands
26
26
  @options = DEFAULT_OPTIONS.merge(options)
27
27
  end
28
- attr_reader :type
29
28
 
30
29
  protected
31
30
 
32
- attr_reader :operands, :options
31
+ attr_reader :options
33
32
 
34
33
  public
35
34
 
@@ -83,6 +82,12 @@ module Bmg
83
82
  end
84
83
  end
85
84
 
85
+ protected ### inspect
86
+
87
+ def args
88
+ [ options ]
89
+ end
90
+
86
91
  end # class Union
87
92
  end # module Operator
88
93
  end # module Bmg
@@ -1,9 +1,8 @@
1
1
  module Bmg
2
2
  module Reader
3
+ include Relation
3
4
 
4
- def to_a
5
- to_enum(:each).to_a
6
- end
5
+ attr_reader :type
7
6
 
8
7
  end
9
8
  end
@@ -8,7 +8,8 @@ module Bmg
8
8
  :return_headers => false
9
9
  }
10
10
 
11
- def initialize(path, options = {})
11
+ def initialize(type, path, options = {})
12
+ @type = type
12
13
  @path = path
13
14
  @options = DEFAULT_OPTIONS.merge(options)
14
15
  @options[:col_sep] ||= infer_col_sep
@@ -22,6 +23,15 @@ module Bmg
22
23
  end
23
24
  end
24
25
 
26
+ def to_ast
27
+ [ :csv, @path, @options ]
28
+ end
29
+
30
+ def to_s
31
+ "(csv #{path})"
32
+ end
33
+ alias :inspect :to_s
34
+
25
35
  private
26
36
 
27
37
  def tuple(row)
@@ -7,7 +7,8 @@ module Bmg
7
7
  skip: 0
8
8
  }
9
9
 
10
- def initialize(path, options = {})
10
+ def initialize(type, path, options = {})
11
+ @type = type
11
12
  @path = path
12
13
  @options = DEFAULT_OPTIONS.merge(options)
13
14
  end
@@ -30,6 +31,15 @@ module Bmg
30
31
  end
31
32
  end
32
33
 
34
+ def to_ast
35
+ [ :excel, @path, @options ]
36
+ end
37
+
38
+ def to_s
39
+ "(excel #{path})"
40
+ end
41
+ alias :inspect :to_s
42
+
33
43
  end # class Excel
34
44
  end # module Reader
35
45
  end # module Bmg
@@ -4,13 +4,19 @@ module Bmg
4
4
  include Algebra
5
5
 
6
6
  def self.new(operand, type = Type::ANY)
7
- operand.is_a?(Relation) ? operand : Leaf.new(type, operand)
7
+ raise ArgumentError, "Missing type" if type.nil?
8
+ operand.is_a?(Relation) ? operand : Bmg.in_memory(operand, type)
8
9
  end
9
10
 
10
11
  def self.empty(type = Type::ANY)
11
12
  Relation::Empty.new(type)
12
13
  end
13
14
 
15
+ def empty?
16
+ each{|t| return false }
17
+ true
18
+ end
19
+
14
20
  # Private helper to implement `one` and `one_or_nil`
15
21
  def one_or_yield(&bl)
16
22
  first = nil
@@ -47,6 +53,30 @@ module Bmg
47
53
  raise InvalidUpdateError, "Cannot delete from this Relvar"
48
54
  end
49
55
 
56
+ def visit(&visitor)
57
+ _visit(nil, visitor)
58
+ end
59
+
60
+ def _visit(parent, visitor)
61
+ visitor.call(self, parent)
62
+ end
63
+ protected :_visit
64
+
65
+ def ys_by_x(y, x, options = {})
66
+ ordering = options[:order]
67
+ projection = [y, ordering].compact.uniq
68
+ by_x = each.each_with_object({}) do |tuple,h|
69
+ h[tuple[x]] ||= []
70
+ h[tuple[x]] << TupleAlgebra.project(tuple, projection)
71
+ end
72
+ by_x.each_with_object({}) do |(x,ys),h|
73
+ ys = ys.sort{|y1,y2| y1[ordering] <=> y2[ordering] } if ordering
74
+ ys = ys.map{|t| t[y] }
75
+ ys = ys.uniq if options[:distinct]
76
+ h[x] = ys
77
+ end
78
+ end
79
+
50
80
  # Returns a json representation
51
81
  def to_json(*args, &bl)
52
82
  to_a.to_json(*args, &bl)
@@ -59,24 +89,11 @@ module Bmg
59
89
 
60
90
  # Returns a String representing the query plan
61
91
  def debug(max_level = nil, on = STDERR)
62
- on.puts _debug(to_ast, 1, max_level)
92
+ on.puts(self.inspect)
63
93
  self
64
94
  end
65
95
 
66
- private
67
-
68
- def _debug(ast, level = 1, max_level = nil)
69
- return ast.inspect if ast.is_a?(Symbol)
70
- return ast.to_s unless ast.is_a?(Array)
71
- return ast.to_s unless ast.first.is_a?(Symbol)
72
- if max_level && level>max_level
73
- "(#{ast.first} ...)"
74
- else
75
- sep = " " * level
76
- "(#{ast.first}\n" + ast[1..-1].map{|a| _debug(a, 1+level, max_level) }.join("\n").gsub(/^/, sep) + ")"
77
- end
78
- end
79
-
80
96
  end # module Relation
81
97
  end # module Bmg
82
98
  require_relative 'relation/empty'
99
+ require_relative 'relation/in_memory'
@@ -22,6 +22,14 @@ module Bmg
22
22
  [ :empty ]
23
23
  end
24
24
 
25
+ def to_s
26
+ "(empty)"
27
+ end
28
+
29
+ def inspect
30
+ "(empty)"
31
+ end
32
+
25
33
  protected ### optimization
26
34
 
27
35
  def _allbut(type, *args)
@@ -0,0 +1,32 @@
1
+ module Bmg
2
+ module Relation
3
+ class InMemory
4
+ include Relation
5
+
6
+ def initialize(type, operand)
7
+ @operand = operand
8
+ @type = type
9
+ end
10
+ attr_reader :type, :operand
11
+
12
+ public
13
+
14
+ def each(&bl)
15
+ @operand.each(&bl)
16
+ end
17
+
18
+ def to_ast
19
+ [ :in_memory, operand ]
20
+ end
21
+
22
+ def to_s
23
+ "(in_memory ...)"
24
+ end
25
+
26
+ def inspect
27
+ "(in_memory #{operand.inspect})"
28
+ end
29
+
30
+ end # class InMemory
31
+ end # module Relation
32
+ end # module Bmg
@@ -0,0 +1,72 @@
1
+ module Bmg
2
+ module Relation
3
+ class Spied
4
+ include Operator::Unary
5
+
6
+ def initialize(operand, spy)
7
+ @operand = operand
8
+ @spy = spy
9
+ end
10
+
11
+ protected
12
+
13
+ attr_reader :spy
14
+
15
+ public
16
+
17
+ def type
18
+ operand.type
19
+ end
20
+
21
+ def each(&bl)
22
+ spy.call(self)
23
+ operand.each(&bl)
24
+ end
25
+
26
+ def to_ast
27
+ [ :spied, operand.to_ast, spy ]
28
+ end
29
+
30
+ public ### algebra
31
+
32
+ Algebra::METHODS.each do |m|
33
+ define_method(m) do |*args, &bl|
34
+ operand.send(m, *args, &bl).spied(spy)
35
+ end
36
+ end
37
+
38
+ def image(right, *args)
39
+ operand.image(right.unspied, *args).spied(spy)
40
+ end
41
+
42
+ def union(right, *args)
43
+ operand.union(right.unspied, *args).spied(spy)
44
+ end
45
+
46
+ def unspied
47
+ operand
48
+ end
49
+
50
+ public ### update
51
+
52
+ def insert(*args, &bl)
53
+ operand.insert(*args, &bl)
54
+ end
55
+
56
+ def delete(*args, &bl)
57
+ operand.delete(*args, &bl)
58
+ end
59
+
60
+ def update(*args, &bl)
61
+ operand.update(*args, &bl)
62
+ end
63
+
64
+ protected ### inspect
65
+
66
+ def args
67
+ [ spy ]
68
+ end
69
+
70
+ end # class Spied
71
+ end # module Relation
72
+ end # module Bmg
@@ -3,7 +3,7 @@ require 'predicate/sequel'
3
3
  module Bmg
4
4
 
5
5
  def sequel(dataset, type = Type::ANY)
6
- Sequel::Relation.new(type, dataset)
6
+ Sequel::Relation.new(type, dataset).spied(main_spy)
7
7
  end
8
8
  module_function :sequel
9
9
 
@@ -24,7 +24,7 @@ module Bmg
24
24
  end
25
25
 
26
26
  def insert(arg)
27
- dataset.insert(arg)
27
+ dataset.insert(arg.merge(type.predicate.constants))
28
28
  end
29
29
 
30
30
  def update(arg)
@@ -32,9 +32,14 @@ module Bmg
32
32
  end
33
33
 
34
34
  def to_ast
35
- [:sequel, @dataset.sql]
35
+ [:sequel, dataset.sql]
36
36
  end
37
37
 
38
+ def to_s
39
+ "(sequel #{dataset.sql})"
40
+ end
41
+ alias :inspect :to_s
42
+
38
43
  protected ### optimization
39
44
 
40
45
  def _restrict(type, predicate)
@@ -1,7 +1,7 @@
1
1
  module Bmg
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 5
4
+ MINOR = 6
5
5
  TINY = 0
6
6
  end
7
7
  VERSION = "#{Version::MAJOR}.#{Version::MINOR}.#{Version::TINY}"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bmg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
@@ -122,7 +122,6 @@ files:
122
122
  - lib/bmg.rb
123
123
  - lib/bmg/algebra.rb
124
124
  - lib/bmg/error.rb
125
- - lib/bmg/leaf.rb
126
125
  - lib/bmg/operator.rb
127
126
  - lib/bmg/operator/allbut.rb
128
127
  - lib/bmg/operator/autosummarize.rb
@@ -139,6 +138,8 @@ files:
139
138
  - lib/bmg/reader/excel.rb
140
139
  - lib/bmg/relation.rb
141
140
  - lib/bmg/relation/empty.rb
141
+ - lib/bmg/relation/in_memory.rb
142
+ - lib/bmg/relation/spied.rb
142
143
  - lib/bmg/sequel.rb
143
144
  - lib/bmg/sequel/relation.rb
144
145
  - lib/bmg/support.rb
@@ -1,22 +0,0 @@
1
- module Bmg
2
- class Leaf
3
- include Relation
4
-
5
- def initialize(type, operand)
6
- @operand = operand
7
- @type = type
8
- end
9
- attr_reader :type, :operand
10
-
11
- public
12
-
13
- def each(&bl)
14
- @operand.each(&bl)
15
- end
16
-
17
- def to_ast
18
- [:leaf, operand]
19
- end
20
-
21
- end
22
- end