factbase 0.9.6 → 0.9.8
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/Rakefile +1 -1
- data/lib/factbase/cached/cached_query.rb +3 -0
- data/lib/factbase/indexed/indexed_query.rb +3 -1
- data/lib/factbase/indexed/indexed_term.rb +2 -4
- data/lib/factbase/logged.rb +4 -3
- data/lib/factbase/query.rb +1 -1
- data/lib/factbase/rules.rb +2 -2
- data/lib/factbase/tee.rb +5 -2
- data/lib/factbase/term.rb +4 -0
- data/lib/factbase.rb +1 -1
- data/test/factbase/indexed/test_indexed_term.rb +8 -8
- data/test/factbase/terms/test_aggregates.rb +2 -2
- data/test/factbase/test_logged.rb +13 -0
- data/test/factbase/test_query.rb +18 -4
- data/test/factbase/test_tee.rb +3 -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: 1b9679d9fad6ba549ccccd428809c330ba6f2c3eefb3a8c32cd6b2ea9668f8e1
|
4
|
+
data.tar.gz: 5103850e97643459fda4640e5564fe8073bc0c949b699a325a83360bb32e7dfc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb9d62637fde56598cb1c2c01d492b6f2e0e9f144ee7eba1cbca88779be1214afc1f7ec43687baec3a9bc232ccb127856a9aad4b5732965667c2f69c91341229
|
7
|
+
data.tar.gz: 10c1b8ddeeb23a0b1ed8de099aad0bf55c2e19370fba0d6686384a24769a57f3483cb10de5313588b0607e8dee9b4484050dde929b8e7fe2a9b053a96f242b20
|
data/Rakefile
CHANGED
@@ -36,9 +36,12 @@ class Factbase::CachedQuery
|
|
36
36
|
key = "each #{@origin}" # params are ignored!
|
37
37
|
before = @cache[key]
|
38
38
|
@cache[key] = @origin.each(fb, params).to_a if before.nil?
|
39
|
+
c = 0
|
39
40
|
@cache[key].each do |f|
|
41
|
+
c += 1
|
40
42
|
yield Factbase::CachedFact.new(f, @cache)
|
41
43
|
end
|
44
|
+
c
|
42
45
|
end
|
43
46
|
|
44
47
|
# Read a single value.
|
@@ -33,9 +33,11 @@ class Factbase::IndexedQuery
|
|
33
33
|
# @return [Integer] Total number of facts yielded
|
34
34
|
def each(fb = @fb, params = {})
|
35
35
|
return to_enum(__method__, fb, params) unless block_given?
|
36
|
-
@origin.each(fb, params).to_a
|
36
|
+
a = @origin.each(fb, params).to_a
|
37
|
+
a.each do |f|
|
37
38
|
yield Factbase::IndexedFact.new(f, @idx)
|
38
39
|
end
|
40
|
+
a.size
|
39
41
|
end
|
40
42
|
|
41
43
|
# Read a single value.
|
@@ -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/logged.rb
CHANGED
@@ -138,13 +138,14 @@ class Factbase::Logged
|
|
138
138
|
def each(fb = @fb, params = {}, &)
|
139
139
|
return to_enum(__method__, fb, params) unless block_given?
|
140
140
|
start = Time.now
|
141
|
-
q = Factbase::Syntax.new(@term).to_term.to_s
|
142
141
|
r = nil
|
142
|
+
qry = @fb.query(@term, @maps)
|
143
143
|
tail =
|
144
144
|
Factbase::Logged.elapsed do
|
145
|
-
r =
|
145
|
+
r = qry.each(fb, params, &)
|
146
146
|
end
|
147
|
-
raise ".each of #{
|
147
|
+
raise ".query(#{@term.to_s.inspect}).each() of #{qry.class} returned #{r.class}" unless r.is_a?(Integer)
|
148
|
+
q = Factbase::Syntax.new(@term).to_term.to_s
|
148
149
|
if r.zero?
|
149
150
|
@tube.say(start, "Zero/#{@fb.size} facts found by '#{q}' #{tail}")
|
150
151
|
else
|
data/lib/factbase/query.rb
CHANGED
@@ -39,7 +39,7 @@ class Factbase::Query
|
|
39
39
|
# @param [Factbase] fb The factbase
|
40
40
|
# @param [Hash] params Optional params accessible in the query via the "$" symbol
|
41
41
|
# @yield [Fact] Facts one-by-one
|
42
|
-
# @return [Integer] Total number of facts yielded
|
42
|
+
# @return [Integer] Total number of facts yielded (if block given), otherwise enumerator
|
43
43
|
def each(fb = @fb, params = {})
|
44
44
|
return to_enum(__method__, fb, params) unless block_given?
|
45
45
|
yielded = 0
|
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,10 +31,13 @@ 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 = @fact[n] if r.nil?
|
39
|
+
r = [r] unless r.respond_to?(:each) || r.nil?
|
40
|
+
r
|
38
41
|
else
|
39
42
|
@fact.method_missing(*args)
|
40
43
|
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.8' 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
|
@@ -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
|
@@ -7,6 +7,7 @@ require_relative '../test__helper'
|
|
7
7
|
require 'loog'
|
8
8
|
require_relative '../../lib/factbase'
|
9
9
|
require_relative '../../lib/factbase/logged'
|
10
|
+
require_relative '../../lib/factbase/cached/cached_factbase'
|
10
11
|
|
11
12
|
# Test.
|
12
13
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
@@ -36,6 +37,18 @@ class TestLogged < Factbase::Test
|
|
36
37
|
assert_equal([42], fb.query('(agg (exists bar) (first bar))').one)
|
37
38
|
end
|
38
39
|
|
40
|
+
def test_avoid_inner_logging
|
41
|
+
buf = Loog::Buffer.new
|
42
|
+
fb = Factbase.new
|
43
|
+
fb.insert
|
44
|
+
fb.insert.bar = 42
|
45
|
+
fb = Factbase::Logged.new(Factbase::CachedFactbase.new(fb), buf)
|
46
|
+
fb.query('(agg (exists bar) (count))').one
|
47
|
+
fb.query('(join "foo<=bar" (exists bar))').each.to_a
|
48
|
+
refute_includes(buf.to_s, '\'(count)\'')
|
49
|
+
refute_includes(buf.to_s, '\'(exists bar)\'')
|
50
|
+
end
|
51
|
+
|
39
52
|
def test_with_txn
|
40
53
|
log = Loog::Buffer.new
|
41
54
|
fb = Factbase::Logged.new(Factbase.new, log)
|
data/test/factbase/test_query.rb
CHANGED
@@ -156,18 +156,22 @@ class TestQuery < Factbase::Test
|
|
156
156
|
|
157
157
|
def test_reading_one
|
158
158
|
maps = [
|
159
|
-
{ 'foo' => [42] },
|
159
|
+
{ 'foo' => [42], 'hello' => [4] },
|
160
160
|
{ 'bar' => [4, 5] }
|
161
161
|
]
|
162
162
|
with_factbases(maps) do |badge, fb|
|
163
163
|
{
|
164
|
+
'(agg (and (eq foo 42) (eq hello $v)) (min foo))' => 42,
|
165
|
+
'(agg (or (eq foo 42) (eq bar 4)) (min foo))' => 42,
|
164
166
|
'(agg (exists foo) (first foo))' => [42],
|
165
167
|
'(agg (exists z) (first z))' => nil,
|
166
168
|
'(agg (always) (count))' => 2,
|
167
169
|
'(agg (eq bar $v) (count))' => 1,
|
170
|
+
'(agg (eq foo 42) (min foo))' => 42,
|
171
|
+
'(agg (and (eq foo 42)) (min foo))' => 42,
|
168
172
|
'(agg (eq z 40) (count))' => 0
|
169
173
|
}.each do |q, expected|
|
170
|
-
result = fb.query(q).one(fb, v
|
174
|
+
result = fb.query(q).one(fb, 'v' => 4)
|
171
175
|
if expected.nil?
|
172
176
|
assert_nil(result, "#{q} -> nil in #{badge}")
|
173
177
|
else
|
@@ -190,6 +194,16 @@ class TestQuery < Factbase::Test
|
|
190
194
|
end
|
191
195
|
end
|
192
196
|
|
197
|
+
def test_finds_with_subsitution
|
198
|
+
maps = [{ 'foo' => [42] }, { 'bar' => [7] }, { 'foo' => [666] }]
|
199
|
+
with_factbases(maps) do |badge, fb|
|
200
|
+
assert_equal(1, fb.query('(eq 2 (agg (eq foo $foo) (count)))').each.to_a.size, "with #{badge}")
|
201
|
+
fb.txn do |fbt|
|
202
|
+
assert_equal(1, fbt.query('(eq 2 (agg (eq foo $foo) (count)))').each.to_a.size, "with #{badge} (txn)")
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
193
207
|
def test_scans_and_inserts
|
194
208
|
with_factbases do |_, fb|
|
195
209
|
fb.insert.foo = 42
|
@@ -277,8 +291,8 @@ class TestQuery < Factbase::Test
|
|
277
291
|
found += 1
|
278
292
|
end
|
279
293
|
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)
|
294
|
+
assert_equal(1, Factbase::Query.new(maps, '(eq foo $bar)', Factbase.new).each(Factbase.new, bar: [42]).to_a.size)
|
295
|
+
assert_equal(0, Factbase::Query.new(maps, '(eq foo $bar)', Factbase.new).each(Factbase.new, bar: [555]).to_a.size)
|
282
296
|
end
|
283
297
|
|
284
298
|
def test_with_nil_alias
|
data/test/factbase/test_tee.rb
CHANGED
@@ -37,10 +37,10 @@ class TestTee < Factbase::Test
|
|
37
37
|
map = {}
|
38
38
|
prim = Factbase::Fact.new(map)
|
39
39
|
prim.foo = 42
|
40
|
-
t = Factbase::Tee.new(Factbase::Fact.new({}), { 'bar' => 7 })
|
41
|
-
assert_equal(7, t['$bar'])
|
40
|
+
t = Factbase::Tee.new(Factbase::Fact.new({}), { 'bar' => [7] })
|
41
|
+
assert_equal([7], t['$bar'])
|
42
42
|
t = Factbase::Tee.new(prim, t)
|
43
|
-
assert_equal(7, t['$bar'])
|
43
|
+
assert_equal([7], t['$bar'])
|
44
44
|
end
|
45
45
|
|
46
46
|
def test_prints_to_string
|