foobara 0.0.115 → 0.0.117

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -0
  3. data/projects/builtin_types/src/date/casters/hash.rb +1 -1
  4. data/projects/callback/src/block.rb +1 -1
  5. data/projects/command/src/command_pattern_implementation/concerns/callbacks.rb +2 -2
  6. data/projects/command/src/command_pattern_implementation/concerns/runtime.rb +7 -7
  7. data/projects/command/src/command_pattern_implementation/concerns/transactions.rb +10 -69
  8. data/projects/command/src/state_machine.rb +22 -22
  9. data/projects/command_connectors/src/authenticator.rb +7 -1
  10. data/projects/command_connectors/src/authenticator_selector.rb +8 -0
  11. data/projects/command_connectors/src/command_connector/command_connector_error.rb +1 -1
  12. data/projects/command_connectors/src/command_connector/request.rb +56 -11
  13. data/projects/command_connectors/src/command_connector/response.rb +4 -0
  14. data/projects/command_connectors/src/command_connector.rb +92 -97
  15. data/projects/command_connectors/src/command_registry.rb +1 -1
  16. data/projects/command_connectors/src/serializers/entities_to_primary_keys_serializer.rb +8 -1
  17. data/projects/{command → command_connectors}/src/transformed_command.rb +16 -7
  18. data/projects/detached_entity/src/concerns/attributes.rb +28 -0
  19. data/projects/detached_entity/src/concerns/initialization.rb +57 -0
  20. data/projects/detached_entity/src/concerns/persistence.rb +14 -0
  21. data/projects/detached_entity/src/detached_entity.rb +3 -0
  22. data/projects/detached_entity/src/extensions/builtin_types/detached_entity/casters/primary_key.rb +43 -0
  23. data/projects/entity/src/concerns/attributes.rb +4 -0
  24. data/projects/entity/src/concerns/callbacks.rb +16 -16
  25. data/projects/entity/src/concerns/initialization.rb +3 -0
  26. data/projects/entity/src/concerns/persistence.rb +1 -5
  27. data/projects/entity/src/extensions/builtin_types/entity/casters/primary_key.rb +3 -29
  28. data/projects/entity/src/sensitive_type_removers/entity.rb +15 -0
  29. data/projects/entity/src/sensitive_value_removers/entity.rb +14 -14
  30. data/projects/enumerated/src/values.rb +1 -1
  31. data/projects/foobara/lib/foobara/all.rb +2 -1
  32. data/projects/manifest/src/foobara/manifest/base_manifest.rb +2 -2
  33. data/projects/manifest/src/foobara/manifest/root_manifest.rb +1 -1
  34. data/projects/model/src/concerns/types.rb +3 -2
  35. data/projects/model/src/extensions/builtin_types/model/validators/model_instance_is_valid.rb +2 -2
  36. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/delegates_desugarizer.rb +2 -2
  37. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/delegates_validator.rb +1 -1
  38. data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/model_class_desugarizer.rb +3 -1
  39. data/projects/model/src/model.rb +8 -5
  40. data/projects/model_attribute_helpers/src/attribute_helper_aliases.rb +11 -11
  41. data/projects/monorepo/lib/foobara/monorepo/project.rb +4 -1
  42. data/projects/nested_transactionable/lib/foobara/nested_transactionable.rb +95 -0
  43. data/projects/persistence/src/entity_base/transaction_table/concerns/record_tracking.rb +5 -5
  44. data/projects/type_declarations/lib/foobara/type_declarations.rb +4 -4
  45. data/projects/type_declarations/src/handlers/extend_array_type_declaration/type_set_to_array_desugarizer.rb +1 -1
  46. data/projects/type_declarations/src/handlers/extend_registered_type_declaration/to_type_transformer.rb +1 -1
  47. data/projects/type_declarations/src/type_declarations.rb +2 -2
  48. data/projects/value/src/caster.rb +2 -2
  49. data/projects/value/src/processor.rb +2 -2
  50. data/projects/value/src/transformer.rb +2 -2
  51. metadata +9 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 94baacc7205e4b750c59df65dede92b2c95f15053144ba8d8324c81eb80da770
4
- data.tar.gz: 696db0d2d875c8f2c40ed9d916019518c3f2ffcc0829015a0333109c83a1e8ef
3
+ metadata.gz: 3baedff1b00683e94d063e4a3c3453e89f9d8383aac79fd63a7b80590b7ac2ab
4
+ data.tar.gz: db340140596337684becb59db82ef8c9f64970195eace6d2cb0032d6e209eb88
5
5
  SHA512:
6
- metadata.gz: 5b5cd5e50eee5c8f652d24107027eaf9115128742b57f8964010667d0e12da2a5bc1087d87870c507c9bd0cc6016eaa0248e9707d567c96c4193794863bebb6a
7
- data.tar.gz: 356150abc278d32b253ddc08ed1f4932ac4432a25f9ed4797518191b9a86fc01c06986df8e314aa5a6fc64b44441adc89946a6b6f49daac42d424a73d41e2589
6
+ metadata.gz: a9cfde792ff8303519b9b98ca46062a7e0dc4209799e00bd64bf3d5674112e685eb8cce621eb50cda6680c54f76084076007d3c18125baefe14eb052566f9038
7
+ data.tar.gz: db3398f6804081f01a44ac188a0597831db3b3ffa0dfa81ffb99de75c01685e33d21d4d91dbefae6e7d601bae29676e60c778e7be59cb3120bfde7dd7ba1b19a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,22 @@
1
+ # [0.0.117] - 2025-05-05
2
+
3
+ - Make sure we do not apply an authenticator unless it is applicable
4
+ - Move loaded/unloaded concept up into DetachedEntity from Entity
5
+ - This allows us to deal with serialization of detached entities as their primary keys
6
+ - Fix bugs preventing connecting/importing types with delegated attributes
7
+
8
+ # [0.0.116] - 2025-05-03
9
+
10
+ - Add automatic transaction support to requests, cover in/out mutators/transformers
11
+ - This makes it so that authenticators and allowed rules can more cleanly be
12
+ expressed when they have the same entity bases needed by the transformed command
13
+ - Move #authenticated_user from TransformedCommand to Request
14
+ - Add a Request#authenticated_credential
15
+ - Provide a way to skip validations for models
16
+ - A type without sensitive types derived from an entity type will now be registered as a
17
+ detached entity
18
+ - Fix model type re-registering bug
19
+
1
20
  # [0.0.115] - 2025-05-01
2
21
 
3
22
  - Make sure Authenticator#authenticate hits #applicable?
@@ -4,7 +4,7 @@ module Foobara
4
4
  module Casters
5
5
  class Hash < Value::Caster
6
6
  def applicable?(hash)
7
- hash.is_a?(::Hash) && hash.keys.size == 3 && (hash.keys.map(&:to_s).sort == %w[day month year])
7
+ hash.is_a?(::Hash) && hash.keys.size == 3 && (hash.keys.map(&:to_s).sort == ["day", "month", "year"])
8
8
  end
9
9
 
10
10
  def applies_message
@@ -56,7 +56,7 @@ module Foobara
56
56
  end
57
57
 
58
58
  def has_keyword_args?
59
- @has_keyword_args ||= param_types.any? { |type| %i[keyreq keyrest].include?(type) }
59
+ @has_keyword_args ||= param_types.any? { |type| [:keyreq, :keyrest].include?(type) }
60
60
  end
61
61
 
62
62
  def has_positional_args?
@@ -28,7 +28,7 @@ module Foobara
28
28
  self.subclass_defined_callbacks ||= Foobara::Callback::Registry::SingleAction.new
29
29
 
30
30
  [self, singleton_class].each do |target|
31
- %i[before after].each do |type|
31
+ [:before, :after].each do |type|
32
32
  target.define_method "#{type}_any_transition" do |&block|
33
33
  callback_state_machine_target.register_transition_callback(type) do |state_machine:, **args|
34
34
  block.call(command: state_machine.owner, **args)
@@ -61,7 +61,7 @@ module Foobara
61
61
 
62
62
  Foobara::Command::StateMachine.transitions.each do |transition|
63
63
  [self, singleton_class].each do |target|
64
- %i[before after].each do |type|
64
+ [:before, :after].each do |type|
65
65
  target.define_method "#{type}_#{transition}" do |&block|
66
66
  callback_state_machine_target.register_transition_callback(
67
67
  type, transition:
@@ -27,13 +27,13 @@ module Foobara
27
27
  Foobara::Namespace.use self.class do
28
28
  invoke_with_callbacks_and_transition(:open_transaction)
29
29
 
30
- invoke_with_callbacks_and_transition_in_transaction(%i[
31
- cast_and_validate_inputs
32
- load_records
33
- validate_records
34
- validate
35
- run_execute
36
- commit_transaction
30
+ invoke_with_callbacks_and_transition_in_transaction([
31
+ :cast_and_validate_inputs,
32
+ :load_records,
33
+ :validate_records,
34
+ :validate,
35
+ :run_execute,
36
+ :commit_transaction
37
37
  ])
38
38
 
39
39
  invoke_with_callbacks_and_transition(:succeed)
@@ -3,81 +3,22 @@ module Foobara
3
3
  module Concerns
4
4
  module Transactions
5
5
  include Concern
6
-
7
- def transactions
8
- @transactions ||= []
9
- end
10
-
11
- def opened_transactions
12
- @opened_transactions ||= []
13
- end
14
-
15
- def auto_detect_current_transactions
16
- bases = relevant_entity_classes.map(&:entity_base).uniq
17
-
18
- bases.each do |base|
19
- tx = base.current_transaction
20
- transactions << tx if tx
21
- end
22
- end
6
+ include NestedTransactionable
23
7
 
24
8
  def relevant_entity_classes
25
- @relevant_entity_classes ||= begin
26
- entity_classes = if inputs_type
27
- Entity.construct_associations(
28
- inputs_type
29
- ).values.uniq.map(&:target_class)
30
- else
31
- []
32
- end
33
-
34
- if result_type
35
- entity_classes += Entity.construct_associations(
36
- result_type
37
- ).values.uniq.map(&:target_class)
38
-
39
- if result_type.extends?(BuiltinTypes[:entity])
40
- entity_classes << result_type.target_class
41
- end
42
- end
9
+ return @relevant_entity_classes if defined?(@relevant_entity_classes)
43
10
 
44
- entity_classes += entity_classes.uniq.map do |entity_class|
45
- entity_class.deep_associations.values
46
- end.flatten.uniq.map(&:target_class)
11
+ entity_classes = if inputs_type
12
+ relevant_entity_classes_for_type(inputs_type)
13
+ else
14
+ []
15
+ end
47
16
 
48
- [*entity_classes, *self.class.depends_on_entities].uniq
17
+ if result_type
18
+ entity_classes += relevant_entity_classes_for_type(result_type)
49
19
  end
50
- end
51
-
52
- def open_transaction
53
- auto_detect_current_transactions
54
-
55
- bases_not_needing_transaction = transactions.map(&:entity_base)
56
-
57
- bases_needing_transaction = relevant_entity_classes.map(&:entity_base).uniq - bases_not_needing_transaction
58
-
59
- bases_needing_transaction.each do |entity_base|
60
- transaction = entity_base.transaction
61
- transaction.open!
62
- opened_transactions << transaction
63
- transactions << transaction
64
- end
65
- end
66
-
67
- def rollback_transaction
68
- opened_transactions.reverse.each do |transaction|
69
- if transaction.currently_open?
70
- # Hard to test this because halting and other exceptions rollback the transactions via
71
- # block form but to be safe keeping this
72
- # :nocov:
73
- transaction.rollback!
74
- # :nocov:
75
- end
76
- end
77
- end
78
20
 
79
- def commit_transaction
80
- opened_transactions.reverse.each(&:commit!)
21
+ @relevant_entity_classes = [*entity_classes, *self.class.depends_on_entities].uniq
81
22
  end
82
23
  end
83
24
  end
@@ -1,31 +1,31 @@
1
1
  module Foobara
2
2
  class Command
3
3
  class StateMachine < Foobara::StateMachine
4
- transitions = %i[
5
- open_transaction
6
- cast_and_validate_inputs
7
- load_records
8
- validate_records
9
- validate
10
- run_execute
11
- commit_transaction
12
- succeed
13
- error
14
- fail
15
- reset
4
+ transitions = [
5
+ :open_transaction,
6
+ :cast_and_validate_inputs,
7
+ :load_records,
8
+ :validate_records,
9
+ :validate,
10
+ :run_execute,
11
+ :commit_transaction,
12
+ :succeed,
13
+ :error,
14
+ :fail,
15
+ :reset
16
16
  ]
17
17
 
18
- terminal_states = %i[succeeded errored failed]
18
+ terminal_states = [:succeeded, :errored, :failed]
19
19
 
20
- states = %i[
21
- initialized
22
- transaction_opened
23
- inputs_casted_and_validated
24
- loaded_records
25
- validated_records
26
- validated_execution
27
- executing
28
- transaction_committed
20
+ states = [
21
+ :initialized,
22
+ :transaction_opened,
23
+ :inputs_casted_and_validated,
24
+ :loaded_records,
25
+ :validated_records,
26
+ :validated_execution,
27
+ :executing,
28
+ :transaction_committed
29
29
  ] + terminal_states
30
30
 
31
31
  can_fail_states = states - terminal_states
@@ -13,6 +13,10 @@ module Foobara
13
13
  @block = block
14
14
  end
15
15
 
16
+ def relevant_entity_classes(_request)
17
+ nil
18
+ end
19
+
16
20
  def symbol
17
21
  declaration_data[:symbol]
18
22
  end
@@ -26,7 +30,9 @@ module Foobara
26
30
  end
27
31
 
28
32
  def authenticate(request)
29
- process_value!(request)
33
+ if applicable?(request)
34
+ process_value!(request)
35
+ end
30
36
  end
31
37
 
32
38
  def to_proc
@@ -24,6 +24,14 @@ module Foobara
24
24
  def authenticate(request)
25
25
  selector.process_value!(request)
26
26
  end
27
+
28
+ def relevant_entity_classes(request)
29
+ outcome = selector.processor_for(request)
30
+
31
+ if outcome.success?
32
+ outcome.result&.relevant_entity_classes(request)
33
+ end
34
+ end
27
35
  end
28
36
  end
29
37
  end
@@ -3,7 +3,7 @@ module Foobara
3
3
  class CommandConnectorError < Foobara::RuntimeError
4
4
  context({})
5
5
 
6
- def initialize(message:, context: {})
6
+ def initialize(message:, symbol: nil, context: {})
7
7
  super
8
8
  end
9
9
  end
@@ -2,9 +2,11 @@ module Foobara
2
2
  class CommandConnector
3
3
  class Request
4
4
  include TruncatedInspect
5
+ include NestedTransactionable
5
6
 
6
7
  # TODO: this feels like a smell of some sort...
7
8
  attr_accessor :command,
9
+ :command_class,
8
10
  :error,
9
11
  :command_connector,
10
12
  # Why aren't there serializers on the response?
@@ -12,12 +14,12 @@ module Foobara
12
14
  :inputs,
13
15
  :full_command_name,
14
16
  :action,
15
- :response
16
-
17
- attr_reader :command_class
17
+ :response,
18
+ :authenticated_user,
19
+ :authenticated_credential
18
20
 
19
21
  def initialize(**opts)
20
- valid_keys = %i[inputs full_command_name action serializers]
22
+ valid_keys = [:inputs, :full_command_name, :action, :serializers]
21
23
 
22
24
  invalid_keys = opts.keys - valid_keys
23
25
 
@@ -33,8 +35,8 @@ module Foobara
33
35
  self.serializers = Util.array(opts[:serializers]) if opts.key?(:serializers)
34
36
  end
35
37
 
36
- def command_class=(klass)
37
- @command_class = klass
38
+ def mutate_request
39
+ return if error
38
40
 
39
41
  # TODO: we really need to revisit these interfaces. Something is wrong.
40
42
  if command_class.respond_to?(:mutate_request)
@@ -42,6 +44,25 @@ module Foobara
42
44
  end
43
45
  end
44
46
 
47
+ def authenticate
48
+ return if error
49
+ return unless command_class.respond_to?(:requires_authentication) && command_class.requires_authentication
50
+
51
+ authenticated_user, authenticated_credential = authenticator.authenticate(self)
52
+
53
+ # TODO: why are these on the command instead of the request??
54
+ self.authenticated_user = authenticated_user
55
+ self.authenticated_credential = authenticated_credential
56
+
57
+ unless authenticated_user
58
+ self.error = CommandConnector::UnauthenticatedError.new
59
+ end
60
+ end
61
+
62
+ def authenticator
63
+ command_class.authenticator
64
+ end
65
+
45
66
  def serializer
46
67
  return @serializer if defined?(@serializer)
47
68
 
@@ -77,12 +98,10 @@ module Foobara
77
98
  end
78
99
 
79
100
  def outcome
80
- outcome = command&.outcome
81
-
82
- if outcome
83
- outcome
84
- elsif error
101
+ if error
85
102
  Outcome.error(error)
103
+ else
104
+ command&.outcome
86
105
  end
87
106
  end
88
107
 
@@ -94,8 +113,34 @@ module Foobara
94
113
  outcome.error_collection
95
114
  end
96
115
 
116
+ def relevant_entity_classes
117
+ if command_class.is_a?(::Class) && command_class < TransformedCommand
118
+ entity_classes = authenticator&.relevant_entity_classes(self)
119
+ [*entity_classes, *relevant_entity_classes_from_inputs_transformer]
120
+ end || []
121
+ end
122
+
97
123
  private
98
124
 
125
+ def relevant_entity_classes_from_inputs_transformer(
126
+ object = [*command_class.inputs_transformer, *command_class.result_transformer]
127
+ )
128
+ case object
129
+ when TypeDeclarations::TypedTransformer
130
+ relevant_entity_classes_from_inputs_transformer([*object.from_type, *object.to_type])
131
+ when Types::Type
132
+ relevant_entity_classes_for_type(object)
133
+ when ::Array
134
+ object.map do |o|
135
+ relevant_entity_classes_from_inputs_transformer(o)
136
+ end.flatten
137
+ when Value::Processor::Pipeline
138
+ relevant_entity_classes_from_inputs_transformer(object.processors)
139
+ else
140
+ []
141
+ end
142
+ end
143
+
99
144
  def objects_to_serializers(objects)
100
145
  objects.map do |object|
101
146
  case object
@@ -22,6 +22,10 @@ module Foobara
22
22
  def success?
23
23
  request.success?
24
24
  end
25
+
26
+ def outcome
27
+ request.outcome
28
+ end
25
29
  end
26
30
  end
27
31
  end