forest_admin_agent 1.38.2 → 1.38.3

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: 948a67317152cf955d6e7ff512b20b810d136ff9ab89e8ad87cbb2a09e9b80e2
4
- data.tar.gz: 3984557e91f84b405857a45debf12c7ec2d39377575be0a645ad9c4c7c1de872
3
+ metadata.gz: 8240dc695f68ad1315a072be614a48151c0f52a0a35596500face2c12bdc3847
4
+ data.tar.gz: 267ec0985751c7c86e5df4c426862063bf1b5e41e06ba24d7ee14bf1a80ecf69
5
5
  SHA512:
6
- metadata.gz: d051b8008198eb80152b4e542ce4c570f0e3215c46a6e9cdbe05405d395c9760fc7176318a4eb0533e1ca91443c7c3be17ac9d51176094910e6fe3230f77bf43
7
- data.tar.gz: a103408031a613a2061036ca066502f72752f2138d22e526cb5706bd7b703b415297cf9aba273d3976dc1a2bf52b6ed948d9f768e6c74d2f99031d9397dbd809
6
+ metadata.gz: 2966283a4f8b14022cdd74a54c6e366cdfae74314cd64d77fafbb8c7c258fa860dcacafc0e1dcd842d7d590ed63884a2550aa16066696d8313d0427fa552ad3b
7
+ data.tar.gz: c943da4d2edf12f3e4f2b34d10ee70184befe11fe276cb246f785051cb7b7fcfb6e885459c9e5431e0351c6621db30ee6e2cab5ad93ee5c9ed3b8cf152ce63cc
@@ -43,7 +43,7 @@ module ForestAdminAgent
43
43
  class_name: context.collection.name,
44
44
  is_collection: true,
45
45
  serializer: Serializer::ForestSerializer,
46
- include: projection.relations(only_keys: true),
46
+ include: projection.relation_include_paths,
47
47
  meta: handle_search_decorator(args[:params]['search'], records, context.collection)
48
48
  )
49
49
  }
@@ -53,7 +53,7 @@ module ForestAdminAgent
53
53
  is_collection: true,
54
54
  class_name: context.child_collection.name,
55
55
  serializer: Serializer::ForestSerializer,
56
- include: projection.relations.keys
56
+ include: projection.relation_include_paths
57
57
  )
58
58
  }
59
59
  end
@@ -38,7 +38,7 @@ module ForestAdminAgent
38
38
  class_name: context.collection.name,
39
39
  is_collection: false,
40
40
  serializer: Serializer::ForestSerializer,
41
- include: projection.relations(only_keys: true)
41
+ include: projection.relation_include_paths
42
42
  )
43
43
  }
44
44
  end
@@ -54,23 +54,24 @@ module ForestAdminAgent
54
54
  # Full linkage: a request for comments.author MUST automatically include comments
55
55
  # in the response.
56
56
  objects = is_collection ? object : [object]
57
+
58
+ relation = ForestAdminAgent::Facades::Container.datasource
59
+ .get_collection(options[:class_name].gsub('::', '__'))
60
+ .schema[:fields][attribute_name]
61
+ if relation.type == 'PolymorphicManyToOne'
62
+ relation_class_name = root_object[relation.foreign_key_type_field]
63
+ else
64
+ relation_class_name = ForestAdminAgent::Facades::Container.datasource.get_collection(relation.foreign_collection).name
65
+ end
66
+
67
+ related_collection_options = options.merge(class_name: relation_class_name)
68
+
57
69
  if child_inclusion_tree[:_include] == true
58
70
  # Include the current level objects if the _include attribute exists.
59
71
  # If it is not set, that indicates that this is an inner path and not a leaf and will
60
72
  # be followed by the recursion below.
61
73
  objects.each do |obj|
62
- relation = ForestAdminAgent::Facades::Container.datasource
63
- .get_collection(options[:class_name].gsub('::', '__'))
64
- .schema[:fields][attribute_name]
65
- if relation.type == 'PolymorphicManyToOne'
66
- relation_class_name = root_object[relation.foreign_key_type_field]
67
- else
68
- relation_class_name = ForestAdminAgent::Facades::Container.datasource.get_collection(relation.foreign_collection).name
69
- end
70
-
71
- option_relation = options.clone
72
- option_relation[:class_name] = relation_class_name
73
- obj_serializer = JSONAPI::Serializer.find_serializer(obj, option_relation)
74
+ obj_serializer = JSONAPI::Serializer.find_serializer(obj, related_collection_options)
74
75
 
75
76
  # Use keys of ['posts', '1'] for the results to enforce uniqueness.
76
77
  # Spec: A compound document MUST NOT include more than one resource object for each
@@ -105,7 +106,7 @@ module ForestAdminAgent
105
106
 
106
107
  # For each object we just loaded, find all deeper recursive relationships.
107
108
  objects.each do |obj|
108
- find_recursive_relationships(obj, child_inclusion_tree, results, options)
109
+ find_recursive_relationships(obj, child_inclusion_tree, results, related_collection_options)
109
110
  end
110
111
  end
111
112
  nil
@@ -9,6 +9,7 @@ module ForestAdminAgent
9
9
 
10
10
  DEFAULT_ITEMS_PER_PAGE = '15'.freeze
11
11
  DEFAULT_PAGE_TO_SKIP = '1'.freeze
12
+ POLYMORPHIC_TARGET_WILDCARD = '*'.freeze
12
13
 
13
14
  def self.parse_condition_tree(collection, args)
14
15
  filters = begin
@@ -88,7 +89,7 @@ module ForestAdminAgent
88
89
  when 'Column'
89
90
  field_name
90
91
  when 'PolymorphicManyToOne'
91
- "#{field_name}:*"
92
+ "#{field_name}:#{POLYMORPHIC_TARGET_WILDCARD}"
92
93
  else
93
94
  relation_fields = args.dig(:params, :fields, field_name)
94
95
 
@@ -110,18 +111,63 @@ module ForestAdminAgent
110
111
  root_field_names_with_types = root_field_names.dup
111
112
  add_polymorphic_type_fields(collection, root_field_names_with_types)
112
113
 
113
- projection_fields = requested_paths.map do |path|
114
- field_name, nested_path = path.split(':', 2)
115
- field = get_field(collection, field_name)
114
+ projection_fields = requested_paths.map { |path| expand_polymorphic_leaf(collection, path) }
116
115
 
117
- if field.type == 'PolymorphicManyToOne' && (nested_path.nil? || nested_path == '*')
118
- "#{field_name}:*"
119
- else
120
- path
116
+ projection_fields |
117
+ (root_field_names_with_types - root_field_names) |
118
+ nested_polymorphic_linkage_fields(collection, projection_fields)
119
+ end
120
+
121
+ def self.expand_polymorphic_leaf(collection, path)
122
+ segments = path.split(':')
123
+ leaf_index = segments.size - 1
124
+
125
+ each_field_along_path(collection, segments) do |field, index|
126
+ return "#{path}:#{POLYMORPHIC_TARGET_WILDCARD}" if polymorphic_many_to_one?(field) && index == leaf_index
127
+ end
128
+
129
+ path
130
+ end
131
+
132
+ def self.nested_polymorphic_linkage_fields(collection, projection_fields)
133
+ projection_fields.flat_map do |path|
134
+ segments = path.split(':')
135
+
136
+ each_field_along_path(collection, segments).flat_map do |field, index|
137
+ next [] unless polymorphic_many_to_one?(field) && index.positive?
138
+
139
+ polymorphic_linkage_columns(field, segments[0...index])
121
140
  end
122
141
  end
142
+ end
143
+
144
+ def self.polymorphic_linkage_columns(field, relation_path)
145
+ [field.foreign_key_type_field, field.foreign_key].map { |column| (relation_path + [column]).join(':') }
146
+ end
147
+
148
+ def self.each_field_along_path(collection, segments)
149
+ return to_enum(:each_field_along_path, collection, segments) unless block_given?
150
+
151
+ current_collection = collection
152
+
153
+ segments.each_with_index do |segment, index|
154
+ field = field_along_path(current_collection, segment, root: index.zero?)
155
+ break if field.nil?
156
+
157
+ yield field, index
158
+
159
+ break unless field.respond_to?(:foreign_collection)
160
+
161
+ current_collection = collection.datasource.get_collection(field.foreign_collection)
162
+ end
163
+ end
164
+
165
+ def self.field_along_path(collection, segment, root:)
166
+ root ? get_field(collection, segment) : collection.schema[:fields][segment]
167
+ end
123
168
 
124
- projection_fields | (root_field_names_with_types - root_field_names)
169
+ def self.polymorphic_many_to_one?(field)
170
+ field.type == 'PolymorphicManyToOne'
125
171
  end
126
172
 
127
173
  def self.get_field(collection, field_name)
@@ -135,7 +181,10 @@ module ForestAdminAgent
135
181
  'Please check if the field name is correct.'
136
182
  end
137
183
  private_class_method :add_polymorphic_type_fields, :build_projection_fields,
138
- :build_header_projection_fields, :get_field
184
+ :build_header_projection_fields, :get_field,
185
+ :expand_polymorphic_leaf, :nested_polymorphic_linkage_fields,
186
+ :polymorphic_linkage_columns, :each_field_along_path,
187
+ :field_along_path, :polymorphic_many_to_one?
139
188
 
140
189
  def self.parse_projection_with_pks(collection, args)
141
190
  parse_projection_from_request(collection, args).with_pks(collection)
@@ -6,7 +6,7 @@ module ForestAdminAgent
6
6
  module Schema
7
7
  class SchemaEmitter
8
8
  LIANA_NAME = "agent-ruby"
9
- LIANA_VERSION = "1.38.2"
9
+ LIANA_VERSION = "1.38.3"
10
10
 
11
11
  def self.generate(datasource)
12
12
  datasource.collections
@@ -1,3 +1,3 @@
1
1
  module ForestAdminAgent
2
- VERSION = "1.38.2"
2
+ VERSION = "1.38.3"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: forest_admin_agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.38.2
4
+ version: 1.38.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthieu
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2026-08-13 00:00:00.000000000 Z
12
+ date: 2026-08-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport