foobara 0.0.102 → 0.0.103

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c472d0a6d4c5d306bf6510632edc586079912f8d389eee47ce7857889cab92e4
4
- data.tar.gz: b4b42fe4f0952cf5322350de3677e7012856bd1ced93c8f72765519c1aab2c14
3
+ metadata.gz: 506c445dbdf8c1bd6d1a2db990e317e3a8893754aea2f1d607aa03dccc516749
4
+ data.tar.gz: e7170ed694b6bc096391a98e724080bfeab36b3b2528bd49ad105a1e1f3453fe
5
5
  SHA512:
6
- metadata.gz: 310bdd43d7858b4f548d62bce8acc58d66f139a2e48b315781ef29623118ddd647258e81e75170a673af050652959b310a87d98c49a3433f76841372453ba564
7
- data.tar.gz: e722a9828ea78374fb63107d44a1bb79b5ff2e0c06699671eb033a1492f5b5279ce047543a256ca953f6560734a4936bed4af5aeab59fa9b02c514b16676f893
6
+ metadata.gz: 5f5350c1728e42deb835e3d4d32b9ffcc7e5ae56cb4054a0738b9932c82d87d0fb6c608954f5bc0f30b55ecb7f688e6da46af364a80f40ed07c152f0c9ae6e50
7
+ data.tar.gz: fbadbfb1a7a086101a2b0e02fefb06e15ad12954c816566fadd6b17728a0b27db140d3e737617ace5fd3e80cb56b57752e50caac8d7063ac61a22b13bc44a48c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ # [0.0.103] - 2025-04-17
2
+
3
+ - Fix bugs in complicated entity query calls involving mixtures of models/records/primary keys/attributes
4
+ - Fix bugs re: .construct_associations/_deep_associations resulting in terribad performance in some projects
5
+ - Allow lambdas to be used as allowed rules
6
+ - Improve .delegate_attribute interface
7
+
1
8
  # [0.0.102] - 2025-04-13
2
9
 
3
10
  - Extract ThreadParent to its own repository/gem
@@ -35,6 +35,10 @@ module Foobara
35
35
  entity_classes += Entity.construct_associations(
36
36
  result_type
37
37
  ).values.uniq.map(&:target_class)
38
+
39
+ if result_type.extends?(BuiltinTypes[:entity])
40
+ entity_classes << result_type.target_class
41
+ end
38
42
  end
39
43
 
40
44
  entity_classes += entity_classes.uniq.map do |entity_class|
@@ -556,9 +556,7 @@ module Foobara
556
556
 
557
557
  if rule
558
558
  command.after_load_records do |command:, **|
559
- # NOTE: apparently no way to convert a lambda to a proc but lambda's won't work here...
560
- # TODO: raise exception here if rule.lambda? is true, if this starts becoming a common error
561
- is_allowed = instance_eval(&rule)
559
+ is_allowed = instance_exec(&rule)
562
560
 
563
561
  unless is_allowed
564
562
  explanation = allowed_rule.explanation
@@ -568,7 +566,18 @@ module Foobara
568
566
  end
569
567
 
570
568
  if explanation.nil?
571
- explanation = allowed_rule.block.source || "No explanation."
569
+ source = begin
570
+ allowed_rule.block.source
571
+ rescue MethodSource::SourceNotFoundError
572
+ # This path is hit if the way the source code is extracted
573
+ # doesn't result in valid Ruby, for example, as part of a hash such as:
574
+ # allowed_rule: -> () { whatever?(something) },
575
+ # :nocov:
576
+ allowed_rule.block.source_location.join(":")
577
+ # :nocov:
578
+ end
579
+
580
+ explanation = source || "No explanation."
572
581
  end
573
582
 
574
583
  error = CommandConnector::NotAllowedError.new(rule_symbol: rule.symbol, explanation:)
@@ -374,7 +374,7 @@ module Foobara
374
374
  request_command = request.command
375
375
 
376
376
  request_command.after_load_records do |command:, **|
377
- authenticated_user = request.instance_eval(&authenticator)
377
+ authenticated_user = request.instance_exec(&authenticator)
378
378
 
379
379
  request_command.authenticated_user = authenticated_user
380
380
 
@@ -154,8 +154,13 @@ module Foobara
154
154
  def construct_associations(
155
155
  type = attributes_type,
156
156
  path = DataPath.new,
157
- result = {}
157
+ result = {},
158
+ initial: true
158
159
  )
160
+ if initial && type.extends?(BuiltinTypes[:detached_entity])
161
+ return construct_associations(type.element_types, path, result, initial: false)
162
+ end
163
+
159
164
  remove_sensitive = TypeDeclarations.foobara_manifest_context_remove_sensitive?
160
165
 
161
166
  if type.extends?(BuiltinTypes[:entity])
@@ -171,7 +176,7 @@ module Foobara
171
176
  end
172
177
 
173
178
  element_types&.each&.with_index do |element_type, index|
174
- construct_associations(element_type, path.append(index), result)
179
+ construct_associations(element_type, path.append(index), result, initial: false)
175
180
  end
176
181
  elsif type.extends?(BuiltinTypes[:array])
177
182
  # TODO: what to do about an associative array type?? Unclear how to make a key from that...
@@ -179,7 +184,7 @@ module Foobara
179
184
  element_type = type.element_type
180
185
 
181
186
  if element_type && (!remove_sensitive || !element_type.sensitive?)
182
- construct_associations(element_type, path.append(:"#"), result)
187
+ construct_associations(element_type, path.append(:"#"), result, initial: false)
183
188
  end
184
189
  elsif type.extends?(BuiltinTypes[:attributes]) # TODO: matches attributes itself instead of only subtypes
185
190
  type.element_types.each_pair do |attribute_name, element_type|
@@ -187,7 +192,7 @@ module Foobara
187
192
  next
188
193
  end
189
194
 
190
- construct_associations(element_type, path.append(attribute_name), result)
195
+ construct_associations(element_type, path.append(attribute_name), result, initial: false)
191
196
  end
192
197
  elsif type.extends?(BuiltinTypes[:model])
193
198
  target_class = type.target_class
@@ -196,7 +201,7 @@ module Foobara
196
201
  attributes_type = target_class.send(method)
197
202
 
198
203
  if !remove_sensitive || !attributes_type.sensitive?
199
- construct_associations(attributes_type, path, result)
204
+ construct_associations(attributes_type, path, result, initial: false)
200
205
  end
201
206
  elsif type.extends?(BuiltinTypes[:associative_array])
202
207
  # not going to bother testing this for now
@@ -9,7 +9,7 @@ module Foobara
9
9
 
10
10
  module Monorepo
11
11
  # could be independent projects
12
- projects "delegate",
12
+ projects "delegate", # Let's just kill delegate
13
13
  "concerns",
14
14
  "weak_object_set",
15
15
  "enumerated",
@@ -173,11 +173,16 @@ module Foobara
173
173
 
174
174
  def delegate_attributes(delegates)
175
175
  delegates.each_pair do |attribute_name, delegate_info|
176
- delegate_attribute(attribute_name, delegate_info[:data_path], writer: delegate_info[:writer])
176
+ data_path = DataPath.for(delegate_info[:data_path])
177
+ delegate_attribute(attribute_name, data_path, writer: delegate_info[:writer])
177
178
  end
178
179
  end
179
180
 
180
181
  def delegate_attribute(attribute_name, data_path, writer: false)
182
+ if data_path.is_a?(::Symbol) || data_path.is_a?(::String)
183
+ data_path = [data_path, attribute_name]
184
+ end
185
+
181
186
  data_path = DataPath.for(data_path)
182
187
 
183
188
  delegate_manifest = { data_path: data_path.to_s }
@@ -1,4 +1,5 @@
1
1
  module Foobara
2
+ # Might be best to rename this to CrudDrivers or CrudDriver instead of Persistence?
2
3
  module Persistence
3
4
  class EntityAttributesCrudDriver
4
5
  attr_accessor :raw_connection, :tables
@@ -156,29 +157,39 @@ module Foobara
156
157
 
157
158
  def matches_attributes_filter?(attributes, attributes_filter)
158
159
  attributes_filter.all? do |attribute_name_or_path, value|
159
- type = nil
160
+ value = normalize_attribute_filter_value(value)
160
161
 
161
162
  if attribute_name_or_path.is_a?(::Array)
162
163
  values = DataPath.values_at(attribute_name_or_path, attributes)
163
164
 
164
- if values.include?(value)
165
- true
166
- else
167
- type ||= entity_class.model_type.type_at_path(attribute_name_or_path)
168
- if type.extends?(:detached_entity)
169
- values.any? do |v|
170
- value.primary_key == v
171
- end
172
- end
165
+ values.any? do |attribute_value|
166
+ normalize_attribute_filter_value(attribute_value) == value
173
167
  end
174
- elsif attributes[attribute_name_or_path] == value
175
- true
176
168
  else
177
- type ||= entity_class.model_type.type_at_path(attribute_name_or_path)
178
- if type.extends?(:detached_entity)
179
- value.primary_key == attributes[attribute_name_or_path]
180
- end
169
+ attribute_value = attributes[attribute_name_or_path]
170
+ normalize_attribute_filter_value(attribute_value) == value
171
+ end
172
+ end
173
+ end
174
+
175
+ def normalize_attribute_filter_value(value)
176
+ case value
177
+ when ::Array
178
+ value.map { |v| normalize_attribute_filter_value(v) }
179
+ when ::Hash
180
+ value.to_h do |k, v|
181
+ [normalize_attribute_filter_value(k), normalize_attribute_filter_value(v)]
182
+ end
183
+ when DetachedEntity
184
+ if value.persisted?
185
+ normalize_attribute_filter_value(value.primary_key)
186
+ else
187
+ value
181
188
  end
189
+ when Model
190
+ normalize_attribute_filter_value(value.attributes)
191
+ else
192
+ value
182
193
  end
183
194
  end
184
195
 
@@ -258,8 +258,6 @@ module Foobara
258
258
  [attribute_name, element_types[attribute_name].process_value!(value)]
259
259
  end
260
260
 
261
- attributes_filter = to_persistable(attributes_filter, false)
262
-
263
261
  tracked_records.each do |record|
264
262
  next if hard_deleted?(record)
265
263
 
@@ -20,8 +20,6 @@ module Foobara
20
20
  :validators,
21
21
  :element_processors,
22
22
  :structure_count,
23
- :element_types,
24
- :element_type,
25
23
  :is_builtin,
26
24
  :raw_declaration_data,
27
25
  :name,
@@ -33,6 +31,9 @@ module Foobara
33
31
 
34
32
  attr_reader :type_symbol
35
33
 
34
+ attr_writer :element_types,
35
+ :element_type
36
+
36
37
  def initialize(
37
38
  *,
38
39
  target_classes:,
@@ -83,6 +84,14 @@ module Foobara
83
84
  sensitive_exposed
84
85
  end
85
86
 
87
+ def element_type
88
+ @element_type || base_type&.element_type
89
+ end
90
+
91
+ def element_types
92
+ @element_types || base_type&.element_types
93
+ end
94
+
86
95
  def has_sensitive_types?
87
96
  return true if sensitive?
88
97
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foobara
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.102
4
+ version: 0.0.103
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miles Georgi