artirix_data_models 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/artirix_data_models.svg)](http://badge.fury.io/rb/artirix_data_models)
|
5
|
+
[![Build Status](https://travis-ci.org/artirix/artirix_data_models.svg?branch=master)](https://travis-ci.org/artirix/artirix_data_models)
|
6
|
+
[![Code Climate](https://codeclimate.com/github/artirix/artirix_data_models.png)](https://codeclimate.com/github/artirix/artirix_data_models)
|
7
|
+
[![Code Climate Coverage](https://codeclimate.com/github/artirix/artirix_data_models/coverage.png)](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
|