full_search 0.4.3 → 0.4.5

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: 894bce4229c00412829f531fbb35c78a3b9a3b4ac869ddc23e67421d1abc773b
4
- data.tar.gz: 3a9504c246aced49dcef0b9991efddf53fdbff873c0ddf7e6781e6551550af71
3
+ metadata.gz: fccc79c0dbfc8eeb24424e156c9be822470e2bbc3ecfdb75539f8a70010b3d38
4
+ data.tar.gz: 3e50db78f978cb095834dd9f0d58802dfb1de69f9c80e04fc6c18cbdf1d9ccef
5
5
  SHA512:
6
- metadata.gz: aea83a66af28bf651dd022c63725d012dea6783e57125c5febbf7e48582fe4ac8990cd30af6d9c72bc9544ae3fbf925e84c03a060c549a1b79aaf65668bb2705
7
- data.tar.gz: 9d9d227f097f3c1b5629aa6ced3768e2cb99db6fdafa28ca15ce641afac2ed4af7f15892d6b7fc87316246eb1be7fd02cdd81db1d1f16407fcf2f8a574d20af6
6
+ metadata.gz: 239eb848fe5631b1a8212840246ccd6be8387642b8f269687ae5052dc765afd25ccb49bd55c395b760aa772eb2da696bf786a2155f451326dbd8908da4f95532
7
+ data.tar.gz: bd01ae3b672adc80f97c5ee70699444d773cb2a66c8ab2b98133f3528cba5099b3750fea9682cd6cdb4315e0fac17b7781b720a60f6c79519bf1857b78324aa4
@@ -71,8 +71,8 @@ module FullSearch
71
71
  with_rebuild_lock(model) do
72
72
  FullSearch::Instrumentation.instrument("rebuild", model: model.name) do
73
73
  drop_triggers!(model)
74
- conn.execute("DROP TABLE IF EXISTS #{qt(fts_table_name(model))};")
75
- conn.execute("DROP TABLE IF EXISTS #{qt(trigram_table_name(model))};")
74
+ drop_fts_table_safely!(fts_table_name(model))
75
+ drop_fts_table_safely!(trigram_table_name(model))
76
76
  conn.execute(create_virtual_table_sql(model))
77
77
  if trigram_table_needed?(model)
78
78
  FullSearch::Typo.warn_unsupported!(model) unless FullSearch::Typo.supported?(model)
@@ -181,8 +181,33 @@ module FullSearch
181
181
  verified_tables.delete(model.table_name)
182
182
  sqlite!(model)
183
183
  drop_triggers!(model)
184
- connection.execute("DROP TABLE IF EXISTS #{qt(fts_table_name(model))};")
185
- connection.execute("DROP TABLE IF EXISTS #{qt(trigram_table_name(model))};")
184
+ drop_fts_table_safely!(fts_table_name(model))
185
+ drop_fts_table_safely!(trigram_table_name(model))
186
+ end
187
+
188
+ # Drops an FTS5 virtual table, recovering from corruption where a bare
189
+ # DROP TABLE IF EXISTS raises "invalid fts5 file format" because the
190
+ # shadow tables were tampered with out-of-band. When that happens we
191
+ # drop the shadow tables directly, then drop the (now-empty) virtual
192
+ # table wrapper, so the caller can recreate a clean index.
193
+ def drop_fts_table_safely!(table_name)
194
+ connection.execute("DROP TABLE IF EXISTS #{qt(table_name)};")
195
+ rescue ActiveRecord::StatementInvalid => e
196
+ raise unless e.message.match?(/fts5: corruption|invalid fts5 file format|malformed database schema/i)
197
+
198
+ drop_shadow_tables!(table_name)
199
+ connection.execute("DROP TABLE IF EXISTS #{qt(table_name)};")
200
+ end
201
+
202
+ # FTS5 stores its index data in a fixed set of shadow tables named
203
+ # <table>_content, <table>_data, <table>_idx, <table>_docsize and
204
+ # <table>_config. Dropping these lets SQLite recover a virtual table
205
+ # that is otherwise undroppable due to internal corruption.
206
+ def drop_shadow_tables!(table_name)
207
+ %w[content data idx docsize config].each do |suffix|
208
+ shadow = "#{table_name}_#{suffix}"
209
+ connection.execute("DROP TABLE IF EXISTS #{qt(shadow)};")
210
+ end
186
211
  end
187
212
 
188
213
  def fts_table_name(model)
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FullSearch
4
+ module OnceRebuilt
5
+ class << self
6
+ def per_test_case(*models)
7
+ models = FullSearch.models.to_a if models.empty?
8
+ unless already_rebuilt?(models)
9
+ rebuild_models!(models)
10
+ mark_rebuilt!(models)
11
+ end
12
+
13
+ yield if block_given?
14
+ end
15
+
16
+ def clear!
17
+ @rebuilt = Set.new
18
+ end
19
+
20
+ private
21
+
22
+ def already_rebuilt?(models)
23
+ keys = models.map { |model| cache_key(model) }
24
+ @rebuilt ||= Set.new
25
+ keys.all? { |key| @rebuilt.include?(key) }
26
+ end
27
+
28
+ def mark_rebuilt!(models)
29
+ @rebuilt ||= Set.new
30
+ models.each { |model| @rebuilt << cache_key(model) }
31
+ end
32
+
33
+ def cache_key(model)
34
+ [
35
+ model.connection_db_config.database,
36
+ model.table_name,
37
+ model.full_search_dsl&.config_hash,
38
+ model.connection_db_config.schema_cache_path
39
+ ].compact.join(":")
40
+ end
41
+
42
+ include FullSearch::TestHelpers
43
+
44
+ def rebuild_models!(models)
45
+ models.each { |model| rebuild_full_search_index(model) }
46
+ end
47
+ end
48
+ end
49
+ end
@@ -54,6 +54,10 @@ module FullSearch
54
54
  end
55
55
  end
56
56
 
57
+ def once_full_search_rebuilt(*models, &block)
58
+ FullSearch::OnceRebuilt.per_test_case(*models, &block)
59
+ end
60
+
57
61
  def with_full_search_rebuild(model)
58
62
  model = resolve_full_search_model(model)
59
63
  rebuild_full_search_index(model)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FullSearch
4
- VERSION = "0.4.3"
4
+ VERSION = "0.4.5"
5
5
  end
data/lib/full_search.rb CHANGED
@@ -30,6 +30,7 @@ require "full_search/backfill_job"
30
30
  require "full_search/test_helpers"
31
31
  require "full_search/multi_search"
32
32
  require "full_search/schema_dumper_patch"
33
+ require "full_search/once_rebuilt"
33
34
 
34
35
  ActiveSupport.on_load(:active_record) do
35
36
  include FullSearch::Model
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.4.3
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben D'Angelo
@@ -155,6 +155,7 @@ files:
155
155
  - lib/full_search/instrumentation.rb
156
156
  - lib/full_search/model.rb
157
157
  - lib/full_search/multi_search.rb
158
+ - lib/full_search/once_rebuilt.rb
158
159
  - lib/full_search/optimize_job.rb
159
160
  - lib/full_search/query_parser.rb
160
161
  - lib/full_search/quoting.rb
@@ -188,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
188
189
  - !ruby/object:Gem::Version
189
190
  version: '2.0'
190
191
  requirements: []
191
- rubygems_version: 4.0.10
192
+ rubygems_version: 4.0.15
192
193
  specification_version: 4
193
194
  summary: SQLite FTS5 full-text search for Rails/ActiveRecord
194
195
  test_files: []