elastictastic 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +19 -0
- data/README.md +326 -0
- data/lib/elastictastic/association.rb +21 -0
- data/lib/elastictastic/bulk_persistence_strategy.rb +70 -0
- data/lib/elastictastic/callbacks.rb +30 -0
- data/lib/elastictastic/child_collection_proxy.rb +56 -0
- data/lib/elastictastic/client.rb +101 -0
- data/lib/elastictastic/configuration.rb +35 -0
- data/lib/elastictastic/dirty.rb +130 -0
- data/lib/elastictastic/discrete_persistence_strategy.rb +52 -0
- data/lib/elastictastic/document.rb +98 -0
- data/lib/elastictastic/errors.rb +7 -0
- data/lib/elastictastic/field.rb +38 -0
- data/lib/elastictastic/index.rb +19 -0
- data/lib/elastictastic/mass_assignment_security.rb +15 -0
- data/lib/elastictastic/middleware.rb +119 -0
- data/lib/elastictastic/nested_document.rb +29 -0
- data/lib/elastictastic/new_relic_instrumentation.rb +26 -0
- data/lib/elastictastic/observer.rb +3 -0
- data/lib/elastictastic/observing.rb +21 -0
- data/lib/elastictastic/parent_child.rb +115 -0
- data/lib/elastictastic/persistence.rb +67 -0
- data/lib/elastictastic/properties.rb +236 -0
- data/lib/elastictastic/railtie.rb +35 -0
- data/lib/elastictastic/resource.rb +4 -0
- data/lib/elastictastic/scope.rb +283 -0
- data/lib/elastictastic/scope_builder.rb +32 -0
- data/lib/elastictastic/scoped.rb +20 -0
- data/lib/elastictastic/search.rb +180 -0
- data/lib/elastictastic/server_error.rb +15 -0
- data/lib/elastictastic/test_helpers.rb +172 -0
- data/lib/elastictastic/util.rb +63 -0
- data/lib/elastictastic/validations.rb +45 -0
- data/lib/elastictastic/version.rb +3 -0
- data/lib/elastictastic.rb +82 -0
- data/spec/environment.rb +6 -0
- data/spec/examples/active_model_lint_spec.rb +20 -0
- data/spec/examples/bulk_persistence_strategy_spec.rb +233 -0
- data/spec/examples/callbacks_spec.rb +96 -0
- data/spec/examples/dirty_spec.rb +238 -0
- data/spec/examples/document_spec.rb +600 -0
- data/spec/examples/mass_assignment_security_spec.rb +13 -0
- data/spec/examples/middleware_spec.rb +92 -0
- data/spec/examples/observing_spec.rb +141 -0
- data/spec/examples/parent_child_spec.rb +308 -0
- data/spec/examples/properties_spec.rb +92 -0
- data/spec/examples/scope_spec.rb +491 -0
- data/spec/examples/search_spec.rb +382 -0
- data/spec/examples/spec_helper.rb +15 -0
- data/spec/examples/validation_spec.rb +65 -0
- data/spec/models/author.rb +9 -0
- data/spec/models/blog.rb +5 -0
- data/spec/models/comment.rb +5 -0
- data/spec/models/post.rb +41 -0
- data/spec/models/post_observer.rb +11 -0
- data/spec/support/fakeweb_request_history.rb +13 -0
- metadata +227 -0
@@ -0,0 +1,180 @@
|
|
1
|
+
module Elastictastic
|
2
|
+
class Search
|
3
|
+
KEYS = %w(query filter from size sort highlight fields script_fields
|
4
|
+
preference facets)
|
5
|
+
|
6
|
+
attr_reader :sort, :from, :size, :fields, :script_fields, :preference, :facets
|
7
|
+
delegate :[], :to => :params
|
8
|
+
|
9
|
+
def initialize(params = {})
|
10
|
+
params = Util.deep_stringify(params) # this creates a copy
|
11
|
+
@queries, @query_filters = extract_queries_and_query_filters(params['query'])
|
12
|
+
@filters = extract_filters(params['filter'])
|
13
|
+
@from = params.delete('from')
|
14
|
+
@size = params.delete('size')
|
15
|
+
@sort = Util.ensure_array(params.delete('sort'))
|
16
|
+
highlight = params.delete('highlight')
|
17
|
+
if highlight
|
18
|
+
@highlight_fields = highlight.delete('fields')
|
19
|
+
@highlight_settings = highlight
|
20
|
+
end
|
21
|
+
@fields = Util.ensure_array(params.delete('fields'))
|
22
|
+
@script_fields = params.delete('script_fields')
|
23
|
+
@preference = params.delete('preference')
|
24
|
+
@facets = params.delete('facets')
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize_copy(other)
|
28
|
+
@queries = deep_copy(other.queries)
|
29
|
+
@query_filters = deep_copy(other.query_filters)
|
30
|
+
@filters = deep_copy(other.filters)
|
31
|
+
@sort = deep_copy(other.sort)
|
32
|
+
@highlight = deep_copy(other.highlight)
|
33
|
+
@fields = other.fields.dup if other.fields
|
34
|
+
@script_fields = deep_copy(other.script_fields)
|
35
|
+
@facets = deep_copy(other.facets)
|
36
|
+
end
|
37
|
+
|
38
|
+
def params
|
39
|
+
{}.tap do |params|
|
40
|
+
params['query'] = query
|
41
|
+
params['filter'] = filter
|
42
|
+
params['from'] = from
|
43
|
+
params['size'] = size
|
44
|
+
params['sort'] = maybe_array(sort)
|
45
|
+
params['highlight'] = highlight
|
46
|
+
params['fields'] = maybe_array(fields)
|
47
|
+
params['script_fields'] = script_fields
|
48
|
+
params['preference'] = preference
|
49
|
+
params['facets'] = facets
|
50
|
+
params.reject! { |k, v| v.blank? }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def query
|
55
|
+
query_query = maybe_array(queries) do
|
56
|
+
{ 'bool' => { 'must' => queries }}
|
57
|
+
end
|
58
|
+
query_filter = maybe_array(query_filters) do
|
59
|
+
{ 'and' => query_filters }
|
60
|
+
end
|
61
|
+
if query_query
|
62
|
+
if query_filter
|
63
|
+
{ 'filtered' => { 'query' => query_query, 'filter' => query_filter }}
|
64
|
+
else
|
65
|
+
query_query
|
66
|
+
end
|
67
|
+
elsif query_filter
|
68
|
+
{ 'constant_score' => { 'filter' => query_filter }}
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def filter
|
73
|
+
maybe_array(filters) do
|
74
|
+
{ 'and' => filters }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def highlight
|
79
|
+
if @highlight_fields
|
80
|
+
@highlight_settings.merge('fields' => @highlight_fields)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def merge(other)
|
85
|
+
dup.merge!(other)
|
86
|
+
end
|
87
|
+
|
88
|
+
def merge!(other)
|
89
|
+
@queries = combine(@queries, other.queries)
|
90
|
+
@query_filters = combine(@query_filters, other.query_filters)
|
91
|
+
@filters = combine(@filters, other.filters)
|
92
|
+
@from = other.from || @from
|
93
|
+
@size = other.size || @size
|
94
|
+
@sort = combine(@sort, other.sort)
|
95
|
+
if @highlight_fields && other.highlight_fields
|
96
|
+
@highlight_fields = combine(highlight_fields_with_settings, other.highlight_fields_with_settings)
|
97
|
+
@highlight_settings = {}
|
98
|
+
else
|
99
|
+
@highlight_settings = combine(@highlight_settings, other.highlight_settings)
|
100
|
+
@highlight_fields = combine(@highlight_fields, other.highlight_fields)
|
101
|
+
end
|
102
|
+
@fields = combine(@fields, other.fields)
|
103
|
+
@script_fields = combine(@script_fields, other.script_fields)
|
104
|
+
@preference = other.preference || @preference
|
105
|
+
@facets = combine(@facets, other.facets)
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
109
|
+
protected
|
110
|
+
attr_reader :queries, :query_filters, :filters, :highlight_fields,
|
111
|
+
:highlight_settings
|
112
|
+
|
113
|
+
def highlight_fields_with_settings
|
114
|
+
if @highlight_fields
|
115
|
+
{}.tap do |fields_with_settings|
|
116
|
+
@highlight_fields.each_pair do |field, settings|
|
117
|
+
fields_with_settings[field] = @highlight_settings.merge(settings)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
def maybe_array(array)
|
126
|
+
case array.length
|
127
|
+
when 0 then nil
|
128
|
+
when 1 then array.first
|
129
|
+
else
|
130
|
+
if block_given? then yield
|
131
|
+
else array
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def combine(object1, object2)
|
137
|
+
if object1.nil? then object2
|
138
|
+
elsif object2.nil? then object1
|
139
|
+
else
|
140
|
+
case object1
|
141
|
+
when Array then object1 + object2
|
142
|
+
when Hash then object1.merge(object2)
|
143
|
+
else raise ArgumentError, "Don't know how to combine #{object1.inspect} with #{object2.inspect}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def extract_queries_and_query_filters(params)
|
149
|
+
if params.nil? then [[], []]
|
150
|
+
elsif params.keys == %w(filtered)
|
151
|
+
[extract_queries(params['filtered']['query']), extract_filters(params['filtered']['filter'])]
|
152
|
+
elsif params.keys == %w(constant_score) && params['constant_score'].keys == %w(filter)
|
153
|
+
[[], extract_filters(params['constant_score']['filter'])]
|
154
|
+
else
|
155
|
+
[extract_queries(params), []]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def extract_queries(params)
|
160
|
+
if params.nil? then []
|
161
|
+
elsif params.keys == %w(bool) && params['bool'].keys == %w(must)
|
162
|
+
params['bool']['must']
|
163
|
+
else [params]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def extract_filters(params)
|
168
|
+
if params.nil? then []
|
169
|
+
elsif params.keys == %w(and)
|
170
|
+
params['and']
|
171
|
+
else
|
172
|
+
[params]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def deep_copy(object)
|
177
|
+
Marshal.load(Marshal.dump(object)) unless object.nil?
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Elastictastic
|
2
|
+
module ServerError
|
3
|
+
class ServerError < StandardError
|
4
|
+
attr_accessor :status
|
5
|
+
end
|
6
|
+
|
7
|
+
class <<self
|
8
|
+
def const_missing(name)
|
9
|
+
Class.new(::Elastictastic::ServerError::ServerError).tap do |error|
|
10
|
+
const_set(name, error)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'fakeweb'
|
2
|
+
|
3
|
+
module Elastictastic
|
4
|
+
module TestHelpers
|
5
|
+
ALPHANUM = ('0'..'9').to_a + ('A'..'Z').to_a + ('a'..'z').to_a
|
6
|
+
|
7
|
+
def stub_elasticsearch_create(index, type, *args)
|
8
|
+
options = args.extract_options!
|
9
|
+
id = args.pop
|
10
|
+
if id.nil?
|
11
|
+
id = ''
|
12
|
+
22.times { id << ALPHANUM[rand(ALPHANUM.length)] }
|
13
|
+
path = "/#{index}/#{type}"
|
14
|
+
method = :post
|
15
|
+
else
|
16
|
+
path = "/#{index}/#{type}/#{id}/_create"
|
17
|
+
method = :put
|
18
|
+
end
|
19
|
+
|
20
|
+
FakeWeb.register_uri(
|
21
|
+
method,
|
22
|
+
/^#{Regexp.escape(TestHelpers.uri_for_path(path))}(\?.*)?$/,
|
23
|
+
options.reverse_merge(:body => {
|
24
|
+
'ok' => 'true',
|
25
|
+
'_index' => index,
|
26
|
+
'_type' => type,
|
27
|
+
'_id' => id
|
28
|
+
}.to_json)
|
29
|
+
)
|
30
|
+
id
|
31
|
+
end
|
32
|
+
|
33
|
+
def stub_elasticsearch_update(index, type, id)
|
34
|
+
FakeWeb.register_uri(
|
35
|
+
:put,
|
36
|
+
/^#{TestHelpers.uri_for_path("/#{index}/#{type}/#{id}")}(\?.*)?$/,
|
37
|
+
:body => {
|
38
|
+
'ok' => 'true',
|
39
|
+
'_index' => index,
|
40
|
+
'_type' => type,
|
41
|
+
'_id' => id
|
42
|
+
}.to_json
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
def stub_elasticsearch_get(index, type, id, doc = {})
|
47
|
+
FakeWeb.register_uri(
|
48
|
+
:get,
|
49
|
+
/^#{Regexp.escape(TestHelpers.uri_for_path("/#{index}/#{type}/#{id}").to_s)}(\?.*)?$/,
|
50
|
+
:body => {
|
51
|
+
'ok' => true,
|
52
|
+
'_index' => index,
|
53
|
+
'_type' => type,
|
54
|
+
'_id' => id,
|
55
|
+
'_source' => doc,
|
56
|
+
'exists' => !doc.nil?
|
57
|
+
}.to_json
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
def stub_elasticsearch_mget(index, type, *ids)
|
62
|
+
given_ids_with_docs = ids.extract_options!
|
63
|
+
ids_with_docs = {}
|
64
|
+
ids.each { |id| ids_with_docs[id] = {} }
|
65
|
+
ids_with_docs.merge!(given_ids_with_docs)
|
66
|
+
path = index ? "/#{index}/#{type}/_mget" : "/_mget"
|
67
|
+
docs = ids_with_docs.each_pair.map do |id, doc|
|
68
|
+
id, index = *id if Array === id
|
69
|
+
{
|
70
|
+
'_index' => index,
|
71
|
+
'_type' => type,
|
72
|
+
'_id' => id,
|
73
|
+
'exists' => !!doc,
|
74
|
+
'_source' => doc
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
FakeWeb.register_uri(
|
79
|
+
:post,
|
80
|
+
TestHelpers.uri_for_path(path).to_s,
|
81
|
+
:body => {
|
82
|
+
'docs' => docs
|
83
|
+
}.to_json
|
84
|
+
)
|
85
|
+
end
|
86
|
+
|
87
|
+
def stub_elasticsearch_destroy(index, type, id, options = {})
|
88
|
+
FakeWeb.register_uri(
|
89
|
+
:delete,
|
90
|
+
/^#{TestHelpers.uri_for_path("/#{index}/#{type}/#{id}")}(\?.*)?$/,
|
91
|
+
options.reverse_merge(:body => {
|
92
|
+
'ok' => true,
|
93
|
+
'found' => true,
|
94
|
+
'_index' => 'test',
|
95
|
+
'_type' => 'test',
|
96
|
+
'_id' => id,
|
97
|
+
'_version' => 1
|
98
|
+
}.to_json)
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
def stub_elasticsearch_destroy_all(index, type)
|
103
|
+
FakeWeb.register_uri(
|
104
|
+
:delete,
|
105
|
+
TestHelpers.uri_for_path("/#{index}/#{type}"),
|
106
|
+
:body => { 'ok' => true }.to_json
|
107
|
+
)
|
108
|
+
end
|
109
|
+
|
110
|
+
def stub_elasticsearch_bulk(*responses)
|
111
|
+
FakeWeb.register_uri(
|
112
|
+
:post,
|
113
|
+
TestHelpers.uri_for_path("/_bulk"),
|
114
|
+
:body => { 'took' => 1, 'items' => responses }.to_json
|
115
|
+
)
|
116
|
+
end
|
117
|
+
|
118
|
+
def stub_elasticsearch_put_mapping(index, type)
|
119
|
+
FakeWeb.register_uri(
|
120
|
+
:put,
|
121
|
+
TestHelpers.uri_for_path("/#{index}/#{type}/_mapping"),
|
122
|
+
:body => { 'ok' => true, 'acknowledged' => true }.to_json
|
123
|
+
)
|
124
|
+
end
|
125
|
+
|
126
|
+
def stub_elasticsearch_search(index, type, data)
|
127
|
+
if Array === data
|
128
|
+
response = data.map do |datum|
|
129
|
+
{ :body => datum.to_json }
|
130
|
+
end
|
131
|
+
else
|
132
|
+
response = { :body => data.to_json }
|
133
|
+
end
|
134
|
+
|
135
|
+
uri = TestHelpers.uri_for_path("/#{index}/#{type}/_search").to_s
|
136
|
+
FakeWeb.register_uri(
|
137
|
+
:post,
|
138
|
+
/^#{Regexp.escape(uri)}/,
|
139
|
+
response
|
140
|
+
)
|
141
|
+
end
|
142
|
+
|
143
|
+
def stub_elasticsearch_scan(index, type, batch_size, *hits)
|
144
|
+
scan_uri = Regexp.escape(TestHelpers.uri_for_path("/#{index}/#{type}/_search").to_s)
|
145
|
+
scroll_ids = Array.new(batch_size + 1) { rand(10**100).to_s(36) }
|
146
|
+
FakeWeb.register_uri(
|
147
|
+
:post,
|
148
|
+
/^#{scan_uri}\?.*search_type=scan/,
|
149
|
+
:body => {
|
150
|
+
'_scroll_id' => scroll_ids.first,
|
151
|
+
'hits' => { 'total' => hits.length, 'hits' => [] }
|
152
|
+
}.to_json
|
153
|
+
)
|
154
|
+
|
155
|
+
batches = hits.each_slice(batch_size).each_with_index.map do |hit_batch, i|
|
156
|
+
{ :body => { '_scroll_id' => scroll_ids[i+1], 'hits' => { 'hits' => hit_batch }}.to_json }
|
157
|
+
end
|
158
|
+
batches << { :body => { 'hits' => { 'hits' => [] }}.to_json }
|
159
|
+
scroll_uri = Regexp.escape(TestHelpers.uri_for_path("/_search/scroll").to_s)
|
160
|
+
FakeWeb.register_uri(
|
161
|
+
:post,
|
162
|
+
/^#{scroll_uri}/,
|
163
|
+
batches
|
164
|
+
)
|
165
|
+
scroll_ids
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.uri_for_path(path)
|
169
|
+
"#{Elastictastic.config.hosts.first}#{path}"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Elastictastic
|
2
|
+
module Util
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def deep_stringify(hash)
|
6
|
+
{}.tap do |stringified|
|
7
|
+
hash.each_pair do |key, value|
|
8
|
+
stringified[key.to_s] = Hash === value ? deep_stringify(value) : value
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def deep_merge(l, r)
|
14
|
+
if l.nil? then r
|
15
|
+
elsif r.nil? then l
|
16
|
+
elsif Hash === l && Hash === r
|
17
|
+
{}.tap do |merged|
|
18
|
+
(l.keys | r.keys).each do |key|
|
19
|
+
merged[key] = deep_merge(l[key], r[key])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
elsif Array === l && Array === r then l + r
|
23
|
+
elsif Array === l then l + [r]
|
24
|
+
elsif Array === r then [l] + r
|
25
|
+
else [l, r]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def ensure_array(object)
|
30
|
+
case object
|
31
|
+
when nil then []
|
32
|
+
when Array then object
|
33
|
+
else [object]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def call_or_each(object, &block)
|
38
|
+
if Array === object then object.each(&block)
|
39
|
+
else
|
40
|
+
block.call(object)
|
41
|
+
object
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def call_or_map(object, &block)
|
46
|
+
if Array === object then object.map(&block)
|
47
|
+
else block.call(object)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def unflatten_hash(hash)
|
52
|
+
{}.tap do |unflattened|
|
53
|
+
hash.each_pair do |key, value|
|
54
|
+
namespace = key.split('.')
|
55
|
+
field_name = namespace.pop
|
56
|
+
namespace.inject(unflattened) do |current, component|
|
57
|
+
current[component] ||= {}
|
58
|
+
end[field_name] = value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Elastictastic
|
2
|
+
module Validations
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
include ActiveModel::Validations
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def embed(*embed_names)
|
11
|
+
super
|
12
|
+
embed_names.extract_options!
|
13
|
+
args = embed_names + [{ :nested => true }]
|
14
|
+
validates(*args)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module InstanceMethods
|
19
|
+
def save
|
20
|
+
if valid?
|
21
|
+
super
|
22
|
+
true
|
23
|
+
else
|
24
|
+
false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def save!
|
29
|
+
if !save
|
30
|
+
raise Elastictastic::RecordInvalid, errors.full_messages.to_sentence
|
31
|
+
end
|
32
|
+
self
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class NestedValidator < ActiveModel::EachValidator
|
37
|
+
def validate_each(record, attribute, value)
|
38
|
+
value = [value].compact unless Array === value
|
39
|
+
unless value.all? { |el| el.valid? }
|
40
|
+
record.errors[:attribute] = :invalid
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
require 'active_model'
|
3
|
+
require 'elastictastic/errors'
|
4
|
+
|
5
|
+
module Elastictastic
|
6
|
+
autoload :Association, 'elastictastic/association'
|
7
|
+
autoload :BulkPersistenceStrategy, 'elastictastic/bulk_persistence_strategy'
|
8
|
+
autoload :Callbacks, 'elastictastic/callbacks'
|
9
|
+
autoload :ChildCollectionProxy, 'elastictastic/child_collection_proxy'
|
10
|
+
autoload :Client, 'elastictastic/client'
|
11
|
+
autoload :Configuration, 'elastictastic/configuration'
|
12
|
+
autoload :Dirty, 'elastictastic/dirty'
|
13
|
+
autoload :DiscretePersistenceStrategy, 'elastictastic/discrete_persistence_strategy'
|
14
|
+
autoload :Document, 'elastictastic/document'
|
15
|
+
autoload :Field, 'elastictastic/field'
|
16
|
+
autoload :Index, 'elastictastic/index'
|
17
|
+
autoload :MassAssignmentSecurity, 'elastictastic/mass_assignment_security'
|
18
|
+
autoload :Middleware, 'elastictastic/middleware'
|
19
|
+
autoload :NestedCollectionProxy, 'elastictastic/nested_collection_proxy'
|
20
|
+
autoload :NestedDocument, 'elastictastic/nested_document'
|
21
|
+
autoload :Observer, 'elastictastic/observer'
|
22
|
+
autoload :Observing, 'elastictastic/observing'
|
23
|
+
autoload :ParentChild, 'elastictastic/parent_child'
|
24
|
+
autoload :Persistence, 'elastictastic/persistence'
|
25
|
+
autoload :Properties, 'elastictastic/properties'
|
26
|
+
autoload :Resource, 'elastictastic/resource'
|
27
|
+
autoload :Scope, 'elastictastic/scope'
|
28
|
+
autoload :ScopeBuilder, 'elastictastic/scope_builder'
|
29
|
+
autoload :Scoped, 'elastictastic/scoped'
|
30
|
+
autoload :Search, 'elastictastic/search'
|
31
|
+
autoload :ServerError, 'elastictastic/server_error'
|
32
|
+
autoload :TestHelpers, 'elastictastic/test_helpers'
|
33
|
+
autoload :Util, 'elastictastic/util'
|
34
|
+
autoload :Validations, 'elastictastic/validations'
|
35
|
+
|
36
|
+
class <<self
|
37
|
+
attr_writer :config
|
38
|
+
|
39
|
+
def config
|
40
|
+
@config ||= Configuration.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def client
|
44
|
+
Thread.current['Elastictastic::client'] ||= Client.new(config)
|
45
|
+
end
|
46
|
+
|
47
|
+
def persister=(persister)
|
48
|
+
Thread.current['Elastictastic::persister'] = persister
|
49
|
+
end
|
50
|
+
|
51
|
+
def persister
|
52
|
+
Thread.current['Elastictastic::persister'] ||=
|
53
|
+
Elastictastic::DiscretePersistenceStrategy.instance
|
54
|
+
end
|
55
|
+
|
56
|
+
def bulk
|
57
|
+
original_persister = self.persister
|
58
|
+
begin
|
59
|
+
self.persister = Elastictastic::BulkPersistenceStrategy.new
|
60
|
+
yield
|
61
|
+
self.persister.flush
|
62
|
+
rescue Elastictastic::CancelBulkOperation
|
63
|
+
# Nothing to see here...
|
64
|
+
ensure
|
65
|
+
self.persister = original_persister
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def Index(name_or_index)
|
70
|
+
Index === name_or_index ? name_or_index : Index.new(name_or_index)
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def new_transport
|
76
|
+
transport_class = const_get("#{config.transport.camelize}Transport")
|
77
|
+
transport_class.new(config)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
require 'elastictastic/railtie' if defined? Rails
|
data/spec/environment.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe 'ActiveModel compliance' do
|
4
|
+
include ActiveModel::Lint::Tests
|
5
|
+
|
6
|
+
ActiveModel::Lint::Tests.public_instance_methods.each do |method|
|
7
|
+
method = method.to_s
|
8
|
+
if method =~ /^test_/
|
9
|
+
example method.gsub('_', ' ') do
|
10
|
+
__send__(method)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def model
|
18
|
+
Post.new
|
19
|
+
end
|
20
|
+
end
|