miscellany 0.1.21 → 0.1.24

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: 7ec30930b46e2c70b23b56abcf878afe159e0f18ffb3233c7ab1e87de6483573
4
- data.tar.gz: b4eea0d8cb2ea1dfc0b3d52351f63fd54dcb9581ed877967ea78beb5cbc96a2f
3
+ metadata.gz: 6de3e8ac55956c58bff00af5ffae6ce8972b142be6a5aad47096c4776658ba4e
4
+ data.tar.gz: 4668195d6a891348e495fff7ecf187415eef6f2588d14e33be556f04f7358042
5
5
  SHA512:
6
- metadata.gz: 53a2d235b7ea3e209b0249eab4964eb3f2426e2de48c7ac6594a06fb077bae34f7df160ff9f7b8bd797fc2a1d47a2cf8f63cf223f45ef71e4899884fd43dd0c6
7
- data.tar.gz: ee1e2a42ce1376ecd3a182e0aa228b248e154b554fcd9fdf6126a4c42855db20e83063b6a71ecd291c7a3fedfc6aa409b001a5d998e78ec8357c0e50d24f6941
6
+ metadata.gz: 2cec7d17686d2d9faf88dcfc20ac2ca5fba8f10ca7c1e021a7e0b67af4f6506b8d0a03444437ac1aae23eaa39e3a116cbb9e9ef62b649ec73faaf3b45e155772
7
+ data.tar.gz: 7a0c8b98668ad66aebd4b51e3d41aa969a13e3138992021f36bf95f04be3e1db289f95fb43e95f04e8b8876c2f5e4652a9e1609b1dfbd907595f21f7d9513d4d
@@ -203,12 +203,12 @@ module Miscellany
203
203
 
204
204
  base_module ||= mod
205
205
 
206
- if mod.name.ends_with? "Patch"
206
+ if mod.name.end_with? "Patch"
207
207
  base_full_name = base_module.to_s
208
208
  mod_full_name = mod.to_s
209
209
  mod_rel_name = mod_full_name.sub(base_full_name, '')
210
210
  mod_rel_bits = mod_rel_name.split('::').select(&:present?).map do |bit|
211
- bit.ends_with?('Patch') ? bit[0..-6] : bit
211
+ bit.end_with?('Patch') ? bit[0..-6] : bit
212
212
  end
213
213
  final_mod_name = [install_base, *mod_rel_bits].select(&:present?).join("::")
214
214
  install_mod = final_mod_name.constantize
@@ -130,14 +130,40 @@ module Miscellany
130
130
  filters.flatten.select(&:present?).map { |q| "(#{q})" }.join(' AND ').presence || '1=1'
131
131
  end
132
132
 
133
- def date_filter(column, key)
134
- if filters["#{key}_end"].present? && filters["#{key}_start"].present?
135
- "#{column} BETWEEN '#{DateTime.parse(filters["#{key}_start"]).beginning_of_day}' AND '#{DateTime.parse(filters["#{key}_end"]).end_of_day}'"
136
- elsif filters["#{key}_start"].present?
137
- "#{column} >= '#{DateTime.parse(filters["#{key}_start"]).beginning_of_day}'"
138
- elsif filters["#{key}_end"].present?
139
- "#{column} <= '#{DateTime.parse(filters["#{key}_end"]).end_of_day}'"
133
+ def date_filter(column, range, timezone: nil)
134
+ range = _parse_datetime_range(range)
135
+
136
+ range = range.map{|dt| dt&.in_time_zone(timezone) } if timezone.present?
137
+ range[0] = range[0]&.beginning_of_day
138
+ range[1] = range[1]&.end_of_day
139
+
140
+ datetime_filter(column, range)
141
+ end
142
+
143
+ def datetime_filter(column, range)
144
+ range = _parse_datetime_range(range)
145
+
146
+ start_date = range[0]
147
+ end_date = range[1]
148
+
149
+ if end_date.present? && start_date.present?
150
+ "#{column} BETWEEN '#{start_date}' AND '#{end_date}'"
151
+ elsif start_date.present?
152
+ "#{column} >= '#{start_date}'"
153
+ elsif end_date.present?
154
+ "#{column} <= '#{end_date}'"
140
155
  end
141
156
  end
157
+
158
+ def _parse_datetime_range(range)
159
+ range = [filters["#{key}_start"], filters["#{key}_end"]] if range.is_a?(String) || range.is_a?(Symbol)
160
+ range = range.map{|v| _parse_datetime(v)}
161
+ range
162
+ end
163
+
164
+ def _parse_datetime(value)
165
+ return DateTime.parse(value) if value.is_a?(String)
166
+ value
167
+ end
142
168
  end
143
169
  end
@@ -202,6 +202,18 @@ module Miscellany
202
202
  limit -= offset unless limit.nil?
203
203
 
204
204
  query = items
205
+
206
+ applied_sorts.each do |sort|
207
+ # TODO Throw an error if joins: is present on a non-AR::Relation?
208
+ if sort[:joins].is_a?(ActiveRecord::Relation)
209
+ query = query.merge(sort[:joins])
210
+ elsif sort[:joins].is_a?(Proc)
211
+ query = sort[:joins].call(query)
212
+ elsif sort[:joins].present?
213
+ query = query.joins(sort[:joins])
214
+ end
215
+ end
216
+
205
217
  sort_clause = sort_sql
206
218
  query = query.order(Arel.sql(sort_clause)) if sort_clause.present?
207
219
 
@@ -219,13 +231,19 @@ module Miscellany
219
231
  [slice_start, slice_end == -1 ? nil : slice_end]
220
232
  end
221
233
 
222
- def sort_sql
223
- sorts = [ *Array(self.sort), *options[:sort_parser]&.default_sorts]
224
- sorts.compact!
234
+ def applied_sorts
235
+ @applied_sorts ||= begin
236
+ sorts = [ *Array(self.sort), *options[:sort_parser]&.default_sorts]
237
+ sorts.compact!
238
+ sorts = Miscellany::SortLang.distinct_sorts(sorts)
239
+ sorts
240
+ end
241
+ end
225
242
 
226
- return nil unless sorts.present?
243
+ def sort_sql
244
+ return nil unless applied_sorts.present?
227
245
 
228
- Miscellany::SortLang.sqlize(sorts)
246
+ Miscellany::SortLang.sqlize(applied_sorts)
229
247
  end
230
248
  end
231
249
  end
@@ -22,11 +22,11 @@ module Miscellany
22
22
  sort.compact
23
23
  end
24
24
 
25
- def self.sqlize(sorts)
25
+ def self.distinct_sorts(sorts)
26
26
  seen_sorts = Set.new
27
27
 
28
28
  # Only include each sort key/"column" once
29
- sorts = sorts.select do |sort|
29
+ sorts.select do |sort|
30
30
  sid = sort[:key] || sort[:column]
31
31
  next true unless sid.present?
32
32
 
@@ -37,7 +37,9 @@ module Miscellany
37
37
  true
38
38
  end
39
39
  end
40
+ end
40
41
 
42
+ def self.sqlize(sorts)
41
43
  sorts.map do |sort|
42
44
  order = sort[:order] || 'ASC'
43
45
  if sort[:column].is_a?(Proc)
@@ -1,3 +1,3 @@
1
1
  module Miscellany
2
- VERSION = "0.1.21".freeze
2
+ VERSION = "0.1.24".freeze
3
3
  end
@@ -30,14 +30,17 @@ describe Miscellany::SortLang do
30
30
  end
31
31
  end
32
32
 
33
- describe ".sqlize" do
33
+ describe ".distinct_sorts" do
34
34
  it "only includes each sort key once" do
35
- expect(Miscellany::SortLang.sqlize([
35
+ distinct = Miscellany::SortLang.distinct_sorts([
36
36
  { column: "created_at", order: "ASC" },
37
37
  { column: "created_at", order: "DESC" },
38
- ])).to eql "created_at ASC NULLS FIRST"
38
+ ])
39
+ expect(Miscellany::SortLang.sqlize(distinct)).to eql "created_at ASC NULLS FIRST"
39
40
  end
41
+ end
40
42
 
43
+ describe ".sqlize" do
41
44
  describe "nulls: option" do
42
45
  it "accepts a nulls: option" do
43
46
  expect(Miscellany::SortLang.sqlize([
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: miscellany
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.21
4
+ version: 0.1.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ethan Knapp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-19 00:00:00.000000000 Z
11
+ date: 2024-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails