miscellany 0.1.17 → 0.1.19

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d8272b6520386bb2e45ef6a4ae8cc6c2c349e465ca8eea10867df3c42c80c7c3
4
- data.tar.gz: aeb81bc5bb198c2f64589c1d416369bd101de5d1db074682e40f66247c2035d5
3
+ metadata.gz: e919c60e03780d5fab1a21ae6d528482db21d5a4fcfbc176b4808cc1d9acdc77
4
+ data.tar.gz: c9ecbbbb69e28e8fbef7aa9efe93db1cab9576634ede5ad2dc698180c1743dda
5
5
  SHA512:
6
- metadata.gz: 3f6ac9e74cacbdb4dd5d990a47c72608181eb005b4a9c3de81b46666bf314a246fa799c29d97753519822318740adf32fa2db63450d2d70e2abc4fb4a38c09de
7
- data.tar.gz: 99f033c54af54257ef660e889f34f683e080fe4e16baeb9d1f201fcf0091561c6d2fd5d26b582a57b9ab91b2d7c0fd3c8e72f8fc8e02f7425b0a395b4bcc7e9f
6
+ metadata.gz: 7468e0d150c79e5ebfb5760648e97699c7b88340c68b7eaa530c58e512ee982eb1d2b44c2599b374a7348a5b9cefe7d7037603a98aa5a8a895f18bac6d4efe84
7
+ data.tar.gz: 0a7dfb9250e3f686d88f7c2932cbd1a8b07f0a38ae4d3e491e98ee4c14a22126bcf3defd58227130fe3a43f8cd7d0b5dbaf002f6ded24fd187706b445fcce28e
@@ -7,8 +7,8 @@ module Miscellany
7
7
  include HttpErrorHandling
8
8
 
9
9
  # Deprecated
10
- def slice_results(queryset, **kwargs)
11
- @sliced_data = sliced_json(queryset, **kwargs) { |x| x }
10
+ def slice_results(*args, **kwargs, &blk)
11
+ @sliced_data = sliced_json(*args, **kwargs, &blk)
12
12
  end
13
13
 
14
14
  def sliced_json(
@@ -219,7 +219,7 @@ module Miscellany
219
219
 
220
220
  def sort_sql
221
221
  sorts = [ *Array(self.sort) ]
222
- sorts << options[:sort_parser]&.default
222
+ sorts.push(*options[:sort_parser]&.default_sorts)
223
223
  sorts.compact!
224
224
 
225
225
  return nil unless sorts.present?
@@ -23,10 +23,25 @@ module Miscellany
23
23
  end
24
24
 
25
25
  def self.sqlize(sorts)
26
+ seen_sorts = Set.new
27
+
28
+ # Only include each sort key/"column" once
29
+ sorts = sorts.select do |sort|
30
+ sid = sort[:key] || sort[:column]
31
+ next true unless sid.present?
32
+
33
+ if seen_sorts.include?(sid)
34
+ false
35
+ else
36
+ seen_sorts << sid
37
+ true
38
+ end
39
+ end
40
+
26
41
  sorts.map do |sort|
27
42
  order = sort[:order] || 'ASC'
28
43
  if sort[:column].is_a?(Proc)
29
- sort[:column].call(qset, order)
44
+ sort[:column].call(order)
30
45
  else
31
46
  desired_nulls = (sort[:nulls] || :low).to_s.downcase.to_sym
32
47
  nulls = case desired_nulls
@@ -45,12 +60,20 @@ module Miscellany
45
60
  class Parser
46
61
  class SortParsingError < StandardError; end
47
62
 
63
+ attr_reader :default_sorts
64
+
48
65
  def initialize(valid_sorts, default: nil)
49
- @sorts_map = normalize_sort_options(valid_sorts, default: default)
50
- end
66
+ @sorts_map = normalize_sort_options(valid_sorts)
67
+
68
+ @default_sorts = []
51
69
 
52
- def default
53
- @sorts_map[:default]
70
+ parsed_defaults = normalize_sort_options(Array(default))
71
+ parsed_defaults.each do |k,v|
72
+ @sorts_map[k] ||= v
73
+ end
74
+ @default_sorts = parsed_defaults.keys.map do |k|
75
+ @sorts_map[k]
76
+ end
54
77
  end
55
78
 
56
79
  def valid?(sortstr)
@@ -80,39 +103,31 @@ module Miscellany
80
103
  sort
81
104
  end
82
105
 
83
- sorts << self.default if default == :append || default && !sorts.compact.present?
106
+ if default == :append || default && !sorts.compact.present?
107
+ sorts.push(*self.default_sorts)
108
+ end
84
109
 
85
110
  sorts.compact.presence
86
111
  end
87
112
 
88
113
  protected
89
114
 
90
- def normalize_sort_options(sorts, default: nil)
115
+ def normalize_sort_options(sorts)
91
116
  norm_sorts = { }
92
117
 
93
118
  sorts.each do |s|
94
119
  if s.is_a?(Hash)
95
120
  s.each do |k,v|
121
+ k = k.to_s
96
122
  sort_hash = normalize_sort(v, key: k)
97
123
  norm_sorts[k] = sort_hash
98
124
  end
99
125
  else
100
126
  sort_hash = normalize_sort(s)
101
127
  norm_sorts[sort_hash[:column]] = sort_hash
102
- # default ||= sort_hash
103
128
  end
104
129
  end
105
130
 
106
- if default.present?
107
- norm_default = normalize_sort(default)
108
- reference = norm_sorts[norm_default[:key].to_s] || norm_default
109
- norm_sorts[:default] = {
110
- key: reference[:key],
111
- column: reference[:column],
112
- order: norm_default[:order] || reference[:order],
113
- }
114
- end
115
-
116
131
  norm_sorts
117
132
  end
118
133
 
@@ -1,3 +1,3 @@
1
1
  module Miscellany
2
- VERSION = "0.1.17".freeze
2
+ VERSION = "0.1.19".freeze
3
3
  end
@@ -129,6 +129,19 @@ describe Miscellany::SlicedResponse do
129
129
 
130
130
  expect(subject.sliced_json(ARModel.all, { page: "all" }, allow_all: true, **slice_config)).to be_a Hash
131
131
  end
132
+
133
+ context "with Hash-based valid_sorts" do
134
+ let(:source) { ARModel.all }
135
+
136
+ before(:each) do
137
+ slice_config[:valid_sorts] = [
138
+ title: ->(dir) { "title #{dir}" }
139
+ ]
140
+ end
141
+
142
+ include_examples "basic functionality"
143
+ include_examples "sortable"
144
+ end
132
145
  end
133
146
 
134
147
  describe "#bearcat_as_sliced_json" do
@@ -0,0 +1,124 @@
1
+
2
+ require 'spec_helper'
3
+
4
+ describe Miscellany::SortLang do
5
+
6
+ describe ".normalize_sort" do
7
+ it "accepts Hash KV pairs" do
8
+ expect(Miscellany::SortLang.normalize_sort(["key", { column: "created_at", order: "ASC" }])).to eql({
9
+ column: "created_at", force_order: false, key: "created_at", order: "ASC"
10
+ })
11
+ end
12
+
13
+ it "accepts strings" do
14
+ expect(Miscellany::SortLang.normalize_sort("created_at")).to eql({
15
+ column: "created_at", force_order: false, key: "created_at"
16
+ })
17
+ expect(Miscellany::SortLang.normalize_sort("created_at ASC")).to eql({
18
+ column: "created_at", force_order: false, key: "created_at", order: "ASC"
19
+ })
20
+ expect(Miscellany::SortLang.normalize_sort("created_at ASC!")).to eql({
21
+ column: "created_at", force_order: true, key: "created_at", order: "ASC"
22
+ })
23
+ end
24
+
25
+ it "accepts Procs" do
26
+ logic = ->(x) { "created_at #{x}" }
27
+ expect(Miscellany::SortLang.normalize_sort(logic, key: "k")).to eql({
28
+ column: logic, key: "k"
29
+ })
30
+ end
31
+ end
32
+
33
+ describe ".sqlize" do
34
+ it "only includes each sort key once" do
35
+ expect(Miscellany::SortLang.sqlize([
36
+ { column: "created_at", order: "ASC" },
37
+ { column: "created_at", order: "DESC" },
38
+ ])).to eql "created_at ASC NULLS FIRST"
39
+ end
40
+
41
+ describe "nulls: option" do
42
+ it "accepts a nulls: option" do
43
+ expect(Miscellany::SortLang.sqlize([
44
+ { column: "created_at", order: "ASC", nulls: :last },
45
+ ])).to eql "created_at ASC NULLS LAST"
46
+ end
47
+
48
+ it "nulls: :high works" do
49
+ expect(Miscellany::SortLang.sqlize([
50
+ { column: "created_at", order: "ASC", nulls: :high },
51
+ ])).to eql "created_at ASC NULLS LAST"
52
+ expect(Miscellany::SortLang.sqlize([
53
+ { column: "created_at", order: "DESC", nulls: :high },
54
+ ])).to eql "created_at DESC NULLS FIRST"
55
+ end
56
+
57
+ it "nulls: :low works" do
58
+ expect(Miscellany::SortLang.sqlize([
59
+ { column: "created_at", order: "ASC", nulls: :low },
60
+ ])).to eql "created_at ASC NULLS FIRST"
61
+ expect(Miscellany::SortLang.sqlize([
62
+ { column: "created_at", order: "DESC", nulls: :low },
63
+ ])).to eql "created_at DESC NULLS LAST"
64
+ end
65
+ end
66
+ end
67
+
68
+ describe Miscellany::SortLang::Parser do
69
+ let(:valid_sorts) {[
70
+ "title", "created_at"
71
+ ]}
72
+ let(:default_sort) { "title" }
73
+
74
+ let(:subject) { Miscellany::SortLang::Parser.new(valid_sorts, default: default_sort) }
75
+
76
+ context "with multiple default sorts" do
77
+ let(:default_sort) { ["title", "created_at"] }
78
+
79
+ it "includes each" do
80
+ expect(subject.parse(nil)).to eql [
81
+ {:column=>"title", :force_order=>false, :key=>"title"},
82
+ {:column=>"created_at", :force_order=>false, :key=>"created_at"},
83
+ ]
84
+ end
85
+ end
86
+
87
+ describe "#parse" do
88
+ it "excludes uknown sorts" do
89
+ expect(subject.parse("updated_at")).to eql [
90
+ {:column=>"title", :force_order=>false, :key=>"title"},
91
+ ]
92
+ end
93
+
94
+ it "considers force_order" do
95
+ subject = Miscellany::SortLang::Parser.new([ "title ASC!" ])
96
+ expect(subject.parse("title DESC")).to eql [
97
+ {:column=>"title", :force_order=>true, :key=>"title", :order=>"ASC"},
98
+ ]
99
+ end
100
+
101
+ it "returns the default sort if no sort is given" do
102
+ expect(subject.parse("")).to eql [
103
+ {:column=>"title", :force_order=>false, :key=>"title"},
104
+ ]
105
+ expect(subject.parse("", default: true)).to eql [
106
+ {:column=>"title", :force_order=>false, :key=>"title"},
107
+ ]
108
+ end
109
+
110
+ it "appends the default sort" do
111
+ expect(subject.parse("created_at", default: :append)).to eql [
112
+ {:column=>"created_at", :force_order=>false, :key=>"created_at"},
113
+ {:column=>"title", :force_order=>false, :key=>"title"},
114
+ ]
115
+ end
116
+
117
+ it "excludes the default sort" do
118
+ expect(subject.parse("created_at", default: false)).to eql [
119
+ {:column=>"created_at", :force_order=>false, :key=>"created_at"},
120
+ ]
121
+ end
122
+ end
123
+ end
124
+ end
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.17
4
+ version: 0.1.19
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-09-29 00:00:00.000000000 Z
11
+ date: 2023-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -149,6 +149,7 @@ files:
149
149
  - spec/miscellany/goldiload_value_spec.rb
150
150
  - spec/miscellany/param_validator_spec.rb
151
151
  - spec/miscellany/sliced_response_spec.rb
152
+ - spec/miscellany/sort_lang_spec.rb
152
153
  - spec/spec_helper.rb
153
154
  homepage: https://instructure.com
154
155
  licenses: []
@@ -174,6 +175,7 @@ specification_version: 4
174
175
  summary: Gem for a bunch of random, re-usable Rails Concerns & Helpers
175
176
  test_files:
176
177
  - spec/db/database.yml
178
+ - spec/miscellany/sort_lang_spec.rb
177
179
  - spec/miscellany/arbitrary_prefetch_spec.rb
178
180
  - spec/miscellany/sliced_response_spec.rb
179
181
  - spec/miscellany/param_validator_spec.rb