appfuel 0.2.5 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
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