realm-elasticsearch 0.7.3 → 0.7.4

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
  SHA256:
3
- metadata.gz: acda028de64439232c09263509ce32717e19e34b0845c6e40ee3da69f89f3ead
4
- data.tar.gz: b05e2cb65596bbeacf951af3d14ef4cfd28e59bbb0c8cb62c37a3a6bd19509f4
3
+ metadata.gz: fc4e001333235b5600c7ce9b60900e459602ef0fc8839afe5bbf1d3682f55234
4
+ data.tar.gz: a61adf8e0fb2e1e1f56c7675a6e74b53b0303afb373e37d9c4f2a6923f1b0ef0
5
5
  SHA512:
6
- metadata.gz: 5a0e53f266e2d48b0e21401e66c0d661682976fa954d1ae2db1e00a433403cb2845c925e0917e8ead489a8d8f2bdb2db28c3fec5e8af75c00eaf757f5b77a093
7
- data.tar.gz: 99a15268d00a042d40d9753cbb99827923c693527d64c28cc62ddf1209860735d04b5093cf968287eb6aa3a5e565b36b9842c4cb11f2c520839e0510606c33a3
6
+ metadata.gz: 50d755a44887aebd67e0065fe5afe31247f26198c587346f95e2e46cb07bf0fbb1728075e80afce80df288ced113d9c535371b759d8424baac72948b278b8ba8
7
+ data.tar.gz: ad410eb69a58cd4ad369696e642c411c4dd03b134e2fb6f3aa80e6c22f21394cd27cced354a9d98d8ffb2ac28d6ab8816d60ffcf381fff871cb0302142c02780
@@ -0,0 +1,15 @@
1
+ # rubocop:disable Naming/FileName
2
+ # frozen_string_literal: true
3
+
4
+ require 'zeitwerk'
5
+
6
+ loader = Zeitwerk::Loader.for_gem
7
+ loader.ignore(__FILE__)
8
+ loader.setup
9
+
10
+ require 'realm-core'
11
+ require 'typhoeus'
12
+ require 'elasticsearch'
13
+ require 'realm/elasticsearch/plugin'
14
+
15
+ # rubocop:enable Naming/FileName
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Realm
4
+ module Elasticsearch
5
+ class Gateway
6
+ def initialize(url:, **options)
7
+ @url = url
8
+ @client_options = options.slice(:adapter, :retry_on_failure, :request_timeout)
9
+ end
10
+
11
+ def health
12
+ issues = []
13
+ index_names = Repository.subclasses.map(&:index_name)
14
+ begin
15
+ issues << 'One or more indexes missing' unless client.indices.exists(index: index_names)
16
+ rescue StandardError => e
17
+ issues << "Elasticsearch connection error: #{e.full_message}"
18
+ end
19
+ HealthStatus.from_issues(issues)
20
+ end
21
+
22
+ def method_missing(...)
23
+ client.send(...)
24
+ end
25
+
26
+ def respond_to_missing?(...)
27
+ client.respond_to?(...)
28
+ end
29
+
30
+ private
31
+
32
+ def client
33
+ @client ||= ::Elasticsearch::Client.new(default_config.merge(@client_options))
34
+ end
35
+
36
+ def default_config
37
+ {
38
+ url: @url,
39
+ adapter: :typhoeus,
40
+ retry_on_failure: 3,
41
+ request_timeout: 30,
42
+ }
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Realm
4
+ module Elasticsearch
5
+ class Plugin < Realm::Plugin
6
+ def self.setup(config, container)
7
+ return unless config.persistence_gateway[:type] == :elasticsearch
8
+
9
+ container.register_factory(Gateway, **config.persistence_gateway, as: 'persistence.gateway')
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module Realm
6
+ module Elasticsearch
7
+ module RakeTasks
8
+ class << self
9
+ def setup(engine_name, engine_root: nil, url: ENV['ELASTICSEARCH_URL'])
10
+ return unless url
11
+
12
+ client = ::Elasticsearch::Client.new(url: url)
13
+
14
+ Rake.application.in_namespace(:es) do
15
+ Rake::Task.define_task(:create_indexes) do
16
+ with_definitions(engine_name, engine_root) do |index, config|
17
+ client.indices.create(index: index, body: config) unless client.indices.exists(index: index)
18
+ end
19
+ end
20
+
21
+ Rake::Task.define_task(:drop_indexes) do
22
+ with_definitions(engine_name, engine_root) do |index, _config|
23
+ client.indices.delete(index: index) if client.indices.exists(index: index)
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def with_definitions(engine_name, engine_root)
32
+ engine_root ||= Rails.root.join('engines', engine_name.to_s)
33
+ Dir.glob(File.join(engine_root, 'elasticsearch/indexes/*.yaml')).each do |path|
34
+ yield File.basename(path, '.yaml'), YAML.safe_load(File.read(path))
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module Realm
6
+ module Elasticsearch
7
+ class Repository
8
+ def self.repo_name(value = :not_provided)
9
+ @repo_name = value.to_sym unless value == :not_provided
10
+ @repo_name = name.demodulize.underscore unless defined?(@repo_name)
11
+ @repo_name
12
+ end
13
+
14
+ def self.index_name(value = :not_provided)
15
+ @index_name = value.to_sym unless value == :not_provided
16
+ @index_name = repo_name.pluralize unless defined?(@index_name)
17
+ @index_name
18
+ end
19
+
20
+ def initialize(client)
21
+ @client = client
22
+ end
23
+
24
+ def find(id:)
25
+ single(client.get(index: index_name, id: id))
26
+ rescue ::Elasticsearch::Transport::Transport::Errors::NotFound
27
+ nil
28
+ end
29
+
30
+ def all
31
+ multiple(raw_search(query: { match_all: {} }))
32
+ end
33
+
34
+ def create(id: nil, **attrs)
35
+ client.index(index: index_name, type: '_doc', id: id, body: attrs, refresh: refresh?)
36
+ rescue ::Elasticsearch::Transport::Transport::Errors::Conflict
37
+ raise Realm::Persistence::Conflict
38
+ end
39
+
40
+ def update(id:, **attrs)
41
+ raw_update(id, doc: attrs)
42
+ end
43
+
44
+ def upsert(id:, **attrs)
45
+ raw_update(id, doc: attrs, doc_as_upsert: true)
46
+ end
47
+
48
+ def delete(id:)
49
+ client.delete(index: index_name, type: '_doc', id: id, refresh: refresh?)
50
+ true
51
+ rescue ::Elasticsearch::Transport::Transport::Errors::NotFound
52
+ false
53
+ end
54
+
55
+ def search_by(params)
56
+ multiple(raw_search(query: { bool: { must: match_params(params) } }))
57
+ end
58
+
59
+ def delete_by(params)
60
+ client.delete_by_query(
61
+ index: index_name,
62
+ refresh: refresh?,
63
+ body: { query: {
64
+ bool: {
65
+ must: match_params(params),
66
+ },
67
+ } },
68
+ )
69
+ end
70
+
71
+ def raw_update(id, body = {})
72
+ client.update(index: index_name, type: '_doc', id: id, body: body, refresh: refresh?)
73
+ end
74
+
75
+ def raw_search(yaml: nil, options: {}, **body)
76
+ client.search(index: index_name, body: yaml ? YAML.safe_load(yaml) : body, **options)
77
+ end
78
+
79
+ def truncate!
80
+ client.delete_by_query(
81
+ index: index_name,
82
+ body: { query: { match_all: {} } },
83
+ conflicts: 'proceed',
84
+ refresh: refresh?,
85
+ )
86
+ end
87
+
88
+ private
89
+
90
+ attr_reader :client
91
+
92
+ def refresh?
93
+ # impacts performance so should be used only in TEST env
94
+ # TODO: remove dependency on Rails
95
+ defined?(::Rails) && ::Rails.env.test?
96
+ end
97
+
98
+ def single(result)
99
+ id = result['_id'].then { |i| i.to_i.positive? ? i.to_i : i }
100
+ result['_source'].merge(id: id).deep_symbolize_keys
101
+ end
102
+
103
+ def multiple(results)
104
+ docs = results.dig('hits', 'hits').map { |doc| single(doc) }
105
+ { docs: docs }
106
+ end
107
+
108
+ def match_params(params)
109
+ params.map { |(key, value)| { match: { key => value } } }
110
+ end
111
+
112
+ def index_name
113
+ self.class.index_name
114
+ end
115
+ end
116
+ end
117
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: realm-elasticsearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.3
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - developers@reevoo.com
@@ -114,8 +114,11 @@ executables: []
114
114
  extensions: []
115
115
  extra_rdoc_files: []
116
116
  files:
117
- - README.md
118
- - Rakefile
117
+ - lib/realm-elasticsearch.rb
118
+ - lib/realm/elasticsearch/gateway.rb
119
+ - lib/realm/elasticsearch/plugin.rb
120
+ - lib/realm/elasticsearch/rake_tasks.rb
121
+ - lib/realm/elasticsearch/repository.rb
119
122
  homepage:
120
123
  licenses:
121
124
  - MIT
data/README.md DELETED
@@ -1,40 +0,0 @@
1
- # Realm
2
-
3
- Domain layer framework following Domain-driven/CQRS design principles.
4
-
5
- [![Build status](https://badge.buildkite.com/346cce75f6c31e0a41bb98b198e85eb6b722243624459fad9c.svg)](https://buildkite.com/reevoo/realm)
6
-
7
- ## Service layers
8
-
9
- We follow the standard MVC design pattern of Rails but giving the model layer more structure and guidance regarding where
10
- to put your code. The model is split into domain layer (using our [Realm](https://github.com/reevoo/smart-mono/tree/master/gems/realm) library)
11
- and persistence layer (using [ROM](https://rom-rb.org/) library). The individual components are explained in the following section.
12
-
13
- ![Service layers](https://confluence-connect.gliffy.net/embed/image/d02d04b1-5e40-415f-b7ba-3a631efa9bf3.png?utm_medium=live&utm_source=custom)
14
-
15
- Advanced components are shown in lighter color, those will be needed only later on as the service domain logic grows.
16
-
17
- ## Model layer components
18
-
19
- ![Service external components](https://confluence-connect.gliffy.net/embed/image/c593fcc2-304e-47c3-8e3c-b0cc09e0ed54.png?utm_medium=live&utm_source=custom)
20
-
21
- Each service has one **domain** module which consists of multiple [**aggregate**](https://martinfowler.com/bliki/DDD_Aggregate.html) modules.
22
- Aggregate is a cluster of domain objects that can be treated as a single unit. The only way for outer world to communicate
23
- with aggregate is by **queries** and **commands**. Query exposes aggregate's internal state and command changes it.
24
- The state of an aggregate is represented by tree of **entities** with one being the aggregate root and zero or more dependent
25
- entities with *belongs_to* relation to the root entity. The state of an aggregate (entity tree) is persisted
26
- and retrieved by **repository**. There is generally one repository per aggregate unless we split the read/write
27
- (query/command) persistence model for that particular domain. The repository uses **relations** to access the database
28
- tables. Each relation class represents one table.
29
-
30
-
31
- ## Where to put my code as it grows?
32
-
33
- TODO
34
-
35
-
36
- ## Roadmap
37
-
38
- - [ ] Support Ruby 3
39
- - [ ] Make it work outside of Rails engines
40
- - [ ] Support multiple persistence gateways in one runtime
data/Rakefile DELETED
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- begin
4
- require 'bundler/setup'
5
- rescue LoadError
6
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
- end
8
-
9
- require 'rdoc/task'
10
-
11
- RDoc::Task.new(:rdoc) do |rdoc|
12
- rdoc.rdoc_dir = 'rdoc'
13
- rdoc.title = 'Realm'
14
- rdoc.options << '--line-numbers'
15
- rdoc.rdoc_files.include('README.md')
16
- rdoc.rdoc_files.include('lib/**/*.rb')
17
- end
18
-
19
- require 'bundler/gem_tasks'