bmg 0.19.3 → 0.20.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 +4 -4
- data/README.md +38 -0
- data/lib/bmg/operator/allbut.rb +4 -4
- data/lib/bmg/operator/constants.rb +25 -25
- data/lib/bmg/operator/extend.rb +4 -4
- data/lib/bmg/operator/project.rb +4 -4
- data/lib/bmg/operator/rename.rb +5 -4
- data/lib/bmg/operator/restrict.rb +12 -0
- data/lib/bmg/reader/csv.rb +1 -3
- data/lib/bmg/relation/in_memory/mutable.rb +23 -0
- data/lib/bmg/relation/in_memory.rb +1 -0
- data/lib/bmg/relation.rb +6 -6
- data/lib/bmg/sequel/predicate_translator.rb +22 -0
- data/lib/bmg/sequel/relation.rb +18 -4
- data/lib/bmg/sequel/translator.rb +5 -22
- data/lib/bmg/sequel.rb +1 -0
- data/lib/bmg/sql/relation.rb +3 -3
- data/lib/bmg/support/ordering.rb +1 -11
- data/lib/bmg/support/output_preferences.rb +1 -27
- data/lib/bmg/version.rb +2 -2
- data/lib/bmg/writer/csv.rb +1 -3
- data/lib/bmg/writer/xlsx.rb +7 -9
- data/lib/bmg/writer.rb +0 -11
- data/lib/bmg.rb +5 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 527bf7476d384f3f1be70ff1f77d1886ac75e4c9bbd8fe8e868fefa9971ff34e
|
4
|
+
data.tar.gz: 628ce8e51b75d3244d937f71b1283556ac16a72835aa9cb415f23c8fbb77fc39
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8948e29965019a1e5fc1204d71a3a423602ea35d4a72ef5e61a7baf12a89f2e653e1428bb4969e731b8ae684e78171c2be0c7c330494c55821d4914b89c46635
|
7
|
+
data.tar.gz: 26e67c96891ed6009c8e8ba1f601053acf71c38951fe0a905c289db83bab40be9809ffabd7c2b5b6287fc9cae1aa6cd1b51dea71cd42f85a9aa77dbfdb70b2bd
|
data/README.md
CHANGED
@@ -16,6 +16,7 @@ further down this README.
|
|
16
16
|
* [Memory relations](#memory-relations)
|
17
17
|
* [Connecting to SQL databases](#connecting-to-sql-databases)
|
18
18
|
* [Reading files (csv, excel, text)](#reading-files-csv-excel-text)
|
19
|
+
* [Connecting to Redis databases](#connecting-to-redis-databases)
|
19
20
|
* [Your own relations](#your-own-relations)
|
20
21
|
* [List of supported operators](#supported-operators)
|
21
22
|
* [How is this different?](#how-is-this-different)
|
@@ -172,6 +173,43 @@ r.type.attrlist
|
|
172
173
|
In this scenario, non matching lines are skipped. The `:line` attribute keeps
|
173
174
|
being used to have at least one candidate key (so to speak).
|
174
175
|
|
176
|
+
### Connecting to Redis databases
|
177
|
+
|
178
|
+
Bmg currently requires `bmg-redis` and `redis >= 4.6` to connect
|
179
|
+
to Redis databases. You also need to require `bmg/redis`.
|
180
|
+
|
181
|
+
```Gemfile
|
182
|
+
gem 'bmg'
|
183
|
+
gem 'bmg-redis'
|
184
|
+
```
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
require 'redis' # also done by 'bmg/redis' below
|
188
|
+
require 'bmg'
|
189
|
+
require 'bmg/redis'
|
190
|
+
```
|
191
|
+
|
192
|
+
Then, you can create Redis relation variables (aka relvars) like
|
193
|
+
this:
|
194
|
+
|
195
|
+
```ruby
|
196
|
+
type = Bmg::Type::ANY.with_keys([[:id]])
|
197
|
+
r = Bmg.redis(type, {
|
198
|
+
key_prefix: "suppliers",
|
199
|
+
redis: Redis.new,
|
200
|
+
serializer: :marshal
|
201
|
+
})
|
202
|
+
```
|
203
|
+
|
204
|
+
The key prefix will be used to distinguish the tuples from other
|
205
|
+
elements in the same database (e.g. tuples from other relvars).
|
206
|
+
The serializer is either `:marshal` or `:json`. Please note that
|
207
|
+
types are not preserved when using the second one (all attribute
|
208
|
+
values will come back as strings, but keys will be symbolized).
|
209
|
+
|
210
|
+
The redis relvars support basic algorithms for insert/update/delete.
|
211
|
+
No optimization is currently supported.
|
212
|
+
|
175
213
|
### Your own relations
|
176
214
|
|
177
215
|
As noted earlier, Bmg has a simple relation interface where you only have to
|
data/lib/bmg/operator/allbut.rb
CHANGED
@@ -50,12 +50,12 @@ module Bmg
|
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
def update(tuple)
|
54
|
-
operand.update(valid_tuple!(tuple))
|
53
|
+
def update(tuple, predicate = Predicate.tautology)
|
54
|
+
operand.update(valid_tuple!(tuple), predicate)
|
55
55
|
end
|
56
56
|
|
57
|
-
def delete
|
58
|
-
operand.delete
|
57
|
+
def delete(predicate = Predicate.tautology)
|
58
|
+
operand.delete(predicate)
|
59
59
|
end
|
60
60
|
|
61
61
|
def to_ast
|
@@ -10,15 +10,15 @@ module Bmg
|
|
10
10
|
class Constants
|
11
11
|
include Operator::Unary
|
12
12
|
|
13
|
-
def initialize(type, operand,
|
13
|
+
def initialize(type, operand, the_constants)
|
14
14
|
@type = type
|
15
15
|
@operand = operand
|
16
|
-
@
|
16
|
+
@the_constants = the_constants
|
17
17
|
end
|
18
18
|
|
19
19
|
protected
|
20
20
|
|
21
|
-
attr_reader :
|
21
|
+
attr_reader :the_constants
|
22
22
|
|
23
23
|
public
|
24
24
|
|
@@ -32,27 +32,27 @@ module Bmg
|
|
32
32
|
def insert(arg)
|
33
33
|
case arg
|
34
34
|
when Hash then operand.insert(allbut_constants(arg))
|
35
|
-
when Relation then operand.insert(arg.allbut(
|
35
|
+
when Relation then operand.insert(arg.allbut(the_constants.keys))
|
36
36
|
when Enumerable then operand.insert(arg.map{|t| allbut_constants(t) })
|
37
37
|
else
|
38
38
|
super
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
def update(tuple)
|
43
|
-
shared = tuple.keys &
|
42
|
+
def update(tuple, predicate = Predicate.tautology)
|
43
|
+
shared = tuple.keys & the_constants.keys
|
44
44
|
on_tuple = TupleAlgebra.project(tuple, shared)
|
45
|
-
on_const = TupleAlgebra.project(
|
45
|
+
on_const = TupleAlgebra.project(the_constants, shared)
|
46
46
|
raise InvalidUpdateError, "Cannot violate relvar predicate" unless on_tuple == on_const
|
47
|
-
operand.update(allbut_constants(tuple))
|
47
|
+
operand.update(allbut_constants(tuple), predicate)
|
48
48
|
end
|
49
49
|
|
50
|
-
def delete
|
51
|
-
operand.delete
|
50
|
+
def delete(predicate = Predicate.tautology)
|
51
|
+
operand.delete(predicate)
|
52
52
|
end
|
53
53
|
|
54
54
|
def to_ast
|
55
|
-
[ :constants, operand.to_ast,
|
55
|
+
[ :constants, operand.to_ast, the_constants.dup ]
|
56
56
|
end
|
57
57
|
|
58
58
|
public ### for internal reasons
|
@@ -65,32 +65,32 @@ module Bmg
|
|
65
65
|
|
66
66
|
def _page(type, ordering, page_index, options)
|
67
67
|
attrs = ordering.map{|(k,v)| k}
|
68
|
-
cs_attrs =
|
68
|
+
cs_attrs = the_constants.keys
|
69
69
|
if (attrs & cs_attrs).empty?
|
70
70
|
operand
|
71
71
|
.page(ordering, page_index, options)
|
72
|
-
.constants(
|
72
|
+
.constants(the_constants)
|
73
73
|
else
|
74
74
|
super
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
78
|
def _restrict(type, predicate)
|
79
|
-
# bottom_p makes no reference to
|
79
|
+
# bottom_p makes no reference to the_constants, top_p possibly
|
80
80
|
# does...
|
81
|
-
top_p, bottom_p = predicate.and_split(
|
81
|
+
top_p, bottom_p = predicate.and_split(the_constants.keys)
|
82
82
|
if top_p.tautology?
|
83
|
-
# push all situation: predicate made no reference to
|
83
|
+
# push all situation: predicate made no reference to the_constants
|
84
84
|
result = operand
|
85
85
|
result = result.restrict(bottom_p)
|
86
|
-
result = result.constants(
|
86
|
+
result = result.constants(the_constants)
|
87
87
|
result
|
88
|
-
elsif (top_p.free_variables -
|
89
|
-
# top_p applies to
|
90
|
-
if eval = top_p.evaluate(
|
88
|
+
elsif (top_p.free_variables - the_constants.keys).empty?
|
89
|
+
# top_p applies to the_constants only
|
90
|
+
if eval = top_p.evaluate(the_constants)
|
91
91
|
result = operand
|
92
92
|
result = result.restrict(bottom_p)
|
93
|
-
result = result.constants(
|
93
|
+
result = result.constants(the_constants)
|
94
94
|
result
|
95
95
|
else
|
96
96
|
Relation.empty(type)
|
@@ -104,7 +104,7 @@ module Bmg
|
|
104
104
|
# of them
|
105
105
|
result = operand
|
106
106
|
result = result.restrict(bottom_p)
|
107
|
-
result = result.constants(
|
107
|
+
result = result.constants(the_constants)
|
108
108
|
result = result.restrict(top_p)
|
109
109
|
result
|
110
110
|
end
|
@@ -115,17 +115,17 @@ module Bmg
|
|
115
115
|
protected ### inspect
|
116
116
|
|
117
117
|
def args
|
118
|
-
[
|
118
|
+
[ the_constants ]
|
119
119
|
end
|
120
120
|
|
121
121
|
private
|
122
122
|
|
123
123
|
def extend_it(tuple)
|
124
|
-
tuple.merge(@
|
124
|
+
tuple.merge(@the_constants)
|
125
125
|
end
|
126
126
|
|
127
127
|
def allbut_constants(tuple)
|
128
|
-
TupleAlgebra.allbut(tuple,
|
128
|
+
TupleAlgebra.allbut(tuple, the_constants.keys)
|
129
129
|
end
|
130
130
|
|
131
131
|
end # class Constants
|
data/lib/bmg/operator/extend.rb
CHANGED
@@ -42,12 +42,12 @@ module Bmg
|
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
|
-
def update(tuple)
|
46
|
-
operand.update(allbut_extkeys(tuple))
|
45
|
+
def update(tuple, predicate = Predicate.tautology)
|
46
|
+
operand.update(allbut_extkeys(tuple), predicate)
|
47
47
|
end
|
48
48
|
|
49
|
-
def delete
|
50
|
-
operand.delete
|
49
|
+
def delete(predicate = Predicate.tautology)
|
50
|
+
operand.delete(predicate)
|
51
51
|
end
|
52
52
|
|
53
53
|
def to_ast
|
data/lib/bmg/operator/project.rb
CHANGED
@@ -49,12 +49,12 @@ module Bmg
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
def update(tuple)
|
53
|
-
operand.update(valid_tuple!(tuple))
|
52
|
+
def update(tuple, predicate = Predicate.tautology)
|
53
|
+
operand.update(valid_tuple!(tuple), predicate)
|
54
54
|
end
|
55
55
|
|
56
|
-
def delete
|
57
|
-
operand.delete
|
56
|
+
def delete(predicate = Predicate.tautology)
|
57
|
+
operand.delete(predicate)
|
58
58
|
end
|
59
59
|
|
60
60
|
def to_ast
|
data/lib/bmg/operator/rename.rb
CHANGED
@@ -45,16 +45,17 @@ module Bmg
|
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
def update(arg)
|
48
|
+
def update(arg, predicate = Predicate.tautology)
|
49
49
|
case arg
|
50
|
-
when Hash
|
50
|
+
when Hash
|
51
|
+
operand.update(rename_tuple(arg, reverse_renaming), predicate)
|
51
52
|
else
|
52
53
|
super
|
53
54
|
end
|
54
55
|
end
|
55
56
|
|
56
|
-
def delete
|
57
|
-
operand.delete
|
57
|
+
def delete(predicate = Predicate.tautology)
|
58
|
+
operand.delete(predicate)
|
58
59
|
end
|
59
60
|
|
60
61
|
def to_ast
|
@@ -32,6 +32,18 @@ module Bmg
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
def insert(tuple)
|
36
|
+
operand.insert(tuple)
|
37
|
+
end
|
38
|
+
|
39
|
+
def update(updating, predicate = Predicate.tautology)
|
40
|
+
operand.update(updating, predicate & self.predicate)
|
41
|
+
end
|
42
|
+
|
43
|
+
def delete(predicate = Predicate.tautology)
|
44
|
+
operand.delete(predicate & self.predicate)
|
45
|
+
end
|
46
|
+
|
35
47
|
def to_ast
|
36
48
|
[ :restrict, operand.to_ast, predicate.sexpr ]
|
37
49
|
end
|
data/lib/bmg/reader/csv.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Relation
|
3
|
+
class InMemory
|
4
|
+
class Mutable < InMemory
|
5
|
+
def insert(arg)
|
6
|
+
raise ArgumentError unless arg.is_a?(Hash)
|
7
|
+
|
8
|
+
@operand << arg.dup
|
9
|
+
end
|
10
|
+
|
11
|
+
def update(updating, predicate = Predicate.tautology)
|
12
|
+
@operand = @operand.map{|t|
|
13
|
+
predicate.call(t) ? t.merge(updating) : t
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete(predicate = Predicate.tautology)
|
18
|
+
@operand = @operand.select{|t| predicate.call(t) }
|
19
|
+
end
|
20
|
+
end # class Mutable
|
21
|
+
end # class InMemory
|
22
|
+
end # module Relation
|
23
|
+
end # module Bmg
|
data/lib/bmg/relation.rb
CHANGED
@@ -74,16 +74,16 @@ module Bmg
|
|
74
74
|
one_or_yield{ nil }
|
75
75
|
end
|
76
76
|
|
77
|
-
def insert(
|
78
|
-
raise InvalidUpdateError, "Cannot insert into
|
77
|
+
def insert(*args, &bl)
|
78
|
+
raise InvalidUpdateError, "Cannot insert into #{self.class.name}"
|
79
79
|
end
|
80
80
|
|
81
|
-
def update(
|
82
|
-
raise InvalidUpdateError, "Cannot update
|
81
|
+
def update(*args, &bl)
|
82
|
+
raise InvalidUpdateError, "Cannot update #{self.class.name}"
|
83
83
|
end
|
84
84
|
|
85
|
-
def delete
|
86
|
-
raise InvalidUpdateError, "Cannot delete from
|
85
|
+
def delete(*args, &bl)
|
86
|
+
raise InvalidUpdateError, "Cannot delete from #{self.class.name}"
|
87
87
|
end
|
88
88
|
|
89
89
|
def visit(&visitor)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sequel
|
3
|
+
class PredicateTranslator < Sexpr::Processor
|
4
|
+
include ::Predicate::ToSequel::Methods
|
5
|
+
|
6
|
+
def initialize(parent)
|
7
|
+
@parent = parent
|
8
|
+
end
|
9
|
+
|
10
|
+
public ### Predicate hack
|
11
|
+
|
12
|
+
def on_opaque(sexpr)
|
13
|
+
@parent.apply(sexpr.last)
|
14
|
+
end
|
15
|
+
|
16
|
+
def on_exists(sexpr)
|
17
|
+
@parent.apply(sexpr.last).exists
|
18
|
+
end
|
19
|
+
|
20
|
+
end # class PredicateTranslator
|
21
|
+
end # module Sequel
|
22
|
+
end # module Bmg
|
data/lib/bmg/sequel/relation.rb
CHANGED
@@ -13,8 +13,13 @@ module Bmg
|
|
13
13
|
dataset.each(&bl)
|
14
14
|
end
|
15
15
|
|
16
|
-
def delete
|
17
|
-
base_table
|
16
|
+
def delete(predicate = Predicate.tautology)
|
17
|
+
target = base_table
|
18
|
+
unless predicate.tautology?
|
19
|
+
compiled = compile_predicate(predicate)
|
20
|
+
target = base_table.where(compiled)
|
21
|
+
end
|
22
|
+
target.delete
|
18
23
|
end
|
19
24
|
|
20
25
|
def insert(arg)
|
@@ -30,8 +35,13 @@ module Bmg
|
|
30
35
|
end
|
31
36
|
end
|
32
37
|
|
33
|
-
def update(arg)
|
34
|
-
base_table
|
38
|
+
def update(arg, predicate = Predicate.tautology)
|
39
|
+
target = base_table
|
40
|
+
unless predicate.tautology?
|
41
|
+
compiled = compile_predicate(predicate)
|
42
|
+
target = base_table.where(compiled)
|
43
|
+
end
|
44
|
+
target.update(arg)
|
35
45
|
end
|
36
46
|
|
37
47
|
def _count
|
@@ -73,6 +83,10 @@ module Bmg
|
|
73
83
|
operand.expr
|
74
84
|
end
|
75
85
|
|
86
|
+
def compile_predicate(predicate)
|
87
|
+
Translator.new(sequel_db).compile_predicate(predicate)
|
88
|
+
end
|
89
|
+
|
76
90
|
end # class Relation
|
77
91
|
end # module Sequel
|
78
92
|
end # module Bmg
|
@@ -179,36 +179,19 @@ module Bmg
|
|
179
179
|
sexpr.last
|
180
180
|
end
|
181
181
|
|
182
|
-
|
183
|
-
|
184
|
-
def dataset(expr)
|
185
|
-
return expr if ::Sequel::Dataset===expr
|
186
|
-
sequel_db[expr]
|
187
|
-
end
|
182
|
+
public
|
188
183
|
|
189
184
|
def compile_predicate(predicate)
|
190
185
|
PredicateTranslator.new(self).call(predicate)
|
191
186
|
end
|
192
187
|
|
193
|
-
|
194
|
-
include ::Predicate::ToSequel::Methods
|
195
|
-
|
196
|
-
def initialize(parent)
|
197
|
-
@parent = parent
|
198
|
-
end
|
199
|
-
|
200
|
-
public ### Predicate hack
|
201
|
-
|
202
|
-
def on_opaque(sexpr)
|
203
|
-
@parent.apply(sexpr.last)
|
204
|
-
end
|
188
|
+
private
|
205
189
|
|
206
|
-
def
|
207
|
-
|
190
|
+
def dataset(expr)
|
191
|
+
return expr if ::Sequel::Dataset===expr
|
192
|
+
sequel_db[expr]
|
208
193
|
end
|
209
194
|
|
210
|
-
end
|
211
|
-
|
212
195
|
end # class Translator
|
213
196
|
end # module Sequel
|
214
197
|
end # module Bmg
|
data/lib/bmg/sequel.rb
CHANGED
data/lib/bmg/sql/relation.rb
CHANGED
@@ -27,15 +27,15 @@ module Bmg
|
|
27
27
|
raise NotImplementedError
|
28
28
|
end
|
29
29
|
|
30
|
-
def delete
|
30
|
+
def delete(*args, &bl)
|
31
31
|
raise NotImplementedError
|
32
32
|
end
|
33
33
|
|
34
|
-
def insert(
|
34
|
+
def insert(*args, &bl)
|
35
35
|
raise NotImplementedError
|
36
36
|
end
|
37
37
|
|
38
|
-
def update(
|
38
|
+
def update(*args, &bl)
|
39
39
|
raise NotImplementedError
|
40
40
|
end
|
41
41
|
|
data/lib/bmg/support/ordering.rb
CHANGED
@@ -2,13 +2,7 @@ module Bmg
|
|
2
2
|
class Ordering
|
3
3
|
|
4
4
|
def initialize(attrs)
|
5
|
-
@attrs =
|
6
|
-
[]
|
7
|
-
elsif attrs.first.is_a?(Symbol)
|
8
|
-
attrs.map{|a| [a, :asc] }
|
9
|
-
else
|
10
|
-
attrs
|
11
|
-
end
|
5
|
+
@attrs = attrs
|
12
6
|
end
|
13
7
|
attr_reader :attrs
|
14
8
|
|
@@ -39,9 +33,5 @@ module Bmg
|
|
39
33
|
0
|
40
34
|
end
|
41
35
|
|
42
|
-
def to_a
|
43
|
-
attrs.to_a
|
44
|
-
end
|
45
|
-
|
46
36
|
end # class Ordering
|
47
37
|
end # module Bmg
|
@@ -3,7 +3,6 @@ module Bmg
|
|
3
3
|
|
4
4
|
DEFAULT_PREFS = {
|
5
5
|
attributes_ordering: nil,
|
6
|
-
tuple_ordering: nil,
|
7
6
|
extra_attributes: :after
|
8
7
|
}
|
9
8
|
|
@@ -18,12 +17,6 @@ module Bmg
|
|
18
17
|
new(arg)
|
19
18
|
end
|
20
19
|
|
21
|
-
def tuple_ordering
|
22
|
-
return nil unless to = options[:tuple_ordering]
|
23
|
-
|
24
|
-
@tuple_ordering = Ordering.new(to)
|
25
|
-
end
|
26
|
-
|
27
20
|
def attributes_ordering
|
28
21
|
options[:attributes_ordering]
|
29
22
|
end
|
@@ -32,29 +25,10 @@ module Bmg
|
|
32
25
|
options[:extra_attributes]
|
33
26
|
end
|
34
27
|
|
35
|
-
def grouping_attributes
|
36
|
-
options[:grouping_attributes]
|
37
|
-
end
|
38
|
-
|
39
|
-
def erase_redundance_in_group(before, current)
|
40
|
-
return [nil, current] unless ga = grouping_attributes
|
41
|
-
return [current, current] unless before
|
42
|
-
|
43
|
-
new_before, new_current = current.dup, current.dup
|
44
|
-
ga.each do |attr|
|
45
|
-
return [new_before, new_current] unless before[attr] == current[attr]
|
46
|
-
new_current[attr] = nil
|
47
|
-
end
|
48
|
-
[new_before, new_current]
|
49
|
-
end
|
50
|
-
|
51
28
|
def order_attrlist(attrlist)
|
52
29
|
return attrlist if attributes_ordering.nil?
|
53
|
-
|
54
30
|
index = Hash[attributes_ordering.each_with_index.to_a]
|
55
|
-
|
56
|
-
base = attrlist & attributes_ordering if extra_attributes == :ignored
|
57
|
-
base.sort{|a,b|
|
31
|
+
attrlist.sort{|a,b|
|
58
32
|
ai, bi = index[a], index[b]
|
59
33
|
if ai && bi
|
60
34
|
ai <=> bi
|
data/lib/bmg/version.rb
CHANGED
data/lib/bmg/writer/csv.rb
CHANGED
@@ -16,14 +16,12 @@ module Bmg
|
|
16
16
|
require 'csv'
|
17
17
|
string_or_io, to_s = string_or_io.nil? ? [StringIO.new, true] : [string_or_io, false]
|
18
18
|
headers, csv = infer_headers(relation.type), nil
|
19
|
-
|
20
|
-
each_tuple(relation) do |tuple,i|
|
19
|
+
relation.each do |tuple|
|
21
20
|
if csv.nil?
|
22
21
|
headers = infer_headers(tuple) if headers.nil?
|
23
22
|
csv_opts = csv_options.merge(headers: headers)
|
24
23
|
csv = CSV.new(string_or_io, **csv_opts)
|
25
24
|
end
|
26
|
-
previous, tuple = output_preferences.erase_redundance_in_group(previous, tuple)
|
27
25
|
csv << headers.map{|h| tuple[h] }
|
28
26
|
end
|
29
27
|
to_s ? string_or_io.string : string_or_io
|
data/lib/bmg/writer/xlsx.rb
CHANGED
@@ -6,11 +6,11 @@ module Bmg
|
|
6
6
|
DEFAULT_OPTIONS = {
|
7
7
|
}
|
8
8
|
|
9
|
-
def initialize(
|
10
|
-
@
|
9
|
+
def initialize(csv_options, output_preferences = nil)
|
10
|
+
@csv_options = DEFAULT_OPTIONS.merge(csv_options)
|
11
11
|
@output_preferences = OutputPreferences.dress(output_preferences)
|
12
12
|
end
|
13
|
-
attr_reader :
|
13
|
+
attr_reader :csv_options, :output_preferences
|
14
14
|
|
15
15
|
def call(relation, path)
|
16
16
|
require 'write_xlsx'
|
@@ -21,24 +21,22 @@ module Bmg
|
|
21
21
|
attr_reader :workbook, :worksheet
|
22
22
|
|
23
23
|
def _call(relation, path)
|
24
|
-
@workbook =
|
25
|
-
@worksheet =
|
24
|
+
@workbook = WriteXLSX.new(path)
|
25
|
+
@worksheet = workbook.add_worksheet
|
26
26
|
|
27
27
|
headers = infer_headers(relation.type)
|
28
|
-
|
29
|
-
each_tuple(relation) do |tuple,i|
|
28
|
+
relation.each_with_index do |tuple,i|
|
30
29
|
headers = infer_headers(tuple) if headers.nil?
|
31
30
|
headers.each_with_index do |h,i|
|
32
31
|
worksheet.write_string(0, i, h)
|
33
32
|
end if i == 0
|
34
|
-
before, tuple = output_preferences.erase_redundance_in_group(before, tuple)
|
35
33
|
headers.each_with_index do |h,j|
|
36
34
|
meth, *args = write_pair(tuple[h])
|
37
35
|
worksheet.send(meth, 1+i, j, *args)
|
38
36
|
end
|
39
37
|
end
|
40
38
|
|
41
|
-
workbook.close
|
39
|
+
workbook.close
|
42
40
|
path
|
43
41
|
end
|
44
42
|
|
data/lib/bmg/writer.rb
CHANGED
@@ -12,17 +12,6 @@ module Bmg
|
|
12
12
|
attrlist ? output_preferences.order_attrlist(attrlist) : nil
|
13
13
|
end
|
14
14
|
|
15
|
-
def each_tuple(relation, &bl)
|
16
|
-
if ordering = output_preferences.tuple_ordering
|
17
|
-
relation
|
18
|
-
.to_a
|
19
|
-
.sort{|t1,t2| ordering.compare_attrs(t1, t2) }
|
20
|
-
.each_with_index(&bl)
|
21
|
-
else
|
22
|
-
relation.each_with_index(&bl)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
15
|
end # module Writer
|
27
16
|
end # module Bmg
|
28
17
|
require_relative 'writer/csv'
|
data/lib/bmg.rb
CHANGED
@@ -4,6 +4,11 @@ require 'forwardable'
|
|
4
4
|
require 'set'
|
5
5
|
module Bmg
|
6
6
|
|
7
|
+
def mutable(enumerable, type = Type::ANY)
|
8
|
+
Relation::InMemory::Mutable.new(type, enumerable).spied(main_spy)
|
9
|
+
end
|
10
|
+
module_function :mutable
|
11
|
+
|
7
12
|
def in_memory(enumerable, type = Type::ANY)
|
8
13
|
Relation::InMemory.new(type, enumerable).spied(main_spy)
|
9
14
|
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.
|
4
|
+
version: 0.20.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bernard Lambeau
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: predicate
|
@@ -174,11 +174,13 @@ files:
|
|
174
174
|
- lib/bmg/relation.rb
|
175
175
|
- lib/bmg/relation/empty.rb
|
176
176
|
- lib/bmg/relation/in_memory.rb
|
177
|
+
- lib/bmg/relation/in_memory/mutable.rb
|
177
178
|
- lib/bmg/relation/materialized.rb
|
178
179
|
- lib/bmg/relation/proxy.rb
|
179
180
|
- lib/bmg/relation/spied.rb
|
180
181
|
- lib/bmg/sequel.rb
|
181
182
|
- lib/bmg/sequel/ext.rb
|
183
|
+
- lib/bmg/sequel/predicate_translator.rb
|
182
184
|
- lib/bmg/sequel/relation.rb
|
183
185
|
- lib/bmg/sequel/translator.rb
|
184
186
|
- lib/bmg/sequel/type_inference.rb
|
@@ -318,7 +320,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
318
320
|
- !ruby/object:Gem::Version
|
319
321
|
version: '0'
|
320
322
|
requirements: []
|
321
|
-
rubygems_version: 3.1.
|
323
|
+
rubygems_version: 3.1.4
|
322
324
|
signing_key:
|
323
325
|
specification_version: 4
|
324
326
|
summary: Bmg is Alf's successor.
|