foobara 0.0.13 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0fe6b2415dddaf6742ae9bd3809f807148d61a8595eff27c7053b7bdf2120b0
4
- data.tar.gz: a0b48950e37a936d2b4aae09ab9fe5bceaed5ae46da724a7f0d64bfe4177e549
3
+ metadata.gz: cec596f3e023a3bb6381c2f4406f6419d15cdeae3b9b1c7140a74ea8d999b4e4
4
+ data.tar.gz: 7d493bb518a6892cbc483bbdedaa0301e2986a8c90d03249dd9abf2210b52032
5
5
  SHA512:
6
- metadata.gz: 67a4249c5ca81daad7c7476eac81dafdea51224135e3e224ca31a4def8a0dc9906a79f4f4500f95a75446073ceccbab6d4ada74fca656bec305aebe7b2b546f7
7
- data.tar.gz: da74f67ea8f39814874c2393c45ff514fd669dbd9865acbf7da4414e2ed702d9a9522d4381343f2201d6804f1b3d31565fa48926e5cf751f3376e8d7bd7069d4
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
@@ -71,6 +71,9 @@ module Foobara
71
71
  @outcome = Outcome.success(result)
72
72
  end
73
73
 
74
+ def execute
75
+ end
76
+
74
77
  def succeed
75
78
  # noop but for now helpful for carrying out state transition
76
79
  end
@@ -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
@@ -12,6 +12,7 @@ module Foobara
12
12
  include Concerns::Persistence
13
13
  include Concerns::Initialization
14
14
  include Concerns::Reflection
15
+ include Concerns::AttributeHelpers
15
16
 
16
17
  class << self
17
18
  prepend NewPrepend
@@ -0,0 +1,4 @@
1
+ require "foobara/all"
2
+
3
+ module Foobara
4
+ 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.13
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-14 00:00:00.000000000 Z
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