jpie 1.5.0 → 1.5.1

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: d6718c74febd247abaa1dd7294fd729209a3e905363e02d8bb88f20e6a8ee92e
4
- data.tar.gz: 388c8ee9564f191f14e87d0095d15657dd4ccb55c841d26755d8d7916811d0f0
3
+ metadata.gz: be60282bbba362a7ac36dca3370a4733981bce7a949352513244879bc76546a7
4
+ data.tar.gz: 6c391beea011b7fd348f8a2439130ba174dd31fa7b8f9f4ea6eaef5c9fd916ee
5
5
  SHA512:
6
- metadata.gz: d4188461bf266a55290b2728691e8b052b8f8eeb2ba319949aa0fbb23109dc9175e2c7d29aa53e3768fe794738cd7f5b70e83f624ec0ff72af13051159eb4800
7
- data.tar.gz: dd193aec85fc8fb12ef21200eca3341411d7c12c0e32f5d2d50562d4fcbefd76ddfc4d08ea36b2c69204c2b579fa2dd9cac18cd2aa4540898f4a9f9543422218
6
+ metadata.gz: 13f21d51760a269d54d1bcd46a9be3916506bae8c25af82eaabea8dc7a214d2f3d39b29437ca0703141a794444d13b7ab20ba26ac4f35f4fe3a8ca15207d1630
7
+ data.tar.gz: 35e11173e5942bc01059217acf3a5028f5980108b2c76e88b33fe03c9c2ae00a4a6a9c0051328e491a257d83700f02f6a206c7a34406cde968af1a6698ac63fd
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- jpie (1.5.0)
4
+ jpie (1.5.1)
5
5
  actionpack (~> 8.0, >= 8.0.0)
6
6
  rails (~> 8.0, >= 8.0.0)
7
7
 
@@ -2,34 +2,62 @@
2
2
 
3
3
  module JSONAPI
4
4
  module Serialization
5
+ IncludeContext = Struct.new(:fields, :included_records, :processed, :all_includes, keyword_init: true)
6
+ PathContext = Struct.new(:path_parts, :path_to_related, :association_name, :current_record, keyword_init: true)
7
+ IncludeIteration = Struct.new(:related_record, :path_parts, :path_to_related, :association_name, :current_record,
8
+ keyword_init: true,)
9
+
5
10
  module IncludesSerialization
11
+ include IncludePathHelpers
12
+
6
13
  def serialize_included(includes, fields = {})
7
14
  all_includes = normalize_include_paths(includes)
8
15
  return [] if all_includes.empty?
9
16
 
10
- included_records = []
11
- processed = Set.new
12
-
13
- all_includes.each do |include_path|
14
- serialize_include_path(record, include_path, fields, included_records, processed, all_includes:)
15
- end
17
+ ctx = build_include_context(fields, all_includes)
18
+ all_includes.each { |path| serialize_include_path(record, path, ctx, path_from_root: "") }
19
+ ctx.included_records
20
+ end
16
21
 
17
- included_records
22
+ def build_include_context(fields, all_includes)
23
+ IncludeContext.new(
24
+ fields: fields,
25
+ included_records: [],
26
+ processed: Set.new,
27
+ all_includes: all_includes,
28
+ )
18
29
  end
19
30
 
20
31
  private
21
32
 
22
- def serialize_include_path(current_record, include_path, fields, included_records, processed, all_includes:)
33
+ def serialize_include_path(current_record, include_path, ctx, path_from_root: "")
23
34
  path_parts = include_path.split(".")
24
35
  association_name = path_parts.first.to_sym
25
-
26
36
  return unless valid_include_association?(current_record, association_name)
27
37
 
28
- related_array = get_related_records(current_record, association_name)
38
+ path_to_related = path_from_root.blank? ? path_parts.first : "#{path_from_root}.#{path_parts.first}"
39
+ path_ctx = PathContext.new(path_parts:, path_to_related:, association_name:, current_record: current_record)
40
+ process_related_records(get_related_records(current_record, association_name), path_ctx, ctx)
41
+ end
42
+
43
+ def process_related_records(related_array, path_ctx, ctx)
29
44
  related_array.each do |related_record|
30
- parent_context = self.class.active_storage_attachment?(association_name, current_record.class) ? { parent_record: current_record, association_name: } : {}
31
- serialize_and_process_record(related_record, include_path, all_includes, fields, included_records, processed, **parent_context)
32
- serialize_nested_path(related_record, path_parts, fields, included_records, processed, all_includes:)
45
+ iter = IncludeIteration.new(related_record: related_record, **path_ctx.to_h)
46
+ serialize_related_record(iter, ctx)
47
+ end
48
+ end
49
+
50
+ def serialize_related_record(iter, ctx)
51
+ parent_context = parent_context_for(iter.association_name, iter.current_record)
52
+ serialize_and_process_record(iter.related_record, iter.path_to_related, ctx, **parent_context)
53
+ serialize_nested_path(iter.related_record, iter.path_parts, iter.path_to_related, ctx)
54
+ end
55
+
56
+ def parent_context_for(association_name, current_record)
57
+ if self.class.active_storage_attachment?(association_name, current_record.class)
58
+ { parent_record: current_record, association_name: }
59
+ else
60
+ {}
33
61
  end
34
62
  end
35
63
 
@@ -81,53 +109,24 @@ module JSONAPI
81
109
  [attachment.blob].compact
82
110
  end
83
111
 
84
- def serialize_and_process_record(related_record, include_path, all_includes, fields, included_records, processed, parent_record: nil, association_name: nil) # rubocop:disable Metrics/ParameterLists
85
- record_key = build_record_key(related_record)
86
- return if processed.include?(record_key)
112
+ def serialize_and_process_record(related_record, path_to_record, ctx, parent_record: nil, association_name: nil)
113
+ return if ctx.processed.include?(build_record_key(related_record))
87
114
 
88
- requested_relationships = include_paths_to_relationship_names(all_includes, include_path)
115
+ requested = include_paths_to_relationship_names(ctx.all_includes, path_to_record)
89
116
  serializer = self.class.new(related_record, parent_record:, association_name:)
90
- included_records << serializer.serialize_record(fields, requested_relationships: requested_relationships)
91
- processed.add(record_key)
117
+ ctx.included_records << serializer.serialize_record(ctx.fields, requested_relationships: requested)
118
+ ctx.processed.add(build_record_key(related_record))
92
119
  end
93
120
 
94
121
  def build_record_key(related_record)
95
122
  "#{related_record.class.name}-#{related_record.id}"
96
123
  end
97
124
 
98
- def serialize_nested_path(related_record, path_parts, fields, included_records, processed, all_includes:)
125
+ def serialize_nested_path(related_record, path_parts, path_from_root, ctx)
99
126
  return unless path_parts.length > 1
100
127
 
101
128
  nested_path = path_parts[1..].join(".")
102
- serialize_include_path(related_record, nested_path, fields, included_records, processed,
103
- all_includes: all_includes,)
104
- end
105
-
106
- def normalize_include_paths(include_param)
107
- case include_param
108
- when Array
109
- include_param.flat_map { |s| s.to_s.split(",").map(&:strip) }.uniq
110
- when String
111
- include_param.split(",").map(&:strip)
112
- else
113
- []
114
- end
115
- end
116
-
117
- def include_paths_to_relationship_names(include_paths, path_prefix)
118
- return [] if include_paths.blank?
119
-
120
- prefix = path_prefix.present? ? "#{path_prefix}." : ""
121
- include_paths.filter_map do |p|
122
- path = p.to_s
123
- next unless path == path_prefix || path.start_with?(prefix)
124
-
125
- segments = path.split(".")
126
- prefix_segments = path_prefix.split(".")
127
- next if segments.length <= prefix_segments.length
128
-
129
- segments[prefix_segments.length].to_sym
130
- end.uniq
129
+ serialize_include_path(related_record, nested_path, ctx, path_from_root: path_from_root)
131
130
  end
132
131
  end
133
132
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module JSONAPI
4
+ module Serialization
5
+ module IncludePathHelpers
6
+ def normalize_include_paths(include_param)
7
+ case include_param
8
+ when Array
9
+ include_param.flat_map { |s| s.to_s.split(",").map(&:strip) }.uniq
10
+ when String
11
+ include_param.split(",").map(&:strip)
12
+ else
13
+ []
14
+ end
15
+ end
16
+
17
+ def include_paths_to_relationship_names(include_paths, path_prefix)
18
+ return [] if include_paths.blank?
19
+
20
+ prefix = path_prefix.present? ? "#{path_prefix}." : ""
21
+ include_paths.filter_map do |p|
22
+ path = p.to_s
23
+ next unless path == path_prefix || path.start_with?(prefix)
24
+
25
+ segments = path.split(".")
26
+ prefix_segments = path_prefix.split(".")
27
+ next if segments.length <= prefix_segments.length
28
+
29
+ segments[prefix_segments.length].to_sym
30
+ end.uniq
31
+ end
32
+ end
33
+ end
34
+ end
@@ -3,6 +3,7 @@
3
3
  require_relative "concerns/attributes_serialization"
4
4
  require_relative "concerns/relationships_serialization"
5
5
  require_relative "concerns/links_serialization"
6
+ require_relative "include_path_helpers"
6
7
  require_relative "concerns/includes_serialization"
7
8
  require_relative "concerns/meta_serialization"
8
9
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSONAPI
4
- VERSION = "1.5.0"
4
+ VERSION = "1.5.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jpie
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 1.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emil Kampp
@@ -126,6 +126,7 @@ files:
126
126
  - lib/json_api/serialization/concerns/relationships_deserialization.rb
127
127
  - lib/json_api/serialization/concerns/relationships_serialization.rb
128
128
  - lib/json_api/serialization/deserializer.rb
129
+ - lib/json_api/serialization/include_path_helpers.rb
129
130
  - lib/json_api/serialization/serializer.rb
130
131
  - lib/json_api/support/active_storage_support.rb
131
132
  - lib/json_api/support/collection_query.rb