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
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.
- #mapper ⇒ Mapper
- #query(criteria, settings = {}) ⇒ Object
-
#query_setup(criteria, settings) ⇒ Object
The first method called in the query life cycle.
- #to_entity(domain_name, storage) ⇒ Object
- #to_storage(entity, exclude = []) ⇒ Object
Methods included from Application::AppContainer
#app_container, included, #qualify_container_key
Class Attribute Details
.mapper ⇒ Mapper
Mapper holds specific knowledge of storage to domain mappings
55 56 57 |
# File 'lib/appfuel/storage/repository/base.rb', line 55 def mapper @mapper ||= create_mapper end |
Class Method Details
.cache ⇒ Hash
A cache of already resolved domain objects
71 72 73 |
# File 'lib/appfuel/storage/repository/base.rb', line 71 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.
35 36 37 |
# File 'lib/appfuel/storage/repository/base.rb', line 35 def container_class_type 'repositories' end |
.create_mapper(maps = nil) ⇒ Mapper
Factory method to create a mapper. Each concrete Repository will override this.
64 65 66 |
# File 'lib/appfuel/storage/repository/base.rb', line 64 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.
47 48 49 50 |
# File 'lib/appfuel/storage/repository/base.rb', line 47 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
142 143 144 |
# File 'lib/appfuel/storage/repository/base.rb', line 142 def apply_query_conditions(_result, _criteria, _settings) method_not_implemented_error end |
#build(type:, name:, storage:, **inputs) ⇒ Object
204 205 206 207 |
# File 'lib/appfuel/storage/repository/base.rb', line 204 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
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/appfuel/storage/repository/base.rb', line 167 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
227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/appfuel/storage/repository/base.rb', line 227 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
153 154 155 |
# File 'lib/appfuel/storage/repository/base.rb', line 153 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..
162 163 164 165 |
# File 'lib/appfuel/storage/repository/base.rb', line 162 def create_settings(settings = {}) return settings if settings.instance_of?(Settings) Settings.new(settings) end |
#criteria?(value) ⇒ Boolean
185 186 187 |
# File 'lib/appfuel/storage/repository/base.rb', line 185 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
89 90 91 92 93 94 95 |
# File 'lib/appfuel/storage/repository/base.rb', line 89 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
189 190 191 192 |
# File 'lib/appfuel/storage/repository/base.rb', line 189 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
214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/appfuel/storage/repository/base.rb', line 214 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 |
#mapper ⇒ Mapper
78 79 80 |
# File 'lib/appfuel/storage/repository/base.rb', line 78 def mapper self.class.mapper end |
#query(criteria, settings = {}) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/appfuel/storage/repository/base.rb', line 112 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.
107 108 109 110 |
# File 'lib/appfuel/storage/repository/base.rb', line 107 def query_setup(criteria, settings) query_method = "#{criteria.domain_basename}_query" execute_query_method(query_method, criteria, settings) end |
#to_entity(domain_name, storage) ⇒ Object
198 199 200 201 202 |
# File 'lib/appfuel/storage/repository/base.rb', line 198 def to_entity(domain_name, storage) key = qualify_container_key(domain_name, "domains") hash = mapper.to_entity_hash(domain_name, storage) app_container[key].new(hash) end |
#to_storage(entity, exclude = []) ⇒ Object
194 195 196 |
# File 'lib/appfuel/storage/repository/base.rb', line 194 def to_storage(entity, exclude = []) mapper.to_storage(entity, exclude) end |