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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0dd01490add2a273a8eb479d1cbbb13ab7489f08e2654de8e4d2ce6b141ff9c7
4
- data.tar.gz: d04b49fb4e9a0caa991143c5d7830d6d2a240a1753090f2c6ac52219e1460e2a
3
+ metadata.gz: 9bbcc978a4adafeac2404f3ac22be354029d5c7a1f14152d75d1db61aeaaecbe
4
+ data.tar.gz: 8f19d5e20248f1ab7f6202bb43172e0b1916d430df8d136c9d78ae5cec8f12df
5
5
  SHA512:
6
- metadata.gz: e7979d0c8e440a3f93891182d50d069b84fdbf403e080dfcc55999d9f12e848554c8282533214e56ad34a9467a8ac9d6700d64e08dff876c70fa6d521afb4f00
7
- data.tar.gz: 6a9d7711e79ed74ae956f29d13de51e4c6715910c394c273636c875acaf5526223b1813a2d780f977f4049d19e6b734b5cf8832178b69a1f264b3e38888244bd
6
+ metadata.gz: 9efd7278de80bcf3599ca631cdb7dfa174bcf8ac3fa258313b01f2ba4e097d09f3eaa6f8362331e94d337696dce8643ce3fe14c88fbf0a31db5e12756c81eb63
7
+ data.tar.gz: 793f55f9df33b7489478d4029ec75e2ea831802893d88e71ea13ffe31e689ef0232a94fad5795ac1e0459ac1da585cc07e0341da04612a3d97f93b7c2832f044
@@ -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
- return to_enum(__method__, fb, params) unless block_given?
59
- qry = @fb.query(@term, @maps)
60
- Timeout.timeout(@timeout) do
61
- qry.each(fb, params, &)
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
- rescue Timeout::Error => e
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
- qry = @fb.query(@term, @maps)
69
- Timeout.timeout(@timeout) do
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
- qry = @fb.query(@term, @maps)
78
- Timeout.timeout(@timeout) do
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 "Query timed out after #{@timeout} seconds: #{e.message}"
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
- nil
71
+ (maps & [])
63
72
  else
64
73
  j = vv.map { |v| @idx[key][v] || [] }.reduce(&:|)
65
74
  (maps & []) | j
@@ -9,5 +9,5 @@
9
9
  # License:: MIT
10
10
  class Factbase
11
11
  # Current version of the gem (changed by .rultor.yml on every release)
12
- VERSION = '0.14.1' unless const_defined?(:VERSION)
12
+ VERSION = '0.14.3' unless const_defined?(:VERSION)
13
13
  end
@@ -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, 'Query timed out after 0.01 seconds')
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, 'Query timed out after 0.01 seconds')
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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: factbase
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.1
4
+ version: 0.14.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko