appfuel 0.2.5 → 0.2.6

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/appfuel.gemspec +1 -1
  4. data/lib/appfuel/application/app_container.rb +0 -1
  5. data/lib/appfuel/application/dispatcher.rb +32 -0
  6. data/lib/appfuel/application/root.rb +4 -4
  7. data/lib/appfuel/application.rb +2 -1
  8. data/lib/appfuel/domain/domain_name_parser.rb +9 -5
  9. data/lib/appfuel/domain.rb +0 -7
  10. data/lib/appfuel/handler/base.rb +8 -14
  11. data/lib/appfuel/storage/db/mapper.rb +31 -35
  12. data/lib/appfuel/storage/db/repository.rb +53 -121
  13. data/lib/appfuel/storage/repository/base.rb +246 -0
  14. data/lib/appfuel/storage/repository/criteria.rb +317 -0
  15. data/lib/appfuel/{domain → storage/repository}/expr.rb +1 -1
  16. data/lib/appfuel/storage/repository/expr_conjunction.rb +41 -0
  17. data/lib/appfuel/{domain → storage/repository}/expr_parser.rb +10 -22
  18. data/lib/appfuel/{domain → storage/repository}/expr_transform.rb +7 -7
  19. data/lib/appfuel/{repository → storage/repository}/mapper.rb +8 -3
  20. data/lib/appfuel/storage/repository/order_expr.rb +51 -0
  21. data/lib/appfuel/storage/repository/runner.rb +62 -0
  22. data/lib/appfuel/storage/repository/search_parser.rb +50 -0
  23. data/lib/appfuel/storage/repository/search_transform.rb +58 -0
  24. data/lib/appfuel/{domain/criteria_settings.rb → storage/repository/settings.rb} +20 -5
  25. data/lib/appfuel/{repository.rb → storage/repository.rb} +13 -0
  26. data/lib/appfuel/storage.rb +1 -0
  27. data/lib/appfuel/version.rb +1 -1
  28. data/lib/appfuel.rb +0 -2
  29. metadata +21 -19
  30. data/lib/appfuel/domain/base_criteria.rb +0 -171
  31. data/lib/appfuel/domain/exists_criteria.rb +0 -57
  32. data/lib/appfuel/domain/expr_conjunction.rb +0 -27
  33. data/lib/appfuel/domain/search_criteria.rb +0 -137
  34. data/lib/appfuel/repository/base.rb +0 -86
  35. data/lib/appfuel/repository_runner.rb +0 -60
  36. /data/lib/appfuel/{repository → storage/repository}/initializer.rb +0 -0
  37. /data/lib/appfuel/{repository → storage/repository}/mapping_dsl.rb +0 -0
  38. /data/lib/appfuel/{repository → storage/repository}/mapping_entry.rb +0 -0
@@ -1,57 +0,0 @@
1
- module Appfuel
2
- module Domain
3
-
4
- # The Criteria represents the interface between the repositories and actions
5
- # or commands. The allow you to find entities in the application storage (
6
- # a database) without knowledge of that storage system. The criteria will
7
- # always refer to its queries in the domain language for which the repo is
8
- # responsible for mapping that query to its persistence layer.
9
- #
10
- # global.user
11
- # memberships.user
12
- #
13
- # exist: 'foo.bar exists id = 6'
14
- #
15
- # exits:
16
- # domain: 'foo.bar'
17
- # expr: 'id = 6'
18
- #
19
- # settings:
20
- # error_on_empty
21
- # parser
22
- # transform
23
- #
24
- #
25
- class ExistsCriteria < BaseCriteria
26
- #
27
- # @param domain [String] fully qualified domain name
28
- # @param opts [Hash] options for initializing criteria
29
- # @return [Criteria]
30
- def initialize(domain_name, data = {})
31
- super
32
- expr(data[:expr]) if data[:expr]
33
- end
34
-
35
- def filter(str)
36
- domain_expr = parse_expr(str)
37
- if filters?
38
- fail "A filter expression has already been assigned"
39
- end
40
-
41
- if domain_expr.conjunction?
42
- fail "Only simple domain expressions are allowed for exists criteria"
43
- end
44
-
45
- if domain_expr.qualified?
46
- fail "Only allows relative domain attributes"
47
- end
48
-
49
- @filters = qualify_expr(domain_expr)
50
- self
51
- end
52
-
53
- private
54
-
55
- end
56
- end
57
- end
@@ -1,27 +0,0 @@
1
- module Appfuel
2
- module Domain
3
- class ExprConjunction
4
- attr_reader :op, :left, :right
5
-
6
- def initialize(type, left, right)
7
- @op = type.to_s.downcase
8
- @left = left
9
- @right = right
10
- end
11
-
12
- def conjunction?
13
- true
14
- end
15
-
16
- def qualify_feature(feature, domain)
17
- left.qualify_feature(feature, domain)
18
- right.qualify_feature(feature, domain)
19
- end
20
-
21
- def qualify_global(domain)
22
- left.qualify_global(domain)
23
- right.qualify_global(domain)
24
- end
25
- end
26
- end
27
- end
@@ -1,137 +0,0 @@
1
- module Appfuel
2
- module Domain
3
-
4
- # The Criteria represents the interface between the repositories and actions
5
- # or commands. The allow you to find entities in the application storage (
6
- # a database) without knowledge of that storage system. The criteria will
7
- # always refer to its queries in the domain language for which the repo is
8
- # responsible for mapping that query to its persistence layer.
9
- #
10
- # search: 'foo.bar filter id = 6 and bar = "foo" order id asc limit 6'
11
- #
12
- # filters: 'id = 6 or id = 8 and id = 9'
13
- # filters: [
14
- # 'id = 6',
15
- # {or: 'id = 8'}
16
- # {and: id = 9'}
17
- # ]
18
- #
19
- # order: 'foo.bar.id asc'
20
- # order: 'foo.bar.id'
21
- # order: [
22
- # 'foo.bar.id',
23
- # {desc: 'foo.bar.id'},
24
- # {asc: 'foo.bar.id'}
25
- # ]
26
- # limit: 1
27
- #
28
- # settings:
29
- # page: 1
30
- # per_page: 2
31
- # disable_pagination
32
- # first
33
- # all
34
- # last
35
- # error_on_empty
36
- # parser
37
- # transform
38
- #
39
- class SearchCriteria < BaseCriteria
40
- attr_reader :order_exprs
41
- # Parse out the domain into feature, domain, determine the name of the
42
- # repo this criteria is for and initailize basic settings.
43
- # global.user
44
- #
45
- # membership.user
46
- # foo.id filter name like "foo" order foo.bar.id asc limit 2
47
- # foo.id exists foo.id = 5
48
- #
49
- # @example
50
- # SpCore::Domain::Criteria('foo', single: true)
51
- # Types.Criteria('foo.bar', single: true)
52
- #
53
- # === Options
54
- # error_on_empty: will cause the repo to fail when query returns an
55
- # an empty dataset. The failure will have the message
56
- # with key as domain and text is "<domain> not found"
57
- #
58
- # single: will cause the repo to return only one, the first,
59
- # entity in the dataset
60
- #
61
- # @param domain [String] fully qualified domain name
62
- # @param opts [Hash] options for initializing criteria
63
- # @return [Criteria]
64
- #
65
- # @param domain [String] fully qualified domain name
66
- # @param opts [Hash] options for initializing criteria
67
- # @return [Criteria]
68
- def initialize(domain_name, data = {})
69
- super
70
- @limit = nil
71
- @order_exprs = []
72
- filter(data[:filter]) if data[:filter]
73
- end
74
-
75
- def filter(str, op: 'and')
76
- expr = parse_expr(str)
77
- return false unless expr
78
-
79
- expr = qualify_expr(expr)
80
- if filters?
81
- expr = ExprConjunction.new(op, filters, expr)
82
- end
83
-
84
- @filters = expr
85
- self
86
- end
87
-
88
- def limit(nbr = nil)
89
- return @limit if nbr.nil?
90
-
91
- @limit = Integer(nbr)
92
- fail "limit must be an integer greater than 0" unless nbr > 0
93
- self
94
- end
95
-
96
- # order first_name asc, last_name
97
- # order: 'foo.bar.id asc'
98
- # order: 'foo.bar.id'
99
- # order: [
100
- # 'foo.bar.id',
101
- # {desc: 'foo.bar.id'},
102
- # {asc: 'foo.bar.id'}
103
- # ]
104
- #
105
- # membership.user.id
106
- def order(data)
107
- data = [data] if data.is_a?(String)
108
- unless data.respond_to?(:each)
109
- fail "order must be a string or implement :each"
110
- end
111
- data.each do |item|
112
- item = transform_order_string(item) if item.is_a?(String)
113
-
114
- if !item.is_a?(Hash)
115
- fail "order array must be a list of strings or hashes"
116
- end
117
-
118
- dir, domain_attr = item.first
119
- dir = dir.to_s.downcase
120
- unless ['desc', 'asc'].include(dir)
121
- fail "order array item must have a hash key of desc or asc"
122
- end
123
- @order_exprs << {dir => domain_attr}
124
- end
125
- self
126
- end
127
-
128
- private
129
-
130
- def transform_order_string(str)
131
- str, dir = item.split(' ')
132
- dir = 'asc' if dir.nil?
133
- {dir.downcase => str}
134
- end
135
- end
136
- end
137
- end
@@ -1,86 +0,0 @@
1
- module Appfuel
2
- module Repository
3
- class Base
4
- include Appfuel::Application::AppContainer
5
-
6
- class << self
7
- attr_writer :mapper
8
-
9
- def container_class_type
10
- 'repositories'
11
- end
12
-
13
- def inherited(klass)
14
- stage_class_for_registration(klass)
15
- end
16
-
17
- def mapper
18
- @mapper ||= create_mapper
19
- end
20
-
21
- def create_mapper(maps = nil)
22
- Mapper.new(container_root_name, maps)
23
- end
24
- end
25
-
26
- def mapper
27
- self.class.mapper
28
- end
29
-
30
- def search(criteria)
31
- mapper.search(criteria)
32
- end
33
-
34
- def exists?(criteria)
35
- expr = criteria.fiilters
36
- mapper.exists?(expr)
37
- end
38
-
39
- def to_storage(entity, exclude = [])
40
- mapper.to_storage(entity, exclude)
41
- end
42
-
43
- def to_entity(domain_name, storage)
44
- key = qualify_container_key(domain_name, "domains")
45
- hash = mapper.to_entity_hash(domain_name, storage)
46
- app_container[key].new(hash)
47
- end
48
-
49
- def build(type:, name:, storage:, **inputs)
50
- builder = find_entity_builder(type: type, domain_name: name)
51
- builder.call(storage, inputs)
52
- end
53
-
54
- # features.membership.presenters.hash.user
55
- # global.presenters.user
56
- #
57
- # key => db_model
58
- # key => db_model
59
- def find_entity_builder(domain_name:, type:)
60
- key = qualify_container_key(domain_name, "domain_builders.#{type}")
61
-
62
- container = app_container
63
- unless container.key?(key)
64
- return ->(data, inputs = {}) {
65
- build_default_entity(domain_name: domain_name, storage: data)
66
- }
67
- end
68
-
69
- container[key]
70
- end
71
-
72
- def build_default_entity(domain_name:, storage:)
73
- storage = [storage] unless storage.is_a?(Array)
74
-
75
- storage_attrs = {}
76
- storage.each do |model|
77
- storage_attrs.merge!(mapper.model_attributes(model))
78
- end
79
-
80
- hash = mapper.to_entity_hash(domain_name, storage_attrs)
81
- key = qualify_container_key(domain_name, "domains")
82
- app_container[key].new(hash)
83
- end
84
- end
85
- end
86
- end
@@ -1,60 +0,0 @@
1
- module Appfuel
2
- # Used in the validation system by custom predicates to ask the question if
3
- # an entity exists in the database
4
- class RepositoryRunner
5
- attr_reader :repo_namespace, :criteria_class
6
-
7
- # The call relies on the fact that we can build a criteria find the
8
- # correct repo and call the exists? interface on that repo. The identity
9
- # of any given repo requires its namespace + its class name.
10
- #
11
- # @param namespace [String] fully qualified namespace string fro repos
12
- # @param criteria_class [Class] class used to represent the criteria
13
- # @returns [ExistsInDbRunner]
14
- def initialize(namespace, criteria_class)
15
- @repo_namespace = namespace
16
- @criteria_class = criteria_class
17
- end
18
-
19
- def create_criteria(entity_key, opts = {})
20
- criteria_class.new(entity_key, opts)
21
- end
22
-
23
- def query(criteria)
24
- load_repo(criteria).query(criteria)
25
- end
26
-
27
- # @param entity_key [String] the type identifier for an entity
28
- # @param opts [Hash] one attr => value pair is required
29
- # repo => name is optional
30
- #
31
- # @return [Bool]
32
- def exists?(entity_key, opts = {})
33
- fail "opts must be a hash" unless opts.is_a?(Hash)
34
-
35
- criteria_opts = {}
36
- if opts.key?(:repo)
37
- criteria_opts[:repo] = opts.delete(:repo)
38
- end
39
- fail "opts hash must have one attr => value pair" if opts.empty?
40
-
41
- property, value = opts.first
42
- criteria = create_criteria(entity_key, criteria_opts)
43
- criteria.exists(property, value)
44
-
45
- load_repo(criteria).exists?(criteria)
46
- end
47
-
48
-
49
- private
50
-
51
- def load_repo(criteria)
52
- klass = "#{repo_namespace}::#{criteria.repo_name}"
53
- unless Kernel.const_defined?(klass)
54
- fail "RepositoryRunner: failed - repo #{klass} not defined"
55
- end
56
-
57
- Kernel.const_get(klass).new
58
- end
59
- end
60
- end