foobara 0.0.85 → 0.0.87
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 +8 -0
- data/projects/command/src/transformed_command.rb +101 -71
- data/projects/command_connectors/src/command_connector.rb +19 -5
- data/projects/command_connectors/src/serializers/errors_serializer.rb +0 -1
- data/projects/detached_entity/src/concerns/associations.rb +25 -2
- data/projects/domain/src/domain_module_extension.rb +6 -2
- data/projects/entity/src/sensitive_value_removers/entity.rb +20 -4
- data/projects/manifest/src/foobara/manifest/type_declaration.rb +0 -1
- data/projects/model/src/extensions/type_declarations/handlers/extend_registered_model_type_declaration.rb +1 -1
- data/projects/model/src/sensitive_value_removers/model.rb +3 -5
- data/projects/namespace/src/namespace_helpers.rb +14 -1
- data/projects/type_declarations/src/attributes.rb +16 -0
- data/projects/type_declarations/src/attributes_transformer.rb +27 -0
- data/projects/type_declarations/src/handlers/registered_type_declaration/to_type_transformer.rb +1 -1
- data/projects/type_declarations/src/remove_sensitive_values_transformer.rb +16 -17
- data/projects/type_declarations/src/typed_transformer.rb +83 -69
- data/projects/type_declarations/src/with_registries.rb +0 -4
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45093221881afa7419b208493f3787403c664a149f77728ac64daaea00c7b083
|
4
|
+
data.tar.gz: 4103467f677825cd70e2d8d468cc9845511789c32e4a2f69c3cc4901fb9704c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e655dc065c7b923be1d76742e9fc651f8d7581cdfd3ad9130cc20e474ca42bb15791ebc35238bc52d8b255cef440237234c01eda4189b850287ecd142141271e
|
7
|
+
data.tar.gz: 54893503e3dfed78a608590f44a9673aca2b8c208094a306c7b10634afea59380caee6a0998cd283c1ecb7097b227705b9a3644186d2f3afe561ee0676170717
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
# [0.0.87] - 2025-03-26
|
2
|
+
|
3
|
+
- TypedTransformer refactor to reduce confusion and bugs
|
4
|
+
|
5
|
+
# [0.0.86] - 2025-03-23
|
6
|
+
|
7
|
+
- Add an AttributesTransformer.only method to quickly get a TypedTransformer (helpful with inputs_transformers)
|
8
|
+
|
1
9
|
# [0.0.85] - 2025-03-22
|
2
10
|
|
3
11
|
- Add Manifest::TypeDeclaration#sensitive?
|
@@ -36,12 +36,12 @@ module Foobara
|
|
36
36
|
result_type = command_class.result_type
|
37
37
|
|
38
38
|
if result_type&.has_sensitive_types?
|
39
|
+
|
39
40
|
remover_class = Foobara::TypeDeclarations.sensitive_value_remover_class_for_type(result_type)
|
40
41
|
|
41
42
|
remover = Namespace.use scoped_namespace do
|
42
43
|
transformed_result_type = result_type_from_transformers(result_type, result_transformers)
|
43
|
-
|
44
|
-
remover_class.new(transformed_result_type).tap do |r|
|
44
|
+
remover_class.new(from: transformed_result_type).tap do |r|
|
45
45
|
r.scoped_path = ["SensitiveValueRemover", *transformed_result_type.scoped_full_path]
|
46
46
|
end
|
47
47
|
end
|
@@ -71,25 +71,34 @@ module Foobara
|
|
71
71
|
to: :command_class
|
72
72
|
|
73
73
|
def inputs_type
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
74
|
+
return @inputs_type if defined?(@inputs_type)
|
75
|
+
|
76
|
+
@inputs_type = if inputs_transformer
|
77
|
+
if inputs_transformer.is_a?(Value::Processor::Pipeline)
|
78
|
+
inputs_transformer.processors.each do |transformer|
|
79
|
+
if transformer.is_a?(TypeDeclarations::TypedTransformer)
|
80
|
+
from_type = transformer.from_type
|
81
|
+
if from_type
|
82
|
+
@inputs_type = from_type
|
83
|
+
return from_type
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
command_class.inputs_type
|
89
|
+
else
|
90
|
+
inputs_transformer.from_type || command_class.inputs_type
|
91
|
+
end
|
92
|
+
else
|
93
|
+
command_class.inputs_type
|
94
|
+
end
|
85
95
|
end
|
86
96
|
|
87
97
|
def result_type_from_transformers(result_type, transformers)
|
88
|
-
|
98
|
+
transformers.reverse.each do |transformer|
|
89
99
|
if transformer.is_a?(Class) && transformer < TypeDeclarations::TypedTransformer
|
90
|
-
new_type = transformer.
|
91
|
-
|
92
|
-
result_type = new_type if new_type
|
100
|
+
new_type = transformer.to_type
|
101
|
+
return new_type if new_type
|
93
102
|
end
|
94
103
|
end
|
95
104
|
|
@@ -217,6 +226,69 @@ module Foobara
|
|
217
226
|
)
|
218
227
|
)
|
219
228
|
end
|
229
|
+
|
230
|
+
def inputs_transformer
|
231
|
+
return @inputs_transformer if defined?(@inputs_transformer)
|
232
|
+
|
233
|
+
if inputs_transformers.empty?
|
234
|
+
@inputs_transformer = nil
|
235
|
+
return
|
236
|
+
end
|
237
|
+
|
238
|
+
@inputs_transformer = begin
|
239
|
+
transformers = transformers_to_processors(inputs_transformers,
|
240
|
+
command_class.inputs_type, direction: :to)
|
241
|
+
|
242
|
+
if transformers.size == 1
|
243
|
+
transformers.first
|
244
|
+
else
|
245
|
+
Value::Processor::Pipeline.new(processors: transformers)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def result_transformer
|
251
|
+
return @result_transformer if defined?(@result_transformer)
|
252
|
+
|
253
|
+
if result_transformers.empty?
|
254
|
+
@result_transformer = nil
|
255
|
+
return
|
256
|
+
end
|
257
|
+
|
258
|
+
@result_transformer = begin
|
259
|
+
transformers = transformers_to_processors(result_transformers, command_class.result_type, direction: :from)
|
260
|
+
|
261
|
+
if transformers.size == 1
|
262
|
+
transformers.first
|
263
|
+
else
|
264
|
+
Value::Processor::Pipeline.new(processors: transformers)
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
# TODO: this is pretty messy with smells.
|
270
|
+
def transformers_to_processors(transformers, target_type, direction: :from, declaration_data: self)
|
271
|
+
transformers.map do |transformer|
|
272
|
+
if transformer.is_a?(Class)
|
273
|
+
if transformer < TypeDeclarations::TypedTransformer
|
274
|
+
transformer.new(direction => target_type).tap do |tx|
|
275
|
+
new_type = direction == :from ? tx.to_type : tx.from_type
|
276
|
+
target_type = new_type if new_type
|
277
|
+
end
|
278
|
+
else
|
279
|
+
transformer.new(declaration_data)
|
280
|
+
end
|
281
|
+
elsif transformer.is_a?(Value::Processor)
|
282
|
+
transformer
|
283
|
+
elsif transformer.respond_to?(:call)
|
284
|
+
Value::Transformer.create(transform: transformer)
|
285
|
+
else
|
286
|
+
# :nocov:
|
287
|
+
raise "Not sure how to apply #{inputs_transformer}"
|
288
|
+
# :nocov:
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
220
292
|
end
|
221
293
|
|
222
294
|
attr_accessor :command, :untransformed_inputs, :transformed_inputs, :outcome, :authenticated_user
|
@@ -259,16 +331,16 @@ module Foobara
|
|
259
331
|
end
|
260
332
|
|
261
333
|
def transform_inputs
|
262
|
-
self.transformed_inputs = if inputs_transformer
|
263
|
-
inputs_transformer.process_value!(untransformed_inputs)
|
334
|
+
self.transformed_inputs = if self.class.inputs_transformer
|
335
|
+
self.class.inputs_transformer.process_value!(untransformed_inputs)
|
264
336
|
else
|
265
337
|
untransformed_inputs
|
266
338
|
end
|
267
339
|
end
|
268
340
|
|
269
341
|
def transform_result
|
270
|
-
if result_transformer
|
271
|
-
self.outcome = Outcome.success(result_transformer.process_value!(result))
|
342
|
+
if self.class.result_transformer
|
343
|
+
self.outcome = Outcome.success(self.class.result_transformer.process_value!(result))
|
272
344
|
end
|
273
345
|
end
|
274
346
|
|
@@ -278,30 +350,6 @@ module Foobara
|
|
278
350
|
end
|
279
351
|
end
|
280
352
|
|
281
|
-
def inputs_transformer
|
282
|
-
return nil if inputs_transformers.empty?
|
283
|
-
|
284
|
-
transformers = transformers_to_processors(inputs_transformers, command_class.inputs_type)
|
285
|
-
|
286
|
-
if transformers.size == 1
|
287
|
-
transformers.first
|
288
|
-
else
|
289
|
-
Value::Processor::Pipeline.new(processors: transformers)
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
def result_transformer
|
294
|
-
return nil if result_transformers.empty?
|
295
|
-
|
296
|
-
transformers = transformers_to_processors(result_transformers, command_class.result_type)
|
297
|
-
|
298
|
-
if transformers.size == 1
|
299
|
-
transformers.first
|
300
|
-
else
|
301
|
-
Value::Processor::Pipeline.new(processors: transformers)
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
353
|
# TODO: let's get this out of here...
|
306
354
|
# we might want to have different serializers for different command instances of the same class.
|
307
355
|
# but currently serializers is set on the class. Since this class should not be concerned with serialization, we
|
@@ -309,7 +357,7 @@ module Foobara
|
|
309
357
|
def serializer
|
310
358
|
return nil if serializers.empty?
|
311
359
|
|
312
|
-
transformers = transformers_to_processors(serializers, nil)
|
360
|
+
transformers = self.class.transformers_to_processors(serializers, nil, declaration_data: self)
|
313
361
|
|
314
362
|
if transformers.size == 1
|
315
363
|
transformers.first
|
@@ -321,7 +369,8 @@ module Foobara
|
|
321
369
|
def errors_transformer
|
322
370
|
return nil if errors_transformers.empty?
|
323
371
|
|
324
|
-
transformers = transformers_to_processors(errors_transformers, nil
|
372
|
+
transformers = self.class.transformers_to_processors(errors_transformers, nil, direction: :from,
|
373
|
+
declaration_data: self)
|
325
374
|
|
326
375
|
if transformers.size == 1
|
327
376
|
transformers.first
|
@@ -334,7 +383,11 @@ module Foobara
|
|
334
383
|
def pre_commit_transformer
|
335
384
|
return nil if pre_commit_transformers.empty?
|
336
385
|
|
337
|
-
transformers = transformers_to_processors(
|
386
|
+
transformers = self.class.transformers_to_processors(
|
387
|
+
pre_commit_transformers,
|
388
|
+
nil,
|
389
|
+
declaration_data: self
|
390
|
+
)
|
338
391
|
|
339
392
|
if transformers.size == 1
|
340
393
|
transformers.first
|
@@ -343,29 +396,6 @@ module Foobara
|
|
343
396
|
end
|
344
397
|
end
|
345
398
|
|
346
|
-
def transformers_to_processors(transformers, from_type)
|
347
|
-
transformers.map do |transformer|
|
348
|
-
if transformer.is_a?(Class)
|
349
|
-
if transformer < TypeDeclarations::TypedTransformer
|
350
|
-
transformer.new(from_type).tap do |tx|
|
351
|
-
new_type = tx.type
|
352
|
-
from_type = new_type if new_type
|
353
|
-
end
|
354
|
-
else
|
355
|
-
transformer.new(self)
|
356
|
-
end
|
357
|
-
elsif transformer.is_a?(Value::Processor)
|
358
|
-
transformer
|
359
|
-
elsif transformer.respond_to?(:call)
|
360
|
-
Value::Transformer.create(transform: transformer)
|
361
|
-
else
|
362
|
-
# :nocov:
|
363
|
-
raise "Not sure how to apply #{inputs_transformer}"
|
364
|
-
# :nocov:
|
365
|
-
end
|
366
|
-
end
|
367
|
-
end
|
368
|
-
|
369
399
|
def construct_command
|
370
400
|
self.command = command_class.new(transformed_inputs)
|
371
401
|
end
|
@@ -387,14 +387,28 @@ module Foobara
|
|
387
387
|
additional_to_include.delete(o)
|
388
388
|
|
389
389
|
if o.is_a?(::Module)
|
390
|
-
if o.foobara_domain? || o.foobara_organization?
|
390
|
+
if o.foobara_domain? || o.foobara_organization?
|
391
|
+
unless o.foobara_root_namespace == command_registry
|
392
|
+
next
|
393
|
+
end
|
394
|
+
elsif o.is_a?(::Class) && o < Foobara::Command
|
391
395
|
next
|
392
396
|
end
|
393
|
-
elsif o.is_a?(Types::Type)
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
+
elsif o.is_a?(Types::Type)
|
398
|
+
if remove_sensitive && o.sensitive?
|
399
|
+
# :nocov:
|
400
|
+
raise UnexpectedSensitiveTypeInManifestError,
|
401
|
+
"Unexpected sensitive type in manifest: #{o.scoped_full_path}. Make sure these are not included."
|
397
402
|
# :nocov:
|
403
|
+
else
|
404
|
+
domain_name = o.foobara_domain.scoped_full_name
|
405
|
+
|
406
|
+
unless command_registry.foobara_registered?(domain_name)
|
407
|
+
domain = command_registry.build_and_register_exposed_domain(domain_name)
|
408
|
+
additional_to_include << domain
|
409
|
+
additional_to_include << domain.foobara_organization
|
410
|
+
end
|
411
|
+
end
|
398
412
|
end
|
399
413
|
|
400
414
|
object = o
|
@@ -123,6 +123,29 @@ module Foobara
|
|
123
123
|
end
|
124
124
|
end
|
125
125
|
|
126
|
+
def construct_deep_associations(
|
127
|
+
type = attributes_type,
|
128
|
+
path = DataPath.new,
|
129
|
+
result = {},
|
130
|
+
remove_sensitive: false
|
131
|
+
)
|
132
|
+
associations = construct_associations(type, path, result, remove_sensitive:)
|
133
|
+
|
134
|
+
deep = {}
|
135
|
+
|
136
|
+
associations.each_pair do |data_path, association_type|
|
137
|
+
deep[data_path] = association_type
|
138
|
+
|
139
|
+
entity_class = association_type.target_class
|
140
|
+
|
141
|
+
entity_class.deep_associations(remove_sensitive:).each_pair do |sub_data_path, sub_type|
|
142
|
+
deep["#{data_path}.#{sub_data_path}"] = sub_type
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
deep
|
147
|
+
end
|
148
|
+
|
126
149
|
# TODO: this big switch is a problem. Hard to create new types in other projects without being able
|
127
150
|
# to modify this switch. Figure out what to do.
|
128
151
|
def construct_associations(
|
@@ -224,8 +247,8 @@ module Foobara
|
|
224
247
|
types = types&.reject(&:sensitive?)
|
225
248
|
end
|
226
249
|
|
227
|
-
types.any? do |
|
228
|
-
contains_associations?(
|
250
|
+
types.any? do |key_or_value_type|
|
251
|
+
contains_associations?(key_or_value_type, false, remove_sensitive:)
|
229
252
|
end
|
230
253
|
end
|
231
254
|
end
|
@@ -231,9 +231,13 @@ module Foobara
|
|
231
231
|
end
|
232
232
|
end
|
233
233
|
|
234
|
-
def foobara_type_from_declaration(
|
234
|
+
def foobara_type_from_declaration(*args, **opts, &block)
|
235
|
+
if opts.empty? && block.nil? && args.size == 1 && args.first.is_a?(Types::Type)
|
236
|
+
return args.first
|
237
|
+
end
|
238
|
+
|
235
239
|
Foobara::Namespace.use self do
|
236
|
-
foobara_type_builder.type_for_declaration(
|
240
|
+
foobara_type_builder.type_for_declaration(*args, **opts, &block)
|
237
241
|
end
|
238
242
|
end
|
239
243
|
|
@@ -3,12 +3,28 @@ module Foobara
|
|
3
3
|
module SensitiveValueRemovers
|
4
4
|
class Entity < DetachedEntity::SensitiveValueRemovers::DetachedEntity
|
5
5
|
def transform(record)
|
6
|
-
|
6
|
+
if record.loaded? || record.created?
|
7
|
+
sanitized_record = super
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
sanitized_record.is_loaded = record.loaded?
|
10
|
+
sanitized_record.is_persisted = record.persisted?
|
10
11
|
|
11
|
-
|
12
|
+
sanitized_record
|
13
|
+
elsif record.persisted?
|
14
|
+
# We will assume that we do not need to clean up the primary key itself as
|
15
|
+
# we will assume we don't allow sensitive primary keys for now.
|
16
|
+
sanitized_record = to_type.target_class.build(record.class.primary_key_attribute => record.primary_key)
|
17
|
+
|
18
|
+
sanitized_record.is_persisted = true
|
19
|
+
sanitized_record.is_loaded = false
|
20
|
+
sanitized_record.is_built = false
|
21
|
+
|
22
|
+
sanitized_record
|
23
|
+
else
|
24
|
+
# :nocov:
|
25
|
+
raise "Not sure what to do with a record that isn't loaded, created, or persisted"
|
26
|
+
# :nocov:
|
27
|
+
end
|
12
28
|
end
|
13
29
|
|
14
30
|
def build_method
|
@@ -5,12 +5,10 @@ module Foobara
|
|
5
5
|
def transform(record)
|
6
6
|
attributes_type = from_type.element_types
|
7
7
|
|
8
|
-
sanitized_attributes,
|
8
|
+
sanitized_attributes, _changed = sanitize_value(attributes_type, record.attributes)
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
else
|
13
|
-
record
|
10
|
+
Namespace.use(to_type.created_in_namespace) do
|
11
|
+
to_type.target_class.send(build_method, sanitized_attributes)
|
14
12
|
end
|
15
13
|
end
|
16
14
|
|
@@ -164,7 +164,20 @@ module Foobara
|
|
164
164
|
def foobara_autoset_scoped_path(mod, make_top_level: false)
|
165
165
|
return if mod.scoped_path_set?
|
166
166
|
|
167
|
-
|
167
|
+
mod_name = mod.name
|
168
|
+
|
169
|
+
if mod_name.nil?
|
170
|
+
parent = mod.superclass
|
171
|
+
super_name = nil
|
172
|
+
|
173
|
+
begin
|
174
|
+
super_name = parent.scoped_path_set? ? parent.scoped_full_name : parent.name
|
175
|
+
end until super_name
|
176
|
+
|
177
|
+
mod_name = [super_name, mod.object_id.to_s(16)].join("::")
|
178
|
+
end
|
179
|
+
|
180
|
+
scoped_path = mod_name.split("::")
|
168
181
|
|
169
182
|
adjusted_scoped_path = []
|
170
183
|
|
@@ -33,6 +33,22 @@ module Foobara
|
|
33
33
|
)
|
34
34
|
end
|
35
35
|
|
36
|
+
def only(declaration, *keys)
|
37
|
+
valid_keys = declaration[:element_type_declarations].keys
|
38
|
+
keys_to_keep = keys.map(&:to_sym)
|
39
|
+
invalid_keys = keys_to_keep - valid_keys
|
40
|
+
|
41
|
+
if invalid_keys.any?
|
42
|
+
# :nocov:
|
43
|
+
raise ArgumentError, "Invalid keys: #{invalid_keys} expected only #{valid_keys}"
|
44
|
+
# :nocov:
|
45
|
+
end
|
46
|
+
|
47
|
+
keys_to_reject = valid_keys - keys_to_keep
|
48
|
+
|
49
|
+
reject(declaration, keys_to_reject)
|
50
|
+
end
|
51
|
+
|
36
52
|
def reject(declaration, *keys)
|
37
53
|
# TODO: do we really need a deep dup?
|
38
54
|
declaration = Util.deep_dup(declaration)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Foobara
|
2
|
+
class AttributesTransformer < TypeDeclarations::TypedTransformer
|
3
|
+
class << self
|
4
|
+
attr_accessor :only_attributes
|
5
|
+
|
6
|
+
def only(*attribute_names)
|
7
|
+
transformer_class = Class.new(self)
|
8
|
+
transformer_class.only_attributes = attribute_names
|
9
|
+
|
10
|
+
transformer_class
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_type_declaration
|
15
|
+
from_declaration = from_type.declaration_data
|
16
|
+
TypeDeclarations::Attributes.only(from_declaration, *self.class.only_attributes)
|
17
|
+
end
|
18
|
+
|
19
|
+
def transform(inputs)
|
20
|
+
inputs.slice(*allowed_keys)
|
21
|
+
end
|
22
|
+
|
23
|
+
def allowed_keys
|
24
|
+
to_type.element_types.keys
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/projects/type_declarations/src/handlers/registered_type_declaration/to_type_transformer.rb
CHANGED
@@ -15,7 +15,7 @@ module Foobara
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def registered_type(strict_type_declaration)
|
18
|
-
|
18
|
+
lookup_type!(type_symbol(strict_type_declaration))
|
19
19
|
end
|
20
20
|
|
21
21
|
def target_classes(strict_type_declaration)
|
@@ -3,24 +3,21 @@ require_relative "typed_transformer"
|
|
3
3
|
module Foobara
|
4
4
|
module TypeDeclarations
|
5
5
|
class RemoveSensitiveValuesTransformer < TypedTransformer
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
def from(...)
|
7
|
+
super.tap do
|
8
|
+
associations = Foobara::DetachedEntity.construct_deep_associations(from_type)
|
9
|
+
|
10
|
+
associations&.values&.reverse&.each do |entity_type|
|
11
|
+
declaration = entity_type.declaration_data
|
12
|
+
sanitized_type_declaration = TypeDeclarations.remove_sensitive_types(declaration)
|
11
13
|
|
12
|
-
|
14
|
+
Domain.current.foobara_type_from_declaration(sanitized_type_declaration)
|
15
|
+
end
|
13
16
|
end
|
14
17
|
end
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
def initialize(...)
|
19
|
-
super
|
20
|
-
|
21
|
-
self.namespace = Namespace.current
|
22
|
-
|
23
|
-
type
|
19
|
+
def to_type_declaration
|
20
|
+
TypeDeclarations.remove_sensitive_types(from_type.declaration_data)
|
24
21
|
end
|
25
22
|
|
26
23
|
def transform(_value)
|
@@ -31,9 +28,11 @@ module Foobara
|
|
31
28
|
|
32
29
|
def sanitize_value(type, value)
|
33
30
|
if type.has_sensitive_types?
|
34
|
-
|
35
|
-
|
36
|
-
|
31
|
+
sanitized_value = Namespace.use to_type.created_in_namespace do
|
32
|
+
remover_class = TypeDeclarations.sensitive_value_remover_class_for_type(type)
|
33
|
+
remover = remover_class.new(from: type)
|
34
|
+
remover.process_value!(value)
|
35
|
+
end
|
37
36
|
|
38
37
|
[sanitized_value, sanitized_value != value]
|
39
38
|
else
|
@@ -3,87 +3,101 @@ module Foobara
|
|
3
3
|
# TODO: this should instead be a processor and have its own possible_errors
|
4
4
|
class TypedTransformer < Value::Transformer
|
5
5
|
class << self
|
6
|
-
|
7
|
-
|
8
|
-
# If we are a noop, then we are going to output D.type and we expect B.type
|
9
|
-
# We obviously have a problem if D is incompatible with our output type.
|
10
|
-
# We need to know B.output_type in order to say what we are going to output.
|
11
|
-
#
|
12
|
-
# Conversely, we need to know what D expects in order to say what we expect to receive (sometimes)
|
13
|
-
#
|
14
|
-
# So logic is... For C to say what its type is, it must know B's output_type.
|
15
|
-
# or... I guess for an inputs transformer, we need to know what D expects as its type, right?
|
16
|
-
# since we have an obligation be compatible with it.
|
17
|
-
#
|
18
|
-
# Use case 1: command line interface gets awkward with models
|
19
|
-
# 1. Command takes model A
|
20
|
-
# 2. we want an inputs transformer that takes A.attributes_type
|
21
|
-
# 3. Therefore its type is A.attributes_type
|
22
|
-
# 4. And also, its output type is A.attributes_type in this case since there's no need to actually create the
|
23
|
-
# models.
|
24
|
-
# 5. So to tell our type, we must know the type of what comes next.
|
25
|
-
#
|
26
|
-
# Use case 2:
|
27
|
-
# 1. Command takes foo: :integer but we want to take bar: :string
|
28
|
-
# 2. transformer has this hard-coded knowledge.
|
29
|
-
# 3. we don't need to receive either types to answer our input and output types.
|
30
|
-
#
|
31
|
-
# Use case 3: Changing a record into its primary key
|
32
|
-
# 1. Command has result type of A which is an Entity
|
33
|
-
# 2. transformer takes an A record and returns record.primary_key
|
34
|
-
# 3. To know the output type, we need to know the result type of the previous type.
|
35
|
-
# 4. To know the input type, we need to know the type of the previous transformer since they are the same.
|
36
|
-
# (however, by convention we can just use nil in this case.)
|
37
|
-
#
|
38
|
-
# Use case 4: document upload
|
39
|
-
# 1. Command takes input stream plus some document info
|
40
|
-
# 2. controller action receives temporary file path
|
41
|
-
# 3. transformer opens input stream and replaces file path with input stream
|
42
|
-
# 4. In this case, we have hard-coded types.
|
43
|
-
#
|
44
|
-
# Challenge: we seem to not know in advance if the transformer needs to know what comes before it or what comes
|
45
|
-
# after it. Unless we are writing a one-off transformer then we have hard-coded knowledge.
|
46
|
-
#
|
47
|
-
# Seems like input transformer really needs to know what comes next, the target type.
|
48
|
-
# Seems like output transformer might require to know what came previously
|
49
|
-
#
|
50
|
-
# Plan:
|
51
|
-
# 1. Both inputs transformer and result have similar structure... they have a relevant type that they transform.
|
52
|
-
# The difference is that the result takes previous steps output and transforms it to a different type, whereas
|
53
|
-
# the input transformer needs to know what comes next in order to communicate its types.
|
54
|
-
# So we might be able to get away with a transformed_type that accepts the from_type. And the calling code can
|
55
|
-
# interpret how it goes. This might create some awkwardness or confusion at least when creating one of the
|
56
|
-
# two types of transformer.
|
57
|
-
def type_declaration(_from_type)
|
58
|
-
# :nocov:
|
59
|
-
nil
|
60
|
-
# :nocov:
|
6
|
+
def requires_declaration_data?
|
7
|
+
false
|
61
8
|
end
|
62
9
|
|
63
|
-
def
|
64
|
-
|
10
|
+
def requires_parent_declaration_data?
|
11
|
+
false
|
12
|
+
end
|
65
13
|
|
66
|
-
|
67
|
-
|
68
|
-
dec
|
69
|
-
else
|
70
|
-
Domain.current.foobara_type_from_declaration(dec)
|
71
|
-
end
|
72
|
-
end
|
14
|
+
def from(...)
|
15
|
+
@from_type = Domain.current.foobara_type_from_declaration(...)
|
73
16
|
end
|
17
|
+
|
18
|
+
def to(...)
|
19
|
+
@to_type = Domain.current.foobara_type_from_declaration(...)
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :from_type, :to_type
|
23
|
+
end
|
24
|
+
|
25
|
+
def from_type_declaration
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_type_declaration
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def from_type
|
34
|
+
return @from_type if defined?(@from_type)
|
35
|
+
|
36
|
+
@from_type = self.class.from_type || if from_type_declaration
|
37
|
+
Domain.current.foobara_type_from_declaration(from_type_declaration)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_type
|
42
|
+
return @to_type if defined?(@to_type)
|
43
|
+
|
44
|
+
@to_type = self.class.to_type || if to_type_declaration
|
45
|
+
Domain.current.foobara_type_from_declaration(to_type_declaration)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def has_to_type?
|
50
|
+
!!to_type
|
74
51
|
end
|
75
52
|
|
76
|
-
|
53
|
+
def has_from_type?
|
54
|
+
!!from_type
|
55
|
+
end
|
56
|
+
|
57
|
+
def from(...)
|
58
|
+
@from_type = Domain.current.foobara_type_from_declaration(...)
|
59
|
+
end
|
60
|
+
|
61
|
+
def to(...)
|
62
|
+
@to_type = Domain.current.foobara_type_from_declaration(...)
|
63
|
+
end
|
77
64
|
|
78
|
-
def
|
79
|
-
|
65
|
+
def initialize(from: nil, to: nil)
|
66
|
+
super()
|
67
|
+
|
68
|
+
if from
|
69
|
+
self.from from
|
70
|
+
end
|
71
|
+
|
72
|
+
if to
|
73
|
+
self.to to
|
74
|
+
end
|
80
75
|
|
81
|
-
|
76
|
+
# we want to force these to be created now in the current name space if they are declarations
|
77
|
+
from_type
|
78
|
+
to_type
|
82
79
|
end
|
83
80
|
|
84
81
|
def process_value(value)
|
82
|
+
if has_from_type?
|
83
|
+
outcome = Namespace.use from_type.created_in_namespace do
|
84
|
+
from_type.process_value(value)
|
85
|
+
end
|
86
|
+
|
87
|
+
return outcome unless outcome.success?
|
88
|
+
|
89
|
+
value = outcome.result
|
90
|
+
end
|
91
|
+
|
85
92
|
output = transform(value)
|
86
|
-
|
93
|
+
|
94
|
+
if has_to_type?
|
95
|
+
Namespace.use to_type.created_in_namespace do
|
96
|
+
to_type.process_value(output)
|
97
|
+
end
|
98
|
+
else
|
99
|
+
Outcome.success(output)
|
100
|
+
end
|
87
101
|
end
|
88
102
|
end
|
89
103
|
end
|
@@ -12,10 +12,6 @@ module Foobara
|
|
12
12
|
Domain.current.foobara_type_builder.type_declaration_handler_for(...)
|
13
13
|
end
|
14
14
|
|
15
|
-
def lookup_absolute_type!(*, **opts, &)
|
16
|
-
Foobara::Namespace.global.foobara_lookup_type!(*, **opts.merge(mode: Namespace::LookupMode::ABSOLUTE), &)
|
17
|
-
end
|
18
|
-
|
19
15
|
def lookup_type!(...)
|
20
16
|
Foobara::Namespace.current.foobara_lookup_type!(...)
|
21
17
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foobara
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.87
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miles Georgi
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-03-
|
10
|
+
date: 2025-03-26 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: bigdecimal
|
@@ -359,6 +359,7 @@ files:
|
|
359
359
|
- projects/thread_parent/src/thread_parent.rb
|
360
360
|
- projects/type_declarations/lib/foobara/type_declarations.rb
|
361
361
|
- projects/type_declarations/src/attributes.rb
|
362
|
+
- projects/type_declarations/src/attributes_transformer.rb
|
362
363
|
- projects/type_declarations/src/caster.rb
|
363
364
|
- projects/type_declarations/src/desugarizer.rb
|
364
365
|
- projects/type_declarations/src/dsl/attributes.rb
|