redi_search 1.0.0 → 1.0.1
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/lib/redi_search/add.rb +2 -9
- data/lib/redi_search/alter.rb +2 -5
- data/lib/redi_search/client/response.rb +32 -0
- data/lib/redi_search/client.rb +5 -31
- data/lib/redi_search/create.rb +1 -5
- data/lib/redi_search/document/display.rb +41 -0
- data/lib/redi_search/document/finder.rb +70 -0
- data/lib/redi_search/document.rb +25 -71
- data/lib/redi_search/lazily_load.rb +30 -8
- data/lib/redi_search/log_subscriber.rb +9 -7
- data/lib/redi_search/schema.rb +1 -3
- data/lib/redi_search/search/clauses/boolean.rb +23 -20
- data/lib/redi_search/search/clauses/where.rb +9 -6
- data/lib/redi_search/search/clauses.rb +5 -7
- data/lib/redi_search/search/result.rb +11 -7
- data/lib/redi_search/search/term.rb +17 -14
- data/lib/redi_search/search.rb +13 -5
- data/lib/redi_search/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28b67b5a88b3440ae45548484cc556a2cc0866328701f3a0ae8bac9aee8fe0c4
|
4
|
+
data.tar.gz: 494003de36b2acfd5b0338dc2421dd1add923d55ac0925f1ae2f798f0d56f535
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf672f8b0c8ac5b129c36596c24bfcbbb0eb522c7b8233d24b5b6f68ccf4465989e298c2fef25ed355a9ab476159ffd2682bf622bc10df8625b46a641005633c
|
7
|
+
data.tar.gz: 319e401ec3cf9ac165c62e84223c62e267bd80658bdf61abcbf673d87a51516a6de8f02c51441d3b355fdd03fddf479c5e6ae5aa86002e7503bc62f33e32422f
|
data/lib/redi_search/add.rb
CHANGED
@@ -35,15 +35,8 @@ module RediSearch
|
|
35
35
|
attr_reader :index, :document, :score, :replace, :language, :no_save
|
36
36
|
|
37
37
|
def command
|
38
|
-
[
|
39
|
-
|
40
|
-
index.name,
|
41
|
-
document.document_id,
|
42
|
-
score,
|
43
|
-
*extract_options,
|
44
|
-
"FIELDS",
|
45
|
-
document.redis_attributes
|
46
|
-
].compact
|
38
|
+
["ADD", index.name, document.document_id, score, *extract_options,
|
39
|
+
"FIELDS", document.redis_attributes].compact
|
47
40
|
end
|
48
41
|
|
49
42
|
def extract_options
|
data/lib/redi_search/alter.rb
CHANGED
@@ -10,12 +10,9 @@ module RediSearch
|
|
10
10
|
|
11
11
|
def call!
|
12
12
|
index.schema.alter(field_name, raw_schema)
|
13
|
+
|
13
14
|
RediSearch.client.call!(
|
14
|
-
"ALTER",
|
15
|
-
index.name,
|
16
|
-
"SCHEMA",
|
17
|
-
"ADD",
|
18
|
-
*field_schema
|
15
|
+
"ALTER", index.name, "SCHEMA", "ADD", *field_schema
|
19
16
|
).ok?
|
20
17
|
end
|
21
18
|
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RediSearch
|
4
|
+
class Client
|
5
|
+
class Response < SimpleDelegator
|
6
|
+
def initialize(response)
|
7
|
+
@response = response
|
8
|
+
|
9
|
+
super(response)
|
10
|
+
end
|
11
|
+
|
12
|
+
def ok?
|
13
|
+
case response
|
14
|
+
when String then response == "OK"
|
15
|
+
when Integer then response == 1
|
16
|
+
when Array then array_ok?
|
17
|
+
else response
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :response
|
24
|
+
|
25
|
+
def array_ok?
|
26
|
+
response.all? do |pipeline_response|
|
27
|
+
Response.new(pipeline_response).ok?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/redi_search/client.rb
CHANGED
@@ -1,31 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "redis"
|
4
|
+
require "redi_search/client/response"
|
4
5
|
|
5
6
|
module RediSearch
|
6
7
|
class Client
|
7
|
-
class Response < SimpleDelegator
|
8
|
-
def initialize(response)
|
9
|
-
@response = response
|
10
|
-
|
11
|
-
super(response)
|
12
|
-
end
|
13
|
-
|
14
|
-
def ok?
|
15
|
-
if response.is_a? String
|
16
|
-
response == "OK"
|
17
|
-
elsif response.is_a? Array
|
18
|
-
response.all? { |pipeline_response| pipeline_response == "OK" }
|
19
|
-
else
|
20
|
-
response
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
attr_reader :response
|
27
|
-
end
|
28
|
-
|
29
8
|
def initialize(redis_config)
|
30
9
|
@redis = Redis.new(redis_config)
|
31
10
|
end
|
@@ -52,16 +31,11 @@ module RediSearch
|
|
52
31
|
Response.new(redis.call("FT.#{command}", *params))
|
53
32
|
end
|
54
33
|
|
55
|
-
def instrument(action, payload)
|
56
|
-
block =
|
57
|
-
if block_given?
|
58
|
-
Proc.new
|
59
|
-
else
|
60
|
-
proc {}
|
61
|
-
end
|
62
|
-
|
34
|
+
def instrument(action, payload, &block)
|
63
35
|
ActiveSupport::Notifications.instrument(
|
64
|
-
"#{action}.redi_search",
|
36
|
+
"#{action}.redi_search",
|
37
|
+
{ name: "RediSearch" }.merge(payload),
|
38
|
+
&Proc.new(&(block || proc {}))
|
65
39
|
)
|
66
40
|
end
|
67
41
|
end
|
data/lib/redi_search/create.rb
CHANGED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RediSearch
|
4
|
+
class Document
|
5
|
+
module Display
|
6
|
+
#:nocov:
|
7
|
+
def inspect
|
8
|
+
inspection = pretty_print_attributes.map do |field_name|
|
9
|
+
"#{field_name}: #{public_send(field_name)}"
|
10
|
+
end.compact.join(", ")
|
11
|
+
|
12
|
+
"#<#{self.class} #{inspection}>"
|
13
|
+
end
|
14
|
+
|
15
|
+
def pretty_print(printer) # rubocop:disable Metrics/MethodLength
|
16
|
+
printer.object_address_group(self) do
|
17
|
+
printer.seplist(
|
18
|
+
pretty_print_attributes , proc { printer.text "," }
|
19
|
+
) do |field_name|
|
20
|
+
printer.breakable " "
|
21
|
+
printer.group(1) do
|
22
|
+
printer.text field_name
|
23
|
+
printer.text ":"
|
24
|
+
printer.breakable
|
25
|
+
printer.pp public_send(field_name)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
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
|
+
#:nocov:
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RediSearch
|
4
|
+
class Document
|
5
|
+
class Finder
|
6
|
+
def initialize(index, *document_ids)
|
7
|
+
@index = index
|
8
|
+
@document_ids = Array.wrap(document_ids)
|
9
|
+
end
|
10
|
+
|
11
|
+
def find
|
12
|
+
if multi?
|
13
|
+
parse_multi_documents
|
14
|
+
else
|
15
|
+
parse_document(document_ids.first, response)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
attr_reader :index, :document_ids
|
22
|
+
|
23
|
+
def response
|
24
|
+
@response ||= call!(get_command, index.name, *prepended_document_ids)
|
25
|
+
end
|
26
|
+
|
27
|
+
def call!(*command)
|
28
|
+
RediSearch.client.call!(*command)
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_command
|
32
|
+
if multi?
|
33
|
+
"MGET"
|
34
|
+
else
|
35
|
+
"GET"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def multi?
|
40
|
+
document_ids.size > 1
|
41
|
+
end
|
42
|
+
|
43
|
+
def prepended_document_ids
|
44
|
+
document_ids.map do |document_id|
|
45
|
+
prepend_document_id(document_id)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def prepend_document_id(id)
|
50
|
+
if id.to_s.start_with? index.name
|
51
|
+
id
|
52
|
+
else
|
53
|
+
"#{index.name}#{id}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_multi_documents
|
58
|
+
document_ids.map.with_index do |document_id, index|
|
59
|
+
parse_document(document_id, response[index])
|
60
|
+
end.compact
|
61
|
+
end
|
62
|
+
|
63
|
+
def parse_document(document_id, document_response)
|
64
|
+
return if document_response.blank?
|
65
|
+
|
66
|
+
Document.new(index, document_id, Hash[*document_response])
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/redi_search/document.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "redi_search/document/display"
|
4
|
+
require "redi_search/document/finder"
|
5
|
+
|
3
6
|
module RediSearch
|
4
7
|
class Document
|
8
|
+
include Display
|
9
|
+
|
5
10
|
class << self
|
6
11
|
def for_object(index, record, serializer: nil, only: [])
|
7
12
|
object_to_serialize = serializer&.new(record) || record
|
@@ -16,34 +21,11 @@ module RediSearch
|
|
16
21
|
end
|
17
22
|
|
18
23
|
def get(index, document_id)
|
19
|
-
|
20
|
-
"GET", index.name, prepend_document_id(index, document_id)
|
21
|
-
)
|
22
|
-
|
23
|
-
return if response.blank?
|
24
|
-
|
25
|
-
new(index, document_id, Hash[*response])
|
24
|
+
Finder.new(index, document_id).find
|
26
25
|
end
|
27
26
|
|
28
27
|
def mget(index, *document_ids)
|
29
|
-
|
30
|
-
prepend_document_id(index, id)
|
31
|
-
end
|
32
|
-
document_ids.zip(
|
33
|
-
RediSearch.client.call!("MGET", index.name, *unique_document_ids)
|
34
|
-
).map do |document|
|
35
|
-
next if document[1].blank?
|
36
|
-
|
37
|
-
new(index, document[0], Hash[*document[1]])
|
38
|
-
end.compact
|
39
|
-
end
|
40
|
-
|
41
|
-
def prepend_document_id(index, document_id)
|
42
|
-
if document_id.to_s.starts_with? index.name
|
43
|
-
document_id
|
44
|
-
else
|
45
|
-
"#{index.name}#{document_id}"
|
46
|
-
end
|
28
|
+
Finder.new(index, *document_ids).find
|
47
29
|
end
|
48
30
|
end
|
49
31
|
|
@@ -55,53 +37,12 @@ module RediSearch
|
|
55
37
|
@attributes = fields
|
56
38
|
@score = score
|
57
39
|
|
58
|
-
|
59
|
-
next unless schema_fields.include? field
|
60
|
-
|
61
|
-
instance_variable_set(:"@#{field}", value)
|
62
|
-
define_singleton_method(field) { value }
|
63
|
-
end
|
40
|
+
load_attributes
|
64
41
|
end
|
65
42
|
|
66
43
|
def del(delete_document: false)
|
67
|
-
|
68
|
-
"DEL", index.name, document_id, ("DD" if delete_document)
|
69
|
-
) == 1
|
70
|
-
end
|
71
|
-
|
72
|
-
#:nocov:
|
73
|
-
def inspect
|
74
|
-
inspection = pretty_print_attributes.map do |field_name|
|
75
|
-
"#{field_name}: #{public_send(field_name)}"
|
76
|
-
end.compact.join(", ")
|
77
|
-
|
78
|
-
"#<#{self.class} #{inspection}>"
|
79
|
-
end
|
80
|
-
|
81
|
-
def pretty_print(printer) # rubocop:disable Metrics/MethodLength
|
82
|
-
printer.object_address_group(self) do
|
83
|
-
printer.seplist(
|
84
|
-
pretty_print_attributes , proc { printer.text "," }
|
85
|
-
) do |field_name|
|
86
|
-
printer.breakable " "
|
87
|
-
printer.group(1) do
|
88
|
-
printer.text field_name
|
89
|
-
printer.text ":"
|
90
|
-
printer.breakable
|
91
|
-
printer.pp public_send(field_name)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def pretty_print_attributes
|
98
|
-
pp_attrs = attributes.keys.dup
|
99
|
-
pp_attrs.push("document_id")
|
100
|
-
pp_attrs.push("score") if score.present?
|
101
|
-
|
102
|
-
pp_attrs.compact
|
44
|
+
call!("DEL", index.name, document_id, ("DD" if delete_document)).ok?
|
103
45
|
end
|
104
|
-
#:nocov:
|
105
46
|
|
106
47
|
def schema_fields
|
107
48
|
@schema_fields ||= index.schema.fields.map(&:to_s)
|
@@ -112,7 +53,11 @@ module RediSearch
|
|
112
53
|
end
|
113
54
|
|
114
55
|
def document_id
|
115
|
-
|
56
|
+
if @document_id.to_s.start_with? index.name
|
57
|
+
@document_id
|
58
|
+
else
|
59
|
+
"#{index.name}#{@document_id}"
|
60
|
+
end
|
116
61
|
end
|
117
62
|
|
118
63
|
def document_id_without_index
|
@@ -127,8 +72,17 @@ module RediSearch
|
|
127
72
|
|
128
73
|
attr_reader :index
|
129
74
|
|
130
|
-
def
|
131
|
-
RediSearch.client
|
75
|
+
def call!(*command)
|
76
|
+
RediSearch.client.call!(*command)
|
77
|
+
end
|
78
|
+
|
79
|
+
def load_attributes
|
80
|
+
attributes.each do |field, value|
|
81
|
+
next unless schema_fields.include? field
|
82
|
+
|
83
|
+
instance_variable_set(:"@#{field}", value)
|
84
|
+
define_singleton_method(field) { value }
|
85
|
+
end
|
132
86
|
end
|
133
87
|
end
|
134
88
|
end
|
@@ -19,24 +19,26 @@ module RediSearch
|
|
19
19
|
def to_a
|
20
20
|
execute unless loaded?
|
21
21
|
|
22
|
-
|
22
|
+
documents
|
23
23
|
end
|
24
24
|
|
25
25
|
alias load to_a
|
26
26
|
|
27
27
|
#:nocov:
|
28
28
|
def inspect
|
29
|
-
|
29
|
+
execute_and_rescue_inspection do
|
30
|
+
return super unless valid?
|
30
31
|
|
31
|
-
|
32
|
+
documents
|
33
|
+
end
|
32
34
|
end
|
33
35
|
|
34
36
|
def pretty_print(printer)
|
35
|
-
|
37
|
+
execute_and_rescue_inspection do
|
38
|
+
return super(inspect) unless valid?
|
36
39
|
|
37
|
-
|
38
|
-
|
39
|
-
printer.pp(e.message)
|
40
|
+
printer.pp(documents)
|
41
|
+
end
|
40
42
|
end
|
41
43
|
#:nocov:
|
42
44
|
|
@@ -51,15 +53,35 @@ module RediSearch
|
|
51
53
|
end
|
52
54
|
|
53
55
|
def execute
|
56
|
+
return unless valid?
|
57
|
+
|
54
58
|
@loaded = true
|
55
59
|
|
56
|
-
|
60
|
+
call!(*command).yield_self do |response|
|
57
61
|
parse_response(response)
|
58
62
|
end
|
59
63
|
end
|
60
64
|
|
65
|
+
def call!(*command)
|
66
|
+
RediSearch.client.call!(*command)
|
67
|
+
end
|
68
|
+
|
61
69
|
def parse_response(_response)
|
62
70
|
raise NotImplementedError, "included class did not define #{__method__}"
|
63
71
|
end
|
72
|
+
|
73
|
+
def valid?
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
#:nocov:
|
78
|
+
def execute_and_rescue_inspection
|
79
|
+
execute unless loaded?
|
80
|
+
|
81
|
+
yield
|
82
|
+
rescue Redis::CommandError => e
|
83
|
+
e.message
|
84
|
+
end
|
85
|
+
#:nocov:
|
64
86
|
end
|
65
87
|
end
|
@@ -68,17 +68,19 @@ module RediSearch
|
|
68
68
|
self.class.runtime += event.duration
|
69
69
|
return unless logger.debug?
|
70
70
|
|
71
|
-
|
72
|
-
name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
|
73
|
-
command = command_string(payload)
|
71
|
+
command = command_string(event)
|
74
72
|
|
75
|
-
debug " #{
|
73
|
+
debug " #{log_name(event)} #{color(command, debug_color, true)}"
|
76
74
|
end
|
77
75
|
|
78
|
-
def
|
79
|
-
payload[:
|
76
|
+
def log_name(event)
|
77
|
+
color("#{event.payload[:name]} (#{event.duration.round(1)}ms)", RED, true)
|
78
|
+
end
|
79
|
+
|
80
|
+
def command_string(event)
|
81
|
+
event.payload[:query].flatten.map.with_index do |arg, i|
|
80
82
|
arg = "FT.#{arg}" if prepend_ft?(arg, i)
|
81
|
-
arg = arg.inspect if inspect_arg?(payload, arg)
|
83
|
+
arg = arg.inspect if inspect_arg?(event.payload, arg)
|
82
84
|
arg
|
83
85
|
end.join(" ")
|
84
86
|
end
|
data/lib/redi_search/schema.rb
CHANGED
@@ -12,9 +12,7 @@ module RediSearch
|
|
12
12
|
schema, options = options.to_a.flatten
|
13
13
|
|
14
14
|
"RediSearch::Schema::#{schema.to_s.capitalize}Field".
|
15
|
-
constantize.
|
16
|
-
new(field_name, **options.to_h).
|
17
|
-
to_a
|
15
|
+
constantize.new(field_name, **options.to_h).to_a
|
18
16
|
end
|
19
17
|
|
20
18
|
def initialize(raw)
|
@@ -9,16 +9,13 @@ module RediSearch
|
|
9
9
|
@prior_clause = prior_clause
|
10
10
|
@not = false
|
11
11
|
|
12
|
-
initialize_term(term, **term_options)
|
12
|
+
initialize_term(term, **term_options) if term.present?
|
13
13
|
end
|
14
14
|
|
15
15
|
def to_s
|
16
16
|
raise ArgumentError, "missing query terms" if term.blank?
|
17
17
|
|
18
|
-
[
|
19
|
-
prior_clause.presence,
|
20
|
-
queryify_term.dup.prepend(not_operator)
|
21
|
-
].compact.join(operand)
|
18
|
+
[prior_clause.presence, queryify_term].compact.join(operand)
|
22
19
|
end
|
23
20
|
|
24
21
|
delegate :inspect, to: :to_s
|
@@ -26,7 +23,7 @@ module RediSearch
|
|
26
23
|
def not(term, **term_options)
|
27
24
|
@not = true
|
28
25
|
|
29
|
-
initialize_term(term, **term_options)
|
26
|
+
initialize_term(term, **term_options) if term.present?
|
30
27
|
|
31
28
|
search
|
32
29
|
end
|
@@ -46,25 +43,31 @@ module RediSearch
|
|
46
43
|
end
|
47
44
|
|
48
45
|
def initialize_term(term, **term_options)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
else
|
55
|
-
Term.new(term, term_options)
|
56
|
-
end
|
46
|
+
@term = if term.is_a? RediSearch::Search
|
47
|
+
term
|
48
|
+
else
|
49
|
+
Term.new(term, term_options)
|
50
|
+
end
|
57
51
|
end
|
58
52
|
|
59
53
|
def queryify_term
|
60
|
-
if
|
61
|
-
|
62
|
-
"(#{term.term_clause})"
|
63
|
-
elsif term.is_a?(RediSearch::Search)
|
64
|
-
term.term_clause
|
54
|
+
if term_is_search?
|
55
|
+
queryify_search
|
65
56
|
else
|
66
57
|
term
|
67
|
-
end.to_s
|
58
|
+
end.to_s.dup.prepend(not_operator)
|
59
|
+
end
|
60
|
+
|
61
|
+
def term_is_search?
|
62
|
+
term.is_a? RediSearch::Search
|
63
|
+
end
|
64
|
+
|
65
|
+
def queryify_search
|
66
|
+
if !term.term_clause.is_a?(RediSearch::Search::Clauses::Where)
|
67
|
+
"(#{term.term_clause})"
|
68
|
+
else
|
69
|
+
term.term_clause
|
70
|
+
end
|
68
71
|
end
|
69
72
|
end
|
70
73
|
end
|
@@ -53,12 +53,15 @@ module RediSearch
|
|
53
53
|
condition, *options = condition.to_a
|
54
54
|
|
55
55
|
@field = condition[0]
|
56
|
-
@term =
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
56
|
+
@term = make_term(condition, options)
|
57
|
+
end
|
58
|
+
|
59
|
+
def make_term(condition, options)
|
60
|
+
if condition[1].is_a? RediSearch::Search
|
61
|
+
condition[1]
|
62
|
+
else
|
63
|
+
Term.new(condition[1], **options.to_h)
|
64
|
+
end
|
62
65
|
end
|
63
66
|
end
|
64
67
|
end
|
@@ -66,13 +66,11 @@ module RediSearch
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def count
|
69
|
-
if
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
).first
|
75
|
-
end
|
69
|
+
return to_a.size if loaded?
|
70
|
+
|
71
|
+
call!(
|
72
|
+
"SEARCH", index.name, term_clause, *Limit.new(total: 0).clause
|
73
|
+
).first
|
76
74
|
end
|
77
75
|
|
78
76
|
def where(**condition)
|
@@ -7,13 +7,7 @@ module RediSearch
|
|
7
7
|
@count = count
|
8
8
|
@used_clauses = used_clauses
|
9
9
|
|
10
|
-
super(documents
|
11
|
-
document_id = slice[0]
|
12
|
-
fields = slice.last unless no_content?
|
13
|
-
score = slice[1].to_f if with_scores?
|
14
|
-
|
15
|
-
Document.new(index, document_id, Hash[*fields.to_a], score)
|
16
|
-
end)
|
10
|
+
super(parse_results(index, documents))
|
17
11
|
end
|
18
12
|
|
19
13
|
def count
|
@@ -41,6 +35,16 @@ module RediSearch
|
|
41
35
|
def no_content?
|
42
36
|
@used_clauses.include? "no_content"
|
43
37
|
end
|
38
|
+
|
39
|
+
def parse_results(index, documents)
|
40
|
+
documents.each_slice(response_slice).map do |slice|
|
41
|
+
document_id = slice[0]
|
42
|
+
fields = slice.last unless no_content?
|
43
|
+
score = slice[1].to_f if with_scores?
|
44
|
+
|
45
|
+
Document.new(index, document_id, Hash[*fields.to_a], score)
|
46
|
+
end
|
47
|
+
end
|
44
48
|
end
|
45
49
|
end
|
46
50
|
end
|
@@ -3,11 +3,19 @@
|
|
3
3
|
module RediSearch
|
4
4
|
class Search
|
5
5
|
class Term
|
6
|
+
include ActiveModel::Validations
|
7
|
+
|
8
|
+
validates :fuzziness, numericality: {
|
9
|
+
only_integer: true, less_than: 4, greater_than: 0, allow_blank: true
|
10
|
+
}
|
11
|
+
validates :option, inclusion: { in: %i(fuzziness optional prefix) },
|
12
|
+
allow_nil: true
|
13
|
+
|
6
14
|
def initialize(term, **options)
|
7
15
|
@term = term
|
8
16
|
@options = options
|
9
17
|
|
10
|
-
|
18
|
+
validate!
|
11
19
|
end
|
12
20
|
|
13
21
|
def to_s
|
@@ -23,7 +31,7 @@ module RediSearch
|
|
23
31
|
attr_accessor :term, :options
|
24
32
|
|
25
33
|
def fuzziness
|
26
|
-
@fuzziness ||= options[:fuzziness]
|
34
|
+
@fuzziness ||= options[:fuzziness]
|
27
35
|
end
|
28
36
|
|
29
37
|
def optional_operator
|
@@ -38,10 +46,14 @@ module RediSearch
|
|
38
46
|
"*"
|
39
47
|
end
|
40
48
|
|
49
|
+
def fuzzy_operator
|
50
|
+
"%" * fuzziness.to_i
|
51
|
+
end
|
52
|
+
|
41
53
|
def stringify_query
|
42
54
|
@term.to_s.
|
43
55
|
tr("`", "\`").
|
44
|
-
yield_self { |str| "#{
|
56
|
+
yield_self { |str| "#{fuzzy_operator}#{str}#{fuzzy_operator}" }.
|
45
57
|
yield_self { |str| "#{optional_operator}#{str}" }.
|
46
58
|
yield_self { |str| "#{str}#{prefix_operator}" }.
|
47
59
|
yield_self { |str| "`#{str}`" }
|
@@ -55,17 +67,8 @@ module RediSearch
|
|
55
67
|
"[#{first} #{last}]"
|
56
68
|
end
|
57
69
|
|
58
|
-
def
|
59
|
-
|
60
|
-
(options.keys.map(&:to_s) - %w(fuzziness optional prefix)).join(", ")
|
61
|
-
|
62
|
-
if unsupported_options.present?
|
63
|
-
raise(ArgumentError,
|
64
|
-
"#{unsupported_options} are unsupported term options")
|
65
|
-
end
|
66
|
-
|
67
|
-
raise(ArgumentError, "fuzziness can only be between 0 and 3") if
|
68
|
-
fuzziness.negative? || fuzziness > 3
|
70
|
+
def option
|
71
|
+
options.keys.first&.to_sym
|
69
72
|
end
|
70
73
|
end
|
71
74
|
end
|
data/lib/redi_search/search.rb
CHANGED
@@ -37,11 +37,7 @@ module RediSearch
|
|
37
37
|
|
38
38
|
def to_redis
|
39
39
|
command.map do |arg|
|
40
|
-
|
41
|
-
arg.inspect
|
42
|
-
else
|
43
|
-
arg
|
44
|
-
end
|
40
|
+
inspect_command_arg(arg)
|
45
41
|
end.join(" ")
|
46
42
|
end
|
47
43
|
|
@@ -63,5 +59,17 @@ module RediSearch
|
|
63
59
|
def parse_response(response)
|
64
60
|
@documents = Result.new(index, used_clauses, response[0], response[1..-1])
|
65
61
|
end
|
62
|
+
|
63
|
+
def inspect_command_arg(arg)
|
64
|
+
if !arg.to_s.starts_with?(/\(-?@/) && arg.to_s.split(/\s|\|/).size > 1
|
65
|
+
arg.inspect
|
66
|
+
else
|
67
|
+
arg
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def valid?
|
72
|
+
term_clause.present?
|
73
|
+
end
|
66
74
|
end
|
67
75
|
end
|
data/lib/redi_search/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redi_search
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Pezza
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-07-
|
11
|
+
date: 2019-07-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -145,9 +145,12 @@ files:
|
|
145
145
|
- lib/redi_search/add.rb
|
146
146
|
- lib/redi_search/alter.rb
|
147
147
|
- lib/redi_search/client.rb
|
148
|
+
- lib/redi_search/client/response.rb
|
148
149
|
- lib/redi_search/configuration.rb
|
149
150
|
- lib/redi_search/create.rb
|
150
151
|
- lib/redi_search/document.rb
|
152
|
+
- lib/redi_search/document/display.rb
|
153
|
+
- lib/redi_search/document/finder.rb
|
151
154
|
- lib/redi_search/index.rb
|
152
155
|
- lib/redi_search/lazily_load.rb
|
153
156
|
- lib/redi_search/log_subscriber.rb
|