bmg 0.5.0 → 0.6.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: 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