redi_search 5.0.0 → 6.0.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/.github/workflows/lint.yml +3 -3
- data/.github/workflows/tests.yml +8 -5
- data/Gemfile +1 -0
- data/README.md +57 -58
- data/bin/console +8 -4
- data/bin/publish +2 -2
- data/gemfiles/activerecord_60.gemfile +1 -0
- data/gemfiles/activerecord_61.gemfile +1 -0
- data/gemfiles/activerecord_70.gemfile +2 -1
- data/lib/redi_search/add_field.rb +9 -15
- data/lib/redi_search/client.rb +9 -7
- data/lib/redi_search/document.rb +6 -11
- data/lib/redi_search/index.rb +4 -11
- data/lib/redi_search/model.rb +20 -28
- data/lib/redi_search/schema/field.rb +15 -1
- data/lib/redi_search/schema/geo_field.rb +5 -6
- data/lib/redi_search/schema/numeric_field.rb +5 -6
- data/lib/redi_search/schema/tag_field.rb +12 -8
- data/lib/redi_search/schema/text_field.rb +7 -6
- data/lib/redi_search/schema.rb +33 -25
- data/lib/redi_search/search/clauses/and.rb +0 -2
- data/lib/redi_search/search/clauses/application_clause.rb +0 -2
- data/lib/redi_search/search/clauses/boolean.rb +1 -1
- data/lib/redi_search/search/clauses/in_order.rb +0 -2
- data/lib/redi_search/search/clauses/language.rb +0 -2
- data/lib/redi_search/search/clauses/limit.rb +0 -2
- data/lib/redi_search/search/clauses/no_content.rb +0 -2
- data/lib/redi_search/search/clauses/no_stop_words.rb +0 -2
- data/lib/redi_search/search/clauses/or.rb +0 -2
- data/lib/redi_search/search/clauses/return.rb +0 -2
- data/lib/redi_search/search/clauses/slop.rb +0 -2
- data/lib/redi_search/search/clauses/sort_by.rb +0 -2
- data/lib/redi_search/search/clauses/verbatim.rb +0 -2
- data/lib/redi_search/search/clauses/where.rb +1 -1
- data/lib/redi_search/search/clauses/with_scores.rb +0 -2
- data/lib/redi_search/search/clauses.rb +0 -16
- data/lib/redi_search/search/term.rb +16 -9
- data/lib/redi_search/search.rb +0 -6
- data/lib/redi_search/spellcheck.rb +2 -6
- data/lib/redi_search/validatable.rb +0 -4
- data/lib/redi_search/validations/numericality.rb +0 -2
- data/lib/redi_search/version.rb +1 -1
- data/lib/redi_search.rb +3 -7
- data/redi_search.gemspec +8 -5
- metadata +17 -2
data/lib/redi_search/model.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "redi_search/index"
|
4
|
-
|
5
3
|
module RediSearch
|
6
4
|
module Model
|
7
5
|
def self.included(base)
|
@@ -9,18 +7,16 @@ module RediSearch
|
|
9
7
|
end
|
10
8
|
|
11
9
|
module ClassMethods
|
12
|
-
attr_reader :
|
10
|
+
attr_reader :search_index
|
13
11
|
|
14
12
|
# rubocop:disable Metrics/MethodLength
|
15
|
-
def redi_search(
|
16
|
-
@
|
17
|
-
[options[:index_prefix],
|
18
|
-
|
19
|
-
schema
|
20
|
-
self
|
13
|
+
def redi_search(**options, &schema)
|
14
|
+
@search_index = Index.new(
|
15
|
+
[options[:index_prefix], model_name.plural, RediSearch.env].
|
16
|
+
compact.join("_"),
|
17
|
+
self, &schema
|
21
18
|
)
|
22
|
-
|
23
|
-
register_redi_search_commit_hooks
|
19
|
+
register_search_commit_hooks
|
24
20
|
|
25
21
|
scope :search_import, -> { all }
|
26
22
|
|
@@ -31,27 +27,26 @@ module RediSearch
|
|
31
27
|
|
32
28
|
private
|
33
29
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
after_destroy_commit(:redi_search_delete_document) if
|
30
|
+
def register_search_commit_hooks
|
31
|
+
after_save_commit(:add_to_index) if respond_to?(:after_save_commit)
|
32
|
+
after_destroy_commit(:remove_from_index) if
|
38
33
|
respond_to?(:after_destroy_commit)
|
39
34
|
end
|
40
35
|
end
|
41
36
|
|
42
37
|
module ModelClassMethods
|
43
38
|
def search(term = nil, **term_options)
|
44
|
-
|
39
|
+
search_index.search(term, **term_options)
|
45
40
|
end
|
46
41
|
|
47
42
|
def spellcheck(term, distance: 1)
|
48
|
-
|
43
|
+
search_index.spellcheck(term, distance: distance)
|
49
44
|
end
|
50
45
|
|
51
46
|
def reindex(recreate: false, only: [])
|
52
47
|
search_import.find_in_batches.all? do |group|
|
53
|
-
|
54
|
-
group.map { |record| record.
|
48
|
+
search_index.reindex(
|
49
|
+
group.map { |record| record.search_document(only: only) },
|
55
50
|
recreate: recreate
|
56
51
|
)
|
57
52
|
end
|
@@ -59,19 +54,16 @@ module RediSearch
|
|
59
54
|
end
|
60
55
|
|
61
56
|
module InstanceMethods
|
62
|
-
def
|
63
|
-
Document.for_object(
|
64
|
-
self.class.redi_search_index, self,
|
65
|
-
only: only, serializer: self.class.redi_search_serializer
|
66
|
-
)
|
57
|
+
def search_document(only: [])
|
58
|
+
Document.for_object(self.class.search_index, self, only: only)
|
67
59
|
end
|
68
60
|
|
69
|
-
def
|
70
|
-
self.class.
|
61
|
+
def remove_from_index
|
62
|
+
self.class.search_index.del(search_document)
|
71
63
|
end
|
72
64
|
|
73
|
-
def
|
74
|
-
self.class.
|
65
|
+
def add_to_index
|
66
|
+
self.class.search_index.add(search_document)
|
75
67
|
end
|
76
68
|
end
|
77
69
|
end
|
@@ -7,12 +7,26 @@ module RediSearch
|
|
7
7
|
@name&.to_sym
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def coerce(value)
|
11
11
|
value
|
12
12
|
end
|
13
13
|
|
14
|
+
def serialize(record)
|
15
|
+
if value_block
|
16
|
+
record.instance_exec(&value_block)
|
17
|
+
else
|
18
|
+
record.public_send(name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def tag?
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
14
26
|
private
|
15
27
|
|
28
|
+
attr_reader :value_block
|
29
|
+
|
16
30
|
FALSES = [
|
17
31
|
nil, "", false, 0, "0", "f", "F", "false", "FALSE", "off", "OFF"
|
18
32
|
].freeze
|
@@ -1,14 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "redi_search/schema/field"
|
4
|
-
|
5
3
|
module RediSearch
|
6
4
|
class Schema
|
7
5
|
class GeoField < Field
|
8
|
-
def initialize(name, sortable: false, no_index: false)
|
9
|
-
@name
|
10
|
-
@sortable
|
11
|
-
@no_index
|
6
|
+
def initialize(name, sortable: false, no_index: false, &block)
|
7
|
+
@name = name
|
8
|
+
@sortable = sortable
|
9
|
+
@no_index = no_index
|
10
|
+
@value_block = block
|
12
11
|
end
|
13
12
|
|
14
13
|
def to_a
|
@@ -1,14 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "redi_search/schema/field"
|
4
|
-
|
5
3
|
module RediSearch
|
6
4
|
class Schema
|
7
5
|
class NumericField < Field
|
8
|
-
def initialize(name, sortable: false, no_index: false)
|
9
|
-
@name
|
10
|
-
@sortable
|
11
|
-
@no_index
|
6
|
+
def initialize(name, sortable: false, no_index: false, &block)
|
7
|
+
@name = name
|
8
|
+
@sortable = sortable
|
9
|
+
@no_index = no_index
|
10
|
+
@value_block = block
|
12
11
|
end
|
13
12
|
|
14
13
|
def to_a
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "redi_search/schema/field"
|
4
|
-
|
5
3
|
module RediSearch
|
6
4
|
class Schema
|
7
5
|
class TagField < Field
|
8
|
-
def initialize(name, separator: ",", sortable: false, no_index: false
|
9
|
-
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@
|
6
|
+
def initialize(name, separator: ",", sortable: false, no_index: false,
|
7
|
+
&block)
|
8
|
+
@name = name
|
9
|
+
@separator = separator
|
10
|
+
@sortable = sortable
|
11
|
+
@no_index = no_index
|
12
|
+
@value_block = block
|
13
13
|
end
|
14
14
|
|
15
15
|
def to_a
|
@@ -20,10 +20,14 @@ module RediSearch
|
|
20
20
|
query
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
23
|
+
def coerce(value)
|
24
24
|
value.join(separator)
|
25
25
|
end
|
26
26
|
|
27
|
+
def tag?
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
27
31
|
private
|
28
32
|
|
29
33
|
attr_reader :separator, :sortable, :no_index
|
@@ -4,13 +4,14 @@ module RediSearch
|
|
4
4
|
class Schema
|
5
5
|
class TextField < Field
|
6
6
|
def initialize(name, weight: 1.0, phonetic: nil, sortable: false,
|
7
|
-
no_index: false, no_stem: false)
|
7
|
+
no_index: false, no_stem: false, &block)
|
8
8
|
@name = name
|
9
|
-
@
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
9
|
+
@value_block = block
|
10
|
+
|
11
|
+
{ weight: weight, phonetic: phonetic, sortable: sortable,
|
12
|
+
no_index: no_index, no_stem: no_stem }.each do |attr, value|
|
13
|
+
instance_variable_set("@#{attr}", value)
|
14
|
+
end
|
14
15
|
end
|
15
16
|
|
16
17
|
def to_a
|
data/lib/redi_search/schema.rb
CHANGED
@@ -1,46 +1,54 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "redi_search/schema/geo_field"
|
4
|
-
require "redi_search/schema/numeric_field"
|
5
|
-
require "redi_search/schema/tag_field"
|
6
|
-
require "redi_search/schema/text_field"
|
7
|
-
|
8
3
|
module RediSearch
|
9
4
|
class Schema
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
attr_reader :fields
|
6
|
+
|
7
|
+
def initialize(&block)
|
8
|
+
@fields = []
|
13
9
|
|
14
|
-
|
15
|
-
new(field_name, **options.to_h)
|
10
|
+
instance_exec(&block)
|
16
11
|
end
|
17
12
|
|
18
|
-
def
|
19
|
-
|
13
|
+
def text_field(name, **options, &block)
|
14
|
+
self[name] || push(Schema::TextField.new(name, **options, &block))
|
20
15
|
end
|
21
16
|
|
22
|
-
def
|
23
|
-
|
17
|
+
def numeric_field(name, **options, &block)
|
18
|
+
self[name] || push(Schema::NumericField.new(name, **options, &block))
|
19
|
+
end
|
20
|
+
|
21
|
+
def tag_field(name, **options, &block)
|
22
|
+
self[name] || push(Schema::TagField.new(name, **options, &block))
|
24
23
|
end
|
25
24
|
|
26
|
-
def
|
27
|
-
|
25
|
+
def geo_field(name, **options, &block)
|
26
|
+
self[name] || push(Schema::GeoField.new(name, **options, &block))
|
28
27
|
end
|
29
28
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
def add_field(name, type, **options, &block)
|
30
|
+
case type
|
31
|
+
when :text then method(:text_field)
|
32
|
+
when :numeric then method(:numeric_field)
|
33
|
+
when :tag then method(:tag_field)
|
34
|
+
when :geo then method(:geo_field)
|
35
|
+
end.call(name, **options, &block)
|
34
36
|
end
|
35
37
|
|
36
|
-
def
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
def to_a
|
39
|
+
fields.map(&:to_a).flatten
|
40
|
+
end
|
41
|
+
|
42
|
+
def [](name)
|
43
|
+
fields.find { |field| field.name == name }
|
40
44
|
end
|
41
45
|
|
42
46
|
private
|
43
47
|
|
44
|
-
|
48
|
+
def push(field)
|
49
|
+
@fields.push(field)
|
50
|
+
|
51
|
+
field
|
52
|
+
end
|
45
53
|
end
|
46
54
|
end
|
@@ -1,21 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "redi_search/search/term"
|
4
|
-
require "redi_search/search/clauses/slop"
|
5
|
-
require "redi_search/search/clauses/in_order"
|
6
|
-
require "redi_search/search/clauses/language"
|
7
|
-
require "redi_search/search/clauses/sort_by"
|
8
|
-
require "redi_search/search/clauses/limit"
|
9
|
-
require "redi_search/search/clauses/no_content"
|
10
|
-
require "redi_search/search/clauses/verbatim"
|
11
|
-
require "redi_search/search/clauses/no_stop_words"
|
12
|
-
require "redi_search/search/clauses/return"
|
13
|
-
require "redi_search/search/clauses/with_scores"
|
14
|
-
require "redi_search/search/clauses/highlight"
|
15
|
-
require "redi_search/search/clauses/and"
|
16
|
-
require "redi_search/search/clauses/or"
|
17
|
-
require "redi_search/search/clauses/where"
|
18
|
-
|
19
3
|
module RediSearch
|
20
4
|
class Search
|
21
5
|
module Clauses
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "redi_search/validatable"
|
4
|
-
|
5
3
|
module RediSearch
|
6
4
|
class Search
|
7
5
|
class Term
|
@@ -12,16 +10,17 @@ module RediSearch
|
|
12
10
|
validates_inclusion_of :option, within: %i(fuzziness optional prefix),
|
13
11
|
allow_nil: true
|
14
12
|
|
15
|
-
def initialize(term, **options)
|
16
|
-
@term
|
13
|
+
def initialize(term, field = nil, **options)
|
14
|
+
@term = term
|
15
|
+
@field = field
|
17
16
|
@options = options
|
18
17
|
|
19
18
|
validate!
|
20
19
|
end
|
21
20
|
|
22
21
|
def to_s
|
23
|
-
if
|
24
|
-
|
22
|
+
if term.is_a?(Range) then stringify_range
|
23
|
+
elsif !field.nil? && field.tag? then stringify_tag
|
25
24
|
else
|
26
25
|
stringify_query
|
27
26
|
end
|
@@ -29,7 +28,7 @@ module RediSearch
|
|
29
28
|
|
30
29
|
private
|
31
30
|
|
32
|
-
attr_accessor :term, :options
|
31
|
+
attr_accessor :term, :field, :options
|
33
32
|
|
34
33
|
def fuzziness
|
35
34
|
@fuzziness ||= options[:fuzziness]
|
@@ -52,7 +51,7 @@ module RediSearch
|
|
52
51
|
end
|
53
52
|
|
54
53
|
def stringify_query
|
55
|
-
|
54
|
+
term.to_s.
|
56
55
|
tr("`", "\`").
|
57
56
|
yield_self { |str| "#{fuzzy_operator}#{str}#{fuzzy_operator}" }.
|
58
57
|
yield_self { |str| "#{optional_operator}#{str}" }.
|
@@ -60,8 +59,16 @@ module RediSearch
|
|
60
59
|
yield_self { |str| "`#{str}`" }
|
61
60
|
end
|
62
61
|
|
62
|
+
def stringify_tag
|
63
|
+
if term.is_a?(Array)
|
64
|
+
"{ #{term.join(' | ')} }"
|
65
|
+
else
|
66
|
+
"{ #{term} }"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
63
70
|
def stringify_range
|
64
|
-
first, last =
|
71
|
+
first, last = term.first, term.last
|
65
72
|
first = "-inf" if first == -Float::INFINITY
|
66
73
|
last = "+inf" if last == Float::INFINITY
|
67
74
|
|
data/lib/redi_search/search.rb
CHANGED
@@ -1,9 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "redi_search/lazily_load"
|
4
|
-
require "redi_search/spellcheck/result"
|
5
|
-
require "redi_search/validatable"
|
6
|
-
|
7
3
|
module RediSearch
|
8
4
|
class Spellcheck
|
9
5
|
include LazilyLoad
|
@@ -41,9 +37,9 @@ module RediSearch
|
|
41
37
|
end
|
42
38
|
|
43
39
|
def parse_response(response)
|
44
|
-
suggestions = response.
|
40
|
+
suggestions = response.to_h do |suggestion|
|
45
41
|
suggestion[1..2]
|
46
|
-
end
|
42
|
+
end
|
47
43
|
|
48
44
|
@documents = parsed_terms.map do |term|
|
49
45
|
Result.new(term, suggestions[term] || [])
|
data/lib/redi_search/version.rb
CHANGED
data/lib/redi_search.rb
CHANGED
@@ -4,14 +4,10 @@ require "delegate"
|
|
4
4
|
require "forwardable"
|
5
5
|
require "redis"
|
6
6
|
require "active_support/lazy_load_hooks"
|
7
|
+
require "zeitwerk"
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
require "redi_search/model"
|
12
|
-
require "redi_search/index"
|
13
|
-
require "redi_search/log_subscriber"
|
14
|
-
require "redi_search/document"
|
9
|
+
loader = Zeitwerk::Loader.for_gem
|
10
|
+
loader.setup
|
15
11
|
|
16
12
|
module RediSearch
|
17
13
|
class << self
|
data/redi_search.gemspec
CHANGED
@@ -18,16 +18,19 @@ Gem::Specification.new do |spec|
|
|
18
18
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test)/}) }
|
19
19
|
end
|
20
20
|
|
21
|
-
spec.metadata
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
"
|
21
|
+
spec.metadata = {
|
22
|
+
"rubygems_mfa_required" => "true",
|
23
|
+
"github_repo" => "ssh://github.com/npezza93/redi_search",
|
24
|
+
"homepage_uri" => spec.homepage,
|
25
|
+
"source_code_uri" => spec.homepage,
|
26
|
+
"changelog_uri" => "https://github.com/npezza93/redi_search/releases",
|
27
|
+
}
|
26
28
|
|
27
29
|
spec.required_ruby_version = ">= 2.7.0"
|
28
30
|
|
29
31
|
spec.add_runtime_dependency "activesupport", ">= 5.1", "< 7.1"
|
30
32
|
spec.add_runtime_dependency "redis", ">= 4.0", "< 5.0"
|
33
|
+
spec.add_runtime_dependency "zeitwerk"
|
31
34
|
|
32
35
|
spec.add_development_dependency "bundler", ">= 1.17", "< 3"
|
33
36
|
spec.add_development_dependency "minitest", "~> 5.0"
|