active_windows 0.1.7 → 0.1.8

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: 78306f0ad28382b0fd83cc679dcfd418fc72a5e0c0a26e1e812ab0cdf3a289e2
4
- data.tar.gz: a155a298bc07f13ead19b25764df4256996b995918b2362f518512066cccb4f8
3
+ metadata.gz: a3591dbeb9c495d128c8fa3fd9f88cdc4be7d6fabad282e48e47a9d3b9e919d7
4
+ data.tar.gz: ee011c561b8e84a1efe6b6366664616286632ff8facfaa1ff3a1df37a093c434
5
5
  SHA512:
6
- metadata.gz: 2c2bb59c2105382c024acc58192266edd835c08422bc6a13221d480f634320185395af8eb3a742ff92a53ca123ed4775d50b765da48e7d9256f1f5ba3f397044
7
- data.tar.gz: d9821806ab2b43d4ce12955f7311d0582b1312f76dd126255465c088e3a1bd9417c1d4fb870fc6a986361229e984253ffd6d67e587c001234a157a38a82ba545
6
+ metadata.gz: dc03d55bfc15cf28e76347b6a8f0f04d52a89c24c6b41feb458cff6c8c4694ed1270802710f9686eb68e90f30281f096ef8d0a0fc9c638c356f347aa894015bd
7
+ data.tar.gz: 92e13ee084266b0fe1a8baf40a5275338d95a07888cca71f44546ef2b518700208c758c2302f1fcb2ff4d32608666652f993a89bc96cbb6e8f692bfaacb46a36
data/README.md CHANGED
@@ -1,16 +1,18 @@
1
+ [![Gem Version](https://badge.fury.io/rb/active_windows.svg)](https://badge.fury.io/rb/active_windows)
2
+
1
3
  # ActiveWindows
2
4
 
3
5
  A Ruby DSL for SQL window functions in ActiveRecord. Write expressive window function queries using a fluent, chainable interface instead of raw SQL.
4
6
 
5
7
  ```ruby
6
8
  # Fluent API
7
- User.row_number.partition_by(:department).order_by(:salary).as(:rank)
9
+ User.window(:row_number).partition_by(:department).order_by(:salary).as(:rank)
8
10
 
9
11
  # Hash API
10
- User.window(row_number: { partition: :department, order_by: :salary, as: :rank })
12
+ User.window(row_number: { partition_by: :department, order_by: :salary, as: :rank })
11
13
 
12
14
  # Both produce:
13
- # SELECT "users".*, ROW_NUMBER() OVER (PARTITION BY "users"."department" ORDER BY "users"."salary") AS rank
15
+ # SELECT "users".*, ROW_NUMBER() OVER (PARTITION BY "users"."department" ORDER BY "users"."salary") AS "rank"
14
16
  # FROM "users"
15
17
  ```
16
18
 
@@ -41,34 +43,31 @@ ActiveWindows provides two equivalent APIs: a **fluent API** with chainable meth
41
43
 
42
44
  ### Fluent API
43
45
 
44
- Every window function method returns a chainable object with `.partition_by()`, `.order_by()`, and `.as()`:
46
+ `window(:function_name, *args)` returns a chainable object with `.partition_by()`, `.order_by()`, and `.as()`:
45
47
 
46
48
  ```ruby
47
- User.row_number.partition_by(:department).order_by(:salary).as(:rank)
49
+ User.window(:row_number).partition_by(:department).order_by(:salary).as(:rank)
50
+
51
+ # Functions with arguments:
52
+ User.window(:lag, :salary, 1, 0).order_by(:hire_date).as(:prev_salary)
53
+ User.window(:ntile, 4).order_by(:salary).as(:quartile)
48
54
  ```
49
55
 
50
56
  All three chain methods are optional. `.order_by()` sets the window's `ORDER BY`, while ActiveRecord's `.order()` controls the query-level `ORDER BY`. You can use both together:
51
57
 
52
58
  ```ruby
53
- User.row_number.order_by(:salary).as(:rn).order(:name)
59
+ User.window(:row_number).order_by(:salary).as(:rn).order(:name)
54
60
  # Window: OVER (ORDER BY salary)
55
61
  # Query: ORDER BY name
56
62
  ```
57
63
 
58
- Order can be mixed freely:
59
-
60
- ```ruby
61
- User.row_number.as(:rn).order_by(:created_at)
62
- User.dense_rank.order_by(:score).as(:position)
63
- ```
64
-
65
64
  ### Hash API
66
65
 
67
66
  Pass one or more window function definitions as a hash:
68
67
 
69
68
  ```ruby
70
69
  User.window(
71
- row_number: { partition: :department, order_by: :salary, as: :rank }
70
+ row_number: { partition_by: :department, order_by: :salary, as: :rank }
72
71
  )
73
72
  ```
74
73
 
@@ -76,7 +75,7 @@ Available options:
76
75
 
77
76
  | Option | Type | Description |
78
77
  |--------|------|-------------|
79
- | `:partition` | `Symbol`, `Array` | Column(s) for `PARTITION BY` |
78
+ | `:partition_by` | `Symbol`, `Array` | Column(s) for `PARTITION BY` |
80
79
  | `:order_by` | `Symbol`, `Array` | Column(s) for `ORDER BY` |
81
80
  | `:as` | `Symbol` | Alias for the result column |
82
81
  | `:frame` | `String` | Raw SQL frame clause (e.g. `"ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING"`) |
@@ -84,28 +83,15 @@ Available options:
84
83
 
85
84
  ### Association Names
86
85
 
87
- You can use association names instead of raw column names. ActiveWindows automatically resolves them:
88
-
89
- **`belongs_to`** — resolves to the foreign key on the current table:
86
+ You can use `belongs_to` association names instead of foreign key columns. ActiveWindows automatically resolves them:
90
87
 
91
88
  ```ruby
92
89
  # These are equivalent:
93
- Order.row_number.partition_by(:user).order_by(:amount).as(:rn)
94
- Order.row_number.partition_by(:user_id).order_by(:amount).as(:rn)
90
+ Order.window(:row_number).partition_by(:user).order_by(:amount).as(:rn)
91
+ Order.window(:row_number).partition_by(:user_id).order_by(:amount).as(:rn)
95
92
 
96
93
  # Works in the hash API too:
97
- Order.window(row_number: { partition: :user, order_by: :amount, as: :rn })
98
- ```
99
-
100
- **`has_one`** — auto-joins the associated table and references its primary key:
101
-
102
- ```ruby
103
- # User has_one :profile
104
- # Automatically joins profiles and partitions by profiles.id
105
- User.row_number.partition_by(:profile).order_by(:salary).as(:rn)
106
-
107
- # Equivalent to:
108
- User.joins(:profile).row_number.partition_by("profiles.id").order_by(:salary).as(:rn)
94
+ Order.window(row_number: { partition_by: :user, order_by: :amount, as: :rn })
109
95
  ```
110
96
 
111
97
  ### Chaining with ActiveRecord
@@ -114,7 +100,7 @@ Window functions integrate naturally with standard ActiveRecord methods:
114
100
 
115
101
  ```ruby
116
102
  User.where(active: true)
117
- .row_number
103
+ .window(:row_number)
118
104
  .partition_by(:department)
119
105
  .order_by(:salary)
120
106
  .as(:rank)
@@ -134,7 +120,7 @@ When no `.select()` is specified, `*` is automatically included so all model col
134
120
  Window function values are accessible as attributes on the returned records:
135
121
 
136
122
  ```ruby
137
- results = User.row_number.partition_by(:department).order_by(:salary).as(:rank)
123
+ results = User.window(:row_number).partition_by(:department).order_by(:salary).as(:rank)
138
124
 
139
125
  results.each do |user|
140
126
  puts "#{user.name}: rank #{user.attributes['rank']}"
@@ -147,66 +133,64 @@ end
147
133
 
148
134
  ```ruby
149
135
  # ROW_NUMBER() - sequential integer within partition
150
- User.row_number.partition_by(:department).order_by(:salary).as(:rn)
136
+ User.window(:row_number).partition_by(:department).order_by(:salary).as(:rn)
151
137
 
152
138
  # RANK() - rank with gaps for ties
153
- User.rank.partition_by(:department).order_by(:salary).as(:salary_rank)
139
+ User.window(:rank).partition_by(:department).order_by(:salary).as(:salary_rank)
154
140
 
155
141
  # DENSE_RANK() - rank without gaps for ties
156
- User.dense_rank.partition_by(:department).order_by(:salary).as(:dense_salary_rank)
142
+ User.window(:dense_rank).partition_by(:department).order_by(:salary).as(:dense_salary_rank)
157
143
 
158
144
  # PERCENT_RANK() - relative rank as a fraction (0 to 1)
159
- User.percent_rank.order_by(:salary).as(:percentile)
145
+ User.window(:percent_rank).order_by(:salary).as(:percentile)
160
146
 
161
147
  # CUME_DIST() - cumulative distribution (fraction of rows <= current row)
162
- User.cume_dist.order_by(:salary).as(:cumulative)
148
+ User.window(:cume_dist).order_by(:salary).as(:cumulative)
163
149
 
164
150
  # NTILE(n) - divide rows into n roughly equal buckets
165
- User.ntile(4).order_by(:salary).as(:quartile)
151
+ User.window(:ntile, 4).order_by(:salary).as(:quartile)
166
152
  ```
167
153
 
168
154
  ### Value Functions
169
155
 
170
156
  ```ruby
171
157
  # LAG(column, offset, default) - value from a preceding row
172
- User.lag(:salary).order_by(:hire_date).as(:prev_salary)
173
- User.lag(:salary, 2).order_by(:hire_date).as(:two_back) # custom offset
174
- User.lag(:salary, 1, 0).order_by(:hire_date).as(:prev_or_zero) # with default
158
+ User.window(:lag, :salary).order_by(:hire_date).as(:prev_salary)
159
+ User.window(:lag, :salary, 2).order_by(:hire_date).as(:two_back) # custom offset
160
+ User.window(:lag, :salary, 1, 0).order_by(:hire_date).as(:prev_or_zero) # with default
175
161
 
176
162
  # LEAD(column, offset, default) - value from a following row
177
- User.lead(:salary).order_by(:hire_date).as(:next_salary)
178
- User.lead(:salary, 2, 0).order_by(:hire_date).as(:two_ahead)
163
+ User.window(:lead, :salary).order_by(:hire_date).as(:next_salary)
164
+ User.window(:lead, :salary, 2, 0).order_by(:hire_date).as(:two_ahead)
179
165
 
180
166
  # FIRST_VALUE(column) - first value in the window frame
181
- User.first_value(:name).partition_by(:department).order_by(:salary).as(:lowest_paid)
167
+ User.window(:first_value, :name).partition_by(:department).order_by(:salary).as(:lowest_paid)
182
168
 
183
169
  # LAST_VALUE(column) - last value in the window frame
184
- User.last_value(:name).partition_by(:department).order_by(:salary).as(:highest_paid)
170
+ User.window(:last_value, :name).partition_by(:department).order_by(:salary).as(:highest_paid)
185
171
 
186
172
  # NTH_VALUE(column, n) - nth value in the window frame
187
- User.nth_value(:name, 2).partition_by(:department).order_by(:salary).as(:second_lowest)
173
+ User.window(:nth_value, :name, 2).partition_by(:department).order_by(:salary).as(:second_lowest)
188
174
  ```
189
175
 
190
176
  ### Aggregate Window Functions
191
177
 
192
- Prefixed with `window_` to avoid conflicts with ActiveRecord's built-in aggregate methods:
193
-
194
178
  ```ruby
195
179
  # SUM(column) OVER(...)
196
- User.window_sum(:salary).partition_by(:department).as(:dept_total)
180
+ User.window(:sum, :salary).partition_by(:department).as(:dept_total)
197
181
 
198
182
  # AVG(column) OVER(...)
199
- User.window_avg(:salary).partition_by(:department).as(:dept_avg)
183
+ User.window(:avg, :salary).partition_by(:department).as(:dept_avg)
200
184
 
201
185
  # COUNT(column) OVER(...)
202
- User.window_count(:id).partition_by(:department).as(:dept_size)
203
- User.window_count.partition_by(:department).as(:dept_size) # COUNT(*)
186
+ User.window(:count, :id).partition_by(:department).as(:dept_size)
187
+ User.window(:count, "*").partition_by(:department).as(:dept_size) # COUNT(*)
204
188
 
205
189
  # MIN(column) OVER(...)
206
- User.window_min(:salary).partition_by(:department).as(:min_salary)
190
+ User.window(:min, :salary).partition_by(:department).as(:min_salary)
207
191
 
208
192
  # MAX(column) OVER(...)
209
- User.window_max(:salary).partition_by(:department).as(:max_salary)
193
+ User.window(:max, :salary).partition_by(:department).as(:max_salary)
210
194
  ```
211
195
 
212
196
  ### Window Frames
@@ -216,7 +200,7 @@ Pass a raw SQL frame clause via the hash API:
216
200
  ```ruby
217
201
  User.window(sum: {
218
202
  value: :salary,
219
- partition: :department,
203
+ partition_by: :department,
220
204
  order_by: :hire_date,
221
205
  frame: "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW",
222
206
  as: :running_total
@@ -228,7 +212,7 @@ User.window(sum: {
228
212
  ### Rank employees by salary within each department
229
213
 
230
214
  ```ruby
231
- User.rank
215
+ User.window(:rank)
232
216
  .partition_by(:department)
233
217
  .order_by(:salary)
234
218
  .as(:salary_rank)
@@ -248,7 +232,7 @@ User.window(sum: {
248
232
  ### Compare each salary to the department average
249
233
 
250
234
  ```ruby
251
- users = User.window_avg(:salary).partition_by(:department).as(:dept_avg)
235
+ users = User.window(:avg, :salary).partition_by(:department).as(:dept_avg)
252
236
 
253
237
  users.each do |user|
254
238
  diff = user.salary - user.attributes["dept_avg"].to_f
@@ -259,7 +243,7 @@ end
259
243
  ### Find the previous and next hire in each department
260
244
 
261
245
  ```ruby
262
- User.lag(:name)
246
+ User.window(:lag, :name)
263
247
  .partition_by(:department)
264
248
  .order_by(:hire_date)
265
249
  .as(:previous_hire)
@@ -268,7 +252,7 @@ User.lag(:name)
268
252
  ### Divide employees into salary quartiles
269
253
 
270
254
  ```ruby
271
- User.ntile(4).order_by(:salary).as(:quartile)
255
+ User.window(:ntile, 4).order_by(:salary).as(:quartile)
272
256
  ```
273
257
 
274
258
  ### Rank users by total order amount (with joins)
@@ -285,7 +269,7 @@ User.joins(:orders)
285
269
  ```ruby
286
270
  # Rank orders by amount within each user
287
271
  Order.joins(:user)
288
- .row_number
272
+ .window(:row_number)
289
273
  .partition_by("users.id")
290
274
  .order_by(amount: :desc)
291
275
  .as(:order_rank)
@@ -293,7 +277,7 @@ Order.joins(:user)
293
277
  # Number each user's orders chronologically
294
278
  Order.joins(:user)
295
279
  .select("orders.*, users.name AS user_name")
296
- .row_number
280
+ .window(:row_number)
297
281
  .partition_by(:user_id)
298
282
  .order_by(:created_at)
299
283
  .as(:order_number)
@@ -307,7 +291,7 @@ Order.joins(:user)
307
291
  .where(users: { department: "Engineering" })
308
292
  .window(sum: {
309
293
  value: :amount,
310
- partition: :user_id,
294
+ partition_by: :user_id,
311
295
  order_by: :created_at,
312
296
  frame: "ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW",
313
297
  as: :running_total
@@ -2,7 +2,7 @@
2
2
 
3
3
  ## Overall Assessment
4
4
 
5
- The gem provides a fluent DSL for SQL window functions in ActiveRecord. Core functionality is implemented and tested, with 16 window functions available via both fluent and hash APIs. 67 tests passing with 328 assertions. CI runs against SQLite, PostgreSQL, and MySQL.
5
+ The gem provides a fluent DSL for SQL window functions in ActiveRecord. Core functionality is implemented and tested, with 16 window functions available via fluent, `window(:symbol)`, and hash APIs. 82 tests passing with 399 assertions. CI runs against SQLite, PostgreSQL, and MySQL.
6
6
 
7
7
  ---
8
8
 
@@ -26,7 +26,7 @@ The gem provides a fluent DSL for SQL window functions in ActiveRecord. Core fun
26
26
  - ~~**RuboCop dependency**~~ — Removed.
27
27
  - ~~**LICENSE**~~ — Cleaned up. Full name, no year, `.txt` extension removed.
28
28
  - ~~**Boilerplate files**~~ — Removed. `CHANGELOG.md`, `CODE_OF_CONDUCT.md`, `bin/console`, `bin/setup`, `sig/active_windows.rbs`.
29
- - ~~**Ordering direction**~~ — Fixed. Supports `order(salary: :desc)`, `order({ col: :asc }, { col: :desc })`, and hash API `order: { salary: :desc }`.
29
+ - ~~**Ordering direction**~~ — Fixed. Supports `order_by(salary: :desc)`, `order_by({ col: :asc }, { col: :desc })`, and hash API `order_by: { salary: :desc }`.
30
30
  - ~~**Gemfile/gemspec duplication**~~ — Fixed. Dev gems (`minitest`, `rake`) defined only in Gemfile under `test, development` group. No more bundler override warnings.
31
31
  - ~~**Cross-platform lockfile**~~ — Fixed. Added `aarch64-linux`, `arm-linux`, `arm64-darwin`, `x86_64-darwin`, `x86_64-linux` platforms.
32
32
  - ~~**Multiple window functions in one call**~~ — Tested. Single `window()` with multiple keys and chaining separate `window()` calls both work.
@@ -34,8 +34,9 @@ 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
+ - ~~**WindowChain `order` naming collision**~~ — Fixed. Renamed to `order_by` to avoid conflict with ActiveRecord's `.order()`. Both fluent (`.order_by(:salary)`) and hash (`order_by: :salary`) APIs use `order_by`. WindowChain delegates `.order()` to the relation for query-level ordering. Uses `method_missing` for full relation method coverage.
38
+ - ~~**Association name resolution**~~ — Added. `belongs_to`: `partition_by(:user)` resolves to `user_id`. Works in both fluent and hash APIs.
39
+ - ~~**Unified `window()` entry point**~~ — Added. `window(:row_number)` returns a WindowChain (fluent), `window(:lag, :salary, 1, 0)` passes function args, `window(row_number: { ... })` is hash API. Single method, three modes. 82 tests, 399 assertions.
39
40
 
40
41
  ---
41
42
 
@@ -32,7 +32,7 @@ module ActiveWindows
32
32
 
33
33
  def to_window_hash
34
34
  options = {}
35
- options[:partition] = @partition_columns unless @partition_columns.empty?
35
+ options[:partition_by] = @partition_columns unless @partition_columns.empty?
36
36
  options[:order_by] = @order_columns unless @order_columns.empty?
37
37
  options[:as] = @alias_name if @alias_name
38
38
  options[:value] = @function_args unless @function_args.empty?
@@ -65,23 +65,24 @@ module ActiveWindows
65
65
  end
66
66
 
67
67
  module QueryMethods
68
- VALID_WINDOW_OPTIONS = %i[value partition order_by frame as].freeze
68
+ VALID_WINDOW_OPTIONS = %i[value partition_by order_by frame as].freeze
69
69
 
70
- # Non-mutating: returns a new relation with window function projections
70
+ # Fluent: window(:row_number) returns a WindowChain
71
+ # Fluent with args: window(:lag, :salary, 1, 0) returns a WindowChain
72
+ # Hash: window(row_number: { partition: :department, order_by: :salary, as: :rank })
71
73
  def window(*args)
72
74
  raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" if args.empty?
73
75
 
76
+ # Fluent API: window(:function_name, *function_args)
77
+ if args.first.is_a?(Symbol) && (args.length == 1 || !args[1].is_a?(Hash))
78
+ function_name = args.shift
79
+ return WindowChain.new(function_name, spawn, function_args: args.map(&:to_s))
80
+ end
81
+
82
+ # Hash API
74
83
  processed = process_window_args(args)
75
84
 
76
85
  result = spawn
77
-
78
- # Auto-join has_one associations referenced in partition/order
79
- joins_needed = processed.flat_map do |_name, options|
80
- next [] unless options.is_a?(Hash)
81
- association_joins_for(options[:partition]) + association_joins_for(options[:order_by])
82
- end.uniq
83
- result = result.joins(*joins_needed) if joins_needed.any?
84
-
85
86
  arel_nodes = processed.map { |name, options| build_window_function(name, options || {}) }
86
87
 
87
88
  # Ensure we keep all columns alongside the window function columns
@@ -89,83 +90,12 @@ module ActiveWindows
89
90
  result.select(*arel_nodes)
90
91
  end
91
92
 
92
- # Ranking window functions
93
- def row_number
94
- WindowChain.new(:row_number, spawn)
95
- end
96
-
97
- def rank
98
- WindowChain.new(:rank, spawn)
99
- end
100
-
101
- def dense_rank
102
- WindowChain.new(:dense_rank, spawn)
103
- end
104
-
105
- def percent_rank
106
- WindowChain.new(:percent_rank, spawn)
107
- end
108
-
109
- def cume_dist
110
- WindowChain.new(:cume_dist, spawn)
111
- end
112
-
113
- def ntile(num_buckets)
114
- WindowChain.new(:ntile, spawn, function_args: [num_buckets.to_s])
115
- end
116
-
117
- # Value window functions
118
- def lag(column, offset = 1, default = nil)
119
- args = [column.to_s, offset.to_s]
120
- args << default.to_s unless default.nil?
121
- WindowChain.new(:lag, spawn, function_args: args)
122
- end
123
-
124
- def lead(column, offset = 1, default = nil)
125
- args = [column.to_s, offset.to_s]
126
- args << default.to_s unless default.nil?
127
- WindowChain.new(:lead, spawn, function_args: args)
128
- end
129
-
130
- def first_value(column)
131
- WindowChain.new(:first_value, spawn, function_args: [column.to_s])
132
- end
133
-
134
- def last_value(column)
135
- WindowChain.new(:last_value, spawn, function_args: [column.to_s])
136
- end
137
-
138
- def nth_value(column, n)
139
- WindowChain.new(:nth_value, spawn, function_args: [column.to_s, n.to_s])
140
- end
141
-
142
- # Aggregate window functions
143
- def window_sum(column)
144
- WindowChain.new(:sum, spawn, function_args: [column.to_s])
145
- end
146
-
147
- def window_avg(column)
148
- WindowChain.new(:avg, spawn, function_args: [column.to_s])
149
- end
150
-
151
- def window_count(column = "*")
152
- WindowChain.new(:count, spawn, function_args: [column.to_s])
153
- end
154
-
155
- def window_min(column)
156
- WindowChain.new(:min, spawn, function_args: [column.to_s])
157
- end
158
-
159
- def window_max(column)
160
- WindowChain.new(:max, spawn, function_args: [column.to_s])
161
- end
162
-
163
93
  private
164
94
 
165
95
  def build_window_function(name, options)
166
96
  window = Arel::Nodes::Window.new
167
97
 
168
- apply_window_partition(window, options[:partition])
98
+ apply_window_partition(window, options[:partition_by])
169
99
  apply_window_order(window, options[:order_by])
170
100
  apply_window_frame(window, options[:frame]) if options[:frame]
171
101
 
@@ -237,22 +167,11 @@ module ActiveWindows
237
167
  reflection = klass.reflect_on_association(name_sym)
238
168
  if reflection&.macro == :belongs_to
239
169
  klass.arel_table[reflection.foreign_key.to_sym]
240
- elsif reflection&.macro == :has_one
241
- reflection.klass.arel_table[reflection.klass.primary_key.to_sym]
242
170
  else
243
171
  klass.arel_table[name_sym]
244
172
  end
245
173
  end
246
174
 
247
- def association_joins_for(columns)
248
- Array(columns).filter_map do |col|
249
- next unless col.is_a?(Symbol) || col.is_a?(String)
250
-
251
- reflection = klass.reflect_on_association(col.to_sym)
252
- col.to_sym if reflection&.macro == :has_one
253
- end
254
- end
255
-
256
175
  def arel_order(expr)
257
176
  case expr
258
177
  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.7"
4
+ VERSION = "0.1.8"
5
5
  end
@@ -7,9 +7,5 @@ require "active_windows/railtie" if defined?(Rails::Railtie)
7
7
  module ActiveWindows
8
8
  class Error < StandardError; end
9
9
 
10
- QUERY_METHODS = %i[
11
- window row_number rank dense_rank percent_rank cume_dist ntile
12
- lag lead first_value last_value nth_value
13
- window_sum window_avg window_count window_min window_max
14
- ].freeze
10
+ QUERY_METHODS = %i[window].freeze
15
11
  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.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrei Andriichuk