Skip to content

Commit 74ae8b8

Browse files
committed
#192: cache works
1 parent ed983c4 commit 74ae8b8

11 files changed

+80
-38
lines changed

Rakefile

+2-2
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ task :benchmark do
4646
fb = Factbase.new
4747
require_relative 'lib/factbase/cached/cached_factbase'
4848
fb = Factbase::CachedFactbase.new(fb)
49-
require_relative 'lib/factbase/indexed/indexed_factbase'
50-
fb = Factbase::IndexedFactbase.new(fb)
49+
# require_relative 'lib/factbase/indexed/indexed_factbase'
50+
# fb = Factbase::IndexedFactbase.new(fb)
5151
require_relative 'lib/factbase/sync/sync_factbase'
5252
fb = Factbase::SyncFactbase.new(fb)
5353
require 'benchmark'

lib/factbase.rb

+9-1
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,19 @@ def insert
135135
# @param [Array<Hash>|nil] maps The subset of maps (if provided)
136136
def query(term, maps = nil)
137137
maps ||= @maps
138+
term = to_term(term) if term.is_a?(String)
138139
require_relative 'factbase/query'
139-
term = Factbase::Syntax.new(term).to_term(self) if term.is_a?(String)
140140
Factbase::Query.new(maps, term)
141141
end
142142

143+
# Convert a query to a term.
144+
# @param [String] query The query to convert
145+
# @return [Factbase::Term] The term
146+
def to_term(query)
147+
require_relative 'factbase/syntax'
148+
Factbase::Syntax.new(query).to_term(self)
149+
end
150+
143151
# Run an ACID transaction, which will either modify the factbase
144152
# or rollback in case of an error.
145153
#

lib/factbase/cached/cached_factbase.rb

+11-3
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,22 @@ def insert
3131
Factbase::CachedFact.new(@origin.insert, @cache)
3232
end
3333

34+
# Convert a query to a term.
35+
# @param [String] query The query to convert
36+
# @return [Factbase::Term] The term
37+
def to_term(query)
38+
require_relative 'cached_term'
39+
@origin.to_term(query).redress(Factbase::CachedTerm, cache: @cache)
40+
end
41+
3442
# Create a query capable of iterating.
3543
# @param [String] term The term to use
3644
# @param [Array<Hash>] maps Possible maps to use
3745
def query(term, maps = nil)
38-
require_relative 'cached_term'
3946
if term.is_a?(String)
40-
term = Factbase::Syntax.new(term, term: Factbase::CachedTerm).to_term(self)
41-
term.inject_cache(@cache)
47+
term = to_term(term)
48+
else
49+
term = term.redress(Factbase::CachedTerm)
4250
end
4351
q = @origin.query(term, maps)
4452
unless term.abstract?

lib/factbase/cached/cached_term.rb

+3-12
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,10 @@ class Factbase::CachedTerm < Factbase::Term
1515
# @param [Symbol] operator Operator
1616
# @param [Array] operands Operands
1717
# @param [Factbase] fb Optional factbase reference
18-
def initialize(operator, operands, fb: nil)
19-
super
20-
@cacheable = static? && !abstract?
21-
end
22-
23-
# Inject cache into this term and all others inside.
24-
# @param [Hash] cache The cache
25-
def inject_cache(cache)
18+
def initialize(operator, operands, fb: nil, cache: {})
19+
super(operator, operands, fb: fb)
2620
@cache = cache
27-
@operands.each do |o|
28-
next unless o.is_a?(Factbase::CachedTerm)
29-
o.inject_cache(cache)
30-
end
21+
@cacheable = static? && !abstract?
3122
end
3223

3324
# Does it match the fact?

lib/factbase/indexed/indexed_factbase.rb

+8-1
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,18 @@ def insert
3131
Factbase::IndexedFact.new(@origin.insert, @idx)
3232
end
3333

34+
# Convert a query to a term.
35+
# @param [String] query The query to convert
36+
# @return [Factbase::Term] The term
37+
def to_term(query)
38+
@origin.to_term(query)
39+
end
40+
3441
# Create a query capable of iterating.
3542
# @param [String] term The term to use
3643
# @param [Array<Hash>] maps Possible maps to use
3744
def query(term, maps = nil)
38-
term = Factbase::Syntax.new(term).to_term(self) if term.is_a?(String)
45+
term = to_term(term) if term.is_a?(String)
3946
require_relative 'indexed_query'
4047
Factbase::IndexedQuery.new(@origin.query(term, maps), @idx)
4148
end

lib/factbase/light.rb

+4
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ def insert
2323
@fb.insert
2424
end
2525

26+
def to_term(query)
27+
@fb.to_term(query)
28+
end
29+
2630
def query(query, maps = nil)
2731
@fb.query(query, maps)
2832
end

lib/factbase/sync/sync_factbase.rb

+8-1
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,18 @@ def insert
3030
end
3131
end
3232

33+
# Convert a query to a term.
34+
# @param [String] query The query to convert
35+
# @return [Factbase::Term] The term
36+
def to_term(query)
37+
@origin.to_term(query)
38+
end
39+
3340
# Create a query capable of iterating.
3441
# @param [String] term The query to use for selections
3542
# @param [Array<Hash>] maps Possible maps to use
3643
def query(term, maps = nil)
37-
term = Factbase::Syntax.new(term).to_term(@origin) if term.is_a?(String)
44+
term = to_term(term) if term.is_a?(String)
3845
@mutex.synchronize do
3946
require_relative 'sync_query'
4047
Factbase::SyncQuery.new(@origin.query(term, maps), @mutex)

lib/factbase/syntax.rb

+4-18
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,10 @@
99
require_relative 'fact'
1010
require_relative 'term'
1111

12-
# Syntax.
12+
# Syntax parser.
1313
#
1414
# This is an internal class, it is not supposed to be instantiated directly.
1515
#
16-
# However, you can use it directly, if you need a parser of our syntax. You can
17-
# create your own "Term" class and let this parser make instances of it for
18-
# every term it meets in the query:
19-
#
20-
# require 'factbase/syntax'
21-
# t = Factbase::Syntax.new('(hello world)', MyTerm).to_term
22-
#
23-
# The +MyTerm+ class should have a constructor with two arguments:
24-
# the operator and the list of operands (Array).
25-
#
2616
# Author:: Yegor Bugayenko ([email protected])
2717
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
2818
# License:: MIT
@@ -37,12 +27,8 @@ class Broken < StandardError; end
3727
# a child of +Factbase::Term+.
3828
#
3929
# @param [String] query The query, for example "(eq id 42)"
40-
# @param [Class] term The class to instantiate to make every term
41-
def initialize(query, term: Factbase::Term)
30+
def initialize(query)
4231
@query = query
43-
raise "Term must be a Class, while #{term.class.name} provided" unless term.is_a?(Class)
44-
raise "The 'term' must be a child of Factbase::Term, while #{term.name} provided" unless term <= Factbase::Term
45-
@term = term
4632
end
4733

4834
# Convert it to a term.
@@ -73,7 +59,7 @@ def build(fb)
7359
raise "Too many terms (#{@ast[1]} != #{@tokens.size})" if @ast[1] != @tokens.size
7460
t = @ast[0]
7561
raise 'No terms found in the AST' if t.nil?
76-
raise "#{t.class.name} is not an instance of #{@term}, thus not a proper term" unless t.is_a?(@term)
62+
raise "#{t.class.name} is not an instance of Term" unless t.is_a?(Factbase::Term)
7763
t
7864
end
7965

@@ -107,7 +93,7 @@ def to_ast(tokens, at, fb)
10793
operands << operand
10894
break if tokens[at] == :close
10995
end
110-
t = @term.new(op, operands, fb:)
96+
t = Factbase::Term.new(op, operands, fb:)
11197
[t, at + 1]
11298
end
11399

lib/factbase/term.rb

+15
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,21 @@ def initialize(operator, operands, fb: Factbase.new)
8787
@fb = fb
8888
end
8989

90+
def redress(type, **args)
91+
type.new(
92+
@op,
93+
@operands.map do |op|
94+
if op.is_a?(Factbase::Term)
95+
op.redress(type, **args)
96+
else
97+
op
98+
end
99+
end,
100+
fb: @fb,
101+
**args
102+
)
103+
end
104+
90105
# Does it match the fact?
91106
# @param [Factbase::Fact] fact The fact
92107
# @param [Array<Factbase::Fact>] maps All maps available

test/factbase/cached/test_cached_query.rb

+10
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ def test_aggregates_too
3131
assert_equal(1, fb.query('(eq foo (agg (exists hello) (min foo)))').each.to_a.size)
3232
end
3333

34+
def test_caches_while_being_decorated
35+
fb = Factbase::SyncFactbase.new(Factbase::CachedFactbase.new(Factbase.new))
36+
10_000.times do |i|
37+
f = fb.insert
38+
f.foo = i
39+
f.hello = 1
40+
end
41+
assert_equal(1, fb.query('(eq foo (agg (exists hello) (min foo)))').each.to_a.size)
42+
end
43+
3444
def test_deletes_too
3545
fb = Factbase::CachedFactbase.new(Factbase.new)
3646
fb.insert.foo = 1

test/test_factbase.rb

+6
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ def test_query_many_times
4141
end
4242
end
4343

44+
def test_converts_query_to_term
45+
fb = Factbase.new
46+
term = fb.to_term('(eq foo 42)')
47+
assert_equal('(eq foo 42)', term.to_s)
48+
end
49+
4450
def test_simple_setting
4551
fb = Factbase.new
4652
fb.insert

0 commit comments

Comments
 (0)