Class: Appfuel::Repository::Base
- Inherits:
-
Object
- Object
- Appfuel::Repository::Base
- Includes:
- Application::AppContainer
- Defined in:
- lib/appfuel/storage/repository/base.rb
Overview
The generic repository behavior. This represents repo behavior that is agnostic to any storage system. The following is a definition of this patter by Martin Fowler:
"The repository mediates between the domain and data mapping
layers using a collection-like interface for accessing domain
objects."
"Conceptually, a Repository encapsulates the set of objects persisted
in a data store and the operations performed over them, providing a
more object-oriented view of the persistence layer."
https://martinfowler.com/eaaCatalog/repository.html
While we are not a full repository pattern, we are evolving into it. All repositories have access to the application container. They register themselves into the container, as well as handling the cache from the container.
Direct Known Subclasses
Db::Repository, Dynamodb::Repository, ElasticSearch::Repository, Memory::Repository, WebApi::Repository
Class Attribute Summary collapse
-
.mapper ⇒ Mapper
Mapper holds specific knowledge of storage to domain mappings.
Class Method Summary collapse
-
.cache ⇒ Hash
A cache of already resolved domain objects.
-
.container_class_type ⇒ String
Used when the concrete class is being registered, to construct the container key as a path.
-
.create_mapper(maps = nil) ⇒ Mapper
Factory method to create a mapper.
-
.inherited(klass) ⇒ Object
Stage the concrete class that is inheriting this for registration.
Instance Method Summary collapse
-
#apply_query_conditions(_result, _criteria, _settings) ⇒ Object
Query conditions can only be applied by a specific type of repo, like a database or elastic search repo.
- #build(type:, name:, storage:, **inputs) ⇒ Object
- #build_criteria(criteria, settings = nil) ⇒ Object
- #build_default_entity(domain_name:, storage:) ⇒ Object
-
#build_domains(_result, _criteria, _settings) ⇒ Object
Domain resolution can only be applied by specific repos.
-
#create_settings(settings = {}) ⇒ Object
Factory method to create repo settings.
- #criteria?(value) ⇒ Boolean
-
#execute_query_method(query_method, criteria, settings) ⇒ Object
Validate the method exists and call it with the criteria and settings objects.
- #exists?(criteria) ⇒ Boolean
-
#find_entity_builder(domain_name:, type:) ⇒ Object
features.membership.presenters.hash.user global.presenters.user.
- #generate_uuid ⇒ Object
- #mapper ⇒ Mapper
- #query(criteria, settings = {}) ⇒ Object
-
#query_setup(criteria, settings) ⇒ Object
The first method called in the query life cycle.
- #timestamp ⇒ Object
- #to_entity(domain_name, type, storage) ⇒ Object
- #to_storage(entity, type, opts = {}) ⇒ Object
- #url_token(nbr = 32) ⇒ Object
Methods included from Application::AppContainer
#app_container, #feature_name, included, #qualify_container_key
Class Attribute Details
.mapper ⇒ Mapper
Mapper holds specific knowledge of storage to domain mappings
57 58 59 |
# File 'lib/appfuel/storage/repository/base.rb', line 57 def mapper @mapper ||= create_mapper end |
Class Method Details
.cache ⇒ Hash
A cache of already resolved domain objects
73 74 75 |
# File 'lib/appfuel/storage/repository/base.rb', line 73 def cache app_container[:repository_cache] end |
.container_class_type ⇒ String
Used when the concrete class is being registered, to construct the container key as a path.
37 38 39 |
# File 'lib/appfuel/storage/repository/base.rb', line 37 def container_class_type 'repositories' end |
.create_mapper(maps = nil) ⇒ Mapper
Factory method to create a mapper. Each concrete Repository will override this.
66 67 68 |
# File 'lib/appfuel/storage/repository/base.rb', line 66 def create_mapper(maps = nil) Mapper.new(container_root_name, maps) end |
.inherited(klass) ⇒ Object
Stage the concrete class that is inheriting this for registration. The reason we have to stage the registration is to give the code enough time to mixin the AppContainer functionality needed for registration. Therefore registration is defered until feature initialization.
49 50 51 52 |
# File 'lib/appfuel/storage/repository/base.rb', line 49 def inherited(klass) stage_class_for_registration(klass) nil end |
Instance Method Details
#apply_query_conditions(_result, _criteria, _settings) ⇒ Object
Query conditions can only be applied by a specific type of repo, like a database or elastic search repo. Because of this we will fail if this is not implemented
144 145 146 |
# File 'lib/appfuel/storage/repository/base.rb', line 144 def apply_query_conditions(_result, _criteria, _settings) method_not_implemented_error end |
#build(type:, name:, storage:, **inputs) ⇒ Object
206 207 208 209 |
# File 'lib/appfuel/storage/repository/base.rb', line 206 def build(type:, name:, storage:, **inputs) builder = find_entity_builder(type: type, domain_name: name) builder.call(storage, inputs) end |
#build_criteria(criteria, settings = nil) ⇒ Object
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/appfuel/storage/repository/base.rb', line 169 def build_criteria(criteria, settings = nil) settings ||= create_settings return criteria if criteria?(criteria) if criteria.is_a?(String) tree = settings.parser.parse(criteria) result = settings.transform.apply(tree) return result[:search] end unless criteria.is_a?(Hash) fail "criteria must be a String, Hash, or " + "Appfuel::Domain::SearchCriteria" end Criteria.build(criteria) end |
#build_default_entity(domain_name:, storage:) ⇒ Object
229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/appfuel/storage/repository/base.rb', line 229 def build_default_entity(domain_name:, storage:) storage = [storage] unless storage.is_a?(Array) storage_attrs = {} storage.each do |model| storage_attrs.merge!(mapper.model_attributes(model)) end hash = mapper.to_entity_hash(domain_name, storage_attrs) key = qualify_container_key(domain_name, "domains") app_container[key].new(hash) end |
#build_domains(_result, _criteria, _settings) ⇒ Object
Domain resolution can only be applied by specific repos. Because of this we fail if is not implmented
155 156 157 |
# File 'lib/appfuel/storage/repository/base.rb', line 155 def build_domains(_result, _criteria, _settings) method_not_implemented_error end |
#create_settings(settings = {}) ⇒ Object
Factory method to create repo settings. This holds things like pagination details, parser classes etc..
164 165 166 167 |
# File 'lib/appfuel/storage/repository/base.rb', line 164 def create_settings(settings = {}) return settings if settings.instance_of?(Settings) Settings.new(settings) end |
#criteria?(value) ⇒ Boolean
187 188 189 |
# File 'lib/appfuel/storage/repository/base.rb', line 187 def criteria?(value) value.instance_of?(Criteria) end |
#execute_query_method(query_method, criteria, settings) ⇒ Object
Validate the method exists and call it with the criteria and settings objects
91 92 93 94 95 96 97 |
# File 'lib/appfuel/storage/repository/base.rb', line 91 def execute_query_method(query_method, criteria, settings) unless respond_to?(query_method) fail "Could not execute query method (#{query_method})" end public_send(query_method, criteria, settings) end |
#exists?(criteria) ⇒ Boolean
191 192 193 194 |
# File 'lib/appfuel/storage/repository/base.rb', line 191 def exists?(criteria) expr = criteria.fiilters mapper.exists?(expr) end |
#find_entity_builder(domain_name:, type:) ⇒ Object
features.membership.presenters.hash.user global.presenters.user
key => db_model key => db_model
216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/appfuel/storage/repository/base.rb', line 216 def find_entity_builder(domain_name:, type:) key = qualify_container_key(domain_name, "domain_builders.#{type}") container = app_container unless container.key?(key) return ->(data, inputs = {}) { build_default_entity(domain_name: domain_name, storage: data) } end container[key] end |
#generate_uuid ⇒ Object
242 243 244 |
# File 'lib/appfuel/storage/repository/base.rb', line 242 def generate_uuid SecureRandom.uuid end |
#mapper ⇒ Mapper
80 81 82 |
# File 'lib/appfuel/storage/repository/base.rb', line 80 def mapper self.class.mapper end |
#query(criteria, settings = {}) ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/appfuel/storage/repository/base.rb', line 114 def query(criteria, settings = {}) settings = create_settings(settings) criteria = build_criteria(criteria, settings) if settings.manual_query? query_method = settings.manual_query return execute_query_method(query_method, criteria, settings) end begin result = query_setup(criteria, settings) result = handle_query_conditions(criteria, result, settings) build_domains(criteria, result, settings) rescue => e msg = "query failed for #{criteria.domain_name}: " + "#{e.class} #{e.}" error = RuntimeError.new(msg) error.set_backtrace(e.backtrace) raise error end end |
#query_setup(criteria, settings) ⇒ Object
The first method called in the query life cycle. It setups up the query method used to return a query relation for the next method in the life cycle. This query method will return a query relation produced by the concrete repo for that domain. The relation is specific to the type of repo, a db repo will return an ActiveRecordRelation for example.
109 110 111 112 |
# File 'lib/appfuel/storage/repository/base.rb', line 109 def query_setup(criteria, settings) query_method = "#{criteria.domain_basename}_query" execute_query_method(query_method, criteria, settings) end |
#timestamp ⇒ Object
251 252 253 |
# File 'lib/appfuel/storage/repository/base.rb', line 251 def Time.now.utc.iso8601 end |
#to_entity(domain_name, type, storage) ⇒ Object
200 201 202 203 204 |
# File 'lib/appfuel/storage/repository/base.rb', line 200 def to_entity(domain_name, type, storage) key = qualify_container_key(domain_name, "domains") hash = mapper.to_entity_hash(domain_name, type, storage) app_container[key].new(hash) end |
#to_storage(entity, type, opts = {}) ⇒ Object
196 197 198 |
# File 'lib/appfuel/storage/repository/base.rb', line 196 def to_storage(entity, type, opts = {}) mapper.to_storage(entity, type, opts) end |
#url_token(nbr = 32) ⇒ Object
246 247 248 249 |
# File 'lib/appfuel/storage/repository/base.rb', line 246 def url_token(nbr = 32) nbr = Integer(nbr) SecureRandom.urlsafe_base64(nbr) end |