full_search 0.3.0 → 0.3.2

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: 50bb1c53fe9f326612a2413a441a37acfe48f25bf4730786de3631c7230b2572
4
- data.tar.gz: ab53bbd57f8fd9cb464af29d37aa70cd0efb18a2835eff1b501d61a14d0de43f
3
+ metadata.gz: 540d8604b539de87bf3d8448c33319a80853132d5d1911d8d0c12bbc35f87ea0
4
+ data.tar.gz: 63d7304396d67181ed0b35d35b37996801b901c7c9998d08945b6be88754d09f
5
5
  SHA512:
6
- metadata.gz: ab98601c786c02808246cf4657ef7c3912e36e0fbc429417c0ff564a3ec1e2575216fda8d64ee2ab22db32c707bcbce0915fcc3d57038059f1dfe05bde48963e
7
- data.tar.gz: 52564a1ce083d5aa0f6cb624f8f9aa4a0bb0ac13a85216f14a857a5c2c2c744d37fa4370272679c3bd13c76eb6ec732814463cfa143bb714654243968c6c800c
6
+ metadata.gz: aeb01d6b88bcf617d83f273dbdbb3ace5bb1f12fa8094ad978d96f88f31ab058d12000e6964454d8f6630bd1f6fe70b6debe5ed3937445e8e07ac8de091e0fd7
7
+ data.tar.gz: ba24e0621fcf6ebb6857cc820a96b0a2a9fde6c43953602dd9a295592fdb5e162a8e63dd91bcdca17ec8e63d913d08fd475b77402dac2a7f0b17f232996cfabd
data/README.md CHANGED
@@ -6,7 +6,7 @@ SQLite FTS5 full-text search for Rails/ActiveRecord. A lightweight, self-contain
6
6
 
7
7
  ## Requirements
8
8
 
9
- - Ruby 3.1+
9
+ - Ruby 3.2+
10
10
  - Rails 8.0+
11
11
  - SQLite 3.34+ (if using typo tolerance)
12
12
 
@@ -59,12 +59,16 @@ module FullSearch
59
59
  conn.execute(
60
60
  "UPDATE #{table} SET #{qc(field.name)} = #{q(value.to_s)} WHERE rowid = #{q(record.id)}"
61
61
  )
62
+ rescue => e
63
+ raise unless e.message.include?("no such table")
62
64
  end
63
65
 
64
66
  def self.remove_record!(record)
65
67
  table = qt(FullSearch::Index.fts_table_name(record.class))
66
68
  conn = ActiveRecord::Base.connection
67
69
  conn.execute("DELETE FROM #{table} WHERE rowid = #{q(record.id)}")
70
+ rescue => e
71
+ raise unless e.message.include?("no such table")
68
72
  end
69
73
 
70
74
  def self.reindex_dependents!(parent_record, dependent_model, field)
@@ -14,7 +14,13 @@ end
14
14
  module FullSearch
15
15
  class Index
16
16
  class << self
17
+ def verified_tables
18
+ @verified_tables ||= Set.new
19
+ end
20
+
17
21
  def ensure_table!(model)
22
+ return if model.respond_to?(:table_name) && verified_tables.include?(model.table_name)
23
+
18
24
  sqlite!(model)
19
25
 
20
26
  conn = connection
@@ -44,6 +50,8 @@ module FullSearch
44
50
 
45
51
  store_config_hash!(model)
46
52
  ensure_triggers!(model) if model_table_exists?(model)
53
+
54
+ verified_tables.add(model.table_name)
47
55
  end
48
56
 
49
57
  def rebuild!(model)
@@ -70,6 +78,7 @@ module FullSearch
70
78
  create_triggers!(model)
71
79
  optimize!(model)
72
80
  store_config_hash!(model, rebuilt_at: Time.current)
81
+ verified_tables.add(model.table_name)
73
82
  end
74
83
  end
75
84
 
@@ -103,6 +112,7 @@ module FullSearch
103
112
  end
104
113
 
105
114
  def drop!(model)
115
+ verified_tables.delete(model.table_name)
106
116
  sqlite!(model)
107
117
  drop_triggers!(model)
108
118
  connection.execute("DROP TABLE IF EXISTS #{qt(fts_table_name(model))};")
@@ -190,12 +200,7 @@ module FullSearch
190
200
  columns = (dsl.fields + dsl.filters.map { |f| FilterColumnPlaceholder.new(name: f.name) })
191
201
  column_list = columns.map { |c| (c.respond_to?(:unindexed?) && c.unindexed?) ? "#{qc(c.name)} UNINDEXED" : qc(c.name) }.join(", ")
192
202
 
193
- <<~SQL
194
- CREATE VIRTUAL TABLE #{qt(fts_table_name(model))} USING fts5(
195
- #{column_list},
196
- tokenize='#{dsl.tokenize}'
197
- );
198
- SQL
203
+ "CREATE VIRTUAL TABLE #{qt(fts_table_name(model))} USING fts5(#{column_list}, tokenize='#{dsl.tokenize}');"
199
204
  end
200
205
 
201
206
  def backfill_sql(model)
@@ -327,12 +332,7 @@ module FullSearch
327
332
  columns = (dsl.fields + dsl.filters.map { |f| FilterColumnPlaceholder.new(name: f.name) })
328
333
  column_list = columns.map { |c| (c.respond_to?(:unindexed?) && c.unindexed?) ? "#{qc(c.name)} UNINDEXED" : qc(c.name) }.join(", ")
329
334
 
330
- <<~SQL
331
- CREATE VIRTUAL TABLE #{qt(trigram_table_name(model))} USING fts5(
332
- #{column_list},
333
- tokenize='trigram'
334
- );
335
- SQL
335
+ "CREATE VIRTUAL TABLE #{qt(trigram_table_name(model))} USING fts5(#{column_list}, tokenize='trigram');"
336
336
  end
337
337
 
338
338
  def backfill_trigram_sql(model)
@@ -10,8 +10,8 @@ module FullSearch
10
10
  @full_search_dsl ||= FullSearch::Dsl.new(self)
11
11
  @full_search_dsl.tokenize(query_or_options[:tokenize]) if query_or_options.is_a?(Hash) && query_or_options.key?(:tokenize)
12
12
  @full_search_dsl.instance_eval(&block) if block_given?
13
- FullSearch::Index.ensure_table!(self)
14
13
  FullSearch::Callbacks.install!(self)
14
+ FullSearch::Index.ensure_table!(self)
15
15
  include InstanceMethods
16
16
 
17
17
  FullSearch.register_model(self)
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FullSearch
4
+ module VirtualTablesPatch
5
+ def virtual_tables
6
+ super.reject { |_, options| options.first.nil? }
7
+ end
8
+ end
9
+
10
+ module SchemaDumperPatch
11
+ private
12
+
13
+ def virtual_tables(stream)
14
+ virtual_tables = @connection.virtual_tables.reject { |name, _| ignored?(name) }
15
+
16
+ if virtual_tables.any?
17
+ stream.puts
18
+ stream.puts " # Virtual tables defined in this database."
19
+ stream.puts " # Note that virtual tables may not work with other database engines. Be careful if changing database."
20
+ virtual_tables.sort.each do |table_name, options|
21
+ module_name, arguments = options
22
+ next if module_name.nil? || arguments.nil?
23
+
24
+ stream.puts " create_virtual_table #{table_name.inspect}, #{module_name.inspect}, #{arguments.split(", ").inspect}"
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ ActiveSupport.on_load(:active_record) do
32
+ begin
33
+ require "active_record/connection_adapters/sqlite3_adapter"
34
+ rescue LoadError
35
+ next
36
+ end
37
+
38
+ if defined?(ActiveRecord::ConnectionAdapters::SQLite3Adapter)
39
+ ActiveRecord::ConnectionAdapters::SQLite3Adapter.prepend(FullSearch::VirtualTablesPatch)
40
+ end
41
+
42
+ if defined?(ActiveRecord::ConnectionAdapters::SQLite3::SchemaDumper)
43
+ ActiveRecord::ConnectionAdapters::SQLite3::SchemaDumper.prepend(FullSearch::SchemaDumperPatch)
44
+ end
45
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FullSearch
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.2"
5
5
  end
data/lib/full_search.rb CHANGED
@@ -24,6 +24,7 @@ require "full_search/reindex_job"
24
24
  require "full_search/optimize_job"
25
25
  require "full_search/test_helpers"
26
26
  require "full_search/multi_search"
27
+ require "full_search/schema_dumper_patch"
27
28
 
28
29
  ActiveSupport.on_load(:active_record) do
29
30
  include FullSearch::Model
@@ -46,6 +47,13 @@ module FullSearch
46
47
  def optimize!
47
48
  models.each { |model| Index.optimize!(model) }
48
49
  end
50
+
51
+ def setup!
52
+ models.each do |model|
53
+ Index.ensure_table!(model)
54
+ Callbacks.install!(model)
55
+ end
56
+ end
49
57
  end
50
58
  end
51
59
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: full_search
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben D'Angelo
@@ -155,6 +155,7 @@ files:
155
155
  - lib/full_search/quoting.rb
156
156
  - lib/full_search/railtie.rb
157
157
  - lib/full_search/reindex_job.rb
158
+ - lib/full_search/schema_dumper_patch.rb
158
159
  - lib/full_search/search.rb
159
160
  - lib/full_search/soft_delete.rb
160
161
  - lib/full_search/test_helpers.rb
@@ -175,7 +176,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
175
176
  requirements:
176
177
  - - ">="
177
178
  - !ruby/object:Gem::Version
178
- version: 3.1.0
179
+ version: 3.2.0
179
180
  required_rubygems_version: !ruby/object:Gem::Requirement
180
181
  requirements:
181
182
  - - ">="