factbase 0.7.5 → 0.9.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/.rubocop.yml +1 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +3 -3
- data/README.md +24 -27
- data/REUSE.toml +7 -2
- data/Rakefile +8 -1
- data/benchmark/bench_factbase.rb +1 -1
- data/fixtures/stories/agg.yml +17 -0
- data/fixtures/stories/always.yml +16 -0
- data/fixtures/stories/as.yml +16 -0
- data/fixtures/stories/count.yml +18 -0
- data/fixtures/stories/eq.yml +30 -0
- data/fixtures/stories/gt.yml +18 -0
- data/fixtures/stories/join.yml +19 -0
- data/fixtures/stories/max.yml +14 -0
- data/fixtures/stories/min.yml +14 -0
- data/fixtures/stories/nth.yml +14 -0
- data/fixtures/stories/or.yml +18 -0
- data/fixtures/stories/sprintf.yml +12 -0
- data/fixtures/stories/sum.yml +14 -0
- data/lib/factbase/cached/cached_fact.rb +28 -0
- data/lib/factbase/cached/cached_factbase.rb +64 -0
- data/lib/factbase/cached/cached_query.rb +61 -0
- data/lib/factbase/cached/cached_term.rb +25 -0
- data/lib/factbase/fact.rb +13 -13
- data/lib/factbase/indexed/indexed_fact.rb +28 -0
- data/lib/factbase/indexed/indexed_factbase.rb +64 -0
- data/lib/factbase/indexed/indexed_query.rb +56 -0
- data/lib/factbase/indexed/indexed_term.rb +60 -0
- data/lib/factbase/light.rb +7 -6
- data/lib/factbase/logged.rb +70 -35
- data/lib/factbase/query.rb +29 -34
- data/lib/factbase/rules.rb +15 -14
- data/lib/factbase/sync/sync_factbase.rb +57 -0
- data/lib/factbase/sync/sync_query.rb +61 -0
- data/lib/factbase/syntax.rb +16 -26
- data/lib/factbase/tallied.rb +10 -9
- data/lib/factbase/taped.rb +8 -0
- data/lib/factbase/tee.rb +2 -0
- data/lib/factbase/term.rb +45 -17
- data/lib/factbase/terms/aggregates.rb +17 -15
- data/lib/factbase/terms/aliases.rb +4 -4
- data/lib/factbase/terms/casting.rb +8 -8
- data/lib/factbase/terms/debug.rb +2 -2
- data/lib/factbase/terms/defn.rb +3 -3
- data/lib/factbase/terms/logical.rb +53 -14
- data/lib/factbase/terms/math.rb +26 -26
- data/lib/factbase/terms/meta.rb +14 -14
- data/lib/factbase/terms/ordering.rb +4 -4
- data/lib/factbase/terms/strings.rb +8 -8
- data/lib/factbase/terms/system.rb +3 -3
- data/lib/factbase.rb +67 -55
- data/test/factbase/cached/test_cached_factbase.rb +22 -0
- data/test/factbase/cached/test_cached_query.rb +79 -0
- data/test/factbase/indexed/test_indexed_query.rb +175 -0
- data/test/factbase/sync/test_sync_query.rb +30 -0
- data/test/factbase/terms/test_aggregates.rb +5 -5
- data/test/factbase/terms/test_aliases.rb +7 -7
- data/test/factbase/terms/test_casting.rb +8 -8
- data/test/factbase/terms/test_debug.rb +6 -6
- data/test/factbase/terms/test_defn.rb +14 -14
- data/test/factbase/terms/test_logical.rb +17 -19
- data/test/factbase/terms/test_math.rb +63 -61
- data/test/factbase/terms/test_meta.rb +36 -36
- data/test/factbase/terms/test_ordering.rb +9 -9
- data/test/factbase/terms/test_strings.rb +10 -10
- data/test/factbase/terms/test_system.rb +6 -6
- data/test/factbase/test_accum.rb +5 -5
- data/test/factbase/test_fact.rb +12 -12
- data/test/factbase/test_logged.rb +7 -0
- data/test/factbase/test_query.rb +99 -37
- data/test/factbase/test_rules.rb +1 -1
- data/test/factbase/test_syntax.rb +24 -11
- data/test/factbase/test_tee.rb +8 -8
- data/test/factbase/test_term.rb +39 -30
- data/test/test__helper.rb +2 -2
- data/test/test_factbase.rb +6 -0
- metadata +29 -4
- data/lib/factbase/query_once.rb +0 -54
- data/lib/factbase/term_once.rb +0 -67
@@ -18,7 +18,7 @@ class TestSyntax < Factbase::Test
|
|
18
18
|
"(foo 'one two three ')",
|
19
19
|
"(foo 'one two three ' 'tail tail')"
|
20
20
|
].each do |q|
|
21
|
-
assert_equal(q, Factbase::Syntax.new(
|
21
|
+
assert_equal(q, Factbase::Syntax.new(q).to_term.to_s, q)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -28,7 +28,7 @@ class TestSyntax < Factbase::Test
|
|
28
28
|
'(foo (bar (a (b c (f $bar)))))' => true,
|
29
29
|
'(foo (bar (a (b c (f bar)))))' => false
|
30
30
|
}.each do |q, a|
|
31
|
-
assert_equal(a, Factbase::Syntax.new(
|
31
|
+
assert_equal(a, Factbase::Syntax.new(q).to_term.abstract?)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
@@ -38,7 +38,7 @@ class TestSyntax < Factbase::Test
|
|
38
38
|
'(foo "bar")' => true,
|
39
39
|
'(agg (always) (max id))' => true
|
40
40
|
}.each do |q, a|
|
41
|
-
assert_equal(a, Factbase::Syntax.new(
|
41
|
+
assert_equal(a, Factbase::Syntax.new(q).to_term.static?)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -53,7 +53,7 @@ class TestSyntax < Factbase::Test
|
|
53
53
|
"(foo 'Hello,\n\nworld!\r\t\n')\n",
|
54
54
|
"(or ( a 4) (b 5) (always) (and (always) (c 5) \t\t(r 7 w8s w8is 'Foo')))"
|
55
55
|
].each do |q|
|
56
|
-
refute_nil(Factbase::Syntax.new(
|
56
|
+
refute_nil(Factbase::Syntax.new(q).to_term)
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
@@ -73,7 +73,7 @@ class TestSyntax < Factbase::Test
|
|
73
73
|
'(eq t 3.0e+21)',
|
74
74
|
"(foo (x (f (t (y 42 'Hey you'))) (never) (r 3)) y z)"
|
75
75
|
].each do |q|
|
76
|
-
assert_equal(q, Factbase::Syntax.new(
|
76
|
+
assert_equal(q, Factbase::Syntax.new(q).to_term.to_s, q)
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
@@ -88,7 +88,7 @@ class TestSyntax < Factbase::Test
|
|
88
88
|
'(or (eq bar 888) (eq z 1))' => true,
|
89
89
|
"(or (gt bar 100) (eq foo 'Hello, world!'))" => true
|
90
90
|
}.each do |k, v|
|
91
|
-
assert_equal(v, Factbase::Syntax.new(
|
91
|
+
assert_equal(v, Factbase::Syntax.new(k).to_term.evaluate(m, [], Factbase.new), k)
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
@@ -113,33 +113,46 @@ class TestSyntax < Factbase::Test
|
|
113
113
|
'"'
|
114
114
|
].each do |q|
|
115
115
|
msg = assert_raises(q) do
|
116
|
-
Factbase::Syntax.new(
|
116
|
+
Factbase::Syntax.new(q).to_term
|
117
117
|
end.message
|
118
118
|
assert_includes(msg, q, msg)
|
119
119
|
end
|
120
120
|
end
|
121
121
|
|
122
|
+
def test_raises_on_broken_syntax
|
123
|
+
100.times do
|
124
|
+
q = [
|
125
|
+
'(', ')', '#test', '$foo', '%what',
|
126
|
+
'"hello"', '42', '+', '?', '!', '\"',
|
127
|
+
'\'', 'привет'
|
128
|
+
].shuffle.join(' . ')
|
129
|
+
assert_raises(Factbase::Syntax::Broken, q) do
|
130
|
+
Factbase::Syntax.new(q).to_term
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
122
135
|
def test_simplification
|
123
136
|
{
|
124
137
|
'(foo)' => '(foo)',
|
125
138
|
'(and (foo) (foo))' => '(foo)',
|
126
139
|
'(and (foo) (or (and (eq a 1))) (eq a 1) (foo))' => '(and (foo) (eq a 1))'
|
127
140
|
}.each do |s, t|
|
128
|
-
assert_equal(t, Factbase::Syntax.new(
|
141
|
+
assert_equal(t, Factbase::Syntax.new(s).to_term.to_s)
|
129
142
|
end
|
130
143
|
end
|
131
144
|
|
132
145
|
def test_fails_when_term_is_not_a_class
|
133
|
-
assert_raises(StandardError) { Factbase::Syntax.new(
|
146
|
+
assert_raises(StandardError) { Factbase::Syntax.new('(foo 1)', term: 'hello') }
|
134
147
|
end
|
135
148
|
|
136
149
|
def test_fails_when_term_is_wrong_class
|
137
|
-
assert_raises(StandardError) { Factbase::Syntax.new(
|
150
|
+
assert_raises(StandardError) { Factbase::Syntax.new('(bar 1)', term: String).to_term }
|
138
151
|
end
|
139
152
|
|
140
153
|
def test_fails_when_term_is_incorrectly_defined_class
|
141
154
|
assert_includes(
|
142
|
-
assert_raises(StandardError) { Factbase::Syntax.new(
|
155
|
+
assert_raises(StandardError) { Factbase::Syntax.new('(bar 1)', term: FakeTerm).to_term }.message,
|
143
156
|
'wrong number of arguments'
|
144
157
|
)
|
145
158
|
end
|
data/test/factbase/test_tee.rb
CHANGED
@@ -14,9 +14,9 @@ require_relative '../../lib/factbase/fact'
|
|
14
14
|
# License:: MIT
|
15
15
|
class TestTee < Factbase::Test
|
16
16
|
def test_two_facts
|
17
|
-
prim = Factbase::Fact.new(
|
17
|
+
prim = Factbase::Fact.new({})
|
18
18
|
prim.foo = 42
|
19
|
-
upper = Factbase::Fact.new(
|
19
|
+
upper = Factbase::Fact.new({})
|
20
20
|
upper.bar = 13
|
21
21
|
t = Factbase::Tee.new(prim, upper)
|
22
22
|
assert_equal(42, t.foo)
|
@@ -24,9 +24,9 @@ class TestTee < Factbase::Test
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def test_all_properties
|
27
|
-
prim = Factbase::Fact.new(
|
27
|
+
prim = Factbase::Fact.new({})
|
28
28
|
prim.foo = 42
|
29
|
-
upper = Factbase::Fact.new(
|
29
|
+
upper = Factbase::Fact.new({})
|
30
30
|
upper.bar = 13
|
31
31
|
t = Factbase::Tee.new(prim, upper)
|
32
32
|
assert_includes(t.all_properties, 'foo')
|
@@ -35,18 +35,18 @@ class TestTee < Factbase::Test
|
|
35
35
|
|
36
36
|
def test_recursively
|
37
37
|
map = {}
|
38
|
-
prim = Factbase::Fact.new(
|
38
|
+
prim = Factbase::Fact.new(map)
|
39
39
|
prim.foo = 42
|
40
|
-
t = Factbase::Tee.new(
|
40
|
+
t = Factbase::Tee.new(Factbase::Fact.new({}), { 'bar' => 7 })
|
41
41
|
assert_equal(7, t['$bar'])
|
42
42
|
t = Factbase::Tee.new(prim, t)
|
43
43
|
assert_equal(7, t['$bar'])
|
44
44
|
end
|
45
45
|
|
46
46
|
def test_prints_to_string
|
47
|
-
prim = Factbase::Fact.new(
|
47
|
+
prim = Factbase::Fact.new({})
|
48
48
|
prim.foo = 42
|
49
|
-
upper = Factbase::Fact.new(
|
49
|
+
upper = Factbase::Fact.new({})
|
50
50
|
upper.bar = 13
|
51
51
|
t = Factbase::Tee.new(prim, upper)
|
52
52
|
assert_equal('[ foo: [42] ]', t.to_s)
|
data/test/factbase/test_term.rb
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
5
5
|
|
6
6
|
require_relative '../test__helper'
|
7
|
+
require_relative '../../lib/factbase'
|
7
8
|
require_relative '../../lib/factbase/term'
|
8
9
|
|
9
10
|
# Term test.
|
@@ -12,65 +13,73 @@ require_relative '../../lib/factbase/term'
|
|
12
13
|
# License:: MIT
|
13
14
|
class TestTerm < Factbase::Test
|
14
15
|
def test_false_matching
|
15
|
-
t = Factbase::Term.new(
|
16
|
-
refute(t.evaluate(fact('foo' => [100]), []))
|
16
|
+
t = Factbase::Term.new(:never, [])
|
17
|
+
refute(t.evaluate(fact('foo' => [100]), [], Factbase.new))
|
17
18
|
end
|
18
19
|
|
19
20
|
def test_size_matching
|
20
|
-
t = Factbase::Term.new(
|
21
|
-
assert_equal(3, t.evaluate(fact('foo' => [42, 12, -90]), []))
|
22
|
-
assert_equal(0, t.evaluate(fact('bar' => 100), []))
|
21
|
+
t = Factbase::Term.new(:size, [:foo])
|
22
|
+
assert_equal(3, t.evaluate(fact('foo' => [42, 12, -90]), [], Factbase.new))
|
23
|
+
assert_equal(0, t.evaluate(fact('bar' => 100), [], Factbase.new))
|
23
24
|
end
|
24
25
|
|
25
26
|
def test_exists_matching
|
26
|
-
t = Factbase::Term.new(
|
27
|
-
assert(t.evaluate(fact('foo' => [42, 12, -90]), []))
|
28
|
-
refute(t.evaluate(fact('bar' => 100), []))
|
27
|
+
t = Factbase::Term.new(:exists, [:foo])
|
28
|
+
assert(t.evaluate(fact('foo' => [42, 12, -90]), [], Factbase.new))
|
29
|
+
refute(t.evaluate(fact('bar' => 100), [], Factbase.new))
|
29
30
|
end
|
30
31
|
|
31
32
|
def test_absent_matching
|
32
|
-
t = Factbase::Term.new(
|
33
|
-
assert(t.evaluate(fact('z' => [42, 12, -90]), []))
|
34
|
-
refute(t.evaluate(fact('foo' => 100), []))
|
33
|
+
t = Factbase::Term.new(:absent, [:foo])
|
34
|
+
assert(t.evaluate(fact('z' => [42, 12, -90]), [], Factbase.new))
|
35
|
+
refute(t.evaluate(fact('foo' => 100), [], Factbase.new))
|
35
36
|
end
|
36
37
|
|
37
38
|
def test_type_matching
|
38
|
-
t = Factbase::Term.new(
|
39
|
-
assert_equal('Integer', t.evaluate(fact('foo' => 42), []))
|
40
|
-
assert_equal('Integer', t.evaluate(fact('foo' => [42]), []))
|
41
|
-
assert_equal('Array', t.evaluate(fact('foo' => [1, 2, 3]), []))
|
42
|
-
assert_equal('String', t.evaluate(fact('foo' => 'Hello, world!'), []))
|
43
|
-
assert_equal('Float', t.evaluate(fact('foo' => 3.14), []))
|
44
|
-
assert_equal('Time', t.evaluate(fact('foo' => Time.now), []))
|
45
|
-
assert_equal('Integer', t.evaluate(fact('foo' => 1_000_000_000_000_000), []))
|
46
|
-
assert_equal('nil', t.evaluate(fact, []))
|
39
|
+
t = Factbase::Term.new(:type, [:foo])
|
40
|
+
assert_equal('Integer', t.evaluate(fact('foo' => 42), [], Factbase.new))
|
41
|
+
assert_equal('Integer', t.evaluate(fact('foo' => [42]), [], Factbase.new))
|
42
|
+
assert_equal('Array', t.evaluate(fact('foo' => [1, 2, 3]), [], Factbase.new))
|
43
|
+
assert_equal('String', t.evaluate(fact('foo' => 'Hello, world!'), [], Factbase.new))
|
44
|
+
assert_equal('Float', t.evaluate(fact('foo' => 3.14), [], Factbase.new))
|
45
|
+
assert_equal('Time', t.evaluate(fact('foo' => Time.now), [], Factbase.new))
|
46
|
+
assert_equal('Integer', t.evaluate(fact('foo' => 1_000_000_000_000_000), [], Factbase.new))
|
47
|
+
assert_equal('nil', t.evaluate(fact, [], Factbase.new))
|
47
48
|
end
|
48
49
|
|
49
50
|
def test_past
|
50
|
-
t = Factbase::Term.new(
|
51
|
-
assert_nil(t.evaluate(fact('foo' => 4), []))
|
52
|
-
assert_equal([4], t.evaluate(fact('foo' => 5), []))
|
51
|
+
t = Factbase::Term.new(:prev, [:foo])
|
52
|
+
assert_nil(t.evaluate(fact('foo' => 4), [], Factbase.new))
|
53
|
+
assert_equal([4], t.evaluate(fact('foo' => 5), [], Factbase.new))
|
53
54
|
end
|
54
55
|
|
55
56
|
def test_at
|
56
|
-
t = Factbase::Term.new(
|
57
|
-
assert_nil(t.evaluate(fact('foo' => 4), []))
|
58
|
-
assert_equal(5, t.evaluate(fact('foo' => [4, 5]), []))
|
57
|
+
t = Factbase::Term.new(:at, [1, :foo])
|
58
|
+
assert_nil(t.evaluate(fact('foo' => 4), [], Factbase.new))
|
59
|
+
assert_equal(5, t.evaluate(fact('foo' => [4, 5]), [], Factbase.new))
|
59
60
|
end
|
60
61
|
|
61
62
|
def test_report_missing_term
|
62
|
-
t = Factbase::Term.new(
|
63
|
+
t = Factbase::Term.new(:something, [])
|
63
64
|
msg = assert_raises(StandardError) do
|
64
|
-
t.evaluate(fact, [])
|
65
|
+
t.evaluate(fact, [], Factbase.new)
|
65
66
|
end.message
|
66
67
|
assert_includes(msg, 'not defined at (something)', msg)
|
67
68
|
end
|
68
69
|
|
69
70
|
def test_report_other_error
|
70
|
-
t = Factbase::Term.new(
|
71
|
+
t = Factbase::Term.new(:at, [])
|
71
72
|
msg = assert_raises(StandardError) do
|
72
|
-
t.evaluate(fact, [])
|
73
|
+
t.evaluate(fact, [], Factbase.new)
|
73
74
|
end.message
|
74
75
|
assert_includes(msg, 'at (at)', msg)
|
75
76
|
end
|
77
|
+
|
78
|
+
def test_redresses_itself
|
79
|
+
t = Factbase::Term.new(:something, [])
|
80
|
+
require_relative '../../lib/factbase/indexed/indexed_term'
|
81
|
+
t.redress!(Factbase::IndexedTerm)
|
82
|
+
require_relative '../../lib/factbase/cached/cached_term'
|
83
|
+
t.redress!(Factbase::CachedTerm)
|
84
|
+
end
|
76
85
|
end
|
data/test/test__helper.rb
CHANGED
@@ -22,7 +22,7 @@ require_relative '../lib/factbase'
|
|
22
22
|
# Default methods for all tests.
|
23
23
|
class Factbase::Test < Minitest::Test
|
24
24
|
def fact(map = {})
|
25
|
-
|
26
|
-
Factbase::Fact.new(
|
25
|
+
require_relative '../lib/factbase/fact'
|
26
|
+
Factbase::Fact.new(map)
|
27
27
|
end
|
28
28
|
end
|
data/test/test_factbase.rb
CHANGED
@@ -41,6 +41,12 @@ class TestFactbase < Factbase::Test
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
def test_converts_query_to_term
|
45
|
+
fb = Factbase.new
|
46
|
+
term = fb.to_term('(eq foo 42)')
|
47
|
+
assert_equal('(eq foo 42)', term.to_s)
|
48
|
+
end
|
49
|
+
|
44
50
|
def test_simple_setting
|
45
51
|
fb = Factbase.new
|
46
52
|
fb.insert
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factbase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-03-
|
10
|
+
date: 2025-03-12 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: backtrace
|
@@ -162,24 +162,45 @@ files:
|
|
162
162
|
- benchmark/bench_query.rb
|
163
163
|
- benchmark/bench_taped.rb
|
164
164
|
- factbase.gemspec
|
165
|
+
- fixtures/stories/agg.yml
|
166
|
+
- fixtures/stories/always.yml
|
167
|
+
- fixtures/stories/as.yml
|
168
|
+
- fixtures/stories/count.yml
|
169
|
+
- fixtures/stories/eq.yml
|
170
|
+
- fixtures/stories/gt.yml
|
171
|
+
- fixtures/stories/join.yml
|
172
|
+
- fixtures/stories/max.yml
|
173
|
+
- fixtures/stories/min.yml
|
174
|
+
- fixtures/stories/nth.yml
|
175
|
+
- fixtures/stories/or.yml
|
176
|
+
- fixtures/stories/sprintf.yml
|
177
|
+
- fixtures/stories/sum.yml
|
165
178
|
- lib/factbase.rb
|
166
179
|
- lib/factbase/accum.rb
|
180
|
+
- lib/factbase/cached/cached_fact.rb
|
181
|
+
- lib/factbase/cached/cached_factbase.rb
|
182
|
+
- lib/factbase/cached/cached_query.rb
|
183
|
+
- lib/factbase/cached/cached_term.rb
|
167
184
|
- lib/factbase/churn.rb
|
168
185
|
- lib/factbase/fact.rb
|
169
186
|
- lib/factbase/flatten.rb
|
187
|
+
- lib/factbase/indexed/indexed_fact.rb
|
188
|
+
- lib/factbase/indexed/indexed_factbase.rb
|
189
|
+
- lib/factbase/indexed/indexed_query.rb
|
190
|
+
- lib/factbase/indexed/indexed_term.rb
|
170
191
|
- lib/factbase/inv.rb
|
171
192
|
- lib/factbase/light.rb
|
172
193
|
- lib/factbase/logged.rb
|
173
194
|
- lib/factbase/pre.rb
|
174
195
|
- lib/factbase/query.rb
|
175
|
-
- lib/factbase/query_once.rb
|
176
196
|
- lib/factbase/rules.rb
|
197
|
+
- lib/factbase/sync/sync_factbase.rb
|
198
|
+
- lib/factbase/sync/sync_query.rb
|
177
199
|
- lib/factbase/syntax.rb
|
178
200
|
- lib/factbase/tallied.rb
|
179
201
|
- lib/factbase/taped.rb
|
180
202
|
- lib/factbase/tee.rb
|
181
203
|
- lib/factbase/term.rb
|
182
|
-
- lib/factbase/term_once.rb
|
183
204
|
- lib/factbase/terms/aggregates.rb
|
184
205
|
- lib/factbase/terms/aliases.rb
|
185
206
|
- lib/factbase/terms/casting.rb
|
@@ -195,6 +216,10 @@ files:
|
|
195
216
|
- lib/factbase/to_xml.rb
|
196
217
|
- lib/factbase/to_yaml.rb
|
197
218
|
- renovate.json
|
219
|
+
- test/factbase/cached/test_cached_factbase.rb
|
220
|
+
- test/factbase/cached/test_cached_query.rb
|
221
|
+
- test/factbase/indexed/test_indexed_query.rb
|
222
|
+
- test/factbase/sync/test_sync_query.rb
|
198
223
|
- test/factbase/terms/test_aggregates.rb
|
199
224
|
- test/factbase/terms/test_aliases.rb
|
200
225
|
- test/factbase/terms/test_casting.rb
|
data/lib/factbase/query_once.rb
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
-
# SPDX-License-Identifier: MIT
|
5
|
-
|
6
|
-
require_relative '../factbase'
|
7
|
-
|
8
|
-
# Query with a cache, a decorator of another query.
|
9
|
-
#
|
10
|
-
# It is NOT thread-safe!
|
11
|
-
#
|
12
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
13
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
14
|
-
# License:: MIT
|
15
|
-
class Factbase::QueryOnce
|
16
|
-
# Constructor.
|
17
|
-
# @param [Factbase] fb Factbase
|
18
|
-
# @param [Factbase::Query] query Original query
|
19
|
-
# @param [Array<Hash>] maps Where to search
|
20
|
-
def initialize(fb, query, maps)
|
21
|
-
@fb = fb
|
22
|
-
@query = query
|
23
|
-
@maps = maps
|
24
|
-
end
|
25
|
-
|
26
|
-
# Iterate facts one by one.
|
27
|
-
# @param [Hash] params Optional params accessible in the query via the "$" symbol
|
28
|
-
# @yield [Fact] Facts one-by-one
|
29
|
-
# @return [Integer] Total number of facts yielded
|
30
|
-
def each(params = {}, &)
|
31
|
-
unless block_given?
|
32
|
-
return to_enum(__method__, params) if Factbase::Syntax.new(@fb, @query).to_term.abstract?
|
33
|
-
key = [@query.to_s, @maps.object_id]
|
34
|
-
before = @fb.cache[key]
|
35
|
-
@fb.cache[key] = to_enum(__method__, params).to_a if before.nil?
|
36
|
-
return @fb.cache[key]
|
37
|
-
end
|
38
|
-
@query.each(params, &)
|
39
|
-
end
|
40
|
-
|
41
|
-
# Read a single value.
|
42
|
-
# @param [Hash] params Optional params accessible in the query via the "$" symbol
|
43
|
-
# @return The value evaluated
|
44
|
-
def one(params = {})
|
45
|
-
@query.one(params)
|
46
|
-
end
|
47
|
-
|
48
|
-
# Delete all facts that match the query.
|
49
|
-
# @return [Integer] Total number of facts deleted
|
50
|
-
def delete!
|
51
|
-
@fb.cache.clear
|
52
|
-
@query.delete!
|
53
|
-
end
|
54
|
-
end
|
data/lib/factbase/term_once.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
|
-
# SPDX-License-Identifier: MIT
|
5
|
-
|
6
|
-
require_relative '../factbase'
|
7
|
-
|
8
|
-
# Term with a cache, a decorator of another term.
|
9
|
-
#
|
10
|
-
# It is NOT thread-safe!
|
11
|
-
#
|
12
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
13
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
14
|
-
# License:: MIT
|
15
|
-
class Factbase::TermOnce < Factbase::Term
|
16
|
-
# Constructor.
|
17
|
-
# @param [Factbase::Term] term Original term
|
18
|
-
# @param [Hash] cache The cache
|
19
|
-
def initialize(term, cache)
|
20
|
-
super(nil, nil, nil) # just to please Rubocop
|
21
|
-
@term = term
|
22
|
-
@cache = cache
|
23
|
-
@text = @term.to_s
|
24
|
-
@cacheable = @term.static? && !@term.abstract?
|
25
|
-
end
|
26
|
-
|
27
|
-
# Does it match the fact?
|
28
|
-
# @param [Factbase::Fact] fact The fact
|
29
|
-
# @param [Array<Factbase::Fact>] maps All maps available
|
30
|
-
# @return [bool] TRUE if matches
|
31
|
-
def evaluate(fact, maps)
|
32
|
-
return @term.evaluate(fact, maps) unless @cacheable
|
33
|
-
key = [@text, maps.object_id]
|
34
|
-
before = @cache[key]
|
35
|
-
@cache[key] = @term.evaluate(nil, maps) if before.nil?
|
36
|
-
@cache[key]
|
37
|
-
end
|
38
|
-
|
39
|
-
# Simplify it if possible.
|
40
|
-
# @return [Factbase::Term] New term or itself
|
41
|
-
def simplify
|
42
|
-
@term.simplify
|
43
|
-
end
|
44
|
-
|
45
|
-
# Does it have any dependencies on a fact?
|
46
|
-
#
|
47
|
-
# If a term is static, it will return the same value for +evaluate+,
|
48
|
-
# no matter what is the fact given.
|
49
|
-
#
|
50
|
-
# @return [Boolean] TRUE if static
|
51
|
-
def static?
|
52
|
-
@term.static?
|
53
|
-
end
|
54
|
-
|
55
|
-
# Does it have any variables (+$foo+, for example) inside?
|
56
|
-
#
|
57
|
-
# @return [Boolean] TRUE if abstract
|
58
|
-
def abstract?
|
59
|
-
@term.abstract?
|
60
|
-
end
|
61
|
-
|
62
|
-
# Turns it into a string.
|
63
|
-
# @return [String] The string of it
|
64
|
-
def to_s
|
65
|
-
@term.to_s
|
66
|
-
end
|
67
|
-
end
|