340 lines
9.6 KiB
Ruby
340 lines
9.6 KiB
Ruby
require 'spec_helper'
|
|
|
|
describe Elasticsearch::Model::Adapter::ActiveRecord do
|
|
|
|
before(:all) do
|
|
ActiveRecord::Schema.define(:version => 1) do
|
|
create_table :articles do |t|
|
|
t.string :title
|
|
t.string :body
|
|
t.integer :clicks, :default => 0
|
|
t.datetime :created_at, :default => 'NOW()'
|
|
end
|
|
end
|
|
|
|
Article.delete_all
|
|
Article.__elasticsearch__.create_index!(force: true)
|
|
|
|
Article.create!(title: 'Test', body: '', clicks: 1)
|
|
Article.create!(title: 'Testing Coding', body: '', clicks: 2)
|
|
Article.create!(title: 'Coding', body: '', clicks: 3)
|
|
|
|
Article.__elasticsearch__.refresh_index!
|
|
end
|
|
|
|
describe 'indexing a document' do
|
|
|
|
let(:search_result) do
|
|
Article.search('title:test')
|
|
end
|
|
|
|
it 'allows searching for documents' do
|
|
expect(search_result.results.size).to be(2)
|
|
expect(search_result.records.size).to be(2)
|
|
end
|
|
end
|
|
|
|
describe '#results' do
|
|
|
|
let(:search_result) do
|
|
Article.search('title:test')
|
|
end
|
|
|
|
it 'returns an instance of Response::Result' do
|
|
expect(search_result.results.first).to be_a(Elasticsearch::Model::Response::Result)
|
|
end
|
|
|
|
it 'prooperly loads the document' do
|
|
expect(search_result.results.first.title).to eq('Test')
|
|
end
|
|
|
|
context 'when the result contains other data' do
|
|
|
|
let(:search_result) do
|
|
Article.search(query: { match: { title: 'test' } }, highlight: { fields: { title: {} } })
|
|
end
|
|
|
|
it 'allows access to the Elasticsearch result' do
|
|
expect(search_result.results.first.title).to eq('Test')
|
|
expect(search_result.results.first.title?).to be(true)
|
|
expect(search_result.results.first.boo?).to be(false)
|
|
expect(search_result.results.first.highlight?).to be(true)
|
|
expect(search_result.results.first.highlight.title?).to be(true)
|
|
expect(search_result.results.first.highlight.boo?).to be(false)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#records' do
|
|
|
|
let(:search_result) do
|
|
Article.search('title:test')
|
|
end
|
|
|
|
it 'returns an instance of the model' do
|
|
expect(search_result.records.first).to be_a(Article)
|
|
end
|
|
|
|
it 'prooperly loads the document' do
|
|
expect(search_result.records.first.title).to eq('Test')
|
|
end
|
|
end
|
|
|
|
describe 'Enumerable' do
|
|
|
|
let(:search_result) do
|
|
Article.search('title:test')
|
|
end
|
|
|
|
it 'allows iteration over results' do
|
|
expect(search_result.results.map(&:_id)).to eq(['1', '2'])
|
|
end
|
|
|
|
it 'allows iteration over records' do
|
|
expect(search_result.records.map(&:id)).to eq([1, 2])
|
|
end
|
|
end
|
|
|
|
describe '#id' do
|
|
|
|
let(:search_result) do
|
|
Article.search('title:test')
|
|
end
|
|
|
|
it 'returns the id' do
|
|
expect(search_result.results.first.id).to eq('1')
|
|
end
|
|
end
|
|
|
|
describe '#id' do
|
|
|
|
let(:search_result) do
|
|
Article.search('title:test')
|
|
end
|
|
|
|
it 'returns the type' do
|
|
expect(search_result.results.first.type).to eq('article')
|
|
end
|
|
end
|
|
|
|
describe '#each_with_hit' do
|
|
|
|
let(:search_result) do
|
|
Article.search('title:test')
|
|
end
|
|
|
|
it 'returns the record with the Elasticsearch hit' do
|
|
search_result.records.each_with_hit do |r, h|
|
|
expect(h._score).not_to be_nil
|
|
expect(h._source.title).not_to be_nil
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'search results order' do
|
|
|
|
let(:search_result) do
|
|
Article.search(query: { match: { title: 'code' }}, sort: { clicks: :desc })
|
|
end
|
|
|
|
it 'preserves the search results order when accessing a single record' do
|
|
expect(search_result.records[0].clicks).to be(3)
|
|
expect(search_result.records[1].clicks).to be(2)
|
|
expect(search_result.records.first).to eq(search_result.records[0])
|
|
end
|
|
|
|
it 'preserves the search results order for the list of records' do
|
|
search_result.records.each_with_hit do |r, h|
|
|
expect(r.id.to_s).to eq(h._id)
|
|
end
|
|
|
|
search_result.records.map_with_hit do |r, h|
|
|
expect(r.id.to_s).to eq(h._id)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'a paged collection' do
|
|
|
|
let(:search_result) do
|
|
Article.search(query: { match: { title: { query: 'test' } } },
|
|
size: 2,
|
|
from: 1)
|
|
end
|
|
|
|
it 'applies the paged options to the search' do
|
|
expect(search_result.results.size).to eq(1)
|
|
expect(search_result.results.first.title).to eq('Testing Coding')
|
|
expect(search_result.records.size).to eq(1)
|
|
expect(search_result.records.first.title).to eq('Testing Coding')
|
|
end
|
|
end
|
|
|
|
describe '#destroy' do
|
|
|
|
before do
|
|
Article.create!(title: 'destroy', body: '', clicks: 1)
|
|
Article.__elasticsearch__.refresh_index!
|
|
Article.where(title: 'destroy').first.destroy
|
|
|
|
Article.__elasticsearch__.refresh_index!
|
|
end
|
|
|
|
let(:search_result) do
|
|
Article.search('title:test')
|
|
end
|
|
|
|
it 'removes the document from the index' do
|
|
expect(Article.count).to eq(3)
|
|
expect(search_result.results.size).to eq(2)
|
|
expect(search_result.records.size).to eq(2)
|
|
end
|
|
end
|
|
|
|
describe 'full document updates' do
|
|
|
|
before do
|
|
article = Article.create!(title: 'update', body: '', clicks: 1)
|
|
Article.__elasticsearch__.refresh_index!
|
|
article.title = 'Writing'
|
|
article.save
|
|
|
|
Article.__elasticsearch__.refresh_index!
|
|
end
|
|
|
|
let(:search_result) do
|
|
Article.search('title:write')
|
|
end
|
|
|
|
it 'applies the update' do
|
|
expect(search_result.results.size).to eq(1)
|
|
expect(search_result.records.size).to eq(1)
|
|
end
|
|
end
|
|
|
|
describe 'attribute updates' do
|
|
|
|
before do
|
|
article = Article.create!(title: 'update', body: '', clicks: 1)
|
|
Article.__elasticsearch__.refresh_index!
|
|
article.title = 'special'
|
|
article.save
|
|
|
|
Article.__elasticsearch__.refresh_index!
|
|
end
|
|
|
|
let(:search_result) do
|
|
Article.search('title:special')
|
|
end
|
|
|
|
it 'applies the update' do
|
|
expect(search_result.results.size).to eq(1)
|
|
expect(search_result.records.size).to eq(1)
|
|
end
|
|
end
|
|
|
|
describe '#save' do
|
|
|
|
before do
|
|
article = Article.create!(title: 'save', body: '', clicks: 1)
|
|
|
|
ActiveRecord::Base.transaction do
|
|
article.body = 'dummy'
|
|
article.save
|
|
|
|
article.title = 'special'
|
|
article.save
|
|
end
|
|
|
|
article.__elasticsearch__.update_document
|
|
Article.__elasticsearch__.refresh_index!
|
|
end
|
|
|
|
let(:search_result) do
|
|
Article.search('body:dummy')
|
|
end
|
|
|
|
it 'applies the save' do
|
|
expect(search_result.results.size).to eq(1)
|
|
expect(search_result.records.size).to eq(1)
|
|
end
|
|
end
|
|
|
|
describe 'a DSL search' do
|
|
|
|
let(:search_result) do
|
|
Article.search(query: { match: { title: { query: 'test' } } })
|
|
end
|
|
|
|
it 'returns the results' do
|
|
expect(search_result.results.size).to eq(2)
|
|
expect(search_result.records.size).to eq(2)
|
|
end
|
|
end
|
|
|
|
describe 'chaining SQL queries on response.records' do
|
|
|
|
let(:search_result) do
|
|
Article.search(query: { match: { title: { query: 'test' } } })
|
|
end
|
|
|
|
it 'executes the SQL request with the chained query criteria' do
|
|
expect(search_result.records.size).to eq(2)
|
|
expect(search_result.records.where(title: 'Test').size).to eq(1)
|
|
expect(search_result.records.where(title: 'Test').first.title).to eq('Test')
|
|
end
|
|
end
|
|
|
|
describe 'ordering of SQL queries' do
|
|
|
|
context 'when order is called on the ActiveRecord query' do
|
|
|
|
let(:search_result) do
|
|
Article.search query: { match: { title: { query: 'test' } } }
|
|
end
|
|
|
|
it 'allows the SQL query to be ordered independent of the Elasticsearch results order', unless: active_record_at_least_4? do
|
|
expect(search_result.records.order('title DESC').first.title).to eq('Testing Coding')
|
|
expect(search_result.records.order('title DESC')[0].title).to eq('Testing Coding')
|
|
end
|
|
|
|
it 'allows the SQL query to be ordered independent of the Elasticsearch results order', if: active_record_at_least_4? do
|
|
expect(search_result.records.order(title: :desc).first.title).to eq('Testing Coding')
|
|
expect(search_result.records.order(title: :desc)[0].title).to eq('Testing Coding')
|
|
end
|
|
end
|
|
|
|
context 'when more methods are chained on the ActiveRecord query' do
|
|
|
|
let(:search_result) do
|
|
Article.search query: {match: {title: {query: 'test'}}}
|
|
end
|
|
|
|
it 'allows the SQL query to be ordered independent of the Elasticsearch results order', if: active_record_at_least_4? do
|
|
expect(search_result.records.distinct.order(title: :desc).first.title).to eq('Testing Coding')
|
|
expect(search_result.records.distinct.order(title: :desc)[0].title).to eq('Testing Coding')
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'access to the response via methods' do
|
|
|
|
let(:search_result) do
|
|
Article.search(query: { match: { title: { query: 'test' } } },
|
|
aggregations: {
|
|
dates: { date_histogram: { field: 'created_at', interval: 'hour' } },
|
|
clicks: { global: {}, aggregations: { min: { min: { field: 'clicks' } } } }
|
|
},
|
|
suggest: { text: 'tezt', title: { term: { field: 'title', suggest_mode: 'always' } } })
|
|
end
|
|
|
|
it 'allows document keys to be access via methods' do
|
|
expect(search_result.aggregations.dates.buckets.first.doc_count).to eq(2)
|
|
expect(search_result.aggregations.clicks.doc_count).to eq(6)
|
|
expect(search_result.aggregations.clicks.min.value).to eq(1.0)
|
|
expect(search_result.aggregations.clicks.max).to be_nil
|
|
expect(search_result.suggestions.title.first.options.size).to eq(1)
|
|
expect(search_result.suggestions.terms).to eq(['test'])
|
|
end
|
|
end
|
|
end
|