foobara 0.1.9 → 0.1.11
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 +13 -0
- data/projects/command/src/command_pattern_implementation/concerns/errors.rb +9 -3
- data/projects/command/src/command_pattern_implementation/concerns/errors_type.rb +22 -3
- data/projects/command/src/command_pattern_implementation/concerns/inputs.rb +20 -0
- data/projects/command/src/command_pattern_implementation/concerns/inputs_type.rb +4 -0
- data/projects/command/src/command_pattern_implementation/concerns/runtime.rb +42 -1
- data/projects/common/src/error.rb +5 -0
- data/projects/domain/src/domain_module_extension.rb +0 -2
- data/projects/model/src/extensions/type_declarations/handlers/extend_model_type_declaration/to_type_transformer.rb +1 -1
- data/projects/model/src/extensions/type_declarations/lazy_element_types/model.rb +6 -4
- data/projects/namespace/src/is_namespace.rb +5 -3
- data/projects/namespace/src/namespace/lookup_mode.rb +1 -0
- data/projects/type_declarations/src/handlers/extend_array_type_declaration/to_type_transformer.rb +1 -1
- data/projects/type_declarations/src/handlers/extend_associative_array_type_declaration/to_type_transformer.rb +1 -1
- data/projects/type_declarations/src/handlers/extend_attributes_type_declaration/to_type_transformer.rb +1 -1
- data/projects/type_declarations/src/handlers/extend_tuple_type_declaration/to_type_transformer.rb +1 -1
- data/projects/type_declarations/src/lazy_element_types/array.rb +7 -5
- data/projects/type_declarations/src/lazy_element_types/attributes.rb +12 -10
- data/projects/type_declarations/src/lazy_element_types/hash.rb +18 -16
- data/projects/type_declarations/src/lazy_element_types/tuple.rb +9 -7
- data/projects/type_declarations/src/type_builder.rb +2 -8
- data/projects/types/src/type.rb +15 -18
- data/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e3d84d4d11b964a30291cd92382117fa45a7736e0ee0b6a247224427a33e6598
|
4
|
+
data.tar.gz: d1a2b86a1983b354412c1e83e2dbfc2ad259feddba8d09a01d3ef39038a27163
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c0c8ed8a92fbc3c1e37172881f855aa0072ffb50cd5f3c652677ddaee2af021aa937a60c2aa35d5c61f110c5b2968474b3cfaf72c593d3f9c5a405f1a3ace968
|
7
|
+
data.tar.gz: e772dc00b34a3293111f49f958c7615507c206c47f10932c461852d0b4a1ada737a9c0c5f198da11bded280aa69d1f0f383e408b241977ec3521fa5e98e76796
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
# [0.1.11] - 2025-09-24
|
2
|
+
|
3
|
+
- Make sure type builder caches are cleared when namespace caches are cleared
|
4
|
+
- Make sure element type resolution is performed in the right namespace
|
5
|
+
- Do not dual-purpose memoized @element_type(s) var, and memoize in IsNamespace.lru_cache instead
|
6
|
+
|
7
|
+
# [0.1.10] - 2025-09-11
|
8
|
+
|
9
|
+
- Add NotFoundError when an entity input doesn't exist
|
10
|
+
- Make #add_input_error more flexible
|
11
|
+
- Fix an error path array bug
|
12
|
+
- Fix a bug that might prevent inherited possible errors
|
13
|
+
|
1
14
|
# [0.1.9] - 2025-09-08
|
2
15
|
|
3
16
|
- Support passing load_paths: to Entity.load to pre-load certain associations
|
@@ -78,7 +78,7 @@ module Foobara
|
|
78
78
|
elsif args.empty? || (args.size == 1 && args.first.is_a?(Hash))
|
79
79
|
error_args = opts.merge(args.first || {})
|
80
80
|
symbol = error_args[:symbol]
|
81
|
-
path =
|
81
|
+
path = error_args[:input] || error_args[:path]
|
82
82
|
|
83
83
|
error_args = error_args.except(:input)
|
84
84
|
|
@@ -100,8 +100,14 @@ module Foobara
|
|
100
100
|
input, symbol, message = args
|
101
101
|
context = opts
|
102
102
|
|
103
|
-
|
104
|
-
|
103
|
+
if symbol.is_a?(::Class) && symbol < Foobara::Error
|
104
|
+
error_class = symbol
|
105
|
+
symbol = error_class.symbol
|
106
|
+
else
|
107
|
+
error_class = self.class.lookup_input_error_class(symbol, input)
|
108
|
+
end
|
109
|
+
|
110
|
+
error_class.new(path: input, symbol:, context:, message:)
|
105
111
|
else
|
106
112
|
# :nocov:
|
107
113
|
raise ArgumentError,
|
@@ -81,6 +81,11 @@ module Foobara
|
|
81
81
|
symbol = error_class.symbol
|
82
82
|
|
83
83
|
possible_error = PossibleError.new(error_class, symbol:, data:)
|
84
|
+
|
85
|
+
if path.is_a?(::String) || path.is_a?(::Symbol)
|
86
|
+
path = path.to_s.split(".")
|
87
|
+
end
|
88
|
+
|
84
89
|
possible_error.prepend_path!(path)
|
85
90
|
|
86
91
|
possible_error.manually_added = true
|
@@ -93,10 +98,24 @@ module Foobara
|
|
93
98
|
|
94
99
|
# TODO: kill this method in favor of possible_errors
|
95
100
|
def error_context_type_map
|
101
|
+
return @error_context_type_map if defined?(@error_context_type_map)
|
102
|
+
|
96
103
|
process_error_constants
|
97
|
-
|
98
|
-
|
99
|
-
|
104
|
+
map = if superclass < Foobara::Command
|
105
|
+
superclass.error_context_type_map.dup
|
106
|
+
end || {}
|
107
|
+
|
108
|
+
@error_context_type_map = if @error_context_type_map
|
109
|
+
map.merge(@error_context_type_map)
|
110
|
+
else
|
111
|
+
map
|
112
|
+
end
|
113
|
+
|
114
|
+
inputs_association_paths&.each do |data_path|
|
115
|
+
possible_input_error(data_path.to_sym, CommandPatternImplementation::NotFoundError)
|
116
|
+
end
|
117
|
+
|
118
|
+
@error_context_type_map
|
100
119
|
end
|
101
120
|
|
102
121
|
def register_possible_error_class(possible_error)
|
@@ -6,6 +6,26 @@ module Foobara
|
|
6
6
|
|
7
7
|
include Concern
|
8
8
|
|
9
|
+
module ClassMethods
|
10
|
+
def inputs_association_paths
|
11
|
+
return @inputs_association_paths if defined?(@inputs_association_paths)
|
12
|
+
|
13
|
+
@inputs_association_paths = if inputs_type.nil?
|
14
|
+
nil
|
15
|
+
else
|
16
|
+
keys = Entity.construct_associations(inputs_type).keys
|
17
|
+
|
18
|
+
if keys.empty?
|
19
|
+
nil
|
20
|
+
else
|
21
|
+
keys.map do |key|
|
22
|
+
DataPath.new(key)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
9
29
|
attr_reader :inputs, :raw_inputs
|
10
30
|
|
11
31
|
def initialize(inputs = {})
|
@@ -12,6 +12,10 @@ module Foobara
|
|
12
12
|
unregister_possible_error_if_registered(possible_error)
|
13
13
|
end
|
14
14
|
|
15
|
+
if defined?(@inputs_association_paths)
|
16
|
+
remove_instance_variable(:@inputs_association_paths)
|
17
|
+
end
|
18
|
+
|
15
19
|
type = type_for_declaration(...)
|
16
20
|
|
17
21
|
if type.extends?(BuiltinTypes[:model]) && !type.extends?(BuiltinTypes[:entity])
|
@@ -7,6 +7,13 @@ module Foobara
|
|
7
7
|
class CannotHaltWithoutAddingErrors < StandardError; end
|
8
8
|
class Halt < StandardError; end
|
9
9
|
|
10
|
+
class NotFoundError < Foobara::DataError
|
11
|
+
context do
|
12
|
+
entity_class :string, :required
|
13
|
+
criteria :duck
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
10
17
|
module ClassMethods
|
11
18
|
def run(...)
|
12
19
|
new(...).run
|
@@ -81,7 +88,41 @@ module Foobara
|
|
81
88
|
end
|
82
89
|
|
83
90
|
def validate_records
|
84
|
-
|
91
|
+
self.class.inputs_association_paths&.each do |data_path|
|
92
|
+
if data_path.last == :"#"
|
93
|
+
records = data_path.values_at(@inputs)
|
94
|
+
|
95
|
+
records.each.with_index do |record, index|
|
96
|
+
if record&.persisted? && !record.loaded?
|
97
|
+
begin
|
98
|
+
record.class.load(record)
|
99
|
+
rescue Foobara::Entity::NotFoundError => e
|
100
|
+
add_input_error(
|
101
|
+
[*data_path.path[..-2], index],
|
102
|
+
CommandPatternImplementation::NotFoundError,
|
103
|
+
criteria: e.criteria,
|
104
|
+
entity_class: record.class.model_type.scoped_full_name
|
105
|
+
)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
else
|
110
|
+
record = data_path.value_at(@inputs)
|
111
|
+
|
112
|
+
if record&.persisted? && !record.loaded?
|
113
|
+
begin
|
114
|
+
record.class.load(record)
|
115
|
+
rescue Foobara::Entity::NotFoundError => e
|
116
|
+
add_input_error(
|
117
|
+
data_path.to_s,
|
118
|
+
CommandPatternImplementation::NotFoundError,
|
119
|
+
criteria: e.criteria,
|
120
|
+
entity_class: record.class.model_type.scoped_full_name
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
85
126
|
end
|
86
127
|
|
87
128
|
def validate
|
@@ -215,6 +215,11 @@ module Foobara
|
|
215
215
|
self.message = message
|
216
216
|
self.context = context
|
217
217
|
self.category = category
|
218
|
+
|
219
|
+
if path.is_a?(::String) || path.is_a?(::Symbol)
|
220
|
+
path = path.to_s.split(".").map(&:to_sym)
|
221
|
+
end
|
222
|
+
|
218
223
|
self.path = path
|
219
224
|
self.runtime_path = runtime_path
|
220
225
|
self.is_fatal = is_fatal
|
@@ -5,11 +5,13 @@ module Foobara
|
|
5
5
|
module_function
|
6
6
|
|
7
7
|
def resolve(type)
|
8
|
-
|
8
|
+
Namespace.use type.created_in_namespace do
|
9
|
+
attributes_type_declaration = type.declaration_data[:attributes_declaration]
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
type.element_types = TypeDeclarations.strict do
|
12
|
+
handler = Domain.current.foobara_type_builder.handler_for_class(Handlers::ExtendAttributesTypeDeclaration)
|
13
|
+
handler.process_value!(TypeDeclaration.new(attributes_type_declaration))
|
14
|
+
end
|
13
15
|
end
|
14
16
|
end
|
15
17
|
end
|
@@ -5,11 +5,13 @@ module Foobara
|
|
5
5
|
module IsNamespace
|
6
6
|
class << self
|
7
7
|
def lru_cache
|
8
|
-
@lru_cache ||= Foobara::LruCache.new(
|
8
|
+
@lru_cache ||= Foobara::LruCache.new(200)
|
9
9
|
end
|
10
10
|
|
11
11
|
def clear_lru_cache!
|
12
|
-
@lru_cache
|
12
|
+
if @lru_cache
|
13
|
+
lru_cache.reset!
|
14
|
+
end
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -141,7 +143,7 @@ module Foobara
|
|
141
143
|
LookupMode.validate!(mode)
|
142
144
|
path = Namespace.to_registry_path(path)
|
143
145
|
|
144
|
-
lru_cache.cached([path, mode,
|
146
|
+
lru_cache.cached([self, path, mode, *filter]) do
|
145
147
|
visited = Set.new
|
146
148
|
foobara_lookup_without_cache(path, filter:, mode:, visited:)
|
147
149
|
end
|
@@ -27,6 +27,7 @@ module Foobara
|
|
27
27
|
# parent: n
|
28
28
|
# dependent: n
|
29
29
|
# TODO: don't we have an enumerated class/project for this?
|
30
|
+
# Maybe use bitmasks for the above 3 places to look instead of a list of 7 lookup types? (There should be 8...)
|
30
31
|
module LookupMode
|
31
32
|
GENERAL = :general
|
32
33
|
RELAXED = :relaxed
|
@@ -8,7 +8,7 @@ module Foobara
|
|
8
8
|
class ToTypeTransformer < ExtendAssociativeArrayTypeDeclaration::ToTypeTransformer
|
9
9
|
def transform(strict_type_declaration)
|
10
10
|
type = super
|
11
|
-
type.
|
11
|
+
type.element_types_loader = LazyElementTypes::Attributes
|
12
12
|
type
|
13
13
|
end
|
14
14
|
end
|
data/projects/type_declarations/src/handlers/extend_tuple_type_declaration/to_type_transformer.rb
CHANGED
@@ -8,7 +8,7 @@ module Foobara
|
|
8
8
|
class ToTypeTransformer < ExtendAssociativeArrayTypeDeclaration::ToTypeTransformer
|
9
9
|
def transform(strict_type_declaration)
|
10
10
|
type = super
|
11
|
-
type.
|
11
|
+
type.element_types_loader = LazyElementTypes::Tuple
|
12
12
|
type
|
13
13
|
end
|
14
14
|
end
|
@@ -5,13 +5,15 @@ module Foobara
|
|
5
5
|
module_function
|
6
6
|
|
7
7
|
def resolve(type)
|
8
|
-
|
8
|
+
Namespace.use type.created_in_namespace do
|
9
|
+
element_type_declaration = type.declaration_data[:element_type_declaration]
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
type.element_type = if element_type_declaration
|
12
|
+
TypeDeclarations.strict do
|
13
|
+
Domain.current.foobara_type_from_declaration(element_type_declaration)
|
14
|
+
end
|
13
15
|
end
|
14
|
-
|
16
|
+
end
|
15
17
|
end
|
16
18
|
end
|
17
19
|
end
|
@@ -5,21 +5,23 @@ module Foobara
|
|
5
5
|
module_function
|
6
6
|
|
7
7
|
def resolve(type)
|
8
|
-
|
8
|
+
Namespace.use type.created_in_namespace do
|
9
|
+
type_declarations = type.declaration_data[:element_type_declarations]
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
type.element_types = if type_declarations
|
12
|
+
if type_declarations.empty?
|
13
|
+
{}
|
14
|
+
else
|
15
|
+
TypeDeclarations.strict do
|
16
|
+
domain = Domain.current
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
type_declarations.transform_values do |attribute_declaration|
|
19
|
+
domain.foobara_type_from_declaration(attribute_declaration)
|
20
|
+
end
|
19
21
|
end
|
20
22
|
end
|
21
23
|
end
|
22
|
-
|
24
|
+
end
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
@@ -7,30 +7,32 @@ module Foobara
|
|
7
7
|
module_function
|
8
8
|
|
9
9
|
def resolve(type)
|
10
|
-
|
10
|
+
Namespace.use type.created_in_namespace do
|
11
|
+
declaration_data = type.declaration_data
|
11
12
|
|
12
|
-
|
13
|
-
|
13
|
+
key_type_declaration = declaration_data[:key_type_declaration]
|
14
|
+
value_type_declaration = declaration_data[:value_type_declaration]
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
type.element_types = if key_type_declaration || value_type_declaration
|
17
|
+
TypeDeclarations.strict do
|
18
|
+
domain = Domain.current
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
else
|
22
|
-
BuiltinTypes[:duck]
|
23
|
-
end
|
24
|
-
|
25
|
-
value_declaration = if value_type_declaration
|
26
|
-
domain.foobara_type_from_declaration(value_type_declaration)
|
20
|
+
key_declaration = if key_type_declaration
|
21
|
+
domain.foobara_type_from_declaration(key_type_declaration)
|
27
22
|
else
|
28
23
|
BuiltinTypes[:duck]
|
29
24
|
end
|
30
25
|
|
31
|
-
|
26
|
+
value_declaration = if value_type_declaration
|
27
|
+
domain.foobara_type_from_declaration(value_type_declaration)
|
28
|
+
else
|
29
|
+
BuiltinTypes[:duck]
|
30
|
+
end
|
31
|
+
|
32
|
+
[key_declaration, value_declaration]
|
33
|
+
end
|
32
34
|
end
|
33
|
-
|
35
|
+
end
|
34
36
|
end
|
35
37
|
end
|
36
38
|
end
|
@@ -5,17 +5,19 @@ module Foobara
|
|
5
5
|
module_function
|
6
6
|
|
7
7
|
def resolve(type)
|
8
|
-
|
8
|
+
Namespace.use type.created_in_namespace do
|
9
|
+
element_type_declarations = type.declaration_data[:element_type_declarations]
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
type.element_types = if element_type_declarations
|
12
|
+
TypeDeclarations.strict do
|
13
|
+
domain = Domain.current
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
element_type_declarations.map do |element_type_declaration|
|
16
|
+
domain.foobara_type_from_declaration(element_type_declaration)
|
17
|
+
end
|
16
18
|
end
|
17
19
|
end
|
18
|
-
|
20
|
+
end
|
19
21
|
end
|
20
22
|
end
|
21
23
|
end
|
@@ -129,7 +129,7 @@ module Foobara
|
|
129
129
|
end
|
130
130
|
|
131
131
|
def type_for_declaration(*type_declaration_bits, &block)
|
132
|
-
lru_cache.cached([
|
132
|
+
lru_cache.cached([self, *block&.object_id, *type_declaration_bits]) do
|
133
133
|
type_for_declaration_without_cache(*type_declaration_bits, &block)
|
134
134
|
end
|
135
135
|
rescue NoTypeDeclarationHandlerFoundError
|
@@ -152,16 +152,10 @@ module Foobara
|
|
152
152
|
handler.process_value!(type_declaration)
|
153
153
|
end
|
154
154
|
|
155
|
-
def clear_cache
|
156
|
-
if @lru_cache
|
157
|
-
lru_cache.reset!
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
155
|
private
|
162
156
|
|
163
157
|
def lru_cache
|
164
|
-
|
158
|
+
Namespace::IsNamespace.lru_cache
|
165
159
|
end
|
166
160
|
end
|
167
161
|
end
|
data/projects/types/src/type.rb
CHANGED
@@ -20,7 +20,9 @@ module Foobara
|
|
20
20
|
:name,
|
21
21
|
:description,
|
22
22
|
:sensitive,
|
23
|
-
:sensitive_exposed
|
23
|
+
:sensitive_exposed,
|
24
|
+
:element_type_loader,
|
25
|
+
:element_types_loader
|
24
26
|
|
25
27
|
attr_reader :type_symbol,
|
26
28
|
:casters,
|
@@ -44,8 +46,6 @@ module Foobara
|
|
44
46
|
transformers: [],
|
45
47
|
validators: [],
|
46
48
|
element_processors: nil,
|
47
|
-
element_type: nil,
|
48
|
-
element_types: nil,
|
49
49
|
structure_count: nil,
|
50
50
|
processor_classes_requiring_type: nil,
|
51
51
|
sensitive: nil,
|
@@ -64,9 +64,6 @@ module Foobara
|
|
64
64
|
self.element_processors = [*element_processors, *base_type&.element_processors]
|
65
65
|
|
66
66
|
self.structure_count = structure_count
|
67
|
-
# TODO: combine these maybe with the term "children_types"?
|
68
|
-
self.element_types = element_types
|
69
|
-
self.element_type = element_type
|
70
67
|
self.target_classes = Util.array(target_classes)
|
71
68
|
self.processor_classes_requiring_type = processor_classes_requiring_type
|
72
69
|
|
@@ -95,23 +92,23 @@ module Foobara
|
|
95
92
|
end
|
96
93
|
|
97
94
|
def element_type
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
95
|
+
lru_cache.cached([self, :element_type]) do
|
96
|
+
if element_type_loader
|
97
|
+
element_type_loader.resolve(self)
|
98
|
+
else
|
99
|
+
base_type&.element_type
|
100
|
+
end
|
102
101
|
end
|
103
|
-
|
104
|
-
type
|
105
102
|
end
|
106
103
|
|
107
104
|
def element_types
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
105
|
+
lru_cache.cached([self, :element_types]) do
|
106
|
+
if element_types_loader
|
107
|
+
element_types_loader.resolve(self)
|
108
|
+
else
|
109
|
+
base_type&.element_types
|
110
|
+
end
|
112
111
|
end
|
113
|
-
|
114
|
-
types
|
115
112
|
end
|
116
113
|
|
117
114
|
def has_sensitive_types?
|
data/version.rb
CHANGED