factbase 0.14.1 → 0.14.3
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/lib/factbase/impatient.rb +23 -16
- data/lib/factbase/indexed/indexed_term.rb +10 -1
- data/lib/factbase/version.rb +1 -1
- data/test/factbase/indexed/test_indexed_factbase.rb +35 -0
- data/test/factbase/test_impatient.rb +2 -30
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9bbcc978a4adafeac2404f3ac22be354029d5c7a1f14152d75d1db61aeaaecbe
|
4
|
+
data.tar.gz: 8f19d5e20248f1ab7f6202bb43172e0b1916d430df8d136c9d78ae5cec8f12df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9efd7278de80bcf3599ca631cdb7dfa174bcf8ac3fa258313b01f2ba4e097d09f3eaa6f8362331e94d337696dce8643ce3fe14c88fbf0a31db5e12756c81eb63
|
7
|
+
data.tar.gz: 793f55f9df33b7489478d4029ec75e2ea831802893d88e71ea13ffe31e689ef0232a94fad5795ac1e0459ac1da585cc07e0341da04612a3d97f93b7c2832f044
|
data/lib/factbase/impatient.rb
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
# SPDX-License-Identifier: MIT
|
5
5
|
|
6
6
|
require 'decoor'
|
7
|
+
require 'tago'
|
7
8
|
require 'timeout'
|
8
9
|
require_relative 'syntax'
|
9
10
|
|
@@ -19,7 +20,7 @@ class Factbase::Impatient
|
|
19
20
|
def initialize(fb, timeout: 15)
|
20
21
|
raise 'The "fb" is nil' if fb.nil?
|
21
22
|
@origin = fb
|
22
|
-
@timeout = timeout
|
23
|
+
@timeout = timeout.to_f
|
23
24
|
end
|
24
25
|
|
25
26
|
decoor(:origin)
|
@@ -55,31 +56,37 @@ class Factbase::Impatient
|
|
55
56
|
end
|
56
57
|
|
57
58
|
def each(fb = @fb, params = {}, &)
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
59
|
+
a =
|
60
|
+
impatient('each') do
|
61
|
+
@fb.query(@term, @maps).each(fb, params).to_a
|
62
|
+
end
|
63
|
+
return a unless block_given?
|
64
|
+
yielded = 0
|
65
|
+
a.each do |f|
|
66
|
+
yield f
|
67
|
+
yielded += 1
|
62
68
|
end
|
63
|
-
|
64
|
-
raise "Query timed out after #{@timeout} seconds: #{e.message}"
|
69
|
+
yielded
|
65
70
|
end
|
66
71
|
|
67
72
|
def one(fb = @fb, params = {})
|
68
|
-
|
69
|
-
|
70
|
-
qry.one(fb, params)
|
73
|
+
impatient('one') do
|
74
|
+
@fb.query(@term, @maps).one(fb, params)
|
71
75
|
end
|
72
|
-
rescue Timeout::Error => e
|
73
|
-
raise "Query timed out after #{@timeout} seconds: #{e.message}"
|
74
76
|
end
|
75
77
|
|
76
78
|
def delete!(fb = @fb)
|
77
|
-
|
78
|
-
|
79
|
-
qry.delete!(fb)
|
79
|
+
impatient('delete!') do
|
80
|
+
@fb.query(@term, @maps).delete!(fb)
|
80
81
|
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def impatient(name, &)
|
87
|
+
Timeout.timeout(@timeout, &)
|
81
88
|
rescue Timeout::Error => e
|
82
|
-
raise "
|
89
|
+
raise "#{name}() timed out after #{@timeout.seconds} (#{e.message}), fb size is #{@fb.size}: #{@term}"
|
83
90
|
end
|
84
91
|
end
|
85
92
|
end
|
@@ -40,6 +40,15 @@ module Factbase::IndexedTerm
|
|
40
40
|
end
|
41
41
|
end
|
42
42
|
(maps & []) | @idx[key]
|
43
|
+
when :absent
|
44
|
+
if @idx[key].nil?
|
45
|
+
@idx[key] = []
|
46
|
+
prop = @operands.first.to_s
|
47
|
+
maps.to_a.each do |m|
|
48
|
+
@idx[key].append(m) if m[prop].nil?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
(maps & []) | @idx[key]
|
43
52
|
when :eq
|
44
53
|
if @operands.first.is_a?(Symbol) && _scalar?(@operands[1])
|
45
54
|
if @idx[key].nil?
|
@@ -59,7 +68,7 @@ module Factbase::IndexedTerm
|
|
59
68
|
[@operands[1]]
|
60
69
|
end
|
61
70
|
if vv.empty?
|
62
|
-
|
71
|
+
(maps & [])
|
63
72
|
else
|
64
73
|
j = vv.map { |v| @idx[key][v] || [] }.reduce(&:|)
|
65
74
|
(maps & []) | j
|
data/lib/factbase/version.rb
CHANGED
@@ -3,6 +3,9 @@
|
|
3
3
|
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
4
4
|
# SPDX-License-Identifier: MIT
|
5
5
|
|
6
|
+
require 'elapsed'
|
7
|
+
require 'loog'
|
8
|
+
require 'timeout'
|
6
9
|
require_relative '../../test__helper'
|
7
10
|
require_relative '../../../lib/factbase'
|
8
11
|
require_relative '../../../lib/factbase/indexed/indexed_factbase'
|
@@ -58,4 +61,36 @@ class TestIndexedFactbase < Factbase::Test
|
|
58
61
|
fb.txn(&:insert)
|
59
62
|
refute_empty(fb.query('(always)').each.to_a)
|
60
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
|
61
96
|
end
|
@@ -81,20 +81,6 @@ class TestImpatient < Factbase::Test
|
|
81
81
|
assert_equal([42], fb.query('(agg (exists bar) (first bar))').one)
|
82
82
|
end
|
83
83
|
|
84
|
-
def test_query_timeout
|
85
|
-
fb = Factbase::Impatient.new(Factbase.new, timeout: 0.1)
|
86
|
-
1000.times do
|
87
|
-
fb.insert.value = rand(1000)
|
88
|
-
end
|
89
|
-
ex =
|
90
|
-
assert_raises(StandardError) do
|
91
|
-
fb.query('(always)').each do
|
92
|
-
sleep 0.2
|
93
|
-
end
|
94
|
-
end
|
95
|
-
assert_includes(ex.message, 'Query timed out after 0.1 seconds')
|
96
|
-
end
|
97
|
-
|
98
84
|
def test_query_one_timeout
|
99
85
|
slow = SlowFactbase.new
|
100
86
|
10_000.times do
|
@@ -105,7 +91,7 @@ class TestImpatient < Factbase::Test
|
|
105
91
|
assert_raises(StandardError) do
|
106
92
|
fb.query('(agg (min value))').one
|
107
93
|
end
|
108
|
-
assert_includes(ex.message, '
|
94
|
+
assert_includes(ex.message, 'timed out after')
|
109
95
|
end
|
110
96
|
|
111
97
|
def test_delete_timeout
|
@@ -118,7 +104,7 @@ class TestImpatient < Factbase::Test
|
|
118
104
|
assert_raises(StandardError) do
|
119
105
|
fb.query('(gt value 500)').delete!
|
120
106
|
end
|
121
|
-
assert_includes(ex.message, '
|
107
|
+
assert_includes(ex.message, 'timed out after')
|
122
108
|
end
|
123
109
|
|
124
110
|
def test_with_txn
|
@@ -131,20 +117,6 @@ class TestImpatient < Factbase::Test
|
|
131
117
|
assert_equal(1, fb.size)
|
132
118
|
end
|
133
119
|
|
134
|
-
def test_with_txn_timeout
|
135
|
-
fb = Factbase::Impatient.new(Factbase.new, timeout: 0.1)
|
136
|
-
fb.txn do |fbt|
|
137
|
-
fbt.insert.slow = 42
|
138
|
-
ex =
|
139
|
-
assert_raises(StandardError) do
|
140
|
-
fbt.query('(always)').each do
|
141
|
-
sleep 0.2
|
142
|
-
end
|
143
|
-
end
|
144
|
-
assert_includes(ex.message, 'Query timed out after 0.1 seconds')
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
120
|
def test_returns_int
|
149
121
|
fb = Factbase.new
|
150
122
|
fb.insert
|