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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/projects/command/src/command_pattern_implementation/concerns/reflection.rb +39 -18
  4. data/projects/command/src/transformed_command.rb +83 -40
  5. data/projects/command_connectors/src/command_connector/commands/describe.rb +1 -5
  6. data/projects/command_connectors/src/command_connector/request.rb +7 -1
  7. data/projects/command_connectors/src/command_connector/response.rb +7 -1
  8. data/projects/command_connectors/src/command_connector.rb +85 -74
  9. data/projects/command_connectors/src/command_registry/exposed_command.rb +3 -2
  10. data/projects/command_connectors/src/command_registry/exposed_domain.rb +10 -3
  11. data/projects/command_connectors/src/command_registry/exposed_organization.rb +2 -2
  12. data/projects/command_connectors/src/serializers/atomic_serializer.rb +1 -1
  13. data/projects/command_connectors/src/serializers/errors_serializer.rb +4 -2
  14. data/projects/command_connectors/src/transformers/load_delegated_attributes_entities_pre_commit_transformer.rb +40 -0
  15. data/projects/common/src/data_path.rb +16 -0
  16. data/projects/common/src/error.rb +10 -4
  17. data/projects/common/src/possible_error.rb +9 -3
  18. data/projects/detached_entity/src/concerns/associations.rb +26 -20
  19. data/projects/detached_entity/src/concerns/reflection.rb +3 -3
  20. data/projects/detached_entity/src/detached_entity_type.rb +8 -3
  21. data/projects/detached_entity/src/extensions/builtin_types/detached_entity/validators/{attributes_declaration.rb → model_instance_is_valid.rb} +1 -1
  22. data/projects/domain/src/domain_module_extension.rb +12 -4
  23. data/projects/domain/src/extensions/foobara.rb +31 -28
  24. data/projects/domain/src/is_manifestable.rb +6 -2
  25. data/projects/domain/src/organization_module_extension.rb +6 -2
  26. data/projects/entity/src/concerns/queries.rb +29 -31
  27. data/projects/entity/src/extensions/builtin_types/entity/validators/{attributes_declaration.rb → model_instance_is_valid.rb} +1 -1
  28. data/projects/model/src/concerns/reflection.rb +8 -2
  29. data/projects/model/src/concerns/types.rb +121 -23
  30. data/projects/model/src/extensions/builtin_types/model/supported_transformers/mutable.rb +1 -2
  31. data/projects/model/src/extensions/builtin_types/model/validators/{attributes_declaration.rb → model_instance_is_valid.rb} +1 -1
  32. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/array_with_symbolic_elements.rb +29 -0
  33. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/delegates_desugarizer.rb +39 -0
  34. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/delegates_validator.rb +44 -0
  35. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/move_private_from_element_types_to_root.rb +48 -0
  36. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/symbolize_private.rb +34 -0
  37. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/to_type_transformer.rb +34 -2
  38. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/valid_attribute_names.rb +54 -0
  39. data/projects/model/src/model.rb +9 -0
  40. data/projects/model_attribute_helpers/src/attribute_helpers.rb +25 -4
  41. data/projects/namespace/src/is_namespace.rb +34 -15
  42. data/projects/persistence/src/entity_attributes_crud_driver.rb +25 -1
  43. data/projects/persistence/src/entity_base/transaction_table.rb +28 -3
  44. data/projects/type_declarations/src/desugarizer.rb +1 -1
  45. data/projects/type_declarations/src/type_builder.rb +42 -39
  46. data/projects/type_declarations/src/type_declaration_handler.rb +1 -1
  47. data/projects/type_declarations/src/type_declaration_handler_registry.rb +1 -1
  48. data/projects/type_declarations/src/type_declaration_validator.rb +1 -1
  49. data/projects/type_declarations/src/type_declarations.rb +39 -10
  50. data/projects/types/src/extensions/error.rb +3 -3
  51. data/projects/types/src/type/concerns/reflection.rb +79 -4
  52. data/projects/types/src/type.rb +42 -17
  53. data/projects/value/src/caster.rb +1 -1
  54. data/projects/value/src/mutator.rb +1 -1
  55. data/projects/value/src/processor/casting.rb +1 -1
  56. data/projects/value/src/processor/pipeline.rb +1 -1
  57. data/projects/value/src/processor/selection.rb +1 -1
  58. data/projects/value/src/processor.rb +13 -5
  59. data/projects/value/src/transformer.rb +1 -1
  60. data/projects/value/src/validator.rb +1 -1
  61. metadata +13 -6
@@ -5,20 +5,26 @@ module Foobara
5
5
  include Concern
6
6
 
7
7
  module ClassMethods
8
- def foobara_manifest(to_include: Set.new, remove_sensitive: false)
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(*args, **opts, &)
39
- new_type = domain.foobara_type_from_declaration(*args, **opts, &)
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 name
89
- model_base_class = superclass.name
90
- model_class = name
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 name.start_with?(closest_namespace_module.name)
90
+ if model_class.start_with?(closest_namespace_module.name)
93
91
  model_module_name = closest_namespace_module.name
94
- model_name = name.gsub(/^#{closest_namespace_module.name}::/, "")
92
+ model_name = model_class.gsub(/^#{closest_namespace_module.name}::/, "")
95
93
  else
96
94
  model_module_name = nil
97
- model_name = 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
@@ -1,8 +1,7 @@
1
1
  module Foobara
2
2
  module BuiltinTypes
3
3
  module Model
4
- # TODO: Create Mutations/SupportedMutations concept
5
- class SupportedTransformers
4
+ module SupportedTransformers
6
5
  class Mutable < TypeDeclarations::Transformer
7
6
  class << self
8
7
  def requires_declaration_data?
@@ -2,7 +2,7 @@ module Foobara
2
2
  module BuiltinTypes
3
3
  module Model
4
4
  module Validators
5
- class AttributesDeclaration < TypeDeclarations::Processor
5
+ class ModelInstanceIsValid < TypeDeclarations::Processor
6
6
  class << self
7
7
  def requires_parent_declaration_data?
8
8
  true
@@ -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
- [:name, :model_class, :model_base_class, :model_module, :attributes_declaration, *super]
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
- type.type_symbol = type.declaration_data[:name]
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
@@ -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(includes_primary_key: false)
35
- return foobara_attributes_type if includes_primary_key
36
- return foobara_attributes_type unless foobara_has_primary_key?
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
- Foobara::TypeDeclarations::Attributes.reject(declaration, foobara_primary_key_attribute)
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)