factbase 0.0.49 → 0.0.51

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.
@@ -44,9 +44,9 @@ class TestQuery < Minitest::Test
44
44
 
45
45
  def test_complex_parsing
46
46
  maps = []
47
- maps << { 'num' => 42, 'name' => 'Jeff' }
48
- maps << { 'pi' => 3.14, 'num' => [42, 66, 0], 'name' => 'peter' }
49
- maps << { 'time' => Time.now - 100, 'num' => 0, 'hi' => [4], 'nome' => ['Walter'] }
47
+ maps << { 'num' => [42], 'name' => ['Jeff'] }
48
+ maps << { 'pi' => [3.14], 'num' => [42, 66, 0], 'name' => ['peter'] }
49
+ maps << { 'time' => [Time.now - 100], 'num' => [0], 'hi' => [4], 'nome' => ['Walter'] }
50
50
  {
51
51
  '(eq num 444)' => 0,
52
52
  '(eq hi 4)' => 1,
@@ -65,6 +65,7 @@ class TestQuery < Minitest::Test
65
65
  '(unique pi)' => 1,
66
66
  '(many num)' => 1,
67
67
  '(one num)' => 2,
68
+ '(nil (agg (exists hello) (min num)))' => 3,
68
69
  '(gt num (minus 1 (either (at 0 (prev num)) 0)))' => 3,
69
70
  '(and (not (many num)) (eq num (plus 21 +21)))' => 1,
70
71
  '(and (not (many num)) (eq num (minus -100 -142)))' => 1,
@@ -84,7 +85,8 @@ class TestQuery < Minitest::Test
84
85
  '(and (absent time) (exists pi))' => 1,
85
86
  "(and (exists time) (not (\t\texists pi)))" => 1,
86
87
  '(undef something)' => 3,
87
- "(or (eq num +66) (lt time #{(Time.now - 200).utc.iso8601}))" => 1
88
+ "(or (eq num +66) (lt time #{(Time.now - 200).utc.iso8601}))" => 1,
89
+ '(eq 3 (agg (eq num $num) (count)))' => 1
88
90
  }.each do |q, r|
89
91
  assert_equal(r, Factbase::Query.new(maps, Mutex.new, q).each.to_a.size, q)
90
92
  end
@@ -93,7 +95,7 @@ class TestQuery < Minitest::Test
93
95
  def test_simple_parsing_with_time
94
96
  maps = []
95
97
  now = Time.now.utc
96
- maps << { 'foo' => now }
98
+ maps << { 'foo' => [now] }
97
99
  q = Factbase::Query.new(maps, Mutex.new, "(eq foo #{now.iso8601})")
98
100
  assert_equal(1, q.each.to_a.size)
99
101
  end
@@ -102,7 +104,7 @@ class TestQuery < Minitest::Test
102
104
  maps = []
103
105
  maps << { 'foo' => [42] }
104
106
  maps << { 'bar' => [4, 5] }
105
- maps << { 'bar' => 5 }
107
+ maps << { 'bar' => [5] }
106
108
  q = Factbase::Query.new(maps, Mutex.new, '(eq bar 5)')
107
109
  assert_equal(2, q.delete!)
108
110
  assert_equal(1, maps.size)
@@ -112,7 +114,7 @@ class TestQuery < Minitest::Test
112
114
  maps = []
113
115
  maps << { 'foo' => [42] }
114
116
  maps << { 'bar' => [4, 5] }
115
- maps << { 'bar' => 5 }
117
+ maps << { 'bar' => [5] }
116
118
  q = Factbase::Query.new(maps, Mutex.new, '(never)')
117
119
  assert_equal(0, q.delete!)
118
120
  assert_equal(3, maps.size)
@@ -126,8 +128,21 @@ class TestQuery < Minitest::Test
126
128
 
127
129
  def test_returns_int
128
130
  maps = []
129
- maps << { 'foo' => 1 }
131
+ maps << { 'foo' => [1] }
130
132
  q = Factbase::Query.new(maps, Mutex.new, '(eq foo 1)')
131
133
  assert_equal(1, q.each(&:to_s))
132
134
  end
135
+
136
+ def test_with_aliases
137
+ maps = []
138
+ maps << { 'foo' => [42] }
139
+ assert_equal(45, Factbase::Query.new(maps, Mutex.new, '(as bar (plus foo 3))').each.to_a[0].bar)
140
+ assert_equal(1, maps[0].size)
141
+ end
142
+
143
+ def test_with_nil_alias
144
+ maps = []
145
+ maps << { 'foo' => [42] }
146
+ assert(Factbase::Query.new(maps, Mutex.new, '(as bar (plus xxx 3))').each.to_a[0]['bar'].nil?)
147
+ end
133
148
  end
@@ -23,6 +23,7 @@
23
23
  require 'minitest/autorun'
24
24
  require_relative '../../lib/factbase'
25
25
  require_relative '../../lib/factbase/rules'
26
+ require_relative '../../lib/factbase/pre'
26
27
 
27
28
  # Test.
28
29
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
@@ -66,6 +67,18 @@ class TestRules < Minitest::Test
66
67
  assert(ok)
67
68
  end
68
69
 
70
+ def test_rollback_on_violation
71
+ fb = Factbase::Rules.new(Factbase.new, '(when (exists a) (exists b))')
72
+ assert_raises do
73
+ fb.txn do |fbt|
74
+ f = fbt.insert
75
+ f.a = 1
76
+ f.c = 2
77
+ end
78
+ end
79
+ assert_equal(0, fb.size)
80
+ end
81
+
69
82
  def test_in_combination_with_pre
70
83
  fb = Factbase::Rules.new(Factbase.new, '(when (exists a) (exists b))')
71
84
  fb = Factbase::Pre.new(fb) do |f|
@@ -81,6 +94,6 @@ class TestRules < Minitest::Test
81
94
  end
82
95
  end
83
96
  assert(ok)
84
- assert_equal(1, fb.query('(eq hello 42)').each.to_a.size)
97
+ assert_equal(0, fb.query('(eq hello 42)').each.to_a.size)
85
98
  end
86
99
  end
@@ -43,7 +43,7 @@ class TestSyntax < Minitest::Test
43
43
  [
44
44
  '(foo)',
45
45
  '(foo (bar) (zz 77) ) # hey',
46
- "# hello\n\n\n(foo (bar))",
46
+ "# hello\n\n\n(foo ($bar))",
47
47
  "(eq foo \n\n 'Hello, world!'\n)\n",
48
48
  "(eq x 'Hello, \\' \n) \\' ( world!')",
49
49
  "# this is a comment\n(eq foo # test\n 42)\n\n# another comment\n",
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2024 Yegor Bugayenko
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the 'Software'), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in all
13
+ # copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ # SOFTWARE.
22
+
23
+ require 'minitest/autorun'
24
+ require_relative '../../lib/factbase'
25
+ require_relative '../../lib/factbase/tee'
26
+ require_relative '../../lib/factbase/fact'
27
+
28
+ # Tee test.
29
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
30
+ # Copyright:: Copyright (c) 2024 Yegor Bugayenko
31
+ # License:: MIT
32
+ class TestTee < Minitest::Test
33
+ def test_two_facts
34
+ map = {}
35
+ prim = Factbase::Fact.new(Mutex.new, map)
36
+ prim.foo = 42
37
+ upper = Factbase::Fact.new(Mutex.new, map)
38
+ upper.bar = 13
39
+ t = Factbase::Tee.new(prim, upper)
40
+ assert_equal(42, t.foo)
41
+ assert_equal([13], t['$bar'])
42
+ end
43
+ end
@@ -22,67 +22,12 @@
22
22
 
23
23
  require 'minitest/autorun'
24
24
  require_relative '../../lib/factbase/term'
25
- require_relative '../../lib/factbase/syntax'
26
25
 
27
26
  # Term test.
28
27
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
28
  # Copyright:: Copyright (c) 2024 Yegor Bugayenko
30
29
  # License:: MIT
31
30
  class TestTerm < Minitest::Test
32
- def test_simple_matching
33
- t = Factbase::Term.new(:eq, [:foo, 42])
34
- assert(t.evaluate(fact('foo' => [42]), []))
35
- assert(!t.evaluate(fact('foo' => 'Hello!'), []))
36
- assert(!t.evaluate(fact('bar' => ['Hello!']), []))
37
- end
38
-
39
- def test_eq_matching
40
- t = Factbase::Term.new(:eq, [:foo, 42])
41
- assert(t.evaluate(fact('foo' => 42), []))
42
- assert(t.evaluate(fact('foo' => [10, 5, 6, -8, 'hey', 42, 9, 'fdsf']), []))
43
- assert(!t.evaluate(fact('foo' => [100]), []))
44
- assert(!t.evaluate(fact('foo' => []), []))
45
- assert(!t.evaluate(fact('bar' => []), []))
46
- end
47
-
48
- def test_eq_matching_time
49
- now = Time.now
50
- t = Factbase::Term.new(:eq, [:foo, Time.parse(now.iso8601)])
51
- assert(t.evaluate(fact('foo' => now), []))
52
- assert(t.evaluate(fact('foo' => [now, Time.now]), []))
53
- end
54
-
55
- def test_lt_matching
56
- t = Factbase::Term.new(:lt, [:foo, 42])
57
- assert(t.evaluate(fact('foo' => [10]), []))
58
- assert(!t.evaluate(fact('foo' => [100]), []))
59
- assert(!t.evaluate(fact('foo' => 100), []))
60
- assert(!t.evaluate(fact('bar' => 100), []))
61
- end
62
-
63
- def test_gt_matching
64
- t = Factbase::Term.new(:gt, [:foo, 42])
65
- assert(t.evaluate(fact('foo' => [100]), []))
66
- assert(t.evaluate(fact('foo' => 100), []))
67
- assert(!t.evaluate(fact('foo' => [10]), []))
68
- assert(!t.evaluate(fact('foo' => 10), []))
69
- assert(!t.evaluate(fact('bar' => 10), []))
70
- end
71
-
72
- def test_lt_matching_time
73
- t = Factbase::Term.new(:lt, [:foo, Time.now])
74
- assert(t.evaluate(fact('foo' => [Time.now - 100]), []))
75
- assert(!t.evaluate(fact('foo' => [Time.now + 100]), []))
76
- assert(!t.evaluate(fact('bar' => [100]), []))
77
- end
78
-
79
- def test_gt_matching_time
80
- t = Factbase::Term.new(:gt, [:foo, Time.now])
81
- assert(t.evaluate(fact('foo' => [Time.now + 100]), []))
82
- assert(!t.evaluate(fact('foo' => [Time.now - 100]), []))
83
- assert(!t.evaluate(fact('bar' => [100]), []))
84
- end
85
-
86
31
  def test_false_matching
87
32
  t = Factbase::Term.new(:never, [])
88
33
  assert(!t.evaluate(fact('foo' => [100]), []))
@@ -125,6 +70,7 @@ class TestTerm < Minitest::Test
125
70
  assert_equal('String', t.evaluate(fact('foo' => 'Hello, world!'), []))
126
71
  assert_equal('Float', t.evaluate(fact('foo' => 3.14), []))
127
72
  assert_equal('Time', t.evaluate(fact('foo' => Time.now), []))
73
+ assert_equal('Integer', t.evaluate(fact('foo' => 1_000_000_000_000_000), []))
128
74
  assert_equal('nil', t.evaluate(fact, []))
129
75
  end
130
76
 
@@ -213,6 +159,12 @@ class TestTerm < Minitest::Test
213
159
  assert_equal([42], t.evaluate(fact('foo' => 4), []))
214
160
  end
215
161
 
162
+ def test_plus
163
+ t = Factbase::Term.new(:plus, [:foo, 42])
164
+ assert_equal(46, t.evaluate(fact('foo' => 4), []))
165
+ assert(t.evaluate(fact, []).nil?)
166
+ end
167
+
216
168
  def test_report_missing_term
217
169
  t = Factbase::Term.new(:something, [])
218
170
  msg = assert_raises do
@@ -229,27 +181,6 @@ class TestTerm < Minitest::Test
229
181
  assert(msg.include?('at (at)'), msg)
230
182
  end
231
183
 
232
- def test_aggregation
233
- maps = [
234
- { 'x' => 1, 'y' => 0, 'z' => 4 },
235
- { 'x' => 2, 'y' => 42, 'z' => 3 },
236
- { 'x' => 3, 'y' => 42, 'z' => 5 },
237
- { 'x' => 4, 'y' => 42, 'z' => 2 },
238
- { 'x' => 5, 'y' => 42, 'z' => 1 },
239
- { 'x' => 8, 'y' => 0, 'z' => 6 }
240
- ]
241
- {
242
- '(eq x (agg (eq y 42) (min x)))' => '(eq x 2)',
243
- '(eq z (agg (eq y 0) (max z)))' => '(eq x 8)',
244
- '(eq x (agg (and (eq y 42) (gt z 1)) (max x)))' => '(eq x 4)',
245
- '(and (eq x (agg (eq y 42) (min x))) (eq z 3))' => '(eq x 2)'
246
- }.each do |q, r|
247
- t = Factbase::Syntax.new(q).to_term
248
- f = maps.find { |m| t.evaluate(fact(m), maps) }
249
- assert(Factbase::Syntax.new(r).to_term.evaluate(fact(f), []))
250
- end
251
- end
252
-
253
184
  private
254
185
 
255
186
  def fact(map = {})
@@ -73,6 +73,27 @@ class TestToXML < Minitest::Test
73
73
  assert(!xml.xpath('/fb/f/class').empty?)
74
74
  end
75
75
 
76
+ def test_show_types_as_attributes
77
+ fb = Factbase.new
78
+ f = fb.insert
79
+ f.a = 42
80
+ f.b = 3.14
81
+ f.c = 'Hello'
82
+ f.d = Time.now
83
+ f.e = 'e'
84
+ f.e = 4
85
+ out = Factbase::ToXML.new(fb).xml
86
+ xml = Nokogiri::XML.parse(out)
87
+ [
88
+ '/fb/f/a[@t="I"]',
89
+ '/fb/f/b[@t="F"]',
90
+ '/fb/f/c[@t="S"]',
91
+ '/fb/f/d[@t="T"]',
92
+ '/fb/f/e/v[@t="S"]',
93
+ '/fb/f/e/v[@t="I"]'
94
+ ].each { |x| assert(!xml.xpath(x).empty?, out) }
95
+ end
96
+
76
97
  def test_sorts_keys
77
98
  fb = Factbase.new
78
99
  f = fb.insert
@@ -80,7 +101,10 @@ class TestToXML < Minitest::Test
80
101
  f.t = 40
81
102
  f.a = 10
82
103
  f.c = 1
83
- xml = Factbase::ToXML.new(fb).xml
84
- assert(xml.gsub(/\s*/, '').include?('<f><a>10</a><c>1</c><t>40</t><x>20</x></f>'), xml)
104
+ to = Factbase::ToXML.new(fb)
105
+ xml = Nokogiri::XML.parse(to.xml)
106
+ %w[a c t x].each_with_index do |e, i|
107
+ assert(!xml.xpath("/fb/f/#{e}[count(preceding-sibling::*) = #{i}]").empty?, e)
108
+ end
85
109
  end
86
110
  end
@@ -68,15 +68,15 @@ class TestFactbase < Minitest::Test
68
68
  fb.insert.bar = 1
69
69
  fb.query('(exists bar)').each do |f|
70
70
  f.bar = 42
71
- assert_equal([1, 42], f['bar'])
71
+ assert_equal(2, f['bar'].size)
72
72
  end
73
73
  found = 0
74
74
  fb.query('(always)').each do |f|
75
- assert_equal([1, 42], f['bar'])
75
+ assert_equal(2, f['bar'].size)
76
76
  found += 1
77
77
  end
78
78
  assert_equal(1, found)
79
- assert_equal([1, 42], fb.query('(always)').each.to_a[0]['bar'])
79
+ assert_equal(2, fb.query('(always)').each.to_a[0]['bar'].size)
80
80
  end
81
81
 
82
82
  def test_serialize_and_deserialize
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: factbase
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.49
4
+ version: 0.0.51
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-11 00:00:00.000000000 Z
11
+ date: 2024-06-18 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: backtrace
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: json
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -115,6 +129,7 @@ files:
115
129
  - Rakefile
116
130
  - factbase.gemspec
117
131
  - lib/factbase.rb
132
+ - lib/factbase/accum.rb
118
133
  - lib/factbase/fact.rb
119
134
  - lib/factbase/flatten.rb
120
135
  - lib/factbase/inv.rb
@@ -123,12 +138,25 @@ files:
123
138
  - lib/factbase/query.rb
124
139
  - lib/factbase/rules.rb
125
140
  - lib/factbase/syntax.rb
141
+ - lib/factbase/tee.rb
126
142
  - lib/factbase/term.rb
143
+ - lib/factbase/terms/aggregates.rb
144
+ - lib/factbase/terms/aliases.rb
145
+ - lib/factbase/terms/debug.rb
146
+ - lib/factbase/terms/defn.rb
147
+ - lib/factbase/terms/logical.rb
148
+ - lib/factbase/terms/math.rb
149
+ - lib/factbase/terms/meta.rb
150
+ - lib/factbase/terms/ordering.rb
151
+ - lib/factbase/terms/strings.rb
127
152
  - lib/factbase/to_json.rb
128
153
  - lib/factbase/to_xml.rb
129
154
  - lib/factbase/to_yaml.rb
130
- - lib/factbase/tuples.rb
131
155
  - renovate.json
156
+ - test/factbase/terms/test_aggregates.rb
157
+ - test/factbase/terms/test_aliases.rb
158
+ - test/factbase/terms/test_math.rb
159
+ - test/factbase/test_accum.rb
132
160
  - test/factbase/test_fact.rb
133
161
  - test/factbase/test_flatten.rb
134
162
  - test/factbase/test_inv.rb
@@ -137,11 +165,11 @@ files:
137
165
  - test/factbase/test_query.rb
138
166
  - test/factbase/test_rules.rb
139
167
  - test/factbase/test_syntax.rb
168
+ - test/factbase/test_tee.rb
140
169
  - test/factbase/test_term.rb
141
170
  - test/factbase/test_to_json.rb
142
171
  - test/factbase/test_to_xml.rb
143
172
  - test/factbase/test_to_yaml.rb
144
- - test/factbase/test_tuples.rb
145
173
  - test/test__helper.rb
146
174
  - test/test_factbase.rb
147
175
  homepage: http://github.com/yegor256/factbase.rb
@@ -1,106 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright (c) 2024 Yegor Bugayenko
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the 'Software'), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
22
-
23
- require 'minitest/autorun'
24
- require_relative '../../lib/factbase'
25
- require_relative '../../lib/factbase/tuples'
26
-
27
- # Test.
28
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
29
- # Copyright:: Copyright (c) 2024 Yegor Bugayenko
30
- # License:: MIT
31
- class TestTuples < Minitest::Test
32
- def test_passes_facts
33
- fb = Factbase.new
34
- f1 = fb.insert
35
- f1.foo = 42
36
- f2 = fb.insert
37
- f2.bar = 55
38
- Factbase::Tuples.new(fb, ['(exists foo)', '(exists bar)']).each do |a, b|
39
- assert_equal(42, a.foo)
40
- assert_equal(55, b.bar)
41
- end
42
- end
43
-
44
- def test_with_empty_list_of_queries
45
- fb = Factbase.new
46
- f1 = fb.insert
47
- f1.foo = 42
48
- tuples = Factbase::Tuples.new(fb, [])
49
- assert(tuples.each.to_a.empty?)
50
- end
51
-
52
- def test_is_reusable
53
- fb = Factbase.new
54
- f1 = fb.insert
55
- f1.foo = 42
56
- tuples = Factbase::Tuples.new(fb, ['(exists foo)'])
57
- assert_equal(1, tuples.each.to_a.size)
58
- assert_equal(1, tuples.each.to_a.size)
59
- end
60
-
61
- def test_with_modifications
62
- fb = Factbase.new
63
- f1 = fb.insert
64
- f1.foo = 42
65
- Factbase::Tuples.new(fb, ['(exists foo)']).each do |fs|
66
- fs[0].bar = 1
67
- end
68
- assert_equal(1, fb.query('(exists bar)').each.to_a.size)
69
- end
70
-
71
- def test_with_txn
72
- fb = Factbase.new
73
- f1 = fb.insert
74
- f1.foo = 42
75
- Factbase::Tuples.new(fb, ['(exists foo)']).each do |fs|
76
- fb.txn do |fbt|
77
- f = fbt.insert
78
- f.bar = 1
79
- end
80
- fs[0].xyz = 'hey'
81
- end
82
- assert_equal(1, fb.query('(exists bar)').each.to_a.size)
83
- assert_equal(1, fb.query('(exists xyz)').each.to_a.size)
84
- end
85
-
86
- def test_with_chaining
87
- fb = Factbase.new
88
- f1 = fb.insert
89
- f1.name = 'Jeff'
90
- f1.friend = 'Walter'
91
- f2 = fb.insert
92
- f2.name = 'Walter'
93
- f2.group = 1
94
- f3 = fb.insert
95
- f3.name = 'Donny'
96
- f3.group = 1
97
- tuples = Factbase::Tuples.new(
98
- fb, ['(eq name "Jeff")', '(eq name "{f0.friend}")', '(eq group {f1.group})']
99
- )
100
- tuples.each do |fs|
101
- assert_equal('Walter', fs[1].name)
102
- assert(%w[Walter Donny].include?(fs[2].name))
103
- end
104
- assert_equal(2, tuples.each.to_a.size)
105
- end
106
- end