caoutsearch 0.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 +7 -0
- data/LICENSE +22 -0
- data/README.md +43 -0
- data/lib/caoutsearch/config/client.rb +13 -0
- data/lib/caoutsearch/config/mappings.rb +40 -0
- data/lib/caoutsearch/config/settings.rb +29 -0
- data/lib/caoutsearch/filter/base.rb +101 -0
- data/lib/caoutsearch/filter/boolean.rb +19 -0
- data/lib/caoutsearch/filter/date.rb +49 -0
- data/lib/caoutsearch/filter/default.rb +51 -0
- data/lib/caoutsearch/filter/geo_point.rb +11 -0
- data/lib/caoutsearch/filter/match.rb +57 -0
- data/lib/caoutsearch/filter/none.rb +7 -0
- data/lib/caoutsearch/filter/range.rb +28 -0
- data/lib/caoutsearch/filter.rb +29 -0
- data/lib/caoutsearch/index/base.rb +35 -0
- data/lib/caoutsearch/index/document.rb +107 -0
- data/lib/caoutsearch/index/indice.rb +55 -0
- data/lib/caoutsearch/index/indice_versions.rb +123 -0
- data/lib/caoutsearch/index/instrumentation.rb +19 -0
- data/lib/caoutsearch/index/internal_dsl.rb +77 -0
- data/lib/caoutsearch/index/naming.rb +29 -0
- data/lib/caoutsearch/index/reindex.rb +77 -0
- data/lib/caoutsearch/index/scoping.rb +54 -0
- data/lib/caoutsearch/index/serialization.rb +136 -0
- data/lib/caoutsearch/index.rb +7 -0
- data/lib/caoutsearch/instrumentation/base.rb +69 -0
- data/lib/caoutsearch/instrumentation/index.rb +57 -0
- data/lib/caoutsearch/instrumentation/search.rb +41 -0
- data/lib/caoutsearch/mappings.rb +79 -0
- data/lib/caoutsearch/search/base.rb +27 -0
- data/lib/caoutsearch/search/dsl/item.rb +42 -0
- data/lib/caoutsearch/search/query/base.rb +16 -0
- data/lib/caoutsearch/search/query/boolean.rb +63 -0
- data/lib/caoutsearch/search/query/cleaning.rb +29 -0
- data/lib/caoutsearch/search/query/getters.rb +35 -0
- data/lib/caoutsearch/search/query/merge.rb +27 -0
- data/lib/caoutsearch/search/query/nested.rb +23 -0
- data/lib/caoutsearch/search/query/setters.rb +68 -0
- data/lib/caoutsearch/search/sanitizer.rb +28 -0
- data/lib/caoutsearch/search/search/delete_methods.rb +21 -0
- data/lib/caoutsearch/search/search/inspect.rb +36 -0
- data/lib/caoutsearch/search/search/instrumentation.rb +21 -0
- data/lib/caoutsearch/search/search/internal_dsl.rb +77 -0
- data/lib/caoutsearch/search/search/naming.rb +47 -0
- data/lib/caoutsearch/search/search/query_builder.rb +94 -0
- data/lib/caoutsearch/search/search/query_methods.rb +180 -0
- data/lib/caoutsearch/search/search/resettable.rb +35 -0
- data/lib/caoutsearch/search/search/response.rb +88 -0
- data/lib/caoutsearch/search/search/scroll_methods.rb +113 -0
- data/lib/caoutsearch/search/search/search_methods.rb +230 -0
- data/lib/caoutsearch/search/type_cast.rb +76 -0
- data/lib/caoutsearch/search/value.rb +111 -0
- data/lib/caoutsearch/search/value_overflow.rb +17 -0
- data/lib/caoutsearch/search.rb +6 -0
- data/lib/caoutsearch/settings.rb +22 -0
- data/lib/caoutsearch/version.rb +5 -0
- data/lib/caoutsearch.rb +38 -0
- metadata +268 -0
@@ -0,0 +1,230 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Search
|
5
|
+
module Search
|
6
|
+
module SearchMethods
|
7
|
+
attr_reader :current_context, :current_order, :current_aggregations,
|
8
|
+
:current_suggestions, :current_fields, :current_source
|
9
|
+
|
10
|
+
# Public API
|
11
|
+
# ------------------------------------------------------------------------
|
12
|
+
def search(...)
|
13
|
+
spawn.search!(...)
|
14
|
+
end
|
15
|
+
|
16
|
+
def context(...)
|
17
|
+
spawn.context!(...)
|
18
|
+
end
|
19
|
+
|
20
|
+
def order(...)
|
21
|
+
spawn.order!(...)
|
22
|
+
end
|
23
|
+
|
24
|
+
def page(...)
|
25
|
+
spawn.page!(...)
|
26
|
+
end
|
27
|
+
|
28
|
+
def limit(...)
|
29
|
+
spawn.limit!(...)
|
30
|
+
end
|
31
|
+
alias_method :per, :limit
|
32
|
+
|
33
|
+
def offset(...)
|
34
|
+
spawn.offset!(...)
|
35
|
+
end
|
36
|
+
|
37
|
+
def aggregate(...)
|
38
|
+
spawn.aggregate!(...)
|
39
|
+
end
|
40
|
+
|
41
|
+
def suggest(...)
|
42
|
+
spawn.suggest!(...)
|
43
|
+
end
|
44
|
+
|
45
|
+
def fields(...)
|
46
|
+
spawn.fields!(...)
|
47
|
+
end
|
48
|
+
alias_method :returns, :fields
|
49
|
+
|
50
|
+
def source(...)
|
51
|
+
spawn.source!(...)
|
52
|
+
end
|
53
|
+
alias_method :with_sources, :source
|
54
|
+
|
55
|
+
def without_sources
|
56
|
+
spawn.source!(false)
|
57
|
+
end
|
58
|
+
|
59
|
+
def without_hits
|
60
|
+
spawn.source!(false).limit!(0)
|
61
|
+
end
|
62
|
+
|
63
|
+
def track_total_hits(...)
|
64
|
+
spawn.track_total_hits!(...)
|
65
|
+
end
|
66
|
+
|
67
|
+
def prepend(...)
|
68
|
+
spawn.prepend!(...)
|
69
|
+
end
|
70
|
+
|
71
|
+
def append(...)
|
72
|
+
spawn.append!(...)
|
73
|
+
end
|
74
|
+
|
75
|
+
def unscope(...)
|
76
|
+
spawn.unscope!(...)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Setters
|
80
|
+
# ------------------------------------------------------------------------
|
81
|
+
def search!(*values)
|
82
|
+
values = values.flatten.map do |value|
|
83
|
+
value = value.stringify_keys if value.is_a?(Hash)
|
84
|
+
value
|
85
|
+
end
|
86
|
+
|
87
|
+
@search_criteria ||= []
|
88
|
+
@search_criteria += values
|
89
|
+
self
|
90
|
+
end
|
91
|
+
|
92
|
+
def context!(value)
|
93
|
+
@current_context = value
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
def order!(value)
|
98
|
+
@current_order = value
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
def page!(value)
|
103
|
+
@current_page = value
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
107
|
+
def limit!(value)
|
108
|
+
@current_limit = value
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
def offset!(value)
|
113
|
+
@current_offset = value
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
117
|
+
def aggregate!(*values)
|
118
|
+
@current_aggregations ||= []
|
119
|
+
@current_aggregations += values.flatten
|
120
|
+
self
|
121
|
+
end
|
122
|
+
|
123
|
+
def suggest!(values, **options)
|
124
|
+
raise ArgumentError unless values.is_a?(Hash)
|
125
|
+
|
126
|
+
@current_suggestions ||= []
|
127
|
+
@current_suggestions << [values, options]
|
128
|
+
self
|
129
|
+
end
|
130
|
+
|
131
|
+
def fields!(*values)
|
132
|
+
@current_fields ||= []
|
133
|
+
@current_fields += values.flatten
|
134
|
+
self
|
135
|
+
end
|
136
|
+
|
137
|
+
def source!(*values)
|
138
|
+
@current_source ||= []
|
139
|
+
@current_source += values.flatten
|
140
|
+
self
|
141
|
+
end
|
142
|
+
|
143
|
+
def track_total_hits!(value = true)
|
144
|
+
@track_total_hits = value
|
145
|
+
self
|
146
|
+
end
|
147
|
+
|
148
|
+
def prepend!(hash)
|
149
|
+
@prepend_hash = hash
|
150
|
+
self
|
151
|
+
end
|
152
|
+
|
153
|
+
def append!(hash)
|
154
|
+
@append_hash = hash
|
155
|
+
self
|
156
|
+
end
|
157
|
+
|
158
|
+
UNSCOPE_KEYS = {
|
159
|
+
"search" => :@search_criteria,
|
160
|
+
"search_criteria" => :@search_criteria,
|
161
|
+
"limit" => :@current_limit,
|
162
|
+
"per" => :@current_limit,
|
163
|
+
"aggregate" => :@current_aggregations,
|
164
|
+
"aggregations" => :@current_aggregations,
|
165
|
+
"suggest" => :@current_suggestions,
|
166
|
+
"suggestions" => :@current_suggestions,
|
167
|
+
"context" => :@current_context,
|
168
|
+
"order" => :@current_order,
|
169
|
+
"page" => :@current_page,
|
170
|
+
"offset" => :@current_offset,
|
171
|
+
"fields" => :@current_fields,
|
172
|
+
"source" => :@current_source
|
173
|
+
}.freeze
|
174
|
+
|
175
|
+
def unscope!(key)
|
176
|
+
raise ArgumentError unless (variable = UNSCOPE_KEYS[key.to_s])
|
177
|
+
|
178
|
+
reset_variable(variable)
|
179
|
+
self
|
180
|
+
end
|
181
|
+
|
182
|
+
# Getters
|
183
|
+
# ------------------------------------------------------------------------
|
184
|
+
def search_criteria
|
185
|
+
@search_criteria ||= []
|
186
|
+
end
|
187
|
+
|
188
|
+
def current_page
|
189
|
+
@current_page&.to_i || 1
|
190
|
+
end
|
191
|
+
|
192
|
+
def current_limit
|
193
|
+
@current_limit&.to_i || 10
|
194
|
+
end
|
195
|
+
|
196
|
+
def current_offset
|
197
|
+
if @current_offset
|
198
|
+
@current_offset.to_i
|
199
|
+
elsif @current_page
|
200
|
+
(current_limit * (current_page - 1))
|
201
|
+
else
|
202
|
+
0
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Criteria handlers
|
207
|
+
# ------------------------------------------------------------------------
|
208
|
+
def find_criterion(key)
|
209
|
+
key = key.to_s
|
210
|
+
search_criteria.find do |value|
|
211
|
+
return value[key] if value.is_a?(Hash) && value.key?(key)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
def has_criterion?(key)
|
216
|
+
key = key.to_s
|
217
|
+
search_criteria.any? do |value|
|
218
|
+
return true if value.is_a?(Hash) && value.key?(key)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def search_criteria_keys
|
223
|
+
search_criteria.each_with_object([]) do |criterion, keys|
|
224
|
+
keys.concat(criterion.keys) if criterion.is_a?(Hash)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Search
|
5
|
+
module TypeCast
|
6
|
+
class << self
|
7
|
+
def cast(type, value)
|
8
|
+
case type.to_s
|
9
|
+
when "integer", "long", "short", "byte"
|
10
|
+
cast_as_integer(value)
|
11
|
+
when "double", "float", "half_float", "scaled_float"
|
12
|
+
cast_as_float(value)
|
13
|
+
when "boolean"
|
14
|
+
cast_as_boolean(value)
|
15
|
+
when "geo_point"
|
16
|
+
cast_as_geo_point(value)
|
17
|
+
when "date"
|
18
|
+
value.to_date.as_json
|
19
|
+
else
|
20
|
+
value
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def cast_as_integer(value)
|
25
|
+
case value
|
26
|
+
when nil then nil
|
27
|
+
when Array then value.map { |v| cast_as_integer(v) }
|
28
|
+
when String then value.delete(" ").to_i
|
29
|
+
else value.to_i
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def cast_as_float(value)
|
34
|
+
case value
|
35
|
+
when nil then nil
|
36
|
+
when Array then value.map { |v| cast_as_float(v) }
|
37
|
+
when String then value.to_s.delete(" ").tr(",", ".").to_f
|
38
|
+
else value.to_f
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# rubocop:disable Lint/BooleanSymbol
|
43
|
+
BOOLEAN_FALSE_VALUES = [
|
44
|
+
false, 0,
|
45
|
+
"0", :"0",
|
46
|
+
"f", :f,
|
47
|
+
"F", :F,
|
48
|
+
"false", :false,
|
49
|
+
"FALSE", :FALSE,
|
50
|
+
"off", :off,
|
51
|
+
"OFF", :OFF
|
52
|
+
].to_set.freeze
|
53
|
+
# rubocop:enable Lint/BooleanSymbol
|
54
|
+
|
55
|
+
def cast_as_boolean(value)
|
56
|
+
if value == ""
|
57
|
+
nil
|
58
|
+
else
|
59
|
+
BOOLEAN_FALSE_VALUES.exclude?(value)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def cast_as_geo_point(value)
|
64
|
+
if value.is_a? Hash
|
65
|
+
value = value.stringify_keys
|
66
|
+
value = [value["lat"], value["lon"] || value["lng"]]
|
67
|
+
end
|
68
|
+
|
69
|
+
raise ArgumentError, "invalid geo point: #{value.inspect}" unless value.is_a?(Array) && value.length == 2
|
70
|
+
|
71
|
+
value.map(&:to_f).reverse
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Search
|
5
|
+
class Value
|
6
|
+
attr_reader :original_value, :type, :null_values, :transform_proc, :overflow_strategy
|
7
|
+
|
8
|
+
def initialize(original_value, type, null_values: nil, transform: nil, sanitize: false)
|
9
|
+
@original_value = original_value
|
10
|
+
@type = type
|
11
|
+
@null_values = Array.wrap(null_values)
|
12
|
+
@sanitize_value = sanitize
|
13
|
+
@transform_proc = transform
|
14
|
+
@transform_proc = transform.to_proc if transform.is_a?(Symbol)
|
15
|
+
end
|
16
|
+
|
17
|
+
def value
|
18
|
+
unless defined?(@value)
|
19
|
+
@value = transform_value(original_value)
|
20
|
+
@value = cast_value(@value)
|
21
|
+
@value = check_value_overflow(@value)
|
22
|
+
@value = strip_value(@value)
|
23
|
+
@value = sanitize_value(@value) if sanitize_value?
|
24
|
+
@value = replace_null_values(@value)
|
25
|
+
@value = reduce_value(@value)
|
26
|
+
end
|
27
|
+
|
28
|
+
@value
|
29
|
+
end
|
30
|
+
|
31
|
+
def cast_value(value)
|
32
|
+
Caoutsearch::Search::TypeCast.cast(type, value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def sanitize_value(value)
|
36
|
+
Caoutsearch::Search::Sanitizer.sanitize(value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def sanitize_value?
|
40
|
+
!!@sanitize_value
|
41
|
+
end
|
42
|
+
|
43
|
+
def check_value_overflow(value)
|
44
|
+
if value.is_a?(Array)
|
45
|
+
value.map { |v| check_value_overflow(v) }
|
46
|
+
elsif value.nil?
|
47
|
+
value
|
48
|
+
else
|
49
|
+
range = INTEGER_TYPE_LIMITS[type.to_s]
|
50
|
+
|
51
|
+
if range
|
52
|
+
raise Caoutsearch::Search::ValueOverflow.new(:lower, value, range.first) if value < range.first
|
53
|
+
raise Caoutsearch::Search::ValueOverflow.new(:upper, value, range.last) if range && value > range.last
|
54
|
+
end
|
55
|
+
|
56
|
+
value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.bytes_size_to_integer_range(bytes_size)
|
61
|
+
limit = 2**(bytes_size - 1)
|
62
|
+
-limit..(limit - 1)
|
63
|
+
end
|
64
|
+
|
65
|
+
INTEGER_TYPE_LIMITS = {
|
66
|
+
"long" => bytes_size_to_integer_range(64),
|
67
|
+
"integer" => bytes_size_to_integer_range(32),
|
68
|
+
"short" => bytes_size_to_integer_range(16),
|
69
|
+
"byte" => bytes_size_to_integer_range(8)
|
70
|
+
}.freeze
|
71
|
+
|
72
|
+
def transform_value(value)
|
73
|
+
if value.is_a?(Array)
|
74
|
+
value.flat_map { |v| transform_value(v) }
|
75
|
+
|
76
|
+
elsif transform_proc.respond_to?(:call)
|
77
|
+
transform_proc.call(value)
|
78
|
+
|
79
|
+
else
|
80
|
+
value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def strip_value(value)
|
85
|
+
value = value.strip if value.is_a?(String)
|
86
|
+
value
|
87
|
+
end
|
88
|
+
|
89
|
+
def replace_null_values(value)
|
90
|
+
if value.is_a?(Array)
|
91
|
+
value.map { |v| replace_null_values(v) }
|
92
|
+
|
93
|
+
elsif null_values.include?(value)
|
94
|
+
nil
|
95
|
+
|
96
|
+
else
|
97
|
+
value
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def reduce_value(value)
|
102
|
+
if value.is_a?(Array) && value.size == 1
|
103
|
+
value[0]
|
104
|
+
|
105
|
+
else
|
106
|
+
value
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Search
|
5
|
+
class ValueOverflow < StandardError
|
6
|
+
attr_reader :value, :limit, :type
|
7
|
+
|
8
|
+
def initialize(type, value, limit)
|
9
|
+
@type = type
|
10
|
+
@value = value
|
11
|
+
@limit = limit
|
12
|
+
|
13
|
+
super("the value #{value.inspect} exceeds the #{type} limit (#{limit})")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
class Settings
|
5
|
+
# Build an index mapping
|
6
|
+
#
|
7
|
+
# Caoutsearch::Settings.new(number_of_replicas: 2)
|
8
|
+
#
|
9
|
+
def initialize(settings = {})
|
10
|
+
@settings = settings.deep_symbolize_keys
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_hash
|
14
|
+
@settings
|
15
|
+
end
|
16
|
+
alias_method :as_json, :to_hash
|
17
|
+
|
18
|
+
def to_json(*)
|
19
|
+
as_json.to_json
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/caoutsearch.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "zeitwerk"
|
4
|
+
loader = Zeitwerk::Loader.for_gem
|
5
|
+
loader.inflector.inflect(
|
6
|
+
"dsl" => "DSL",
|
7
|
+
"internal_dsl" => "InternalDSL",
|
8
|
+
"none" => "NONE"
|
9
|
+
)
|
10
|
+
loader.setup
|
11
|
+
|
12
|
+
module Caoutsearch
|
13
|
+
class << self
|
14
|
+
attr_writer :client
|
15
|
+
|
16
|
+
def client
|
17
|
+
@client ||= Elasticsearch::Client.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def settings
|
21
|
+
@settings ||= Caoutsearch::Settings.new({})
|
22
|
+
end
|
23
|
+
|
24
|
+
def settings=(settings)
|
25
|
+
@settings = Caoutsearch::Settings.new(settings)
|
26
|
+
end
|
27
|
+
|
28
|
+
def instrument!(**options)
|
29
|
+
@instrumentation_options = options
|
30
|
+
Caoutsearch::Instrumentation::Index.attach_to :caoutsearch_index if options[:index]
|
31
|
+
Caoutsearch::Instrumentation::Search.attach_to :caoutsearch_search if options[:search]
|
32
|
+
end
|
33
|
+
|
34
|
+
def instrumentation_options
|
35
|
+
@instrumentation_options ||= {}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|