forest_admin_agent 1.0.0.pre.beta.27 → 1.0.0.pre.beta.28

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: d5a1222f5af1bf778087d4b388f224d8802cb52f4aa59a203d608145f11a0920
4
- data.tar.gz: a63be1a15f8778eb1a7766ebcc099ef66a39f8804059bb6b1fe9783c45cec718
3
+ metadata.gz: e2ae114be4b54df0354aca036cdc18ca08ab1c78b72d6975b3002179cea93a18
4
+ data.tar.gz: fd369183191175beb32c586bd98f2c67ccd21a7438e5b41741c0a5f0667985ce
5
5
  SHA512:
6
- metadata.gz: b395ae4c2e8a0d5c1a5f974170dc863af79f969d0118b703b97dde95e92b119f007bdc5373bac86fd271029f69493baca613f0608e031cfb7b1cf0284514bfc0
7
- data.tar.gz: 90a0a84788e6e13aa7a324463aee664c44f28952e22625335bbf95f7534ccccced3f8e397834658e1bb1154e6aa8756e39408fa3f5ad4c4e84885d5f360a6513
6
+ metadata.gz: 2465a1fb919eccdd5daef0183cf0bc371d312b6fa8462dfcbb6096e587376efad479184269b32617143e53d321c0208b361d99af66eabbeea299c6050dd87e3c
7
+ data.tar.gz: e8ee04c59cbc81fa1b38478e40507d94434b68e2be5009a7b6403731ac117793b9aa462c567704125a7a96264eee46123c7c915979f91ec20042fea2620dc361
@@ -34,6 +34,7 @@ module ForestAdminAgent
34
34
  name: args[:params]['collection_name'],
35
35
  content: JSONAPI::Serializer.serialize(
36
36
  records,
37
+ class_name: @collection.name,
37
38
  is_collection: true,
38
39
  serializer: Serializer::ForestSerializer,
39
40
  include: projection.relations.keys,
@@ -50,6 +50,7 @@ module ForestAdminAgent
50
50
  content: JSONAPI::Serializer.serialize(
51
51
  records,
52
52
  is_collection: true,
53
+ class_name: @child_collection.name,
53
54
  serializer: Serializer::ForestSerializer,
54
55
  include: projection.relations.keys
55
56
  )
@@ -34,6 +34,7 @@ module ForestAdminAgent
34
34
  name: args[:params]['collection_name'],
35
35
  content: JSONAPI::Serializer.serialize(
36
36
  records[0],
37
+ class_name: @collection.name,
37
38
  is_collection: false,
38
39
  serializer: Serializer::ForestSerializer,
39
40
  include: projection.relations.keys
@@ -25,6 +25,7 @@ module ForestAdminAgent
25
25
  content: JSONAPI::Serializer.serialize(
26
26
  record,
27
27
  is_collection: false,
28
+ class_name: @collection.name,
28
29
  serializer: Serializer::ForestSerializer
29
30
  )
30
31
  }
@@ -33,6 +33,7 @@ module ForestAdminAgent
33
33
  content: JSONAPI::Serializer.serialize(
34
34
  records[0],
35
35
  is_collection: false,
36
+ class_name: @collection.name,
36
37
  serializer: Serializer::ForestSerializer
37
38
  )
38
39
  }
@@ -20,8 +20,17 @@ module ForestAdminAgent
20
20
  end
21
21
 
22
22
  def type
23
- class_name = object.class.name
24
- @@class_names[class_name] ||= class_name.demodulize.underscore.freeze
23
+ class_name = @options[:class_name]
24
+ @@class_names[class_name] ||= class_name
25
+ end
26
+
27
+ def id
28
+ forest_collection = ForestAdminAgent::Facades::Container.datasource.get_collection(@options[:class_name])
29
+ primary_keys = ForestAdminDatasourceToolkit::Utils::Schema.primary_keys(forest_collection)
30
+ id = []
31
+ primary_keys.each { |key| id << @object[key] }
32
+
33
+ id.join('|')
25
34
  end
26
35
 
27
36
  def format_name(attribute_name)
@@ -41,7 +50,7 @@ module ForestAdminAgent
41
50
  end
42
51
 
43
52
  def attributes
44
- forest_collection = ForestAdminAgent::Facades::Container.datasource.get_collection(object.class.name.demodulize.underscore)
53
+ forest_collection = ForestAdminAgent::Facades::Container.datasource.get_collection(@options[:class_name])
45
54
  fields = forest_collection.schema[:fields].select { |_field_name, field| field.type == 'Column' }
46
55
  fields.each { |field_name, _field| add_attribute(field_name) }
47
56
  return {} if attributes_map.nil?
@@ -61,11 +70,7 @@ module ForestAdminAgent
61
70
  instance_eval(&attr_or_block)
62
71
  else
63
72
  # Default behavior, call a method by the name of the attribute.
64
- begin
65
- object.try(attr_or_block)
66
- rescue
67
- nil
68
- end
73
+ object[attr_or_block]
69
74
  end
70
75
  end
71
76
 
@@ -104,7 +109,8 @@ module ForestAdminAgent
104
109
  end
105
110
 
106
111
  def relationships
107
- forest_collection = ForestAdminAgent::Facades::Container.datasource.get_collection(object.class.name.demodulize.underscore)
112
+ datasource = ForestAdminAgent::Facades::Container.datasource
113
+ forest_collection = datasource.get_collection(@options[:class_name])
108
114
  relations_to_many = forest_collection.schema[:fields].select { |_field_name, field| field.type == 'OneToMany' || field.type == 'ManyToMany' }
109
115
  relations_to_one = forest_collection.schema[:fields].select { |_field_name, field| field.type == 'OneToOne' || field.type == 'ManyToOne' }
110
116
 
@@ -124,10 +130,13 @@ module ForestAdminAgent
124
130
  end
125
131
 
126
132
  object = has_one_relationship(attribute_name, attr_data)
127
- if object.nil?
133
+ if object.nil? || object.empty?
128
134
  data[formatted_attribute_name]['data'] = nil
129
135
  else
130
- related_object_serializer = ForestSerializer.new(object, @options)
136
+ relation = datasource.get_collection(@options[:class_name]).schema[:fields][attribute_name.to_s]
137
+ options = @options.clone
138
+ options[:class_name] = datasource.get_collection(relation.foreign_collection).name
139
+ related_object_serializer = ForestSerializer.new(object, options)
131
140
  data[formatted_attribute_name]['data'] = {
132
141
  'type' => related_object_serializer.type.to_s,
133
142
  'id' => related_object_serializer.id.to_s,
@@ -152,6 +161,9 @@ module ForestAdminAgent
152
161
  if @_include_linkages.include?(formatted_attribute_name) || attr_data[:options][:include_data]
153
162
  data[formatted_attribute_name]['data'] = []
154
163
  objects = has_many_relationship(attribute_name, attr_data) || []
164
+ relation = datasource.get_collection(@options[:class_name]).schema[:fields][attribute_name.to_s]
165
+ options = @options.clone
166
+ options[:class_name] = datasource.get_collection(relation.foreign_collection).name
155
167
  objects.each do |obj|
156
168
  related_object_serializer = JSONAPI::Serializer.find_serializer(obj, @options)
157
169
  data[formatted_attribute_name]['data'] << {
@@ -48,7 +48,7 @@ module ForestAdminAgent
48
48
  end
49
49
 
50
50
  # We're finding relationships for compound documents, so skip anything that doesn't exist.
51
- next if object.nil?
51
+ next if object.nil? || object.empty?
52
52
 
53
53
  # Full linkage: a request for comments.author MUST automatically include comments
54
54
  # in the response.
@@ -58,6 +58,8 @@ module ForestAdminAgent
58
58
  # If it is not set, that indicates that this is an inner path and not a leaf and will
59
59
  # be followed by the recursion below.
60
60
  objects.each do |obj|
61
+ relation = ForestAdminAgent::Facades::Container.datasource.get_collection(options[:class_name]).schema[:fields][attribute_name]
62
+ relation_class_name = ForestAdminAgent::Facades::Container.datasource.get_collection(relation.foreign_collection).name
61
63
  obj_serializer = JSONAPI::Serializer.find_serializer(obj, options)
62
64
  # Use keys of ['posts', '1'] for the results to enforce uniqueness.
63
65
  # Spec: A compound document MUST NOT include more than one resource object for each
@@ -82,7 +84,8 @@ module ForestAdminAgent
82
84
  # so merge the include_linkages each time we see it to load all the relevant linkages.
83
85
  current_child_includes += (results[key] && results[key][:include_linkages]) || []
84
86
  current_child_includes.uniq!
85
- results[key] = { object: obj, include_linkages: current_child_includes }
87
+
88
+ results[key] = { object: obj, include_linkages: current_child_includes, class_name: relation_class_name }
86
89
  end
87
90
  end
88
91
 
@@ -96,6 +99,123 @@ module ForestAdminAgent
96
99
  end
97
100
  nil
98
101
  end
102
+
103
+ def self.serialize(objects, options = {})
104
+ # Normalize option strings to symbols.
105
+ options[:is_collection] = options.delete('is_collection') || options[:is_collection] || false
106
+ options[:include] = options.delete('include') || options[:include]
107
+ options[:serializer] = options.delete('serializer') || options[:serializer]
108
+ options[:namespace] = options.delete('namespace') || options[:namespace]
109
+ options[:context] = options.delete('context') || options[:context] || {}
110
+ options[:skip_collection_check] = options.delete('skip_collection_check') || options[:skip_collection_check] || false
111
+ options[:base_url] = options.delete('base_url') || options[:base_url]
112
+ options[:jsonapi] = options.delete('jsonapi') || options[:jsonapi]
113
+ options[:meta] = options.delete('meta') || options[:meta]
114
+ options[:links] = options.delete('links') || options[:links]
115
+ options[:fields] = options.delete('fields') || options[:fields] || {}
116
+
117
+ # Deprecated: use serialize_errors method instead
118
+ options[:errors] = options.delete('errors') || options[:errors]
119
+
120
+ # Normalize includes.
121
+ includes = options[:include]
122
+ includes = (includes.is_a?(String) ? includes.split(',') : includes).uniq if includes
123
+
124
+ # Transforms input so that the comma-separated fields are separate symbols in array
125
+ # and keys are stringified
126
+ # Example:
127
+ # {posts: 'title,author,long_comments'} => {'posts' => [:title, :author, :long_comments]}
128
+ # {posts: ['title', 'author', 'long_comments'} => {'posts' => [:title, :author, :long_comments]}
129
+ #
130
+ fields = {}
131
+ # Normalize fields to accept a comma-separated string or an array of strings.
132
+ options[:fields].map do |type, whitelisted_fields|
133
+ whitelisted_fields = [whitelisted_fields] if whitelisted_fields.is_a?(Symbol)
134
+ whitelisted_fields = whitelisted_fields.split(',') if whitelisted_fields.is_a?(String)
135
+ fields[type.to_s] = whitelisted_fields.map(&:to_sym)
136
+ end
137
+
138
+ # An internal-only structure that is passed through serializers as they are created.
139
+ passthrough_options = {
140
+ context: options[:context],
141
+ serializer: options[:serializer],
142
+ namespace: options[:namespace],
143
+ include: includes,
144
+ fields: fields,
145
+ base_url: options[:base_url],
146
+ class_name: options[:class_name]
147
+ }
148
+
149
+ if !options[:skip_collection_check] && options[:is_collection] && !objects.respond_to?(:each)
150
+ raise JSONAPI::Serializer::AmbiguousCollectionError.new(
151
+ 'Attempted to serialize a single object as a collection.')
152
+ end
153
+
154
+ # Automatically include linkage data for any relation that is also included.
155
+ if includes
156
+ include_linkages = includes.map { |key| key.to_s.split('.').first }
157
+ passthrough_options[:include_linkages] = include_linkages
158
+ end
159
+
160
+ # Spec: Primary data MUST be either:
161
+ # - a single resource object or null, for requests that target single resources.
162
+ # - an array of resource objects or an empty array ([]), for resource collections.
163
+ # http://jsonapi.org/format/#document-structure-top-level
164
+ if options[:is_collection] && !objects.any?
165
+ primary_data = []
166
+ elsif !options[:is_collection] && objects.nil?
167
+ primary_data = nil
168
+ elsif options[:is_collection]
169
+ # Have object collection.
170
+ primary_data = serialize_primary_multi(objects, passthrough_options)
171
+ else
172
+ # Duck-typing check for a collection being passed without is_collection true.
173
+ # We always must be told if serializing a collection because the JSON:API spec distinguishes
174
+ # how to serialize null single resources vs. empty collections.
175
+ if !options[:skip_collection_check] && objects.is_a?(Array)
176
+ raise JSONAPI::Serializer::AmbiguousCollectionError.new(
177
+ 'Must provide `is_collection: true` to `serialize` when serializing collections.')
178
+ end
179
+ # Have single object.
180
+ primary_data = serialize_primary(objects, passthrough_options)
181
+ end
182
+ result = {
183
+ 'data' => primary_data,
184
+ }
185
+ result['jsonapi'] = options[:jsonapi] if options[:jsonapi]
186
+ result['meta'] = options[:meta] if options[:meta]
187
+ result['links'] = options[:links] if options[:links]
188
+ result['errors'] = options[:errors] if options[:errors]
189
+
190
+ # If 'include' relationships are given, recursively find and include each object.
191
+ if includes
192
+ relationship_data = {}
193
+ inclusion_tree = parse_relationship_paths(includes)
194
+
195
+ # Given all the primary objects (either the single root object or collection of objects),
196
+ # recursively search and find related associations that were specified as includes.
197
+ objects = options[:is_collection] ? objects.to_a : [objects]
198
+ objects.compact.each do |obj|
199
+ # Use the mutability of relationship_data as the return datastructure to take advantage
200
+ # of the internal special merging logic.
201
+ find_recursive_relationships(obj, inclusion_tree, relationship_data, passthrough_options)
202
+ end
203
+
204
+ result['included'] = relationship_data.map do |_, data|
205
+ included_passthrough_options = {}
206
+ included_passthrough_options[:base_url] = passthrough_options[:base_url]
207
+ included_passthrough_options[:context] = passthrough_options[:context]
208
+ included_passthrough_options[:fields] = passthrough_options[:fields]
209
+ included_passthrough_options[:serializer] = find_serializer_class(data[:object], options)
210
+ included_passthrough_options[:namespace] = passthrough_options[:namespace]
211
+ included_passthrough_options[:include_linkages] = data[:include_linkages]
212
+ included_passthrough_options[:class_name] = data[:class_name]
213
+
214
+ serialize_primary(data[:object], included_passthrough_options)
215
+ end
216
+ end
217
+ result
218
+ end
99
219
  end
100
220
  end
101
221
  end
@@ -7,7 +7,7 @@ module ForestAdminAgent
7
7
  class SchemaEmitter
8
8
  LIANA_NAME = "forest-rails"
9
9
 
10
- LIANA_VERSION = "1.0.0-beta.27"
10
+ LIANA_VERSION = "1.0.0-beta.28"
11
11
 
12
12
  def self.get_serialized_schema(datasource)
13
13
  schema_path = Facades::Container.cache(:schema_path)
@@ -1,3 +1,3 @@
1
1
  module ForestAdminAgent
2
- VERSION = "1.0.0-beta.27"
2
+ VERSION = "1.0.0-beta.28"
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.0.0.pre.beta.27
4
+ version: 1.0.0.pre.beta.28
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: 2024-01-02 00:00:00.000000000 Z
12
+ date: 2024-01-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport