elos 0.1.0 → 1.0.4

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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/bin/push +40 -0
  4. data/bin/rspec +16 -0
  5. data/db/migrate/001_create_a_entry_repos.rb +7 -0
  6. data/elos-0.1.0.gem +0 -0
  7. data/elos-1.0.3.gem +0 -0
  8. data/elos.gemspec +20 -9
  9. data/lib/elos/configuration.rb +16 -0
  10. data/lib/elos/criteria.rb +78 -0
  11. data/lib/elos/data_object.rb +30 -0
  12. data/lib/elos/errors/not_found.rb +5 -0
  13. data/lib/elos/errors/validation_failed.rb +5 -0
  14. data/lib/elos/index/core.rb +35 -0
  15. data/lib/elos/index/indexable.rb +32 -0
  16. data/lib/elos/index/locatable.rb +17 -0
  17. data/lib/elos/index/mappings.rb +25 -0
  18. data/lib/elos/index/model/assignable.rb +19 -0
  19. data/lib/elos/index/model/identifiable.rb +9 -0
  20. data/lib/elos/index/model/initializable.rb +13 -0
  21. data/lib/elos/index/model.rb +12 -0
  22. data/lib/elos/index/raw_helpers.rb +9 -0
  23. data/lib/elos/index/refreshable.rb +9 -0
  24. data/lib/elos/index/reindexable.rb +132 -0
  25. data/lib/elos/index/searchable.rb +17 -0
  26. data/lib/elos/index/subscribable.rb +14 -0
  27. data/lib/elos/index/unindexable.rb +9 -0
  28. data/lib/elos/index.rb +15 -0
  29. data/lib/elos/lock.rb +48 -0
  30. data/lib/elos/query_builder/base.rb +23 -0
  31. data/lib/elos/query_builder/builtin/match_all_query_builder.rb +5 -0
  32. data/lib/elos/query_builder/builtin/where_query_builder.rb +5 -0
  33. data/lib/elos/query_builder/filters.rb +41 -0
  34. data/lib/elos/query_builder/queries.rb +15 -0
  35. data/lib/elos/repository/adapter/active_record/scanable.rb +11 -0
  36. data/lib/elos/repository/adapter/active_record.rb +6 -0
  37. data/lib/elos/repository/adapter/elos/migratable.rb +13 -0
  38. data/lib/elos/repository/adapter/elos/model/destroyable.rb +44 -0
  39. data/lib/elos/repository/adapter/elos/model/persistable.rb +79 -0
  40. data/lib/elos/repository/adapter/elos/model/reindexable.rb +15 -0
  41. data/lib/elos/repository/adapter/elos/model/unindexable.rb +7 -0
  42. data/lib/elos/repository/adapter/elos/model/validatable.rb +8 -0
  43. data/lib/elos/repository/adapter/elos/scanable.rb +24 -0
  44. data/lib/elos/repository/adapter/elos.rb +31 -0
  45. data/lib/elos/repository/publishable.rb +26 -0
  46. data/lib/elos/result.rb +23 -0
  47. data/lib/elos/version.rb +2 -2
  48. data/lib/elos.rb +3 -3
  49. data/lib/initialize.rb +6 -0
  50. metadata +129 -2
data/lib/elos/lock.rb ADDED
@@ -0,0 +1,48 @@
1
+ class Elos::Lock
2
+ include Elos::Index::Core
3
+
4
+ def self.lock(key, &block)
5
+ create_index(index_name)
6
+ id = SecureRandom.uuid
7
+ body = { doc: {}, upsert: { lock: id } }
8
+ client.update(index: index_name, type: type_name, id: key, body: body)
9
+ if client.get(index: index_name, type: type_name, id: key)['_source']['lock'] == id
10
+ if block
11
+ begin
12
+ ret = block.()
13
+ ensure
14
+ unlock(key)
15
+ end
16
+ else
17
+ true
18
+ end
19
+ end
20
+ end
21
+
22
+ def self.unlock(key)
23
+ client.delete(index: index_name, type: type_name, id: key)
24
+ rescue Elasticsearch::Transport::Transport::Errors::NotFound
25
+ end
26
+
27
+ private
28
+
29
+ def self.mappings
30
+ {
31
+ type_name => {
32
+ _all: { enabled: false },
33
+ _ttl: { enabled: true, default: '5d' },
34
+ properties: properties
35
+ }
36
+ }
37
+ end
38
+
39
+ def self.properties
40
+ {
41
+ boolean_property => %i(lock)
42
+ }.inject({}) { |m, x| m.merge(Hash[x[1].map { |y| [y, x[0]] }]) }
43
+ end
44
+
45
+ def self.boolean_property
46
+ { type: 'boolean' }
47
+ end
48
+ end
@@ -0,0 +1,23 @@
1
+ class Elos::QueryBuilder::Base
2
+ include Elos::QueryBuilder::Filters
3
+ include Elos::QueryBuilder::Queries
4
+
5
+ def initialize(params)
6
+ @params = params
7
+ end
8
+
9
+ def _build
10
+ query = build
11
+ original_query = query[:query]
12
+ filter = term_filter(:_destroyed, value: false)
13
+ query[:query] = { filtered: { query: original_query, filter: filter } }
14
+ # puts JSON.pretty_generate(query)
15
+ query
16
+ end
17
+
18
+ protected
19
+
20
+ def params
21
+ @params
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ class Elos::QueryBuilder::Builtin::MatchAllQueryBuilder < Elos::QueryBuilder::Base
2
+ def build
3
+ match_all_query
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Elos::QueryBuilder::Builtin::WhereQueryBuilder < Elos::QueryBuilder::Base
2
+ def build
3
+ ids_query
4
+ end
5
+ end
@@ -0,0 +1,41 @@
1
+ module Elos::QueryBuilder::Filters
2
+ extend ActiveSupport::Concern
3
+
4
+ def or_filter(*filters)
5
+ filters = filters.first if filters.first.is_a?(Array)
6
+ filters.compact!
7
+ { or: filters } unless filters.empty?
8
+ end
9
+
10
+ def and_filter(*filters)
11
+ filters = filters.first if filters.first.is_a?(Array)
12
+ filters.compact!
13
+ { and: filters } unless filters.empty?
14
+ end
15
+
16
+ def term_filter(key, params_sym = nil, value: nil)
17
+ v = value.nil? ? params[params_sym || key] : value
18
+ { term: { key => v } } unless v.nil?
19
+ end
20
+
21
+ def terms_filter(key, params_sym = nil, values: nil)
22
+ v = value.nil? ? params[params_sym || key.to_s.pluralize.to_sym] : value
23
+ { terms: { key => v } } unless v.empty?
24
+ end
25
+
26
+ def exists_filter(key)
27
+ { exists: { field: key } }
28
+ end
29
+
30
+ def missing_filter(key)
31
+ { missing: { field: key } }
32
+ end
33
+
34
+ def range_filter(key, min: nil, max: nil)
35
+ return unless min || max
36
+ r = { range: { key => {} } }
37
+ r[:range][key][:gte] = min if min
38
+ r[:range][key][:lte] = max if max
39
+ r
40
+ end
41
+ end
@@ -0,0 +1,15 @@
1
+ module Elos::QueryBuilder::Queries
2
+ extend ActiveSupport::Concern
3
+
4
+ def ids_query(key = :id, value = nil)
5
+ { query: { ids: { values: value || params[key] } } }
6
+ end
7
+
8
+ def match_query(key, value)
9
+ { query: { match: { key => { query: value, operator: 'and' } } } }
10
+ end
11
+
12
+ def match_all_query
13
+ { query: { match_all: {} } }
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Elos::Repository::Adapter::ActiveRecord::Scanable
2
+ extend ActiveSupport::Concern
3
+
4
+ class_methods do
5
+ def scan(batch_size = nil, &block)
6
+ find_each(batch_size: batch_size) do |record|
7
+ block.(record)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ module Elos::Repository::Adapter::ActiveRecord
2
+ extend ActiveSupport::Concern
3
+
4
+ include Elos::Repository::Publishable
5
+ include Elos::Repository::Adapter::ActiveRecord::Scanable
6
+ end
@@ -0,0 +1,13 @@
1
+ module Elos::Repository::Adapter::Elos::Migratable
2
+ extend ActiveSupport::Concern
3
+
4
+ class_methods do
5
+ def migrate
6
+ reindex do |old_index_name, new_index_name|
7
+ _scan(index_name: old_index_name) do |hit|
8
+ client.update(index: new_index_name, type: type_name, id: hit['_id'], body: { doc: {}, upsert: hit['_source'] })
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,44 @@
1
+ module Elos::Repository::Adapter::Elos::Model::Destroyable
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ cattr_writer :physically_destroy
6
+
7
+ attr_accessor :destroyed
8
+
9
+ define_model_callbacks :destroy
10
+
11
+ before_new -> { self.destroyed = false; true }
12
+
13
+ self.physically_destroy = true
14
+ end
15
+
16
+ class_methods do
17
+ def physically_destroy?
18
+ physically_destroy
19
+ end
20
+
21
+ def physically_destroy(flag = nil)
22
+ if flag.nil?
23
+ self.class_variable_get(:@@physically_destroy)
24
+ else
25
+ self.physically_destroy = flag
26
+ end
27
+ end
28
+ end
29
+
30
+ def destroyed?
31
+ destroyed
32
+ end
33
+
34
+ def destroy
35
+ run_callbacks :destroy do
36
+ if self.class.physically_destroy?
37
+ self.class.index(self, unindex: true)
38
+ else
39
+ self.class.index(self, destroy: true)
40
+ end
41
+ self.destroyed = true
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,79 @@
1
+ module Elos::Repository::Adapter::Elos::Model::Persistable
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ attr_accessor :persisted
6
+
7
+ define_model_callbacks :save, :create, :update
8
+
9
+ before_new -> { self.persisted = !!@_attrs.delete(:_persisted); true }
10
+ end
11
+
12
+ class_methods do
13
+ def create(attrs = {})
14
+ obj = new(attrs)
15
+ obj.save
16
+ obj
17
+ end
18
+
19
+ def create!(attrs = {})
20
+ obj = new(attrs)
21
+ obj.save!
22
+ obj
23
+ end
24
+ end
25
+
26
+ def persisted?
27
+ persisted
28
+ end
29
+
30
+ def save
31
+ _save
32
+ end
33
+
34
+ def save!
35
+ _save(raise_error: true)
36
+ end
37
+
38
+ def update(attrs = {})
39
+ assign_attributes(attrs)
40
+ save
41
+ end
42
+
43
+ def update!(attrs = {})
44
+ assign_attributes(attrs)
45
+ save!
46
+ end
47
+
48
+ private
49
+
50
+ def _save(raise_error: false, callback: true)
51
+ return false unless raise_error ? validate! : valid?
52
+ optionally_run_callbacks(:save, callback: callback) do
53
+ if persisted?
54
+ optionally_run_callbacks(:update, callback: callback) do
55
+ _save_core
56
+ end
57
+ else
58
+ optionally_run_callbacks(:create, callback: callback) do
59
+ _save_core
60
+ self.persisted = true
61
+ end
62
+ end
63
+ end
64
+ true
65
+ end
66
+
67
+ def optionally_run_callbacks(method, callback: true, &block)
68
+ if callback
69
+ run_callbacks(method, &block)
70
+ else
71
+ block.()
72
+ end
73
+ end
74
+
75
+ def _save_core
76
+ r = reindex
77
+ self.id ||= r
78
+ end
79
+ end
@@ -0,0 +1,15 @@
1
+ module Elos::Repository::Adapter::Elos::Model::Reindexable
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ reindex -> do
6
+ scan do |obj|
7
+ obj.reindex
8
+ end
9
+ end
10
+ end
11
+
12
+ def reindex(destroy: false)
13
+ self.class.index(self, destroy: destroy)
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module Elos::Repository::Adapter::Elos::Model::Unindexable
2
+ extend ActiveSupport::Concern
3
+
4
+ def unindex
5
+ self.class.index(obj, unindex: true)
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module Elos::Repository::Adapter::Elos::Model::Validatable
2
+ extend ActiveSupport::Concern
3
+
4
+ def validate!
5
+ return true if valid?
6
+ raise Elos::Errors::ValidationFailed.new
7
+ end
8
+ end
@@ -0,0 +1,24 @@
1
+ module Elos::Repository::Adapter::Elos::Scanable
2
+ extend ActiveSupport::Concern
3
+
4
+ class_methods do
5
+ def scan(batch_size = nil, &block)
6
+ _scan(batch_size) do |hit|
7
+ block.(new(hit['_source'].merge(id: hit['_id'], _persisted: true)))
8
+ end
9
+ end
10
+
11
+ protected
12
+
13
+ def _scan(batch_size = nil, index_name: read_alias_name, &block)
14
+ batch_size ||= 100
15
+ scroll_id = client.search(index: index_name, type: type_name, search_type: :scan, scroll: '1h', body: { query: { match_all: {} }, size: batch_size })['_scroll_id']
16
+ while r = client.scroll(scroll: '1h', scroll_id: scroll_id) and (hits = r['hits']['hits']).present? do
17
+ scroll_id = r['_scroll_id']
18
+ hits.each do |hit|
19
+ block.(hit)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ module Elos::Repository::Adapter::Elos
2
+ extend ActiveSupport::Concern
3
+
4
+ include Elos::Index
5
+
6
+ included do
7
+ cattr_accessor :included_callbacks
8
+
9
+ self.included_callbacks = []
10
+
11
+ include Elos::Repository::Adapter::Elos::Migratable
12
+ include Elos::Repository::Adapter::Elos::Scanable
13
+ include Elos::Repository::Publishable
14
+ include Elos::Repository::Adapter::Elos::Model::Reindexable
15
+ include Elos::Repository::Adapter::Elos::Model::Unindexable
16
+ include Elos::Repository::Adapter::Elos::Model::Persistable
17
+ include Elos::Repository::Adapter::Elos::Model::Destroyable
18
+ include Elos::Repository::Adapter::Elos::Model::Validatable
19
+
20
+ included_callbacks.each { |callback| callback.() }
21
+
22
+ subscribe self
23
+
24
+ physically_destroy false
25
+ end
26
+
27
+ def self.reindex_all(indices = nil)
28
+ # indices ||= 結びつく全てのindexたち
29
+ # indicesのreindex全てをnestさせてその中でscanしてreindexしていく
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ module Elos::Repository::Publishable
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ cattr_accessor :subscribers
6
+
7
+ self.subscribers = []
8
+
9
+ proc = -> { after_save ->(obj) { subscribers.each { |s| s.index(obj) } } }
10
+ if respond_to?(:after_save)
11
+ proc.()
12
+ else
13
+ self.included_callbacks << proc
14
+ end
15
+ end
16
+
17
+ class_methods do
18
+ def publish_reindex
19
+ scan do |obj|
20
+ subscribers.each do |klass|
21
+ klass.index(obj)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ class Elos::Result
2
+ include Enumerable
3
+
4
+ def initialize(result)
5
+ @result = result
6
+ end
7
+
8
+ def each
9
+ result.each do |item|
10
+ yield item
11
+ end
12
+ end
13
+
14
+ def pluck(key)
15
+ map { |obj| obj.send(key) }
16
+ end
17
+
18
+ protected
19
+
20
+ def result
21
+ @result
22
+ end
23
+ end
data/lib/elos/version.rb CHANGED
@@ -1,3 +1,3 @@
1
- module Elos
2
- VERSION = "0.1.0"
1
+ class Elos
2
+ VERSION = '1.0.4'
3
3
  end
data/lib/elos.rb CHANGED
@@ -1,5 +1,5 @@
1
- require "elos/version"
1
+ require_relative 'initialize'
2
2
 
3
- module Elos
4
- # Your code goes here...
3
+ class Elos
4
+ include Elos::Configuration
5
5
  end
data/lib/initialize.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'active_support/all'
5
+
6
+ ActiveSupport::Dependencies.autoload_paths << File.expand_path('../../lib', __FILE__)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elos
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tetsuri Moriya
@@ -10,6 +10,34 @@ bindir: exe
10
10
  cert_chain: []
11
11
  date: 2015-05-23 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: 3.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.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
@@ -38,6 +66,62 @@ dependencies:
38
66
  - - "~>"
39
67
  - !ruby/object:Gem::Version
40
68
  version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
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: database_cleaner
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.2.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 1.2.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: activerecord
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: mysql2
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'
41
125
  description: Elasticsearch integration for Databases, such as ActiveRecord
42
126
  email:
43
127
  - tetsuri.moriya@gmail.com
@@ -54,10 +138,54 @@ files:
54
138
  - README.md
55
139
  - Rakefile
56
140
  - bin/console
141
+ - bin/push
142
+ - bin/rspec
57
143
  - bin/setup
144
+ - db/migrate/001_create_a_entry_repos.rb
145
+ - elos-0.1.0.gem
146
+ - elos-1.0.3.gem
58
147
  - elos.gemspec
59
148
  - lib/elos.rb
149
+ - lib/elos/configuration.rb
150
+ - lib/elos/criteria.rb
151
+ - lib/elos/data_object.rb
152
+ - lib/elos/errors/not_found.rb
153
+ - lib/elos/errors/validation_failed.rb
154
+ - lib/elos/index.rb
155
+ - lib/elos/index/core.rb
156
+ - lib/elos/index/indexable.rb
157
+ - lib/elos/index/locatable.rb
158
+ - lib/elos/index/mappings.rb
159
+ - lib/elos/index/model.rb
160
+ - lib/elos/index/model/assignable.rb
161
+ - lib/elos/index/model/identifiable.rb
162
+ - lib/elos/index/model/initializable.rb
163
+ - lib/elos/index/raw_helpers.rb
164
+ - lib/elos/index/refreshable.rb
165
+ - lib/elos/index/reindexable.rb
166
+ - lib/elos/index/searchable.rb
167
+ - lib/elos/index/subscribable.rb
168
+ - lib/elos/index/unindexable.rb
169
+ - lib/elos/lock.rb
170
+ - lib/elos/query_builder/base.rb
171
+ - lib/elos/query_builder/builtin/match_all_query_builder.rb
172
+ - lib/elos/query_builder/builtin/where_query_builder.rb
173
+ - lib/elos/query_builder/filters.rb
174
+ - lib/elos/query_builder/queries.rb
175
+ - lib/elos/repository/adapter/active_record.rb
176
+ - lib/elos/repository/adapter/active_record/scanable.rb
177
+ - lib/elos/repository/adapter/elos.rb
178
+ - lib/elos/repository/adapter/elos/migratable.rb
179
+ - lib/elos/repository/adapter/elos/model/destroyable.rb
180
+ - lib/elos/repository/adapter/elos/model/persistable.rb
181
+ - lib/elos/repository/adapter/elos/model/reindexable.rb
182
+ - lib/elos/repository/adapter/elos/model/unindexable.rb
183
+ - lib/elos/repository/adapter/elos/model/validatable.rb
184
+ - lib/elos/repository/adapter/elos/scanable.rb
185
+ - lib/elos/repository/publishable.rb
186
+ - lib/elos/result.rb
60
187
  - lib/elos/version.rb
188
+ - lib/initialize.rb
61
189
  homepage: https://github.com/pandora2000/elos
62
190
  licenses:
63
191
  - MIT
@@ -83,4 +211,3 @@ signing_key:
83
211
  specification_version: 4
84
212
  summary: Elasticsearch integration for Databases
85
213
  test_files: []
86
- has_rdoc: