factbase 0.15.0 → 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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +5 -5
  3. data/factbase.gemspec +4 -4
  4. data/lib/factbase/fact.rb +1 -1
  5. data/lib/factbase/fact_as_yaml.rb +10 -1
  6. data/lib/factbase/indexed/indexed_term.rb +6 -1
  7. data/lib/factbase/version.rb +1 -1
  8. metadata +7 -87
  9. data/.0pdd.yml +0 -8
  10. data/.gitattributes +0 -7
  11. data/.github/publish-benchmark.sh +0 -24
  12. data/.github/workflows/actionlint.yml +0 -25
  13. data/.github/workflows/benchmark.yml +0 -36
  14. data/.github/workflows/codecov.yml +0 -27
  15. data/.github/workflows/copyrights.yml +0 -19
  16. data/.github/workflows/markdown-lint.yml +0 -23
  17. data/.github/workflows/pdd.yml +0 -19
  18. data/.github/workflows/rake.yml +0 -28
  19. data/.github/workflows/reuse.yml +0 -19
  20. data/.github/workflows/typos.yml +0 -19
  21. data/.github/workflows/xcop.yml +0 -19
  22. data/.github/workflows/yamllint.yml +0 -19
  23. data/.gitignore +0 -11
  24. data/.pdd +0 -7
  25. data/.rubocop.yml +0 -51
  26. data/.rultor.yml +0 -27
  27. data/benchmark/bench_factbase.rb +0 -61
  28. data/benchmark/bench_large_query.rb +0 -128
  29. data/benchmark/bench_query.rb +0 -57
  30. data/benchmark/bench_taped.rb +0 -33
  31. data/fixtures/stories/agg.yml +0 -17
  32. data/fixtures/stories/always.yml +0 -16
  33. data/fixtures/stories/and.yml +0 -19
  34. data/fixtures/stories/as.yml +0 -16
  35. data/fixtures/stories/count.yml +0 -18
  36. data/fixtures/stories/empty.yml +0 -23
  37. data/fixtures/stories/eq.yml +0 -30
  38. data/fixtures/stories/gt.yml +0 -18
  39. data/fixtures/stories/join.yml +0 -22
  40. data/fixtures/stories/max.yml +0 -14
  41. data/fixtures/stories/min.yml +0 -14
  42. data/fixtures/stories/nth.yml +0 -14
  43. data/fixtures/stories/one.yml +0 -14
  44. data/fixtures/stories/or.yml +0 -18
  45. data/fixtures/stories/sprintf.yml +0 -12
  46. data/fixtures/stories/sum.yml +0 -14
  47. data/fixtures/stories/unique.yml +0 -30
  48. data/renovate.json +0 -6
  49. data/test/factbase/cached/test_cached_factbase.rb +0 -44
  50. data/test/factbase/cached/test_cached_query.rb +0 -100
  51. data/test/factbase/indexed/test_indexed_fact.rb +0 -23
  52. data/test/factbase/indexed/test_indexed_factbase.rb +0 -96
  53. data/test/factbase/indexed/test_indexed_query.rb +0 -208
  54. data/test/factbase/indexed/test_indexed_term.rb +0 -140
  55. data/test/factbase/sync/test_sync_factbase.rb +0 -22
  56. data/test/factbase/sync/test_sync_query.rb +0 -30
  57. data/test/factbase/terms/test_aggregates.rb +0 -63
  58. data/test/factbase/terms/test_aliases.rb +0 -58
  59. data/test/factbase/terms/test_casting.rb +0 -33
  60. data/test/factbase/terms/test_debug.rb +0 -111
  61. data/test/factbase/terms/test_defn.rb +0 -48
  62. data/test/factbase/terms/test_logical.rb +0 -57
  63. data/test/factbase/terms/test_math.rb +0 -122
  64. data/test/factbase/terms/test_meta.rb +0 -70
  65. data/test/factbase/terms/test_ordering.rb +0 -44
  66. data/test/factbase/terms/test_strings.rb +0 -36
  67. data/test/factbase/terms/test_system.rb +0 -31
  68. data/test/factbase/test_accum.rb +0 -74
  69. data/test/factbase/test_churn.rb +0 -41
  70. data/test/factbase/test_fact.rb +0 -108
  71. data/test/factbase/test_fact_as_yaml.rb +0 -77
  72. data/test/factbase/test_flatten.rb +0 -28
  73. data/test/factbase/test_impatient.rb +0 -176
  74. data/test/factbase/test_inv.rb +0 -44
  75. data/test/factbase/test_logged.rb +0 -155
  76. data/test/factbase/test_pre.rb +0 -35
  77. data/test/factbase/test_query.rb +0 -445
  78. data/test/factbase/test_rules.rb +0 -128
  79. data/test/factbase/test_syntax.rb +0 -166
  80. data/test/factbase/test_tallied.rb +0 -81
  81. data/test/factbase/test_taped.rb +0 -72
  82. data/test/factbase/test_tee.rb +0 -85
  83. data/test/factbase/test_term.rb +0 -87
  84. data/test/factbase/test_to_json.rb +0 -35
  85. data/test/factbase/test_to_xml.rb +0 -89
  86. data/test/factbase/test_to_yaml.rb +0 -39
  87. data/test/test__helper.rb +0 -41
  88. data/test/test_factbase.rb +0 -509
@@ -1,100 +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 'loog'
7
- require_relative '../../test__helper'
8
- require_relative '../../../lib/factbase'
9
- require_relative '../../../lib/factbase/logged'
10
- require_relative '../../../lib/factbase/cached/cached_factbase'
11
- require_relative '../../../lib/factbase/indexed/indexed_factbase'
12
- require_relative '../../../lib/factbase/sync/sync_factbase'
13
-
14
- # Query test.
15
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
16
- # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
17
- # License:: MIT
18
- class TestCachedQuery < Factbase::Test
19
- def test_queries_many_times
20
- fb = Factbase::CachedFactbase.new(Factbase.new)
21
- total = 5
22
- total.times { fb.insert }
23
- total.times do
24
- assert_equal(5, fb.query('(always)').each.to_a.size)
25
- end
26
- end
27
-
28
- def test_negates_correctly
29
- fb = Factbase::CachedFactbase.new(Factbase.new)
30
- fb.insert.foo = 42
31
- 3.times do
32
- assert_equal(1, fb.query('(always)').each.to_a.size)
33
- assert_equal(0, fb.query('(not (always))').each.to_a.size)
34
- end
35
- end
36
-
37
- def test_aggregates_too
38
- fb = Factbase::IndexedFactbase.new(Factbase::CachedFactbase.new(Factbase.new))
39
- 10_000.times do |i|
40
- f = fb.insert
41
- f.foo = i
42
- f.hello = 1
43
- end
44
- 3.times do
45
- q = fb.query('(eq foo (agg (exists hello) (min foo)))')
46
- assert_equal(1, q.each.to_a.size)
47
- end
48
- end
49
-
50
- def test_joins_too
51
- fb = Factbase::IndexedFactbase.new(Factbase::CachedFactbase.new(Factbase.new))
52
- total = 10
53
- total.times do |i|
54
- f = fb.insert
55
- f.foo = i
56
- f.hello = 1
57
- end
58
- 3.times do
59
- assert_equal(total, fb.query('(join "bar<=foo" (eq foo (agg (exists hello) (min foo))))').each.to_a.size)
60
- end
61
- end
62
-
63
- def test_works_with_logging
64
- fb = Factbase::CachedFactbase.new(Factbase::Logged.new(Factbase.new, Loog::NULL))
65
- total = 10
66
- total.times do |i|
67
- f = fb.insert
68
- f.foo = i
69
- f.hello = 1
70
- end
71
- 3.times do
72
- [
73
- '(exists foo)',
74
- '(and (gt foo -99) (exists hello))',
75
- '(and (lt hello 1000.44) (exists foo) (not (exists bar)))'
76
- ].each do |q|
77
- assert_equal(total, fb.query(q).each.to_a.size)
78
- end
79
- end
80
- end
81
-
82
- def test_caches_while_being_decorated
83
- fb = Factbase::SyncFactbase.new(Factbase::CachedFactbase.new(Factbase.new))
84
- 10_000.times do |i|
85
- f = fb.insert
86
- f.foo = i
87
- f.hello = 1
88
- end
89
- 3.times do
90
- assert_equal(1, fb.query('(eq foo (agg (exists hello) (min foo)))').each.to_a.size)
91
- end
92
- end
93
-
94
- def test_deletes_too
95
- fb = Factbase::CachedFactbase.new(Factbase.new)
96
- fb.insert.foo = 1
97
- fb.query('(eq foo 1)').delete!
98
- assert_equal(0, fb.query('(always)').each.to_a.size)
99
- end
100
- end
@@ -1,23 +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_relative '../../../lib/factbase'
8
- require_relative '../../../lib/factbase/fact'
9
- require_relative '../../../lib/factbase/indexed/indexed_fact'
10
-
11
- # Fact test.
12
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
13
- # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
14
- # License:: MIT
15
- class TestIndexedFact < Factbase::Test
16
- def test_updates_origin
17
- origin = Factbase::Fact.new({})
18
- fact = Factbase::IndexedFact.new(origin, {})
19
- fact.foo = 42
20
- refute_nil(origin['foo'])
21
- assert_equal(42, origin.foo)
22
- end
23
- end
@@ -1,96 +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 'elapsed'
7
- require 'loog'
8
- require 'timeout'
9
- require_relative '../../test__helper'
10
- require_relative '../../../lib/factbase'
11
- require_relative '../../../lib/factbase/indexed/indexed_factbase'
12
-
13
- # Factbase test.
14
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
15
- # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
16
- # License:: MIT
17
- class TestIndexedFactbase < Factbase::Test
18
- def test_queries_after_update
19
- origin = Factbase.new
20
- fb = Factbase::IndexedFactbase.new(origin)
21
- fb.insert.foo = 42
22
- fb.query('(exists foo)').each do |f|
23
- f.bar = 33
24
- end
25
- refute_empty(origin.query('(exists bar)').each.to_a)
26
- refute_empty(fb.query('(exists bar)').each.to_a)
27
- end
28
-
29
- def test_queries_after_update_in_txn
30
- [
31
- '(exists boom)',
32
- '(one boom)',
33
- '(and (exists boom) (exists boom))',
34
- '(and (exists boom) (exists boom) (exists boom))',
35
- '(and (one boom) (one boom))',
36
- '(and (one boom) (one foo))',
37
- '(and (one boom) (one boom) (one boom))',
38
- '(and (one boom) (one boom) (one boom) (one foo))',
39
- '(and (one boom) (exists boom))',
40
- '(and (exists boom) (one boom) (one boom))',
41
- '(and (exists boom) (exists boom) (one boom))',
42
- '(and (eq foo 42) (exists boom) (one boom) (not (exists bar)))'
43
- ].each do |q|
44
- origin = Factbase.new
45
- fb = Factbase::IndexedFactbase.new(origin)
46
- f = fb.insert
47
- f.foo = 42
48
- f.boom = 33
49
- fb.txn do |fbt|
50
- fbt.query(q).each do |n|
51
- n.bar = n.foo + 1
52
- end
53
- end
54
- refute_empty(origin.query('(exists bar)').each.to_a, q)
55
- refute_empty(fb.query('(exists bar)').each.to_a, q)
56
- end
57
- end
58
-
59
- def test_queries_after_insert_in_txn
60
- fb = Factbase::IndexedFactbase.new(Factbase.new)
61
- fb.txn(&:insert)
62
- refute_empty(fb.query('(always)').each.to_a)
63
- end
64
-
65
- def test_works_with_huge_dataset
66
- fb = Factbase.new
67
- fb = Factbase::IndexedFactbase.new(fb)
68
- 10_000.times do |i|
69
- fb.insert.then do |f|
70
- f.id = i
71
- f.foo = [42, 1, 256, 7, 99].sample
72
- f.bar = [42, 13, 88, 19, 93].sample
73
- f.rarely = rand if rand > 0.95
74
- f.often = rand if rand > 0.05
75
- end
76
- end
77
- [
78
- '(and (eq foo 42) (exists bar))',
79
- '(and (eq foo 42) (exists rarely))',
80
- '(and (eq foo 42) (exists often))',
81
- '(and (eq foo 42) (exists often) (exists bar) (absent rarely))',
82
- '(and (eq foo 42) (empty (eq foo 888)))',
83
- '(and (eq foo 42) (empty (eq foo $id)))',
84
- '(and (eq foo 42) (empty (eq foo $often)))',
85
- '(and (eq foo 42) (empty (and (eq foo $often) (gt foo 43))))',
86
- '(and (eq foo 42) (empty (and (eq foo 42) (eq bar 42) (eq id -1))))',
87
- '(and (eq foo 42) (empty (exists another)))'
88
- ].each do |q|
89
- Timeout.timeout(4) do
90
- elapsed(Loog::NULL, good: q) do
91
- refute_empty(fb.query(q).each.to_a)
92
- end
93
- end
94
- end
95
- end
96
- end
@@ -1,208 +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_relative '../../../lib/factbase'
8
- require_relative '../../../lib/factbase/cached/cached_factbase'
9
- require_relative '../../../lib/factbase/indexed/indexed_factbase'
10
-
11
- # Query test.
12
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
13
- # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
14
- # License:: MIT
15
- class TestIndexedQuery < Factbase::Test
16
- def test_converts_to_string
17
- fb = Factbase.new
18
- fb.insert.foo = 42
19
- refute_nil(Factbase::IndexedQuery.new(fb.query('(exists foo)'), {}, fb).to_s)
20
- end
21
-
22
- def test_queries_and_updates_origin
23
- fb = Factbase.new
24
- fb.insert.foo = 42
25
- Factbase::IndexedQuery.new(fb.query('(exists foo)'), {}, fb).each do |f|
26
- f.bar = 33
27
- end
28
- refute_empty(fb.query('(exists bar)').each.to_a)
29
- end
30
-
31
- def test_queries_many_times
32
- fb = Factbase::IndexedFactbase.new(Factbase.new)
33
- total = 5
34
- total.times { fb.insert }
35
- total.times do
36
- assert_equal(5, fb.query('(always)').each.to_a.size)
37
- end
38
- end
39
-
40
- def test_finds_by_eq
41
- fb = Factbase::IndexedFactbase.new(Factbase.new)
42
- fb.insert.foo = 42
43
- fb.insert
44
- 3.times do
45
- assert_equal(1, fb.query('(eq foo 42)').each.to_a.size)
46
- end
47
- end
48
-
49
- def test_fills_up_the_index
50
- idx = {}
51
- fb = Factbase::IndexedFactbase.new(Factbase.new, idx)
52
- fb.query('(eq x 1)').each.to_a
53
- assert_equal(1, idx.size)
54
- fb.insert
55
- assert_empty(idx)
56
- end
57
-
58
- def test_finds_by_eq_with_symbol
59
- fb = Factbase::IndexedFactbase.new(Factbase.new)
60
- f = fb.insert
61
- f.num = 256
62
- f.num = 42
63
- fb.insert.num = 42
64
- fb.insert.num = 55
65
- fb.insert
66
- fb.insert
67
- 3.times do
68
- assert_equal(1, fb.query('(eq 1 (agg (eq num $num) (count)))').each.to_a.size)
69
- end
70
- end
71
-
72
- def test_finds_by_eq_with_array
73
- fb = Factbase::IndexedFactbase.new(Factbase.new)
74
- f = fb.insert
75
- f.foo = 33
76
- f.foo = 42
77
- f.foo = 1
78
- 3.times do
79
- assert_equal(1, fb.query('(eq foo 42)').each.to_a.size)
80
- end
81
- end
82
-
83
- def test_finds_by_eq_with_agg
84
- fb = Factbase::IndexedFactbase.new(Factbase.new)
85
- fb.insert.foo = 42
86
- fb.insert.foo = 33
87
- fb.insert
88
- 3.times do
89
- assert_equal(1, fb.query('(eq foo (agg (exists foo) (max foo)))').each.to_a.size)
90
- end
91
- end
92
-
93
- def test_finds_max_value
94
- fb = Factbase::IndexedFactbase.new(Factbase.new)
95
- fb.insert.foo = 42
96
- fb.insert.foo = 33
97
- fb.insert
98
- 3.times do
99
- assert_equal(42, fb.query('(agg (exists foo) (max foo))').one)
100
- end
101
- end
102
-
103
- def test_finds_by_eq_with_formula
104
- fb = Factbase::IndexedFactbase.new(Factbase.new)
105
- fb.insert.foo = 42
106
- fb.insert
107
- 3.times do
108
- assert_equal(1, fb.query('(eq foo (plus 40 2))').each.to_a.size)
109
- end
110
- end
111
-
112
- def test_finds_by_eq_in_txn
113
- fb = Factbase::IndexedFactbase.new(Factbase.new)
114
- fb.insert.foo = 42
115
- fb.insert
116
- 3.times do
117
- fb.txn { |fbt| assert_equal(1, fbt.query('(eq foo 42)').each.to_a.size) }
118
- end
119
- end
120
-
121
- def test_finds_with_conjunction
122
- fb = Factbase::IndexedFactbase.new(Factbase.new)
123
- fb.insert.foo = 42
124
- fb.insert.bar = 33
125
- 3.times do
126
- assert_equal(2, fb.query('(or (exists foo) (exists bar))').each.to_a.size)
127
- end
128
- end
129
-
130
- def test_finds_with_disjunction
131
- fb = Factbase::IndexedFactbase.new(Factbase.new)
132
- fb.insert.foo = 42
133
- fb.insert.bar = 33
134
- f = fb.insert
135
- f.foo = 42
136
- f.bar = 33
137
- 3.times do
138
- assert_equal(1, fb.query('(and (exists foo) (exists bar))').each.to_a.size)
139
- end
140
- end
141
-
142
- def test_finds_with_inversion
143
- fb = Factbase::IndexedFactbase.new(Factbase.new)
144
- fb.insert.foo = 42
145
- fb.insert.bar = 33
146
- 3.times do
147
- assert_equal(1, fb.query('(not (exists foo))').each.to_a.size)
148
- end
149
- end
150
-
151
- def test_finds_with_disjunction_in_txn
152
- fb = Factbase::IndexedFactbase.new(Factbase.new)
153
- fb.insert.foo = 42
154
- fb.insert.bar = 33
155
- f = fb.insert
156
- f.foo = 42
157
- f.bar = 33
158
- 3.times do
159
- fb.txn { |fbt| assert_equal(1, fbt.query('(and (exists foo) (exists bar))').each.to_a.size) }
160
- end
161
- end
162
-
163
- def test_attaches_alias
164
- fb = Factbase::IndexedFactbase.new(Factbase.new)
165
- total = 10
166
- total.times do |i|
167
- f = fb.insert
168
- f.foo = rand(0..10)
169
- f.bar = rand(0..10)
170
- f.xyz = i
171
- end
172
- 3.times do
173
- assert_equal(total, fb.query('(as boom (agg (eq foo $bar) (min xyz)))').each.to_a.size)
174
- end
175
- end
176
-
177
- def test_joins_simple_one
178
- idx = {}
179
- fb = Factbase::IndexedFactbase.new(Factbase.new, idx)
180
- fb.insert.who = 4
181
- fb.insert.friend = 4
182
- assert_equal(1, fb.query('(and (exists who) (join "f<=friend" (eq friend $who)))').each.to_a.size)
183
- assert_equal(2, idx.size)
184
- end
185
-
186
- def test_joins_too
187
- fb = Factbase::IndexedFactbase.new(Factbase.new)
188
- total = 10_000
189
- total.times do |i|
190
- f = fb.insert
191
- f.who = i
192
- end
193
- total.times do |i|
194
- f = fb.insert
195
- f.friend = i
196
- end
197
- 3.times do
198
- assert_equal(total, fb.query('(and (exists who) (join "f<=friend" (eq friend $who)))').each.to_a.size)
199
- end
200
- end
201
-
202
- def test_deletes_too
203
- fb = Factbase::IndexedFactbase.new(Factbase.new)
204
- fb.insert.foo = 1
205
- fb.query('(eq foo 1)').delete!
206
- assert_equal(0, fb.query('(always)').each.to_a.size)
207
- end
208
- end
@@ -1,140 +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_relative '../../../lib/factbase'
8
- require_relative '../../../lib/factbase/term'
9
- require_relative '../../../lib/factbase/taped'
10
- require_relative '../../../lib/factbase/indexed/indexed_term'
11
-
12
- # Term test.
13
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
14
- # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
15
- # License:: MIT
16
- class TestIndexedTerm < Factbase::Test
17
- def test_predicts_on_eq
18
- term = Factbase::Term.new(:eq, [:foo, 42])
19
- idx = {}
20
- term.redress!(Factbase::IndexedTerm, idx:)
21
- maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7] }, { 'foo' => [22, 42] }, { 'foo' => [] }])
22
- n = term.predict(maps, {})
23
- assert_equal(2, n.size)
24
- assert_kind_of(Factbase::Taped, n)
25
- end
26
-
27
- def test_predicts_on_exists
28
- term = Factbase::Term.new(:exists, [:foo])
29
- idx = {}
30
- term.redress!(Factbase::IndexedTerm, idx:)
31
- maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7] }, { 'foo' => [22, 42] }, { 'foo' => [] }])
32
- n = term.predict(maps, {})
33
- assert_equal(3, n.size)
34
- assert_kind_of(Factbase::Taped, n)
35
- end
36
-
37
- def test_predicts_on_one
38
- term = Factbase::Term.new(:one, [:foo])
39
- idx = {}
40
- term.redress!(Factbase::IndexedTerm, idx:)
41
- maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7] }, { 'foo' => [22, 42] }, { 'foo' => [] }])
42
- n = term.predict(maps, {})
43
- assert_equal(1, n.size)
44
- assert_kind_of(Factbase::Taped, n)
45
- end
46
-
47
- def test_predicts_on_not
48
- term = Factbase::Term.new(:not, [Factbase::Term.new(:eq, [:foo, 42])])
49
- idx = {}
50
- term.redress!(Factbase::IndexedTerm, idx:)
51
- maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7], 'foo' => [22, 42] }, { 'foo' => [22] }])
52
- n = term.predict(maps, {})
53
- assert_equal(1, n.size)
54
- assert_kind_of(Factbase::Taped, n)
55
- end
56
-
57
- def test_predicts_on_and
58
- term = Factbase::Term.new(
59
- :and,
60
- [
61
- Factbase::Term.new(:eq, [:foo, 42]),
62
- Factbase::Term.new(:eq, %i[bar $jeff])
63
- ]
64
- )
65
- idx = {}
66
- term.redress!(Factbase::IndexedTerm, idx:)
67
- maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7], 'foo' => [22, 42] }, { 'foo' => [22, 42] }])
68
- n = term.predict(maps, Factbase::Tee.new({}, { 'jeff' => [7] }))
69
- assert_equal(1, n.size)
70
- assert_kind_of(Factbase::Taped, n)
71
- end
72
-
73
- def test_predicts_on_single_and
74
- term = Factbase::Term.new(:and, [Factbase::Term.new(:eq, [:foo, 42])])
75
- idx = {}
76
- term.redress!(Factbase::IndexedTerm, idx:)
77
- maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7], 'foo' => [4] }])
78
- assert_equal(1, term.predict(maps, {}).size)
79
- end
80
-
81
- def test_predicts_on_or
82
- term = Factbase::Term.new(
83
- :or,
84
- [
85
- Factbase::Term.new(:exists, [:bar]),
86
- Factbase::Term.new(:eq, [:foo, 42]),
87
- Factbase::Term.new(:eq, [:bar, 7])
88
- ]
89
- )
90
- idx = {}
91
- term.redress!(Factbase::IndexedTerm, idx:)
92
- maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'bar' => [7], 'foo' => [22, 42] }, { 'foo' => [22, 42] }])
93
- n = term.predict(maps, {})
94
- assert_equal(3, n.size)
95
- assert_kind_of(Factbase::Taped, n)
96
- end
97
-
98
- def test_predicts_on_others
99
- term = Factbase::Term.new(:boom, [])
100
- idx = {}
101
- term.redress!(Factbase::IndexedTerm, idx:)
102
- maps = Factbase::Taped.new([{ 'foo' => [42] }, { 'alpha' => [] }, {}])
103
- n = term.predict(maps, {})
104
- assert_nil(n)
105
- end
106
-
107
- def test_predicts_on_gt
108
- term = Factbase::Term.new(:gt, [:foo, 42])
109
- idx = {}
110
- term.redress!(Factbase::IndexedTerm, idx:)
111
- maps = Factbase::Taped.new([
112
- { 'foo' => [10] },
113
- { 'foo' => [43] },
114
- { 'foo' => [42] },
115
- { 'foo' => [100, 5] },
116
- { 'bar' => [50] },
117
- { 'foo' => [41, 42, 43] }
118
- ])
119
- n = term.predict(maps, {})
120
- assert_equal(3, n.size)
121
- assert_kind_of(Factbase::Taped, n)
122
- end
123
-
124
- def test_predicts_on_lt
125
- term = Factbase::Term.new(:lt, [:foo, 42])
126
- idx = {}
127
- term.redress!(Factbase::IndexedTerm, idx:)
128
- maps = Factbase::Taped.new([
129
- { 'foo' => [10] },
130
- { 'foo' => [43] },
131
- { 'foo' => [42] },
132
- { 'foo' => [100, 5] },
133
- { 'bar' => [50] },
134
- { 'foo' => [41, 42, 43] }
135
- ])
136
- n = term.predict(maps, {})
137
- assert_equal(3, n.size)
138
- assert_kind_of(Factbase::Taped, n)
139
- end
140
- end
@@ -1,22 +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_relative '../../../lib/factbase'
8
- require_relative '../../../lib/factbase/sync/sync_factbase'
9
-
10
- # Sync factbase test.
11
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
12
- # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
13
- # License:: MIT
14
- class TestSyncFactbase < Factbase::Test
15
- def test_queries_and_inserts
16
- fb = Factbase::SyncFactbase.new(Factbase.new)
17
- fb.insert.foo = 42
18
- fb.query('(exists foo)').each do
19
- fb.insert
20
- end
21
- end
22
- end
@@ -1,30 +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_relative '../../../lib/factbase'
8
- require_relative '../../../lib/factbase/sync/sync_factbase'
9
-
10
- # Query test.
11
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
12
- # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
13
- # License:: MIT
14
- class TestSyncQuery < Factbase::Test
15
- def test_queries_many_times
16
- fb = Factbase::SyncFactbase.new(Factbase.new)
17
- total = 5
18
- total.times { fb.insert }
19
- total.times do
20
- assert_equal(5, fb.query('(always)').each.to_a.size)
21
- end
22
- end
23
-
24
- def test_deletes_too
25
- fb = Factbase::SyncFactbase.new(Factbase.new)
26
- fb.insert.foo = 1
27
- fb.query('(eq foo 1)').delete!
28
- assert_equal(0, fb.query('(always)').each.to_a.size)
29
- end
30
- end
@@ -1,63 +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_relative '../../../lib/factbase/term'
8
- require_relative '../../../lib/factbase/syntax'
9
-
10
- # Aggregates test.
11
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
12
- # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
13
- # License:: MIT
14
- class TestAggregates < Factbase::Test
15
- def test_aggregation
16
- maps = [
17
- { 'x' => [1], 'y' => [0], 'z' => [4] },
18
- { 'x' => [2], 'y' => [42], 'z' => [3] },
19
- { 'x' => [3], 'y' => [42], 'z' => [5] },
20
- { 'x' => [4], 'y' => [42], 'z' => [2] },
21
- { 'x' => [5], 'y' => [42], 'z' => [1] },
22
- { 'x' => [8], 'y' => [0], 'z' => [6] }
23
- ]
24
- {
25
- '(eq x (agg (eq y 42) (min x)))' => '(eq x 2)',
26
- '(eq z (agg (eq y 0) (max z)))' => '(eq x 8)',
27
- '(eq x (agg (and (eq y 42) (gt z 1)) (max x)))' => '(eq x 4)',
28
- '(and (eq x (agg (eq y 42) (min x))) (eq z 3))' => '(eq x 2)',
29
- '(eq x (agg (eq y 0) (nth 0 x)))' => '(eq x 1)',
30
- '(eq x (agg (eq y 0) (first x)))' => '(eq x 1)',
31
- '(agg (eq foo 42) (always))' => '(eq x 1)'
32
- }.each do |q, r|
33
- t = Factbase::Syntax.new(q).to_term
34
- f = maps.find { |m| t.evaluate(fact(m), maps, Factbase.new) }
35
- refute_nil(f, "nothing found by: #{q}")
36
- assert(Factbase::Syntax.new(r).to_term.evaluate(fact(f), [], Factbase.new))
37
- end
38
- end
39
-
40
- def test_empty
41
- maps = [
42
- { 'x' => [1], 'y' => [0], 'z' => [4] },
43
- { 'x' => [8], 'y' => [0] }
44
- ]
45
- {
46
- '(empty (eq y 42))' => true,
47
- '(empty (eq x 1))' => false
48
- }.each do |q, r|
49
- t = Factbase::Syntax.new(q).to_term
50
- assert_equal(r, t.evaluate(Factbase::Fact.new({}), maps, Factbase.new), q)
51
- end
52
- end
53
-
54
- def test_empty_with_params
55
- maps = [
56
- { 'a' => [3], 'b' => [44] },
57
- { 'a' => [4], 'b' => [55] }
58
- ]
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))
62
- end
63
- end