caoutsearch 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bca0632fb965301b9c35bcd47ea7c8346cae1b49a22f41f6ccebd5fdd3181495
|
4
|
+
data.tar.gz: af08a8b38223708009694fa0025c6e83986b12db7e564009416a2cf8c2e303c8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: aef96ca4c7b5dfb867dcaf962eb619deb6091eb47dcbc4946ca3e940d6496af9c8e92d0bff3138039e920f27eaf447e735ec008c79b30e6a4eceadb9d66b13ce
|
7
|
+
data.tar.gz: 0fbc8e5451179f8066a7af0ac228d33639fe81e8e4f157edcf36923e89d73a778116717cc50e06f5d614844249da2993baabac0b99236978ff7373917e0f5735
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2022 Mon Territoire
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# Caoutsearch [\ˈkawt͡ˈsɝtʃ\\](http://ipa-reader.xyz/?text=ˈkawt͡ˈsɝtʃ)
|
2
|
+
|
3
|
+
### Installation
|
4
|
+
|
5
|
+
```bash
|
6
|
+
bundle add caoutsearch
|
7
|
+
```
|
8
|
+
|
9
|
+
### Configuration
|
10
|
+
|
11
|
+
<!-- TODO -->
|
12
|
+
|
13
|
+
### Usage
|
14
|
+
|
15
|
+
<!-- TODO -->
|
16
|
+
|
17
|
+
## Contributing
|
18
|
+
|
19
|
+
1. Don't hesitate to submit your feature/idea/fix in [issues](https://github.com/mon-territoire/caoutsearch)
|
20
|
+
2. Fork the [repository](https://github.com/mon-territoire/caoutsearch)
|
21
|
+
3. Create your feature branch
|
22
|
+
4. Ensure RSpec & Rubocop are passing
|
23
|
+
4. Create a pull request
|
24
|
+
|
25
|
+
### Tests & lint
|
26
|
+
|
27
|
+
```bash
|
28
|
+
bundle exec rspec
|
29
|
+
bundle exec rubocop
|
30
|
+
```
|
31
|
+
|
32
|
+
Both can be run with:
|
33
|
+
|
34
|
+
```bash
|
35
|
+
bundle exec rake
|
36
|
+
```
|
37
|
+
|
38
|
+
## License & credits
|
39
|
+
|
40
|
+
Please see [LICENSE](https://github.com/mon-territoire/caoutsearch/blob/main/LICENSE) for further details.
|
41
|
+
|
42
|
+
Contributors: [./graphs/contributors](https://github.com/mon-territoire/caoutsearch/graphs/contributors)
|
43
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Config
|
5
|
+
module Mappings
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
delegate :mappings, to: :class
|
10
|
+
end
|
11
|
+
|
12
|
+
class_methods do
|
13
|
+
def mappings
|
14
|
+
@mappings ||= Caoutsearch::Mappings.new(default_mappings)
|
15
|
+
end
|
16
|
+
|
17
|
+
def mappings=(mappings)
|
18
|
+
@mappings = Caoutsearch::Mappings.new(mappings)
|
19
|
+
end
|
20
|
+
|
21
|
+
def remote_mappings
|
22
|
+
@remote_mappings ||= Caoutsearch::Mappings.new(get_remote_mappings)
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def default_mappings
|
28
|
+
path = ::Rails.root.join("config/elasticsearch/#{index_name}.json")
|
29
|
+
raise ArgumentError, "No mappings file found for #{index_name} at #{path}" unless path.exist?
|
30
|
+
|
31
|
+
JSON.parse(path.read)
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_remote_mappings
|
35
|
+
client.indices.get_mapping(index: index_name).values[0]["mappings"]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Config
|
5
|
+
module Settings
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
delegate :mappings, to: :class
|
10
|
+
end
|
11
|
+
|
12
|
+
class_methods do
|
13
|
+
def settings
|
14
|
+
@settings ||= Caoutsearch::Settings.new(default_settings)
|
15
|
+
end
|
16
|
+
|
17
|
+
def settings=(settings)
|
18
|
+
@settings = Caoutsearch::Settings.new(settings)
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def default_settings
|
24
|
+
Caoutsearch.settings.to_hash.dup
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Filter
|
5
|
+
class Base
|
6
|
+
attr_reader :key, :original_value, :type, :options
|
7
|
+
|
8
|
+
def initialize(key, original_value, type, options = {})
|
9
|
+
@key = key
|
10
|
+
@original_value = original_value
|
11
|
+
@type = type
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def value
|
16
|
+
@value = cast_value(original_value) unless defined?(@value)
|
17
|
+
@value
|
18
|
+
end
|
19
|
+
|
20
|
+
def as_json
|
21
|
+
filter = self.filter
|
22
|
+
filter = group_filters(filter) if filter.is_a?(Array)
|
23
|
+
|
24
|
+
if filter.present? && nested_query?
|
25
|
+
filter = {
|
26
|
+
nested: {
|
27
|
+
path: nested_path,
|
28
|
+
query: { bool: { filter: Array.wrap(filter) } }
|
29
|
+
}
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
filter
|
34
|
+
end
|
35
|
+
|
36
|
+
def filter
|
37
|
+
raise NotImplementedError
|
38
|
+
end
|
39
|
+
|
40
|
+
protected
|
41
|
+
|
42
|
+
def default_cast_type
|
43
|
+
type
|
44
|
+
end
|
45
|
+
|
46
|
+
def cast_value(value, type = default_cast_type)
|
47
|
+
Caoutsearch::Search::Value.new(
|
48
|
+
value,
|
49
|
+
type,
|
50
|
+
**options.slice(:null_values, :transform)
|
51
|
+
).value
|
52
|
+
end
|
53
|
+
|
54
|
+
def original_values
|
55
|
+
case original_value
|
56
|
+
when String then original_value.split(",")
|
57
|
+
when Array then original_value
|
58
|
+
else Array.wrap(original_value)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def group_filters(terms)
|
63
|
+
groups = terms.select { |term| term.is_a?(Hash) && (term.key?(:term) || term.key?(:terms)) }
|
64
|
+
groups = groups.group_by { |term| (term[:term] || term[:terms]).keys[0] }
|
65
|
+
|
66
|
+
groups.each do |key, grouped_terms|
|
67
|
+
next if grouped_terms.size < 2
|
68
|
+
|
69
|
+
values = grouped_terms.flat_map { |term| (term[:term] || term[:terms])[key] }
|
70
|
+
values = values.uniq
|
71
|
+
|
72
|
+
grouped_terms.each { |term| terms.delete(term) }
|
73
|
+
|
74
|
+
terms << if values.size == 1
|
75
|
+
{ term: { key => values[0] } }
|
76
|
+
else
|
77
|
+
{ terms: { key => values } }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
terms
|
82
|
+
end
|
83
|
+
|
84
|
+
def nested_query?
|
85
|
+
nested_path? && !include_in_parent?
|
86
|
+
end
|
87
|
+
|
88
|
+
def nested_path?
|
89
|
+
options[:nested] && key.to_s.include?(".")
|
90
|
+
end
|
91
|
+
|
92
|
+
def include_in_parent?
|
93
|
+
options[:include_in_parent]
|
94
|
+
end
|
95
|
+
|
96
|
+
def nested_path
|
97
|
+
options[:nested].is_a?(String) ? options[:nested] : key.to_s.split(".")[0].to_sym
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Filter
|
5
|
+
class Boolean < Base
|
6
|
+
def filter
|
7
|
+
return {} if value.nil?
|
8
|
+
|
9
|
+
{ term: { key => value } }
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def default_cast_type
|
15
|
+
"boolean"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Filter
|
5
|
+
class Date < Base
|
6
|
+
def filter
|
7
|
+
original_values.map do |value|
|
8
|
+
case value
|
9
|
+
when true
|
10
|
+
{ exists: { field: key } }
|
11
|
+
when false
|
12
|
+
{ bool: { must_not: { exists: { field: key } } } }
|
13
|
+
when Hash
|
14
|
+
operator, value, unit = value.stringify_keys.values_at("operator", "value", "unit")
|
15
|
+
|
16
|
+
case operator
|
17
|
+
when "less_than"
|
18
|
+
{ range: { key => { gte: cast_date(value, unit) } } }
|
19
|
+
when "greater_than"
|
20
|
+
{ range: { key => { lt: cast_date(value, unit) } } }
|
21
|
+
when "between"
|
22
|
+
dates = value.map { |v| cast_date(v, unit) }.sort
|
23
|
+
{ range: { key => { gte: dates[0], lt: dates[1] } } }
|
24
|
+
else
|
25
|
+
raise ArgumentError, "unknown operator #{operator.inspect} in #{value.inspect}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def cast_date(value, unit)
|
32
|
+
if value.is_a?(Numeric) && unit
|
33
|
+
case unit
|
34
|
+
when "day" then value = value.days.ago
|
35
|
+
when "week" then value = value.weeks.ago
|
36
|
+
when "month" then value = value.months.ago
|
37
|
+
when "year", nil then value = value.years.ago
|
38
|
+
else
|
39
|
+
raise ArgumentError, "unknown unit #{unit.inspect} in #{value.inspect}"
|
40
|
+
end
|
41
|
+
elsif value.is_a?(ActiveSupport::Duration)
|
42
|
+
value = value.ago
|
43
|
+
end
|
44
|
+
|
45
|
+
cast_value(value, :date)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Filter
|
5
|
+
class Default < Base
|
6
|
+
def filter
|
7
|
+
if value.nil? && %w[text keyword].include?(type)
|
8
|
+
{
|
9
|
+
bool: {
|
10
|
+
should: [
|
11
|
+
{ bool: { must_not: { exists: { field: key } } } },
|
12
|
+
{ term: { key => "" } }
|
13
|
+
]
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
elsif value.nil?
|
18
|
+
{ bool: { must_not: { exists: { field: key } } } }
|
19
|
+
|
20
|
+
elsif value.is_a?(Array) && value.any?(&:nil?)
|
21
|
+
terms = []
|
22
|
+
terms << { bool: { must_not: { exists: { field: key } } } }
|
23
|
+
|
24
|
+
terms_values = value.compact
|
25
|
+
terms_values += [""] if %w[text keyword].include?(type)
|
26
|
+
|
27
|
+
if terms_values.size == 1
|
28
|
+
terms << { term: { key => terms_values[0] } }
|
29
|
+
elsif terms_values.size > 1
|
30
|
+
terms << { terms: { key => terms_values } }
|
31
|
+
end
|
32
|
+
|
33
|
+
if terms.size == 1
|
34
|
+
terms[0]
|
35
|
+
else
|
36
|
+
{ bool: { should: terms } }
|
37
|
+
end
|
38
|
+
|
39
|
+
elsif value.is_a?(Array) && value.size == 1
|
40
|
+
{ term: { key => value[0] } }
|
41
|
+
|
42
|
+
elsif value.is_a?(Array)
|
43
|
+
{ terms: { key => value } }
|
44
|
+
|
45
|
+
else
|
46
|
+
{ term: { key => value } }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Filter
|
5
|
+
class Match < Base
|
6
|
+
def filter
|
7
|
+
if use_query_string?
|
8
|
+
{
|
9
|
+
query_string: {
|
10
|
+
query: sanitized_for_query_string,
|
11
|
+
default_field: key,
|
12
|
+
default_operator: "and",
|
13
|
+
analyze_wildcard: true
|
14
|
+
}
|
15
|
+
}
|
16
|
+
elsif multiple_words?
|
17
|
+
{ match: { key => { query: value, operator: "and" } } }
|
18
|
+
else
|
19
|
+
{ match: { key => value } }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def nested_query?
|
24
|
+
nested_path? && (multiple_words? || !include_in_parent?)
|
25
|
+
end
|
26
|
+
|
27
|
+
def multiple_words?
|
28
|
+
value.is_a?(String) && value.squish.include?(" ")
|
29
|
+
end
|
30
|
+
|
31
|
+
# https://rubular.com/r/KEA7poAaIeNrZe
|
32
|
+
QUERY_STRING_REGEXP = %r{
|
33
|
+
(?:[*?][^\s*?]|[^\s*?][*?]|(?:^|\s)(?:AND|OR|NOT)(?:$|\s)|^\*$)
|
34
|
+
}x
|
35
|
+
|
36
|
+
# https://rubular.com/r/tVMSviF0a74e1s
|
37
|
+
STRIPPED_OPERATOR_REGEXP = %r{
|
38
|
+
(?:^\s*(?:AND|OR)\*$|^\s*(?:AND|OR)\s+|\s+(?:AND|OR)\s*$)
|
39
|
+
}x
|
40
|
+
|
41
|
+
def use_query_string?
|
42
|
+
QUERY_STRING_REGEXP.match?(value)
|
43
|
+
end
|
44
|
+
|
45
|
+
def sanitized_for_query_string
|
46
|
+
# Do not allow setting fields in query string
|
47
|
+
clean_value = Caoutsearch::Search::Sanitizer.sanitize(value, ":")
|
48
|
+
|
49
|
+
# Delete leading and trailing operators
|
50
|
+
# Example : " OR ANGE" => "ANGE"
|
51
|
+
# Example : "MASSE OR " => "MASSE"
|
52
|
+
|
53
|
+
clean_value.gsub(STRIPPED_OPERATOR_REGEXP, "")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Filter
|
5
|
+
class Range < Base
|
6
|
+
def filter
|
7
|
+
original_values.map do |value|
|
8
|
+
case value
|
9
|
+
when />(.+)/ then { range: { key => { gt: cast_value_with_overflow($1, :lower) } } }
|
10
|
+
when /<(.+)/ then { range: { key => { lt: cast_value_with_overflow($1, :upper) } } }
|
11
|
+
when /≥(.+)/ then { range: { key => { gte: cast_value_with_overflow($1, :lower) } } }
|
12
|
+
when /≤(.+)/ then { range: { key => { lte: cast_value_with_overflow($1, :upper) } } }
|
13
|
+
when /(.+)-(.+)/ then { range: { key => { gte: cast_value_with_overflow($1, :lower), lte: cast_value_with_overflow($2, :upper) } } }
|
14
|
+
else { term: { key => cast_value(value) } }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def cast_value_with_overflow(value, type)
|
20
|
+
cast_value(value)
|
21
|
+
rescue Caoutsearch::Search::ValueOverflow => e
|
22
|
+
raise(e) unless type == e.type
|
23
|
+
|
24
|
+
e.limit
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Filter
|
5
|
+
class << self
|
6
|
+
def filters
|
7
|
+
@filters ||= {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def [](key)
|
11
|
+
@filters[key.to_s]
|
12
|
+
end
|
13
|
+
|
14
|
+
def register(filter_class, as: nil)
|
15
|
+
as ||= filter_class.name.demodulize.underscore
|
16
|
+
|
17
|
+
@filters ||= {}
|
18
|
+
@filters[as] = filter_class
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Caoutsearch::Filter.register(Caoutsearch::Filter::Boolean)
|
25
|
+
Caoutsearch::Filter.register(Caoutsearch::Filter::Date)
|
26
|
+
Caoutsearch::Filter.register(Caoutsearch::Filter::Default)
|
27
|
+
Caoutsearch::Filter.register(Caoutsearch::Filter::GeoPoint)
|
28
|
+
Caoutsearch::Filter.register(Caoutsearch::Filter::Match)
|
29
|
+
Caoutsearch::Filter.register(Caoutsearch::Filter::Range)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Index
|
5
|
+
class Base
|
6
|
+
include Caoutsearch::Config::Client
|
7
|
+
include Caoutsearch::Config::Mappings
|
8
|
+
include Caoutsearch::Config::Settings
|
9
|
+
|
10
|
+
include Caoutsearch::Index::Document
|
11
|
+
include Caoutsearch::Index::Indice
|
12
|
+
include Caoutsearch::Index::IndiceVersions
|
13
|
+
include Caoutsearch::Index::Instrumentation
|
14
|
+
include Caoutsearch::Index::InternalDSL
|
15
|
+
include Caoutsearch::Index::Naming
|
16
|
+
include Caoutsearch::Index::Reindex
|
17
|
+
include Caoutsearch::Index::Scoping
|
18
|
+
include Caoutsearch::Index::Serialization
|
19
|
+
|
20
|
+
attr_reader :record
|
21
|
+
|
22
|
+
delegate_missing_to :record
|
23
|
+
|
24
|
+
def initialize(record)
|
25
|
+
@record = record
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def wrap(*records)
|
30
|
+
Array.wrap(*records).map { |record| new(record) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Caoutsearch
|
4
|
+
module Index
|
5
|
+
module Document
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
# Return the indexed document
|
9
|
+
#
|
10
|
+
# record = Article.find(1)
|
11
|
+
# ArticleIndex.new(record).indexed_document
|
12
|
+
#
|
13
|
+
def indexed_document
|
14
|
+
request_payload = {
|
15
|
+
index: index_name,
|
16
|
+
id: record.id
|
17
|
+
}
|
18
|
+
|
19
|
+
response = instrument(:get) do |event_payload|
|
20
|
+
event_payload[:request] = request_payload
|
21
|
+
event_payload[:response] = client.get(request_payload)
|
22
|
+
end
|
23
|
+
|
24
|
+
response.body
|
25
|
+
end
|
26
|
+
|
27
|
+
# Overwrite or partially update a document
|
28
|
+
#
|
29
|
+
# record = Article.find(1)
|
30
|
+
# ArticleIndex.new(record).update_document
|
31
|
+
# ArticleIndex.new(record).update_document(:title, :content)
|
32
|
+
#
|
33
|
+
def update_document(*keys, index: index_name, refresh: false)
|
34
|
+
request_payload = {
|
35
|
+
index: index,
|
36
|
+
id: id
|
37
|
+
}
|
38
|
+
|
39
|
+
if keys.empty?
|
40
|
+
request_payload[:body] = as_json
|
41
|
+
|
42
|
+
instrument(:index) do |event_payload|
|
43
|
+
event_payload[:request] = request_payload
|
44
|
+
event_payload[:response] = client.index(request_payload)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
request_payload[:body] = bulkify(:update, keys)
|
48
|
+
|
49
|
+
instrument(:bulk, method: :update) do |event_payload|
|
50
|
+
event_payload[:request] = request_payload
|
51
|
+
event_payload[:response] = client.bulk(request_payload)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
refresh_indice(index: index) if refresh
|
56
|
+
end
|
57
|
+
|
58
|
+
# Delete the document
|
59
|
+
#
|
60
|
+
# record = Article.find(1)
|
61
|
+
# ArticleIndex.new(record).delete_document
|
62
|
+
#
|
63
|
+
def delete_document(index: index_name, refresh: false)
|
64
|
+
self.class.delete_document(record.id, index: index, refresh: refresh)
|
65
|
+
end
|
66
|
+
|
67
|
+
class_methods do
|
68
|
+
# Delete one document
|
69
|
+
#
|
70
|
+
# ArticleIndex.delete_document(1)
|
71
|
+
#
|
72
|
+
def delete_document(id, index: index_name, refresh: false)
|
73
|
+
request_payload = {
|
74
|
+
index: index,
|
75
|
+
id: id,
|
76
|
+
ignore: 404
|
77
|
+
}
|
78
|
+
|
79
|
+
instrument(:delete) do |event_payload|
|
80
|
+
event_payload[:request] = request_payload
|
81
|
+
event_payload[:response] = client.delete(request_payload)
|
82
|
+
end
|
83
|
+
|
84
|
+
refresh_indice(index: index) if refresh
|
85
|
+
end
|
86
|
+
|
87
|
+
# Delete many documents, using bulk API
|
88
|
+
#
|
89
|
+
# ArticleIndex.delete_documents([1, 2, 3])
|
90
|
+
#
|
91
|
+
def delete_documents(ids, index: index_name, refresh: false)
|
92
|
+
request_payload = {
|
93
|
+
index: index,
|
94
|
+
body: ids.map { |id| { delete: { _id: id } } }
|
95
|
+
}
|
96
|
+
|
97
|
+
instrument(:bulk, method: :delete) do |event_payload|
|
98
|
+
event_payload[:request] = request_payload
|
99
|
+
event_payload[:response] = client.bulk(request_payload)
|
100
|
+
end
|
101
|
+
|
102
|
+
refresh_indice(index: index) if refresh
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|