factbase 0.14.7 → 0.15.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/Gemfile.lock +5 -5
- data/README.md +6 -12
- data/factbase.gemspec +4 -4
- data/lib/factbase/fact.rb +1 -1
- data/lib/factbase/fact_as_yaml.rb +10 -1
- data/lib/factbase/indexed/indexed_term.rb +6 -1
- data/lib/factbase/terms/ordering.rb +17 -8
- data/lib/factbase/version.rb +1 -1
- metadata +8 -88
- data/.0pdd.yml +0 -8
- data/.gitattributes +0 -7
- data/.github/publish-benchmark.sh +0 -24
- data/.github/workflows/actionlint.yml +0 -25
- data/.github/workflows/benchmark.yml +0 -36
- data/.github/workflows/codecov.yml +0 -27
- data/.github/workflows/copyrights.yml +0 -19
- data/.github/workflows/markdown-lint.yml +0 -23
- data/.github/workflows/pdd.yml +0 -19
- data/.github/workflows/rake.yml +0 -28
- data/.github/workflows/reuse.yml +0 -19
- data/.github/workflows/typos.yml +0 -19
- data/.github/workflows/xcop.yml +0 -19
- data/.github/workflows/yamllint.yml +0 -19
- data/.gitignore +0 -11
- data/.pdd +0 -7
- data/.rubocop.yml +0 -51
- data/.rultor.yml +0 -27
- data/benchmark/bench_factbase.rb +0 -61
- data/benchmark/bench_large_query.rb +0 -128
- data/benchmark/bench_query.rb +0 -57
- data/benchmark/bench_taped.rb +0 -33
- data/fixtures/stories/agg.yml +0 -17
- data/fixtures/stories/always.yml +0 -16
- data/fixtures/stories/and.yml +0 -19
- data/fixtures/stories/as.yml +0 -16
- data/fixtures/stories/count.yml +0 -18
- data/fixtures/stories/empty.yml +0 -23
- data/fixtures/stories/eq.yml +0 -30
- data/fixtures/stories/gt.yml +0 -18
- data/fixtures/stories/join.yml +0 -22
- data/fixtures/stories/max.yml +0 -14
- data/fixtures/stories/min.yml +0 -14
- data/fixtures/stories/nth.yml +0 -14
- data/fixtures/stories/one.yml +0 -14
- data/fixtures/stories/or.yml +0 -18
- data/fixtures/stories/sprintf.yml +0 -12
- data/fixtures/stories/sum.yml +0 -14
- data/fixtures/stories/unique.yml +0 -16
- data/renovate.json +0 -6
- data/test/factbase/cached/test_cached_factbase.rb +0 -44
- data/test/factbase/cached/test_cached_query.rb +0 -100
- data/test/factbase/indexed/test_indexed_fact.rb +0 -23
- data/test/factbase/indexed/test_indexed_factbase.rb +0 -96
- data/test/factbase/indexed/test_indexed_query.rb +0 -208
- data/test/factbase/indexed/test_indexed_term.rb +0 -140
- data/test/factbase/sync/test_sync_factbase.rb +0 -22
- data/test/factbase/sync/test_sync_query.rb +0 -30
- data/test/factbase/terms/test_aggregates.rb +0 -63
- data/test/factbase/terms/test_aliases.rb +0 -58
- data/test/factbase/terms/test_casting.rb +0 -33
- data/test/factbase/terms/test_debug.rb +0 -111
- data/test/factbase/terms/test_defn.rb +0 -48
- data/test/factbase/terms/test_logical.rb +0 -57
- data/test/factbase/terms/test_math.rb +0 -122
- data/test/factbase/terms/test_meta.rb +0 -70
- data/test/factbase/terms/test_ordering.rb +0 -28
- data/test/factbase/terms/test_strings.rb +0 -36
- data/test/factbase/terms/test_system.rb +0 -31
- data/test/factbase/test_accum.rb +0 -74
- data/test/factbase/test_churn.rb +0 -41
- data/test/factbase/test_fact.rb +0 -108
- data/test/factbase/test_fact_as_yaml.rb +0 -77
- data/test/factbase/test_flatten.rb +0 -28
- data/test/factbase/test_impatient.rb +0 -176
- data/test/factbase/test_inv.rb +0 -44
- data/test/factbase/test_logged.rb +0 -155
- data/test/factbase/test_pre.rb +0 -35
- data/test/factbase/test_query.rb +0 -445
- data/test/factbase/test_rules.rb +0 -113
- data/test/factbase/test_syntax.rb +0 -166
- data/test/factbase/test_tallied.rb +0 -81
- data/test/factbase/test_taped.rb +0 -72
- data/test/factbase/test_tee.rb +0 -85
- data/test/factbase/test_term.rb +0 -87
- data/test/factbase/test_to_json.rb +0 -35
- data/test/factbase/test_to_xml.rb +0 -89
- data/test/factbase/test_to_yaml.rb +0 -39
- data/test/test__helper.rb +0 -41
- data/test/test_factbase.rb +0 -509
@@ -1,155 +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 '../test__helper'
|
7
|
-
require 'loog'
|
8
|
-
require_relative '../../lib/factbase'
|
9
|
-
require_relative '../../lib/factbase/logged'
|
10
|
-
require_relative '../../lib/factbase/cached/cached_factbase'
|
11
|
-
|
12
|
-
# Test.
|
13
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
14
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
15
|
-
# License:: MIT
|
16
|
-
class TestLogged < Factbase::Test
|
17
|
-
def test_simple_setting
|
18
|
-
fb = Factbase::Logged.new(Factbase.new, Loog::NULL)
|
19
|
-
fb.insert
|
20
|
-
fb.insert.bar = 3
|
21
|
-
found = 0
|
22
|
-
fb.query('(exists bar)').each do |f|
|
23
|
-
assert_predicate(f.bar, :positive?)
|
24
|
-
f.foo = 42
|
25
|
-
assert_equal(42, f.foo)
|
26
|
-
found += 1
|
27
|
-
end
|
28
|
-
assert_equal(1, found)
|
29
|
-
assert_equal(2, fb.size)
|
30
|
-
end
|
31
|
-
|
32
|
-
def test_reading_one
|
33
|
-
fb = Factbase::Logged.new(Factbase.new, Loog::NULL)
|
34
|
-
fb.insert
|
35
|
-
fb.insert.bar = 42
|
36
|
-
assert_equal(1, fb.query('(agg (exists bar) (count))').one)
|
37
|
-
assert_equal([42], fb.query('(agg (exists bar) (first bar))').one)
|
38
|
-
end
|
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
|
-
|
52
|
-
def test_with_txn
|
53
|
-
log = Loog::Buffer.new
|
54
|
-
fb = Factbase::Logged.new(Factbase.new, log)
|
55
|
-
assert(
|
56
|
-
fb.txn do |fbt|
|
57
|
-
fbt.insert.foo = 42
|
58
|
-
end
|
59
|
-
)
|
60
|
-
assert_equal(1, fb.size)
|
61
|
-
assert_includes(log.to_s, 'touched', log)
|
62
|
-
end
|
63
|
-
|
64
|
-
def test_with_slow_txn
|
65
|
-
log = Loog::Buffer.new
|
66
|
-
fb = Factbase::Logged.new(Factbase.new, log, time_tolerate: 0.1)
|
67
|
-
fb.txn { sleep 0.4 }
|
68
|
-
assert_includes(log.to_s, '(slow!)', log)
|
69
|
-
end
|
70
|
-
|
71
|
-
def test_with_txn_rollback
|
72
|
-
log = Loog::Buffer.new
|
73
|
-
fb = Factbase::Logged.new(Factbase.new, log)
|
74
|
-
assert_equal(0, fb.txn { raise Factbase::Rollback })
|
75
|
-
assert_equal(0, fb.size)
|
76
|
-
assert_includes(log.to_s, 'rolled back', log)
|
77
|
-
refute_includes(log.to_s, 'didn\'t touch', log)
|
78
|
-
end
|
79
|
-
|
80
|
-
def test_with_modifying_txn
|
81
|
-
log = Loog::Buffer.new
|
82
|
-
fb = Factbase::Logged.new(Factbase.new, log)
|
83
|
-
fb.insert.foo = 1
|
84
|
-
assert_equal(0, fb.txn { |fbt| fbt.query('(always)').each.to_a }.to_i, log)
|
85
|
-
assert_equal(1, fb.txn { |fbt| fbt.query('(always)').each.to_a[0].foo = 42 }.to_i)
|
86
|
-
assert_includes(log.to_s, 'touched', log)
|
87
|
-
end
|
88
|
-
|
89
|
-
def test_with_empty_txn
|
90
|
-
log = Loog::Buffer.new
|
91
|
-
fb = Factbase::Logged.new(Factbase.new, log)
|
92
|
-
assert_equal(0, fb.txn { |fbt| fbt.query('(always)').each.to_a }.to_i)
|
93
|
-
assert_includes(log.to_s, 'touched', log)
|
94
|
-
end
|
95
|
-
|
96
|
-
def test_returns_int
|
97
|
-
fb = Factbase.new
|
98
|
-
fb.insert
|
99
|
-
fb.insert
|
100
|
-
assert_equal(2, Factbase::Logged.new(fb, Loog::NULL).query('(always)').each(&:to_s))
|
101
|
-
end
|
102
|
-
|
103
|
-
def test_returns_int_when_empty
|
104
|
-
fb = Factbase.new
|
105
|
-
assert_equal(0, Factbase::Logged.new(fb, Loog::NULL).query('(always)').each(&:to_s))
|
106
|
-
end
|
107
|
-
|
108
|
-
def test_returns_to_s_correctly
|
109
|
-
fb = Factbase.new
|
110
|
-
q = '(always)'
|
111
|
-
assert_equal(q, fb.query(q).to_s)
|
112
|
-
end
|
113
|
-
|
114
|
-
def test_logs_when_enumerator
|
115
|
-
fb = Factbase::Logged.new(Factbase.new, Loog::NULL)
|
116
|
-
assert_equal(0, fb.query('(always)').each.to_a.size)
|
117
|
-
fb.insert
|
118
|
-
assert_equal(1, fb.query('(always)').each.to_a.size)
|
119
|
-
end
|
120
|
-
|
121
|
-
def test_proper_logging
|
122
|
-
log = Loog::Buffer.new
|
123
|
-
fb = Factbase::Logged.new(Factbase.new, log)
|
124
|
-
fb.insert
|
125
|
-
fb.insert.bar = 3
|
126
|
-
fb.insert
|
127
|
-
fb.insert.str =
|
128
|
-
"Он поскорей звонит. Вбегает
|
129
|
-
К нему слуга француз Гильо,
|
130
|
-
Халат и туфли предлагает
|
131
|
-
И подает ему белье.
|
132
|
-
Спешит Онегин одеваться,
|
133
|
-
Слуге велит приготовляться
|
134
|
-
С ним вместе ехать и с собой
|
135
|
-
Взять также ящик боевой.
|
136
|
-
Готовы санки беговые.
|
137
|
-
Он сел, на мельницу летит.
|
138
|
-
Примчались. Он слуге велит
|
139
|
-
Лепажа стволы роковые
|
140
|
-
Нести за ним, а лошадям
|
141
|
-
Отъехать в поле к двум дубкам."
|
142
|
-
fb.query('(exists bar)').each(&:to_s)
|
143
|
-
fb.query('(not (exists bar))').delete!
|
144
|
-
[
|
145
|
-
'Inserted new fact #1',
|
146
|
-
'Inserted new fact #2',
|
147
|
-
'Set \'bar\' to 3 (Integer)',
|
148
|
-
'Set \'str\' to "Он поскорей звонит. Вбегает\n ... Отъехать в поле к двум дубкам." (String)',
|
149
|
-
'Found 1/4 fact(s) by \'(exists bar)\'',
|
150
|
-
'Deleted 3 fact(s) out of 4 by \'(not (exists bar))\''
|
151
|
-
].each do |s|
|
152
|
-
assert_includes(log.to_s, s, "#{log}\n")
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
data/test/factbase/test_pre.rb
DELETED
@@ -1,35 +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 '../test__helper'
|
7
|
-
require 'loog'
|
8
|
-
require_relative '../../lib/factbase/pre'
|
9
|
-
|
10
|
-
# Test.
|
11
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
12
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
13
|
-
# License:: MIT
|
14
|
-
class TestPre < Factbase::Test
|
15
|
-
def test_simple_setting
|
16
|
-
fb = Factbase::Pre.new(Factbase.new) { |f| f.foo = 42 }
|
17
|
-
f = fb.insert
|
18
|
-
assert_equal(42, f.foo)
|
19
|
-
assert_equal(1, fb.query('(always)').each.to_a.size)
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_in_transaction
|
23
|
-
fb =
|
24
|
-
Factbase::Pre.new(Factbase.new) do |f, fbt|
|
25
|
-
f.total = fbt.size
|
26
|
-
end
|
27
|
-
fb.txn do |fbt|
|
28
|
-
fbt.insert
|
29
|
-
fbt.insert
|
30
|
-
end
|
31
|
-
arr = fb.query('(always)').each.to_a
|
32
|
-
assert_equal(1, arr[0].total)
|
33
|
-
assert_equal(2, arr[1].total)
|
34
|
-
end
|
35
|
-
end
|
data/test/factbase/test_query.rb
DELETED
@@ -1,445 +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 '../test__helper'
|
7
|
-
require 'loog'
|
8
|
-
require 'time'
|
9
|
-
require_relative '../../lib/factbase'
|
10
|
-
require_relative '../../lib/factbase/query'
|
11
|
-
require_relative '../../lib/factbase/logged'
|
12
|
-
require_relative '../../lib/factbase/pre'
|
13
|
-
require_relative '../../lib/factbase/impatient'
|
14
|
-
require_relative '../../lib/factbase/inv'
|
15
|
-
require_relative '../../lib/factbase/rules'
|
16
|
-
require_relative '../../lib/factbase/tallied'
|
17
|
-
require_relative '../../lib/factbase/cached/cached_factbase'
|
18
|
-
require_relative '../../lib/factbase/indexed/indexed_factbase'
|
19
|
-
require_relative '../../lib/factbase/sync/sync_factbase'
|
20
|
-
|
21
|
-
# Query test.
|
22
|
-
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
23
|
-
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
24
|
-
# License:: MIT
|
25
|
-
class TestQuery < Factbase::Test
|
26
|
-
def test_stories
|
27
|
-
with_factbases do |badge, fb|
|
28
|
-
Dir[File.join(__dir__, '../../fixtures/stories/**/*.yml')].each do |fixture|
|
29
|
-
base = File.basename(fixture)
|
30
|
-
story = YAML.load_file(fixture)
|
31
|
-
2.times do
|
32
|
-
fb.query('(always)').delete!
|
33
|
-
story['facts'].each do |y|
|
34
|
-
f = fb.insert
|
35
|
-
y.each do |k, vv|
|
36
|
-
vv = [vv] unless vv.is_a?(Array)
|
37
|
-
vv.each do |v|
|
38
|
-
f.send(:"#{k}=", v)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
story['queries'].each do |q|
|
43
|
-
qry = q['query']
|
44
|
-
if q['size']
|
45
|
-
size = q['size']
|
46
|
-
assert_equal(size, fb.query(qry).each.to_a.size, "#{base}: #{qry} at #{badge}")
|
47
|
-
fb.txn do |fbt|
|
48
|
-
facts = fbt.query(qry).each.to_a
|
49
|
-
assert_equal(size, facts.size, "#{base}: #{qry} at #{badge} (in txn)")
|
50
|
-
facts.each do |fact|
|
51
|
-
refute_empty(fact.all_properties)
|
52
|
-
refute_nil(fact.to_s)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
else
|
56
|
-
ret = q['one']
|
57
|
-
assert_equal(ret, fb.query(qry).one, "#{base}: #{qry} at #{badge}")
|
58
|
-
fb.txn do |fbt|
|
59
|
-
assert_equal(ret, fbt.query(qry).one, "#{base}: #{qry} at #{badge} (in txn)")
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def test_simple_parsing
|
69
|
-
maps = []
|
70
|
-
maps << { 'foo' => [42] }
|
71
|
-
q = Factbase::Query.new(maps, '(eq foo 42)', Factbase.new)
|
72
|
-
assert_equal(
|
73
|
-
1,
|
74
|
-
q.each do |f|
|
75
|
-
assert_equal(42, f.foo)
|
76
|
-
end
|
77
|
-
)
|
78
|
-
end
|
79
|
-
|
80
|
-
def test_complex_parsing
|
81
|
-
queries = {
|
82
|
-
'(eq num 444)' => 0,
|
83
|
-
'(eq hi 4)' => 1,
|
84
|
-
'(eq time 0)' => 0,
|
85
|
-
'(gt num 60)' => 1,
|
86
|
-
'(gt hi 3)' => 1,
|
87
|
-
"(and (lt pi 100) \n\n (gt num 1000))" => 0,
|
88
|
-
'(exists pi)' => 1,
|
89
|
-
'(eq pi +3.14)' => 1,
|
90
|
-
'(not (exists hello))' => 3,
|
91
|
-
'(eq "Integer" (type num))' => 2,
|
92
|
-
'(eq "Integer" (type hi))' => 1,
|
93
|
-
'(when (eq num 0) (exists time))' => 2,
|
94
|
-
'(unique num)' => 2,
|
95
|
-
'(unique name)' => 2,
|
96
|
-
'(unique pi)' => 1,
|
97
|
-
'(many num)' => 1,
|
98
|
-
'(one num)' => 2,
|
99
|
-
'(nil (agg (exists hello) (min num)))' => 3,
|
100
|
-
'(gt num (minus 1 (either (at 0 (prev num)) 0)))' => 3,
|
101
|
-
'(and (not (many num)) (eq num (plus 21 +21)))' => 1,
|
102
|
-
'(and (not (many num)) (eq num (minus -100 -142)))' => 1,
|
103
|
-
'(and (one num) (eq num (times 7 6)))' => 1,
|
104
|
-
'(and (one pi) (eq pi (div -6.28 -2)))' => 1,
|
105
|
-
'(gt (size num) 2)' => 1,
|
106
|
-
'(matches name "^[a-z]+$")' => 1,
|
107
|
-
'(matches nome "^Walter$")' => 1,
|
108
|
-
'(lt (size num) 2)' => 2,
|
109
|
-
'(eq (size _hello) 0)' => 3,
|
110
|
-
'(eq num pi)' => 0,
|
111
|
-
'(absent time)' => 2,
|
112
|
-
'(eq pi (agg (eq num 0) (sum pi)))' => 1,
|
113
|
-
'(eq num (agg (exists oops) (count)))' => 2,
|
114
|
-
'(lt num (agg (eq num 0) (max pi)))' => 2,
|
115
|
-
'(eq time (min time))' => 1,
|
116
|
-
'(and (absent time) (exists pi))' => 1,
|
117
|
-
"(and (exists time) (not (\t\texists pi)))" => 1,
|
118
|
-
'(undef something)' => 3,
|
119
|
-
"(or (eq num +66) (lt time #{(Time.now - 200).utc.iso8601}))" => 1,
|
120
|
-
'(eq 3 (agg (eq num $num) (count)))' => 1,
|
121
|
-
'(and (eq num 42) (not (empty (eq name "Jeff"))))' => 2,
|
122
|
-
'(and (eq num 42) (empty (eq x $name)))' => 2,
|
123
|
-
'(and (eq num 42) (not (empty (eq name $name))))' => 2
|
124
|
-
}
|
125
|
-
maps = [
|
126
|
-
{ 'num' => [42], 'name' => ['Jeff'] },
|
127
|
-
{ 'num' => [42, 66, 0], 'pi' => [3.14], 'name' => ['peter'] },
|
128
|
-
{ 'num' => [0], 'time' => [Time.now - 100], 'hi' => [4], 'nome' => ['Walter'] }
|
129
|
-
]
|
130
|
-
3.times do |cycle|
|
131
|
-
with_factbases(maps) do |badge, fb|
|
132
|
-
queries.each do |q, r|
|
133
|
-
assert_equal(r, fb.query(q).each.to_a.size, "#{q} in #{badge} (cycle ##{cycle})")
|
134
|
-
fb.txn do |fbt|
|
135
|
-
assert_equal(r, fbt.query(q).each.to_a.size, "#{q} in #{badge} (txn, cycle ##{cycle})")
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
def test_simple_parsing_with_time
|
143
|
-
maps = []
|
144
|
-
now = Time.now.utc
|
145
|
-
maps << { 'foo' => [now] }
|
146
|
-
q = Factbase::Query.new(maps, "(eq foo #{now.iso8601})", Factbase.new)
|
147
|
-
assert_equal(1, q.each.to_a.size)
|
148
|
-
end
|
149
|
-
|
150
|
-
def test_simple_deleting
|
151
|
-
maps = [
|
152
|
-
{ 'foo' => [42] },
|
153
|
-
{ 'bar' => [4, 5] },
|
154
|
-
{ 'bar' => [5] }
|
155
|
-
]
|
156
|
-
q = Factbase::Query.new(maps, '(eq bar 5)', Factbase.new)
|
157
|
-
assert_equal(2, q.delete!)
|
158
|
-
assert_equal(1, maps.size)
|
159
|
-
end
|
160
|
-
|
161
|
-
def test_reading_one
|
162
|
-
maps = [
|
163
|
-
{ 'foo' => [42], 'hello' => [4] },
|
164
|
-
{ 'bar' => [4, 5] }
|
165
|
-
]
|
166
|
-
with_factbases(maps) do |badge, fb|
|
167
|
-
{
|
168
|
-
'(agg (and (eq foo 42) (eq hello $v)) (min foo))' => 42,
|
169
|
-
'(agg (or (eq foo 42) (eq bar 4)) (min foo))' => 42,
|
170
|
-
'(agg (exists foo) (first foo))' => [42],
|
171
|
-
'(agg (exists z) (first z))' => nil,
|
172
|
-
'(agg (always) (count))' => 2,
|
173
|
-
'(agg (eq bar $v) (count))' => 1,
|
174
|
-
'(agg (eq foo 42) (min foo))' => 42,
|
175
|
-
'(agg (and (eq foo 42)) (min foo))' => 42,
|
176
|
-
'(agg (eq z 40) (count))' => 0
|
177
|
-
}.each do |q, expected|
|
178
|
-
result = fb.query(q).one(fb, 'v' => 4)
|
179
|
-
if expected.nil?
|
180
|
-
assert_nil(result, "#{q} -> nil in #{badge}")
|
181
|
-
else
|
182
|
-
assert_equal(expected, result, "#{q} -> #{expected} in #{badge}")
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
def test_deleting_nothing
|
189
|
-
maps = [
|
190
|
-
{ 'foo' => [42] },
|
191
|
-
{ 'bar' => [4, 5] },
|
192
|
-
{ 'bar' => [5] }
|
193
|
-
]
|
194
|
-
with_factbases(maps) do |badge, fb|
|
195
|
-
q = fb.query('(never)')
|
196
|
-
assert_equal(0, q.delete!, "#{q} in #{badge}")
|
197
|
-
assert_equal(3, maps.size, "#{q} in #{badge}")
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def test_finds_with_substitution
|
202
|
-
maps = [{ 'foo' => [42] }, { 'bar' => [7] }, { 'foo' => [666] }]
|
203
|
-
with_factbases(maps) do |badge, fb|
|
204
|
-
assert_equal(0, fb.query('(eq 2 (agg (eq foo $foo) (count)))').each.to_a.size, "with #{badge}")
|
205
|
-
fb.txn do |fbt|
|
206
|
-
assert_equal(0, fbt.query('(eq 2 (agg (eq foo $foo) (count)))').each.to_a.size, "with #{badge} (txn)")
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
def test_scans_and_inserts
|
212
|
-
with_factbases do |_, fb|
|
213
|
-
fb.insert.foo = 42
|
214
|
-
before = fb.size
|
215
|
-
more = 0
|
216
|
-
fb.query('(exists foo)').each do |f|
|
217
|
-
fb.insert.bar = f.foo
|
218
|
-
more += 1
|
219
|
-
end
|
220
|
-
assert_equal(before + more, fb.size)
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
def test_scans_and_inserts_in_txn
|
225
|
-
with_factbases do |_, fb|
|
226
|
-
fb.insert.foo = 42
|
227
|
-
before = fb.size
|
228
|
-
more = 0
|
229
|
-
fb.query('(exists foo)').each do |f|
|
230
|
-
fb.txn do |fbt|
|
231
|
-
fbt.insert.bar = f.foo
|
232
|
-
more += 1
|
233
|
-
end
|
234
|
-
end
|
235
|
-
assert_equal(before + more, fb.size)
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
def test_scans_and_inserts_in_queried_txn
|
240
|
-
with_factbases do |_, fb|
|
241
|
-
fb.insert.foo = 42
|
242
|
-
before = fb.size
|
243
|
-
more = 0
|
244
|
-
fb.txn do |fbt|
|
245
|
-
fbt.query('(exists foo)').each do |f|
|
246
|
-
fbt.insert.bar = f.foo
|
247
|
-
more += 1
|
248
|
-
end
|
249
|
-
end
|
250
|
-
assert_equal(before + more, fb.size)
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
def test_scans_and_appends_in_queried_txn
|
255
|
-
with_factbases do |badge, fb|
|
256
|
-
fb.insert.foo = 42
|
257
|
-
fb.txn do |fbt|
|
258
|
-
fbt.query('(exists foo)').each do |f|
|
259
|
-
f.bar = 33
|
260
|
-
end
|
261
|
-
refute_empty(fbt.query('(exists bar)').each.to_a, "in #{badge}")
|
262
|
-
end
|
263
|
-
refute_empty(fb.query('(exists bar)').each.to_a, "in #{badge}")
|
264
|
-
assert_empty(fb.query('(and (exists foo) (not (exists bar)))').each.to_a, "in #{badge}")
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
def test_turns_query_to_string
|
269
|
-
with_factbases do |badge, fb|
|
270
|
-
assert_equal('(always)', fb.query('(always)').to_s, "Fails with #{badge}")
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
def test_to_array
|
275
|
-
maps = []
|
276
|
-
maps << { 'foo' => [42] }
|
277
|
-
assert_equal(1, Factbase::Query.new(maps, '(eq foo 42)', Factbase.new).each.to_a.size)
|
278
|
-
end
|
279
|
-
|
280
|
-
def test_returns_int
|
281
|
-
maps = []
|
282
|
-
maps << { 'foo' => [1] }
|
283
|
-
q = Factbase::Query.new(maps, '(eq foo 1)', Factbase.new)
|
284
|
-
assert_equal(1, q.each(&:to_s))
|
285
|
-
end
|
286
|
-
|
287
|
-
def test_with_aliases
|
288
|
-
maps = []
|
289
|
-
maps << { 'foo' => [42] }
|
290
|
-
assert_equal(45, Factbase::Query.new(maps, '(as bar (plus foo 3))', Factbase.new).each.to_a[0].bar)
|
291
|
-
assert_equal(1, maps[0].size)
|
292
|
-
end
|
293
|
-
|
294
|
-
def test_with_params
|
295
|
-
maps = [
|
296
|
-
{ 'foo' => [42] },
|
297
|
-
{ 'foo' => [17] }
|
298
|
-
]
|
299
|
-
found = 0
|
300
|
-
Factbase::Query.new(maps, '(eq foo $bar)', Factbase.new).each(Factbase.new, bar: [42]) do
|
301
|
-
found += 1
|
302
|
-
end
|
303
|
-
assert_equal(1, found)
|
304
|
-
assert_equal(1, Factbase::Query.new(maps, '(eq foo $bar)', Factbase.new).each(Factbase.new, bar: [42]).to_a.size)
|
305
|
-
assert_equal(0, Factbase::Query.new(maps, '(eq foo $bar)', Factbase.new).each(Factbase.new, bar: [555]).to_a.size)
|
306
|
-
end
|
307
|
-
|
308
|
-
def test_with_nil_alias
|
309
|
-
maps = [{ 'foo' => [42] }]
|
310
|
-
assert_nil(Factbase::Query.new(maps, '(as bar (plus xxx 3))', Factbase.new).each.to_a[0]['bar'])
|
311
|
-
end
|
312
|
-
|
313
|
-
def test_get_all_properties
|
314
|
-
maps = [{ 'foo' => [42] }]
|
315
|
-
f = Factbase::Query.new(maps, '(always)', Factbase.new).each.to_a[0]
|
316
|
-
assert_includes(f.all_properties, 'foo')
|
317
|
-
end
|
318
|
-
|
319
|
-
private
|
320
|
-
|
321
|
-
def with_factbases(maps = [], &)
|
322
|
-
{
|
323
|
-
'plain' => Factbase.new(maps),
|
324
|
-
'plain+impatient' => Factbase::Impatient.new(Factbase.new(maps)),
|
325
|
-
'pre+plain' => Factbase::Pre.new(Factbase.new(maps)) { nil },
|
326
|
-
'rules+plain' => Factbase::Rules.new(Factbase.new(maps), '(always)'),
|
327
|
-
'inv+plain' => Factbase::Inv.new(Factbase.new(maps)) { nil },
|
328
|
-
'sync+plain' => Factbase::SyncFactbase.new(Factbase.new(maps)),
|
329
|
-
'tallied+plain' => Factbase::Tallied.new(Factbase.new(maps)),
|
330
|
-
'indexed+plain' => Factbase::IndexedFactbase.new(Factbase.new(maps)),
|
331
|
-
'indexed+logged+plain' => Factbase::IndexedFactbase.new(
|
332
|
-
Factbase::Logged.new(
|
333
|
-
Factbase.new(maps),
|
334
|
-
Loog::NULL
|
335
|
-
)
|
336
|
-
),
|
337
|
-
'cached+plain' => Factbase::CachedFactbase.new(Factbase.new(maps)),
|
338
|
-
'cached+logged+plain' => Factbase::CachedFactbase.new(
|
339
|
-
Factbase::Logged.new(
|
340
|
-
Factbase.new(maps),
|
341
|
-
Loog::NULL
|
342
|
-
)
|
343
|
-
),
|
344
|
-
'logged+plain' => Factbase::Logged.new(Factbase.new(maps), Loog::NULL),
|
345
|
-
'indexed+cached+plain' => Factbase::IndexedFactbase.new(
|
346
|
-
Factbase::CachedFactbase.new(Factbase.new(maps))
|
347
|
-
),
|
348
|
-
'indexed+cached+rules+plain' => Factbase::IndexedFactbase.new(
|
349
|
-
Factbase::CachedFactbase.new(
|
350
|
-
Factbase::Rules.new(
|
351
|
-
Factbase.new(maps),
|
352
|
-
'(always)',
|
353
|
-
uid: '_id'
|
354
|
-
)
|
355
|
-
)
|
356
|
-
),
|
357
|
-
'cached+indexed+plain' => Factbase::CachedFactbase.new(
|
358
|
-
Factbase::IndexedFactbase.new(Factbase.new(maps))
|
359
|
-
),
|
360
|
-
'indexed+indexed+plain' => Factbase::IndexedFactbase.new(
|
361
|
-
Factbase::IndexedFactbase.new(Factbase.new(maps))
|
362
|
-
),
|
363
|
-
'cached+cached+cached+plain' => Factbase::CachedFactbase.new(
|
364
|
-
Factbase::CachedFactbase.new(
|
365
|
-
Factbase::CachedFactbase.new(
|
366
|
-
Factbase.new(maps)
|
367
|
-
)
|
368
|
-
)
|
369
|
-
),
|
370
|
-
'tallied+pre+rules+inv+plain' => Factbase::Tallied.new(
|
371
|
-
Factbase::Pre.new(
|
372
|
-
Factbase::Rules.new(
|
373
|
-
Factbase::Inv.new(
|
374
|
-
Factbase.new(maps)
|
375
|
-
) { nil },
|
376
|
-
'(always)'
|
377
|
-
)
|
378
|
-
) { nil }
|
379
|
-
),
|
380
|
-
'sync+cached+indexed+plain' => Factbase::SyncFactbase.new(
|
381
|
-
Factbase::CachedFactbase.new(
|
382
|
-
Factbase::IndexedFactbase.new(
|
383
|
-
Factbase.new(maps)
|
384
|
-
)
|
385
|
-
)
|
386
|
-
),
|
387
|
-
'sync+logged+plain' => Factbase::SyncFactbase.new(
|
388
|
-
Factbase::Logged.new(
|
389
|
-
Factbase.new(maps),
|
390
|
-
Loog::NULL
|
391
|
-
)
|
392
|
-
),
|
393
|
-
'sync+cached+indexed+logged+plain' => Factbase::SyncFactbase.new(
|
394
|
-
Factbase::CachedFactbase.new(
|
395
|
-
Factbase::IndexedFactbase.new(
|
396
|
-
Factbase::Logged.new(
|
397
|
-
Factbase.new(maps),
|
398
|
-
Loog::NULL
|
399
|
-
)
|
400
|
-
)
|
401
|
-
)
|
402
|
-
),
|
403
|
-
'sync+sync+sync+plain' => Factbase::SyncFactbase.new(
|
404
|
-
Factbase::SyncFactbase.new(
|
405
|
-
Factbase::SyncFactbase.new(
|
406
|
-
Factbase::SyncFactbase.new(
|
407
|
-
Factbase.new(maps)
|
408
|
-
)
|
409
|
-
)
|
410
|
-
)
|
411
|
-
),
|
412
|
-
'logged+logged+logged+plain' => Factbase::SyncFactbase.new(
|
413
|
-
Factbase::Logged.new(
|
414
|
-
Factbase::Logged.new(
|
415
|
-
Factbase::Logged.new(
|
416
|
-
Factbase.new(maps),
|
417
|
-
Loog::NULL
|
418
|
-
),
|
419
|
-
Loog::NULL
|
420
|
-
),
|
421
|
-
Loog::NULL
|
422
|
-
)
|
423
|
-
),
|
424
|
-
'all+plain' => Factbase::Tallied.new(
|
425
|
-
Factbase::Pre.new(
|
426
|
-
Factbase::Rules.new(
|
427
|
-
Factbase::Inv.new(
|
428
|
-
Factbase::SyncFactbase.new(
|
429
|
-
Factbase::CachedFactbase.new(
|
430
|
-
Factbase::IndexedFactbase.new(
|
431
|
-
Factbase::Logged.new(
|
432
|
-
Factbase.new(maps),
|
433
|
-
Loog::NULL
|
434
|
-
)
|
435
|
-
)
|
436
|
-
)
|
437
|
-
)
|
438
|
-
) { nil },
|
439
|
-
'(always)'
|
440
|
-
)
|
441
|
-
) { nil }
|
442
|
-
)
|
443
|
-
}.each(&)
|
444
|
-
end
|
445
|
-
end
|