artirix_data_models 0.5.0
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 +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.travis.yml +17 -0
- data/Gemfile +18 -0
- data/LICENSE.txt +22 -0
- data/README.md +230 -0
- data/Rakefile +6 -0
- data/artirix_data_models.gemspec +36 -0
- data/lib/artirix_data_models/aggregation.rb +58 -0
- data/lib/artirix_data_models/aggregations_factory.rb +45 -0
- data/lib/artirix_data_models/cache_service.rb +168 -0
- data/lib/artirix_data_models/cached_action_adaptor/get.rb +22 -0
- data/lib/artirix_data_models/cached_action_adaptor/get_full.rb +80 -0
- data/lib/artirix_data_models/cached_action_adaptor/get_some.rb +22 -0
- data/lib/artirix_data_models/cached_action_adaptor.rb +118 -0
- data/lib/artirix_data_models/dao.rb +172 -0
- data/lib/artirix_data_models/dao_registry.rb +94 -0
- data/lib/artirix_data_models/daos/basic_model_dao.rb +132 -0
- data/lib/artirix_data_models/daos/model_fields_dao.rb +37 -0
- data/lib/artirix_data_models/es_collection.rb +221 -0
- data/lib/artirix_data_models/fake_response_factory.rb +88 -0
- data/lib/artirix_data_models/gateway_response_adaptors/model_adaptor.rb +68 -0
- data/lib/artirix_data_models/gateways/data_gateway.rb +135 -0
- data/lib/artirix_data_models/model.rb +414 -0
- data/lib/artirix_data_models/spec_support/fake_mode.rb +24 -0
- data/lib/artirix_data_models/spec_support/gateway_mock.rb +23 -0
- data/lib/artirix_data_models/spec_support/shared_examples/a_readonly_active_model_like_artirix_data_models.rb +20 -0
- data/lib/artirix_data_models/spec_support/shared_examples/an_artirix_data_model_dao.rb +97 -0
- data/lib/artirix_data_models/spec_support/shared_examples/an_artirix_data_model_model.rb +224 -0
- data/lib/artirix_data_models/spec_support/shared_examples/has_attributes.rb +32 -0
- data/lib/artirix_data_models/spec_support/shared_examples.rb +4 -0
- data/lib/artirix_data_models/spec_support.rb +3 -0
- data/lib/artirix_data_models/version.rb +3 -0
- data/lib/artirix_data_models.rb +126 -0
- data/spec/artirix_data_models/dao_registry_spec.rb +21 -0
- data/spec/artirix_data_models/es_collection_spec.rb +45 -0
- data/spec/artirix_data_models/gateways/data_gateway_spec.rb +218 -0
- data/spec/artirix_data_models/gateways/gateway_response_adaptors/model_adaptor_spec.rb +78 -0
- data/spec/artirix_data_models/model_fields_dao_spec.rb +40 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/.keep +0 -0
- data/spec/support/a_finder_enabled_ui_model_dao.rb +36 -0
- data/spec/support/a_search_enabled_ui_model_dao.rb +40 -0
- data/spec/support/artirix_data_models.rb +1 -0
- metadata +281 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: f6a90c9b7956cc31c38374094fd416d8d4e9dd09
|
|
4
|
+
data.tar.gz: 3cf3edcbf15f24b14b7beb57943b9f93bb12dbaa
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 568c1f293797134592df3bd5bca0ba3daacf0ede0aff7770004b5a3aae4821f9ae8eb2df8a668607bff2bfcb4f31bc6ea1a8c334b213084c19763ddebe578714
|
|
7
|
+
data.tar.gz: 5e27b33a022ccb060b174fb4466fb62bea449cc8c6ff8a5b3b405482b20f0f7c14eba73eeeddd4f62b31d447b0f2999d0afa8cf2485f095eda3ff3d425dea8bc
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
language: ruby
|
|
2
|
+
rvm:
|
|
3
|
+
- 2.1.2
|
|
4
|
+
before_install: gem install bundler -v 1.10.3
|
|
5
|
+
|
|
6
|
+
addons:
|
|
7
|
+
code_climate:
|
|
8
|
+
repo_token: 84e47c3e41ba9fbc2d639c167be45aa3f6c077374015309dac005ab51f713d83
|
|
9
|
+
|
|
10
|
+
script: 'bundle exec rake spec'
|
|
11
|
+
|
|
12
|
+
notifications:
|
|
13
|
+
email:
|
|
14
|
+
recipients:
|
|
15
|
+
- eturino@eturino.com
|
|
16
|
+
on_failure: change
|
|
17
|
+
on_success: never
|
data/Gemfile
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
source 'https://rubygems.org'
|
|
2
|
+
|
|
3
|
+
# Specify your gem's dependencies in artirix_data_models.gemspec
|
|
4
|
+
gemspec
|
|
5
|
+
|
|
6
|
+
group :development, :test do
|
|
7
|
+
gem 'pry'
|
|
8
|
+
gem 'pry-nav'
|
|
9
|
+
gem 'pry-stack_explorer'
|
|
10
|
+
gem 'pry-doc'
|
|
11
|
+
gem 'pry-rescue'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
group :test do
|
|
15
|
+
gem 'fakeredis', require: "fakeredis/rspec"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
gem 'codeclimate-test-reporter', :group => :test, :require => nil
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2014 Eduardo Turiño
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# ArtirixDataModels
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
[](http://badge.fury.io/rb/artirix_data_models)
|
|
5
|
+
[](https://travis-ci.org/artirix/artirix_data_models)
|
|
6
|
+
[](https://codeclimate.com/github/artirix/artirix_data_models)
|
|
7
|
+
[](https://codeclimate.com/github/artirix/artirix_data_models)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
This gem provides the tools for building Data Models (ActiveModel compliant objects that only receive attributes on initialisation),
|
|
11
|
+
with their DAOs (Data Access Objects, the ones responsible for loading them up), the EsCollection objects (collection of
|
|
12
|
+
objects, paginatable and with extra features), and tools that allow them to work.
|
|
13
|
+
|
|
14
|
+
Its goal is to provide a set of Read Only model objects that receive their data from some sort of Data API.
|
|
15
|
+
|
|
16
|
+
It's designed to work assuming JSON APIs and ElasticSearch responses.
|
|
17
|
+
|
|
18
|
+
# TODO:
|
|
19
|
+
- usage doc
|
|
20
|
+
- change Cache to use [artirix_cache_service](https://github.com/artirix/artirix_cache_service)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
### Model
|
|
26
|
+
|
|
27
|
+
TODO:
|
|
28
|
+
|
|
29
|
+
### DAO
|
|
30
|
+
|
|
31
|
+
TODO:
|
|
32
|
+
|
|
33
|
+
### EsCollection
|
|
34
|
+
|
|
35
|
+
TODO:
|
|
36
|
+
|
|
37
|
+
#### Pagination
|
|
38
|
+
|
|
39
|
+
TODO:
|
|
40
|
+
|
|
41
|
+
### The Registry
|
|
42
|
+
|
|
43
|
+
Your app should extend the `ArtirixDataModels::DAORegistry`. We can override the `setup_config` method to add extra loaders.
|
|
44
|
+
|
|
45
|
+
**important: do not forget to call `super` on `setup_config`.**
|
|
46
|
+
|
|
47
|
+
Also, the Registry class that you want to use in your app should have in its definition a call to `self.mark_as_main_registry`. This call must be **after the override of `setup_config`.**
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
class DAORegistry < ArtirixDataModels::DAORegistry
|
|
51
|
+
def setup_config
|
|
52
|
+
super
|
|
53
|
+
|
|
54
|
+
set_loader(:aggregations_factory) { AggregationsFactory.new }
|
|
55
|
+
|
|
56
|
+
set_loader(:yacht) { YachtDAO.new gateway: get(:gateway) }
|
|
57
|
+
set_loader(:article) { ArticleDAO.new gateway: get(:gateway) }
|
|
58
|
+
set_loader(:broker) { BrokerDAO.new gateway: get(:gateway) }
|
|
59
|
+
|
|
60
|
+
set_loader(:artirix_hub_api_gateway) { ArtirixDataModels::DataGateway.new connection: ArtirixHubApiService::ConnectionLoader.connection }
|
|
61
|
+
set_loader(:lead) { LeadDAO.new gateway: get(:artirix_hub_api_gateway) }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
# AFTER defining setup_config
|
|
66
|
+
self.mark_as_main_registry
|
|
67
|
+
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### initializer
|
|
72
|
+
|
|
73
|
+
An initializer should be added for extra configuration.
|
|
74
|
+
|
|
75
|
+
We can enable pagination with either `will_paginate` or `kaminari`.
|
|
76
|
+
|
|
77
|
+
We can also disable cache at a lib level.
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
require 'artirix_data_models'
|
|
81
|
+
|
|
82
|
+
# pagination
|
|
83
|
+
ArtirixDataModels::EsCollection.work_with_kaminari
|
|
84
|
+
# or ArtirixDataModels::EsCollection.work_with_will_paginate
|
|
85
|
+
|
|
86
|
+
#cache
|
|
87
|
+
ArtirixDataModels.disable_cache unless Rails.configuration.dao_cache_enabled
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
### Cache
|
|
92
|
+
|
|
93
|
+
By default all `get`, `get_full` and `get_some` calls to on a normal DAO will be cached. The response body and status of the Gateway is cached (if it is successful or a 404 error).
|
|
94
|
+
|
|
95
|
+
The cache key and the options will be determined by the cache adaptor, set by the DAO. The options are loaded from SimpleConfig, merging `default_options` with the first most specific option hash.
|
|
96
|
+
|
|
97
|
+
For example, a DAO `get` call will try to load the first options hash defined from the following list:
|
|
98
|
+
- "dao_#{dao_name}_get_options"
|
|
99
|
+
- "dao_#{dao_name}_options"
|
|
100
|
+
- 'dao_get_options'
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
example of config options (using SimpleConfig)
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
SimpleConfig.for(:site) do
|
|
107
|
+
set :cache_app_prefix, 'ui'
|
|
108
|
+
|
|
109
|
+
group :cache_options do
|
|
110
|
+
group :default_options do
|
|
111
|
+
set :expires_in, 15.minutes
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
group :dao_get_full_options do
|
|
115
|
+
set :expires_in, 1.hour
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
group :dao_get_full_no_time_options do
|
|
119
|
+
set :expires_in, 5.minutes
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
group :dao_yacht_get_full_options do
|
|
123
|
+
set :expires_in, 15.minutes
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Cache can be disabled at lib level with `ArtirixDataModels.disable_cache`
|
|
130
|
+
|
|
131
|
+
### Rails integration
|
|
132
|
+
|
|
133
|
+
if Rails is defined when the lib is first used, then the `logger` will be assigned to `Rails.logger` by default, and
|
|
134
|
+
`cache` will be `Rails.cache` by default.
|
|
135
|
+
|
|
136
|
+
### Fake Mode
|
|
137
|
+
|
|
138
|
+
TODO:
|
|
139
|
+
|
|
140
|
+
fake mode will be enabled if:
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
SimpleConfig.for(:site) do
|
|
144
|
+
group :data_fake_mode do
|
|
145
|
+
set :article, false # NO FAKE MODE
|
|
146
|
+
set :broker, false # WITH FAKE MODE
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Use with RSpec
|
|
152
|
+
|
|
153
|
+
#### Custom DAO Registry
|
|
154
|
+
|
|
155
|
+
For the use of a custom DAO Registry, it is recomended to actually require it on the test helper:
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
in spec/rails_helper.rb:
|
|
159
|
+
|
|
160
|
+
```ruby
|
|
161
|
+
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
|
162
|
+
ENV["RAILS_ENV"] ||= 'test'
|
|
163
|
+
require 'rspec/given'
|
|
164
|
+
require 'spec_helper'
|
|
165
|
+
require File.expand_path("../../config/environment", __FILE__)
|
|
166
|
+
require 'rspec/rails'
|
|
167
|
+
# Add additional requires below this line. Rails is not loaded until this point!
|
|
168
|
+
|
|
169
|
+
# force the use of the custom DAORegistry
|
|
170
|
+
require 'dao_registry'
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### Spec Support
|
|
174
|
+
|
|
175
|
+
add the spec support in your support files or rails_helper file:
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
```ruby
|
|
179
|
+
require 'artirix_data_models/spec_support'
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
This depends on SimpleConfig!
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
SimpleConfig.for(:site) do
|
|
186
|
+
group :data_gateway do
|
|
187
|
+
set :url, c
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### FactoryGirl
|
|
193
|
+
|
|
194
|
+
In order to use FactoryGirl with these Models, we need to specify:
|
|
195
|
+
|
|
196
|
+
1. the objects cannot be saved, so we need to specify `skip_create` to avoid it.
|
|
197
|
+
2. the setting of the data is only to be done on the model's initialisation, not with public setters.
|
|
198
|
+
For that, we need to specify: `initialize_with { new(attributes) }`
|
|
199
|
+
|
|
200
|
+
```ruby
|
|
201
|
+
|
|
202
|
+
FactoryGirl.define do
|
|
203
|
+
factory :article do
|
|
204
|
+
# no save call
|
|
205
|
+
skip_create
|
|
206
|
+
|
|
207
|
+
# in our models we have private setters -> we need the attributes to be
|
|
208
|
+
# passed on object initialisation
|
|
209
|
+
initialize_with { new(attributes) }
|
|
210
|
+
|
|
211
|
+
sequence(:id)
|
|
212
|
+
title { Faker::Lorem.sentence }
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## TODO
|
|
218
|
+
|
|
219
|
+
1. Documentation
|
|
220
|
+
2. clean `basic_dao` (probably not backwards compatible, so we'll do it in a new major release)
|
|
221
|
+
3. use [artirix_cache_service](https://github.com/artirix/artirix_cache_service) instead of this implementation (might be not backwards compatible. If so: new major release)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
## Changes
|
|
226
|
+
|
|
227
|
+
### v.0.5.0
|
|
228
|
+
|
|
229
|
+
- opening gem as is to the public.
|
|
230
|
+
- still a lot of TODOs in the documentation
|
data/Rakefile
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'artirix_data_models/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = 'artirix_data_models'
|
|
8
|
+
spec.version = ArtirixDataModels::VERSION
|
|
9
|
+
spec.authors = ['Eduardo Turiño']
|
|
10
|
+
spec.email = ['eturino@artirix.com']
|
|
11
|
+
spec.summary = 'Data Models (read only model) and Data Layer connection lib'
|
|
12
|
+
spec.description = %q{used in Boat International UI and Admin apps}
|
|
13
|
+
spec.homepage = ''
|
|
14
|
+
spec.license = 'MIT'
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
17
|
+
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']
|
|
20
|
+
|
|
21
|
+
spec.add_dependency 'activesupport'
|
|
22
|
+
spec.add_dependency 'simpleconfig'
|
|
23
|
+
spec.add_dependency 'oj'
|
|
24
|
+
spec.add_dependency 'faraday'
|
|
25
|
+
spec.add_dependency 'keyword_init', '~> 1.3'
|
|
26
|
+
spec.add_dependency 'naught'
|
|
27
|
+
|
|
28
|
+
spec.add_development_dependency 'kaminari', '~> 0.16'
|
|
29
|
+
spec.add_development_dependency 'will_paginate', '~> 3.0'
|
|
30
|
+
|
|
31
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
|
32
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
|
33
|
+
spec.add_development_dependency 'rspec'
|
|
34
|
+
spec.add_development_dependency 'rspec-given'
|
|
35
|
+
spec.add_development_dependency 'faker'
|
|
36
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module ArtirixDataModels
|
|
2
|
+
class Aggregation < Struct.new(:name, :buckets)
|
|
3
|
+
|
|
4
|
+
include Enumerable
|
|
5
|
+
|
|
6
|
+
delegate :each, :empty?, to: :buckets
|
|
7
|
+
|
|
8
|
+
def self.from_json(definition, value_class = Value)
|
|
9
|
+
buckets = definition[:buckets].map do |bucket|
|
|
10
|
+
value_class.new definition[:name].to_sym, bucket[:name], bucket[:count]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
new definition[:name].to_sym, buckets
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def pretty_name
|
|
17
|
+
I18n.t("aggregations.#{name.to_s.gsub('.', '_')}.name", default: default_pretty_name)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def default_pretty_name
|
|
21
|
+
name
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def non_empty_buckets
|
|
25
|
+
buckets.reject { |x| x.empty? }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def data_hash
|
|
29
|
+
{
|
|
30
|
+
name: name,
|
|
31
|
+
buckets: buckets.map(&:data_hash)
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class Value < Struct.new(:aggregation_name, :name, :count)
|
|
36
|
+
|
|
37
|
+
def pretty_name
|
|
38
|
+
tranlsation_key = "aggregations.#{aggregation_name.to_s.gsub('.', '_')}.buckets.#{name.to_s.gsub('.', '_')}"
|
|
39
|
+
I18n.t(tranlsation_key, default: default_pretty_name)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def default_pretty_name
|
|
43
|
+
name
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def empty?
|
|
47
|
+
count == 0
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def data_hash
|
|
51
|
+
{
|
|
52
|
+
name: name,
|
|
53
|
+
count: count
|
|
54
|
+
}
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module ArtirixDataModels
|
|
2
|
+
class AggregationsFactory
|
|
3
|
+
DEFAULT_FACTORY = ->(aggregation) { Aggregation.from_json aggregation }
|
|
4
|
+
DEFAULT_COLLECTION_CLASS_NAME = ''.freeze
|
|
5
|
+
|
|
6
|
+
# singleton instance
|
|
7
|
+
def initialize
|
|
8
|
+
@_loaders = Hash.new { |h, k| h[k] = {} }
|
|
9
|
+
setup_config
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def setup_config
|
|
13
|
+
# To be Extended
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def build_from_json(aggregation, collection_class = nil)
|
|
17
|
+
get_loader(aggregation[:name], collection_class).call aggregation
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def get_loader(aggregation_name, collection_class)
|
|
21
|
+
@_loaders[collection_class.to_s][aggregation_name.to_s] ||
|
|
22
|
+
@_loaders[DEFAULT_COLLECTION_CLASS_NAME][aggregation_name.to_s] ||
|
|
23
|
+
DEFAULT_FACTORY
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def set_loader(aggregation_name, collection_class = nil, loader = nil, &block)
|
|
27
|
+
if block
|
|
28
|
+
@_loaders[collection_class.to_s][aggregation_name.to_s] = block
|
|
29
|
+
elsif loader.respond_to? :call
|
|
30
|
+
@_loaders[collection_class.to_s][aggregation_name.to_s] = loader
|
|
31
|
+
else
|
|
32
|
+
raise ArgumentError, "no block and no loader given for key #{key}"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# static methods
|
|
37
|
+
def self.set_loader(aggregation_name, collection_class, loader = nil, &block)
|
|
38
|
+
instance.set_loader aggregation_name, collection_class, loader, &block
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.build_from_json(aggregation_name, collection_class)
|
|
42
|
+
instance.build_from_json aggregation_name, collection_class
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
module ArtirixDataModels::CacheService
|
|
2
|
+
|
|
3
|
+
def self.digest_element(element)
|
|
4
|
+
Digest::SHA1.hexdigest element.to_s
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def self.first_options(*options, return_if_none: :default)
|
|
8
|
+
key = options.detect { |x| OptionsStore.has? x }
|
|
9
|
+
return OptionsStore.get(key) if key.present?
|
|
10
|
+
|
|
11
|
+
case return_if_none
|
|
12
|
+
when NilClass
|
|
13
|
+
nil
|
|
14
|
+
when :default
|
|
15
|
+
OptionsStore.default.dup
|
|
16
|
+
else
|
|
17
|
+
{}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.method_missing(m, *args, &block)
|
|
22
|
+
method = m.to_s
|
|
23
|
+
|
|
24
|
+
if KeyCleaner.valid_method method
|
|
25
|
+
KeyCleaner.final_key(m, *args)
|
|
26
|
+
|
|
27
|
+
elsif OptionsStore.valid_method method
|
|
28
|
+
OptionsStore.send m, *args, &block
|
|
29
|
+
|
|
30
|
+
elsif Expirer.valid_method method
|
|
31
|
+
Expirer.send m, *args, &block
|
|
32
|
+
|
|
33
|
+
else
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.respond_to_missing?(m, include_all = false)
|
|
39
|
+
method = m.to_s
|
|
40
|
+
|
|
41
|
+
if KeyCleaner.valid_method method
|
|
42
|
+
true
|
|
43
|
+
|
|
44
|
+
elsif OptionsStore.valid_method method
|
|
45
|
+
OptionsStore.respond_to? m, include_all
|
|
46
|
+
|
|
47
|
+
elsif Expirer.valid_method method
|
|
48
|
+
Expirer.respond_to? m, include_all
|
|
49
|
+
|
|
50
|
+
else
|
|
51
|
+
super
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
module KeyCleaner
|
|
58
|
+
def self.valid_method(method_name)
|
|
59
|
+
method_name.end_with? '_key'
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.final_key(m, *args)
|
|
63
|
+
cleaned = clean_key_section(m, *args)
|
|
64
|
+
CacheStoreHelper.final_key cleaned
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
def self.clean_key_section(key, *args)
|
|
69
|
+
key_name = clean_key_name key
|
|
70
|
+
a = clean_key_args args
|
|
71
|
+
suffix = a.present? ? "/#{a}" : ''
|
|
72
|
+
"#{key_name}#{suffix}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.clean_key_name(key)
|
|
76
|
+
key.to_s.gsub(/_key$/, '').to_sym
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def self.clean_key_args(args)
|
|
80
|
+
args.map { |x| x.try(:cache_key) || x.to_s }.join '/'
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
module OptionsStore
|
|
85
|
+
def self.valid_method(method_name)
|
|
86
|
+
method_name.end_with? '_options'
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def self.method_missing(m, *args, &block)
|
|
90
|
+
if has?(m)
|
|
91
|
+
get(m)
|
|
92
|
+
else
|
|
93
|
+
super
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def self.respond_to_missing?(m, include_all = false)
|
|
98
|
+
has?(m) || super
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
def self.has?(name)
|
|
103
|
+
option_store.respond_to?(name)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def self.get(name)
|
|
107
|
+
default.merge(get_particular(name))
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def self.get_particular(name)
|
|
111
|
+
Hash(option_store.send(name))
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def self.default
|
|
115
|
+
@default ||= Hash(option_store.default_options)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def self.option_store
|
|
119
|
+
@option_store ||= SimpleConfig.for(:site).try(:cache_options) || disabled_options_store
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def self.disabled_options_store
|
|
123
|
+
DisabledOptionsStore.new
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
class DisabledOptionsStore
|
|
127
|
+
def method_missing(m, *args, &block)
|
|
128
|
+
{}
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def respond_to_missing?(m, include_all = false)
|
|
132
|
+
true
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
module Expirer
|
|
138
|
+
def self.valid_method(method_name)
|
|
139
|
+
method_name.start_with? 'expire_'
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def self.expire_cache(pattern = nil)
|
|
143
|
+
CacheStoreHelper.delete_matched(pattern)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# we use `delete_matched` method -> it will work fine with Redis but it seems that it won't with Memcached
|
|
148
|
+
module CacheStoreHelper
|
|
149
|
+
def self.final_key(key_value)
|
|
150
|
+
"#{prefix}__#{key_value}"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def self.final_pattern(pattern)
|
|
154
|
+
suf = pattern.present? ? "#{pattern}*" : ''
|
|
155
|
+
"*#{prefix}*#{suf}"
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def self.delete_matched(pattern = nil)
|
|
159
|
+
return false unless ArtirixDataModels.cache.present?
|
|
160
|
+
ArtirixDataModels.cache.delete_matched final_pattern(pattern)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def self.prefix
|
|
164
|
+
SimpleConfig.for(:site).try(:cache_app_prefix)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
class ArtirixDataModels::CachedActionAdaptor::Get < ArtirixDataModels::CachedActionAdaptor
|
|
2
|
+
|
|
3
|
+
attr_reader :dao_name, :model_pk
|
|
4
|
+
|
|
5
|
+
def initialize(dao_name:, model_pk:, **extra_options)
|
|
6
|
+
@dao_name = dao_name
|
|
7
|
+
@model_pk = model_pk
|
|
8
|
+
|
|
9
|
+
super(**extra_options)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def load_cache_key
|
|
13
|
+
ArtirixDataModels::CacheService.dao_get_key(dao_name, model_pk)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def load_cache_options
|
|
17
|
+
ArtirixDataModels::CacheService.first_options "dao_#{dao_name}_get_options",
|
|
18
|
+
"dao_#{dao_name}_options",
|
|
19
|
+
'dao_get_options',
|
|
20
|
+
return_if_none: :default
|
|
21
|
+
end
|
|
22
|
+
end
|