redi_search 1.0.3 → 2.0.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 +4 -4
- data/.github/workflows/lint.yml +20 -0
- data/.github/workflows/tests.yml +44 -0
- data/.rubocop.yml +67 -189
- data/Appraisals +4 -8
- data/Gemfile +3 -4
- data/README.md +79 -74
- data/Rakefile +15 -3
- data/bin/console +29 -0
- data/gemfiles/{rails_6.gemfile → activerecord_51.gemfile} +1 -5
- data/gemfiles/{rails_51.gemfile → activerecord_52.gemfile} +1 -5
- data/lib/redi_search.rb +8 -6
- data/lib/redi_search/add.rb +9 -5
- data/lib/redi_search/{alter.rb → add_field.rb} +13 -5
- data/lib/redi_search/client.rb +8 -6
- data/lib/redi_search/client/response.rb +8 -8
- data/lib/redi_search/configuration.rb +1 -11
- data/lib/redi_search/create.rb +6 -4
- data/lib/redi_search/document.rb +5 -4
- data/lib/redi_search/document/display.rb +9 -9
- data/lib/redi_search/document/finder.rb +10 -2
- data/lib/redi_search/index.rb +9 -9
- data/lib/redi_search/lazily_load.rb +7 -13
- data/lib/redi_search/log_subscriber.rb +23 -52
- data/lib/redi_search/model.rb +43 -39
- data/lib/redi_search/schema.rb +3 -3
- data/lib/redi_search/schema/field.rb +2 -3
- data/lib/redi_search/schema/tag_field.rb +1 -1
- data/lib/redi_search/schema/text_field.rb +1 -1
- data/lib/redi_search/search.rb +15 -26
- data/lib/redi_search/search/clauses.rb +6 -7
- data/lib/redi_search/search/clauses/application_clause.rb +20 -5
- data/lib/redi_search/search/clauses/boolean.rb +8 -6
- data/lib/redi_search/search/clauses/highlight.rb +18 -2
- data/lib/redi_search/search/clauses/limit.rb +7 -5
- data/lib/redi_search/search/clauses/return.rb +1 -1
- data/lib/redi_search/search/clauses/slop.rb +1 -1
- data/lib/redi_search/search/clauses/sort_by.rb +1 -1
- data/lib/redi_search/search/clauses/where.rb +13 -3
- data/lib/redi_search/search/result.rb +27 -11
- data/lib/redi_search/search/term.rb +7 -6
- data/lib/redi_search/spellcheck.rb +3 -4
- data/lib/redi_search/spellcheck/result.rb +1 -1
- data/lib/redi_search/validatable.rb +49 -0
- data/lib/redi_search/validations/inclusion.rb +26 -0
- data/lib/redi_search/validations/numericality.rb +45 -0
- data/lib/redi_search/validations/presence.rb +29 -0
- data/lib/redi_search/version.rb +1 -1
- data/redi_search.gemspec +1 -3
- metadata +14 -45
- data/.travis.yml +0 -31
- data/bin/test +0 -7
- data/gemfiles/rails_52.gemfile +0 -17
data/lib/redi_search.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "delegate"
|
4
|
+
require "forwardable"
|
3
5
|
require "redis"
|
4
|
-
require "active_support"
|
5
|
-
require "active_model"
|
6
|
-
require "active_support/core_ext/object"
|
7
|
-
require "active_support/core_ext/module/delegation"
|
6
|
+
require "active_support/lazy_load_hooks"
|
8
7
|
|
9
8
|
require "redi_search/configuration"
|
9
|
+
require "redi_search/client"
|
10
10
|
|
11
11
|
require "redi_search/model"
|
12
12
|
require "redi_search/index"
|
@@ -29,10 +29,12 @@ module RediSearch
|
|
29
29
|
yield(configuration)
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
def client
|
33
|
+
@client ||= Client.new(Redis.new(configuration.redis_config.to_h))
|
34
|
+
end
|
33
35
|
|
34
36
|
def env
|
35
|
-
|
37
|
+
ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
36
38
|
end
|
37
39
|
end
|
38
40
|
end
|
data/lib/redi_search/add.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "redi_search/validatable"
|
4
|
+
|
3
5
|
module RediSearch
|
4
6
|
class Add
|
5
|
-
include
|
7
|
+
include Validatable
|
6
8
|
|
7
|
-
|
8
|
-
greater_than_or_equal_to: 0.0, less_than_or_equal_to: 1.0
|
9
|
-
}
|
9
|
+
validates_numericality_of :score, within: 0.0..1.0
|
10
10
|
|
11
11
|
def initialize(index, document, score: 1.0, replace: {}, language: nil,
|
12
12
|
no_save: false)
|
@@ -48,7 +48,11 @@ module RediSearch
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def replace?
|
51
|
-
replace.
|
51
|
+
if replace.respond_to?(:empty?)
|
52
|
+
!replace.empty?
|
53
|
+
else
|
54
|
+
replace
|
55
|
+
end
|
52
56
|
end
|
53
57
|
|
54
58
|
def replace_options
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RediSearch
|
4
|
-
class
|
4
|
+
class AddField
|
5
5
|
def initialize(index, field_name, schema)
|
6
6
|
@index = index
|
7
7
|
@field_name = field_name
|
@@ -9,17 +9,25 @@ module RediSearch
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def call!
|
12
|
-
index.schema.
|
12
|
+
index.schema.add_field(field_name, raw_schema)
|
13
13
|
|
14
|
-
RediSearch.client.call!(
|
15
|
-
|
16
|
-
|
14
|
+
RediSearch.client.call!(*command).ok?
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
call!
|
19
|
+
rescue Redis::CommandError
|
20
|
+
false
|
17
21
|
end
|
18
22
|
|
19
23
|
private
|
20
24
|
|
21
25
|
attr_reader :index, :field_name, :raw_schema
|
22
26
|
|
27
|
+
def command
|
28
|
+
["ALTER", index.name, "SCHEMA", "ADD", *field_schema]
|
29
|
+
end
|
30
|
+
|
23
31
|
def field_schema
|
24
32
|
@field_schema ||= Schema.make_field(field_name, raw_schema)
|
25
33
|
end
|
data/lib/redi_search/client.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "redis"
|
4
|
+
require "active_support/notifications"
|
5
|
+
|
4
6
|
require "redi_search/client/response"
|
5
7
|
|
6
8
|
module RediSearch
|
7
9
|
class Client
|
8
|
-
def initialize(
|
9
|
-
@redis =
|
10
|
+
def initialize(redis = Redis.new)
|
11
|
+
@redis = redis
|
10
12
|
end
|
11
13
|
|
12
14
|
def call!(command, *params)
|
@@ -15,8 +17,8 @@ module RediSearch
|
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
|
-
def
|
19
|
-
Response.new(redis.
|
20
|
+
def multi
|
21
|
+
Response.new(redis.multi do
|
20
22
|
instrument("pipeline", query: ["begin pipeline"])
|
21
23
|
yield
|
22
24
|
instrument("pipeline", query: ["finish pipeline"])
|
@@ -33,8 +35,8 @@ module RediSearch
|
|
33
35
|
|
34
36
|
def instrument(action, payload, &block)
|
35
37
|
ActiveSupport::Notifications.instrument(
|
36
|
-
"
|
37
|
-
{ name: "RediSearch" }.merge(payload),
|
38
|
+
"action.redi_search",
|
39
|
+
{ name: "RediSearch", action: action }.merge(payload),
|
38
40
|
&Proc.new(&(block || proc {}))
|
39
41
|
)
|
40
42
|
end
|
@@ -3,12 +3,6 @@
|
|
3
3
|
module RediSearch
|
4
4
|
class Client
|
5
5
|
class Response < SimpleDelegator
|
6
|
-
def initialize(response)
|
7
|
-
@response = response
|
8
|
-
|
9
|
-
super(response)
|
10
|
-
end
|
11
|
-
|
12
6
|
def ok?
|
13
7
|
case response
|
14
8
|
when String then response == "OK"
|
@@ -18,15 +12,21 @@ module RediSearch
|
|
18
12
|
end
|
19
13
|
end
|
20
14
|
|
21
|
-
|
15
|
+
def nil?
|
16
|
+
response.nil?
|
17
|
+
end
|
22
18
|
|
23
|
-
|
19
|
+
private
|
24
20
|
|
25
21
|
def array_ok?
|
26
22
|
response.all? do |pipeline_response|
|
27
23
|
Response.new(pipeline_response).ok?
|
28
24
|
end
|
29
25
|
end
|
26
|
+
|
27
|
+
def response
|
28
|
+
__getobj__
|
29
|
+
end
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
@@ -1,17 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "redi_search/client"
|
4
|
-
|
5
3
|
module RediSearch
|
6
4
|
class Configuration
|
7
|
-
|
8
|
-
|
9
|
-
def client
|
10
|
-
@client ||= Client.new(redis_config)
|
11
|
-
end
|
12
|
-
|
13
|
-
def redis_config
|
14
|
-
@redis_config ||= { host: "127.0.0.1", port: "6379" }
|
15
|
-
end
|
5
|
+
attr_accessor :redis_config
|
16
6
|
end
|
17
7
|
end
|
data/lib/redi_search/create.rb
CHANGED
@@ -17,9 +17,7 @@ module RediSearch
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def call!
|
20
|
-
RediSearch.client.call!(
|
21
|
-
"CREATE", index.name, *extract_options.compact, "SCHEMA", schema.to_a
|
22
|
-
).ok?
|
20
|
+
RediSearch.client.call!(*command).ok?
|
23
21
|
end
|
24
22
|
|
25
23
|
def call
|
@@ -32,12 +30,16 @@ module RediSearch
|
|
32
30
|
|
33
31
|
attr_reader :index, :schema, :options
|
34
32
|
|
33
|
+
def command
|
34
|
+
["CREATE", index.name, *extract_options.compact, "SCHEMA", schema.to_a]
|
35
|
+
end
|
36
|
+
|
35
37
|
def extract_options
|
36
38
|
options.map do |clause, switch|
|
37
39
|
next unless OPTION_MAPPER.key?(clause.to_sym) && switch
|
38
40
|
|
39
41
|
OPTION_MAPPER[clause.to_sym]
|
40
|
-
end
|
42
|
+
end + temporary_option
|
41
43
|
end
|
42
44
|
|
43
45
|
def temporary_option
|
data/lib/redi_search/document.rb
CHANGED
@@ -12,7 +12,7 @@ module RediSearch
|
|
12
12
|
object_to_serialize = serializer&.new(record) || record
|
13
13
|
|
14
14
|
field_values = index.schema.fields.map do |field|
|
15
|
-
next
|
15
|
+
next unless only.empty? || only.include?(field.to_sym)
|
16
16
|
|
17
17
|
[field.to_s, object_to_serialize.public_send(field)]
|
18
18
|
end.compact.to_h
|
@@ -41,7 +41,8 @@ module RediSearch
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def del(delete_document: false)
|
44
|
-
|
44
|
+
command = ["DEL", index.name, document_id, ("DD" if delete_document)]
|
45
|
+
call!(*command.compact).ok?
|
45
46
|
end
|
46
47
|
|
47
48
|
def schema_fields
|
@@ -61,7 +62,7 @@ module RediSearch
|
|
61
62
|
end
|
62
63
|
|
63
64
|
def document_id_without_index
|
64
|
-
if @document_id.to_s.
|
65
|
+
if @document_id.to_s.start_with? index.name
|
65
66
|
@document_id.gsub(index.name, "")
|
66
67
|
else
|
67
68
|
@document_id
|
@@ -78,7 +79,7 @@ module RediSearch
|
|
78
79
|
|
79
80
|
def load_attributes
|
80
81
|
attributes.each do |field, value|
|
81
|
-
next unless schema_fields.include? field
|
82
|
+
next unless schema_fields.include? field.to_s
|
82
83
|
|
83
84
|
instance_variable_set(:"@#{field}", value)
|
84
85
|
define_singleton_method(field) { value }
|
@@ -3,7 +3,6 @@
|
|
3
3
|
module RediSearch
|
4
4
|
class Document
|
5
5
|
module Display
|
6
|
-
#:nocov:
|
7
6
|
def inspect
|
8
7
|
inspection = pretty_print_attributes.map do |field_name|
|
9
8
|
"#{field_name}: #{public_send(field_name)}"
|
@@ -12,6 +11,15 @@ module RediSearch
|
|
12
11
|
"#<#{self.class} #{inspection}>"
|
13
12
|
end
|
14
13
|
|
14
|
+
def pretty_print_attributes
|
15
|
+
pp_attrs = attributes.keys.dup
|
16
|
+
pp_attrs.push("document_id")
|
17
|
+
pp_attrs.push("score") if score
|
18
|
+
|
19
|
+
pp_attrs.compact
|
20
|
+
end
|
21
|
+
|
22
|
+
#:nocov:
|
15
23
|
def pretty_print(printer) # rubocop:disable Metrics/MethodLength
|
16
24
|
printer.object_address_group(self) do
|
17
25
|
printer.seplist(
|
@@ -27,14 +35,6 @@ module RediSearch
|
|
27
35
|
end
|
28
36
|
end
|
29
37
|
end
|
30
|
-
|
31
|
-
def pretty_print_attributes
|
32
|
-
pp_attrs = attributes.keys.dup
|
33
|
-
pp_attrs.push("document_id")
|
34
|
-
pp_attrs.push("score") if score.present?
|
35
|
-
|
36
|
-
pp_attrs.compact
|
37
|
-
end
|
38
38
|
#:nocov:
|
39
39
|
end
|
40
40
|
end
|
@@ -5,7 +5,7 @@ module RediSearch
|
|
5
5
|
class Finder
|
6
6
|
def initialize(index, *document_ids)
|
7
7
|
@index = index
|
8
|
-
@document_ids =
|
8
|
+
@document_ids = [*document_ids]
|
9
9
|
end
|
10
10
|
|
11
11
|
def find
|
@@ -61,10 +61,18 @@ module RediSearch
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def parse_document(document_id, document_response)
|
64
|
-
return
|
64
|
+
return unless document_response?(document_response)
|
65
65
|
|
66
66
|
Document.new(index, document_id, Hash[*document_response])
|
67
67
|
end
|
68
|
+
|
69
|
+
def document_response?(document_response)
|
70
|
+
if document_response.respond_to?(:empty?)
|
71
|
+
!document_response.empty?
|
72
|
+
else
|
73
|
+
!document_response.nil?
|
74
|
+
end
|
75
|
+
end
|
68
76
|
end
|
69
77
|
end
|
70
78
|
end
|
data/lib/redi_search/index.rb
CHANGED
@@ -5,14 +5,14 @@ require "redi_search/create"
|
|
5
5
|
require "redi_search/schema"
|
6
6
|
require "redi_search/search"
|
7
7
|
require "redi_search/spellcheck"
|
8
|
-
require "redi_search/
|
8
|
+
require "redi_search/add_field"
|
9
9
|
|
10
10
|
module RediSearch
|
11
11
|
class Index
|
12
12
|
attr_reader :name, :schema, :model
|
13
13
|
|
14
14
|
def initialize(name, schema, model = nil)
|
15
|
-
@name = name
|
15
|
+
@name = name.to_s
|
16
16
|
@schema = Schema.new(schema)
|
17
17
|
@model = model
|
18
18
|
end
|
@@ -51,10 +51,10 @@ module RediSearch
|
|
51
51
|
Add.new(self, document, **options).call!
|
52
52
|
end
|
53
53
|
|
54
|
-
def add_multiple
|
55
|
-
client.
|
54
|
+
def add_multiple(documents, **options)
|
55
|
+
client.multi do
|
56
56
|
documents.each do |document|
|
57
|
-
add
|
57
|
+
add(document, **options)
|
58
58
|
end
|
59
59
|
end.ok?
|
60
60
|
end
|
@@ -85,15 +85,15 @@ module RediSearch
|
|
85
85
|
drop if recreate
|
86
86
|
create unless exist?
|
87
87
|
|
88
|
-
add_multiple
|
88
|
+
add_multiple documents, **options
|
89
89
|
end
|
90
90
|
|
91
91
|
def document_count
|
92
|
-
info
|
92
|
+
info.num_docs.to_i
|
93
93
|
end
|
94
94
|
|
95
|
-
def
|
96
|
-
|
95
|
+
def add_field(field_name, schema)
|
96
|
+
AddField.new(self, field_name, schema).call!
|
97
97
|
end
|
98
98
|
|
99
99
|
private
|
@@ -2,13 +2,11 @@
|
|
2
2
|
|
3
3
|
module RediSearch
|
4
4
|
module LazilyLoad
|
5
|
-
extend
|
5
|
+
extend Forwardable
|
6
6
|
|
7
7
|
include Enumerable
|
8
8
|
|
9
|
-
|
10
|
-
delegate :size, :each, to: :to_a
|
11
|
-
end
|
9
|
+
def_delegators :to_a, :size, :each, :last, :[], :count, :empty?
|
12
10
|
|
13
11
|
def loaded?
|
14
12
|
@loaded = false unless defined? @loaded
|
@@ -24,7 +22,6 @@ module RediSearch
|
|
24
22
|
|
25
23
|
alias load to_a
|
26
24
|
|
27
|
-
#:nocov:
|
28
25
|
def inspect
|
29
26
|
execute_and_rescue_inspection do
|
30
27
|
return super unless valid?
|
@@ -33,6 +30,7 @@ module RediSearch
|
|
33
30
|
end
|
34
31
|
end
|
35
32
|
|
33
|
+
#:nocov:
|
36
34
|
def pretty_print(printer)
|
37
35
|
execute_and_rescue_inspection do
|
38
36
|
return super(inspect) unless valid?
|
@@ -42,12 +40,10 @@ module RediSearch
|
|
42
40
|
end
|
43
41
|
#:nocov:
|
44
42
|
|
45
|
-
def count
|
46
|
-
to_a.size
|
47
|
-
end
|
48
|
-
|
49
43
|
private
|
50
44
|
|
45
|
+
attr_reader :documents
|
46
|
+
|
51
47
|
def command
|
52
48
|
raise NotImplementedError, "included class did not define #{__method__}"
|
53
49
|
end
|
@@ -57,12 +53,12 @@ module RediSearch
|
|
57
53
|
|
58
54
|
@loaded = true
|
59
55
|
|
60
|
-
call
|
56
|
+
call!.yield_self do |response|
|
61
57
|
parse_response(response)
|
62
58
|
end
|
63
59
|
end
|
64
60
|
|
65
|
-
def call!
|
61
|
+
def call!
|
66
62
|
RediSearch.client.call!(*command)
|
67
63
|
end
|
68
64
|
|
@@ -74,7 +70,6 @@ module RediSearch
|
|
74
70
|
true
|
75
71
|
end
|
76
72
|
|
77
|
-
#:nocov:
|
78
73
|
def execute_and_rescue_inspection
|
79
74
|
execute unless loaded?
|
80
75
|
|
@@ -82,6 +77,5 @@ module RediSearch
|
|
82
77
|
rescue Redis::CommandError => e
|
83
78
|
e.message
|
84
79
|
end
|
85
|
-
#:nocov:
|
86
80
|
end
|
87
81
|
end
|