constrainable 0.5.1 → 0.6.0
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.
- data/README.markdown +5 -5
- data/lib/bsm/constrainable/field.rb +2 -0
- data/lib/bsm/constrainable/field/base.rb +6 -5
- data/lib/bsm/constrainable/field/common.rb +20 -0
- data/lib/bsm/constrainable/operation/base.rb +4 -7
- data/lib/bsm/constrainable/relation.rb +1 -1
- data/lib/bsm/constrainable/schema.rb +1 -1
- metadata +58 -14
data/README.markdown
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# Constrainable
|
2
2
|
|
3
|
-
Simple filtering for ActiveRecord. Sanitizes simple and readable query parameters -great for building APIs & HTML filters.
|
3
|
+
Simple filtering for ActiveRecord. Sanitizes simple and readable query parameters - great for building APIs & HTML filters.
|
4
4
|
|
5
5
|
## Straight to the point. Examples:
|
6
6
|
|
7
|
-
Let's
|
7
|
+
Let's assume we have a model called Post, defined as:
|
8
8
|
Post(id: integer, title: string, body: string, author_id: integer, category: string, created_at: datetime, updated_at: datetime)
|
9
9
|
|
10
10
|
In the simplest possible case you can define a few attributes and start filtering:
|
@@ -17,7 +17,7 @@ In the simplest possible case you can define a few attributes and start filterin
|
|
17
17
|
|
18
18
|
end
|
19
19
|
|
20
|
-
#
|
20
|
+
# Example request:
|
21
21
|
# GET /posts?where[id__not_eq]=1&where[author_id__eq]=2
|
22
22
|
# Params:
|
23
23
|
# "where" => { "id__not_eq" => "1", "author_id__eq" => "2" }
|
@@ -84,8 +84,8 @@ Integration with controllers, views & filter forms:
|
|
84
84
|
respond_to :html
|
85
85
|
|
86
86
|
def index
|
87
|
-
@filters = Post.constrainable.
|
88
|
-
@posts
|
87
|
+
@filters = Post.constrainable.filter(params[:where])
|
88
|
+
@posts = Post.constrain(@filters)
|
89
89
|
respond_with @posts
|
90
90
|
end
|
91
91
|
end
|
@@ -9,6 +9,7 @@ module Bsm::Constrainable::Field
|
|
9
9
|
autoload :Timestamp,'bsm/constrainable/field/common'
|
10
10
|
autoload :Datetime, 'bsm/constrainable/field/common'
|
11
11
|
autoload :Date, 'bsm/constrainable/field/common'
|
12
|
+
autoload :Boolean, 'bsm/constrainable/field/common'
|
12
13
|
|
13
14
|
register self::Number
|
14
15
|
register self::Integer
|
@@ -17,4 +18,5 @@ module Bsm::Constrainable::Field
|
|
17
18
|
register self::Timestamp
|
18
19
|
register self::Datetime
|
19
20
|
register self::Date
|
21
|
+
register self::Boolean
|
20
22
|
end
|
@@ -11,12 +11,12 @@ class Bsm::Constrainable::Field::Base
|
|
11
11
|
@kind ||= name.demodulize.underscore.to_sym
|
12
12
|
end
|
13
13
|
|
14
|
-
attr_reader :name, :operators, :attribute, :scope
|
14
|
+
attr_reader :name, :operators, :attribute, :scope, :options
|
15
15
|
|
16
16
|
# Accepts a name and options. Valid options are:
|
17
17
|
# * <tt>:using</tt> - a Symbol or a Proc pointing to a DB column, optional (uses name by default)
|
18
18
|
# * <tt>:with</tt> - a list of operators to use
|
19
|
-
# * <tt>:scope</tt> - a Proc containing
|
19
|
+
# * <tt>:scope</tt> - a Proc containing additional scopes
|
20
20
|
#
|
21
21
|
# Examples:
|
22
22
|
#
|
@@ -28,10 +28,11 @@ class Bsm::Constrainable::Field::Base
|
|
28
28
|
#
|
29
29
|
def initialize(name, options = {})
|
30
30
|
@name = name.to_s
|
31
|
-
@
|
32
|
-
@
|
31
|
+
@options = options.dup
|
32
|
+
@attribute = @options.delete(:using) || name
|
33
|
+
@operators = Set.new(self.class.operators & Array.wrap(@options.delete(:with)))
|
33
34
|
@operators = Set.new(self.class.defaults) if @operators.empty?
|
34
|
-
@scope = options
|
35
|
+
@scope = @options.delete(:scope)
|
35
36
|
end
|
36
37
|
|
37
38
|
# Merge params into a relation
|
@@ -23,6 +23,11 @@ module Bsm::Constrainable::Field
|
|
23
23
|
|
24
24
|
class String < Base
|
25
25
|
self.operators = [:eq, :not_eq]
|
26
|
+
|
27
|
+
def _convert(v)
|
28
|
+
result = super
|
29
|
+
result.blank? && !options[:allow_blank] ? nil : result
|
30
|
+
end
|
26
31
|
end
|
27
32
|
|
28
33
|
class Timestamp < Base
|
@@ -43,4 +48,19 @@ module Bsm::Constrainable::Field
|
|
43
48
|
v.to_date rescue nil
|
44
49
|
end
|
45
50
|
end
|
51
|
+
|
52
|
+
class Boolean < Base
|
53
|
+
self.operators = [:eq, :not_eq]
|
54
|
+
|
55
|
+
TRUE_VALUES = ["true", "TRUE", "t", "T", "1", 1].to_set.freeze
|
56
|
+
FALSE_VALUES = ["false", "FALSE", "f", "F", "0", 0].to_set.freeze
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
def _convert(v)
|
61
|
+
result = super
|
62
|
+
TRUE_VALUES.include?(result) || (FALSE_VALUES.include?(result) ? false : nil)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
46
66
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
class Bsm::Constrainable::Operation::Base
|
2
|
-
extend ActiveSupport::Memoizable
|
3
2
|
|
4
3
|
def self.kind
|
5
4
|
name.demodulize.underscore.to_sym
|
@@ -27,9 +26,9 @@ class Bsm::Constrainable::Operation::Base
|
|
27
26
|
end
|
28
27
|
|
29
28
|
def clause
|
30
|
-
|
29
|
+
return @clause if defined?(@clause)
|
30
|
+
@clause ||= valid? ? _clause : nil
|
31
31
|
end
|
32
|
-
memoize :clause
|
33
32
|
|
34
33
|
protected
|
35
34
|
|
@@ -38,18 +37,16 @@ class Bsm::Constrainable::Operation::Base
|
|
38
37
|
end
|
39
38
|
|
40
39
|
def normalized
|
41
|
-
field.convert(parsed)
|
40
|
+
@normalized ||= field.convert(parsed)
|
42
41
|
end
|
43
|
-
memoize :normalized
|
44
42
|
|
45
43
|
def attribute
|
46
|
-
case field.attribute
|
44
|
+
@attribute ||= case field.attribute
|
47
45
|
when Proc
|
48
46
|
field.attribute.call(relation)
|
49
47
|
else
|
50
48
|
relation.table[field.attribute]
|
51
49
|
end
|
52
50
|
end
|
53
|
-
memoize :attribute
|
54
51
|
|
55
52
|
end
|
@@ -40,7 +40,7 @@ class Bsm::Constrainable::Schema < Hash
|
|
40
40
|
# # Complex example, using an attribute from another table, and ensure it's included (LEFT OUTER JOIN)
|
41
41
|
# match :author, :using => proc { Author.scope.table[:name] }, :scope => { includes(:author) }, :as => :string, :with => [:eq, :matches]
|
42
42
|
#
|
43
|
-
# There are also several short-
|
43
|
+
# There are also several short-cuts available. Examples:
|
44
44
|
#
|
45
45
|
# timestamp :created, :using => :created_at, :with => [:lt, :between]
|
46
46
|
# number :id, :author_id
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: constrainable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,22 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-01-23 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement: &
|
15
|
+
name: activerecord
|
16
|
+
requirement: &12912960 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: 3.0.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *12912960
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
|
-
name:
|
27
|
-
requirement: &
|
26
|
+
name: activesupport
|
27
|
+
requirement: &12912280 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,18 +32,62 @@ dependencies:
|
|
32
32
|
version: 3.0.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *12912280
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
|
-
name:
|
38
|
-
requirement: &
|
37
|
+
name: rspec
|
38
|
+
requirement: &12911680 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version:
|
44
|
-
type: :
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *12911680
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec-rails
|
49
|
+
requirement: &12910780 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *12910780
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: sqlite3-ruby
|
60
|
+
requirement: &12909920 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *12909920
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: shoulda-matchers
|
71
|
+
requirement: &12908980 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *12908980
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: actionpack
|
82
|
+
requirement: &12907980 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
45
89
|
prerelease: false
|
46
|
-
version_requirements: *
|
90
|
+
version_requirements: *12907980
|
47
91
|
description: Sanitizes simple and readable query parameters -great for building APIs
|
48
92
|
& HTML filters
|
49
93
|
email: dimitrij@blacksquaremedia.com
|