full_search 0.1.3 → 0.3.0

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.
@@ -5,23 +5,25 @@ module FullSearch
5
5
  MIN_SQLITE_VERSION = [3, 34].freeze
6
6
 
7
7
  class << self
8
- def supported?
9
- major, minor = sqlite_version_parts
8
+ def supported?(model = nil)
9
+ conn = model&.connection || ActiveRecord::Base.connection
10
+ major, minor = sqlite_version_parts(conn)
10
11
  major > MIN_SQLITE_VERSION.first || (major == MIN_SQLITE_VERSION.first && minor >= MIN_SQLITE_VERSION.last)
11
12
  end
12
13
 
13
- def warn_unsupported!
14
- warn "[full_search] SQLite #{sqlite_version} does not support the trigram tokenizer. typo_tolerance requires SQLite >= 3.34."
14
+ def warn_unsupported!(model = nil)
15
+ version = sqlite_version(model&.connection || ActiveRecord::Base.connection)
16
+ warn "[full_search] SQLite #{version} does not support the trigram tokenizer. typo_tolerance requires SQLite >= 3.34."
15
17
  end
16
18
 
17
19
  private
18
20
 
19
- def sqlite_version_parts
20
- sqlite_version.split(".").first(2).map(&:to_i)
21
+ def sqlite_version_parts(conn)
22
+ sqlite_version(conn).split(".").first(2).map(&:to_i)
21
23
  end
22
24
 
23
- def sqlite_version
24
- ActiveRecord::Base.connection.execute("SELECT sqlite_version() AS v").first["v"]
25
+ def sqlite_version(conn)
26
+ conn.execute("SELECT sqlite_version() AS v").first["v"]
25
27
  end
26
28
  end
27
29
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FullSearch
4
- VERSION = "0.1.3"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/full_search.rb CHANGED
@@ -6,6 +6,8 @@ require "active_support/concern"
6
6
 
7
7
  require "full_search/version"
8
8
  require "full_search/config"
9
+ require "full_search/distance"
10
+ require "full_search/quoting"
9
11
  require "full_search/errors"
10
12
  require "full_search/tokenizer"
11
13
  require "full_search/dsl"
@@ -19,6 +21,7 @@ require "full_search/search"
19
21
  require "full_search/soft_delete"
20
22
  require "full_search/callbacks"
21
23
  require "full_search/reindex_job"
24
+ require "full_search/optimize_job"
22
25
  require "full_search/test_helpers"
23
26
  require "full_search/multi_search"
24
27
 
@@ -29,7 +32,19 @@ end
29
32
  module FullSearch
30
33
  class << self
31
34
  def models
32
- @models ||= []
35
+ @models ||= Set.new
36
+ end
37
+
38
+ def register_model(model)
39
+ models << model
40
+ end
41
+
42
+ def deregister_model(model)
43
+ models.delete(model)
44
+ end
45
+
46
+ def optimize!
47
+ models.each { |model| Index.optimize!(model) }
33
48
  end
34
49
  end
35
50
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  FullSearch.configure do |config|
4
- config.auto_manage_schema = Rails.env.local?
4
+ config.auto_rebuild_schema = Rails.env.local?
5
5
 
6
6
  config.stale_query_behavior = Rails.env.production? ? :log_and_fallback : :raise
7
7
 
@@ -1,30 +1,50 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ def resolve_full_search_models(args)
4
+ if args[:models]
5
+ args[:models].split(",").map do |name|
6
+ klass = begin
7
+ name.singularize.camelize.constantize
8
+ rescue NameError, LoadError => e
9
+ warn "[full_search] Could not resolve model '#{name}': #{e.message}"
10
+ nil
11
+ end
12
+ klass || FullSearch.models.find { |m| m.table_name == name }
13
+ end.compact
14
+ else
15
+ FullSearch.models
16
+ end
17
+ end
18
+
3
19
  namespace :full_search do
4
- desc "Rebuild full_search indexes"
20
+ desc "Rebuild indexes when DSL has changed (checks config hash; safe for production)"
5
21
  task :rebuild, [:models] => :environment do |_t, args|
6
22
  Rails.application.eager_load!
7
23
 
8
- models = if args[:models]
9
- args[:models].split(",").map do |name|
10
- klass = name.singularize.camelize.constantize rescue nil
11
- klass || FullSearch.models.find { |m| m.table_name == name }
12
- end.compact
13
- else
14
- FullSearch.models
15
- end
24
+ resolve_full_search_models(args).each do |model|
25
+ if FullSearch::Index.rebuild_if_needed!(model)
26
+ puts "Rebuilt #{FullSearch::Index.fts_table_name(model)}"
27
+ else
28
+ puts "#{FullSearch::Index.fts_table_name(model)} is current"
29
+ end
30
+ end
31
+ end
16
32
 
17
- models.each do |model|
33
+ desc "Force reset indexes (drops and recreates all FTS tables)"
34
+ task :reset, [:models] => :environment do |_t, args|
35
+ Rails.application.eager_load!
36
+
37
+ resolve_full_search_models(args).each do |model|
18
38
  FullSearch::Index.rebuild!(model)
19
- puts "Rebuilt #{FullSearch::Index.fts_table_name(model)}"
39
+ puts "Reset #{FullSearch::Index.fts_table_name(model)}"
20
40
  end
21
41
  end
22
42
 
23
43
  desc "Optimize full_search indexes"
24
44
  task optimize: :environment do
25
45
  Rails.application.eager_load!
46
+ FullSearch.optimize!
26
47
  FullSearch.models.each do |model|
27
- FullSearch::Index.optimize!(model)
28
48
  puts "Optimized #{FullSearch::Index.fts_table_name(model)}"
29
49
  end
30
50
  end
@@ -35,8 +55,24 @@ namespace :full_search do
35
55
  FullSearch.models.each do |model|
36
56
  stored = FullSearch::Index.stored_config_hash(model)
37
57
  current = model.full_search_dsl.config_hash
38
- status = stored == current ? "ok" : "stale"
39
- puts "#{model.table_name}: #{status} (stored=#{stored}, current=#{current})"
58
+ status = (stored == current) ? "ok" : "stale"
59
+ source_fields = model.full_search_dsl.fields.select(&:source).map(&:name)
60
+
61
+ drift_info = if source_fields.any?
62
+ conn = ActiveRecord::Base.connection
63
+ qc = ->(name) { conn.quote_column_name(name) }
64
+ qt = ->(name) { conn.quote_table_name(name) }
65
+ empty_count = ActiveRecord::Base.connection.execute(<<~SQL).first["c"]
66
+ SELECT COUNT(*) AS c
67
+ FROM #{qt.call(FullSearch::Index.fts_table_name(model))}
68
+ WHERE #{source_fields.map { |c| "#{qc.call(c)} = ''" }.join(" OR ")}
69
+ SQL
70
+ " | empty source fields: #{empty_count}"
71
+ else
72
+ ""
73
+ end
74
+
75
+ puts "#{model.table_name}: #{status}#{drift_info}"
40
76
  end
41
77
  end
42
78
  end
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.1.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben D'Angelo
@@ -16,6 +16,9 @@ dependencies:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
18
  version: '8.0'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '9'
19
22
  type: :runtime
20
23
  prerelease: false
21
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -23,6 +26,9 @@ dependencies:
23
26
  - - ">="
24
27
  - !ruby/object:Gem::Version
25
28
  version: '8.0'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '9'
26
32
  - !ruby/object:Gem::Dependency
27
33
  name: railties
28
34
  requirement: !ruby/object:Gem::Requirement
@@ -30,6 +36,9 @@ dependencies:
30
36
  - - ">="
31
37
  - !ruby/object:Gem::Version
32
38
  version: '8.0'
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '9'
33
42
  type: :runtime
34
43
  prerelease: false
35
44
  version_requirements: !ruby/object:Gem::Requirement
@@ -37,6 +46,9 @@ dependencies:
37
46
  - - ">="
38
47
  - !ruby/object:Gem::Version
39
48
  version: '8.0'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '9'
40
52
  - !ruby/object:Gem::Dependency
41
53
  name: sqlite3
42
54
  requirement: !ruby/object:Gem::Requirement
@@ -51,6 +63,34 @@ dependencies:
51
63
  - - ">="
52
64
  - !ruby/object:Gem::Version
53
65
  version: '2.0'
66
+ - !ruby/object:Gem::Dependency
67
+ name: minitest
68
+ requirement: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - "~>"
71
+ - !ruby/object:Gem::Version
72
+ version: '5.0'
73
+ type: :development
74
+ prerelease: false
75
+ version_requirements: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '5.0'
80
+ - !ruby/object:Gem::Dependency
81
+ name: rake
82
+ requirement: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - "~>"
85
+ - !ruby/object:Gem::Version
86
+ version: '13.0'
87
+ type: :development
88
+ prerelease: false
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "~>"
92
+ - !ruby/object:Gem::Version
93
+ version: '13.0'
54
94
  - !ruby/object:Gem::Dependency
55
95
  name: ostruct
56
96
  requirement: !ruby/object:Gem::Requirement
@@ -58,7 +98,7 @@ dependencies:
58
98
  - - ">="
59
99
  - !ruby/object:Gem::Version
60
100
  version: '0.6'
61
- type: :runtime
101
+ type: :development
62
102
  prerelease: false
63
103
  version_requirements: !ruby/object:Gem::Requirement
64
104
  requirements:
@@ -66,33 +106,33 @@ dependencies:
66
106
  - !ruby/object:Gem::Version
67
107
  version: '0.6'
68
108
  - !ruby/object:Gem::Dependency
69
- name: minitest
109
+ name: irb
70
110
  requirement: !ruby/object:Gem::Requirement
71
111
  requirements:
72
- - - "~>"
112
+ - - ">="
73
113
  - !ruby/object:Gem::Version
74
- version: '5.0'
114
+ version: '0'
75
115
  type: :development
76
116
  prerelease: false
77
117
  version_requirements: !ruby/object:Gem::Requirement
78
118
  requirements:
79
- - - "~>"
119
+ - - ">="
80
120
  - !ruby/object:Gem::Version
81
- version: '5.0'
121
+ version: '0'
82
122
  - !ruby/object:Gem::Dependency
83
- name: rake
123
+ name: standard
84
124
  requirement: !ruby/object:Gem::Requirement
85
125
  requirements:
86
126
  - - "~>"
87
127
  - !ruby/object:Gem::Version
88
- version: '13.0'
128
+ version: '1.40'
89
129
  type: :development
90
130
  prerelease: false
91
131
  version_requirements: !ruby/object:Gem::Requirement
92
132
  requirements:
93
133
  - - "~>"
94
134
  - !ruby/object:Gem::Version
95
- version: '13.0'
135
+ version: '1.40'
96
136
  description: Declarative full-text search for Rails apps backed by SQLite FTS5
97
137
  executables: []
98
138
  extensions: []
@@ -102,6 +142,7 @@ files:
102
142
  - lib/full_search.rb
103
143
  - lib/full_search/callbacks.rb
104
144
  - lib/full_search/config.rb
145
+ - lib/full_search/distance.rb
105
146
  - lib/full_search/dsl.rb
106
147
  - lib/full_search/errors.rb
107
148
  - lib/full_search/exact_match.rb
@@ -109,7 +150,9 @@ files:
109
150
  - lib/full_search/index.rb
110
151
  - lib/full_search/model.rb
111
152
  - lib/full_search/multi_search.rb
153
+ - lib/full_search/optimize_job.rb
112
154
  - lib/full_search/query_parser.rb
155
+ - lib/full_search/quoting.rb
113
156
  - lib/full_search/railtie.rb
114
157
  - lib/full_search/reindex_job.rb
115
158
  - lib/full_search/search.rb
@@ -132,12 +175,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
132
175
  requirements:
133
176
  - - ">="
134
177
  - !ruby/object:Gem::Version
135
- version: 4.0.0
178
+ version: 3.1.0
136
179
  required_rubygems_version: !ruby/object:Gem::Requirement
137
180
  requirements:
138
181
  - - ">="
139
182
  - !ruby/object:Gem::Version
140
- version: '0'
183
+ version: '2.0'
141
184
  requirements: []
142
185
  rubygems_version: 4.0.15
143
186
  specification_version: 4