foobara 0.0.13 → 0.0.15
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 +9 -0
- data/projects/command/src/concerns/runtime.rb +3 -0
- data/projects/entity/src/concerns/attribute_helpers.rb +190 -0
- data/projects/entity/src/entity.rb +1 -0
- data/projects/foobara/lib/foobara.rb +4 -0
- metadata +4 -3
- data/projects/command/src/command/entity_helpers.rb +0 -184
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cec596f3e023a3bb6381c2f4406f6419d15cdeae3b9b1c7140a74ea8d999b4e4
|
4
|
+
data.tar.gz: 7d493bb518a6892cbc483bbdedaa0301e2986a8c90d03249dd9abf2210b52032
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f869b1e7749e1388c86de79964d0031eb0bddb00eea9c477bc8336aa41d2941571dceaa506a16fbd9f8dee479e2cf6e708542fb938bae3cc295d8dddc4909a29
|
7
|
+
data.tar.gz: 7755a9dfe9587cbcf7726ba1d25397012e31a6123efa97c8141b63d703c42af56df007d4fd22e604da0b1f05d4f2d84e3484f718c00d917863803921d47aecd7
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## [0.0.15] - 2024-11-20
|
2
|
+
|
3
|
+
- Move entity attributes type declaration helpers from Command::EntityHelpers to Entity for convenience.
|
4
|
+
|
5
|
+
## [0.0.14] - 2024-11-15
|
6
|
+
|
7
|
+
- Provide a default execute because why not...
|
8
|
+
- Allow require "foobara" instead of require "foobara/all"
|
9
|
+
|
1
10
|
## [0.0.13] - 2024-11-13
|
2
11
|
|
3
12
|
- Do not fail :one_of if it is nil and :allows_nil
|
@@ -0,0 +1,190 @@
|
|
1
|
+
module Foobara
|
2
|
+
class Entity < Model
|
3
|
+
module Concerns
|
4
|
+
module AttributeHelpers
|
5
|
+
include Foobara::Concern
|
6
|
+
|
7
|
+
def update_aggregate(value, type = self.class.model_type)
|
8
|
+
# is this a smell?
|
9
|
+
self.class.update_aggregate(self, value, type)
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def attributes_for_update
|
14
|
+
attributes_for_aggregate_update
|
15
|
+
end
|
16
|
+
|
17
|
+
# TODO: we should have metadata on the entity about whether it required a primary key
|
18
|
+
# upon creation or not instead of an option here.
|
19
|
+
def attributes_for_create(includes_primary_key: false)
|
20
|
+
return attributes_type if includes_primary_key
|
21
|
+
|
22
|
+
declaration = attributes_type.declaration_data
|
23
|
+
# TODO: just slice out the element type declarations
|
24
|
+
declaration = Util.deep_dup(declaration)
|
25
|
+
|
26
|
+
if declaration.key?(:required) && declaration[:required].include?(primary_key_attribute)
|
27
|
+
declaration[:required].delete(primary_key_attribute)
|
28
|
+
end
|
29
|
+
|
30
|
+
if declaration.key?(:defaults) && declaration[:defaults].include?(primary_key_attribute)
|
31
|
+
declaration[:defaults].delete(primary_key_attribute)
|
32
|
+
end
|
33
|
+
|
34
|
+
if declaration.key?(:element_type_declarations)
|
35
|
+
if declaration[:element_type_declarations].key?(primary_key_attribute)
|
36
|
+
declaration[:element_type_declarations].delete(primary_key_attribute)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
handler = Domain.global.foobara_type_builder.handler_for_class(
|
41
|
+
TypeDeclarations::Handlers::ExtendAttributesTypeDeclaration
|
42
|
+
)
|
43
|
+
|
44
|
+
handler.desugarize(declaration)
|
45
|
+
end
|
46
|
+
|
47
|
+
def attributes_for_aggregate_update(initial = true)
|
48
|
+
declaration = attributes_type.declaration_data
|
49
|
+
# TODO: just slice out the element type declarations
|
50
|
+
declaration = Util.deep_dup(declaration)
|
51
|
+
|
52
|
+
declaration.delete(:defaults)
|
53
|
+
declaration.delete(:required)
|
54
|
+
|
55
|
+
if initial
|
56
|
+
declaration[:required] = [primary_key_attribute]
|
57
|
+
end
|
58
|
+
|
59
|
+
associations.each_pair do |data_path, type|
|
60
|
+
if type.extends?(BuiltinTypes[:entity])
|
61
|
+
target_class = type.target_class
|
62
|
+
|
63
|
+
entry = type_declaration_value_at(declaration, DataPath.new(data_path).path)
|
64
|
+
entry.clear
|
65
|
+
entry.merge!(target_class.attributes_for_aggregate_update(false))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
declaration
|
70
|
+
end
|
71
|
+
|
72
|
+
def attributes_for_atom_update
|
73
|
+
declaration = attributes_type.declaration_data
|
74
|
+
# TODO: just slice out the element type declarations
|
75
|
+
declaration = Util.deep_dup(declaration)
|
76
|
+
|
77
|
+
declaration.delete(:defaults)
|
78
|
+
declaration[:required] = [primary_key_attribute]
|
79
|
+
|
80
|
+
# expect all associations to be expressed as primary key values
|
81
|
+
# TODO: should we have a special type for encapsulating primary keys types??
|
82
|
+
associations.each_pair do |data_path, type|
|
83
|
+
if type.extends?(BuiltinTypes[:entity])
|
84
|
+
target_class = type.target_class
|
85
|
+
# TODO: do we really need declaration_data? Why cant we use the type directly?
|
86
|
+
# TODO: make this work with the type directly for performance reasons.
|
87
|
+
primary_key_type_declaration = target_class.primary_key_type.declaration_data
|
88
|
+
entry = type_declaration_value_at(declaration, DataPath.new(data_path).path)
|
89
|
+
entry.clear
|
90
|
+
entry.merge!(primary_key_type_declaration)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
declaration
|
95
|
+
end
|
96
|
+
|
97
|
+
def attributes_for_find_by
|
98
|
+
element_type_declarations = {}
|
99
|
+
|
100
|
+
attributes_type.element_types.each_pair do |attribute_name, attribute_type|
|
101
|
+
element_type_declarations[attribute_name] = attribute_type.reference_or_declaration_data
|
102
|
+
end
|
103
|
+
|
104
|
+
handler = Domain.global.foobara_type_builder.handler_for_class(
|
105
|
+
TypeDeclarations::Handlers::ExtendAttributesTypeDeclaration
|
106
|
+
)
|
107
|
+
|
108
|
+
handler.desugarize(
|
109
|
+
type: "::attributes",
|
110
|
+
element_type_declarations:
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
def update_aggregate(object, value, type = object.class.model_type)
|
115
|
+
return value if object.nil?
|
116
|
+
|
117
|
+
if type.extends?(BuiltinTypes[:model])
|
118
|
+
element_types = type.element_types.element_types
|
119
|
+
|
120
|
+
value.each_pair do |attribute_name, new_value|
|
121
|
+
current_value = object.read_attribute(attribute_name)
|
122
|
+
|
123
|
+
attribute_type = element_types[attribute_name]
|
124
|
+
|
125
|
+
updated_value = update_aggregate(current_value, new_value, attribute_type)
|
126
|
+
|
127
|
+
object.write_attribute(attribute_name, updated_value)
|
128
|
+
end
|
129
|
+
|
130
|
+
object
|
131
|
+
elsif type.extends?(BuiltinTypes[:attributes])
|
132
|
+
element_types = type.element_types
|
133
|
+
|
134
|
+
object = object.dup
|
135
|
+
object ||= {}
|
136
|
+
|
137
|
+
value.each_pair do |attribute_name, new_value|
|
138
|
+
current_value = object[attribute_name]
|
139
|
+
attribute_type = element_types[attribute_name]
|
140
|
+
|
141
|
+
updated_value = update_aggregate(current_value, new_value, attribute_type)
|
142
|
+
|
143
|
+
object[attribute_name] = updated_value
|
144
|
+
end
|
145
|
+
|
146
|
+
object
|
147
|
+
elsif type.extends?(BuiltinTypes[:tuple])
|
148
|
+
# :nocov:
|
149
|
+
raise "Tuple not yet supported"
|
150
|
+
# :nocov:
|
151
|
+
elsif type.extends?(BuiltinTypes[:associative_array])
|
152
|
+
# :nocov:
|
153
|
+
raise "Associated array not yet supported"
|
154
|
+
# :nocov:
|
155
|
+
elsif type.extends?(BuiltinTypes[:array])
|
156
|
+
element_type = type.element_type
|
157
|
+
|
158
|
+
value.map.with_index do |element, index|
|
159
|
+
update_aggregate(object[index], element, element_type)
|
160
|
+
end
|
161
|
+
else
|
162
|
+
value
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def type_declaration_value_at(declaration, path_parts)
|
169
|
+
return declaration if path_parts.empty?
|
170
|
+
|
171
|
+
path_part, *path_parts = path_parts
|
172
|
+
|
173
|
+
declaration = case path_part
|
174
|
+
when :"#"
|
175
|
+
declaration[:element_type_declaration]
|
176
|
+
when Symbol, Integer
|
177
|
+
declaration[:element_type_declarations][path_part]
|
178
|
+
else
|
179
|
+
# :nocov:
|
180
|
+
raise "Bad path part #{path_part}"
|
181
|
+
# :nocov:
|
182
|
+
end
|
183
|
+
|
184
|
+
type_declaration_value_at(declaration, path_parts)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miles Georgi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-11-
|
11
|
+
date: 2024-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: foobara-util
|
@@ -116,7 +116,6 @@ files:
|
|
116
116
|
- projects/callback/src/set.rb
|
117
117
|
- projects/command/lib/foobara/command.rb
|
118
118
|
- projects/command/src/command.rb
|
119
|
-
- projects/command/src/command/entity_helpers.rb
|
120
119
|
- projects/command/src/concerns/callbacks.rb
|
121
120
|
- projects/command/src/concerns/description.rb
|
122
121
|
- projects/command/src/concerns/domain_mappers.rb
|
@@ -187,6 +186,7 @@ files:
|
|
187
186
|
- projects/domain/src/organization_module_extension.rb
|
188
187
|
- projects/entity/lib/foobara/entity.rb
|
189
188
|
- projects/entity/src/concerns/associations.rb
|
189
|
+
- projects/entity/src/concerns/attribute_helpers.rb
|
190
190
|
- projects/entity/src/concerns/attributes.rb
|
191
191
|
- projects/entity/src/concerns/callbacks.rb
|
192
192
|
- projects/entity/src/concerns/initialization.rb
|
@@ -214,6 +214,7 @@ files:
|
|
214
214
|
- projects/enumerated/lib/foobara/enumerated.rb
|
215
215
|
- projects/enumerated/src/accessors.rb
|
216
216
|
- projects/enumerated/src/values.rb
|
217
|
+
- projects/foobara/lib/foobara.rb
|
217
218
|
- projects/foobara/lib/foobara/all.rb
|
218
219
|
- projects/in_memory_crud_driver/lib/foobara/in_memory_crud_driver.rb
|
219
220
|
- projects/in_memory_crud_driver/src/in_memory.rb
|
@@ -1,184 +0,0 @@
|
|
1
|
-
module Foobara
|
2
|
-
class Command
|
3
|
-
module EntityHelpers
|
4
|
-
module_function
|
5
|
-
|
6
|
-
# Just for convenience
|
7
|
-
def attributes_for_update(entity_class)
|
8
|
-
type_declaration_for_record_aggregate_update(entity_class)
|
9
|
-
end
|
10
|
-
|
11
|
-
# TODO: we should have metadata on the entity about whether it required a primary key
|
12
|
-
# upon creation or not instead of an option here.
|
13
|
-
def attributes_for_create(entity_class, includes_primary_key: false)
|
14
|
-
attributes_type = entity_class.attributes_type
|
15
|
-
|
16
|
-
return attributes_type if includes_primary_key
|
17
|
-
|
18
|
-
declaration = attributes_type.declaration_data
|
19
|
-
# TODO: just slice out the element type declarations
|
20
|
-
declaration = Util.deep_dup(declaration)
|
21
|
-
|
22
|
-
primary_key_attribute = entity_class.primary_key_attribute
|
23
|
-
|
24
|
-
if declaration.key?(:required) && declaration[:required].include?(primary_key_attribute)
|
25
|
-
declaration[:required].delete(primary_key_attribute)
|
26
|
-
end
|
27
|
-
|
28
|
-
if declaration.key?(:defaults) && declaration[:defaults].include?(primary_key_attribute)
|
29
|
-
declaration[:defaults].delete(primary_key_attribute)
|
30
|
-
end
|
31
|
-
|
32
|
-
if declaration.key?(:element_type_declarations)
|
33
|
-
if declaration[:element_type_declarations].key?(primary_key_attribute)
|
34
|
-
declaration[:element_type_declarations].delete(primary_key_attribute)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
handler = Domain.global.foobara_type_builder.handler_for_class(
|
39
|
-
TypeDeclarations::Handlers::ExtendAttributesTypeDeclaration
|
40
|
-
)
|
41
|
-
|
42
|
-
handler.desugarize(declaration)
|
43
|
-
end
|
44
|
-
|
45
|
-
def type_declaration_for_record_aggregate_update(entity_class, initial = true)
|
46
|
-
declaration = entity_class.attributes_type.declaration_data
|
47
|
-
# TODO: just slice out the element type declarations
|
48
|
-
declaration = Util.deep_dup(declaration)
|
49
|
-
|
50
|
-
declaration.delete(:defaults)
|
51
|
-
declaration.delete(:required)
|
52
|
-
|
53
|
-
if initial
|
54
|
-
declaration[:required] = [entity_class.primary_key_attribute]
|
55
|
-
end
|
56
|
-
|
57
|
-
entity_class.associations.each_pair do |data_path, type|
|
58
|
-
if type.extends?(BuiltinTypes[:entity])
|
59
|
-
target_class = type.target_class
|
60
|
-
|
61
|
-
entry = type_declaration_value_at(declaration, DataPath.new(data_path).path)
|
62
|
-
entry.clear
|
63
|
-
entry.merge!(type_declaration_for_record_aggregate_update(target_class, false))
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
declaration
|
68
|
-
end
|
69
|
-
|
70
|
-
def type_declaration_for_record_atom_update(entity_class)
|
71
|
-
declaration = entity_class.attributes_type.declaration_data
|
72
|
-
# TODO: just slice out the element type declarations
|
73
|
-
declaration = Util.deep_dup(declaration)
|
74
|
-
|
75
|
-
declaration.delete(:defaults)
|
76
|
-
declaration[:required] = [entity_class.primary_key_attribute]
|
77
|
-
|
78
|
-
# expect all associations to be expressed as primary key values
|
79
|
-
# TODO: should we have a special type for encapsulating primary keys types??
|
80
|
-
entity_class.associations.each_pair do |data_path, type|
|
81
|
-
if type.extends?(BuiltinTypes[:entity])
|
82
|
-
target_class = type.target_class
|
83
|
-
# TODO: do we really need declaration_data? Why cant we use the type directly?
|
84
|
-
# TODO: make this work with the type directly for performance reasons.
|
85
|
-
primary_key_type_declaration = target_class.primary_key_type.declaration_data
|
86
|
-
entry = type_declaration_value_at(declaration, DataPath.new(data_path).path)
|
87
|
-
entry.clear
|
88
|
-
entry.merge!(primary_key_type_declaration)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
declaration
|
93
|
-
end
|
94
|
-
|
95
|
-
def type_declaration_for_find_by(entity_class)
|
96
|
-
element_type_declarations = {}
|
97
|
-
|
98
|
-
entity_class.attributes_type.element_types.each_pair do |attribute_name, attribute_type|
|
99
|
-
element_type_declarations[attribute_name] = attribute_type.reference_or_declaration_data
|
100
|
-
end
|
101
|
-
|
102
|
-
handler = Domain.global.foobara_type_builder.handler_for_class(
|
103
|
-
TypeDeclarations::Handlers::ExtendAttributesTypeDeclaration
|
104
|
-
)
|
105
|
-
|
106
|
-
handler.desugarize(
|
107
|
-
type: "::attributes",
|
108
|
-
element_type_declarations:
|
109
|
-
)
|
110
|
-
end
|
111
|
-
|
112
|
-
def update_aggregate(object, value, type = object.class.model_type)
|
113
|
-
return value if object.nil?
|
114
|
-
|
115
|
-
if type.extends?(BuiltinTypes[:model])
|
116
|
-
element_types = type.element_types.element_types
|
117
|
-
|
118
|
-
value.each_pair do |attribute_name, new_value|
|
119
|
-
current_value = object.read_attribute(attribute_name)
|
120
|
-
|
121
|
-
attribute_type = element_types[attribute_name]
|
122
|
-
|
123
|
-
updated_value = update_aggregate(current_value, new_value, attribute_type)
|
124
|
-
|
125
|
-
object.write_attribute(attribute_name, updated_value)
|
126
|
-
end
|
127
|
-
|
128
|
-
object
|
129
|
-
elsif type.extends?(BuiltinTypes[:attributes])
|
130
|
-
element_types = type.element_types
|
131
|
-
|
132
|
-
object = object.dup
|
133
|
-
object ||= {}
|
134
|
-
|
135
|
-
value.each_pair do |attribute_name, new_value|
|
136
|
-
current_value = object[attribute_name]
|
137
|
-
attribute_type = element_types[attribute_name]
|
138
|
-
|
139
|
-
updated_value = update_aggregate(current_value, new_value, attribute_type)
|
140
|
-
|
141
|
-
object[attribute_name] = updated_value
|
142
|
-
end
|
143
|
-
|
144
|
-
object
|
145
|
-
elsif type.extends?(BuiltinTypes[:tuple])
|
146
|
-
# :nocov:
|
147
|
-
raise "Tuple not yet supported"
|
148
|
-
# :nocov:
|
149
|
-
elsif type.extends?(BuiltinTypes[:associative_array])
|
150
|
-
# :nocov:
|
151
|
-
raise "Associated array not yet supported"
|
152
|
-
# :nocov:
|
153
|
-
elsif type.extends?(BuiltinTypes[:array])
|
154
|
-
element_type = type.element_type
|
155
|
-
|
156
|
-
value.map.with_index do |element, index|
|
157
|
-
update_aggregate(object[index], element, element_type)
|
158
|
-
end
|
159
|
-
else
|
160
|
-
value
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
def type_declaration_value_at(declaration, path_parts)
|
165
|
-
return declaration if path_parts.empty?
|
166
|
-
|
167
|
-
path_part, *path_parts = path_parts
|
168
|
-
|
169
|
-
declaration = case path_part
|
170
|
-
when :"#"
|
171
|
-
declaration[:element_type_declaration]
|
172
|
-
when Symbol, Integer
|
173
|
-
declaration[:element_type_declarations][path_part]
|
174
|
-
else
|
175
|
-
# :nocov:
|
176
|
-
raise "Bad path part #{path_part}"
|
177
|
-
# :nocov:
|
178
|
-
end
|
179
|
-
|
180
|
-
type_declaration_value_at(declaration, path_parts)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|