active_windows 0.1.3 → 0.1.5

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: 40d81b47d0bf35406b6d9004f3eb82b0137b3bfc0dc5bed7e2d33b697753aeae
4
- data.tar.gz: 11897b5353a3c8b993922c7af8a4819964d417640bce9501182b145750051144
3
+ metadata.gz: 03e84e2dfa5e33f68986b9d63c7875e490ceaaab2f8e1a50a9974c42f883d1b5
4
+ data.tar.gz: e2565adc58e0a2ccc236970baa804ede27522ce6d3688131bc5a23554cde71e1
5
5
  SHA512:
6
- metadata.gz: 3b858116cd6290e77e23c5688336102efd83a234bb2caca193728e9b9458a91591fe0653420f5cc400238603921f86e472d3d92ab4028342e4ad9eb2396b4d2e
7
- data.tar.gz: 3974f6c3a73e2efbbb6aeb603c2ab4ddfd65a88eb23d10353fe94ef50746f38fc4c5c7abceec862f2eb53e8b26f710d3a7b9e274f3889132d83c48874d984e3d
6
+ metadata.gz: 375915ceb4ff9845df08d952bf6e6e48f9e46e07ae4a7857dbca78ea698b7f5025ee634254fd5d8d03c7a7810df4c5ece16406864b4feba8604d7ce98b336770
7
+ data.tar.gz: 0c4df8c117ab1f49b08bb16f3e7573d2600339ff26bc64bea6f2d42aa3ae5e419ebd4c33e8c833f8e057d919f10ebaf6f0f1713e0077603fb40d5e6cb6b5da93
data/README.md CHANGED
@@ -84,6 +84,19 @@ Available options:
84
84
  | `:frame` | `String` | Raw SQL frame clause (e.g. `"ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING"`) |
85
85
  | `:value` | `Symbol`, `String`, `Array` | Expression(s) passed as function arguments |
86
86
 
87
+ ### Association Names
88
+
89
+ You can use `belongs_to` association names instead of foreign key columns. ActiveWindows automatically resolves them:
90
+
91
+ ```ruby
92
+ # These are equivalent:
93
+ Order.row_number.partition_by(:user).window_order(:amount).as(:rn)
94
+ Order.row_number.partition_by(:user_id).window_order(:amount).as(:rn)
95
+
96
+ # Works in the hash API too:
97
+ Order.window(row_number: { partition: :user, order: :amount, as: :rn })
98
+ ```
99
+
87
100
  ### Chaining with ActiveRecord
88
101
 
89
102
  Window functions integrate naturally with standard ActiveRecord methods:
@@ -34,6 +34,8 @@ The gem provides a fluent DSL for SQL window functions in ActiveRecord. Core fun
34
34
  - ~~**PostgreSQL CI**~~ — Added. GitHub Actions workflow tests against PostgreSQL 17 with service container.
35
35
  - ~~**MySQL CI**~~ — Added. GitHub Actions workflow tests against MySQL 8.0 with service container.
36
36
  - ~~**MySQL compatibility**~~ — Fixed. Aliases now use `klass.connection.quote_column_name` to properly quote reserved words (e.g., `rank`) with backticks on MySQL and double quotes on PostgreSQL/SQLite. Test assertions use adapter-agnostic `q()` and `col()` helpers.
37
+ - ~~**WindowChain `order` naming collision**~~ — Fixed. Renamed to `window_order` to avoid conflict with ActiveRecord's `.order()`. WindowChain now delegates `.order()` to the relation for query-level ordering. Uses `method_missing` for full relation method coverage.
38
+ - ~~**Association name resolution**~~ — Added. `partition_by(:user)` automatically resolves to `user_id` via `belongs_to` reflection. Works in both fluent and hash APIs. 74 tests, 355 assertions.
37
39
 
38
40
  ---
39
41
 
@@ -44,11 +44,24 @@ module ActiveWindows
44
44
  @relation.window(to_window_hash)
45
45
  end
46
46
 
47
- # Delegate common relation/query methods so the chain is transparent
48
- delegate :to_sql, :to_a, :to_ary, :load, :loaded?, :each, :map, :first, :last, :count,
49
- :where, :select, :joins, :group, :having, :order, :limit, :offset, :reorder, :pluck,
50
- :find_each, :find_in_batches, :inspect, :exists?, :any?, :none?, :empty?,
51
- to: :to_relation
47
+ # Delegate to the materialized relation so the chain is transparent.
48
+ # Explicit delegates for Ruby protocol methods that must be defined eagerly.
49
+ delegate :to_sql, :to_a, :to_ary, :inspect, to: :to_relation
50
+
51
+ private
52
+
53
+ def method_missing(method, ...)
54
+ relation = to_relation
55
+ if relation.respond_to?(method)
56
+ relation.public_send(method, ...)
57
+ else
58
+ super
59
+ end
60
+ end
61
+
62
+ def respond_to_missing?(method, include_private = false)
63
+ to_relation.respond_to?(method, include_private) || super
64
+ end
52
65
  end
53
66
 
54
67
  module QueryMethods
@@ -204,10 +217,20 @@ module ActiveWindows
204
217
  if name.is_a?(Arel::Nodes::Node) || name.is_a?(Arel::Nodes::SqlLiteral)
205
218
  name
206
219
  else
207
- klass.arel_table[name.to_sym]
220
+ klass.arel_table[resolve_column_name(name)]
208
221
  end
209
222
  end
210
223
 
224
+ def resolve_column_name(name)
225
+ name_sym = name.to_sym
226
+ return name_sym if klass.column_names.include?(name.to_s)
227
+
228
+ reflection = klass.reflect_on_association(name_sym)
229
+ return reflection.foreign_key.to_sym if reflection&.macro == :belongs_to
230
+
231
+ name_sym
232
+ end
233
+
211
234
  def arel_order(expr)
212
235
  case expr
213
236
  when Arel::Nodes::Node, Arel::Nodes::SqlLiteral
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveWindows
4
- VERSION = "0.1.3"
4
+ VERSION = "0.1.5"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_windows
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrei Andriichuk