realm-elasticsearch 0.7.3 → 0.7.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.
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'