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
@@ -4,22 +4,15 @@ module Foobara
4
4
  class Entity < DetachedEntity::SensitiveValueRemovers::DetachedEntity
5
5
  def transform(record)
6
6
  if record.loaded? || record.created?
7
- sanitized_record = super
8
-
9
- sanitized_record.is_loaded = record.loaded?
10
- sanitized_record.is_persisted = record.persisted?
11
-
12
- sanitized_record
7
+ super
13
8
  elsif record.persisted?
14
9
  # We will assume that we do not need to clean up the primary key itself as
15
10
  # 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
11
+ # We use .new because the target_class should be a detached entity
12
+ to_type.target_class.new(
13
+ { record.class.primary_key_attribute => record.primary_key },
14
+ { mutable: false, skip_validations: true }
15
+ )
23
16
  else
24
17
  # :nocov:
25
18
  raise "Not sure what to do with a record that isn't loaded, created, or persisted"
@@ -28,7 +21,14 @@ module Foobara
28
21
  end
29
22
 
30
23
  def build_method
31
- :build
24
+ if to_type.extends?(:entity)
25
+ # TODO: test this code path
26
+ # :nocov:
27
+ :build
28
+ # :nocov:
29
+ else
30
+ :new
31
+ end
32
32
  end
33
33
  end
34
34
  end
@@ -125,7 +125,7 @@ module Foobara
125
125
  mod = Module.new
126
126
  enumerated = self
127
127
 
128
- %i[all all_names all_values value?].each do |method_name|
128
+ [:all, :all_names, :all_values, :value?].each do |method_name|
129
129
  mod.singleton_class.define_method method_name do |*args, **opts, &block|
130
130
  enumerated.send(method_name, *args, **opts, &block)
131
131
  end
@@ -30,9 +30,10 @@ module Foobara
30
30
  "detached_entity",
31
31
  "entity",
32
32
  "model_attribute_helpers",
33
+ "nested_transactionable",
33
34
  "command",
34
35
  "domain_mapper",
35
- "persistence",
36
+ "persistence", # Feels like this would be loaded before command?
36
37
  "in_memory_crud_driver_minimal",
37
38
  "in_memory_crud_driver",
38
39
  "manifest"
@@ -103,11 +103,11 @@ module Foobara
103
103
  end
104
104
 
105
105
  def global_domain
106
- Domain.new(root_manifest, %i[domain global_organization::global_domain])
106
+ Domain.new(root_manifest, [:domain, :"global_organization::global_domain"])
107
107
  end
108
108
 
109
109
  def global_organization
110
- Organization.new(root_manifest, %i[organization global_organization])
110
+ Organization.new(root_manifest, [:organization, :global_organization])
111
111
  end
112
112
 
113
113
  def method_missing(method_name, *, &)
@@ -102,7 +102,7 @@ module Foobara
102
102
  end
103
103
 
104
104
  def lookup(reference)
105
- prioritized_categories = %i[command type error domain organization processor processor_class]
105
+ prioritized_categories = [:command, :type, :error, :domain, :organization, :processor, :processor_class]
106
106
 
107
107
  prioritized_categories.each do |category|
108
108
  path = [category, reference]
@@ -64,8 +64,9 @@ module Foobara
64
64
 
65
65
  if model_type
66
66
  unless Foobara::TypeDeclarations.declarations_equal?(declaration, model_type.declaration_data)
67
+ type_domain = domain
67
68
  self.model_type = nil
68
- domain.foobara_type_from_declaration(declaration)
69
+ type_domain.foobara_type_from_declaration(declaration)
69
70
  end
70
71
  else
71
72
  domain.foobara_type_from_declaration(declaration)
@@ -198,7 +199,7 @@ module Foobara
198
199
  delegates[attribute_name] = delegate_manifest
199
200
 
200
201
  delegated_type_declaration = model_type.type_at_path(data_path).reference_or_declaration_data
201
- attributes attribute_name => delegated_type_declaration
202
+ attributes(type: :attributes, element_type_declarations: { attribute_name => delegated_type_declaration })
202
203
 
203
204
  define_method attribute_name do
204
205
  data_path.value_at(self)
@@ -13,8 +13,8 @@ module Foobara
13
13
  end
14
14
  end
15
15
 
16
- def always_applicable?
17
- true
16
+ def applicable?(model_instance)
17
+ !model_instance.skip_validations
18
18
  end
19
19
 
20
20
  def process_value(model_instance)
@@ -8,8 +8,8 @@ module Foobara
8
8
  end
9
9
 
10
10
  def desugarize(sugary_type_declaration)
11
- desugarized = Util.deep_dup(sugary_type_declaration)
12
- delegates = desugarized[:delegates]
11
+ desugarized = sugary_type_declaration.dup
12
+ delegates = Util.deep_symbolize_keys(desugarized[:delegates])
13
13
 
14
14
  if delegates.empty?
15
15
  desugarized.delete(:delegates)
@@ -21,7 +21,7 @@ module Foobara
21
21
  )
22
22
  end
23
23
 
24
- allowed_keys = %i[data_path writer]
24
+ allowed_keys = [:data_path, :writer]
25
25
 
26
26
  delegates.each_pair do |attribute_name, delegate_hash|
27
27
  invalid_keys = delegate_hash.keys - allowed_keys
@@ -17,6 +17,8 @@ module Foobara
17
17
 
18
18
  # TODO: consider splitting this up into multiple desugarizers
19
19
  def desugarize(strictish_type_declaration)
20
+ strictish_type_declaration = strictish_type_declaration.dup
21
+
20
22
  if strictish_type_declaration.key?(:model_module)
21
23
  model_module = strictish_type_declaration[:model_module]
22
24
 
@@ -47,7 +49,7 @@ module Foobara
47
49
  end
48
50
  end
49
51
 
50
- strictish_type_declaration[:model_base_class] = model_class.superclass.name
52
+ strictish_type_declaration[:model_base_class] ||= model_class.superclass.name
51
53
 
52
54
  model_class.name
53
55
  elsif klass.is_a?(::String)
@@ -169,18 +169,21 @@ module Foobara
169
169
 
170
170
  abstract
171
171
 
172
- attr_accessor :mutable
172
+ attr_accessor :mutable, :skip_validations
173
+
174
+ ALLOWED_OPTIONS = [:validate, :mutable, :ignore_unexpected_attributes, :skip_validations].freeze
173
175
 
174
176
  def initialize(attributes = nil, options = {})
175
- allowed_options = %i[validate mutable ignore_unexpected_attributes]
176
- invalid_options = options.keys - allowed_options
177
+ invalid_options = options.keys - ALLOWED_OPTIONS
177
178
 
178
179
  unless invalid_options.empty?
179
180
  # :nocov:
180
- raise ArgumentError, "Invalid options #{invalid_options} expected only #{allowed_options}"
181
+ raise ArgumentError, "Invalid options #{invalid_options} expected only #{ALLOWED_OPTIONS}"
181
182
  # :nocov:
182
183
  end
183
184
 
185
+ self.skip_validations = options[:skip_validations]
186
+
184
187
  if options[:ignore_unexpected_attributes]
185
188
  Thread.with_inheritable_thread_local_var(:foobara_ignore_unexpected_attributes, true) do
186
189
  initialize(attributes, options.except(:ignore_unexpected_attributes))
@@ -226,7 +229,7 @@ module Foobara
226
229
  mutable
227
230
  end
228
231
 
229
- validate! if validate
232
+ validate! if validate # TODO: test this code path
230
233
  end
231
234
 
232
235
  foobara_delegate :model_name, :valid_attribute_name?, :validate_attribute_name!, to: :class
@@ -7,17 +7,17 @@ module Foobara
7
7
  include Foobara::Concern
8
8
 
9
9
  module ClassMethods
10
- %i[
11
- attributes_for_update
12
- type_from_foobara_model_class
13
- attributes_type_from_foobara_model_class
14
- primary_key_attribute_from_foobara_model_class
15
- foobara_model_class_has_primary_key
16
- attributes_for_create
17
- attributes_for_aggregate_update
18
- attributes_for_atom_update
19
- attributes_for_find_by
20
- type_declaration_value_at
10
+ [
11
+ :attributes_for_update,
12
+ :type_from_foobara_model_class,
13
+ :attributes_type_from_foobara_model_class,
14
+ :primary_key_attribute_from_foobara_model_class,
15
+ :foobara_model_class_has_primary_key,
16
+ :attributes_for_create,
17
+ :attributes_for_aggregate_update,
18
+ :attributes_for_atom_update,
19
+ :attributes_for_find_by,
20
+ :type_declaration_value_at
21
21
  ].each do |method_name|
22
22
  define_method method_name do |*args, **opts, &block|
23
23
  send("foobara_#{method_name}", *args, **opts, &block)
@@ -26,7 +26,10 @@ module Foobara
26
26
 
27
27
  def load
28
28
  require require_path
29
- Util.require_directory("#{project_path}/src")
29
+ src_dir = "#{project_path}/src"
30
+ if Dir.exist?(src_dir)
31
+ Util.require_directory(src_dir)
32
+ end
30
33
  end
31
34
 
32
35
  def install!
@@ -0,0 +1,95 @@
1
+ module Foobara
2
+ module NestedTransactionable
3
+ include Concern
4
+
5
+ class << self
6
+ def relevant_entity_classes_for_type(type)
7
+ entity_classes = []
8
+ entity_classes += Entity.construct_associations(type).values.map(&:target_class)
9
+
10
+ if type.extends?(BuiltinTypes[:entity])
11
+ entity_classes << type.target_class
12
+ end
13
+
14
+ entity_classes.uniq.each do |entity_class|
15
+ entity_classes += entity_class.deep_associations.values.map(&:target_class)
16
+ end
17
+
18
+ entity_classes.uniq
19
+ end
20
+ end
21
+
22
+ def relevant_entity_classes_for_type(type)
23
+ NestedTransactionable.relevant_entity_classes_for_type(type)
24
+ end
25
+
26
+ def relevant_entity_classes
27
+ # :nocov:
28
+ raise "subclass responsibility"
29
+ # :nocov:
30
+ end
31
+
32
+ def transactions
33
+ @transactions ||= []
34
+ end
35
+
36
+ def opened_transactions
37
+ @opened_transactions ||= []
38
+ end
39
+
40
+ def auto_detect_current_transactions
41
+ classes = relevant_entity_classes
42
+ return if classes.nil? || classes.empty?
43
+
44
+ bases = classes.map(&:entity_base).uniq
45
+
46
+ bases.each do |base|
47
+ tx = base.current_transaction
48
+ transactions << tx if tx
49
+ 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
+
79
+ def commit_transaction
80
+ opened_transactions.reverse.each(&:commit!)
81
+ end
82
+
83
+ def commit_transaction_if_open
84
+ opened_transactions.reverse.each do |tx|
85
+ if tx.currently_open?
86
+ tx.commit!
87
+ end
88
+ end
89
+ end
90
+
91
+ def use_transaction(&)
92
+ Persistence::EntityBase.using_transactions(transactions, &)
93
+ end
94
+ end
95
+ end
@@ -95,11 +95,11 @@ module Foobara
95
95
  marked_created.clear
96
96
  end
97
97
 
98
- interesting_record_states = %i[
99
- updated
100
- hard_deleted
101
- created
102
- loading
98
+ interesting_record_states = [
99
+ :updated,
100
+ :hard_deleted,
101
+ :created,
102
+ :loading
103
103
  ]
104
104
 
105
105
  interesting_record_states.each do |state|
@@ -17,10 +17,10 @@ module Foobara
17
17
  end
18
18
  end
19
19
 
20
- %w[
21
- foobara_children
22
- foobara_registry
23
- foobara_type_builder
20
+ [
21
+ "foobara_children",
22
+ "foobara_registry",
23
+ "foobara_type_builder"
24
24
  ].each do |var_name|
25
25
  var_name = "@#{var_name}"
26
26
 
@@ -8,7 +8,7 @@ module Foobara
8
8
  class TypeSetToArrayDesugarizer < ArrayDesugarizer
9
9
  def applicable?(sugary_type_declaration)
10
10
  if sugary_type_declaration.is_a?(::Hash) && sugary_type_declaration.key?(:type)
11
- extra_keys = sugary_type_declaration.keys - %i[type description sensitive sensitive_exposed]
11
+ extra_keys = sugary_type_declaration.keys - [:type, :description, :sensitive, :sensitive_exposed]
12
12
 
13
13
  return false if extra_keys.any?
14
14
 
@@ -74,7 +74,7 @@ module Foobara
74
74
  end
75
75
 
76
76
  def non_processor_keys
77
- %i[type _desugarized description sensitive sensitive_exposed]
77
+ [:type, :_desugarized, :description, :sensitive, :sensitive_exposed]
78
78
  end
79
79
  end
80
80
  end
@@ -96,8 +96,8 @@ module Foobara
96
96
  Thread.inheritable_thread_local_var_get("foobara_manifest_context")
97
97
  end
98
98
 
99
- allowed_context_keys = %i[detached to_include mode remove_sensitive]
100
- booleans = %i[detached remove_sensitive]
99
+ allowed_context_keys = [:detached, :to_include, :mode, :remove_sensitive]
100
+ booleans = [:detached, :remove_sensitive]
101
101
 
102
102
  booleans.each do |context_item|
103
103
  define_method "foobara_manifest_context_#{context_item}?" do
@@ -16,8 +16,8 @@ module Foobara
16
16
  end
17
17
 
18
18
  def subclass(name: nil, **options)
19
- arity_zero = %i[name applies_message]
20
- arity_one = %i[applicable? cast]
19
+ arity_zero = [:name, :applies_message]
20
+ arity_one = [:applicable?, :cast]
21
21
  allowed = arity_zero + arity_one
22
22
 
23
23
  invalid_options = options.keys - allowed
@@ -48,7 +48,7 @@ module Foobara
48
48
  end
49
49
 
50
50
  def new_with_agnostic_args(**rest)
51
- allowed_keys = %i[declaration_data parent_declaration_data]
51
+ allowed_keys = [:declaration_data, :parent_declaration_data]
52
52
 
53
53
  invalid_keys = rest.keys - allowed_keys
54
54
 
@@ -283,7 +283,7 @@ module Foobara
283
283
  end
284
284
 
285
285
  def dup_processor(**opts)
286
- valid_opts = %i[declaration_data parent_declaration_data]
286
+ valid_opts = [:declaration_data, :parent_declaration_data]
287
287
 
288
288
  invalid_opts = opts.keys - valid_opts
289
289
 
@@ -24,8 +24,8 @@ module Foobara
24
24
 
25
25
  # TODO: make transform the first argument for convenience
26
26
  def subclass(name: nil, **options)
27
- arity_zero = %i[always_applicable? priority]
28
- arity_one = %i[applicable? transform]
27
+ arity_zero = [:always_applicable?, :priority]
28
+ arity_one = [:applicable?, :transform]
29
29
  allowed = arity_zero + arity_one
30
30
 
31
31
  invalid_options = options.keys - allowed
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.115
4
+ version: 0.0.117
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Georgi
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-05-01 00:00:00.000000000 Z
10
+ date: 2025-05-05 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bigdecimal
@@ -179,7 +179,6 @@ files:
179
179
  - projects/command/src/command_pattern_implementation/concerns/subcommands.rb
180
180
  - projects/command/src/command_pattern_implementation/concerns/transactions.rb
181
181
  - projects/command/src/state_machine.rb
182
- - projects/command/src/transformed_command.rb
183
182
  - projects/command_connectors/lib/foobara/command_connectors.rb
184
183
  - projects/command_connectors/src/authenticator.rb
185
184
  - projects/command_connectors/src/authenticator_selector.rb
@@ -216,6 +215,7 @@ files:
216
215
  - projects/command_connectors/src/serializers/record_store_serializer.rb
217
216
  - projects/command_connectors/src/serializers/success_serializer.rb
218
217
  - projects/command_connectors/src/serializers/yaml_serializer.rb
218
+ - projects/command_connectors/src/transformed_command.rb
219
219
  - projects/command_connectors/src/transformers/auth_errors_transformer.rb
220
220
  - projects/command_connectors/src/transformers/load_aggregates_pre_commit_transformer.rb
221
221
  - projects/command_connectors/src/transformers/load_delegated_attributes_entities_pre_commit_transformer.rb
@@ -234,7 +234,10 @@ files:
234
234
  - projects/detached_entity/lib/foobara/detached_entity.rb
235
235
  - projects/detached_entity/src/concerns/aliases.rb
236
236
  - projects/detached_entity/src/concerns/associations.rb
237
+ - projects/detached_entity/src/concerns/attributes.rb
237
238
  - projects/detached_entity/src/concerns/equality.rb
239
+ - projects/detached_entity/src/concerns/initialization.rb
240
+ - projects/detached_entity/src/concerns/persistence.rb
238
241
  - projects/detached_entity/src/concerns/primary_key.rb
239
242
  - projects/detached_entity/src/concerns/reflection.rb
240
243
  - projects/detached_entity/src/concerns/serialize.rb
@@ -243,6 +246,7 @@ files:
243
246
  - projects/detached_entity/src/detached_entity_type.rb
244
247
  - projects/detached_entity/src/extensions/builtin_types/detached_entity.rb
245
248
  - projects/detached_entity/src/extensions/builtin_types/detached_entity/casters/hash.rb
249
+ - projects/detached_entity/src/extensions/builtin_types/detached_entity/casters/primary_key.rb
246
250
  - projects/detached_entity/src/extensions/builtin_types/detached_entity/validators/model_instance_is_valid.rb
247
251
  - projects/detached_entity/src/extensions/type_declarations/handlers/extend_detached_entity_type_declaration.rb
248
252
  - projects/detached_entity/src/extensions/type_declarations/handlers/extend_detached_entity_type_declaration/attributes_handler_desugarizer.rb
@@ -369,6 +373,7 @@ files:
369
373
  - projects/namespace/src/prefixless_registry.rb
370
374
  - projects/namespace/src/scoped.rb
371
375
  - projects/namespace/src/unambiguous_registry.rb
376
+ - projects/nested_transactionable/lib/foobara/nested_transactionable.rb
372
377
  - projects/persistence/lib/foobara/persistence.rb
373
378
  - projects/persistence/src/entity_attributes_crud_driver.rb
374
379
  - projects/persistence/src/entity_base.rb
@@ -492,6 +497,7 @@ require_paths:
492
497
  - "./projects/model_attribute_helpers/lib"
493
498
  - "./projects/monorepo/lib"
494
499
  - "./projects/namespace/lib"
500
+ - "./projects/nested_transactionable/lib"
495
501
  - "./projects/persistence/lib"
496
502
  - "./projects/state_machine/lib"
497
503
  - "./projects/type_declarations/lib"