hario 0.3.0 → 0.3.1

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
  SHA1:
3
- metadata.gz: 51eaa13608caa623aa57c2e1c2b275aab5419e0a
4
- data.tar.gz: 0bdab870d96a09ccdaf3357f0c45107dc366a50e
3
+ metadata.gz: 136e0b28f2d3f6bc51ba637b83c31f48fcdda3ca
4
+ data.tar.gz: a8b61b6290486260fe75361a503513b98ca689d6
5
5
  SHA512:
6
- metadata.gz: 2b0236ad432571151b232b5d2f869cc46048a60bbe058ee550347fa7940664728952c1a84f5f413bbc166aacd15eae613af47528d19645c8e451577fca862bb3
7
- data.tar.gz: 7c598b57e7310d36620783a0bcd3dd17878e79a4dbe0b65221495fd2e7f52c221f7ea7ba23e5188f560483944af7fbc06d99150fe29c3e663326d2910188f43b
6
+ metadata.gz: 2f96e37359a8f64548d93c65c2ca1421cfa99551f236dc5ae465da78bd978e1704ce81a87bf07271e9bdc5cb0ace2d854d3c99f39046bf0a75c554ff14413f6b
7
+ data.tar.gz: eb7059a076117f97f07e20681af33d67c43d12d028fe28781bb99b9b9aff371a79ebaac29ffec4195e4ce584da75680142f87a842e61203c75f5a67651a3b3ac
data/lib/hario.rb CHANGED
@@ -4,10 +4,16 @@ require "hario/behaviours/pluck"
4
4
 
5
5
  module Hario
6
6
  module Filterable
7
- def search(filters, pluck = nil)
7
+ HARIO_APPLY_TYPES = %w( filters pluck ).map(&:to_sym)
8
+
9
+ attr_reader :hario_attributes_list
10
+
11
+ def search(filters, pluck = [])
12
+ pluck = pluck.reject{ |p| p.nil? || p.empty? }
13
+
8
14
  s = all
9
15
  s = s.apply_filters(filters) if filters
10
- s = s.apply_pluck(pluck) if pluck
16
+ s = s.apply_pluck(pluck) if pluck.any?
11
17
  s
12
18
  end
13
19
 
@@ -32,5 +38,22 @@ module Hario
32
38
  def hash_pluck(*keys)
33
39
  pluck(*keys).map{ |vals| Hash[keys.zip(Array(vals))] }
34
40
  end
41
+
42
+ def hario_attributes(types, only: nil, except: nil)
43
+ @hario_attributes_list ||= {}
44
+ Array.wrap(types).each do |t|
45
+ raise_if_not_hario_type!(t)
46
+ @hario_attributes_list[t] =
47
+ { only: Array.wrap(only), except: Array.wrap(except) }
48
+ end
49
+ end
50
+
51
+ private
52
+ def raise_if_not_hario_type!(type)
53
+ unless HARIO_APPLY_TYPES.include?(type)
54
+ raise ArgumentError, "#{type} is not one of " \
55
+ "#{HARIO_APPLY_TYPES.map(&:inspect).join(', ')}"
56
+ end
57
+ end
35
58
  end
36
59
  end
@@ -4,7 +4,8 @@ module Hario
4
4
  class FilterParser
5
5
  include ParserUtils
6
6
 
7
- OPERATORS = { lt: '<', gt: '>', lte: '<=', gte: '>=', like: 'like', equals: '=' }
7
+ OPERATORS = { lt: '<', gt: '>', lte: '<=', gte: '>=', like: 'like', equals: '=', is: 'is' }
8
+ IS_VALUES = { null: 'NULL', not_null: 'NOT NULL' }
8
9
 
9
10
  attr_accessor :join_clause, :where_clauses
10
11
 
@@ -15,7 +16,7 @@ module Hario
15
16
  parse_filters
16
17
  end
17
18
 
18
- InvalidAttributeError = Class.new(RuntimeError)
19
+ InvalidValueError = Class.new(RuntimeError)
19
20
 
20
21
  private
21
22
  def parse_filters
@@ -47,12 +48,18 @@ module Hario
47
48
  end_model = @klass
48
49
  end
49
50
 
51
+ raise_if_unlisted_attribute!(:filters, end_model, attribute)
50
52
  raise_if_invalid_attribute!(attribute, end_model)
51
53
 
52
54
  case operator
53
55
  when :equals
54
56
  condition = { attribute => value }
55
57
  condition = { attribute_table => condition } if attribute_table
58
+ when :is
59
+ value = value.to_sym
60
+ raise_if_invalid_is_value!(value)
61
+ condition = ["#{attribute} #{operator} #{IS_VALUES[value]}"]
62
+ condition[0].prepend("#{attribute_table || @klass.table_name}.")
56
63
  else
57
64
  operator = OPERATORS[operator]
58
65
  condition = ["#{attribute} #{operator} ?", value]
@@ -62,6 +69,13 @@ module Hario
62
69
  condition
63
70
  end
64
71
 
72
+ def raise_if_invalid_is_value!(value)
73
+ unless IS_VALUES[value]
74
+ raise InvalidValueError,
75
+ "When using 'is', value must be one of #{IS_VALUES.keys.join(', ')}"
76
+ end
77
+ end
78
+
65
79
  def raise_if_invalid_attribute!(attribute, end_model)
66
80
  unless end_model.column_names.include?(attribute)
67
81
  raise InvalidAttributeError,
@@ -20,11 +20,17 @@ module Hario
20
20
 
21
21
  ns, no_ns = @pluck.partition{ |p| p.include?('.') }
22
22
 
23
- no_ns.each{ |p| @pluck_clause << [@klass.table_name, p].join('.') }
23
+ no_ns.each do |p|
24
+ raise_if_unlisted_attribute!(:pluck, @klass, p)
25
+ @pluck_clause << [@klass.table_name, p].join('.')
26
+ end
24
27
 
25
28
  ns.each do |p|
26
29
  association_chain, attribute = parse_namespace(p)
27
30
 
31
+ end_model = end_model_from_association_chain(association_chain)
32
+ raise_if_unlisted_attribute!(:pluck, end_model, attribute)
33
+
28
34
  nested_associations = (association_chain.dup << {}).reverse.inject { |v, key| { key => v } }
29
35
  @join_clause.deep_merge!(nested_associations)
30
36
 
@@ -1,4 +1,6 @@
1
1
  module ParserUtils
2
+ InvalidAttributeError = Class.new(RuntimeError)
3
+
2
4
  def table_name_from_association_chain(association_chain)
3
5
  end_model_from_association_chain(association_chain).table_name
4
6
  end
@@ -12,4 +14,16 @@ module ParserUtils
12
14
 
13
15
  head
14
16
  end
17
+
18
+ def raise_if_unlisted_attribute!(type, model_class, attribute)
19
+ return unless model_class.respond_to?(:hario_attributes_list)
20
+ return unless model_class.hario_attributes_list
21
+ lists = model_class.hario_attributes_list[type]
22
+ return unless lists
23
+ attribute = attribute.to_sym
24
+ if (lists[:except].present? && lists[:except].include?(attribute)) ||
25
+ (lists[:only ].present? && !lists[:only ].include?(attribute))
26
+ raise InvalidAttributeError, "#{attribute} is forbidden"
27
+ end
28
+ end
15
29
  end
data/lib/hario/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Hario
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
data/test/filter_test.rb CHANGED
@@ -38,7 +38,7 @@ class FilterTest < Hario::Test
38
38
  filters = { 'created_at.gt' => (DateTime.now - 5).iso8601 }
39
39
  products = Product.search(filters)
40
40
 
41
- assert_equal 2, products.count
41
+ assert_equal 3, products.count
42
42
  end
43
43
 
44
44
  def test_invalid_attribute_raises
@@ -48,4 +48,46 @@ class FilterTest < Hario::Test
48
48
  Product.search(filters)
49
49
  end
50
50
  end
51
+
52
+ def test_is_null
53
+ filters = { 'brand_id.is' => "null" }
54
+
55
+ products = Product.search(filters)
56
+ assert_equal 1, products.count
57
+ assert_equal 'Nil product', products.first.name
58
+ end
59
+
60
+ def test_is_not_null
61
+ filters = { 'brand_id.is' => "not_null" }
62
+
63
+ products = Product.search(filters)
64
+ assert_equal 3, products.count
65
+ products.each do |p|
66
+ refute_equal 'Nil product', p.name
67
+ end
68
+ end
69
+
70
+ def test_is_value_must_be_correct
71
+ filters = { 'brand_id.is' => "meh" }
72
+
73
+ assert_raises Hario::FilterParser::InvalidValueError do
74
+ Product.search(filters)
75
+ end
76
+ end
77
+
78
+ def test_hidden_column_filter
79
+ filters = { 'hidden_column.equals' => 5 }
80
+
81
+ assert_raises Hario::FilterParser::InvalidAttributeError do
82
+ Product.search(filters)
83
+ end
84
+ end
85
+
86
+ def test_hidden_column_filter_with_join
87
+ filters = { 'products.hidden_column.equals' => 5 }
88
+
89
+ assert_raises Hario::FilterParser::InvalidAttributeError do
90
+ Brand.search(filters)
91
+ end
92
+ end
51
93
  end
data/test/fixtures.rb CHANGED
@@ -19,4 +19,7 @@ Product.create!(
19
19
  brand_id: @adidas.id,
20
20
  category_id: @tee.id,
21
21
  name: "Hamburg"
22
- )
22
+ )
23
+ Product.create!(
24
+ name: 'Nil product'
25
+ )
data/test/models.rb CHANGED
@@ -9,6 +9,8 @@ end
9
9
  class Product < ActiveRecord::Base
10
10
  extend Hario::Filterable
11
11
 
12
+ hario_attributes [:filters, :pluck], except: :hidden_column
13
+
12
14
  belongs_to :brand
13
15
  belongs_to :category, class_name: "ProductCategory"
14
16
  end
data/test/pluck_test.rb CHANGED
@@ -16,4 +16,23 @@ class PluckTest < Hario::Test
16
16
  assert_equal ["id", "name", "brands.name"], products.flat_map(&:keys).uniq,
17
17
  "Pluck not returning correct attributes with association pluck"
18
18
  end
19
- end
19
+
20
+ def test_hidden_column_pluck
21
+ assert_raises Hario::PluckParser::InvalidAttributeError do
22
+ Product.search(nil, %w( hidden_column ))
23
+ end
24
+ end
25
+
26
+ def test_hidden_column_pluck_with_join
27
+ assert_raises Hario::PluckParser::InvalidAttributeError do
28
+ Brand.search(nil, %w( products.hidden_column ))
29
+ end
30
+ end
31
+
32
+ def test_empty_string_ignored
33
+ Product.search(nil, [""])
34
+
35
+ # no exception
36
+ assert true
37
+ end
38
+ end
data/test/schema.rb CHANGED
@@ -8,6 +8,7 @@ ActiveRecord::Schema.define(:version => 1) do
8
8
  t.column :name, :string
9
9
  t.column :category_id, :integer
10
10
  t.column :brand_id, :integer
11
+ t.column :hidden_column, :integer
11
12
  t.timestamps null: false
12
13
  end
13
14
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hario
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Campbell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-17 00:00:00.000000000 Z
11
+ date: 2017-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -126,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
126
126
  version: '0'
127
127
  requirements: []
128
128
  rubyforge_project:
129
- rubygems_version: 2.4.6
129
+ rubygems_version: 2.5.1
130
130
  signing_key:
131
131
  specification_version: 4
132
132
  summary: Hario provides ActiveRecord filtering for Rails APIs.