bmg 0.17.5 → 0.17.6

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
  SHA256:
3
- metadata.gz: faea9567e3ec11347ccd8d1e063d027a720095bc8623221597a40e26aade3d99
4
- data.tar.gz: 01b649d2810c6460822c06c83ce06911d438f68cc9b8d297afb766c389619544
3
+ metadata.gz: e67d11656619195bfaa20a9d55fff49d593ccaa3ad558d0876c82534977d4e04
4
+ data.tar.gz: 7ecd9b926d4289feb0fec3efcafcf7b14c483b70f8c4e47b87e3ba038db64774
5
5
  SHA512:
6
- metadata.gz: e75f1778fc7fd0578b37fda44c6b2ccf5f5aa4441c16efeb42b495c38bc9361495b6597d70ce0ea8829caceaceb708c247c24b8531464d6c16f8f3faef1ee01f
7
- data.tar.gz: 3762248213c27bf9e11276fe3a2b9deb75a124e80cc2f7cdf8fbe9a70856649f85fe55eb71474ae6f4a2836fd3d2d144ff6ae44b7b3810ff08bde51d813136a1
6
+ metadata.gz: 4d99c96391c73c096e3e981155cbe53e637c909854a0e3fe92bae991eb7da1be7cf78188c87f9fb53cdbb90e5dd0d92b4fec0501f8d1fcf7f1cdb1900828d575
7
+ data.tar.gz: f8ff33a830852b1e0c5648596ef5f11cae7fc5f7bd817c1ed30a73ce3da81a92bfb42871eecd928a3ce7b717499fb9a975ee8f174a1b013054af506ed056b825
data/README.md CHANGED
@@ -132,6 +132,10 @@ r.restrict(a: "foo", b: "bar", ...) # relational restriction, aka where
132
132
  r.rxmatch([:a, :b, ...], /xxx/) # regex match kind of restriction
133
133
  r.summarize([:a, :b, ...], x: :sum) # relational summarization
134
134
  r.suffix(:_foo, but: [:a, ...]) # suffix kind of renaming
135
+ t.transform(:to_s) # all-attrs transformation
136
+ t.transform(&:to_s) # similar, but Proc-driven
137
+ t.transform(:foo => :upcase, ...) # specific-attrs tranformation
138
+ t.transform([:to_s, :upcase]) # chain-transformation
135
139
  r.union(right) # relational union
136
140
  ```
137
141
 
data/lib/bmg.rb CHANGED
@@ -44,6 +44,7 @@ module Bmg
44
44
  require_relative 'bmg/relation/in_memory'
45
45
  require_relative 'bmg/relation/spied'
46
46
  require_relative 'bmg/relation/materialized'
47
+ require_relative 'bmg/relation/proxy'
47
48
 
48
49
  # Deprecated
49
50
  Leaf = Relation::InMemory
@@ -172,6 +172,16 @@ module Bmg
172
172
  end
173
173
  protected :_summarize
174
174
 
175
+ def transform(transformation = nil, options = {}, &proc)
176
+ transformation, options = proc, (transformation || {}) unless proc.nil?
177
+ _transform(self.type.transform(transformation, options), transformation, options)
178
+ end
179
+
180
+ def _transform(type, transformation, options)
181
+ Operator::Transform.new(type, self, transformation, options)
182
+ end
183
+ protected :_transform
184
+
175
185
  def union(other, options = {})
176
186
  return self if other.is_a?(Relation::Empty)
177
187
  _union self.type.union(other.type), other, options
@@ -46,4 +46,5 @@ require_relative 'operator/rename'
46
46
  require_relative 'operator/restrict'
47
47
  require_relative 'operator/rxmatch'
48
48
  require_relative 'operator/summarize'
49
+ require_relative 'operator/transform'
49
50
  require_relative 'operator/union'
@@ -0,0 +1,57 @@
1
+ module Bmg
2
+ module Operator
3
+ #
4
+ # Transform operator.
5
+ #
6
+ # Transforms existing attributes through computations
7
+ #
8
+ # Example:
9
+ #
10
+ # [{ a: 1 }] transform { a: ->(t){ t[:a]*2 } } => [{ a: 4 }]
11
+ #
12
+ class Transform
13
+ include Operator::Unary
14
+
15
+ DEFAULT_OPTIONS = {}
16
+
17
+ def initialize(type, operand, transformation, options = {})
18
+ @type = type
19
+ @operand = operand
20
+ @transformation = transformation
21
+ @options = DEFAULT_OPTIONS.merge(options)
22
+ end
23
+
24
+ protected
25
+
26
+ attr_reader :transformation
27
+
28
+ public
29
+
30
+ def each
31
+ t = transformer
32
+ @operand.each do |tuple|
33
+ yield t.call(tuple)
34
+ end
35
+ end
36
+
37
+ def to_ast
38
+ [ :transform, operand.to_ast, transformation.dup ]
39
+ end
40
+
41
+ protected ### optimization
42
+
43
+ protected ### inspect
44
+
45
+ def args
46
+ [ transformation ]
47
+ end
48
+
49
+ private
50
+
51
+ def transformer
52
+ @transformer ||= TupleTransformer.new(transformation)
53
+ end
54
+
55
+ end # class Transform
56
+ end # module Operator
57
+ end # module Bmg
@@ -0,0 +1,63 @@
1
+ module Bmg
2
+ module Relation
3
+ #
4
+ # This module can be used to create typed collection on top
5
+ # of Bmg relations. Algebra methods will be delegated to the
6
+ # decorated relation, and results wrapped in a new instance
7
+ # of the class.
8
+ #
9
+ module Proxy
10
+
11
+ def initialize(relation)
12
+ @relation = relation
13
+ end
14
+
15
+ def method_missing(name, *args, &bl)
16
+ if @relation.respond_to?(name)
17
+ res = @relation.send(name, *args, &bl)
18
+ res.is_a?(Relation) ? _proxy(res) : res
19
+ else
20
+ super
21
+ end
22
+ end
23
+
24
+ def respond_to?(name, *args)
25
+ @relation.respond_to?(name) || super
26
+ end
27
+
28
+ [
29
+ :extend
30
+ ].each do |name|
31
+ define_method(name) do |*args, &bl|
32
+ res = @relation.send(name, *args, &bl)
33
+ res.is_a?(Relation) ? _proxy(res) : res
34
+ end
35
+ end
36
+
37
+ [
38
+ :one,
39
+ :one_or_nil
40
+ ].each do |meth|
41
+ define_method(meth) do |*args, &bl|
42
+ res = @relation.send(meth, *args, &bl)
43
+ res.nil? ? nil : _proxy_tuple(res)
44
+ end
45
+ end
46
+
47
+ def to_json(*args, &bl)
48
+ @relation.to_json(*args, &bl)
49
+ end
50
+
51
+ protected
52
+
53
+ def _proxy(relation)
54
+ self.class.new(relation)
55
+ end
56
+
57
+ def _proxy_tuple(tuple)
58
+ tuple
59
+ end
60
+
61
+ end # module Proxy
62
+ end # class Relation
63
+ end # module Bmg
@@ -1,2 +1,3 @@
1
1
  require_relative 'support/tuple_algebra'
2
+ require_relative 'support/tuple_transformer'
2
3
  require_relative 'support/keys'
@@ -7,6 +7,10 @@ module Bmg
7
7
 
8
8
  public ## tools
9
9
 
10
+ def select(&bl)
11
+ Keys.new(@keys.select(&bl), false)
12
+ end
13
+
10
14
  public ## algebra
11
15
 
12
16
  def allbut(oldtype, newtype, butlist)
@@ -0,0 +1,62 @@
1
+ module Bmg
2
+ class TupleTransformer
3
+
4
+ def initialize(transformation)
5
+ @transformation = transformation
6
+ end
7
+
8
+ def self.new(arg)
9
+ return arg if arg.is_a?(TupleTransformer)
10
+ super
11
+ end
12
+
13
+ def call(tuple)
14
+ transform_tuple(tuple, @transformation)
15
+ end
16
+
17
+ def knows_attrlist?
18
+ @transformation.is_a?(Hash)
19
+ end
20
+
21
+ def to_attrlist
22
+ @transformation.keys
23
+ end
24
+
25
+ private
26
+
27
+ def transform_tuple(tuple, with)
28
+ case with
29
+ when Symbol
30
+ tuple.each_with_object({}){|(k,v),dup|
31
+ dup[k] = transform_attr(v, with)
32
+ }
33
+ when Proc
34
+ tuple.each_with_object({}){|(k,v),dup|
35
+ dup[k] = transform_attr(v, with)
36
+ }
37
+ when Hash
38
+ with.each_with_object(tuple.dup){|(k,v),dup|
39
+ dup[k] = transform_attr(dup[k], v)
40
+ }
41
+ when Array
42
+ with.inject(tuple){|dup,on|
43
+ transform_tuple(dup, on)
44
+ }
45
+ else
46
+ raise ArgumentError, "Unexpected transformation `#{with.inspect}`"
47
+ end
48
+ end
49
+
50
+ def transform_attr(value, with)
51
+ case with
52
+ when Symbol
53
+ value.send(with)
54
+ when Proc
55
+ with.call(value)
56
+ else
57
+ raise ArgumentError, "Unexpected transformation `#{with.inspect}`"
58
+ end
59
+ end
60
+
61
+ end # module TupleTransformer
62
+ end # module Bmg
@@ -241,6 +241,31 @@ module Bmg
241
241
  }
242
242
  end
243
243
 
244
+ def transform(transformation, options = {})
245
+ transformer = TupleTransformer.new(transformation)
246
+ if typechecked? && knows_attrlist? && transformer.knows_attrlist?
247
+ known_attributes!(transformer.to_attrlist)
248
+ end
249
+ keys = if options[:key_preserving]
250
+ self._keys
251
+ elsif transformer.knows_attrlist? && knows_keys?
252
+ touched_attrs = transformer.to_attrlist
253
+ keys = self._keys.select{|k| (k & touched_attrs).empty? }
254
+ else
255
+ nil
256
+ end
257
+ pred = if transformer.knows_attrlist?
258
+ attr_list = transformer.to_attrlist
259
+ predicate.and_split(attr_list).last
260
+ else
261
+ Predicate.tautology
262
+ end
263
+ dup.tap{|x|
264
+ x.keys = keys
265
+ x.predicate = pred
266
+ }
267
+ end
268
+
244
269
  def union(other)
245
270
  if typechecked? && knows_attrlist? && other.knows_attrlist?
246
271
  missing = self.attrlist - other.attrlist
@@ -2,7 +2,7 @@ module Bmg
2
2
  module Version
3
3
  MAJOR = 0
4
4
  MINOR = 17
5
- TINY = 5
5
+ TINY = 6
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.17.5
4
+ version: 0.17.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-17 00:00:00.000000000 Z
11
+ date: 2020-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: predicate
@@ -149,6 +149,7 @@ files:
149
149
  - lib/bmg/operator/shared/nary.rb
150
150
  - lib/bmg/operator/shared/unary.rb
151
151
  - lib/bmg/operator/summarize.rb
152
+ - lib/bmg/operator/transform.rb
152
153
  - lib/bmg/operator/union.rb
153
154
  - lib/bmg/reader.rb
154
155
  - lib/bmg/reader/csv.rb
@@ -157,6 +158,7 @@ files:
157
158
  - lib/bmg/relation/empty.rb
158
159
  - lib/bmg/relation/in_memory.rb
159
160
  - lib/bmg/relation/materialized.rb
161
+ - lib/bmg/relation/proxy.rb
160
162
  - lib/bmg/relation/spied.rb
161
163
  - lib/bmg/sequel.rb
162
164
  - lib/bmg/sequel/ext.rb
@@ -259,6 +261,7 @@ files:
259
261
  - lib/bmg/support.rb
260
262
  - lib/bmg/support/keys.rb
261
263
  - lib/bmg/support/tuple_algebra.rb
264
+ - lib/bmg/support/tuple_transformer.rb
262
265
  - lib/bmg/type.rb
263
266
  - lib/bmg/version.rb
264
267
  - lib/bmg/writer.rb