factbase 0.9.0 → 0.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d9aeae89fbcf5e3c1b74f475a8ad001867869d29eab8b861a26b07a2fee9db93
4
- data.tar.gz: 0c20ed8b499cb495ca438621b30c24c9c837a73c8cffdde812ecacabc7b9a49c
3
+ metadata.gz: d4918d14dba9ff6a434de85e418f0f8249b4e3ea2e3bf7ae1c7cd1ed0836b20c
4
+ data.tar.gz: 2810d6061d951226e42b51f8d0f6afb27698ad16bdda448088a7dff7dd930937
5
5
  SHA512:
6
- metadata.gz: 5f342a46704cdfa9f4355726fd7ca98f6a20d44090fd84c70e69189167abb97c378aca6f52fb295e736acbe4f501d61c65dd93ae833338327be8e81c9bb8f9a7
7
- data.tar.gz: 0ec8785757ba4a370e0b1f50b3a7d50271e5245278b23d1b6a45618c90676517bf45763af7f5b150c606c22571992fcd15a95e771e661d2f62308add8e97d93a
6
+ metadata.gz: 975e9b4c4deda01bd2177c44adbf9049b784ffa76e17b3718f9a6103582eda766c5ae9df7eb92235acaa25823ed8a5bfa42cfd5245a11182132d977c2851ff65
7
+ data.tar.gz: 914915154434ed8265aad9c1cda22e8e6dbd14ba3f2248478f45579418aa4dcb90752550eab337c80936faba9e384dd09b44539a6ff74278b71d4298b2efc858
data/Gemfile.lock CHANGED
@@ -14,9 +14,9 @@ PATH
14
14
  GEM
15
15
  remote: https://rubygems.org/
16
16
  specs:
17
- actionpack (8.0.1)
18
- actionview (= 8.0.1)
19
- activesupport (= 8.0.1)
17
+ actionpack (8.0.2)
18
+ actionview (= 8.0.2)
19
+ activesupport (= 8.0.2)
20
20
  nokogiri (>= 1.8.5)
21
21
  rack (>= 2.2.4)
22
22
  rack-session (>= 1.0.1)
@@ -24,13 +24,13 @@ GEM
24
24
  rails-dom-testing (~> 2.2)
25
25
  rails-html-sanitizer (~> 1.6)
26
26
  useragent (~> 0.16)
27
- actionview (8.0.1)
28
- activesupport (= 8.0.1)
27
+ actionview (8.0.2)
28
+ activesupport (= 8.0.2)
29
29
  builder (~> 3.1)
30
30
  erubi (~> 1.11)
31
31
  rails-dom-testing (~> 2.2)
32
32
  rails-html-sanitizer (~> 1.6)
33
- activesupport (8.0.1)
33
+ activesupport (8.0.2)
34
34
  base64
35
35
  benchmark (>= 0.3)
36
36
  bigdecimal
@@ -66,7 +66,7 @@ GEM
66
66
  pp (>= 0.6.0)
67
67
  rdoc (>= 4.0.0)
68
68
  reline (>= 0.4.2)
69
- json (2.10.1)
69
+ json (2.10.2)
70
70
  language_server-protocol (3.17.0.4)
71
71
  lint_roller (1.1.0)
72
72
  logger (1.6.6)
@@ -100,7 +100,7 @@ GEM
100
100
  date
101
101
  stringio
102
102
  racc (1.8.1)
103
- rack (3.1.11)
103
+ rack (3.1.12)
104
104
  rack-session (2.1.0)
105
105
  base64 (>= 0.1.0)
106
106
  rack (>= 3.0.0)
@@ -115,9 +115,9 @@ GEM
115
115
  rails-html-sanitizer (1.6.2)
116
116
  loofah (~> 2.21)
117
117
  nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
118
- railties (8.0.1)
119
- actionpack (= 8.0.1)
120
- activesupport (= 8.0.1)
118
+ railties (8.0.2)
119
+ actionpack (= 8.0.2)
120
+ activesupport (= 8.0.2)
121
121
  irb (~> 1.13)
122
122
  rackup (>= 1.0.0)
123
123
  rake (>= 12.2)
data/README.md CHANGED
@@ -209,33 +209,33 @@ This is the result of the benchmark:
209
209
  <!-- benchmark_begin -->
210
210
  ```text
211
211
  user system total real
212
- insert 20000 facts 0.561512 0.006100 0.567612 ( 0.567669)
213
- export 20000 facts 0.021207 0.001926 0.023133 ( 0.023136)
214
- import 411017 bytes (20000 facts) 0.030268 0.004025 0.034293 ( 0.034298)
215
- insert 10 facts 0.041799 0.003981 0.045780 ( 0.045783)
216
- query 10 times w/txn 1.949384 0.022040 1.971424 ( 1.971572)
217
- query 10 times w/o txn 0.766215 0.000000 0.766215 ( 0.766298)
218
- modify 10 attrs w/txn 1.831320 0.019013 1.850333 ( 1.850663)
219
- delete 10 facts w/txn 0.720217 0.000982 0.721199 ( 0.721265)
220
- (and (eq what 'issue-was-closed') (exists... -> 200 2.699199 0.003986 2.703185 ( 2.703395)
221
- (and (eq what 'issue-was-closed') (exists... -> 200/txn 2.711764 0.003998 2.715762 ( 2.716000)
222
- (and (eq what 'issue-was-closed') (exists... -> zero 4.091858 0.003001 4.094859 ( 4.095101)
223
- (and (eq what 'issue-was-closed') (exists... -> zero/txn 4.156396 0.003004 4.159400 ( 4.159589)
224
- (gt time '2024-03-23T03:21:43Z') 0.104266 0.001002 0.105268 ( 0.105284)
225
- (gt cost 50) 0.090716 0.000000 0.090716 ( 0.090721)
226
- (eq title 'Object Thinking 5000') 0.005533 0.000002 0.005535 ( 0.005536)
227
- (and (eq foo 42.998) (or (gt bar 200) (absent zzz))) 0.053251 0.000002 0.053253 ( 0.053255)
228
- (eq id (agg (always) (max id))) 0.300388 0.000000 0.300388 ( 0.300414)
229
- (join "c<=cost,b<=bar" (eq id (agg (always) (max id)))) 1.254507 0.002999 1.257506 ( 1.257555)
230
- delete! 0.051979 0.000000 0.051979 ( 0.051982)
231
- Taped.append() x50000 0.028540 0.000000 0.028540 ( 0.028543)
232
- Taped.each() x125 1.332618 0.000000 1.332618 ( 1.332645)
233
- Taped.delete_if() x375 0.815309 0.000000 0.815309 ( 0.815348)
212
+ insert 20000 facts 0.625135 0.006294 0.631429 ( 0.631443)
213
+ export 20000 facts 0.023877 0.000991 0.024868 ( 0.024873)
214
+ import 411050 bytes (20000 facts) 0.034864 0.004984 0.039848 ( 0.039853)
215
+ insert 10 facts 0.045526 0.002959 0.048485 ( 0.048490)
216
+ query 10 times w/txn 2.221776 0.028103 2.249879 ( 2.249996)
217
+ query 10 times w/o txn 0.842098 0.002019 0.844117 ( 0.844159)
218
+ modify 10 attrs w/txn 2.056211 0.014021 2.070232 ( 2.070541)
219
+ delete 10 facts w/txn 0.770236 0.003988 0.774224 ( 0.774272)
220
+ (and (eq what 'issue-was-closed') (exists... -> 200 2.805609 0.003005 2.808614 ( 2.808765)
221
+ (and (eq what 'issue-was-closed') (exists... -> 200/txn 2.812425 0.002000 2.814425 ( 2.814779)
222
+ (and (eq what 'issue-was-closed') (exists... -> zero 4.288405 0.000001 4.288406 ( 4.288758)
223
+ (and (eq what 'issue-was-closed') (exists... -> zero/txn 4.320962 0.008005 4.328967 ( 4.329469)
224
+ (gt time '2024-03-23T03:21:43Z') 0.116707 0.001996 0.118703 ( 0.118716)
225
+ (gt cost 50) 0.093508 0.000004 0.093512 ( 0.093517)
226
+ (eq title 'Object Thinking 5000') 0.006989 0.000000 0.006989 ( 0.006990)
227
+ (and (eq foo 42.998) (or (gt bar 200) (absent zzz))) 0.060383 0.000002 0.060385 ( 0.060385)
228
+ (eq id (agg (always) (max id))) 0.357125 0.000994 0.358119 ( 0.358130)
229
+ (join "c<=cost,b<=bar" (eq id (agg (always) (max id)))) 1.350979 0.000001 1.350980 ( 1.351072)
230
+ delete! 0.054491 0.000004 0.054495 ( 0.054497)
231
+ Taped.append() x50000 0.048166 0.001997 0.050163 ( 0.050167)
232
+ Taped.each() x125 1.347655 0.002002 1.349657 ( 1.349747)
233
+ Taped.delete_if() x375 0.846874 0.000003 0.846877 ( 0.846926)
234
234
  ```
235
235
 
236
236
  The results were calculated in [this GHA job][benchmark-gha]
237
- on 2025-03-12 at 08:03,
237
+ on 2025-03-12 at 13:25,
238
238
  on Linux with 4 CPUs.
239
239
  <!-- benchmark_end -->
240
240
 
241
- [benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/13806425302
241
+ [benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/13812482648
data/lib/factbase/inv.rb CHANGED
@@ -8,6 +8,17 @@ require 'decoor'
8
8
  require_relative '../factbase'
9
9
 
10
10
  # A decorator of a Factbase, that checks invariants on every set.
11
+ #
12
+ # For example, you can use this decorator if you want to check that every
13
+ # fact has +when+:
14
+ #
15
+ # fb = Factbase::Inv.new(Factbase.new) do |f, fbt|
16
+ # assert !f['when'].nil?
17
+ # end
18
+ #
19
+ # The second argument passed to the block is the factbase, while the first
20
+ # one is the fact just touched.
21
+ #
11
22
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
12
23
  # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
13
24
  # License:: MIT
@@ -23,8 +34,8 @@ class Factbase::Inv
23
34
  Fact.new(@fb.insert, @block)
24
35
  end
25
36
 
26
- def query(query)
27
- Query.new(@fb.query(query), @block)
37
+ def query(query, maps = nil)
38
+ Query.new(@fb.query(query, maps), @block, self)
28
39
  end
29
40
 
30
41
  def txn
@@ -65,14 +76,15 @@ class Factbase::Inv
65
76
  class Query
66
77
  decoor(:query)
67
78
 
68
- def initialize(query, block)
79
+ def initialize(query, block, fb)
69
80
  @query = query
70
81
  @block = block
82
+ @fb = fb
71
83
  end
72
84
 
73
- def each
74
- return to_enum(__method__) unless block_given?
75
- @query.each do |f|
85
+ def each(fb = @fb, params = {})
86
+ return to_enum(__method__, fb, params) unless block_given?
87
+ @query.each(fb, params) do |f|
76
88
  yield Fact.new(f, @block)
77
89
  end
78
90
  end
@@ -22,7 +22,7 @@ class Factbase::Logged
22
22
  # @param [Print] tube The tube to use, if log is NIL
23
23
  def initialize(fb, log = nil, time_tolerate: 1, tube: nil)
24
24
  raise 'The "fb" is nil' if fb.nil?
25
- @fb = fb
25
+ @origin = fb
26
26
  if log.nil?
27
27
  raise 'Either "log" or "tube" must be non-NIL' if tube.nil?
28
28
  @tube = tube
@@ -31,17 +31,18 @@ class Factbase::Logged
31
31
  end
32
32
  end
33
33
 
34
- decoor(:fb)
34
+ decoor(:origin)
35
35
 
36
36
  def insert
37
37
  start = Time.now
38
- f = @fb.insert
39
- @tube.say(start, "Inserted new fact ##{@fb.size} in #{start.ago}")
38
+ f = @origin.insert
39
+ @tube.say(start, "Inserted new fact ##{@origin.size} in #{start.ago}")
40
40
  Fact.new(f, tube: @tube)
41
41
  end
42
42
 
43
- def query(query)
44
- Query.new(query, @tube, @fb)
43
+ def query(term, maps = nil)
44
+ term = to_term(term) if term.is_a?(String)
45
+ Query.new(term, maps, @tube, @origin)
45
46
  end
46
47
 
47
48
  def txn
@@ -49,7 +50,7 @@ class Factbase::Logged
49
50
  id = nil
50
51
  rollback = false
51
52
  r =
52
- @fb.txn do |fbt|
53
+ @origin.txn do |fbt|
53
54
  id = fbt.object_id
54
55
  yield Factbase::Logged.new(fbt, tube: @tube)
55
56
  rescue Factbase::Rollback => e
@@ -122,40 +123,25 @@ class Factbase::Logged
122
123
  # Query decorator.
123
124
  #
124
125
  # This is an internal class, it is not supposed to be instantiated directly.
125
- #
126
126
  class Query
127
- def initialize(expr, tube, fb)
128
- @expr = expr
127
+ def initialize(term, maps, tube, fb)
128
+ @term = term
129
+ @maps = maps
129
130
  @tube = tube
130
131
  @fb = fb
131
132
  end
132
133
 
133
- def one(fb = @fb, params = {})
134
- start = Time.now
135
- q = Factbase::Syntax.new(@expr).to_term.to_s
136
- r = nil
137
- tail =
138
- Factbase::Logged.elapsed do
139
- r = fb.query(@expr).one(fb, params)
140
- end
141
- if r.nil?
142
- @tube.say(start, "Nothing found by '#{q}' #{tail}")
143
- else
144
- @tube.say(start, "Found #{r} (#{r.class}) by '#{q}' #{tail}")
145
- end
146
- r
147
- end
148
-
149
- def each(fb = @fb, params = {}, &)
134
+ def each(fb = nil, params = {}, &)
135
+ return to_enum(__method__, fb, params) unless block_given?
150
136
  start = Time.now
151
- q = Factbase::Syntax.new(@expr).to_term.to_s
137
+ q = Factbase::Syntax.new(@term).to_term.to_s
152
138
  if block_given?
153
139
  r = nil
154
140
  tail =
155
141
  Factbase::Logged.elapsed do
156
- r = fb.query(@expr).each(fb, params, &)
142
+ r = @fb.query(@term, @maps).each(@fb, params, &)
157
143
  end
158
- raise ".each of #{@expr.class} returned #{r.class}" unless r.is_a?(Integer)
144
+ raise ".each of #{@term.class} returned #{r.class}" unless r.is_a?(Integer)
159
145
  if r.zero?
160
146
  @tube.say(start, "Nothing found by '#{q}' #{tail}")
161
147
  else
@@ -166,7 +152,7 @@ class Factbase::Logged
166
152
  array = []
167
153
  tail =
168
154
  Factbase::Logged.elapsed do
169
- fb.query(@expr).each(fb, params) do |f|
155
+ @fb.query(@term, @maps).each(@fb, params) do |f|
170
156
  array << f
171
157
  end
172
158
  end
@@ -179,21 +165,37 @@ class Factbase::Logged
179
165
  end
180
166
  end
181
167
 
182
- def delete!(fb = @fb)
168
+ def one(_fb = nil, params = {})
169
+ start = Time.now
170
+ q = Factbase::Syntax.new(@term).to_term.to_s
171
+ r = nil
172
+ tail =
173
+ Factbase::Logged.elapsed do
174
+ r = @fb.query(@term, @maps).one(@fb, params)
175
+ end
176
+ if r.nil?
177
+ @tube.say(start, "Nothing found by '#{q}' #{tail}")
178
+ else
179
+ @tube.say(start, "Found #{r} (#{r.class}) by '#{q}' #{tail}")
180
+ end
181
+ r
182
+ end
183
+
184
+ def delete!(_fb = nil)
183
185
  r = nil
184
186
  start = Time.now
185
- before = fb.size
187
+ before = @fb.size
186
188
  tail =
187
189
  Factbase::Logged.elapsed do
188
- r = @fb.query(@expr).delete!(fb)
190
+ r = @fb.query(@term).delete!(@fb)
189
191
  end
190
- raise ".delete! of #{@expr.class} returned #{r.class}" unless r.is_a?(Integer)
192
+ raise ".delete! of #{@term.class} returned #{r.class}" unless r.is_a?(Integer)
191
193
  if before.zero?
192
- @tube.say(start, "There were no facts, nothing deleted by '#{@expr}' #{tail}")
194
+ @tube.say(start, "There were no facts, nothing deleted by '#{@term}' #{tail}")
193
195
  elsif r.zero?
194
- @tube.say(start, "No facts out of #{before} deleted by '#{@expr}' #{tail}")
196
+ @tube.say(start, "No facts out of #{before} deleted by '#{@term}' #{tail}")
195
197
  else
196
- @tube.say(start, "Deleted #{r} fact(s) out of #{before} by '#{@expr}' #{tail}")
198
+ @tube.say(start, "Deleted #{r} fact(s) out of #{before} by '#{@term}' #{tail}")
197
199
  end
198
200
  r
199
201
  end
@@ -40,8 +40,8 @@ class Factbase::Rules
40
40
  Fact.new(@fb.insert, @check, @fb)
41
41
  end
42
42
 
43
- def query(query)
44
- Query.new(@fb.query(query), @check, @fb)
43
+ def query(query, maps = nil)
44
+ Query.new(@fb.query(query, maps), @check, @fb)
45
45
  end
46
46
 
47
47
  def txn
@@ -31,8 +31,8 @@ class Factbase::Tallied
31
31
  f
32
32
  end
33
33
 
34
- def query(query)
35
- Query.new(@fb.query(query), @churn, @fb)
34
+ def query(query, maps = nil)
35
+ Query.new(@fb.query(query, maps), @churn, @fb)
36
36
  end
37
37
 
38
38
  def txn
data/lib/factbase.rb CHANGED
@@ -82,7 +82,7 @@ require 'yaml'
82
82
  # License:: MIT
83
83
  class Factbase
84
84
  # Current version of the gem (changed by .rultor.yml on every release)
85
- VERSION = '0.9.0'
85
+ VERSION = '0.9.1'
86
86
 
87
87
  # An exception that may be thrown in a transaction, to roll it back.
88
88
  class Rollback < StandardError; end
@@ -4,9 +4,15 @@
4
4
  # SPDX-License-Identifier: MIT
5
5
 
6
6
  require_relative '../test__helper'
7
+ require 'loog'
7
8
  require 'time'
8
9
  require_relative '../../lib/factbase'
9
10
  require_relative '../../lib/factbase/query'
11
+ require_relative '../../lib/factbase/logged'
12
+ require_relative '../../lib/factbase/pre'
13
+ require_relative '../../lib/factbase/inv'
14
+ require_relative '../../lib/factbase/rules'
15
+ require_relative '../../lib/factbase/tallied'
10
16
  require_relative '../../lib/factbase/cached/cached_factbase'
11
17
  require_relative '../../lib/factbase/indexed/indexed_factbase'
12
18
  require_relative '../../lib/factbase/sync/sync_factbase'
@@ -227,9 +233,14 @@ class TestQuery < Factbase::Test
227
233
  def with_factbases(maps = [], &)
228
234
  {
229
235
  'plain' => Factbase.new(maps),
236
+ 'pre+plain' => Factbase::Pre.new(Factbase.new(maps)) { nil },
237
+ 'rules+plain' => Factbase::Rules.new(Factbase.new(maps), '(always)'),
238
+ 'inv+plain' => Factbase::Inv.new(Factbase.new(maps)) { nil },
230
239
  'sync+plain' => Factbase::SyncFactbase.new(Factbase.new(maps)),
240
+ 'tallied+plain' => Factbase::Tallied.new(Factbase.new(maps)),
231
241
  'indexed+plain' => Factbase::IndexedFactbase.new(Factbase.new(maps)),
232
242
  'cached+plain' => Factbase::CachedFactbase.new(Factbase.new(maps)),
243
+ 'logged+plain' => Factbase::Logged.new(Factbase.new(maps), Loog::NULL),
233
244
  'indexed+cached+plain' => Factbase::IndexedFactbase.new(Factbase::CachedFactbase.new(Factbase.new(maps))),
234
245
  'cached+indexed+plain' => Factbase::CachedFactbase.new(Factbase::IndexedFactbase.new(Factbase.new(maps))),
235
246
  'sync+cached+indexed+plain' => Factbase::SyncFactbase.new(
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.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko