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 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
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
- MAX_PER_PAGE = 1000
69
- DEFAULT_PAGE = 1
70
- DEFAULT_PER_PAGE = 30
68
+ DEFAULT_SKIP = 0
69
+ MAX_LIMIT = 500
70
+ DEFAULT_LIMIT = 50
71
71
 
72
- def self.db_opts( params )
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! page_param( params )
76
- opts.merge! per_page_param( params )
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
- protected
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
- def self.page_param( params )
90
- return { :page => DEFAULT_PAGE } unless params.key?( "start" ) && params.key?( "limit" )
91
-
92
- start = params["start"].to_i
93
- limit = per_page_param( params )[:per_page]
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.per_page_param( params )
99
- unless params.key?( "limit" ) && params["limit"].to_i > 0
100
- return { :per_page => DEFAULT_PER_PAGE }
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
- sort = params["dir"] =~ /desc/i ? sort.desc : sort.asc
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
- if params["filter"] && params["filter"]["0"]
116
- field = params["filter"]["0"]["field"].gsub(/[^\.\w\d_-]/, "").strip
117
- values = Array( params["filter"]["0"]["data"]["value"] )
118
-
119
- if values.size == 1
120
- values = values[0]
121
- else
122
- values = { "$in" => values }
123
- end
124
-
125
- unless field.blank? || !allowed_filters.include?( field ) || values.blank?
126
- return { field => values }
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
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ruby-ext-js}
8
- s.version = "0.0.1"
8
+ s.version = "0.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Tyson Tate"]
@@ -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
- 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
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
- it "specs the rest of the class or it gets the hose" do
19
- pending "The current spec suite is currently rigidly tied to private models. Someday we'll write a generic spec suite here."
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: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 0
9
8
  - 1
10
- version: 0.0.1
9
+ - 0
10
+ version: 0.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Tyson Tate