Skip to content

Commit

Permalink
Add option regexp_function_cache_class in sqlite adapter
Browse files Browse the repository at this point in the history
Also add sqlite adapter specs for when setup_regexp_function=cached
option is used.
  • Loading branch information
paddor authored and jeremyevans committed Jan 5, 2024
1 parent c078533 commit a6cc908
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 4 deletions.
19 changes: 15 additions & 4 deletions lib/sequel/adapters/sqlite.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ def initialize(opts = OPTS)
# it will be called with a string for the regexp and a string
# for the value to compare, and should return whether the regexp
# matches.
# :regexp_function_cache_class :: Defaults to Hash. To avoid a potential
# memory leak, pass ObjectSpace::WeakKeyMap.
def connect(server)
opts = server_opts(server)
opts[:database] = ':memory:' if blank_object?(opts[:database])
Expand All @@ -133,7 +135,7 @@ def connect(server)
connection_pragmas.each{|s| log_connection_yield(s, db){db.execute_batch(s)}}

if typecast_value_boolean(opts[:setup_regexp_function])
setup_regexp_function(db, opts[:setup_regexp_function])
setup_regexp_function(db, opts[:setup_regexp_function], opts[:regexp_function_cache_class])
end

class << db
Expand Down Expand Up @@ -208,13 +210,22 @@ def adapter_initialize
set_integer_booleans
end

def setup_regexp_function(db, how)
def setup_regexp_function(db, how, cache_class)
case how
when Proc
# nothing
when :cached, "cached"
cache = Hash.new{|h,k| h[k] = Regexp.new(k)}
how = lambda{|regexp_str, str| cache[regexp_str].match(str)}
cache_class ||= Hash
cache = cache_class.new
how = lambda do |regexp_str, str|
if regexp = cache[regexp_str]
regexp.match(str)
else
regexp = Regexp.new(regexp_str)
cache[regexp_str] = regexp
regexp.match(str)
end
end
else
how = lambda{|regexp_str, str| Regexp.new(regexp_str).match(str)}
end
Expand Down
41 changes: 41 additions & 0 deletions spec/adapters/sqlite_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -878,3 +878,44 @@
@db.get(ja.valid).must_equal 1
end
end if DB.sqlite_version >= 33800


describe 'Regexp support' do
before do
@db = DB

@db.create_table(:names) do
primary_key :id
String :name
end

@db[:names].insert(name: 'Adam')
@db[:names].insert(name: 'Jane')
@db[:names].insert(name: 'John')
@db[:names].insert(name: 'Leo')
@db[:names].insert(name: 'Tim')
@db[:names].insert(name: 'Tom')
end
after do
@db.drop_table?(:names)
end

it "should support regexp" do
@db.must_be :allow_regexp?
end

it "should find by regexp" do
names = @db[:names].where(name: /^J/).map { |row| row[:name] }
names.must_include 'Jane'
names.must_include 'John'
names.wont_include 'Adam'
end

it "caches regexp" do
before = ObjectSpace.count_objects[:T_REGEXP]
@db[:names].where(name: /^J/)
after = ObjectSpace.count_objects[:T_REGEXP]
diff = after - before
diff.must_be :<=, 1
end if [:cached, "cached"].include? DB.opts[:setup_regexp_function]
end if DB.adapter_scheme == :sqlite && DB.opts[:setup_regexp_function]

0 comments on commit a6cc908

Please sign in to comment.