appfuel 0.2.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/.codeclimate.yml +25 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +1156 -0
- data/.travis.yml +19 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +9 -0
- data/README.md +38 -0
- data/Rakefile +6 -0
- data/appfuel.gemspec +42 -0
- data/bin/console +7 -0
- data/bin/setup +8 -0
- data/lib/appfuel.rb +210 -0
- data/lib/appfuel/application.rb +4 -0
- data/lib/appfuel/application/app_container.rb +223 -0
- data/lib/appfuel/application/container_class_registration.rb +22 -0
- data/lib/appfuel/application/container_key.rb +201 -0
- data/lib/appfuel/application/qualify_container_key.rb +76 -0
- data/lib/appfuel/application/root.rb +140 -0
- data/lib/appfuel/cli_msg_request.rb +19 -0
- data/lib/appfuel/configuration.rb +14 -0
- data/lib/appfuel/configuration/definition_dsl.rb +175 -0
- data/lib/appfuel/configuration/file_loader.rb +61 -0
- data/lib/appfuel/configuration/populate.rb +95 -0
- data/lib/appfuel/configuration/search.rb +45 -0
- data/lib/appfuel/db_model.rb +16 -0
- data/lib/appfuel/domain.rb +7 -0
- data/lib/appfuel/domain/criteria.rb +436 -0
- data/lib/appfuel/domain/domain_name_parser.rb +44 -0
- data/lib/appfuel/domain/dsl.rb +247 -0
- data/lib/appfuel/domain/entity.rb +242 -0
- data/lib/appfuel/domain/entity_collection.rb +87 -0
- data/lib/appfuel/domain/expr.rb +127 -0
- data/lib/appfuel/domain/value_object.rb +7 -0
- data/lib/appfuel/errors.rb +104 -0
- data/lib/appfuel/feature.rb +2 -0
- data/lib/appfuel/feature/action_loader.rb +25 -0
- data/lib/appfuel/feature/initializer.rb +43 -0
- data/lib/appfuel/handler.rb +6 -0
- data/lib/appfuel/handler/action.rb +17 -0
- data/lib/appfuel/handler/base.rb +103 -0
- data/lib/appfuel/handler/command.rb +18 -0
- data/lib/appfuel/handler/inject_dsl.rb +88 -0
- data/lib/appfuel/handler/validator_dsl.rb +256 -0
- data/lib/appfuel/initialize.rb +70 -0
- data/lib/appfuel/initialize/initializer.rb +68 -0
- data/lib/appfuel/msg_request.rb +207 -0
- data/lib/appfuel/predicates.rb +10 -0
- data/lib/appfuel/presenter.rb +18 -0
- data/lib/appfuel/presenter/base.rb +7 -0
- data/lib/appfuel/repository.rb +73 -0
- data/lib/appfuel/repository/base.rb +72 -0
- data/lib/appfuel/repository/initializer.rb +19 -0
- data/lib/appfuel/repository/mapper.rb +203 -0
- data/lib/appfuel/repository/mapping_dsl.rb +210 -0
- data/lib/appfuel/repository/mapping_entry.rb +76 -0
- data/lib/appfuel/repository/mapping_registry.rb +121 -0
- data/lib/appfuel/repository_runner.rb +60 -0
- data/lib/appfuel/request.rb +53 -0
- data/lib/appfuel/response.rb +96 -0
- data/lib/appfuel/response_handler.rb +79 -0
- data/lib/appfuel/root_module.rb +31 -0
- data/lib/appfuel/run_error.rb +9 -0
- data/lib/appfuel/storage.rb +3 -0
- data/lib/appfuel/storage/db.rb +4 -0
- data/lib/appfuel/storage/db/active_record_model.rb +42 -0
- data/lib/appfuel/storage/db/mapper.rb +213 -0
- data/lib/appfuel/storage/db/migration_initializer.rb +42 -0
- data/lib/appfuel/storage/db/migration_runner.rb +15 -0
- data/lib/appfuel/storage/db/migration_tasks.rb +18 -0
- data/lib/appfuel/storage/db/repository.rb +231 -0
- data/lib/appfuel/storage/db/repository_query.rb +13 -0
- data/lib/appfuel/storage/file.rb +1 -0
- data/lib/appfuel/storage/file/base.rb +32 -0
- data/lib/appfuel/storage/memory.rb +2 -0
- data/lib/appfuel/storage/memory/mapper.rb +30 -0
- data/lib/appfuel/storage/memory/repository.rb +37 -0
- data/lib/appfuel/types.rb +53 -0
- data/lib/appfuel/validation.rb +80 -0
- data/lib/appfuel/validation/validator.rb +59 -0
- data/lib/appfuel/validation/validator_pipe.rb +47 -0
- data/lib/appfuel/version.rb +3 -0
- metadata +335 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
module Appfuel
|
2
|
+
class Request
|
3
|
+
attr_reader :action_route, :feature, :action, :inputs, :namespace
|
4
|
+
|
5
|
+
def initialize(action_route, inputs = {})
|
6
|
+
unless inputs.respond_to?(:to_h)
|
7
|
+
fail "inputs must respond to :to_h"
|
8
|
+
end
|
9
|
+
@inputs = inputs.to_h
|
10
|
+
@action_route, @feature, @action = parse_route(action_route)
|
11
|
+
@namespace = "features.#{feature}.actions.#{action}"
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
# The service route is a forward slash separated string consisting of two
|
17
|
+
# parts. The first part is the feature that holds the action and the
|
18
|
+
# second is the action itself.
|
19
|
+
#
|
20
|
+
# @example 'offers/create'
|
21
|
+
# feature is Offers
|
22
|
+
# action is Create
|
23
|
+
#
|
24
|
+
# @param route [String]
|
25
|
+
# @return [Array]
|
26
|
+
def parse_route(route)
|
27
|
+
feature_name, action_name = route.to_s.split('/')
|
28
|
+
|
29
|
+
feature_name = handle_parsed_string(feature_name)
|
30
|
+
action_name = handle_parsed_string(action_name)
|
31
|
+
|
32
|
+
handle_empty_feature(feature_name)
|
33
|
+
handle_empty_action(action_name)
|
34
|
+
|
35
|
+
|
36
|
+
[route, feature_name, action_name]
|
37
|
+
end
|
38
|
+
|
39
|
+
def handle_parsed_string(value)
|
40
|
+
value.to_s.strip
|
41
|
+
end
|
42
|
+
|
43
|
+
def handle_empty_feature(feature_name)
|
44
|
+
return unless feature_name.empty?
|
45
|
+
fail "feature is missing, action route must be like <feature/action>"
|
46
|
+
end
|
47
|
+
|
48
|
+
def handle_empty_action(action_name)
|
49
|
+
return unless action_name.empty?
|
50
|
+
fail "action is missing, action route must be like <feature/action>"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Appfuel
|
2
|
+
# Every action or command must return a response. A response is either
|
3
|
+
# ok or it has errors. You can retrieve the results with the "ok" method
|
4
|
+
# or the errors with the "error" method
|
5
|
+
class Response
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# Convience method for creating a successfull response
|
9
|
+
#
|
10
|
+
# @param result Hash the successfull resultset
|
11
|
+
# @reuturn Response
|
12
|
+
def ok(result = nil)
|
13
|
+
self.new(ok: result)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Convience method for creating an error response. It understands
|
17
|
+
# how to handle a SpCore::Error object. Any thing that
|
18
|
+
# is not a hash or can't be converted to a hash is assumed to be
|
19
|
+
# a string and converted into a general_error
|
20
|
+
#
|
21
|
+
# @param data Hash the errors hash
|
22
|
+
# @reuturn Response
|
23
|
+
def error(data)
|
24
|
+
result = format_result_hash(data, default_key: :general_error)
|
25
|
+
result = result[:errors] if result.key?(:errors)
|
26
|
+
self.new(errors: result)
|
27
|
+
end
|
28
|
+
|
29
|
+
def format_result_hash(data, default_key:)
|
30
|
+
if data.is_a?(Hash)
|
31
|
+
result = data
|
32
|
+
elsif data.respond_to?(:to_h)
|
33
|
+
result = data.to_h
|
34
|
+
else
|
35
|
+
result = {default_key => data.to_s}
|
36
|
+
end
|
37
|
+
|
38
|
+
result.symbolize_keys
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_reader :ok, :errors
|
43
|
+
|
44
|
+
# @param data [Hash]
|
45
|
+
# @return [Response]
|
46
|
+
def initialize(data = {})
|
47
|
+
result = format_result_hash(data)
|
48
|
+
|
49
|
+
# when no ok key and no errors key the assume
|
50
|
+
# it is a successfull response
|
51
|
+
if !result.key?(:ok) && !result.key?(:errors)
|
52
|
+
result = {ok: result}
|
53
|
+
end
|
54
|
+
|
55
|
+
@ok = result[:ok]
|
56
|
+
@errors = nil
|
57
|
+
if result.key?(:errors)
|
58
|
+
@ok = nil
|
59
|
+
@errors = Errors.new(result[:errors])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def errors?
|
64
|
+
!ok?
|
65
|
+
end
|
66
|
+
alias_method :failure?, :errors?
|
67
|
+
|
68
|
+
def error_messages
|
69
|
+
return {} if ok?
|
70
|
+
|
71
|
+
errors.messages
|
72
|
+
end
|
73
|
+
|
74
|
+
def ok?
|
75
|
+
errors.nil?
|
76
|
+
end
|
77
|
+
alias_method :success?, :ok?
|
78
|
+
|
79
|
+
def to_h
|
80
|
+
if ok?
|
81
|
+
{ok: ok}
|
82
|
+
else
|
83
|
+
errors.to_h
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_json
|
88
|
+
to_h.to_json
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
def format_result_hash(data)
|
93
|
+
self.class.format_result_hash(data, default_key: :ok)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Appfuel
|
2
|
+
class ResponseHandler
|
3
|
+
attr_reader :response_class
|
4
|
+
|
5
|
+
def initialize(response_class = Response)
|
6
|
+
@response_class = response_class
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_response(data)
|
10
|
+
return data if response?(data)
|
11
|
+
return error(data) if error_data?(data)
|
12
|
+
ok(data)
|
13
|
+
end
|
14
|
+
|
15
|
+
def response?(data)
|
16
|
+
data.is_a?(response_class)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Determine if the data given is an error by looking at its class or
|
20
|
+
# checking if it is a hash with the key :errors
|
21
|
+
#
|
22
|
+
# @param data
|
23
|
+
# @return Bool
|
24
|
+
def error_data?(data)
|
25
|
+
case
|
26
|
+
when data.kind_of?(::StandardError) || data.is_a?(Errors)
|
27
|
+
true
|
28
|
+
when data.is_a?(Hash)
|
29
|
+
data.key?(:errors)
|
30
|
+
else
|
31
|
+
false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# This is used when returning results back to the action handler. We
|
36
|
+
# use this to indicate it was a successful response
|
37
|
+
#
|
38
|
+
# @param ok Hash
|
39
|
+
# @return Response
|
40
|
+
def ok(value = nil)
|
41
|
+
response_class.ok(value)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Convert a number of different error formats into hash and use that to
|
45
|
+
# build the response
|
46
|
+
#
|
47
|
+
# @param args StandardError|ActiveModel::Errors|Hash|Errors|Symbol|Response
|
48
|
+
# @return Response
|
49
|
+
def error(*args)
|
50
|
+
error = args.shift
|
51
|
+
case
|
52
|
+
when error.kind_of?(ActiveModel::Errors)
|
53
|
+
messages = error.messages
|
54
|
+
when error.kind_of?(StandardError)
|
55
|
+
key = error.class.to_s.underscore.to_sym
|
56
|
+
backtrace_key = "#{key}_backtrace".to_sym
|
57
|
+
messages = {
|
58
|
+
errors: {
|
59
|
+
key => [error.message],
|
60
|
+
backtrace_key => error.backtrace || []
|
61
|
+
}
|
62
|
+
}
|
63
|
+
when error.is_a?(Hash)
|
64
|
+
messages = error.key?(:errors) ? error : {errors: error}
|
65
|
+
when error.is_a?(Errors)
|
66
|
+
messages = error.to_h
|
67
|
+
|
68
|
+
when args.length >= 1
|
69
|
+
messages = {errors: {error => args}}
|
70
|
+
when error.is_a?(response_class)
|
71
|
+
return error
|
72
|
+
else
|
73
|
+
messages = {errors: {general_error: [error.to_s]}}
|
74
|
+
end
|
75
|
+
|
76
|
+
response_class.error(messages)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Appfuel
|
2
|
+
# The root module is an import concept. It represents the services top most
|
3
|
+
# namespace. It is assumed that the root module will have a feature module,
|
4
|
+
# its child, and that feature module will have many action classes inside it.
|
5
|
+
module RootModule
|
6
|
+
|
7
|
+
def root_module=(value)
|
8
|
+
fail "Root module must be a module" unless value.is_a?(Module)
|
9
|
+
@root_module = value
|
10
|
+
end
|
11
|
+
|
12
|
+
def root_module
|
13
|
+
@root_module ||= root_module_const
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def root_module_const
|
19
|
+
name = root_module_name
|
20
|
+
unless Kernel.const_defined?(name)
|
21
|
+
fail "Root module is not defined (#{name})"
|
22
|
+
end
|
23
|
+
|
24
|
+
Kernel.const_get(name)
|
25
|
+
end
|
26
|
+
|
27
|
+
def root_module_name
|
28
|
+
self.to_s.split("::").first
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Appfuel
|
2
|
+
module Db
|
3
|
+
class ActiveRecordModel < ActiveRecord::Base
|
4
|
+
# ChangeOrder::Global::Db::FooBar
|
5
|
+
#
|
6
|
+
# ChangeOrder::Membership::Peristence::Db::Account
|
7
|
+
# ChangeOrder::Membership::Persistence::Yaml::Account
|
8
|
+
#
|
9
|
+
# ChangeOrder::Membership::Domains::Account
|
10
|
+
#
|
11
|
+
# Appfuel.mapping membership.account,
|
12
|
+
# db: account, yaml: account do
|
13
|
+
# map id, account.id
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# module Membership
|
17
|
+
# module Db
|
18
|
+
#
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
#
|
23
|
+
# global.db.foobar
|
24
|
+
#
|
25
|
+
# features.membership.db.account
|
26
|
+
# features.membership.yaml.account
|
27
|
+
#
|
28
|
+
#
|
29
|
+
self.abstract_class = true
|
30
|
+
include Appfuel::Application::AppContainer
|
31
|
+
def self.inherited(klass)
|
32
|
+
super
|
33
|
+
register_container_class(klass)
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def entity_attributes
|
38
|
+
attributes.symbolize_keys.select {|_,value| !value.nil?}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
module Appfuel
|
2
|
+
module Db
|
3
|
+
class Mapper < Appfuel::Repository::Mapper
|
4
|
+
|
5
|
+
# Determines if an domain entity exists for this key
|
6
|
+
#
|
7
|
+
# @param key [String, Symbol]
|
8
|
+
# @return [Boolean]
|
9
|
+
def entity_mapped?(name)
|
10
|
+
registry.entity?(name)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns the active record model from a map for a given entity
|
14
|
+
#
|
15
|
+
# @raise [RuntimeError] if entity key does not exist
|
16
|
+
# @raise [RuntimeError] if map key does not exist
|
17
|
+
#
|
18
|
+
# @param entity [String] encoded "feature.entity"
|
19
|
+
# @param domain_attr [String] attribute of entity
|
20
|
+
# @return [DbModel]
|
21
|
+
def db_class_key(entity_name, entity_attr)
|
22
|
+
entry = find(entity_name, entity_attr)
|
23
|
+
db_class_key = entry.storage(:db)
|
24
|
+
|
25
|
+
mapp.storage(entity, domain_attr)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Converts an entity expression into a valid active record expresion with
|
29
|
+
# string expresion (array canditions) and value(s)
|
30
|
+
#
|
31
|
+
# @param expr [Domain::Expr]
|
32
|
+
# @param results [Hash]
|
33
|
+
# @return [DbExpr] Returns a valid active record expresion
|
34
|
+
def create_db_expr(expr)
|
35
|
+
DbExpr.new(qualified_db_column(expr), expr.op, expr.value)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Validates if a record exists in the table that matches the array with
|
39
|
+
# the conditions given.
|
40
|
+
#
|
41
|
+
# @param criteria [Criteria]
|
42
|
+
# @return [Boolean]
|
43
|
+
def exists?(criteria)
|
44
|
+
domain_expr = criteria.exists_expr
|
45
|
+
domain_name = domain_expr.domain_name
|
46
|
+
domain_attr = domain_expr.domain_attr
|
47
|
+
|
48
|
+
db_expr = create_db_expr(domain_expr)
|
49
|
+
db_model = registry.db_class(domain_name, domain_attr)
|
50
|
+
db_model.exists?([db_expr.string, db_expr.values])
|
51
|
+
end
|
52
|
+
|
53
|
+
# Build a where expression from the mapped db class using the criteria.Ï
|
54
|
+
#
|
55
|
+
# @param criteria [Criteria]
|
56
|
+
# @param relation [DbModel, ActiveRecord::Relation]
|
57
|
+
# @return [DbModel, ActiveRecord::Relation]
|
58
|
+
def where(criteria, relation)
|
59
|
+
unless criteria.where?
|
60
|
+
fail "you must explicitly call :all when criteria has no exprs."
|
61
|
+
end
|
62
|
+
|
63
|
+
criteria.each do |domain_expr, op|
|
64
|
+
relation = if op == :or
|
65
|
+
relation.or(db_where(domain_expr, relation))
|
66
|
+
else
|
67
|
+
db_where(domain_expr, relation)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
relation
|
71
|
+
end
|
72
|
+
|
73
|
+
# Return qualified db column name from entity expression.
|
74
|
+
#
|
75
|
+
# @param expr [SpCore::Domain::Expr]
|
76
|
+
# @return db column name [String]
|
77
|
+
def qualified_db_column(expr)
|
78
|
+
table_name, column = db_table_column(expr)
|
79
|
+
"#{table_name}.#{column}"
|
80
|
+
end
|
81
|
+
|
82
|
+
# Determine Domain Mapentry and DbModel from entity expression.
|
83
|
+
#
|
84
|
+
# @param expr [SpCore::Domain::Expr]
|
85
|
+
# @return [table_name, column] [Array]
|
86
|
+
def db_table_column(expr)
|
87
|
+
entry = registry.find(expr.domain_name, expr.domain_attr)
|
88
|
+
db = registry.db_class_constant(entry.db_class)
|
89
|
+
[db.table_name, entry.db_column]
|
90
|
+
end
|
91
|
+
|
92
|
+
# Build an order by expression for the given db relation based on the
|
93
|
+
# criteria
|
94
|
+
#
|
95
|
+
# @param criteria [Criteria]
|
96
|
+
# @param relation [DbModel, ActiveRecord::Relation]
|
97
|
+
# @return [ActiveRecord::Relation]
|
98
|
+
def order(criteria, relation)
|
99
|
+
return relation unless criteria.order?
|
100
|
+
criteria.order.each do |expr|
|
101
|
+
db_column = qualified_db_column(expr)
|
102
|
+
direction = expr.value
|
103
|
+
relation = relation.order("#{db_column} #{direction}")
|
104
|
+
end
|
105
|
+
relation
|
106
|
+
end
|
107
|
+
|
108
|
+
# Eventhough there is no mapping here we add the interface for
|
109
|
+
# consistency.
|
110
|
+
#
|
111
|
+
# @param criteria [Criteria]
|
112
|
+
# @param relation [DbModel, ActiveRecord::Relation]
|
113
|
+
# @return [ActiveRecord::Relation]
|
114
|
+
def limit(criteria, relation)
|
115
|
+
return relation unless criteria.limit?
|
116
|
+
|
117
|
+
relation.limit(criteria.limit)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Map the entity expr to a hash of db_column => value and call
|
121
|
+
# on the relation using that.
|
122
|
+
#
|
123
|
+
# @note this is db library specific and needs to be moved to an adapter
|
124
|
+
#
|
125
|
+
# @param expr [Appfuel::Domain::Expr]
|
126
|
+
# @param relation [ActiveRecord::Relation]
|
127
|
+
# @return [ActiveRecord::Relation]
|
128
|
+
def db_where(domain_expr, relation)
|
129
|
+
db_expr = create_db_expr(domain_expr)
|
130
|
+
relation.where([db_expr.string, db_expr.values])
|
131
|
+
end
|
132
|
+
|
133
|
+
# Convert the entity into a hash of db tables that represent
|
134
|
+
# that entity. Each table has its own hash of mapped columns.
|
135
|
+
#
|
136
|
+
# @param domain [Appfuel::Domain::Entity]
|
137
|
+
# @param opts [Hash]
|
138
|
+
# @option exclued [Array] list of columns to exclude from mapping
|
139
|
+
#
|
140
|
+
# @return [Hash] each key is a table with a hash of column name/value
|
141
|
+
def to_storage(domain, opts = {})
|
142
|
+
excluded = opts[:exclude] || []
|
143
|
+
data = {}
|
144
|
+
each_entity_attr(domain.domain_name) do |entry|
|
145
|
+
column = entry.storage_attr
|
146
|
+
db_class = entry.storage(:db)
|
147
|
+
next if excluded.include?(column) || entry.skip?
|
148
|
+
|
149
|
+
data[db_class] = {} unless data.key?(db_class)
|
150
|
+
data[db_class][column] = entity_value(domain, entry)
|
151
|
+
end
|
152
|
+
data
|
153
|
+
end
|
154
|
+
|
155
|
+
# Handles entity value by checking if its a computed property,
|
156
|
+
# fetching the value and converting undefined values to nil.
|
157
|
+
#
|
158
|
+
# @param domain [Appfuel::Domain::Entity]
|
159
|
+
# @param map_entry [MappingEntity]
|
160
|
+
# @return the value
|
161
|
+
def entity_value(domain, entry)
|
162
|
+
value = retrieve_entity_value(domain, entry.domain_attr)
|
163
|
+
if entry.computed_attr?
|
164
|
+
value = entry.compute_attr(value)
|
165
|
+
end
|
166
|
+
|
167
|
+
value = nil if undefined?(value)
|
168
|
+
|
169
|
+
value
|
170
|
+
end
|
171
|
+
|
172
|
+
# @params value [mixed]
|
173
|
+
# @return [Boolean]
|
174
|
+
def undefined?(value)
|
175
|
+
value == Types::Undefined
|
176
|
+
end
|
177
|
+
|
178
|
+
# Fetch the value for the entity attribute. When the attribute name
|
179
|
+
# contains a '.' then traverse the dots and call the last attribute
|
180
|
+
# for the value
|
181
|
+
#
|
182
|
+
# @param domain [Appfuel::Domain::Entity]
|
183
|
+
# @param entity_attribute [String]
|
184
|
+
# @return the value
|
185
|
+
def retrieve_entity_value(domain, entity_attr)
|
186
|
+
chain = entity_attr.split('.')
|
187
|
+
target = domain
|
188
|
+
chain.each do |attr_method|
|
189
|
+
unless target.respond_to?(attr_method)
|
190
|
+
return nil
|
191
|
+
end
|
192
|
+
|
193
|
+
target = target.public_send(attr_method)
|
194
|
+
end
|
195
|
+
target
|
196
|
+
end
|
197
|
+
|
198
|
+
# Create nested hashes from string
|
199
|
+
#
|
200
|
+
# @param domain_attr [String]
|
201
|
+
# @param entity_value [String]
|
202
|
+
# @return [nested hash]
|
203
|
+
def create_entity_hash(domain_attr, entity_value)
|
204
|
+
domain_attr.split('.').reverse.inject(entity_value) { |a,n| {n => a}}
|
205
|
+
end
|
206
|
+
|
207
|
+
def model_attributes(relation)
|
208
|
+
ap relation
|
209
|
+
relation.attributes.select {|_, value| !value.nil?}
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|