jpie 0.4.1 → 0.4.2

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.
@@ -23,9 +23,15 @@ module JPie
23
23
  end
24
24
 
25
25
  # More concise method names following Rails conventions
26
- def render_jsonapi(resource_or_resources, status: :ok, meta: nil)
26
+ def render_jsonapi(resource_or_resources, status: :ok, meta: nil, pagination: nil, original_scope: nil)
27
27
  includes = parse_include_params
28
28
  json_data = serializer.serialize(resource_or_resources, context, includes: includes)
29
+
30
+ # Add pagination metadata and links if pagination is provided and valid
31
+ if pagination && pagination[:per_page]
32
+ add_pagination_metadata(json_data, resource_or_resources, pagination, original_scope)
33
+ end
34
+
29
35
  json_data[:meta] = meta if meta
30
36
 
31
37
  render json: json_data, status:, content_type: 'application/vnd.api+json'
@@ -37,6 +43,94 @@ module JPie
37
43
 
38
44
  private
39
45
 
46
+ def add_pagination_metadata(json_data, resources, pagination, original_scope)
47
+ page = pagination[:page] || 1
48
+ per_page = pagination[:per_page]
49
+
50
+ # Get total count from the original scope before pagination
51
+ total_count = get_total_count(resources, original_scope)
52
+ total_pages = (total_count.to_f / per_page).ceil
53
+
54
+ # Add pagination metadata
55
+ json_data[:meta] ||= {}
56
+ json_data[:meta][:pagination] = {
57
+ page: page,
58
+ per_page: per_page,
59
+ total_pages: total_pages,
60
+ total_count: total_count
61
+ }
62
+
63
+ # Add pagination links
64
+ json_data[:links] = build_pagination_links(page, per_page, total_pages)
65
+ end
66
+
67
+ def get_total_count(resources, original_scope)
68
+ # Use original scope if provided, otherwise fall back to resources
69
+ scope_to_count = original_scope || resources
70
+
71
+ # If scope is an ActiveRecord relation, get the count
72
+ # Otherwise, if it's an array, get the length
73
+ if scope_to_count.respond_to?(:count) && !scope_to_count.loaded?
74
+ scope_to_count.count
75
+ elsif scope_to_count.respond_to?(:size)
76
+ scope_to_count.size
77
+ else
78
+ 0
79
+ end
80
+ end
81
+
82
+ def build_pagination_links(page, per_page, total_pages)
83
+ url_components = extract_url_components
84
+ pagination_data = { page: page, per_page: per_page, total_pages: total_pages }
85
+
86
+ links = build_base_pagination_links(url_components, pagination_data)
87
+ add_conditional_pagination_links(links, url_components, pagination_data)
88
+
89
+ links
90
+ end
91
+
92
+ def extract_url_components
93
+ base_url = request.respond_to?(:base_url) ? request.base_url : 'http://example.com'
94
+ path = request.respond_to?(:path) ? request.path : '/resources'
95
+ query_params = request.respond_to?(:query_parameters) ? request.query_parameters.except('page') : {}
96
+
97
+ { base_url: base_url, path: path, query_params: query_params }
98
+ end
99
+
100
+ def build_base_pagination_links(url_components, pagination_data)
101
+ full_url = url_components[:base_url] + url_components[:path]
102
+ query_params = url_components[:query_params]
103
+ page = pagination_data[:page]
104
+ per_page = pagination_data[:per_page]
105
+ total_pages = pagination_data[:total_pages]
106
+
107
+ {
108
+ self: build_page_url(full_url, query_params, page, per_page),
109
+ first: build_page_url(full_url, query_params, 1, per_page),
110
+ last: build_page_url(full_url, query_params, total_pages, per_page)
111
+ }
112
+ end
113
+
114
+ def add_conditional_pagination_links(links, url_components, pagination_data)
115
+ full_url = url_components[:base_url] + url_components[:path]
116
+ query_params = url_components[:query_params]
117
+ page = pagination_data[:page]
118
+ per_page = pagination_data[:per_page]
119
+ total_pages = pagination_data[:total_pages]
120
+
121
+ links[:prev] = build_page_url(full_url, query_params, page - 1, per_page) if page > 1
122
+ links[:next] = build_page_url(full_url, query_params, page + 1, per_page) if page < total_pages
123
+ end
124
+
125
+ def build_page_url(base_url, query_params, page_num, per_page)
126
+ params = query_params.merge(
127
+ 'page' => page_num.to_s,
128
+ 'per_page' => per_page.to_s
129
+ )
130
+ query_string = params.respond_to?(:to_query) ? params.to_query : params.map { |k, v| "#{k}=#{v}" }.join('&')
131
+ "#{base_url}?#{query_string}"
132
+ end
133
+
40
134
  def infer_resource_class
41
135
  # Convert controller name to resource class name
42
136
  # e.g., "UsersController" -> "UserResource"
@@ -104,13 +104,8 @@ module JPie
104
104
 
105
105
  # Handle through associations by calling the appropriate association method
106
106
  def handle_through_association(name, options)
107
- if options[:attr]
108
- # Custom attribute name was provided - use it
109
- @object.public_send(options[:attr])
110
- else
111
- # Use the relationship name directly - Rails will handle the through association
112
- @object.public_send(name)
113
- end
107
+ attr_name = options[:attr] || name
108
+ @object.public_send(attr_name)
114
109
  end
115
110
  end
116
111
  end
data/lib/jpie/resource.rb CHANGED
@@ -51,17 +51,31 @@ module JPie
51
51
  # Return supported sort fields for validation
52
52
  # Override this method to customize supported sort fields
53
53
  def supported_sort_fields
54
- # Return all attributes and sortable fields as supported sort fields by default
55
- fields = (_attributes + _sortable_fields.keys).uniq.map(&:to_s)
54
+ base_fields = extract_base_sort_fields
55
+ timestamp_fields = extract_timestamp_fields
56
+ (base_fields + timestamp_fields).uniq
57
+ end
56
58
 
57
- # Add common model timestamp fields if the model supports them
58
- if model.respond_to?(:column_names)
59
- fields << 'created_at' if model.column_names.include?('created_at') && fields.exclude?('created_at')
59
+ private
60
60
 
61
- fields << 'updated_at' if model.column_names.include?('updated_at') && fields.exclude?('updated_at')
62
- end
61
+ def extract_base_sort_fields
62
+ (_attributes + _sortable_fields.keys).uniq.map(&:to_s)
63
+ end
64
+
65
+ def extract_timestamp_fields
66
+ return [] unless model.respond_to?(:column_names)
67
+
68
+ timestamp_fields = []
69
+ add_timestamp_field(timestamp_fields, 'created_at')
70
+ add_timestamp_field(timestamp_fields, 'updated_at')
71
+ timestamp_fields
72
+ end
73
+
74
+ def add_timestamp_field(fields, field_name)
75
+ return unless model.column_names.include?(field_name)
76
+ return if fields.include?(field_name)
63
77
 
64
- fields
78
+ fields << field_name
65
79
  end
66
80
  end
67
81
 
data/lib/jpie/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JPie
4
- VERSION = '0.4.1'
4
+ VERSION = '0.4.2'
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jpie
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Emil Kampp
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-05-25 00:00:00.000000000 Z
10
+ date: 2025-05-26 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activesupport
@@ -170,6 +170,7 @@ extensions: []
170
170
  extra_rdoc_files: []
171
171
  files:
172
172
  - ".cursorrules"
173
+ - ".overcommit.yml"
173
174
  - ".rubocop.yml"
174
175
  - CHANGELOG.md
175
176
  - LICENSE.txt
@@ -177,6 +178,7 @@ files:
177
178
  - Rakefile
178
179
  - examples/basic_example.md
179
180
  - examples/including_related_resources.md
181
+ - examples/pagination.md
180
182
  - examples/resource_attribute_configuration.md
181
183
  - examples/resource_meta_configuration.md
182
184
  - examples/single_table_inheritance.md
@@ -186,6 +188,8 @@ files:
186
188
  - lib/jpie/controller.rb
187
189
  - lib/jpie/controller/crud_actions.rb
188
190
  - lib/jpie/controller/error_handling.rb
191
+ - lib/jpie/controller/error_handling/handler_setup.rb
192
+ - lib/jpie/controller/error_handling/handlers.rb
189
193
  - lib/jpie/controller/json_api_validation.rb
190
194
  - lib/jpie/controller/parameter_parsing.rb
191
195
  - lib/jpie/controller/rendering.rb