ruby-ext-js 0.0.1 → 0.1.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 +14 -12
- data/VERSION +1 -1
- data/lib/ruby-ext-js.rb +50 -37
- data/ruby-ext-js.gemspec +1 -1
- data/spec/ruby-ext-js_spec.rb +108 -14
- metadata +3 -3
data/README.markdown
CHANGED
@@ -4,8 +4,22 @@ Provides ultra-basic classes for translating Ext.js GET params to Postgres (via
|
|
4
4
|
|
5
5
|
Examples:
|
6
6
|
|
7
|
+
## MongoDB
|
8
|
+
|
9
|
+
class PullRequests < ExtJs::Mongo
|
10
|
+
def self.allowed_filters
|
11
|
+
["state"]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
mongo = PullRequests.new( params )
|
16
|
+
mongo.conditions # search conditions
|
17
|
+
mongo.options # pagination and sorting options
|
18
|
+
|
7
19
|
## Postgres
|
8
20
|
|
21
|
+
(Implementation and API will change significantly in the future, don't use this yet.)
|
22
|
+
|
9
23
|
module ExtJs
|
10
24
|
class PullRequests < Postgres
|
11
25
|
# Converts Ext.js' wacky params structure into a Postgres db query opts
|
@@ -33,18 +47,6 @@ Examples:
|
|
33
47
|
end
|
34
48
|
end
|
35
49
|
|
36
|
-
## MongoDB
|
37
|
-
|
38
|
-
Mongo's a lot easier to work with:
|
39
|
-
|
40
|
-
module ExtJs
|
41
|
-
class PullRequests < Mongo
|
42
|
-
def self.allowed_filters
|
43
|
-
["state"]
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
50
|
# Specs
|
49
51
|
|
50
52
|
`ExtJs` was extracted from private code. Existing specs rely on private models, so there are no specs here yet. Specs will require DataMapper.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/lib/ruby-ext-js.rb
CHANGED
@@ -65,68 +65,81 @@ module ExtJs
|
|
65
65
|
end
|
66
66
|
|
67
67
|
class Mongo
|
68
|
-
|
69
|
-
|
70
|
-
|
68
|
+
DEFAULT_SKIP = 0
|
69
|
+
MAX_LIMIT = 500
|
70
|
+
DEFAULT_LIMIT = 50
|
71
71
|
|
72
|
-
def
|
72
|
+
def initialize( params )
|
73
|
+
@params = params
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [Hash] `find()` conditions for `Mongo::Collection.find( conditions, opts )`
|
77
|
+
def conditions
|
78
|
+
self.class.search_param( @params )
|
79
|
+
end
|
80
|
+
|
81
|
+
# @return [Hash] `find()` options for `Mongo::Collection.find( conditions, opts )`
|
82
|
+
def options
|
73
83
|
opts = {}
|
74
84
|
|
75
|
-
opts.merge!
|
76
|
-
opts.merge!
|
77
|
-
opts.merge! sort_param( params )
|
78
|
-
opts.merge! search_param( params )
|
85
|
+
opts.merge! self.class.skip_param( @params )
|
86
|
+
opts.merge! self.class.limit_param( @params )
|
87
|
+
opts.merge! self.class.sort_param( @params )
|
79
88
|
|
80
89
|
opts
|
81
90
|
end
|
82
91
|
|
83
|
-
|
84
|
-
|
92
|
+
# @return [Array] Array of string values representing keys that are filterable.
|
85
93
|
def self.allowed_filters
|
86
94
|
[]
|
87
95
|
end
|
88
96
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
{ :page => ( start / limit ) + 1 }
|
97
|
+
protected
|
98
|
+
|
99
|
+
def self.skip_param( params )
|
100
|
+
return { :skip => DEFAULT_SKIP } unless params.key?( "start" ) && params.key?( "limit" )
|
101
|
+
{ :skip => [params["start"].to_i, 0].max }
|
96
102
|
end
|
97
103
|
|
98
|
-
def self.
|
99
|
-
unless params.key?( "limit" ) && params["limit"].to_i > 0
|
100
|
-
|
101
|
-
end
|
102
|
-
{ :per_page => [params["limit"].to_i, MAX_PER_PAGE].min }
|
104
|
+
def self.limit_param( params )
|
105
|
+
return { :limit => DEFAULT_LIMIT } unless params.key?( "limit" ) && params["limit"].to_i > 0
|
106
|
+
{ :limit => [params["limit"].to_i, MAX_LIMIT].min }
|
103
107
|
end
|
104
108
|
|
105
109
|
def self.sort_param( params )
|
106
110
|
return {} unless params.key?( "sort" )
|
107
111
|
|
108
112
|
sort = params["sort"] ? params["sort"].to_sym : :id
|
109
|
-
|
113
|
+
dir = params["dir"] =~ /desc/i ? :desc : :asc
|
110
114
|
|
111
|
-
{ :sort => sort }
|
115
|
+
{ :sort => [sort, dir] }
|
112
116
|
end
|
113
117
|
|
114
118
|
def self.search_param( params )
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
119
|
+
conds = {}
|
120
|
+
|
121
|
+
if params["filter"] && params["filter"].size > 0
|
122
|
+
0.upto( params["filter"].size - 1 ).each do |i|
|
123
|
+
i = i.to_s
|
124
|
+
|
125
|
+
next unless params["filter"][i]
|
126
|
+
|
127
|
+
field = (params["filter"][i]["field"] || "").gsub(/[^\.\w\d_-]/, "").strip
|
128
|
+
values = Array( params["filter"][i]["data"] ? params["filter"][i]["data"]["value"] : nil )
|
129
|
+
|
130
|
+
if values.size == 1
|
131
|
+
values = values[0]
|
132
|
+
elsif values.size > 1
|
133
|
+
values = { "$in" => values }
|
134
|
+
end
|
135
|
+
|
136
|
+
unless field.empty? || !allowed_filters.include?( field ) || values.empty?
|
137
|
+
conds.merge! field => values
|
138
|
+
end
|
127
139
|
end
|
128
140
|
end
|
129
|
-
|
141
|
+
|
142
|
+
conds
|
130
143
|
end
|
131
144
|
end
|
132
145
|
end
|
data/ruby-ext-js.gemspec
CHANGED
data/spec/ruby-ext-js_spec.rb
CHANGED
@@ -1,22 +1,116 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
3
|
describe "ExtJs" do
|
4
|
-
describe "Postgres" do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
4
|
+
# describe "Postgres" do
|
5
|
+
# it "sorts on id when you ask it to sort on created_at" do
|
6
|
+
# ExtJs::Postgres.pagination_opts({
|
7
|
+
# :sort => "created_at",
|
8
|
+
# :order => "desc"
|
9
|
+
# })[:order].should == [:id.asc]
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# it "specs the rest of the class or it gets the hose" do
|
13
|
+
# pending "The current spec suite is currently rigidly tied to private models. Someday we'll write a generic spec suite here."
|
14
|
+
# end
|
15
|
+
# end
|
16
16
|
|
17
17
|
describe "Mongo" do
|
18
|
-
|
19
|
-
|
18
|
+
describe "conditions" do
|
19
|
+
class TestMongoNoFilters < ExtJs::Mongo; end
|
20
|
+
|
21
|
+
class TestMongoWithFilters < ExtJs::Mongo
|
22
|
+
def self.allowed_filters
|
23
|
+
["state", "score"]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it "handles empty params" do
|
28
|
+
mongo = TestMongoNoFilters.new( {} )
|
29
|
+
mongo.conditions.should == {}
|
30
|
+
|
31
|
+
mongo = TestMongoWithFilters.new( {} )
|
32
|
+
mongo.conditions.should == {}
|
33
|
+
end
|
34
|
+
|
35
|
+
it "handles filter params" do
|
36
|
+
params = {
|
37
|
+
"filter" => {
|
38
|
+
"0" => {
|
39
|
+
"field" => "state",
|
40
|
+
"data" => {
|
41
|
+
"value" => "open"
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
mongo = TestMongoNoFilters.new( params )
|
47
|
+
mongo.conditions.should == {}
|
48
|
+
|
49
|
+
mongo = TestMongoWithFilters.new( params )
|
50
|
+
mongo.conditions.should == { "state" => "open" }
|
51
|
+
end
|
52
|
+
|
53
|
+
it "handles complex filter params" do
|
54
|
+
params = {
|
55
|
+
"filter" => {
|
56
|
+
"0" => {
|
57
|
+
"field" => "state",
|
58
|
+
"data" => {
|
59
|
+
"value" => "open"
|
60
|
+
}
|
61
|
+
},
|
62
|
+
"1" => {
|
63
|
+
"field" => "score",
|
64
|
+
"data" => {
|
65
|
+
"value" => ["5", "4"]
|
66
|
+
}
|
67
|
+
},
|
68
|
+
"2" => {
|
69
|
+
"field" => "score"
|
70
|
+
},
|
71
|
+
"3" => {
|
72
|
+
"data" => {
|
73
|
+
"value" => ["5", "4"]
|
74
|
+
}
|
75
|
+
},
|
76
|
+
"4" => {
|
77
|
+
"field" => "score",
|
78
|
+
"data" => {
|
79
|
+
"value" => []
|
80
|
+
}
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
mongo = TestMongoWithFilters.new( params )
|
86
|
+
mongo.conditions.should == { "state" => "open", "score" => { "$in" => ["5", "4"] } }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "opts" do
|
91
|
+
class TestMongo < ExtJs::Mongo; end
|
92
|
+
|
93
|
+
it "handles empty params with sensible defaults" do
|
94
|
+
TestMongo.new( {} ).options.should == { :limit => 50, :skip => 0 }
|
95
|
+
end
|
96
|
+
|
97
|
+
it "handles pagination" do
|
98
|
+
TestMongo.new( "start" => "50", "limit" => "10" ).options.should == { :limit => 10, :skip => 50 }
|
99
|
+
TestMongo.new( "start" => "10" ).options.should == { :limit => 50, :skip => 0 }
|
100
|
+
TestMongo.new( "limit" => "10" ).options.should == { :limit => 10, :skip => 0 }
|
101
|
+
end
|
102
|
+
|
103
|
+
it "handles sorting" do
|
104
|
+
TestMongo.new( "sort" => "foo" ).options.should == { :limit => 50, :skip => 0, :sort => [:foo, :asc] }
|
105
|
+
TestMongo.new( "sort" => "foo", "dir" => "desc" ).options.should == { :limit => 50, :skip => 0, :sort => [:foo, :desc] }
|
106
|
+
TestMongo.new( "sort" => "foo", "dir" => "no idea" ).options.should == { :limit => 50, :skip => 0, :sort => [:foo, :asc] }
|
107
|
+
TestMongo.new( "dir" => "asc" ).options.should == { :limit => 50, :skip => 0 }
|
108
|
+
end
|
109
|
+
|
110
|
+
it "prevents dumb queries" do
|
111
|
+
TestMongo.new( "start" => "9999999", "limit" => "9999999" ).options.should == { :limit => 500, :skip => 9999999 }
|
112
|
+
TestMongo.new( "start" => "-200", "limit" => "-200" ).options.should == { :limit => 50, :skip => 0 }
|
113
|
+
end
|
20
114
|
end
|
21
115
|
end
|
22
116
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-ext-js
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
- 0
|
9
8
|
- 1
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tyson Tate
|