mindex 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0551f44df8bc5a94b2f3e115d1649bb0c64bb0be
4
- data.tar.gz: fe326d30a64848f1cdf15d0e590165757dbfcb9e
3
+ metadata.gz: 8a71d6115d947753187c7da5136c2ca67fbb1131
4
+ data.tar.gz: 0ec7e8030e636f8305b09d496185e948c950d4bd
5
5
  SHA512:
6
- metadata.gz: a2f2c6b60704baeab1ea36aa6372743d73a10ac5197d0ee5b134ccdb426806cb1b71264671fe0e248597248a4e631117607b800c63202a2c0f7c8053bc92bb80
7
- data.tar.gz: 0123ab5f1ba1b23abffe2e795c9d5501c2b380b761123ccc52297b0df3786a330f2d189d9a9d7622941d5c5284d111c9130a574ec45c53e9068ff8e34d1aa00c
6
+ metadata.gz: 0535323e08ea36d5897b162b1de6d69e53f08e9bac68c794e70559b175b963ced7d584680cb9153e61e33ec1ad436ae69b823ab619a4f0dba26388a818737d42
7
+ data.tar.gz: e6eb59a631d55a8aceaca0ab13ded8e092e9ea359dc946a65db69299e6bf7657780ad8915349424485a01a43547f06a1f73d50fa564c46f7e502937d0a6ad190
data/.dockerignore ADDED
@@ -0,0 +1 @@
1
+ tmp
data/.gitignore CHANGED
@@ -20,3 +20,5 @@ tmp
20
20
  *.o
21
21
  *.a
22
22
  mkmf.log
23
+ .ruby-version
24
+ .ruby-gemset
data/.gitlab-ci.yml ADDED
@@ -0,0 +1,44 @@
1
+ image: "ruby:2.4"
2
+
3
+ stages:
4
+ - test
5
+ - release
6
+
7
+ cache:
8
+ paths:
9
+ - vendor/ruby
10
+
11
+ before_script:
12
+ - gem install bundler --no-ri --no-rdoc
13
+ - bundle install --jobs $(nproc) --path vendor
14
+ - mkdir -p tmp
15
+
16
+ rubocop:
17
+ stage: test
18
+ script:
19
+ - rubocop
20
+
21
+ rspec:
22
+ stage: test
23
+ services:
24
+ - name: docker.elastic.co/elasticsearch/elasticsearch:5.6.3
25
+ alias: elasticsearch
26
+ variables:
27
+ ELASTICSEARCH_URL: elasticsearch:9200
28
+ ELASTICSEARCH_USERNAME: elastic
29
+ ELASTICSEARCH_PASSWORD: changeme
30
+ script:
31
+ - rspec
32
+
33
+ release-gem:
34
+ stage: release
35
+ only:
36
+ - tags
37
+ script:
38
+ - mkdir -p ~/.gem
39
+ - 'echo -e "---\n:rubygems_api_key: $RUBYGEMS_API_KEY" > ~/.gem/credentials'
40
+ - chmod 0600 ~/.gem/credentials
41
+ - GEM_VERSION=$(echo $CI_COMMIT_TAG|sed 's/[^.0-9]//g')
42
+ - sed -i -e "s/0.0.0/$GEM_VERSION/g" lib/mindex/version.rb
43
+ - gem build mindex.gemspec
44
+ - gem push mindex-$GEM_VERSION.gem -k rubygems
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color --format doc --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,10 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ Documentation:
4
+ Enabled: false
5
+
6
+ AllCops:
7
+ TargetRubyVersion: 2.4
8
+
9
+ Metrics/LineLength:
10
+ Max: 150
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,28 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2017-10-23 21:48:29 +0000 using RuboCop version 0.51.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 2
10
+ Metrics/AbcSize:
11
+ Max: 24
12
+
13
+ # Offense count: 3
14
+ # Configuration parameters: CountComments, ExcludedMethods.
15
+ Metrics/BlockLength:
16
+ Max: 117
17
+
18
+ # Offense count: 1
19
+ # Configuration parameters: CountComments.
20
+ Metrics/MethodLength:
21
+ Max: 21
22
+
23
+ # Offense count: 1
24
+ # Cop supports --auto-correct.
25
+ # Configuration parameters: AutoCorrect.
26
+ Performance/TimesMap:
27
+ Exclude:
28
+ - 'lib/mindex/index.rb'
data/Dockerfile ADDED
@@ -0,0 +1,17 @@
1
+ FROM ruby:latest
2
+
3
+ RUN gem update --system && gem install bundler
4
+
5
+ WORKDIR /code
6
+
7
+ RUN mkdir -p /code/lib/mindex
8
+
9
+ COPY Gemfile .
10
+ COPY mindex.gemspec .
11
+ COPY lib/mindex/version.rb /code/lib/mindex
12
+
13
+ RUN bundle install
14
+
15
+ ADD . /code
16
+
17
+ CMD ["bundle", "exec", "rspec"]
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in mindex.gemspec
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Michael Voigt
1
+ Copyright (c) 2017 Michael Voigt
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,29 +1,82 @@
1
1
  # Mindex
2
2
 
3
- TODO: Write a gem description
3
+ This gem provides functionality to build elasticsearch indices.
4
4
 
5
5
  ## Installation
6
6
 
7
- Add this line to your application's Gemfile:
8
-
9
- gem 'mindex'
7
+ Add the following line to your Gemfile:
8
+ ```ruby
9
+ gem 'mindex'
10
+ ```
10
11
 
11
12
  And then execute:
13
+ ```
14
+ $ bundle
15
+ ```
12
16
 
13
- $ bundle
17
+ ## Example
14
18
 
15
- Or install it yourself as:
19
+ ### Index declaration
20
+ ```ruby
21
+ module Index
22
+ class Event
23
+ include Mindex::Index
16
24
 
17
- $ gem install mindex
25
+ def self.scroll(options = {})
26
+ query = Event
27
+ query = query.where('"updated_at" >= ?', options[:started_at]) if options[:started_at]
28
+ query.find_in_batches do |events|
29
+ yield index_data(events)
30
+ end
31
+ end
18
32
 
19
- ## Usage
33
+ def self.fetch(ids)
34
+ Event.where(id: ids).map do |event|
35
+ index_data(event)
36
+ end
37
+ end
20
38
 
21
- TODO: Write usage instructions here
39
+ private
22
40
 
23
- ## Contributing
41
+ def index_data(events)
42
+ [events].flatten.map do |event|
43
+ {
44
+ id: event.id,
45
+ name: event.name,
46
+ updated_at: event.updated_at,
47
+ created_at: event.created_at
48
+ }
49
+ end
50
+ end
51
+ end
52
+ end
53
+ ```
54
+
55
+ ### Usage
56
+ recreate index
57
+ ```ruby
58
+ Event.recreate_index
59
+ ```
60
+
61
+ reindex all items
62
+ ```ruby
63
+ Event.reindex
64
+ ```
24
65
 
25
- 1. Fork it ( https://github.com/[my-github-username]/mindex/fork )
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Add some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create a new Pull Request
66
+ index specific items
67
+ ```ruby
68
+ Event.reindex_items([2903, 2016])
69
+ ```
70
+
71
+ drop items
72
+ ```ruby
73
+ Event.drop_items([29, 3])
74
+ ```
75
+
76
+ get item from elasticsearch
77
+ ```ruby
78
+ Event.es.get(index: Event.index_alias, id: 2903)
79
+ ```
80
+
81
+ ## Contributing
82
+ Please create an issue or merge request
data/Rakefile CHANGED
@@ -1,2 +1,9 @@
1
- require "bundler/gem_tasks"
1
+ # frozen_string_literal: true
2
2
 
3
+ require 'bundler/gem_tasks'
4
+
5
+ require 'rspec/core/rake_task'
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ task default: :spec
@@ -0,0 +1,20 @@
1
+ version: '2'
2
+
3
+ services:
4
+ mindex:
5
+ build: .
6
+ volumes:
7
+ - .:/code
8
+ environment:
9
+ ELASTICSEARCH_URL: elasticsearch:9200
10
+ ELASTICSEARCH_USERNAME: elastic
11
+ ELASTICSEARCH_PASSWORD: changeme
12
+ depends_on:
13
+ - elasticsearch
14
+ - kibana
15
+ elasticsearch:
16
+ image: docker.elastic.co/elasticsearch/elasticsearch:5.6.3
17
+ kibana: # https://www.elastic.co/guide/en/kibana/current/_configuring_kibana_on_docker.html
18
+ image: docker.elastic.co/kibana/kibana:5.6.3
19
+ ports:
20
+ - "5601:5601"
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'elasticsearch'
4
+
5
+ module Mindex
6
+ class Elasticsearch < Delegator
7
+ def self.connect(options = {})
8
+ new({
9
+ url: Mindex.config.elasticsearch_url,
10
+ user: Mindex.config.elasticsearch_user,
11
+ password: Mindex.config.elasticsearch_pass
12
+ }.merge(Mindex.config.elasticsearch_options || {}).merge(options || {}))
13
+ end
14
+
15
+ def version
16
+ info['version']['number']
17
+ end
18
+
19
+ def version_gte?(expected_version)
20
+ Gem::Version.new(version) >= Gem::Version.new(expected_version)
21
+ end
22
+
23
+ def initialize(options)
24
+ @delegate_sd_obj ||= ::Elasticsearch::Client.new(options)
25
+ end
26
+
27
+ def __getobj__
28
+ @delegate_sd_obj
29
+ end
30
+
31
+ def __setobj__(obj)
32
+ @delegate_sd_obj = obj
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'elasticsearch'
4
+ require 'active_support/core_ext/string/inflections'
5
+
6
+ module Mindex
7
+ module Index
8
+ module ClassMethods # rubocop:disable Metrics/ModuleLength
9
+ def connection_settings(options = {})
10
+ @connection_settings = options
11
+ end
12
+
13
+ def index_config(settings:, mappings:)
14
+ @index_settings = settings
15
+ @index_mappings = mappings
16
+ end
17
+
18
+ def index_prefix(prefix)
19
+ @index_prefix = prefix
20
+ end
21
+
22
+ def index_label(label)
23
+ @index_label = label
24
+ end
25
+
26
+ def index_num_threads(count)
27
+ @index_num_threads = count
28
+ end
29
+
30
+ def index_alias
31
+ [@index_prefix, (@index_label || name.demodulize.tableize)].compact.join('_').underscore
32
+ end
33
+
34
+ def index_name
35
+ elasticsearch.indices.get_alias(name: index_alias).keys.first
36
+ rescue ::Elasticsearch::Transport::Transport::Errors::NotFound
37
+ nil
38
+ end
39
+
40
+ def doc_type
41
+ @index_label || name.demodulize.tableize
42
+ end
43
+
44
+ def index_refresh
45
+ elasticsearch.indices.refresh(index: index_name)
46
+ end
47
+
48
+ def index_exist?(name = nil)
49
+ return false if name.nil? && index_name.nil?
50
+ elasticsearch.indices.exists(index: name || index_name)
51
+ end
52
+
53
+ def index_create(move_or_create_index_alias: true)
54
+ index_name = new_index_name
55
+ elasticsearch.indices.create(index: index_name, body: { settings: @index_settings || {}, mappings: @index_mappings || {} })
56
+ add_index_alias(target: index_name) if move_or_create_index_alias
57
+ index_name
58
+ end
59
+
60
+ def drop_items(ids)
61
+ bulk_data = [ids].flatten.map { |id| { delete: { _index: index_alias, _type: doc_type, _id: id } } }
62
+ elasticsearch.indices.client.bulk(body: bulk_data) if bulk_data.any?
63
+ end
64
+
65
+ def reindex_items(ids)
66
+ index_queue(threads: 1) do |queue|
67
+ queue << fetch(ids)
68
+ end
69
+ end
70
+
71
+ def reindex(options = {})
72
+ index_create unless index_exist?
73
+ index_queue do |queue|
74
+ scroll(options) do |items|
75
+ queue << items
76
+ end
77
+ end
78
+ end
79
+
80
+ def recreate_index(options = {})
81
+ started_at = Time.now
82
+ index_name = index_create(move_or_create_index_alias: false)
83
+ index_queue(index: index_name) do |queue|
84
+ scroll(options) do |items|
85
+ queue << items
86
+ end
87
+ end
88
+ add_index_alias(target: index_name)
89
+ reindex(options.merge(started_at: started_at))
90
+ end
91
+
92
+ def elasticsearch
93
+ Elasticsearch.connect(@connection_settings)
94
+ end
95
+ alias es elasticsearch
96
+
97
+ private
98
+
99
+ def index_queue(index: nil, threads: nil) # rubocop:disable Metrics/AbcSize
100
+ index ||= index_name
101
+ num_threads = threads || @index_num_threads || 4
102
+ queue = SizedQueue.new(num_threads * 2)
103
+ threads = num_threads.times.map do
104
+ thread = Thread.new do
105
+ until (items = queue.pop) == :stop
106
+ bulk_data = []
107
+ [items].flatten.each do |item|
108
+ bulk_data << { index: { _index: index, _type: doc_type, _id: (item[:id] || item['id']), data: item } }
109
+ end
110
+ elasticsearch.indices.client.bulk(body: bulk_data) if bulk_data.any?
111
+ end
112
+ end
113
+ thread.abort_on_exception = true
114
+ thread
115
+ end
116
+
117
+ yield queue
118
+
119
+ index
120
+ ensure
121
+ num_threads.times { queue << :stop }
122
+ threads.each(&:join)
123
+ end
124
+
125
+ def new_index_name
126
+ "#{index_alias}-v#{DateTime.now.strftime('%Q')}" # rubocop:disable Style/DateTime
127
+ end
128
+
129
+ def add_index_alias(target:)
130
+ actions = [{ add: { index: target, alias: index_alias } }]
131
+
132
+ if elasticsearch.indices.exists_alias(name: index_alias)
133
+ actions += elasticsearch.indices.get_alias(name: index_alias).keys.map do |index_name|
134
+ { remove: { index: index_name, alias: index_alias } }
135
+ end
136
+ end
137
+
138
+ elasticsearch.indices.update_aliases(body: { actions: actions })
139
+ end
140
+ end
141
+
142
+ module InstanceMethods
143
+ def elasticsearch
144
+ @elasticsearch ||= self.class.elasticsearch
145
+ end
146
+ alias es elasticsearch
147
+ end
148
+
149
+ def self.included(receiver)
150
+ receiver.extend ClassMethods
151
+ receiver.send :include, InstanceMethods
152
+ end
153
+ end
154
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Mindex
2
- VERSION = "0.0.1"
4
+ VERSION = '0.1.0'
3
5
  end
data/lib/mindex.rb CHANGED
@@ -1,5 +1,20 @@
1
- require "mindex/version"
1
+ # frozen_string_literal: true
2
+
3
+ require 'mindex/version'
4
+ require 'mindex/elasticsearch'
5
+ require 'mindex/index'
6
+ require 'ostruct'
2
7
 
3
8
  module Mindex
4
- # Your code goes here...
9
+ class << self
10
+ attr_writer :config
11
+ end
12
+
13
+ def self.config
14
+ @config ||= OpenStruct.new
15
+ end
16
+
17
+ def self.configure
18
+ yield(config)
19
+ end
5
20
  end
data/mindex.gemspec CHANGED
@@ -1,23 +1,31 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
4
4
  require 'mindex/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "mindex"
7
+ spec.name = 'mindex'
8
8
  spec.version = Mindex::VERSION
9
- spec.authors = ["Michael Voigt"]
10
- spec.email = ["michael.voigt@voigt-mail.de"]
11
- spec.summary = %q{Write a short summary. Required.}
12
- spec.description = %q{Write a longer description. Optional.}
13
- spec.homepage = ""
14
- spec.license = "MIT"
9
+ spec.authors = ['Michael Voigt']
10
+ spec.email = ['michael.voigt@spider-network.com']
11
+ spec.summary = 'Mindex provides functionality to build elasticsearch indices'
12
+ spec.homepage = 'http://www.spider-network.com'
13
+ spec.license = 'MIT'
15
14
 
16
15
  spec.files = `git ls-files -z`.split("\x0")
17
16
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
17
+ spec.test_files = spec.files.grep(%r{^(spec)/})
18
+ spec.require_paths = ['lib']
19
+
20
+ spec.add_dependency 'activesupport'
21
+ spec.add_dependency 'elasticsearch'
20
22
 
21
- spec.add_development_dependency "bundler", "~> 1.6"
22
- spec.add_development_dependency "rake"
23
+ spec.add_development_dependency 'bundler', '> 1'
24
+ spec.add_development_dependency 'pry'
25
+ spec.add_development_dependency 'rake'
26
+ spec.add_development_dependency 'rspec'
27
+ spec.add_development_dependency 'rubocop'
28
+ spec.add_development_dependency 'rubocop-rspec'
29
+ spec.add_development_dependency 'sequel'
30
+ spec.add_development_dependency 'sqlite3'
23
31
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Index
4
+ class Event
5
+ include Mindex::Index
6
+
7
+ def self.reset_settings!
8
+ @connection_settings = nil
9
+ @index_settings = nil
10
+ @index_mappings = nil
11
+ @index_prefix = nil
12
+ @index_label = nil
13
+ @index_num_threads = nil
14
+ end
15
+
16
+ def self.scroll(_options = {})
17
+ DB[:events].select.each_slice(500) do |events|
18
+ yield events
19
+ end
20
+ end
21
+
22
+ def self.fetch(ids)
23
+ DB[:events].where(id: ids).all
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Mindex::Elasticsearch do
4
+ subject(:connect) { described_class.connect }
5
+
6
+ describe '.connect' do
7
+ before do
8
+ allow(::Elasticsearch::Client).to receive(:new)
9
+ end
10
+
11
+ it 'creates a Elasticsearch::Client instance' do
12
+ connect
13
+ expect(::Elasticsearch::Client).to have_received(:new)
14
+ end
15
+
16
+ context 'when elasticsearch_url is set to "foo"' do
17
+ before { Mindex.config.elasticsearch_url = 'foo' }
18
+
19
+ it do
20
+ connect
21
+ expect(::Elasticsearch::Client).to have_received(:new).with(hash_including(url: 'foo'))
22
+ end
23
+ end
24
+
25
+ context 'when elasticsearch_user is set' do
26
+ before { Mindex.config.elasticsearch_user = 'username' }
27
+
28
+ it do
29
+ connect
30
+ expect(::Elasticsearch::Client).to have_received(:new).with(hash_including(user: 'username'))
31
+ end
32
+ end
33
+
34
+ context 'when elasticsearch_pass is set' do
35
+ before { Mindex.config.elasticsearch_pass = 'password' }
36
+
37
+ it do
38
+ connect
39
+ expect(::Elasticsearch::Client).to have_received(:new).with(hash_including(password: 'password'))
40
+ end
41
+ end
42
+
43
+ context 'when elasticsearch_options is set' do
44
+ before { Mindex.config.elasticsearch_options = { url: 'local', foo: 'bar' } }
45
+
46
+ it do
47
+ connect
48
+ expect(::Elasticsearch::Client).to have_received(:new).with(hash_including(url: 'local', foo: 'bar'))
49
+ end
50
+ end
51
+ end
52
+
53
+ describe '.version' do
54
+ before do
55
+ client = instance_double(Elasticsearch::Transport::Client, info: { 'version' => { 'number' => '6.6.6' } })
56
+ allow(::Elasticsearch::Client).to receive(:new).and_return(client)
57
+ end
58
+
59
+ it 'returns the elasticsearch cluster version' do
60
+ expect(connect.version).to eq '6.6.6'
61
+ end
62
+ end
63
+
64
+ describe '.version_gte' do
65
+ before do
66
+ client = instance_double(Elasticsearch::Transport::Client, info: { 'version' => { 'number' => '6.6.6' } })
67
+ allow(::Elasticsearch::Client).to receive(:new).and_return(client)
68
+ end
69
+
70
+ context 'when expected version is smaller' do
71
+ it { expect(connect.version_gte?('0.90.0')).to be true }
72
+ end
73
+
74
+ context 'when expected version is equal' do
75
+ it { expect(connect.version_gte?('6.6.6')).to be true }
76
+ end
77
+
78
+ context 'when expected version is greater' do
79
+ it { expect(connect.version_gte?('7.0.0')).to be false }
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,205 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dummy/index/event'
4
+
5
+ describe Mindex::Index do # rubocop:disable Metrics/BlockLength
6
+ let(:index_klass) { Index::Event }
7
+
8
+ before do
9
+ index_klass.reset_settings!
10
+ end
11
+
12
+ describe '.index_alias' do
13
+ it 'returns the alias name of the index' do
14
+ expect(index_klass.index_alias).to eq 'events'
15
+ end
16
+
17
+ context 'when prefix is definde' do
18
+ let(:prefix) { 'foobar' }
19
+ before { index_klass.index_prefix(prefix) }
20
+
21
+ it 'prefixes the alias name' do
22
+ expect(index_klass.index_alias).to eq "#{prefix}_events"
23
+ end
24
+ end
25
+
26
+ context 'when label is definde' do
27
+ let(:label) { 'competition' }
28
+ before { index_klass.index_label(label) }
29
+
30
+ it 'uses the label instead of the tableize class name' do
31
+ expect(index_klass.index_alias).to eq label
32
+ end
33
+ end
34
+ end
35
+
36
+ describe '.doc_type' do
37
+ it 'uses the tableize class name' do
38
+ expect(index_klass.doc_type).to eq index_klass.name.demodulize.tableize
39
+ end
40
+
41
+ context 'when label is definde' do
42
+ let(:label) { 'competition' }
43
+ before { index_klass.index_label(label) }
44
+
45
+ it 'uses the label instead of the tableize class name' do
46
+ expect(index_klass.doc_type).to eq label
47
+ end
48
+ end
49
+ end
50
+
51
+ describe '.index_name' do
52
+ context 'when index does not exists' do
53
+ it do
54
+ expect(index_klass.index_name).to be_nil
55
+ end
56
+ end
57
+
58
+ context 'when index exists' do
59
+ before do
60
+ @index_name = index_klass.index_create
61
+ end
62
+
63
+ it 'returns the index name' do
64
+ expect(index_klass.index_name).to eq @index_name
65
+ end
66
+ end
67
+ end
68
+
69
+ describe '.index_refresh' do
70
+ context 'when index does not exists' do
71
+ it do
72
+ expect { index_klass.index_refresh }.not_to raise_error
73
+ end
74
+ end
75
+
76
+ context 'when index exists' do
77
+ before { index_klass.index_create }
78
+
79
+ it do
80
+ expect { index_klass.index_refresh }.not_to raise_error
81
+ end
82
+ end
83
+ end
84
+
85
+ describe '.index_exist?' do
86
+ context 'when the index does not exists' do
87
+ it do
88
+ expect(index_klass.index_exist?).to be false
89
+ end
90
+ end
91
+
92
+ context 'when the index exists' do
93
+ before { index_klass.index_create }
94
+
95
+ it do
96
+ expect(index_klass.index_exist?).to be true
97
+ end
98
+ end
99
+ end
100
+
101
+ describe '.connection_settings' do
102
+ let(:connection_settings) { { foo: :bar, foobar: :baz, qux: :quux } }
103
+
104
+ before do
105
+ allow(Mindex::Elasticsearch).to receive(:connect)
106
+ index_klass.connection_settings(connection_settings)
107
+ end
108
+
109
+ it 'overwrites the connection settings' do
110
+ index_klass.elasticsearch
111
+ expect(Mindex::Elasticsearch).to have_received(:connect).with(connection_settings)
112
+ end
113
+ end
114
+
115
+ describe '.index_config' do
116
+ let(:settings) { { foo: :bar } }
117
+ let(:mapping) { { bar: :foo } }
118
+
119
+ before do
120
+ @indices = instance_double(Elasticsearch::API::Indices::IndicesClient, create: nil)
121
+ allow(::Elasticsearch::Client).to receive(:new).and_return(instance_double(Elasticsearch::Transport::Client, indices: @indices))
122
+
123
+ index_klass.index_config(settings: settings, mappings: mapping)
124
+ end
125
+
126
+ it 'creates the index with the given settings and mappings' do
127
+ index_klass.index_create(move_or_create_index_alias: false)
128
+ expect(@indices).to have_received(:create).with(hash_including(index: anything, body: { settings: settings, mappings: mapping }))
129
+ end
130
+ end
131
+
132
+ describe '.reindex' do
133
+ let(:event_1) { { 'id' => 1, 'name' => 'BerlinMan' } }
134
+ let(:event_2) { { 'id' => 2, 'name' => 'Leipziger Triathlon' } }
135
+
136
+ before do
137
+ DB.run 'CREATE TABLE events (id integer primary key autoincrement, name varchar(255))'
138
+ DB[:events].insert(event_1)
139
+ DB[:events].insert(event_2)
140
+ end
141
+
142
+ it 'updates the entities' do
143
+ index_klass.reindex
144
+ expect(index_klass.es.get(index: index_klass.index_alias, id: event_1['id'])['_source']).to eq event_1
145
+ expect(index_klass.es.get(index: index_klass.index_alias, id: event_2['id'])['_source']).to eq event_2
146
+ DB[:events].where(id: event_1['id']).update(name: 'BerlinMan 2018')
147
+ DB[:events].where(id: event_2['id']).update(name: 'Leipziger Triathlon 2018')
148
+ index_klass.reindex
149
+ expect(index_klass.es.get(index: index_klass.index_alias, id: event_1['id'])['_source']['name']).to eq 'BerlinMan 2018'
150
+ expect(index_klass.es.get(index: index_klass.index_alias, id: event_2['id'])['_source']['name']).to eq 'Leipziger Triathlon 2018'
151
+ end
152
+ end
153
+
154
+ describe '.reindex_items' do
155
+ let(:event_1) { { 'id' => 1, 'name' => 'BerlinMan' } }
156
+ let(:event_2) { { 'id' => 2, 'name' => 'Paderborner Triathlon' } }
157
+
158
+ before do
159
+ index_klass.index_create
160
+ DB.run 'CREATE TABLE events (id integer primary key autoincrement, name varchar(255))'
161
+ DB[:events].insert(event_1)
162
+ DB[:events].insert(event_2)
163
+ end
164
+
165
+ it 'updates the entities' do
166
+ index_klass.reindex_items([event_1['id'], event_2['id']])
167
+ expect(index_klass.es.get(index: index_klass.index_alias, id: event_1['id'])['_source']['name']).to eq 'BerlinMan'
168
+ expect(index_klass.es.get(index: index_klass.index_alias, id: event_2['id'])['_source']['name']).to eq 'Paderborner Triathlon'
169
+ end
170
+ end
171
+
172
+ describe '.drop_items' do
173
+ let(:event) { { 'id' => 1, 'name' => 'BerlinMan' } }
174
+
175
+ before do
176
+ DB.run 'CREATE TABLE events (id integer primary key autoincrement, name varchar(255))'
177
+ DB[:events].insert(event)
178
+ index_klass.reindex
179
+ end
180
+
181
+ it 'drops the given entities' do
182
+ expect { index_klass.es.get(index: index_klass.index_alias, id: event['id']) }.not_to raise_error
183
+
184
+ index_klass.drop_items(event['id'])
185
+
186
+ expect do
187
+ index_klass.es.get(index: index_klass.index_alias, id: event['id'])
188
+ end.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
189
+ end
190
+ end
191
+
192
+ describe '.recreate_index' do
193
+ let(:event) { { 'id' => 1, 'name' => 'BerlinMan' } }
194
+
195
+ before do
196
+ DB.run 'CREATE TABLE events (id integer primary key autoincrement, name varchar(255))'
197
+ DB[:events].insert(event)
198
+ end
199
+
200
+ it 'inserts the entities in a new index' do
201
+ index_name = index_klass.recreate_index
202
+ expect(index_klass.es.get(index: index_name, id: event['id'])['_source']).to eq event
203
+ end
204
+ end
205
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Mindex do
4
+ it 'defines a version number' do
5
+ expect(described_class::VERSION).to eq '0.0.0'
6
+ end
7
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
4
+ require 'mindex'
5
+ require 'pry'
6
+
7
+ require 'sequel'
8
+ require 'sqlite3'
9
+
10
+ DB = Sequel.sqlite('tmp/database.sqlite3')
11
+
12
+ def reset_configuration!
13
+ Mindex.configure do |config|
14
+ config.elasticsearch_url = ENV.fetch('ELASTICSEARCH_URL', 'localhost:9200')
15
+ config.elasticsearch_user = ENV.fetch('ELASTICSEARCH_USERNAME', 'elastic')
16
+ config.elasticsearch_pass = ENV.fetch('ELASTICSEARCH_PASSWORD', 'changeme')
17
+ config.elasticsearch_options = nil
18
+ end
19
+ end
20
+
21
+ def drop_indices!
22
+ Mindex::Elasticsearch.connect.indices.delete(index: '_all')
23
+ end
24
+
25
+ def drop_sqlite_tables!
26
+ tables = DB[:sqlite_master].where(type: 'table').exclude(name: %w[sqlite_sequence sqlite_master]).select.map { |row| row[:name] }
27
+ tables.each { |table| DB.run("DROP TABLE #{table}") }
28
+ end
29
+
30
+ RSpec.configure do |config|
31
+ config.before(:each) do
32
+ reset_configuration!
33
+ drop_indices!
34
+ drop_sqlite_tables!
35
+ end
36
+ end
metadata CHANGED
@@ -1,59 +1,185 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mindex
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Voigt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-08-11 00:00:00.000000000 Z
11
+ date: 2017-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: elasticsearch
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: bundler
15
43
  requirement: !ruby/object:Gem::Requirement
16
44
  requirements:
17
- - - ~>
45
+ - - ">"
18
46
  - !ruby/object:Gem::Version
19
- version: '1.6'
47
+ version: '1'
20
48
  type: :development
21
49
  prerelease: false
22
50
  version_requirements: !ruby/object:Gem::Requirement
23
51
  requirements:
24
- - - ~>
52
+ - - ">"
25
53
  - !ruby/object:Gem::Version
26
- version: '1.6'
54
+ version: '1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
27
69
  - !ruby/object:Gem::Dependency
28
70
  name: rake
29
71
  requirement: !ruby/object:Gem::Requirement
30
72
  requirements:
31
- - - '>='
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: sequel
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: sqlite3
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
32
144
  - !ruby/object:Gem::Version
33
145
  version: '0'
34
146
  type: :development
35
147
  prerelease: false
36
148
  version_requirements: !ruby/object:Gem::Requirement
37
149
  requirements:
38
- - - '>='
150
+ - - ">="
39
151
  - !ruby/object:Gem::Version
40
152
  version: '0'
41
- description: Write a longer description. Optional.
153
+ description:
42
154
  email:
43
- - michael.voigt@voigt-mail.de
155
+ - michael.voigt@spider-network.com
44
156
  executables: []
45
157
  extensions: []
46
158
  extra_rdoc_files: []
47
159
  files:
48
- - .gitignore
160
+ - ".dockerignore"
161
+ - ".gitignore"
162
+ - ".gitlab-ci.yml"
163
+ - ".rspec"
164
+ - ".rubocop.yml"
165
+ - ".rubocop_todo.yml"
166
+ - Dockerfile
49
167
  - Gemfile
50
168
  - LICENSE.txt
51
169
  - README.md
52
170
  - Rakefile
171
+ - docker-compose.yml
53
172
  - lib/mindex.rb
173
+ - lib/mindex/elasticsearch.rb
174
+ - lib/mindex/index.rb
54
175
  - lib/mindex/version.rb
55
176
  - mindex.gemspec
56
- homepage: ''
177
+ - spec/dummy/index/event.rb
178
+ - spec/lib/mindex/elasticsearch_spec.rb
179
+ - spec/lib/mindex/index_spec.rb
180
+ - spec/lib/mindex_spec.rb
181
+ - spec/spec_helper.rb
182
+ homepage: http://www.spider-network.com
57
183
  licenses:
58
184
  - MIT
59
185
  metadata: {}
@@ -63,18 +189,23 @@ require_paths:
63
189
  - lib
64
190
  required_ruby_version: !ruby/object:Gem::Requirement
65
191
  requirements:
66
- - - '>='
192
+ - - ">="
67
193
  - !ruby/object:Gem::Version
68
194
  version: '0'
69
195
  required_rubygems_version: !ruby/object:Gem::Requirement
70
196
  requirements:
71
- - - '>='
197
+ - - ">="
72
198
  - !ruby/object:Gem::Version
73
199
  version: '0'
74
200
  requirements: []
75
201
  rubyforge_project:
76
- rubygems_version: 2.4.1
202
+ rubygems_version: 2.6.14
77
203
  signing_key:
78
204
  specification_version: 4
79
- summary: Write a short summary. Required.
80
- test_files: []
205
+ summary: Mindex provides functionality to build elasticsearch indices
206
+ test_files:
207
+ - spec/dummy/index/event.rb
208
+ - spec/lib/mindex/elasticsearch_spec.rb
209
+ - spec/lib/mindex/index_spec.rb
210
+ - spec/lib/mindex_spec.rb
211
+ - spec/spec_helper.rb