factbase 0.9.7 → 0.9.9
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/fixtures/stories/empty.yml +2 -0
- data/lib/factbase/indexed/indexed_term.rb +2 -4
- data/lib/factbase/query.rb +1 -1
- data/lib/factbase/rules.rb +2 -2
- data/lib/factbase/tee.rb +5 -3
- data/lib/factbase/term.rb +4 -0
- data/lib/factbase.rb +1 -1
- data/test/factbase/indexed/test_indexed_query.rb +18 -0
- data/test/factbase/indexed/test_indexed_term.rb +8 -8
- data/test/factbase/terms/test_aggregates.rb +2 -2
- data/test/factbase/test_query.rb +22 -5
- data/test/factbase/test_tee.rb +10 -3
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 72ae2c1184dfd8ab966591846cd054c3155b0536d8c7f2f7acf636df1eb7e045
|
4
|
+
data.tar.gz: fcf929766bf80cc040744ce9caa719503548fac719d956f676e9604374d78b8c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d6c3b87fd94afe4fc7984ca17be09ffd6dbff5d93951e264720201e2e5680e387fc0215331af563af7cc78ac3db9e199ca8a0aadc39d989fb377b975d3e1b8d
|
7
|
+
data.tar.gz: 26c9ffe593d79fc17d80949208cc0833d4147684a0fcd221dc6abd669c545da678dc4fd52723913bc29a68662ca43cf7470a9523022d0919af6dd42a440d69ca
|
data/fixtures/stories/empty.yml
CHANGED
@@ -54,8 +54,7 @@ module Factbase::IndexedTerm
|
|
54
54
|
end
|
55
55
|
vv =
|
56
56
|
if @operands[1].is_a?(Symbol)
|
57
|
-
|
58
|
-
params[sym] || []
|
57
|
+
params[@operands[1].to_s] || []
|
59
58
|
else
|
60
59
|
[@operands[1]]
|
61
60
|
end
|
@@ -84,8 +83,7 @@ module Factbase::IndexedTerm
|
|
84
83
|
tuples = _as_tuples(
|
85
84
|
@operands.sort_by { |o| o.operands.first }.map do |o|
|
86
85
|
if o.operands[1].is_a?(Symbol)
|
87
|
-
|
88
|
-
params[sym] || []
|
86
|
+
params[o.operands[1].to_s] || []
|
89
87
|
else
|
90
88
|
[o.operands[1]]
|
91
89
|
end
|
data/lib/factbase/query.rb
CHANGED
@@ -44,7 +44,7 @@ class Factbase::Query
|
|
44
44
|
return to_enum(__method__, fb, params) unless block_given?
|
45
45
|
yielded = 0
|
46
46
|
params = params.transform_keys(&:to_s) if params.is_a?(Hash)
|
47
|
-
maybe = @term.predict(@maps, params)
|
47
|
+
maybe = @term.predict(@maps, Factbase::Tee.new({}, params))
|
48
48
|
(maybe || @maps).each do |m|
|
49
49
|
extras = {}
|
50
50
|
f = Factbase::Fact.new(m)
|
data/lib/factbase/rules.rb
CHANGED
@@ -61,7 +61,6 @@ class Factbase::Rules
|
|
61
61
|
# Fact decorator.
|
62
62
|
#
|
63
63
|
# This is an internal class, it is not supposed to be instantiated directly.
|
64
|
-
#
|
65
64
|
class Fact
|
66
65
|
def initialize(fact, check, fb)
|
67
66
|
@fact = fact
|
@@ -130,9 +129,10 @@ class Factbase::Rules
|
|
130
129
|
end
|
131
130
|
|
132
131
|
def it(fact, _fb)
|
132
|
+
return if @uid.nil?
|
133
133
|
a = fact[@uid]
|
134
134
|
return if a.nil?
|
135
|
-
@facts << a[0]
|
135
|
+
@facts << a[0]
|
136
136
|
end
|
137
137
|
|
138
138
|
def include?(fact)
|
data/lib/factbase/tee.rb
CHANGED
@@ -31,12 +31,14 @@ class Factbase::Tee
|
|
31
31
|
end
|
32
32
|
|
33
33
|
others do |*args|
|
34
|
-
if args[0].to_s == '[]' && args[1].
|
34
|
+
if args[0].to_s == '[]' && args[1].start_with?('$')
|
35
35
|
n = args[1].to_s
|
36
36
|
n = n[1..] unless @upper.is_a?(Factbase::Tee)
|
37
|
-
@upper[n]
|
37
|
+
r = @upper[n]
|
38
|
+
r = [r] unless r.respond_to?(:each) || r.nil?
|
39
|
+
r
|
38
40
|
else
|
39
|
-
@fact.
|
41
|
+
@fact.send(*args)
|
40
42
|
end
|
41
43
|
end
|
42
44
|
end
|
data/lib/factbase/term.rb
CHANGED
@@ -218,6 +218,10 @@ class Factbase::Term
|
|
218
218
|
[v]
|
219
219
|
end
|
220
220
|
end
|
221
|
+
raise 'Why not array?' unless v.is_a?(Array)
|
222
|
+
unless v.all? { |i| [Float, Integer, String, Time, TrueClass, FalseClass].any? { |t| i.is_a?(t) } }
|
223
|
+
raise 'Wrong type inside'
|
224
|
+
end
|
221
225
|
v
|
222
226
|
end
|
223
227
|
end
|
data/lib/factbase.rb
CHANGED
@@ -82,7 +82,7 @@ require 'yaml'
|
|
82
82
|
# License:: MIT
|
83
83
|
class Factbase
|
84
84
|
# Current version of the gem (changed by .rultor.yml on every release)
|
85
|
-
VERSION = '0.9.
|
85
|
+
VERSION = '0.9.9' unless const_defined?(:VERSION)
|
86
86
|
|
87
87
|
# An exception that may be thrown in a transaction, to roll it back.
|
88
88
|
class Rollback < StandardError; end
|
@@ -40,6 +40,15 @@ class TestIndexedQuery < Factbase::Test
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
+
def test_fills_up_the_index
|
44
|
+
idx = {}
|
45
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new, idx)
|
46
|
+
fb.query('(eq x 1)').each.to_a
|
47
|
+
assert_equal(1, idx.size)
|
48
|
+
fb.insert
|
49
|
+
assert_empty(idx)
|
50
|
+
end
|
51
|
+
|
43
52
|
def test_finds_by_eq_with_symbol
|
44
53
|
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
45
54
|
f = fb.insert
|
@@ -159,6 +168,15 @@ class TestIndexedQuery < Factbase::Test
|
|
159
168
|
end
|
160
169
|
end
|
161
170
|
|
171
|
+
def test_joins_simple_one
|
172
|
+
idx = {}
|
173
|
+
fb = Factbase::IndexedFactbase.new(Factbase.new, idx)
|
174
|
+
fb.insert.who = 4
|
175
|
+
fb.insert.friend = 4
|
176
|
+
assert_equal(1, fb.query('(and (exists who) (join "f<=friend" (eq friend $who)))').each.to_a.size)
|
177
|
+
assert_equal(2, idx.size)
|
178
|
+
end
|
179
|
+
|
162
180
|
def test_joins_too
|
163
181
|
fb = Factbase::IndexedFactbase.new(Factbase.new)
|
164
182
|
total = 10_000
|
@@ -19,7 +19,7 @@ class TestIndexedTerm < Factbase::Test
|
|
19
19
|
idx = {}
|
20
20
|
term.redress!(Factbase::IndexedTerm, idx:)
|
21
21
|
maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7] }, { 'foo' => [22, 42] }, { 'foo' => [] }])
|
22
|
-
n = term.predict(maps, {
|
22
|
+
n = term.predict(maps, {})
|
23
23
|
assert_equal(2, n.size)
|
24
24
|
assert_kind_of(Factbase::Taped, n)
|
25
25
|
end
|
@@ -29,7 +29,7 @@ class TestIndexedTerm < Factbase::Test
|
|
29
29
|
idx = {}
|
30
30
|
term.redress!(Factbase::IndexedTerm, idx:)
|
31
31
|
maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7] }, { 'foo' => [22, 42] }, { 'foo' => [] }])
|
32
|
-
n = term.predict(maps, {
|
32
|
+
n = term.predict(maps, {})
|
33
33
|
assert_equal(3, n.size)
|
34
34
|
assert_kind_of(Factbase::Taped, n)
|
35
35
|
end
|
@@ -39,7 +39,7 @@ class TestIndexedTerm < Factbase::Test
|
|
39
39
|
idx = {}
|
40
40
|
term.redress!(Factbase::IndexedTerm, idx:)
|
41
41
|
maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7] }, { 'foo' => [22, 42] }, { 'foo' => [] }])
|
42
|
-
n = term.predict(maps, {
|
42
|
+
n = term.predict(maps, {})
|
43
43
|
assert_equal(1, n.size)
|
44
44
|
assert_kind_of(Factbase::Taped, n)
|
45
45
|
end
|
@@ -49,7 +49,7 @@ class TestIndexedTerm < Factbase::Test
|
|
49
49
|
idx = {}
|
50
50
|
term.redress!(Factbase::IndexedTerm, idx:)
|
51
51
|
maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7], 'foo' => [22, 42] }, { 'foo' => [22] }])
|
52
|
-
n = term.predict(maps, {
|
52
|
+
n = term.predict(maps, {})
|
53
53
|
assert_equal(1, n.size)
|
54
54
|
assert_kind_of(Factbase::Taped, n)
|
55
55
|
end
|
@@ -59,13 +59,13 @@ class TestIndexedTerm < Factbase::Test
|
|
59
59
|
:and,
|
60
60
|
[
|
61
61
|
Factbase::Term.new(:eq, [:foo, 42]),
|
62
|
-
Factbase::Term.new(:eq, %i[bar $
|
62
|
+
Factbase::Term.new(:eq, %i[bar $jeff])
|
63
63
|
]
|
64
64
|
)
|
65
65
|
idx = {}
|
66
66
|
term.redress!(Factbase::IndexedTerm, idx:)
|
67
67
|
maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7], 'foo' => [22, 42] }, { 'foo' => [22, 42] }])
|
68
|
-
n = term.predict(maps, { '
|
68
|
+
n = term.predict(maps, Factbase::Tee.new({}, { 'jeff' => [7] }))
|
69
69
|
assert_equal(1, n.size)
|
70
70
|
assert_kind_of(Factbase::Taped, n)
|
71
71
|
end
|
@@ -90,7 +90,7 @@ class TestIndexedTerm < Factbase::Test
|
|
90
90
|
idx = {}
|
91
91
|
term.redress!(Factbase::IndexedTerm, idx:)
|
92
92
|
maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7], 'foo' => [22, 42] }, { 'foo' => [22, 42] }])
|
93
|
-
n = term.predict(maps, {
|
93
|
+
n = term.predict(maps, {})
|
94
94
|
assert_equal(3, n.size)
|
95
95
|
assert_kind_of(Factbase::Taped, n)
|
96
96
|
end
|
@@ -100,7 +100,7 @@ class TestIndexedTerm < Factbase::Test
|
|
100
100
|
idx = {}
|
101
101
|
term.redress!(Factbase::IndexedTerm, idx:)
|
102
102
|
maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'alpha' => [] }, {}])
|
103
|
-
n = term.predict(maps, {
|
103
|
+
n = term.predict(maps, {})
|
104
104
|
assert_nil(n)
|
105
105
|
end
|
106
106
|
end
|
@@ -57,7 +57,7 @@ class TestAggregates < Factbase::Test
|
|
57
57
|
{ 'a' => [4], 'b' => [55] }
|
58
58
|
]
|
59
59
|
t = Factbase::Syntax.new('(empty (eq b $x))').to_term
|
60
|
-
assert(t.evaluate(Factbase::Fact.new({ 'x' => 42 }), maps, Factbase.new))
|
61
|
-
refute(t.evaluate(Factbase::Fact.new({ 'x' => 44 }), maps, Factbase.new))
|
60
|
+
assert(t.evaluate(Factbase::Fact.new({ 'x' => [42] }), maps, Factbase.new))
|
61
|
+
refute(t.evaluate(Factbase::Fact.new({ 'x' => [44] }), maps, Factbase.new))
|
62
62
|
end
|
63
63
|
end
|
data/test/factbase/test_query.rb
CHANGED
@@ -116,7 +116,10 @@ class TestQuery < Factbase::Test
|
|
116
116
|
"(and (exists time) (not (\t\texists pi)))" => 1,
|
117
117
|
'(undef something)' => 3,
|
118
118
|
"(or (eq num +66) (lt time #{(Time.now - 200).utc.iso8601}))" => 1,
|
119
|
-
'(eq 3 (agg (eq num $num) (count)))' => 1
|
119
|
+
'(eq 3 (agg (eq num $num) (count)))' => 1,
|
120
|
+
'(and (eq num 42) (not (empty (eq name "Jeff"))))' => 2,
|
121
|
+
'(and (eq num 42) (empty (eq x $name)))' => 2,
|
122
|
+
'(and (eq num 42) (not (empty (eq name $name))))' => 2
|
120
123
|
}
|
121
124
|
maps = [
|
122
125
|
{ 'num' => [42], 'name' => ['Jeff'] },
|
@@ -156,18 +159,22 @@ class TestQuery < Factbase::Test
|
|
156
159
|
|
157
160
|
def test_reading_one
|
158
161
|
maps = [
|
159
|
-
{ 'foo' => [42] },
|
162
|
+
{ 'foo' => [42], 'hello' => [4] },
|
160
163
|
{ 'bar' => [4, 5] }
|
161
164
|
]
|
162
165
|
with_factbases(maps) do |badge, fb|
|
163
166
|
{
|
167
|
+
'(agg (and (eq foo 42) (eq hello $v)) (min foo))' => 42,
|
168
|
+
'(agg (or (eq foo 42) (eq bar 4)) (min foo))' => 42,
|
164
169
|
'(agg (exists foo) (first foo))' => [42],
|
165
170
|
'(agg (exists z) (first z))' => nil,
|
166
171
|
'(agg (always) (count))' => 2,
|
167
172
|
'(agg (eq bar $v) (count))' => 1,
|
173
|
+
'(agg (eq foo 42) (min foo))' => 42,
|
174
|
+
'(agg (and (eq foo 42)) (min foo))' => 42,
|
168
175
|
'(agg (eq z 40) (count))' => 0
|
169
176
|
}.each do |q, expected|
|
170
|
-
result = fb.query(q).one(fb, v
|
177
|
+
result = fb.query(q).one(fb, 'v' => 4)
|
171
178
|
if expected.nil?
|
172
179
|
assert_nil(result, "#{q} -> nil in #{badge}")
|
173
180
|
else
|
@@ -190,6 +197,16 @@ class TestQuery < Factbase::Test
|
|
190
197
|
end
|
191
198
|
end
|
192
199
|
|
200
|
+
def test_finds_with_subsitution
|
201
|
+
maps = [{ 'foo' => [42] }, { 'bar' => [7] }, { 'foo' => [666] }]
|
202
|
+
with_factbases(maps) do |badge, fb|
|
203
|
+
assert_equal(0, fb.query('(eq 2 (agg (eq foo $foo) (count)))').each.to_a.size, "with #{badge}")
|
204
|
+
fb.txn do |fbt|
|
205
|
+
assert_equal(0, fbt.query('(eq 2 (agg (eq foo $foo) (count)))').each.to_a.size, "with #{badge} (txn)")
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
193
210
|
def test_scans_and_inserts
|
194
211
|
with_factbases do |_, fb|
|
195
212
|
fb.insert.foo = 42
|
@@ -277,8 +294,8 @@ class TestQuery < Factbase::Test
|
|
277
294
|
found += 1
|
278
295
|
end
|
279
296
|
assert_equal(1, found)
|
280
|
-
assert_equal(1, Factbase::Query.new(maps, '(eq foo $bar)', Factbase.new).each(Factbase.new, bar: 42).to_a.size)
|
281
|
-
assert_equal(0, Factbase::Query.new(maps, '(eq foo $bar)', Factbase.new).each(Factbase.new, bar: 555).to_a.size)
|
297
|
+
assert_equal(1, Factbase::Query.new(maps, '(eq foo $bar)', Factbase.new).each(Factbase.new, bar: [42]).to_a.size)
|
298
|
+
assert_equal(0, Factbase::Query.new(maps, '(eq foo $bar)', Factbase.new).each(Factbase.new, bar: [555]).to_a.size)
|
282
299
|
end
|
283
300
|
|
284
301
|
def test_with_nil_alias
|
data/test/factbase/test_tee.rb
CHANGED
@@ -23,6 +23,13 @@ class TestTee < Factbase::Test
|
|
23
23
|
assert_equal([13], t['$bar'])
|
24
24
|
end
|
25
25
|
|
26
|
+
def test_no_trip_to_prim_if_not_found
|
27
|
+
prim = Factbase::Fact.new({})
|
28
|
+
prim.foo = 777
|
29
|
+
t = Factbase::Tee.new(prim, Factbase::Fact.new({}))
|
30
|
+
assert_nil(t['$foo'])
|
31
|
+
end
|
32
|
+
|
26
33
|
def test_all_properties
|
27
34
|
prim = Factbase::Fact.new({})
|
28
35
|
prim.foo = 42
|
@@ -37,10 +44,10 @@ class TestTee < Factbase::Test
|
|
37
44
|
map = {}
|
38
45
|
prim = Factbase::Fact.new(map)
|
39
46
|
prim.foo = 42
|
40
|
-
t = Factbase::Tee.new(Factbase::Fact.new({}), { 'bar' => 7 })
|
41
|
-
assert_equal(7, t['$bar'])
|
47
|
+
t = Factbase::Tee.new(Factbase::Fact.new({}), { 'bar' => [7] })
|
48
|
+
assert_equal([7], t['$bar'])
|
42
49
|
t = Factbase::Tee.new(prim, t)
|
43
|
-
assert_equal(7, t['$bar'])
|
50
|
+
assert_equal([7], t['$bar'])
|
44
51
|
end
|
45
52
|
|
46
53
|
def test_prints_to_string
|