bmg 0.23.6 → 1.0.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 +45 -2
- data/lib/bmg/operator/allbut.rb +1 -1
- data/lib/bmg/operator/autosummarize.rb +4 -6
- data/lib/bmg/operator/group.rb +5 -0
- data/lib/bmg/operator/image.rb +10 -10
- data/lib/bmg/operator/join.rb +5 -4
- data/lib/bmg/operator/matching.rb +5 -4
- data/lib/bmg/operator/not_matching.rb +5 -4
- data/lib/bmg/operator/project.rb +2 -1
- data/lib/bmg/operator/summarize.rb +2 -1
- data/lib/bmg/sequel/translator.rb +9 -1
- data/lib/bmg/sql/grammar.rb +1 -0
- data/lib/bmg/sql/grammar.sexp.yml +3 -0
- data/lib/bmg/sql/nodes/case_when.rb +33 -0
- data/lib/bmg/sql/processor/transform.rb +27 -1
- data/lib/bmg/sql/relation.rb +2 -1
- data/lib/bmg/support/tuple_algebra.rb +18 -0
- data/lib/bmg/version.rb +3 -3
- data/lib/bmg.rb +0 -3
- metadata +77 -17
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b73ed9026efe140b3d55eb59a1949db5fad0ac04ff401f3c44199d39274108ca
|
|
4
|
+
data.tar.gz: 1d375d5ca7638e43d21c6bc27a34b3df47f6947d7d853158fa0bdc90db0754cc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f55dba1dc2db2ef68beaf1d0f58c0c84fd2ff7c4bb2c1b883ad5726fcdd6b44588529f602876783d6d14823e3cb6494bb9335490c6b214cc725a1e55d93d4181
|
|
7
|
+
data.tar.gz: ba1fe4d29f70002410ddb0d7afe7fd63555a87746cbfac7c85bc1ca0c3af5c796a3f4245928e8c1f841dfc847ad375518728c1f3ad225c434bb2c8420f8e4a2b
|
data/README.md
CHANGED
|
@@ -31,6 +31,7 @@ further down this README.
|
|
|
31
31
|
* [How is this different?](#how-is-this-different)
|
|
32
32
|
* [... from similar libraries](#-from-similar-libraries)
|
|
33
33
|
* [... from Alf](#-from-alf)
|
|
34
|
+
* [Stability and versioning](#stability-and-versioning)
|
|
34
35
|
* [Contribute](#contribute)
|
|
35
36
|
* [License](#license)
|
|
36
37
|
|
|
@@ -202,7 +203,7 @@ documentation.
|
|
|
202
203
|
|
|
203
204
|
### Connecting to Redis databases
|
|
204
205
|
|
|
205
|
-
Bmg currently requires `bmg-redis` and `redis >= 4.
|
|
206
|
+
Bmg currently requires `bmg-redis` and `redis >= 4.0` to connect
|
|
206
207
|
to Redis databases. You also need to require `bmg/redis`.
|
|
207
208
|
|
|
208
209
|
```Gemfile
|
|
@@ -360,7 +361,7 @@ db.to_xlsx('path/to/file.xlsx')
|
|
|
360
361
|
```ruby
|
|
361
362
|
r.allbut([:a, :b, ...]) # remove specified attributes
|
|
362
363
|
r.autowrap(split: '_') # structure a flat relation, split: '_' is the default
|
|
363
|
-
r.autosummarize([:a, :b, ...], x: :sum) #
|
|
364
|
+
r.autosummarize([:a, :b, ...], x: :sum) # usual summarizers supported
|
|
364
365
|
r.constants(x: 12, ...) # add constant attributes (sometimes useful in unions)
|
|
365
366
|
r.cross_product(right) # cross product, alias `cross_join`
|
|
366
367
|
r.extend(x: ->(t){ ... }, ...) # add computed attributes
|
|
@@ -536,12 +537,54 @@ probably never be.
|
|
|
536
537
|
building an AST internally first. Strictly speaking this makes Bmg less
|
|
537
538
|
powerful than Alf since optimizations cannot be turned off for now.
|
|
538
539
|
|
|
540
|
+
## Stability and versioning
|
|
541
|
+
|
|
542
|
+
As of 1.0, Bmg follows [semantic versioning](https://semver.org). Breaking
|
|
543
|
+
changes to the API described below only happen on a major version.
|
|
544
|
+
|
|
545
|
+
The following is public, and covered by that promise:
|
|
546
|
+
|
|
547
|
+
* the factory methods on `Bmg` and `Bmg::Relation` (`in_memory`, `sequel`,
|
|
548
|
+
`csv`, `json`, `yaml`, `excel`, `text_file`, `generate`, `mutable`, ...);
|
|
549
|
+
* the relational operators listed under [Supported
|
|
550
|
+
operators](#supported-operators), their arguments and their documented
|
|
551
|
+
options;
|
|
552
|
+
* the predicates and summarizers listed under [Supported
|
|
553
|
+
predicates](#supported-predicates) and [Supported
|
|
554
|
+
summaries](#supported-summaries);
|
|
555
|
+
* `Bmg::Relation` as an interface to include, with `each` yielding symbolized
|
|
556
|
+
tuples, as shown in [Your own relations](#your-own-relations);
|
|
557
|
+
* `Bmg::Type`, `Bmg::Database`, and the reader/writer output preferences.
|
|
558
|
+
|
|
559
|
+
The following is explicitly *not* covered, and may change in a minor version:
|
|
560
|
+
|
|
561
|
+
* the underscored optimization hooks (`_restrict`, `_project`, ...). They are
|
|
562
|
+
documented in [Your own relations](#your-own-relations) because adapters
|
|
563
|
+
need them, but the protocol evolves as new optimizations are added. If you
|
|
564
|
+
override them, pin a minor version and read the CHANGELOG.
|
|
565
|
+
* the shape of the ASTs returned by `to_ast`, and the SQL actually generated
|
|
566
|
+
for a given query tree. Both are observable, and both are expected to
|
|
567
|
+
change as the compiler improves; only the *semantics* of a relation is
|
|
568
|
+
guaranteed.
|
|
569
|
+
* anything under `Bmg::Sql`, `Bmg::Sequel::Translator` and the sexpr grammar,
|
|
570
|
+
which are compiler internals.
|
|
571
|
+
|
|
539
572
|
## Contribute
|
|
540
573
|
|
|
541
574
|
Please use github issues and pull requests for all questions, bug reports,
|
|
542
575
|
and contributions. Don't hesitate to get in touch with us with an early code
|
|
543
576
|
spike if you plan to add non trivial features.
|
|
544
577
|
|
|
578
|
+
The `bench/` folder holds benchmarks for the in-memory operators and for the
|
|
579
|
+
SQL compiler. Run one with `bundle exec ruby bench/operators.rb`. To compare
|
|
580
|
+
two versions of the code, point `BMG_LIB` at another checkout and alternate
|
|
581
|
+
between the two — benchmarking both in one batch, then the other, mostly
|
|
582
|
+
measures how busy your machine was:
|
|
583
|
+
|
|
584
|
+
```
|
|
585
|
+
BMG_LIB=/path/to/other/lib bundle exec ruby bench/operators.rb
|
|
586
|
+
```
|
|
587
|
+
|
|
545
588
|
## Licence
|
|
546
589
|
|
|
547
590
|
This software is distributed by Enspirit SRL under a MIT Licence. Please
|
data/lib/bmg/operator/allbut.rb
CHANGED
|
@@ -5,9 +5,6 @@ module Bmg
|
|
|
5
5
|
#
|
|
6
6
|
# Autosummarize helps structuring the results of a big flat join.
|
|
7
7
|
#
|
|
8
|
-
# This operator is still largely experimental and should be used with
|
|
9
|
-
# care...
|
|
10
|
-
#
|
|
11
8
|
class Autosummarize
|
|
12
9
|
include Operator::Unary
|
|
13
10
|
|
|
@@ -294,10 +291,11 @@ module Bmg
|
|
|
294
291
|
v = v.reject{|tuple| tuple[@x].nil? }
|
|
295
292
|
v = v.sort(&@sorter) if @sorter
|
|
296
293
|
v.each do |tuple|
|
|
297
|
-
h[tuple[@x]] ||= []
|
|
298
|
-
h[tuple[@x]] << tuple[@y]
|
|
299
|
-
h[tuple[@x]].uniq!
|
|
294
|
+
(h[tuple[@x]] ||= []) << tuple[@y]
|
|
300
295
|
end
|
|
296
|
+
# deduplicating once at the end, instead of on every append,
|
|
297
|
+
# keeps this linear in the number of observed `y`s
|
|
298
|
+
h.each_value(&:uniq!)
|
|
301
299
|
h
|
|
302
300
|
end
|
|
303
301
|
|
data/lib/bmg/operator/group.rb
CHANGED
|
@@ -34,6 +34,7 @@ module Bmg
|
|
|
34
34
|
def each(&bl)
|
|
35
35
|
return to_enum unless block_given?
|
|
36
36
|
index = Hash.new{|h,k| h[k] = k.merge(as => empty_group) }
|
|
37
|
+
attrs = attrs_index
|
|
37
38
|
operand.each do |tuple|
|
|
38
39
|
key = TupleAlgebra.allbut(tuple, attrs)
|
|
39
40
|
sub = TupleAlgebra.project(tuple, attrs)
|
|
@@ -76,6 +77,10 @@ module Bmg
|
|
|
76
77
|
|
|
77
78
|
private
|
|
78
79
|
|
|
80
|
+
def attrs_index
|
|
81
|
+
@attrs_index ||= TupleAlgebra.membership(attrs)
|
|
82
|
+
end
|
|
83
|
+
|
|
79
84
|
def empty_group
|
|
80
85
|
Relation::InMemory.new(group_type, Set.new)
|
|
81
86
|
end
|
data/lib/bmg/operator/image.rb
CHANGED
|
@@ -34,6 +34,8 @@ module Bmg
|
|
|
34
34
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
EMPTY_BUTLIST = [].freeze
|
|
38
|
+
|
|
37
39
|
def initialize(type, left, right, as, on, options = {})
|
|
38
40
|
@type = type
|
|
39
41
|
@left = left
|
|
@@ -91,8 +93,9 @@ module Bmg
|
|
|
91
93
|
index = build_right_index(right_rel)
|
|
92
94
|
|
|
93
95
|
# each left with image from right index
|
|
96
|
+
on = on_index
|
|
94
97
|
left_rel.each do |tuple|
|
|
95
|
-
key =
|
|
98
|
+
key = TupleAlgebra.project(tuple, on)
|
|
96
99
|
image = index[key] || (options[:array] ? [] : empty_image)
|
|
97
100
|
yield tuple.merge(as => image)
|
|
98
101
|
end
|
|
@@ -100,10 +103,11 @@ module Bmg
|
|
|
100
103
|
|
|
101
104
|
def build_right_index(right)
|
|
102
105
|
index = Hash.new{|h,k| h[k] = empty_image }
|
|
103
|
-
|
|
106
|
+
on = on_index
|
|
107
|
+
butlist = options[:preserve] ? EMPTY_BUTLIST : on
|
|
104
108
|
right.each_with_object(index) do |t, index|
|
|
105
|
-
key =
|
|
106
|
-
index[key].operand <<
|
|
109
|
+
key = TupleAlgebra.project(t, on)
|
|
110
|
+
index[key].operand << TupleAlgebra.allbut(t, butlist)
|
|
107
111
|
end
|
|
108
112
|
if opt = options[:array]
|
|
109
113
|
sorter = to_sorter(opt)
|
|
@@ -252,12 +256,8 @@ module Bmg
|
|
|
252
256
|
|
|
253
257
|
private
|
|
254
258
|
|
|
255
|
-
def
|
|
256
|
-
TupleAlgebra.
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
def tuple_allbut(tuple, butlist)
|
|
260
|
-
TupleAlgebra.allbut(tuple, butlist)
|
|
259
|
+
def on_index
|
|
260
|
+
@on_index ||= TupleAlgebra.membership(on)
|
|
261
261
|
end
|
|
262
262
|
|
|
263
263
|
def image_type
|
data/lib/bmg/operator/join.rb
CHANGED
|
@@ -27,13 +27,14 @@ module Bmg
|
|
|
27
27
|
def each
|
|
28
28
|
return to_enum unless block_given?
|
|
29
29
|
index = Hash.new
|
|
30
|
+
on = on_index
|
|
30
31
|
right.each_with_object(index) do |t, index|
|
|
31
|
-
key =
|
|
32
|
+
key = TupleAlgebra.project(t, on)
|
|
32
33
|
index[key] ||= []
|
|
33
34
|
index[key] << t
|
|
34
35
|
end
|
|
35
36
|
left.each do |tuple|
|
|
36
|
-
key =
|
|
37
|
+
key = TupleAlgebra.project(tuple, on)
|
|
37
38
|
if to_join = index[key]
|
|
38
39
|
to_join.each do |right|
|
|
39
40
|
yield right.merge(tuple)
|
|
@@ -113,8 +114,8 @@ module Bmg
|
|
|
113
114
|
|
|
114
115
|
private
|
|
115
116
|
|
|
116
|
-
def
|
|
117
|
-
TupleAlgebra.
|
|
117
|
+
def on_index
|
|
118
|
+
@on_index ||= TupleAlgebra.membership(on)
|
|
118
119
|
end
|
|
119
120
|
|
|
120
121
|
end # class Join
|
|
@@ -25,12 +25,13 @@ module Bmg
|
|
|
25
25
|
def each
|
|
26
26
|
return to_enum unless block_given?
|
|
27
27
|
index = Hash.new
|
|
28
|
+
on = on_index
|
|
28
29
|
right.each_with_object(index) do |t, index|
|
|
29
|
-
key =
|
|
30
|
+
key = TupleAlgebra.project(t, on)
|
|
30
31
|
index[key] = true
|
|
31
32
|
end
|
|
32
33
|
left.each do |tuple|
|
|
33
|
-
key =
|
|
34
|
+
key = TupleAlgebra.project(tuple, on)
|
|
34
35
|
yield tuple if index.has_key?(key)
|
|
35
36
|
end
|
|
36
37
|
end
|
|
@@ -73,8 +74,8 @@ module Bmg
|
|
|
73
74
|
|
|
74
75
|
private
|
|
75
76
|
|
|
76
|
-
def
|
|
77
|
-
TupleAlgebra.
|
|
77
|
+
def on_index
|
|
78
|
+
@on_index ||= TupleAlgebra.membership(on)
|
|
78
79
|
end
|
|
79
80
|
|
|
80
81
|
end # class Matching
|
|
@@ -25,12 +25,13 @@ module Bmg
|
|
|
25
25
|
def each
|
|
26
26
|
return to_enum unless block_given?
|
|
27
27
|
index = Hash.new
|
|
28
|
+
on = on_index
|
|
28
29
|
right.each_with_object(index) do |t, index|
|
|
29
|
-
key =
|
|
30
|
+
key = TupleAlgebra.project(t, on)
|
|
30
31
|
index[key] = true
|
|
31
32
|
end
|
|
32
33
|
left.each do |tuple|
|
|
33
|
-
key =
|
|
34
|
+
key = TupleAlgebra.project(tuple, on)
|
|
34
35
|
yield tuple unless index.has_key?(key)
|
|
35
36
|
end
|
|
36
37
|
end
|
|
@@ -57,8 +58,8 @@ module Bmg
|
|
|
57
58
|
|
|
58
59
|
private
|
|
59
60
|
|
|
60
|
-
def
|
|
61
|
-
TupleAlgebra.
|
|
61
|
+
def on_index
|
|
62
|
+
@on_index ||= TupleAlgebra.membership(on)
|
|
62
63
|
end
|
|
63
64
|
|
|
64
65
|
end # class NotMatching
|
data/lib/bmg/operator/project.rb
CHANGED
|
@@ -80,7 +80,8 @@ module Bmg
|
|
|
80
80
|
private
|
|
81
81
|
|
|
82
82
|
def tuple_project(tuple)
|
|
83
|
-
|
|
83
|
+
attrs = (@attrs_index ||= TupleAlgebra.membership(@attrlist))
|
|
84
|
+
tuple.dup.delete_if{|k,_| !attrs.include?(k) }
|
|
84
85
|
end
|
|
85
86
|
|
|
86
87
|
def valid_tuple!(tuple)
|
|
@@ -51,8 +51,9 @@ module Bmg
|
|
|
51
51
|
}]
|
|
52
52
|
}
|
|
53
53
|
# iterate each tuple
|
|
54
|
+
by_index = TupleAlgebra.membership(@by)
|
|
54
55
|
@operand.each do |tuple|
|
|
55
|
-
key = TupleAlgebra.project(tuple,
|
|
56
|
+
key = TupleAlgebra.project(tuple, by_index)
|
|
56
57
|
# apply them all and create a new memo
|
|
57
58
|
result[key] = Hash[@summarization.map{|k,v|
|
|
58
59
|
[ k, v.happens(result[key][k], tuple) ]
|
|
@@ -70,13 +70,21 @@ module Bmg
|
|
|
70
70
|
case kind = sexpr.left.first
|
|
71
71
|
when :qualified_name
|
|
72
72
|
left.column == right.value ? left : ::Sequel.as(left, right)
|
|
73
|
-
when :literal, :summarizer, :func_call
|
|
73
|
+
when :literal, :summarizer, :func_call, :case_when
|
|
74
74
|
::Sequel.as(left, right)
|
|
75
75
|
else
|
|
76
76
|
raise NotImplementedError, "Unexpected select item `#{kind}`"
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
+
def on_case_when(sexpr)
|
|
81
|
+
operand = apply(sexpr[1])
|
|
82
|
+
mapping = sexpr[2..-1].each_slice(2).each_with_object({}){|(w, t), h|
|
|
83
|
+
h[w.last] = t.last
|
|
84
|
+
}
|
|
85
|
+
::Sequel.case(mapping, nil, operand)
|
|
86
|
+
end
|
|
87
|
+
|
|
80
88
|
def on_func_call(sexpr)
|
|
81
89
|
case sexpr.func_name
|
|
82
90
|
when :cast
|
data/lib/bmg/sql/grammar.rb
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Bmg
|
|
2
|
+
module Sql
|
|
3
|
+
module CaseWhen
|
|
4
|
+
include Expr
|
|
5
|
+
|
|
6
|
+
def operand
|
|
7
|
+
self[1]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def whens
|
|
11
|
+
self[2..-1].each_slice(2).to_a
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def is_computed?
|
|
15
|
+
true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_sql(buffer, dialect)
|
|
19
|
+
buffer << "CASE "
|
|
20
|
+
operand.to_sql(buffer, dialect)
|
|
21
|
+
whens.each do |(when_val, then_val)|
|
|
22
|
+
buffer << " WHEN "
|
|
23
|
+
when_val.to_sql(buffer, dialect)
|
|
24
|
+
buffer << " THEN "
|
|
25
|
+
then_val.to_sql(buffer, dialect)
|
|
26
|
+
end
|
|
27
|
+
buffer << " END"
|
|
28
|
+
buffer
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end # module CaseWhen
|
|
32
|
+
end # module Sql
|
|
33
|
+
end # module Bmg
|
|
@@ -50,6 +50,14 @@ module Bmg
|
|
|
50
50
|
SplitSupported.split_supported(*args, &bl)
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
# An SQL-able element the transform can emit verbatim: an object that
|
|
54
|
+
# carries its own SQL (the predicate gem's `:sql`/`:sql_literal`
|
|
55
|
+
# convention) or a Sequel expression (rendered through `Sequel.expr`).
|
|
56
|
+
def self.sql_expr?(x)
|
|
57
|
+
x.respond_to?(:sql_literal) || x.respond_to?(:sql) ||
|
|
58
|
+
(defined?(::Sequel::SQL::Expression) && x.is_a?(::Sequel::SQL::Expression))
|
|
59
|
+
end
|
|
60
|
+
|
|
53
61
|
def on_select_list(sexpr)
|
|
54
62
|
sexpr.each_with_index.map{|child,index|
|
|
55
63
|
index == 0 ? child : apply(child)
|
|
@@ -66,8 +74,17 @@ module Bmg
|
|
|
66
74
|
func_call_node(sexpr, Array(t).reverse),
|
|
67
75
|
sexpr[2]
|
|
68
76
|
])
|
|
77
|
+
when Hash
|
|
78
|
+
sexpr([:select_item,
|
|
79
|
+
case_when_node(sexpr, t),
|
|
80
|
+
sexpr[2]
|
|
81
|
+
])
|
|
69
82
|
else
|
|
70
|
-
|
|
83
|
+
# An SQL-able value (e.g. a Sequel expression) carries its own SQL
|
|
84
|
+
# — including the column reference — so it rides through as a
|
|
85
|
+
# literal, which the Sequel translator emits verbatim.
|
|
86
|
+
raise NotSupportedError unless Transform.sql_expr?(t)
|
|
87
|
+
sexpr([:select_item, [:literal, t], sexpr[2]])
|
|
71
88
|
end
|
|
72
89
|
end
|
|
73
90
|
|
|
@@ -89,6 +106,15 @@ module Bmg
|
|
|
89
106
|
[ :literal, head ] ]
|
|
90
107
|
end
|
|
91
108
|
|
|
109
|
+
def case_when_node(sexpr, mapping)
|
|
110
|
+
node = [:case_when, sexpr[1]]
|
|
111
|
+
mapping.each do |when_val, then_val|
|
|
112
|
+
node << [:literal, when_val]
|
|
113
|
+
node << [:literal, then_val]
|
|
114
|
+
end
|
|
115
|
+
node
|
|
116
|
+
end
|
|
117
|
+
|
|
92
118
|
def transformation_for(as)
|
|
93
119
|
case t = transformation
|
|
94
120
|
when Class then t
|
data/lib/bmg/sql/relation.rb
CHANGED
|
@@ -167,7 +167,8 @@ module Bmg
|
|
|
167
167
|
def _transform(type, transformation, options)
|
|
168
168
|
expr = before_use(self.expr)
|
|
169
169
|
sup, unsup = Processor::Transform.split_supported(transformation){|x|
|
|
170
|
-
[String, Integer, Float, Date, DateTime].include?(x)
|
|
170
|
+
[String, Integer, Float, Date, DateTime].include?(x) || x.is_a?(Hash) ||
|
|
171
|
+
Processor::Transform.sql_expr?(x)
|
|
171
172
|
}
|
|
172
173
|
return super if sup.nil?
|
|
173
174
|
expr = Processor::Transform.new(sup, options, builder).call(expr)
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
module Bmg
|
|
2
|
+
#
|
|
3
|
+
# Tuple-level counterparts of the relational operators.
|
|
4
|
+
#
|
|
2
5
|
module TupleAlgebra
|
|
3
6
|
|
|
7
|
+
# `allbut` and `project` below test every attribute of every tuple for
|
|
8
|
+
# membership in an attribute list, so the cost of that lookup is paid
|
|
9
|
+
# `tuples x attributes` times. Converting the list to a Set is worth it,
|
|
10
|
+
# but only past a few elements: below that an Array scan wins, on every
|
|
11
|
+
# ruby (measured in bench/set_vs_array.rb). Join keys, in particular,
|
|
12
|
+
# are usually one or two attributes and are better left alone.
|
|
13
|
+
#
|
|
14
|
+
# Callers that iterate are expected to hoist this out of their loop.
|
|
15
|
+
SET_FROM = 3
|
|
16
|
+
|
|
17
|
+
def membership(attrlist)
|
|
18
|
+
attrlist.size < SET_FROM ? attrlist : attrlist.to_set
|
|
19
|
+
end
|
|
20
|
+
module_function :membership
|
|
21
|
+
|
|
4
22
|
def allbut(tuple, butlist)
|
|
5
23
|
tuple.reject{|k,v| butlist.include?(k) }
|
|
6
24
|
end
|
data/lib/bmg/version.rb
CHANGED
data/lib/bmg.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bmg
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bernard Lambeau
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: predicate
|
|
@@ -37,6 +36,9 @@ dependencies:
|
|
|
37
36
|
- - ">="
|
|
38
37
|
- !ruby/object:Gem::Version
|
|
39
38
|
version: '2.0'
|
|
39
|
+
- - "<"
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '3.0'
|
|
40
42
|
type: :runtime
|
|
41
43
|
prerelease: false
|
|
42
44
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -44,6 +46,9 @@ dependencies:
|
|
|
44
46
|
- - ">="
|
|
45
47
|
- !ruby/object:Gem::Version
|
|
46
48
|
version: '2.0'
|
|
49
|
+
- - "<"
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '3.0'
|
|
47
52
|
- !ruby/object:Gem::Dependency
|
|
48
53
|
name: rake
|
|
49
54
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -79,6 +84,9 @@ dependencies:
|
|
|
79
84
|
- - ">="
|
|
80
85
|
- !ruby/object:Gem::Version
|
|
81
86
|
version: '2.8'
|
|
87
|
+
- - "<"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '4.0'
|
|
82
90
|
type: :development
|
|
83
91
|
prerelease: false
|
|
84
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -86,6 +94,9 @@ dependencies:
|
|
|
86
94
|
- - ">="
|
|
87
95
|
- !ruby/object:Gem::Version
|
|
88
96
|
version: '2.8'
|
|
97
|
+
- - "<"
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: '4.0'
|
|
89
100
|
- !ruby/object:Gem::Dependency
|
|
90
101
|
name: write_xlsx
|
|
91
102
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -104,44 +115,90 @@ dependencies:
|
|
|
104
115
|
name: sequel
|
|
105
116
|
requirement: !ruby/object:Gem::Requirement
|
|
106
117
|
requirements:
|
|
107
|
-
- - "
|
|
118
|
+
- - "~>"
|
|
108
119
|
- !ruby/object:Gem::Version
|
|
109
|
-
version: '0'
|
|
120
|
+
version: '5.0'
|
|
110
121
|
type: :development
|
|
111
122
|
prerelease: false
|
|
112
123
|
version_requirements: !ruby/object:Gem::Requirement
|
|
113
124
|
requirements:
|
|
114
|
-
- - "
|
|
125
|
+
- - "~>"
|
|
115
126
|
- !ruby/object:Gem::Version
|
|
116
|
-
version: '0'
|
|
127
|
+
version: '5.0'
|
|
117
128
|
- !ruby/object:Gem::Dependency
|
|
118
129
|
name: sqlite3
|
|
119
130
|
requirement: !ruby/object:Gem::Requirement
|
|
120
131
|
requirements:
|
|
121
132
|
- - ">="
|
|
122
133
|
- !ruby/object:Gem::Version
|
|
123
|
-
version: '
|
|
134
|
+
version: '1.4'
|
|
135
|
+
- - "<"
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '3.0'
|
|
124
138
|
type: :development
|
|
125
139
|
prerelease: false
|
|
126
140
|
version_requirements: !ruby/object:Gem::Requirement
|
|
127
141
|
requirements:
|
|
128
142
|
- - ">="
|
|
129
143
|
- !ruby/object:Gem::Version
|
|
130
|
-
version: '
|
|
144
|
+
version: '1.4'
|
|
145
|
+
- - "<"
|
|
146
|
+
- !ruby/object:Gem::Version
|
|
147
|
+
version: '3.0'
|
|
131
148
|
- !ruby/object:Gem::Dependency
|
|
132
149
|
name: activesupport
|
|
133
150
|
requirement: !ruby/object:Gem::Requirement
|
|
134
151
|
requirements:
|
|
135
152
|
- - ">="
|
|
136
153
|
- !ruby/object:Gem::Version
|
|
137
|
-
version: '0'
|
|
154
|
+
version: '6.0'
|
|
155
|
+
- - "<"
|
|
156
|
+
- !ruby/object:Gem::Version
|
|
157
|
+
version: '9.0'
|
|
138
158
|
type: :development
|
|
139
159
|
prerelease: false
|
|
140
160
|
version_requirements: !ruby/object:Gem::Requirement
|
|
141
161
|
requirements:
|
|
142
162
|
- - ">="
|
|
143
163
|
- !ruby/object:Gem::Version
|
|
144
|
-
version: '0'
|
|
164
|
+
version: '6.0'
|
|
165
|
+
- - "<"
|
|
166
|
+
- !ruby/object:Gem::Version
|
|
167
|
+
version: '9.0'
|
|
168
|
+
- !ruby/object:Gem::Dependency
|
|
169
|
+
name: ostruct
|
|
170
|
+
requirement: !ruby/object:Gem::Requirement
|
|
171
|
+
requirements:
|
|
172
|
+
- - ">="
|
|
173
|
+
- !ruby/object:Gem::Version
|
|
174
|
+
version: '0.2'
|
|
175
|
+
- - "<"
|
|
176
|
+
- !ruby/object:Gem::Version
|
|
177
|
+
version: '1.0'
|
|
178
|
+
type: :development
|
|
179
|
+
prerelease: false
|
|
180
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
181
|
+
requirements:
|
|
182
|
+
- - ">="
|
|
183
|
+
- !ruby/object:Gem::Version
|
|
184
|
+
version: '0.2'
|
|
185
|
+
- - "<"
|
|
186
|
+
- !ruby/object:Gem::Version
|
|
187
|
+
version: '1.0'
|
|
188
|
+
- !ruby/object:Gem::Dependency
|
|
189
|
+
name: benchmark-ips
|
|
190
|
+
requirement: !ruby/object:Gem::Requirement
|
|
191
|
+
requirements:
|
|
192
|
+
- - "~>"
|
|
193
|
+
- !ruby/object:Gem::Version
|
|
194
|
+
version: '2.14'
|
|
195
|
+
type: :development
|
|
196
|
+
prerelease: false
|
|
197
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
198
|
+
requirements:
|
|
199
|
+
- - "~>"
|
|
200
|
+
- !ruby/object:Gem::Version
|
|
201
|
+
version: '2.14'
|
|
145
202
|
description: Bmg is Alf's relational algebra for ruby, but much simpler and lighter
|
|
146
203
|
than Alf itself
|
|
147
204
|
email: blambeau@gmail.com
|
|
@@ -233,6 +290,7 @@ files:
|
|
|
233
290
|
- lib/bmg/sql/ext/predicate/tautology.rb
|
|
234
291
|
- lib/bmg/sql/grammar.rb
|
|
235
292
|
- lib/bmg/sql/grammar.sexp.yml
|
|
293
|
+
- lib/bmg/sql/nodes/case_when.rb
|
|
236
294
|
- lib/bmg/sql/nodes/column_name.rb
|
|
237
295
|
- lib/bmg/sql/nodes/cross_join.rb
|
|
238
296
|
- lib/bmg/sql/nodes/except.rb
|
|
@@ -328,11 +386,14 @@ files:
|
|
|
328
386
|
- lib/bmg/xlsx.rb
|
|
329
387
|
- tasks/gem.rake
|
|
330
388
|
- tasks/test.rake
|
|
331
|
-
homepage:
|
|
389
|
+
homepage: https://github.com/enspirit/bmg
|
|
332
390
|
licenses:
|
|
333
391
|
- MIT
|
|
334
|
-
metadata:
|
|
335
|
-
|
|
392
|
+
metadata:
|
|
393
|
+
source_code_uri: https://github.com/enspirit/bmg
|
|
394
|
+
changelog_uri: https://github.com/enspirit/bmg/blob/master/CHANGELOG.md
|
|
395
|
+
bug_tracker_uri: https://github.com/enspirit/bmg/issues
|
|
396
|
+
documentation_uri: https://www.relational-algebra.dev/
|
|
336
397
|
rdoc_options: []
|
|
337
398
|
require_paths:
|
|
338
399
|
- lib
|
|
@@ -340,15 +401,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
340
401
|
requirements:
|
|
341
402
|
- - ">="
|
|
342
403
|
- !ruby/object:Gem::Version
|
|
343
|
-
version: '
|
|
404
|
+
version: '2.7'
|
|
344
405
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
345
406
|
requirements:
|
|
346
407
|
- - ">="
|
|
347
408
|
- !ruby/object:Gem::Version
|
|
348
409
|
version: '0'
|
|
349
410
|
requirements: []
|
|
350
|
-
rubygems_version: 3.
|
|
351
|
-
signing_key:
|
|
411
|
+
rubygems_version: 3.6.9
|
|
352
412
|
specification_version: 4
|
|
353
413
|
summary: Bmg is Alf's successor.
|
|
354
414
|
test_files: []
|