bmg 0.17.5 → 0.17.6

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