active_record-cursor_paginator 0.3.1 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e6079364fab39f26c9d63199730cc44ae0138c5c3d8452aa1b73219e0afa0e1
4
- data.tar.gz: 36d9c3020d18dafe2905b18a6a50bebee06ab17caff4ff4abd4eb9bb965aa851
3
+ metadata.gz: 2b976c754e305df50a8c5eb4889bf98a6041a3e4c8fa73b7c6d6a4566068037a
4
+ data.tar.gz: 680ed7b82dd56e0c1a72db977350b701bdd9c90666053e7399f9dd9d280afae6
5
5
  SHA512:
6
- metadata.gz: db459de8e2b52873f5ccb95e9bb7b957af9381a30fcfca97786189874bfacc8808f80fb939ea86d54c8f50cb5983b263089df16f4e7f2294387d41757cf723d1
7
- data.tar.gz: a344ab46f80d38a5c43d890793031a31194d3f3b7dfe6b53258c94a77a08386470c7201e46f5d6833cd2f9e77c0f3fa940afb0306c951648193b1f04f0530ce9
6
+ metadata.gz: 7097e691c6a902bb42d0c2b8a7cb55a22d768b3d7bedefe344d05500efa6e665145d5e6ed8263bc3cbc313dd256bfab294a2651aa6fc1b230c910a8bdabd7abb
7
+ data.tar.gz: e1508a1aed8100c86f8f389a16b35996a4d633fb371a0e7a918ab728ee7e236f57b22df4d9d7ab6a1b8fe9785294bd0c5cc804f2f6d0e712d2ef4e88b746de84
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## [0.3.2] - 2026-06-03
2
+
3
+ - Fix timezone offset in datetime cursor values being ignored in WHERE clause
4
+ - Warn when a datetime cursor column is a join table alias, as type inference may be inaccurate
5
+
1
6
  ## [0.3.1] - 2026-03-06
2
7
 
3
8
  - Add support for Rails enum columns
data/README.md CHANGED
@@ -65,6 +65,18 @@ ActiveSupport::JSON::Encoding.time_precision = 6
65
65
 
66
66
  ## Limitation
67
67
 
68
+ ### Datetime cursor values on join table columns
69
+
70
+ When ordering by a datetime column from a joined table via an alias (e.g. `authors.created_at as author_created_at`), the column type is inferred from the root model. If the joined table's column type differs from the root model's column with the same name, timezone conversion in cursor values may be inaccurate.
71
+
72
+ A warning is logged when this situation is detected:
73
+
74
+ ```
75
+ [CursorPaginator] Cursor column 'author_created_at' resolves to 'authors.created_at'
76
+ (join column). Type is inferred from Post and may be inaccurate.
77
+ Timezone-aware datetime cursors on joined tables may not work correctly.
78
+ ```
79
+
68
80
  This library does not support the following order expressions
69
81
 
70
82
  ```ruby
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveRecord
4
4
  class CursorPaginator
5
- VERSION = '0.3.1'
5
+ VERSION = '0.3.2'
6
6
  end
7
7
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'active_record'
4
+ require 'set'
4
5
  require_relative 'cursor_paginator/version'
5
6
 
6
7
  module ActiveRecord
@@ -168,7 +169,7 @@ module ActiveRecord
168
169
  def cursor_for_record(record)
169
170
  unencoded_cursor = @fields.map do |field|
170
171
  field_name = field.keys.first
171
- value = if record.class.defined_enums.key?(field_name.to_s)
172
+ value = if record.class.defined_enums.has_key?(field_name.to_s)
172
173
  # For enum columns, get the raw integer value from the database
173
174
  record.read_attribute_before_type_cast(field_name)
174
175
  else
@@ -268,14 +269,43 @@ module ActiveRecord
268
269
  def build_filter_query(sorted_relation, op, current_field, prev_fields)
269
270
  relation = sorted_relation
270
271
  prev_fields.each do |col, val|
272
+ col_key = col
271
273
  col = @aliases[col] if @aliases.has_key? col
272
274
  col = qualify_field_if_needed(col)
273
- relation = relation.where("#{col} = ?", val)
275
+ relation = relation.where("#{col} = ?", cast_cursor_value(col_key, val))
274
276
  end
275
277
  col, val = current_field
278
+ col_key = col
276
279
  col = @aliases[col] if @aliases.has_key? col
277
280
  col = qualify_field_if_needed(col)
278
- relation.where("#{col} #{op} ?", val)
281
+ relation.where("#{col} #{op} ?", cast_cursor_value(col_key, val))
282
+ end
283
+
284
+ def cast_cursor_value(col_name, val)
285
+ return val unless val.is_a?(String)
286
+
287
+ resolved_expr = @aliases[col_name.to_s]
288
+ resolved_col = (resolved_expr || col_name.to_s).split('.').last
289
+ type = @relation.klass.type_for_attribute(resolved_col)
290
+
291
+ return val unless %i[datetime time timestamp].include?(type.type)
292
+
293
+ warn_join_column_cast(col_name, resolved_expr) if resolved_expr&.match?(/\A\w+\.\w+\z/)
294
+
295
+ type.cast(val)
296
+ end
297
+
298
+ def warn_join_column_cast(alias_name, expression)
299
+ @_warned_join_casts ||= Set.new
300
+ return if @_warned_join_casts.include?(alias_name)
301
+
302
+ @_warned_join_casts << alias_name
303
+
304
+ msg = "[CursorPaginator] Cursor column '#{alias_name}' resolves to '#{expression}' " \
305
+ "(join column). Type is inferred from #{@relation.klass.name} and may be " \
306
+ 'inaccurate. Timezone-aware datetime cursors on joined tables may not work correctly.'
307
+ logger = ActiveRecord::Base.logger
308
+ logger ? logger.warn(msg) : Kernel.warn(msg)
279
309
  end
280
310
 
281
311
  # parse aliases from select values
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_record-cursor_paginator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shinichi Sugiyama
@@ -66,7 +66,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
66
66
  - !ruby/object:Gem::Version
67
67
  version: '0'
68
68
  requirements: []
69
- rubygems_version: 3.7.2
69
+ rubygems_version: 3.6.7
70
70
  specification_version: 4
71
71
  summary: cursor pagination for ActiveRecord
72
72
  test_files: []