hario 0.3.0 → 0.3.1

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
  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.