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.
- checksums.yaml +4 -4
- data/README.md +115 -9
- data/lib/full_search/callbacks.rb +26 -8
- data/lib/full_search/config.rb +2 -2
- data/lib/full_search/distance.rb +33 -0
- data/lib/full_search/dsl.rb +29 -12
- data/lib/full_search/errors.rb +2 -0
- data/lib/full_search/exact_match.rb +7 -4
- data/lib/full_search/highlighter.rb +175 -80
- data/lib/full_search/index.rb +134 -44
- data/lib/full_search/model.rb +23 -4
- data/lib/full_search/multi_search.rb +4 -1
- data/lib/full_search/optimize_job.rb +13 -0
- data/lib/full_search/query_parser.rb +101 -88
- data/lib/full_search/quoting.rb +11 -0
- data/lib/full_search/railtie.rb +2 -8
- data/lib/full_search/search.rb +161 -30
- data/lib/full_search/soft_delete.rb +15 -2
- data/lib/full_search/typo.rb +10 -8
- data/lib/full_search/version.rb +1 -1
- data/lib/full_search.rb +16 -1
- data/lib/generators/full_search/install/templates/full_search.rb +1 -1
- data/lib/tasks/full_search.rake +50 -14
- metadata +55 -12
data/lib/full_search/typo.rb
CHANGED
|
@@ -5,23 +5,25 @@ module FullSearch
|
|
|
5
5
|
MIN_SQLITE_VERSION = [3, 34].freeze
|
|
6
6
|
|
|
7
7
|
class << self
|
|
8
|
-
def supported?
|
|
9
|
-
|
|
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
|
-
|
|
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
|
-
|
|
25
|
+
def sqlite_version(conn)
|
|
26
|
+
conn.execute("SELECT sqlite_version() AS v").first["v"]
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
29
|
end
|
data/lib/full_search/version.rb
CHANGED
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
|
data/lib/tasks/full_search.rake
CHANGED
|
@@ -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
|
|
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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
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 "
|
|
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
|
-
|
|
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.
|
|
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: :
|
|
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:
|
|
109
|
+
name: irb
|
|
70
110
|
requirement: !ruby/object:Gem::Requirement
|
|
71
111
|
requirements:
|
|
72
|
-
- - "
|
|
112
|
+
- - ">="
|
|
73
113
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: '
|
|
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: '
|
|
121
|
+
version: '0'
|
|
82
122
|
- !ruby/object:Gem::Dependency
|
|
83
|
-
name:
|
|
123
|
+
name: standard
|
|
84
124
|
requirement: !ruby/object:Gem::Requirement
|
|
85
125
|
requirements:
|
|
86
126
|
- - "~>"
|
|
87
127
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: '
|
|
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: '
|
|
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:
|
|
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
|