foobara 0.0.78 → 0.0.80

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/projects/builtin_types/src/attributes/supported_validators/required/type_declaration_extension/extend_attributes_type_declaration/desugarizers/alphabetize_required.rb +38 -0
  4. data/projects/command/src/command_pattern_implementation/concerns/reflection.rb +63 -35
  5. data/projects/command/src/transformed_command.rb +12 -11
  6. data/projects/command_connectors/src/command_connector.rb +9 -2
  7. data/projects/command_connectors/src/command_registry/exposed_command.rb +3 -3
  8. data/projects/command_connectors/src/command_registry/exposed_domain.rb +2 -2
  9. data/projects/command_connectors/src/command_registry/exposed_organization.rb +2 -2
  10. data/projects/common/src/error.rb +2 -2
  11. data/projects/common/src/possible_error.rb +1 -1
  12. data/projects/detached_entity/lib/foobara/detached_entity.rb +4 -1
  13. data/projects/detached_entity/src/concerns/associations.rb +60 -20
  14. data/projects/detached_entity/src/concerns/reflection.rb +3 -3
  15. data/projects/detached_entity/src/concerns/types.rb +7 -1
  16. data/projects/detached_entity/src/detached_entity_type.rb +2 -2
  17. data/projects/detached_entity/src/sensitive_type_removers/detached_entity.rb +8 -0
  18. data/projects/domain/src/domain_module_extension.rb +5 -1
  19. data/projects/domain/src/is_manifestable.rb +1 -1
  20. data/projects/domain/src/organization_module_extension.rb +1 -1
  21. data/projects/entity/lib/foobara/entity.rb +4 -1
  22. data/projects/entity/src/sensitive_type_removers/entity.rb +8 -0
  23. data/projects/model/lib/foobara/model.rb +9 -2
  24. data/projects/model/src/concerns/reflection.rb +8 -2
  25. data/projects/model/src/sensitive_type_removers/extended_model.rb +10 -0
  26. data/projects/model/src/sensitive_type_removers/model.rb +19 -0
  27. data/projects/type_declarations/lib/foobara/type_declarations.rb +10 -2
  28. data/projects/type_declarations/src/attributes.rb +1 -0
  29. data/projects/type_declarations/src/desugarizer.rb +1 -1
  30. data/projects/type_declarations/src/handlers/extend_array_type_declaration/type_set_to_array_desugarizer.rb +9 -1
  31. data/projects/type_declarations/src/handlers/extend_registered_type_declaration/to_type_transformer.rb +7 -3
  32. data/projects/type_declarations/src/sensitive_type_remover.rb +17 -0
  33. data/projects/type_declarations/src/sensitive_type_removers/array.rb +21 -0
  34. data/projects/type_declarations/src/sensitive_type_removers/attributes.rb +43 -0
  35. data/projects/type_declarations/src/type_declaration_handler.rb +1 -1
  36. data/projects/type_declarations/src/type_declaration_handler_registry.rb +1 -1
  37. data/projects/type_declarations/src/type_declaration_validator.rb +1 -1
  38. data/projects/type_declarations/src/type_declarations.rb +21 -0
  39. data/projects/types/src/extensions/error.rb +3 -3
  40. data/projects/types/src/type/concerns/reflection.rb +29 -8
  41. data/projects/types/src/type.rb +40 -9
  42. data/projects/value/src/caster.rb +1 -1
  43. data/projects/value/src/processor/casting.rb +1 -1
  44. data/projects/value/src/processor/pipeline.rb +1 -1
  45. data/projects/value/src/processor/selection.rb +1 -1
  46. data/projects/value/src/processor.rb +3 -3
  47. data/projects/value/src/transformer.rb +1 -1
  48. data/projects/value/src/validator.rb +1 -1
  49. metadata +11 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3c5ce6bf1f2bf6f67db74bbc811f5fe37218215b00876564b97e315ec3016c6d
4
- data.tar.gz: a17df1d60eb6b77e162a799250df7d13c44bde9c4a387ed96d3c7c05f3819d26
3
+ metadata.gz: 1b2fdc64452fe8ed0285ac3b9d9ad26108cd7157f798a3fac36b814a0855d802
4
+ data.tar.gz: 4e37ca0d5af8ffd919b068a2fb67573ecddf056e2b13d6d39604f09188cc11c6
5
5
  SHA512:
6
- metadata.gz: 4e1d33d80f67cfc49407079dfafe3c8fe7e0da904f4ece41021ce6a8df412c754ce2dfe09cc3a60fbee74c2d2784b65b05e5839370deb06afd632f23c9e479f1
7
- data.tar.gz: 408920762e79e50dd77c568f75345f6a3b952f4b10a5d2c412e3efb1fa6244874921e98c0b942d0c599f560f4769684e3261dd487e07f5a3494352c8b8525f6b
6
+ metadata.gz: cefd96fe33a1c2fdf1fd2f53aa128e8c6f636507d921f0f30dd9730983b8fa10c5aa10b43bd2b8c0008f50452106f90cf7b8bacae9b0142df4898d3c1ba62b2f
7
+ data.tar.gz: b8fb560d295f3fe8c6a1f0e194f8528a02771e5504b9c482235e16cd9cba7cb0d51858e7b12952027e14d78909a4fd07c68be54553ff3b6356f029ff4cc3259c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # [0.0.80] - 2025-03-19
2
+
3
+ - Fix bug preventing combining array type sugar with sensitive flag in type declarations
4
+
5
+ # [0.0.79] - 2025-03-19
6
+
7
+ - Make foobara manifest output more deterministic (alphabetize required fields array)
8
+ - Add sensitive/sensitive_exposed type declaration flags
9
+ - Add sensitive-type removing feature and default to removing all sensitive (but not sensitive_exposed types)
10
+ from the command connector manifest
11
+
1
12
  # [0.0.78] - 2025-03-17
2
13
 
3
14
  - Include types that possible errors depend on in TransformedCommand#types_depdended_on
@@ -0,0 +1,38 @@
1
+ module Foobara
2
+ module BuiltinTypes
3
+ module Attributes
4
+ module SupportedValidators
5
+ class Required < TypeDeclarations::Validator
6
+ module TypeDeclarationExtension
7
+ module ExtendAttributesTypeDeclaration
8
+ module Desugarizers
9
+ class AlphabetizeRequired < TypeDeclarations::Desugarizer
10
+ def applicable?(value)
11
+ value.is_a?(::Hash) && value[:type] == :attributes &&
12
+ value.key?(:required) && value[:required].size > 1
13
+ end
14
+
15
+ def desugarize(rawish_type_declaration)
16
+ required = rawish_type_declaration[:required]
17
+
18
+ sorted_required = required.sort
19
+
20
+ if sorted_required == required
21
+ rawish_type_declaration
22
+ else
23
+ rawish_type_declaration.merge(required: sorted_required)
24
+ end
25
+ end
26
+
27
+ def priority
28
+ Priority::LOW
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -19,7 +19,7 @@ module Foobara
19
19
  remove_instance_variable("@all") if instance_variable_defined?("@all")
20
20
  end
21
21
 
22
- def foobara_manifest(to_include: Set.new)
22
+ def foobara_manifest(to_include: Set.new, remove_sensitive: false)
23
23
  depends_on = self.depends_on.map do |command_name|
24
24
  other_command = Foobara::Namespace.global.foobara_lookup!(command_name,
25
25
  mode: Foobara::Namespace::LookupMode::ABSOLUTE)
@@ -27,7 +27,7 @@ module Foobara
27
27
  other_command.foobara_manifest_reference
28
28
  end.sort
29
29
 
30
- types = types_depended_on.map do |t|
30
+ types = types_depended_on(remove_sensitive:).map do |t|
31
31
  to_include << t
32
32
  t.foobara_manifest_reference
33
33
  end.sort
@@ -78,54 +78,82 @@ module Foobara
78
78
  Util.non_full_name(self)
79
79
  end
80
80
 
81
- def types_depended_on
82
- # TODO: is there a simpler way to wrap these methods in this namespace?
83
- # something aspect-oriented-ish?
84
- @types_depended_on ||= begin
85
- types = inputs_types_depended_on | result_types_depended_on | errors_types_depended_on
81
+ def types_depended_on(remove_sensitive: false)
82
+ if defined?(@types_depended_on) && @types_depended_on.key?(remove_sensitive)
83
+ return @types_depended_on[remove_sensitive]
84
+ end
85
+
86
+ @types_depended_on ||= {}
87
+ @types_depended_on[remove_sensitive] = begin
88
+ types = inputs_types_depended_on(remove_sensitive:) | result_types_depended_on(remove_sensitive:) |
89
+ errors_types_depended_on(remove_sensitive:)
86
90
 
87
91
  unless depends_on_entities.empty?
88
92
  entity_types = depends_on_entities.map(&:entity_type)
93
+
94
+ if remove_sensitive
95
+ entity_types = entity_types.reject(&:sensitive?)
96
+ end
97
+
89
98
  types |= entity_types
90
- types |= entity_types.map(&:types_depended_on).inject(:|)
99
+ types |= entity_types.map { |t| t.types_depended_on(remove_sensitive:) }.inject(:|)
91
100
  end
92
101
 
93
102
  types
94
103
  end
95
104
  end
96
105
 
97
- def inputs_types_depended_on
98
- @inputs_types_depended_on ||= if inputs_type
99
- if inputs_type.registered?
100
- # TODO: if we ever change from attributes-only inputs type
101
- # then this will be handy
102
- # :nocov:
103
- Set[inputs_type]
104
- # :nocov:
105
- else
106
- inputs_type.types_depended_on
107
- end
108
- else
109
- Set.new
110
- end
106
+ def inputs_types_depended_on(remove_sensitive: false)
107
+ if defined?(@inputs_types_depended_on) && @inputs_types_depended_on.key?(remove_sensitive)
108
+ return @inputs_types_depended_on[remove_sensitive]
109
+ end
110
+
111
+ @inputs_types_depended_on ||= {}
112
+ @inputs_types_depended_on[remove_sensitive] = if inputs_type
113
+ if inputs_type.registered?
114
+ # TODO: if we ever change from attributes-only inputs type
115
+ # then this will be handy
116
+ # :nocov:
117
+ if !remove_sensitive || !inputs_type.sensitive?
118
+ Set[inputs_type]
119
+ else
120
+ Set.new
121
+ end
122
+ # :nocov:
123
+ else
124
+ inputs_type.types_depended_on(remove_sensitive:)
125
+ end
126
+ else
127
+ Set.new
128
+ end
111
129
  end
112
130
 
113
- def result_types_depended_on
114
- @result_types_depended_on ||= if result_type
115
- if result_type.registered?
116
- Set[result_type]
117
- else
118
- result_type.types_depended_on
119
- end
120
- else
121
- Set.new
122
- end
131
+ def result_types_depended_on(remove_sensitive: false)
132
+ if defined?(@result_types_depended_on) && @result_types_depended_on.key?(remove_sensitive)
133
+ return @result_types_depended_on[remove_sensitive]
134
+ end
135
+
136
+ @result_types_depended_on ||= {}
137
+ @result_types_depended_on[remove_sensitive] = if result_type
138
+ if result_type.registered?
139
+ Set[result_type]
140
+ else
141
+ result_type.types_depended_on(remove_sensitive:)
142
+ end
143
+ else
144
+ Set.new
145
+ end
123
146
  end
124
147
 
125
- def errors_types_depended_on
126
- @errors_types_depended_on ||= begin
148
+ def errors_types_depended_on(remove_sensitive: false)
149
+ if defined?(@errors_types_depended_on) && @errors_types_depended_on.key?(remove_sensitive)
150
+ return @errors_types_depended_on[remove_sensitive]
151
+ end
152
+
153
+ @errors_types_depended_on ||= {}
154
+ @errors_types_depended_on[remove_sensitive] = begin
127
155
  error_classes = possible_errors.map(&:error_class)
128
- error_classes.map(&:types_depended_on).inject(:|) || Set.new
156
+ error_classes.map { |e| e.types_depended_on(remove_sensitive:) }.inject(:|) || Set.new
129
157
  end
130
158
  end
131
159
  end
@@ -114,16 +114,16 @@ module Foobara
114
114
  @possible_errors ||= error_context_type_map.values
115
115
  end
116
116
 
117
- def possible_errors_manifest(to_include:)
117
+ def possible_errors_manifest(to_include:, remove_sensitive: true)
118
118
  possible_errors.map do |possible_error|
119
- [possible_error.key.to_s, possible_error.foobara_manifest(to_include:)]
119
+ [possible_error.key.to_s, possible_error.foobara_manifest(to_include:, remove_sensitive:)]
120
120
  end.sort.to_h
121
121
  end
122
122
 
123
- def types_depended_on
123
+ def types_depended_on(remove_sensitive: true)
124
124
  # TODO: memoize this
125
125
  # TODO: this should not delegate to command since transformers are in play
126
- types = command_class.types_depended_on
126
+ types = command_class.types_depended_on(remove_sensitive:)
127
127
 
128
128
  type = inputs_type
129
129
 
@@ -135,7 +135,7 @@ module Foobara
135
135
  [type]
136
136
  # :nocov:
137
137
  else
138
- type.types_depended_on
138
+ type.types_depended_on(remove_sensitive:)
139
139
  end
140
140
  end
141
141
 
@@ -149,19 +149,19 @@ module Foobara
149
149
  [type]
150
150
  # :nocov:
151
151
  else
152
- type.types_depended_on
152
+ type.types_depended_on(remove_sensitive:)
153
153
  end
154
154
  end
155
155
 
156
156
  possible_errors.each do |possible_error|
157
157
  error_class = possible_error.error_class
158
- types |= error_class.types_depended_on
158
+ types |= error_class.types_depended_on(remove_sensitive:)
159
159
  end
160
160
 
161
161
  types
162
162
  end
163
163
 
164
- def foobara_manifest(to_include: Set.new)
164
+ def foobara_manifest(to_include: Set.new, remove_sensitive: true)
165
165
  types = types_depended_on.select(&:registered?).map do |t|
166
166
  to_include << t
167
167
  t.foobara_manifest_reference
@@ -180,12 +180,13 @@ module Foobara
180
180
  end
181
181
  end
182
182
 
183
- command_class.foobara_manifest(to_include:).merge(
183
+ command_class.foobara_manifest(to_include:, remove_sensitive:).merge(
184
184
  Util.remove_blank(
185
185
  types_depended_on: types,
186
186
  inputs_type: inputs_type&.reference_or_declaration_data,
187
- result_type: result_type&.reference_or_declaration_data,
188
- possible_errors: possible_errors_manifest(to_include:),
187
+ # TODO: we need a way to unmask values in the result type that we want to expose
188
+ result_type: result_type&.reference_or_declaration_data(remove_sensitive:),
189
+ possible_errors: possible_errors_manifest(to_include:, remove_sensitive:),
189
190
  capture_unknown_error:,
190
191
  inputs_transformers:,
191
192
  result_transformers:,
@@ -1,5 +1,7 @@
1
1
  module Foobara
2
2
  class CommandConnector
3
+ class UnexpectedSensitiveTypeInManifestError < StandardError; end
4
+
3
5
  class CommandConnectorError < Foobara::RuntimeError
4
6
  class << self
5
7
  def context_type_declaration
@@ -349,7 +351,7 @@ module Foobara
349
351
  Foobara.foobara_lookup_type(name, mode: Namespace::LookupMode::RELAXED)
350
352
  end
351
353
 
352
- def foobara_manifest
354
+ def foobara_manifest(remove_sensitive: true)
353
355
  process_delayed_connections
354
356
 
355
357
  # Drive all of this off of the list of exposed commands...
@@ -384,6 +386,11 @@ module Foobara
384
386
  if o.foobara_domain? || o.foobara_organization? || (o.is_a?(::Class) && o < Foobara::Command)
385
387
  next
386
388
  end
389
+ elsif o.is_a?(Types::Type) && remove_sensitive && o.sensitive?
390
+ # :nocov:
391
+ raise UnexpectedSensitiveTypeInManifestError,
392
+ "Unexpected sensitive type in manifest: #{o.scoped_full_path}. Make sure these are not included."
393
+ # :nocov:
387
394
  end
388
395
 
389
396
  object = o
@@ -412,7 +419,7 @@ module Foobara
412
419
  cat = h[category_symbol] ||= {}
413
420
  # TODO: do we really need to enter the namespace here for this?
414
421
  cat[manifest_reference] = Foobara::Namespace.use namespace do
415
- object.foobara_manifest(to_include: additional_to_include)
422
+ object.foobara_manifest(to_include: additional_to_include, remove_sensitive:)
416
423
  end
417
424
 
418
425
  included << object
@@ -100,11 +100,11 @@ module Foobara
100
100
  parent
101
101
  end
102
102
 
103
- def foobara_manifest(to_include: Set.new)
103
+ def foobara_manifest(to_include: Set.new, remove_sensitive: true)
104
104
  # A bit of a hack here. We don't have an exposed type class to encapsulate including exposed domains/orgs
105
105
  # which leads to a bug when a global command is exposed that depends on a type in a non-global domain
106
106
  # but there being no other reason to include that non-global domain.
107
- transformed_command_class.types_depended_on.select(&:registered?).each do |type|
107
+ transformed_command_class.types_depended_on(remove_sensitive:).select(&:registered?).each do |type|
108
108
  full_domain_name = type.foobara_domain.scoped_full_name
109
109
 
110
110
  unless root_registry.foobara_lookup_domain(full_domain_name)
@@ -114,7 +114,7 @@ module Foobara
114
114
  end
115
115
  end
116
116
 
117
- transformed_command_class.foobara_manifest(to_include:).merge(super).merge(
117
+ transformed_command_class.foobara_manifest(to_include:, remove_sensitive:).merge(super).merge(
118
118
  Util.remove_blank(
119
119
  scoped_category: :command,
120
120
  domain: command_class.domain.foobara_manifest_reference,
@@ -14,10 +14,10 @@ module Foobara
14
14
  end
15
15
 
16
16
  # TODO: unable to address types here so it is handled as a hack higher up...
17
- def foobara_manifest(to_include: Set.new)
17
+ def foobara_manifest(to_include: Set.new, remove_sensitive: true)
18
18
  to_include << foobara_organization
19
19
 
20
- domain_manifest = domain_module.foobara_manifest(to_include: Set.new)
20
+ domain_manifest = domain_module.foobara_manifest(to_include: Set.new, remove_sensitive:)
21
21
  mode = Foobara::Namespace::LookupMode::DIRECT
22
22
  commands = foobara_all_command(mode:).map(&:foobara_manifest_reference).sort
23
23
 
@@ -14,8 +14,8 @@ module Foobara
14
14
  end
15
15
 
16
16
  # TODO: unable to address types here so it is handled as a hack higher up...
17
- def foobara_manifest(to_include: Set.new)
18
- organization_manifest = organization_module.foobara_manifest(to_include: Set.new)
17
+ def foobara_manifest(to_include: Set.new, remove_sensitive: true)
18
+ organization_manifest = organization_module.foobara_manifest(to_include: Set.new, remove_sensitive:)
19
19
  mode = Foobara::Namespace::LookupMode::DIRECT
20
20
  domains = foobara_all_domain(mode:).map(&:foobara_manifest_reference).sort
21
21
 
@@ -102,8 +102,8 @@ module Foobara
102
102
  }
103
103
  end
104
104
 
105
- def foobara_manifest(to_include: Set.new)
106
- types = types_depended_on.map do |t|
105
+ def foobara_manifest(to_include: Set.new, remove_sensitive: false)
106
+ types = types_depended_on(remove_sensitive:).map do |t|
107
107
  to_include << t
108
108
  t.foobara_manifest_reference
109
109
  end
@@ -46,7 +46,7 @@ module Foobara
46
46
  end
47
47
 
48
48
  # TODO: technically does not belong in this project but maybe it should
49
- def foobara_manifest(to_include: Set.new)
49
+ def foobara_manifest(to_include: Set.new, remove_sensitive: false)
50
50
  to_include << error_class
51
51
 
52
52
  if processor
@@ -5,7 +5,10 @@ module Foobara
5
5
  class << self
6
6
  # Need to override this otherwise we install Model twice
7
7
  def install!
8
- TypeDeclarations.register_type_declaration(TypeDeclarations::Handlers::ExtendDetachedEntityTypeDeclaration.new)
8
+ handler = TypeDeclarations::Handlers::ExtendDetachedEntityTypeDeclaration.new
9
+ TypeDeclarations.register_type_declaration(handler)
10
+
11
+ TypeDeclarations.register_sensitive_type_remover(SensitiveTypeRemovers::DetachedEntity.new(handler))
9
12
 
10
13
  model = Namespace.global.foobara_lookup_type!(:model)
11
14
  BuiltinTypes.build_and_register!(:detached_entity, model, nil)
@@ -5,14 +5,24 @@ module Foobara
5
5
  include Concern
6
6
 
7
7
  module ClassMethods
8
- def foobara_associations
9
- @foobara_associations ||= construct_associations
8
+ def foobara_associations(remove_sensitive: false)
9
+ if defined?(@foobara_associations) && @foobara_associations.key?(remove_sensitive)
10
+ return @foobara_associations[remove_sensitive]
11
+ end
12
+
13
+ @foobara_associations ||= {}
14
+ @foobara_associations[remove_sensitive] = construct_associations(remove_sensitive:)
10
15
  end
11
16
 
12
17
  alias associations foobara_associations
13
18
 
14
- def foobara_deep_associations
15
- @foobara_deep_associations ||= begin
19
+ def foobara_deep_associations(remove_sensitive: false)
20
+ if defined?(@foobara_deep_associations) && @foobara_deep_associations.key?(remove_sensitive)
21
+ return @foobara_deep_associations[remove_sensitive]
22
+ end
23
+
24
+ @foobara_deep_associations ||= {}
25
+ @foobara_deep_associations[remove_sensitive] = begin
16
26
  deep = {}
17
27
 
18
28
  associations.each_pair do |data_path, type|
@@ -20,7 +30,7 @@ module Foobara
20
30
 
21
31
  entity_class = type.target_class
22
32
 
23
- entity_class.deep_associations.each_pair do |sub_data_path, sub_type|
33
+ entity_class.deep_associations(remove_sensitive:).each_pair do |sub_data_path, sub_type|
24
34
  deep["#{data_path}.#{sub_data_path}"] = sub_type
25
35
  end
26
36
  end
@@ -118,27 +128,39 @@ module Foobara
118
128
  def construct_associations(
119
129
  type = attributes_type,
120
130
  path = DataPath.new,
121
- result = {}
131
+ result = {},
132
+ remove_sensitive: false
122
133
  )
123
134
  if type.extends?(BuiltinTypes[:entity])
124
135
  result[path.to_s] = type
125
136
  elsif type.extends?(BuiltinTypes[:tuple])
126
137
  element_types = type.element_types
127
138
 
139
+ if remove_sensitive
140
+ # TODO: test this code path
141
+ # :nocov:
142
+ element_types = element_types&.reject(&:sensitive?)
143
+ # :nocov:
144
+ end
145
+
128
146
  element_types&.each&.with_index do |element_type, index|
129
- construct_associations(element_type, path.append(index), result)
147
+ construct_associations(element_type, path.append(index), result, remove_sensitive:)
130
148
  end
131
149
  elsif type.extends?(BuiltinTypes[:array])
132
150
  # TODO: what to do about an associative array type?? Unclear how to make a key from that...
133
151
  # TODO: raise if associative array contains a non-persisted record to handle this edge case for now.
134
152
  element_type = type.element_type
135
153
 
136
- if element_type
137
- construct_associations(element_type, path.append(:"#"), result)
154
+ if element_type && (!remove_sensitive || !element_type.sensitive?)
155
+ construct_associations(element_type, path.append(:"#"), result, remove_sensitive:)
138
156
  end
139
157
  elsif type.extends?(BuiltinTypes[:attributes]) # TODO: matches attributes itself instead of only subtypes
140
158
  type.element_types.each_pair do |attribute_name, element_type|
141
- construct_associations(element_type, path.append(attribute_name), result)
159
+ if remove_sensitive && element_type.sensitive?
160
+ next
161
+ end
162
+
163
+ construct_associations(element_type, path.append(attribute_name), result, remove_sensitive:)
142
164
  end
143
165
  elsif type.extends?(BuiltinTypes[:model])
144
166
  target_class = type.target_class
@@ -146,11 +168,13 @@ module Foobara
146
168
  method = target_class.respond_to?(:foobara_attributes_type) ? :foobara_attributes_type : :attributes_type
147
169
  attributes_type = target_class.send(method)
148
170
 
149
- construct_associations(attributes_type, path, result)
171
+ if !remove_sensitive || !attributes_type.sensitive?
172
+ construct_associations(attributes_type, path, result, remove_sensitive:)
173
+ end
150
174
  elsif type.extends?(BuiltinTypes[:associative_array])
151
175
  # not going to bother testing this for now
152
176
  # :nocov:
153
- if contains_associations?(type)
177
+ if contains_associations?(type, remove_sensitive:)
154
178
  raise "Associative array types with associations in them are not currently supported. " \
155
179
  "Use attributes type if you can or set the key_type and/or value_type to duck type"
156
180
  end
@@ -160,10 +184,19 @@ module Foobara
160
184
  result
161
185
  end
162
186
 
163
- def contains_associations?(type = entity_type, initial = true)
187
+ def contains_associations?(type = entity_type, initial = true, remove_sensitive: false)
164
188
  if type.extends?(BuiltinTypes[:detached_entity])
165
189
  if initial
166
- contains_associations?(type.element_types, false)
190
+ element_types = type.element_types
191
+
192
+ if remove_sensitive
193
+ # TODO: test this code path
194
+ # :nocov:
195
+ element_types = element_types&.reject(&:sensitive?)
196
+ # :nocov:
197
+ end
198
+
199
+ contains_associations?(element_types, false, remove_sensitive:)
167
200
  else
168
201
  true
169
202
  end
@@ -172,21 +205,28 @@ module Foobara
172
205
  # TODO: raise if associative array contains a non-persisted record to handle this edge case for now.
173
206
  element_type = type.element_type
174
207
 
175
- if element_type
176
- contains_associations?(element_type, false)
208
+ if element_type && (!remove_sensitive || !element_type.sensitive?)
209
+ contains_associations?(element_type, false, remove_sensitive:)
177
210
  end
178
211
  elsif type.extends?(BuiltinTypes[:attributes])
179
212
  type.element_types.values.any? do |element_type|
180
- contains_associations?(element_type, false)
213
+ if !remove_sensitive || !element_type.sensitive?
214
+ contains_associations?(element_type, false, remove_sensitive:)
215
+ end
181
216
  end
182
217
  elsif type.extends?(BuiltinTypes[:associative_array])
183
218
  element_types = type.element_types
184
219
 
185
220
  if element_types
186
- key_type, value_type = element_types
221
+ types = element_types
222
+
223
+ if remove_sensitive
224
+ types = types&.reject(&:sensitive?)
225
+ end
187
226
 
188
- contains_associations?(key_type, false) ||
189
- contains_associations?(value_type, false)
227
+ types.any? do |type|
228
+ contains_associations?(type, false, remove_sensitive:)
229
+ end
190
230
  end
191
231
  end
192
232
  end
@@ -17,15 +17,15 @@ module Foobara
17
17
  types.map(&:target_class).uniq
18
18
  end
19
19
 
20
- def foobara_manifest(to_include: Set.new)
21
- associations = foobara_associations.map do |(path, type)|
20
+ def foobara_manifest(to_include: Set.new, remove_sensitive: false)
21
+ associations = foobara_associations(remove_sensitive:).map do |(path, type)|
22
22
  entity_class = type.target_class
23
23
  entity_name = entity_class.foobara_type.scoped_full_name
24
24
 
25
25
  [path, entity_name]
26
26
  end.sort.to_h
27
27
 
28
- deep_associations = foobara_deep_associations.map do |(path, type)|
28
+ deep_associations = foobara_deep_associations(remove_sensitive:).map do |(path, type)|
29
29
  entity_class = type.target_class
30
30
  entity_name = entity_class.foobara_type.scoped_full_name
31
31
 
@@ -8,7 +8,13 @@ module Foobara
8
8
 
9
9
  module ClassMethods
10
10
  def entity_type
11
- model_type
11
+ return @model_type if defined?(@model_type)
12
+
13
+ if attributes_type
14
+ set_model_type
15
+ end
16
+
17
+ @model_type
12
18
  end
13
19
 
14
20
  def type_declaration(...)
@@ -18,7 +18,7 @@ module Foobara
18
18
  end
19
19
  end
20
20
 
21
- def foobara_manifest(to_include: Set.new)
21
+ def foobara_manifest(to_include: Set.new, remove_sensitive: false)
22
22
  manifest = super
23
23
 
24
24
  if detached_context?
@@ -37,7 +37,7 @@ module Foobara
37
37
  manifest
38
38
  end
39
39
 
40
- def types_to_add_to_manifest
40
+ def types_to_add_to_manifest(remove_sensitive: false)
41
41
  types = super
42
42
 
43
43
  if detached_context?
@@ -0,0 +1,8 @@
1
+ module Foobara
2
+ class DetachedEntity < Model
3
+ module SensitiveTypeRemovers
4
+ class DetachedEntity < Model::SensitiveTypeRemovers::Model
5
+ end
6
+ end
7
+ end
8
+ end
@@ -109,10 +109,14 @@ module Foobara
109
109
 
110
110
  # TODO: unclear why we need this check, hmmm, figure it out and document it (or delete if not needed)
111
111
  break if child.constants(false).any? do |constant|
112
+ # TODO: a clue: this stopped being entered by the test suite after deleting GlobalDomain::Types
113
+ # in .reset_alls hmmmmmm...
114
+ # :nocov:
112
115
  value = child.const_get(constant)
113
116
 
114
117
  # TODO: can we make this not coupled to model project??
115
118
  value.is_a?(Types::Type) || (value.is_a?(::Class) && value < Foobara::Model)
119
+ # :nocov:
116
120
  end
117
121
 
118
122
  lower_case_constants = child.instance_variable_get(:@foobara_lowercase_constants)
@@ -393,7 +397,7 @@ module Foobara
393
397
  end
394
398
 
395
399
  # TODO: can we kill this skip concept?
396
- def foobara_manifest(to_include: Set.new)
400
+ def foobara_manifest(to_include: Set.new, remove_sensitive: false)
397
401
  depends_on = foobara_depends_on.map do |name|
398
402
  domain = Domain.to_domain(name)
399
403
  to_include << domain
@@ -37,7 +37,7 @@ module Foobara
37
37
  end
38
38
  end
39
39
 
40
- def foobara_manifest(to_include: Set.new)
40
+ def foobara_manifest(to_include: Set.new, remove_sensitive: false)
41
41
  h = {
42
42
  scoped_path:,
43
43
  scoped_name:,