bmg 0.19.1 → 0.20.1
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 +39 -2
- data/lib/bmg/operator/allbut.rb +4 -4
- data/lib/bmg/operator/constants.rb +25 -25
- data/lib/bmg/operator/extend.rb +10 -5
- 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/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 +6 -22
- data/lib/bmg/sequel.rb +1 -0
- data/lib/bmg/sql/processor/extend.rb +33 -0
- data/lib/bmg/sql/processor/reorder.rb +1 -1
- data/lib/bmg/sql/processor/where.rb +2 -1
- data/lib/bmg/sql/processor.rb +1 -0
- data/lib/bmg/sql/relation.rb +20 -3
- data/lib/bmg/version.rb +1 -1
- data/lib/bmg.rb +5 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35789fefdd2032b4e807b730fb2fc6f5abe163e1
|
4
|
+
data.tar.gz: 2f20b907d1f66560cbe802c6b3fe3e4064b7bfd0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8c1182190f70a94825505f358701e3ba728eadcfe7026da40f10b7b7dc9b2ff21d8f2f9ec2ccf24baa880b81728e9ef530830e168a33a2742a196c135445d0e5
|
7
|
+
data.tar.gz: b2e7ef1f3bf5983cfd3ff6fbaff820a04f9f118e39df88728ad6c87fec7261269b9fe22f60d44f9d141ce47c78db5e91399345475835f5c88c7b44b16a1c5873
|
data/README.md
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# Bmg, a relational algebra (Alf's successor)!
|
2
2
|
|
3
|
-
[](https://travis-ci.com/enspirit/bmg)
|
4
|
-
|
5
3
|
Bmg is a relational algebra implemented as a ruby library. It implements the
|
6
4
|
[Relation as First-Class Citizen](http://www.try-alf.org/blog/2013-10-21-relations-as-first-class-citizen)
|
7
5
|
paradigm contributed with [Alf](http://www.try-alf.org/) a few years ago.
|
@@ -18,6 +16,7 @@ further down this README.
|
|
18
16
|
* [Memory relations](#memory-relations)
|
19
17
|
* [Connecting to SQL databases](#connecting-to-sql-databases)
|
20
18
|
* [Reading files (csv, excel, text)](#reading-files-csv-excel-text)
|
19
|
+
* [Connecting to Redis databases](#connecting-to-redis-databases)
|
21
20
|
* [Your own relations](#your-own-relations)
|
22
21
|
* [List of supported operators](#supported-operators)
|
23
22
|
* [How is this different?](#how-is-this-different)
|
@@ -174,6 +173,43 @@ r.type.attrlist
|
|
174
173
|
In this scenario, non matching lines are skipped. The `:line` attribute keeps
|
175
174
|
being used to have at least one candidate key (so to speak).
|
176
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
|
+
|
177
213
|
### Your own relations
|
178
214
|
|
179
215
|
As noted earlier, Bmg has a simple relation interface where you only have to
|
@@ -210,6 +246,7 @@ r.autowrap(split: '_') # structure a flat relation, split:
|
|
210
246
|
r.autosummarize([:a, :b, ...], x: :sum) # (experimental) usual summarizers supported
|
211
247
|
r.constants(x: 12, ...) # add constant attributes (sometimes useful in unions)
|
212
248
|
r.extend(x: ->(t){ ... }, ...) # add computed attributes
|
249
|
+
r.extend(x: :y) # shortcut for r.extend(x: ->(t){ t[:y] })
|
213
250
|
r.exclude(predicate) # shortcut for restrict(!predicate)
|
214
251
|
r.group([:a, :b, ...], :x) # relation-valued attribute from attributes
|
215
252
|
r.image(right, :x, [:a, :b, ...]) # relation-valued attribute from another relation
|
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
|
@@ -160,7 +160,12 @@ module Bmg
|
|
160
160
|
|
161
161
|
def extend_it(tuple)
|
162
162
|
@extension.each_with_object(tuple.dup) { |(k,v), memo|
|
163
|
-
memo[k] = v
|
163
|
+
memo[k] = case v
|
164
|
+
when Symbol
|
165
|
+
tuple[v]
|
166
|
+
else
|
167
|
+
v.call(tuple)
|
168
|
+
end
|
164
169
|
memo
|
165
170
|
}
|
166
171
|
end
|
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
|
@@ -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
|
@@ -81,6 +81,7 @@ module Bmg
|
|
81
81
|
case sexpr.func_name
|
82
82
|
when :cast
|
83
83
|
to_cast = apply(sexpr.func_args.first)
|
84
|
+
to_cast = ::Sequel.expr(nil) if to_cast.nil?
|
84
85
|
type = sexpr.func_args.last.last
|
85
86
|
to_cast.cast(type)
|
86
87
|
else
|
@@ -178,36 +179,19 @@ module Bmg
|
|
178
179
|
sexpr.last
|
179
180
|
end
|
180
181
|
|
181
|
-
|
182
|
-
|
183
|
-
def dataset(expr)
|
184
|
-
return expr if ::Sequel::Dataset===expr
|
185
|
-
sequel_db[expr]
|
186
|
-
end
|
182
|
+
public
|
187
183
|
|
188
184
|
def compile_predicate(predicate)
|
189
185
|
PredicateTranslator.new(self).call(predicate)
|
190
186
|
end
|
191
187
|
|
192
|
-
|
193
|
-
include ::Predicate::ToSequel::Methods
|
194
|
-
|
195
|
-
def initialize(parent)
|
196
|
-
@parent = parent
|
197
|
-
end
|
198
|
-
|
199
|
-
public ### Predicate hack
|
200
|
-
|
201
|
-
def on_opaque(sexpr)
|
202
|
-
@parent.apply(sexpr.last)
|
203
|
-
end
|
188
|
+
private
|
204
189
|
|
205
|
-
def
|
206
|
-
|
190
|
+
def dataset(expr)
|
191
|
+
return expr if ::Sequel::Dataset===expr
|
192
|
+
sequel_db[expr]
|
207
193
|
end
|
208
194
|
|
209
|
-
end
|
210
|
-
|
211
195
|
end # class Translator
|
212
196
|
end # module Sequel
|
213
197
|
end # module Bmg
|
data/lib/bmg/sequel.rb
CHANGED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Bmg
|
2
|
+
module Sql
|
3
|
+
class Processor
|
4
|
+
class Extend < Processor
|
5
|
+
|
6
|
+
def initialize(extension, builder)
|
7
|
+
super(builder)
|
8
|
+
@extension = extension
|
9
|
+
end
|
10
|
+
attr_reader :extension
|
11
|
+
|
12
|
+
def on_set_operator(sexpr)
|
13
|
+
apply(builder.from_self(sexpr))
|
14
|
+
end
|
15
|
+
alias :on_union :on_set_operator
|
16
|
+
alias :on_except :on_set_operator
|
17
|
+
alias :on_intersect :on_set_operator
|
18
|
+
|
19
|
+
def on_select_star(sexpr)
|
20
|
+
raise NotImplementedError, "Extend on * is not supported"
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_select_list(sexpr)
|
24
|
+
sexpr + extension.each_pair.map{|(k,v)|
|
25
|
+
desaliased = sexpr.desaliaser[v]
|
26
|
+
[:select_item, desaliased, [:column_name, k] ]
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
end # class Extend
|
31
|
+
end # class Processor
|
32
|
+
end # module Sql
|
33
|
+
end # module Bmg
|
@@ -39,9 +39,10 @@ module Bmg
|
|
39
39
|
def falsy?(sexpr)
|
40
40
|
return false unless sexpr.respond_to?(:predicate)
|
41
41
|
return false if sexpr.predicate.nil?
|
42
|
+
|
42
43
|
left = Predicate.new(Predicate::Grammar.sexpr(sexpr.predicate)).unqualify
|
43
44
|
right = Predicate.new(Predicate::Grammar.sexpr(@predicate.sexpr)).unqualify
|
44
|
-
|
45
|
+
(left & right).contradiction?
|
45
46
|
end
|
46
47
|
|
47
48
|
end # class Where
|
data/lib/bmg/sql/processor.rb
CHANGED
@@ -71,6 +71,7 @@ require_relative 'processor/distinct'
|
|
71
71
|
require_relative 'processor/all'
|
72
72
|
require_relative 'processor/clip'
|
73
73
|
require_relative 'processor/constants'
|
74
|
+
require_relative 'processor/extend'
|
74
75
|
require_relative 'processor/star'
|
75
76
|
require_relative 'processor/rename'
|
76
77
|
require_relative 'processor/order_by'
|
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
|
|
@@ -57,6 +57,23 @@ module Bmg
|
|
57
57
|
_instance(type, builder, expr)
|
58
58
|
end
|
59
59
|
|
60
|
+
def _extend(type, extension)
|
61
|
+
supported, unsupported = {}, {}
|
62
|
+
extension.each_pair do |k,v|
|
63
|
+
(v.is_a?(Symbol) ? supported : unsupported)[k] = v
|
64
|
+
end
|
65
|
+
if supported.empty?
|
66
|
+
Operator::Extend.new(type, self, extension)
|
67
|
+
elsif unsupported.empty?
|
68
|
+
expr = Processor::Extend.new(supported, builder).call(self.expr)
|
69
|
+
_instance(type, builder, expr)
|
70
|
+
else
|
71
|
+
expr = Processor::Extend.new(supported, builder).call(self.expr)
|
72
|
+
operand = _instance(type.allbut(unsupported.keys), builder, expr)
|
73
|
+
Operator::Extend.new(type, operand, unsupported)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
60
77
|
def _join(type, right, on)
|
61
78
|
if right_expr = extract_compatible_sexpr(right)
|
62
79
|
right_expr = Processor::Requalify.new(builder).call(right_expr)
|
data/lib/bmg/version.rb
CHANGED
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.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bernard Lambeau
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-05-31 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
|
@@ -248,6 +250,7 @@ files:
|
|
248
250
|
- lib/bmg/sql/processor/clip.rb
|
249
251
|
- lib/bmg/sql/processor/constants.rb
|
250
252
|
- lib/bmg/sql/processor/distinct.rb
|
253
|
+
- lib/bmg/sql/processor/extend.rb
|
251
254
|
- lib/bmg/sql/processor/flatten.rb
|
252
255
|
- lib/bmg/sql/processor/from_self.rb
|
253
256
|
- lib/bmg/sql/processor/join.rb
|