foobara 0.0.92 → 0.0.94
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 +4 -4
- data/CHANGELOG.md +12 -0
- data/projects/command/src/command_pattern_implementation/concerns/reflection.rb +39 -18
- data/projects/command/src/transformed_command.rb +83 -40
- data/projects/command_connectors/src/command_connector/commands/describe.rb +1 -5
- data/projects/command_connectors/src/command_connector/request.rb +7 -1
- data/projects/command_connectors/src/command_connector/response.rb +7 -1
- data/projects/command_connectors/src/command_connector.rb +85 -74
- data/projects/command_connectors/src/command_registry/exposed_command.rb +3 -2
- data/projects/command_connectors/src/command_registry/exposed_domain.rb +10 -3
- data/projects/command_connectors/src/command_registry/exposed_organization.rb +2 -2
- data/projects/command_connectors/src/serializers/atomic_serializer.rb +1 -1
- data/projects/command_connectors/src/serializers/errors_serializer.rb +4 -2
- data/projects/command_connectors/src/transformers/load_delegated_attributes_entities_pre_commit_transformer.rb +40 -0
- data/projects/common/src/data_path.rb +16 -0
- data/projects/common/src/error.rb +10 -4
- data/projects/common/src/possible_error.rb +9 -3
- data/projects/detached_entity/src/concerns/associations.rb +26 -20
- data/projects/detached_entity/src/concerns/reflection.rb +3 -3
- data/projects/detached_entity/src/detached_entity_type.rb +8 -3
- data/projects/detached_entity/src/extensions/builtin_types/detached_entity/validators/{attributes_declaration.rb → model_instance_is_valid.rb} +1 -1
- data/projects/domain/src/domain_module_extension.rb +12 -4
- data/projects/domain/src/extensions/foobara.rb +31 -28
- data/projects/domain/src/is_manifestable.rb +6 -2
- data/projects/domain/src/organization_module_extension.rb +6 -2
- data/projects/entity/src/concerns/queries.rb +29 -31
- data/projects/entity/src/extensions/builtin_types/entity/validators/{attributes_declaration.rb → model_instance_is_valid.rb} +1 -1
- data/projects/model/src/concerns/reflection.rb +8 -2
- data/projects/model/src/concerns/types.rb +121 -23
- data/projects/model/src/extensions/builtin_types/model/supported_transformers/mutable.rb +1 -2
- data/projects/model/src/extensions/builtin_types/model/validators/{attributes_declaration.rb → model_instance_is_valid.rb} +1 -1
- data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/array_with_symbolic_elements.rb +29 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/delegates_desugarizer.rb +39 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/delegates_validator.rb +44 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/move_private_from_element_types_to_root.rb +48 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/symbolize_private.rb +34 -0
- data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/to_type_transformer.rb +34 -2
- data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/valid_attribute_names.rb +54 -0
- data/projects/model/src/model.rb +9 -0
- data/projects/model_attribute_helpers/src/attribute_helpers.rb +25 -4
- data/projects/namespace/src/is_namespace.rb +34 -15
- data/projects/persistence/src/entity_attributes_crud_driver.rb +25 -1
- data/projects/persistence/src/entity_base/transaction_table.rb +28 -3
- data/projects/type_declarations/src/desugarizer.rb +1 -1
- data/projects/type_declarations/src/type_builder.rb +42 -39
- data/projects/type_declarations/src/type_declaration_handler.rb +1 -1
- data/projects/type_declarations/src/type_declaration_handler_registry.rb +1 -1
- data/projects/type_declarations/src/type_declaration_validator.rb +1 -1
- data/projects/type_declarations/src/type_declarations.rb +39 -10
- data/projects/types/src/extensions/error.rb +3 -3
- data/projects/types/src/type/concerns/reflection.rb +79 -4
- data/projects/types/src/type.rb +42 -17
- data/projects/value/src/caster.rb +1 -1
- data/projects/value/src/mutator.rb +1 -1
- data/projects/value/src/processor/casting.rb +1 -1
- data/projects/value/src/processor/pipeline.rb +1 -1
- data/projects/value/src/processor/selection.rb +1 -1
- data/projects/value/src/processor.rb +13 -5
- data/projects/value/src/transformer.rb +1 -1
- data/projects/value/src/validator.rb +1 -1
- metadata +13 -6
@@ -5,20 +5,26 @@ module Foobara
|
|
5
5
|
include Concern
|
6
6
|
|
7
7
|
module ClassMethods
|
8
|
-
def foobara_manifest
|
8
|
+
def foobara_manifest
|
9
|
+
remove_sensitive = TypeDeclarations.foobara_manifest_context_remove_sensitive?
|
10
|
+
|
9
11
|
attributes_declaration = foobara_attributes_type.declaration_data
|
10
12
|
|
11
13
|
if remove_sensitive
|
12
14
|
attributes_declaration = TypeDeclarations.remove_sensitive_types(attributes_declaration)
|
13
15
|
end
|
14
16
|
|
17
|
+
# TODO: do we really need all this stuff? Can't it be grabbed off of the declaration data to save
|
18
|
+
# space?
|
15
19
|
Util.remove_blank(
|
16
20
|
attributes_type: attributes_declaration,
|
17
21
|
organization_name: foobara_type.foobara_domain.foobara_organization_name,
|
18
22
|
domain_name: foobara_type.foobara_domain.foobara_domain_name,
|
19
23
|
model_name: foobara_model_name,
|
20
24
|
model_base_class: foobara_type.declaration_data[:model_base_class],
|
21
|
-
model_class: foobara_type.declaration_data[:model_class]
|
25
|
+
model_class: foobara_type.declaration_data[:model_class],
|
26
|
+
delegates:,
|
27
|
+
private: private_attribute_names
|
22
28
|
)
|
23
29
|
end
|
24
30
|
end
|
@@ -35,16 +35,10 @@ module Foobara
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
def attributes(
|
39
|
-
|
40
|
-
|
41
|
-
unless new_type.extends?(BuiltinTypes[:attributes])
|
42
|
-
# :nocov:
|
43
|
-
raise ArgumentError, "Expected #{args} #{opts} to extend :attributes " \
|
44
|
-
"but instead it resulted in: #{new_type.declaration_data}"
|
45
|
-
# :nocov:
|
46
|
-
end
|
38
|
+
def attributes(...)
|
39
|
+
private, attributes_type_declaration = extract_private_from_attributes_declaration(...)
|
47
40
|
|
41
|
+
new_type = domain.foobara_type_from_declaration(attributes_type_declaration)
|
48
42
|
existing_type = attributes_type
|
49
43
|
|
50
44
|
if existing_type
|
@@ -57,6 +51,7 @@ module Foobara
|
|
57
51
|
end
|
58
52
|
|
59
53
|
self.attributes_type = new_type
|
54
|
+
private_attributes(private)
|
60
55
|
|
61
56
|
set_model_type
|
62
57
|
end
|
@@ -69,14 +64,12 @@ module Foobara
|
|
69
64
|
|
70
65
|
if model_type
|
71
66
|
unless Foobara::TypeDeclarations.declarations_equal?(declaration, model_type.declaration_data)
|
72
|
-
domain.foobara_unregister(model_type)
|
73
67
|
self.model_type = nil
|
74
68
|
domain.foobara_type_from_declaration(declaration)
|
75
69
|
end
|
76
70
|
else
|
77
71
|
domain.foobara_type_from_declaration(declaration)
|
78
72
|
end
|
79
|
-
|
80
73
|
end
|
81
74
|
end
|
82
75
|
|
@@ -85,22 +78,22 @@ module Foobara
|
|
85
78
|
end
|
86
79
|
|
87
80
|
def type_declaration(attributes_declaration)
|
88
|
-
if
|
89
|
-
|
90
|
-
model_class =
|
81
|
+
if model_type
|
82
|
+
model_module_name = model_type.declaration_data[:model_module]
|
83
|
+
model_class = model_type.declaration_data[:model_class]
|
84
|
+
model_name = model_type.scoped_name
|
85
|
+
model_base_class = superclass.name || superclass.model_type.scoped_full_name
|
86
|
+
else
|
87
|
+
model_base_class = superclass.name || superclass.full_model_name
|
88
|
+
model_class = name || full_model_name
|
91
89
|
|
92
|
-
if
|
90
|
+
if model_class.start_with?(closest_namespace_module.name)
|
93
91
|
model_module_name = closest_namespace_module.name
|
94
|
-
model_name =
|
92
|
+
model_name = model_class.gsub(/^#{closest_namespace_module.name}::/, "")
|
95
93
|
else
|
96
94
|
model_module_name = nil
|
97
|
-
model_name =
|
95
|
+
model_name = model_class
|
98
96
|
end
|
99
|
-
else
|
100
|
-
model_module_name = model_type.declaration_data[:model_module]
|
101
|
-
model_class = model_type.declaration_data[:model_class]
|
102
|
-
model_name = model_type.scoped_name
|
103
|
-
model_base_class = superclass.name || superclass.model_type.scoped_full_name
|
104
97
|
end
|
105
98
|
|
106
99
|
Util.remove_blank(
|
@@ -112,7 +105,9 @@ module Foobara
|
|
112
105
|
attributes_declaration:,
|
113
106
|
description:,
|
114
107
|
_desugarized: { type_absolutified: true },
|
115
|
-
mutable
|
108
|
+
mutable:,
|
109
|
+
delegates:,
|
110
|
+
private: private_attribute_names
|
116
111
|
)
|
117
112
|
end
|
118
113
|
|
@@ -131,7 +126,15 @@ module Foobara
|
|
131
126
|
def model_type=(model_type)
|
132
127
|
@model_type = model_type
|
133
128
|
|
129
|
+
return if model_type.nil?
|
130
|
+
|
131
|
+
private = model_type.declaration_data[:private]
|
132
|
+
|
134
133
|
attributes_type.element_types.each_key do |attribute_name|
|
134
|
+
if delegates.key?(attribute_name)
|
135
|
+
next
|
136
|
+
end
|
137
|
+
|
135
138
|
define_method attribute_name do
|
136
139
|
read_attribute(attribute_name)
|
137
140
|
end
|
@@ -140,7 +143,102 @@ module Foobara
|
|
140
143
|
define_method "#{attribute_name}=" do |value|
|
141
144
|
write_attribute(attribute_name, value)
|
142
145
|
end
|
146
|
+
|
147
|
+
if private&.include?(attribute_name)
|
148
|
+
private attribute_name
|
149
|
+
private "#{attribute_name}="
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def delegates
|
155
|
+
@delegates ||= {}
|
156
|
+
end
|
157
|
+
|
158
|
+
def private_attribute_names
|
159
|
+
@private_attribute_names ||= []
|
160
|
+
end
|
161
|
+
|
162
|
+
def private_attributes(attribute_names)
|
163
|
+
attribute_names.each do |attribute_name|
|
164
|
+
private_attribute attribute_name
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def private_attribute(attribute_name)
|
169
|
+
@private_attribute_names = private_attribute_names | [attribute_name]
|
170
|
+
|
171
|
+
set_model_type
|
172
|
+
end
|
173
|
+
|
174
|
+
def delegate_attributes(delegates)
|
175
|
+
delegates.each_pair do |attribute_name, delegate_info|
|
176
|
+
delegate_attribute(attribute_name, delegate_info[:data_path], writer: delegate_info[:writer])
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def delegate_attribute(attribute_name, data_path, writer: false)
|
181
|
+
data_path = DataPath.for(data_path)
|
182
|
+
|
183
|
+
delegate_manifest = { data_path: data_path.to_s }
|
184
|
+
|
185
|
+
if writer
|
186
|
+
delegate_manifest[:writer] = true
|
187
|
+
end
|
188
|
+
|
189
|
+
delegates[attribute_name] = delegate_manifest
|
190
|
+
|
191
|
+
delegated_type_declaration = model_type.type_at_path(data_path).reference_or_declaration_data
|
192
|
+
attributes attribute_name => delegated_type_declaration
|
193
|
+
|
194
|
+
define_method attribute_name do
|
195
|
+
data_path.value_at(self)
|
196
|
+
end
|
197
|
+
|
198
|
+
if writer
|
199
|
+
define_method "#{attribute_name}=" do |value|
|
200
|
+
data_path.set_value_at(self, value)
|
201
|
+
end
|
202
|
+
else
|
203
|
+
method = :"#{attribute_name}="
|
204
|
+
|
205
|
+
if instance_methods.include?(method)
|
206
|
+
# TODO: test this code path
|
207
|
+
# :nocov:
|
208
|
+
remove_method method
|
209
|
+
# :nocov:
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
set_model_type
|
214
|
+
end
|
215
|
+
|
216
|
+
private
|
217
|
+
|
218
|
+
def extract_private_from_attributes_declaration(...)
|
219
|
+
private = []
|
220
|
+
attributes_type_declaration = TypeDeclarations.args_to_type_declaration(...)
|
221
|
+
|
222
|
+
if attributes_type_declaration.is_a?(::Hash) || attributes_type_declaration.is_a?(Proc)
|
223
|
+
handler = domain.foobara_type_builder.handler_for_class(
|
224
|
+
TypeDeclarations::Handlers::ExtendAttributesTypeDeclaration
|
225
|
+
)
|
226
|
+
attributes_type_declaration = Namespace.use domain do
|
227
|
+
handler.desugarize(attributes_type_declaration)
|
228
|
+
end
|
229
|
+
|
230
|
+
element_type_declarations = attributes_type_declaration[:element_type_declarations]
|
231
|
+
|
232
|
+
element_type_declarations.each_pair do |attribute_name, attribute_type_declaration|
|
233
|
+
is_private = attribute_type_declaration.delete(:private)
|
234
|
+
|
235
|
+
if is_private
|
236
|
+
private |= [attribute_name]
|
237
|
+
end
|
238
|
+
end
|
143
239
|
end
|
240
|
+
|
241
|
+
[private, attributes_type_declaration]
|
144
242
|
end
|
145
243
|
end
|
146
244
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Foobara
|
2
|
+
module TypeDeclarations
|
3
|
+
module Handlers
|
4
|
+
class ExtendModelTypeDeclaration < ExtendRegisteredTypeDeclaration
|
5
|
+
class ArrayWithSymbolicElements < TypeDeclarations::TypeDeclarationValidator
|
6
|
+
class InvalidPrivateValuesGivenError < Value::DataError
|
7
|
+
class << self
|
8
|
+
def message
|
9
|
+
"Private should be an array with symbolic elements"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def applicable?(strict_type_declaration)
|
15
|
+
strict_type_declaration.is_a?(Hash) && strict_type_declaration.key?(:private)
|
16
|
+
end
|
17
|
+
|
18
|
+
def validation_errors(strict_type_declaration)
|
19
|
+
private = strict_type_declaration[:private]
|
20
|
+
|
21
|
+
unless private.is_a?(::Array) && Util.all_symbolic_elements?(private)
|
22
|
+
build_error(context: { attribute_name: :private, value: private })
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Foobara
|
2
|
+
module TypeDeclarations
|
3
|
+
module Handlers
|
4
|
+
class ExtendModelTypeDeclaration < ExtendRegisteredTypeDeclaration
|
5
|
+
class DelegatesDesugarizer < TypeDeclarations::Desugarizer
|
6
|
+
def applicable?(sugary_type_declaration)
|
7
|
+
sugary_type_declaration.key?(:delegates) && sugary_type_declaration[:delegates].is_a?(::Hash)
|
8
|
+
end
|
9
|
+
|
10
|
+
def desugarize(sugary_type_declaration)
|
11
|
+
desugarized = Util.deep_dup(sugary_type_declaration)
|
12
|
+
delegates = desugarized[:delegates]
|
13
|
+
|
14
|
+
if delegates.empty?
|
15
|
+
desugarized.delete(:delegates)
|
16
|
+
desugarized
|
17
|
+
else
|
18
|
+
delegates.each_pair do |attribute_name, delegate_info|
|
19
|
+
h = delegate_info.merge(data_path: DataPath.new(delegate_info[:data_path]).to_s)
|
20
|
+
|
21
|
+
no_writer = !delegate_info[:writer]
|
22
|
+
|
23
|
+
if no_writer
|
24
|
+
h.delete(:writer)
|
25
|
+
else
|
26
|
+
h[:writer] = true
|
27
|
+
end
|
28
|
+
|
29
|
+
delegates[attribute_name] = h
|
30
|
+
end
|
31
|
+
|
32
|
+
sugary_type_declaration.merge(delegates:)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Foobara
|
2
|
+
module TypeDeclarations
|
3
|
+
module Handlers
|
4
|
+
class ExtendModelTypeDeclaration < ExtendRegisteredTypeDeclaration
|
5
|
+
class DelegatesValidator < TypeDeclarations::TypeDeclarationValidator
|
6
|
+
class InvalidDelegatesError < TypeDeclarationError
|
7
|
+
context delegates: :duck
|
8
|
+
end
|
9
|
+
|
10
|
+
def applicable?(value)
|
11
|
+
value.key?(:delegates)
|
12
|
+
end
|
13
|
+
|
14
|
+
def validation_errors(strict_type_declaration)
|
15
|
+
delegates = strict_type_declaration[:delegates]
|
16
|
+
|
17
|
+
unless delegates.is_a?(::Hash)
|
18
|
+
return build_error(
|
19
|
+
message: "delegates must be a hash",
|
20
|
+
context: { delegates: }
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
allowed_keys = %i[data_path writer]
|
25
|
+
|
26
|
+
delegates.each_pair do |attribute_name, delegate_hash|
|
27
|
+
invalid_keys = delegate_hash.keys - allowed_keys
|
28
|
+
|
29
|
+
unless invalid_keys.empty?
|
30
|
+
return build_error(
|
31
|
+
message: "delegates must only contain data_path and writer but contained " \
|
32
|
+
"#{invalid_keys} at #{attribute_name}",
|
33
|
+
context: { delegates: }
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Foobara
|
2
|
+
module TypeDeclarations
|
3
|
+
module Handlers
|
4
|
+
class ExtendModelTypeDeclaration < ExtendRegisteredTypeDeclaration
|
5
|
+
class MovePrivateFromElementTypesToRoot < TypeDeclarations::Desugarizer
|
6
|
+
def applicable?(value)
|
7
|
+
if value.is_a?(::Hash) && value.key?(:type) && value.key?(:attributes_declaration)
|
8
|
+
type_symbol = value[:type]
|
9
|
+
|
10
|
+
if type_registered?(type_symbol)
|
11
|
+
type = lookup_type!(type_symbol)
|
12
|
+
type.extends?(BuiltinTypes[:model])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def desugarize(rawish_type_declaration)
|
18
|
+
private = rawish_type_declaration[:private]
|
19
|
+
private = private ? private.dup : []
|
20
|
+
|
21
|
+
attributes_declaration = rawish_type_declaration[:attributes_declaration]
|
22
|
+
element_type_declarations = attributes_declaration[:element_type_declarations]
|
23
|
+
|
24
|
+
element_type_declarations.each_pair do |attribute_name, attribute_type_declaration|
|
25
|
+
if attribute_type_declaration.is_a?(Hash) && attribute_type_declaration.key?(:private)
|
26
|
+
is_private = attribute_type_declaration[:private]
|
27
|
+
element_type_declarations[attribute_name] = attribute_type_declaration.except(:private)
|
28
|
+
if is_private
|
29
|
+
private |= [attribute_name]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if private.empty?
|
35
|
+
rawish_type_declaration.except(:private)
|
36
|
+
else
|
37
|
+
rawish_type_declaration.merge(private:)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def priority
|
42
|
+
Priority::MEDIUM + 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Foobara
|
2
|
+
module TypeDeclarations
|
3
|
+
module Handlers
|
4
|
+
class ExtendModelTypeDeclaration < ExtendRegisteredTypeDeclaration
|
5
|
+
class SymbolizePrivate < TypeDeclarations::Desugarizer
|
6
|
+
def applicable?(value)
|
7
|
+
if value.is_a?(::Hash) && value.key?(:type) && value.key?(:attributes_declaration) && value.key?(:private)
|
8
|
+
type_symbol = value[:type]
|
9
|
+
|
10
|
+
if type_registered?(type_symbol)
|
11
|
+
type = lookup_type!(type_symbol)
|
12
|
+
type.extends?(BuiltinTypes[:model])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def desugarize(rawish_type_declaration)
|
18
|
+
private = rawish_type_declaration[:private]
|
19
|
+
|
20
|
+
if private.any? { |key| key.is_a?(::String) }
|
21
|
+
rawish_type_declaration.merge(private: private.map(&:to_sym))
|
22
|
+
else
|
23
|
+
rawish_type_declaration
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def priority
|
28
|
+
Priority::LOW
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -22,6 +22,13 @@ module Foobara
|
|
22
22
|
# :nocov:
|
23
23
|
end
|
24
24
|
end
|
25
|
+
else
|
26
|
+
existing_type = Domain.current.foobara_lookup_type(
|
27
|
+
model_class_name,
|
28
|
+
mode: Namespace::LookupMode::ABSOLUTE
|
29
|
+
)
|
30
|
+
|
31
|
+
existing_type&.target_class
|
25
32
|
end
|
26
33
|
end
|
27
34
|
|
@@ -53,7 +60,16 @@ module Foobara
|
|
53
60
|
# TODO: create declaration validator for name and the others
|
54
61
|
# TODO: seems like a smell that we don't have processors for these?
|
55
62
|
def non_processor_keys
|
56
|
-
[
|
63
|
+
[
|
64
|
+
:name,
|
65
|
+
:model_class,
|
66
|
+
:model_base_class,
|
67
|
+
:model_module,
|
68
|
+
:attributes_declaration,
|
69
|
+
:delegates,
|
70
|
+
:private,
|
71
|
+
*super
|
72
|
+
]
|
57
73
|
end
|
58
74
|
|
59
75
|
def process_value(...)
|
@@ -84,9 +100,25 @@ module Foobara
|
|
84
100
|
root_namespace = Namespace.current.foobara_root_namespace
|
85
101
|
domain = root_namespace.foobara_lookup_domain(domain_name)
|
86
102
|
|
87
|
-
|
103
|
+
type_symbol = type.declaration_data[:name]
|
104
|
+
type.type_symbol = type_symbol.to_sym
|
105
|
+
|
88
106
|
model_class.description type.declaration_data[:description]
|
107
|
+
|
108
|
+
if domain.foobara_type_registered?(type_symbol, mode: Namespace::LookupMode::ABSOLUTE)
|
109
|
+
existing_type = domain.foobara_lookup_type(type_symbol, mode: Namespace::LookupMode::ABSOLUTE)
|
110
|
+
domain.foobara_unregister(existing_type)
|
111
|
+
end
|
112
|
+
|
89
113
|
domain.foobara_register_model(model_class)
|
114
|
+
|
115
|
+
if type.declaration_data[:delegates]
|
116
|
+
model_class.delegate_attributes type.declaration_data[:delegates]
|
117
|
+
end
|
118
|
+
|
119
|
+
if type.declaration_data[:private]
|
120
|
+
model_class.private_attributes type.declaration_data[:private]
|
121
|
+
end
|
90
122
|
end
|
91
123
|
end
|
92
124
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Foobara
|
2
|
+
module TypeDeclarations
|
3
|
+
module Handlers
|
4
|
+
class ExtendModelTypeDeclaration < ExtendRegisteredTypeDeclaration
|
5
|
+
class ValidAttributeNames < TypeDeclarations::TypeDeclarationValidator
|
6
|
+
class InvalidPrivateValueGivenError < Value::DataError
|
7
|
+
class << self
|
8
|
+
def context_type_declaration
|
9
|
+
{
|
10
|
+
invalid_attribute_name: :symbol,
|
11
|
+
valid_attribute_names: [:symbol],
|
12
|
+
private: :array
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def fatal?
|
17
|
+
# Since there could be multiple bad private
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def applicable?(strict_type_declaration)
|
24
|
+
private = strict_type_declaration[:private]
|
25
|
+
|
26
|
+
private.is_a?(::Array) && Util.all_symbolic_elements?(private)
|
27
|
+
end
|
28
|
+
|
29
|
+
def validation_errors(strict_type_declaration)
|
30
|
+
private = strict_type_declaration[:private]
|
31
|
+
|
32
|
+
attributes_declaration = strict_type_declaration[:attributes_declaration]
|
33
|
+
valid_attribute_names = attributes_declaration[:element_type_declarations].keys
|
34
|
+
|
35
|
+
# TODO: this should be one error instead of multiple
|
36
|
+
private.map do |element|
|
37
|
+
unless valid_attribute_names.include?(element)
|
38
|
+
build_error(
|
39
|
+
message: "#{element} is not a valid private attribute name, " \
|
40
|
+
"expected one of #{valid_attribute_names}",
|
41
|
+
context: {
|
42
|
+
invalid_attribute_name: element,
|
43
|
+
valid_attribute_names:,
|
44
|
+
private:
|
45
|
+
}
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end.compact
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/projects/model/src/model.rb
CHANGED
@@ -146,6 +146,7 @@ module Foobara
|
|
146
146
|
|
147
147
|
p
|
148
148
|
else
|
149
|
+
# Hmmm, can't there still be errors even if it's immutable?
|
149
150
|
[]
|
150
151
|
end
|
151
152
|
end
|
@@ -232,6 +233,14 @@ module Foobara
|
|
232
233
|
@attributes ||= {}
|
233
234
|
end
|
234
235
|
|
236
|
+
def attributes_with_delegates
|
237
|
+
h = self.class.delegates.keys.to_h do |delegated_attribute_name|
|
238
|
+
[delegated_attribute_name, send(delegated_attribute_name)]
|
239
|
+
end
|
240
|
+
|
241
|
+
attributes.merge(h)
|
242
|
+
end
|
243
|
+
|
235
244
|
def write_attribute(attribute_name, value)
|
236
245
|
attribute_name = attribute_name.to_sym
|
237
246
|
|
@@ -31,13 +31,34 @@ module Foobara
|
|
31
31
|
|
32
32
|
# TODO: we should have metadata on the entity about whether it required a primary key
|
33
33
|
# upon creation or not instead of an option here.
|
34
|
-
def foobara_attributes_for_create(
|
35
|
-
|
36
|
-
|
34
|
+
def foobara_attributes_for_create(
|
35
|
+
includes_primary_key: false, # usually the underlying data store creates this
|
36
|
+
include_private: true, # we usually need to initialize these values to something but not always
|
37
|
+
include_delegates: false # usually these are already set on the passed-in objects it delegates to
|
38
|
+
)
|
39
|
+
if includes_primary_key && include_private
|
40
|
+
if include_delegates || delegates.empty?
|
41
|
+
return foobara_attributes_type
|
42
|
+
end
|
43
|
+
end
|
37
44
|
|
38
45
|
declaration = foobara_attributes_type.declaration_data
|
39
46
|
|
40
|
-
|
47
|
+
Namespace.use foobara_attributes_type.created_in_namespace do
|
48
|
+
unless includes_primary_key
|
49
|
+
declaration = Foobara::TypeDeclarations::Attributes.reject(declaration, foobara_primary_key_attribute)
|
50
|
+
end
|
51
|
+
|
52
|
+
unless include_private
|
53
|
+
declaration = Foobara::TypeDeclarations::Attributes.reject(declaration, *private_attribute_names)
|
54
|
+
end
|
55
|
+
|
56
|
+
unless include_delegates
|
57
|
+
declaration = Foobara::TypeDeclarations::Attributes.reject(declaration, *delegates.keys)
|
58
|
+
end
|
59
|
+
|
60
|
+
Domain.current.foobara_type_from_declaration(declaration)
|
61
|
+
end
|
41
62
|
end
|
42
63
|
|
43
64
|
def foobara_attributes_for_aggregate_update(require_primary_key: true, initial: true)
|