datatable 0.1.0alpha2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (187) hide show
  1. data/.bundle/config +3 -0
  2. data/.gitignore +7 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +9 -0
  5. data/Gemfile.lock +83 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +135 -0
  8. data/Rakefile +27 -0
  9. data/TODO +71 -0
  10. data/datatable.gemspec +20 -0
  11. data/example_app/.DS_Store +0 -0
  12. data/example_app/.gitignore +6 -0
  13. data/example_app/.rspec +1 -0
  14. data/example_app/Gemfile +35 -0
  15. data/example_app/Gemfile.lock +126 -0
  16. data/example_app/Rakefile +7 -0
  17. data/example_app/app/controllers/application_controller.rb +3 -0
  18. data/example_app/app/controllers/orders_controller.rb +13 -0
  19. data/example_app/app/datatables/orders_index.rb +31 -0
  20. data/example_app/app/helpers/application_helper.rb +2 -0
  21. data/example_app/app/models/customer.rb +4 -0
  22. data/example_app/app/models/item.rb +4 -0
  23. data/example_app/app/models/order.rb +5 -0
  24. data/example_app/app/models/order_item.rb +4 -0
  25. data/example_app/app/models/sales_rep.rb +3 -0
  26. data/example_app/app/views/layouts/application.html.erb +12 -0
  27. data/example_app/app/views/orders/index.html.erb +14 -0
  28. data/example_app/config/application.rb +41 -0
  29. data/example_app/config/boot.rb +6 -0
  30. data/example_app/config/database.yml.mysql +20 -0
  31. data/example_app/config/database.yml.pg +20 -0
  32. data/example_app/config/environment.rb +5 -0
  33. data/example_app/config/environments/development.rb +28 -0
  34. data/example_app/config/environments/production.rb +49 -0
  35. data/example_app/config/environments/test.rb +35 -0
  36. data/example_app/config/initializers/backtrace_silencers.rb +7 -0
  37. data/example_app/config/initializers/datatable.rb +6 -0
  38. data/example_app/config/initializers/inflections.rb +10 -0
  39. data/example_app/config/initializers/mime_types.rb +5 -0
  40. data/example_app/config/initializers/secret_token.rb +9 -0
  41. data/example_app/config/initializers/session_store.rb +8 -0
  42. data/example_app/config/locales/en.yml +5 -0
  43. data/example_app/config/routes.rb +6 -0
  44. data/example_app/config.ru +4 -0
  45. data/example_app/db/migrate/20110429185712_create_customers.rb +15 -0
  46. data/example_app/db/migrate/20110429185742_create_sales_reps.rb +14 -0
  47. data/example_app/db/migrate/20110429185807_create_items.rb +15 -0
  48. data/example_app/db/migrate/20110429185913_create_orders.rb +15 -0
  49. data/example_app/db/migrate/20110429190005_create_order_items.rb +14 -0
  50. data/example_app/db/schema.rb +53 -0
  51. data/example_app/db/seeds.rb +49 -0
  52. data/example_app/lib/tasks/.gitkeep +0 -0
  53. data/example_app/lib/tasks/setup.rake +12 -0
  54. data/example_app/public/404.html +26 -0
  55. data/example_app/public/422.html +26 -0
  56. data/example_app/public/500.html +26 -0
  57. data/example_app/public/datatable/css/demo_page.css +99 -0
  58. data/example_app/public/datatable/css/demo_table.css +539 -0
  59. data/example_app/public/datatable/css/demo_table_jui.css +521 -0
  60. data/example_app/public/datatable/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  61. data/example_app/public/datatable/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  62. data/example_app/public/datatable/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  63. data/example_app/public/datatable/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  64. data/example_app/public/datatable/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  65. data/example_app/public/datatable/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  66. data/example_app/public/datatable/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  67. data/example_app/public/datatable/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  68. data/example_app/public/datatable/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
  69. data/example_app/public/datatable/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  70. data/example_app/public/datatable/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
  71. data/example_app/public/datatable/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
  72. data/example_app/public/datatable/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  73. data/example_app/public/datatable/css/smoothness/jquery-ui-1.8.14.custom.css +568 -0
  74. data/example_app/public/datatable/images/back_disabled.jpg +0 -0
  75. data/example_app/public/datatable/images/back_enabled.jpg +0 -0
  76. data/example_app/public/datatable/images/favicon.ico +0 -0
  77. data/example_app/public/datatable/images/forward_disabled.jpg +0 -0
  78. data/example_app/public/datatable/images/forward_enabled.jpg +0 -0
  79. data/example_app/public/datatable/images/sort_asc.png +0 -0
  80. data/example_app/public/datatable/images/sort_asc_disabled.png +0 -0
  81. data/example_app/public/datatable/images/sort_both.png +0 -0
  82. data/example_app/public/datatable/images/sort_desc.png +0 -0
  83. data/example_app/public/datatable/images/sort_desc_disabled.png +0 -0
  84. data/example_app/public/datatable/js/jquery-ui-1.8.14.custom.min.js +789 -0
  85. data/example_app/public/datatable/js/jquery.dataTables.js +7347 -0
  86. data/example_app/public/datatable/js/jquery.dataTables.min.js +151 -0
  87. data/example_app/public/favicon.ico +0 -0
  88. data/example_app/public/flash/copy_cvs_xls.swf +0 -0
  89. data/example_app/public/flash/copy_cvs_xls_pdf.swf +0 -0
  90. data/example_app/public/images/rails.png +0 -0
  91. data/example_app/public/javascripts/application.js +2 -0
  92. data/example_app/public/javascripts/jquery.js +8936 -0
  93. data/example_app/public/javascripts/jquery.min.js +18 -0
  94. data/example_app/public/javascripts/jquery_ujs.js +316 -0
  95. data/example_app/public/robots.txt +5 -0
  96. data/example_app/public/stylesheets/.gitkeep +0 -0
  97. data/example_app/script/rails +6 -0
  98. data/example_app/spec/datatables/active_record_dsl_spec.rb +59 -0
  99. data/example_app/spec/datatables/active_record_link_to_spec.rb +22 -0
  100. data/example_app/spec/datatables/active_record_pagination_spec.rb +94 -0
  101. data/example_app/spec/datatables/active_record_table_operations_spec.rb +180 -0
  102. data/example_app/spec/datatables/config_spec.rb +10 -0
  103. data/example_app/spec/datatables/query_params_spec.rb +73 -0
  104. data/example_app/spec/datatables/sql_default_spec.rb +22 -0
  105. data/example_app/spec/datatables/sql_pagination_spec.rb +177 -0
  106. data/example_app/spec/datatables/sql_search_cast_spec.rb +6 -0
  107. data/example_app/spec/datatables/sql_search_global_spec.rb +107 -0
  108. data/example_app/spec/datatables/sql_search_individual_spec.rb +113 -0
  109. data/example_app/spec/datatables/sql_search_where_spec.rb +87 -0
  110. data/example_app/spec/datatables/sql_sorting_spec.rb +80 -0
  111. data/example_app/spec/datatables/sql_variables_spec.rb +104 -0
  112. data/example_app/spec/factories/customer_factory.rb +4 -0
  113. data/example_app/spec/factories/item_factory.rb +2 -0
  114. data/example_app/spec/factories/order_factory.rb +7 -0
  115. data/example_app/spec/factories/order_item_factory.rb +2 -0
  116. data/example_app/spec/factories/sales_rep_factory.rb +4 -0
  117. data/example_app/spec/helpers/aocolumn_spec.rb +239 -0
  118. data/example_app/spec/helpers/data_table_helper_spec.rb +148 -0
  119. data/example_app/spec/helpers/headings_spec.rb +71 -0
  120. data/example_app/spec/spec_helper.rb +29 -0
  121. data/generators.txt +6 -0
  122. data/images/datatable_screenshot.png +0 -0
  123. data/lib/datatable/active_record_dsl.rb +49 -0
  124. data/lib/datatable/errors.rb +5 -0
  125. data/lib/datatable/helper.rb +199 -0
  126. data/lib/datatable/railtie.rb +17 -0
  127. data/lib/datatable/version.rb +4 -0
  128. data/lib/datatable.rb +341 -0
  129. data/lib/generators/datatable/install_generator.rb +58 -0
  130. data/lib/generators/datatable/new_generator.rb +46 -0
  131. data/lib/generators/templates/datatable.rb +33 -0
  132. data/lib/generators/templates/datatable_initializer.rb +6 -0
  133. data/vendor/datatable/Readme.txt +11 -0
  134. data/vendor/datatable/extras/TableTools/media/css/TableTools.css +264 -0
  135. data/vendor/datatable/extras/TableTools/media/css/TableTools_JUI.css +182 -0
  136. data/vendor/datatable/extras/TableTools/media/images/background.png +0 -0
  137. data/vendor/datatable/extras/TableTools/media/images/collection.png +0 -0
  138. data/vendor/datatable/extras/TableTools/media/images/collection_hover.png +0 -0
  139. data/vendor/datatable/extras/TableTools/media/images/copy.png +0 -0
  140. data/vendor/datatable/extras/TableTools/media/images/copy_hover.png +0 -0
  141. data/vendor/datatable/extras/TableTools/media/images/csv.png +0 -0
  142. data/vendor/datatable/extras/TableTools/media/images/csv_hover.png +0 -0
  143. data/vendor/datatable/extras/TableTools/media/images/pdf.png +0 -0
  144. data/vendor/datatable/extras/TableTools/media/images/pdf_hover.png +0 -0
  145. data/vendor/datatable/extras/TableTools/media/images/print.png +0 -0
  146. data/vendor/datatable/extras/TableTools/media/images/print_hover.png +0 -0
  147. data/vendor/datatable/extras/TableTools/media/images/xls.png +0 -0
  148. data/vendor/datatable/extras/TableTools/media/images/xls_hover.png +0 -0
  149. data/vendor/datatable/extras/TableTools/media/js/TableTools.js +2410 -0
  150. data/vendor/datatable/extras/TableTools/media/js/TableTools.min.js +78 -0
  151. data/vendor/datatable/extras/TableTools/media/js/TableTools.min.js.gz +0 -0
  152. data/vendor/datatable/extras/TableTools/media/js/ZeroClipboard.js +365 -0
  153. data/vendor/datatable/extras/TableTools/media/swf/copy_cvs_xls.swf +0 -0
  154. data/vendor/datatable/extras/TableTools/media/swf/copy_cvs_xls_pdf.swf +0 -0
  155. data/vendor/datatable/license-bsd.txt +10 -0
  156. data/vendor/datatable/license-gpl2.txt +339 -0
  157. data/vendor/datatable/media/css/demo_page.css +99 -0
  158. data/vendor/datatable/media/css/demo_table.css +539 -0
  159. data/vendor/datatable/media/css/demo_table_jui.css +521 -0
  160. data/vendor/datatable/media/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  161. data/vendor/datatable/media/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  162. data/vendor/datatable/media/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  163. data/vendor/datatable/media/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  164. data/vendor/datatable/media/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  165. data/vendor/datatable/media/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  166. data/vendor/datatable/media/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  167. data/vendor/datatable/media/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  168. data/vendor/datatable/media/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
  169. data/vendor/datatable/media/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  170. data/vendor/datatable/media/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
  171. data/vendor/datatable/media/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
  172. data/vendor/datatable/media/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  173. data/vendor/datatable/media/css/smoothness/jquery-ui-1.8.14.custom.css +568 -0
  174. data/vendor/datatable/media/images/back_disabled.jpg +0 -0
  175. data/vendor/datatable/media/images/back_enabled.jpg +0 -0
  176. data/vendor/datatable/media/images/favicon.ico +0 -0
  177. data/vendor/datatable/media/images/forward_disabled.jpg +0 -0
  178. data/vendor/datatable/media/images/forward_enabled.jpg +0 -0
  179. data/vendor/datatable/media/images/sort_asc.png +0 -0
  180. data/vendor/datatable/media/images/sort_asc_disabled.png +0 -0
  181. data/vendor/datatable/media/images/sort_both.png +0 -0
  182. data/vendor/datatable/media/images/sort_desc.png +0 -0
  183. data/vendor/datatable/media/images/sort_desc_disabled.png +0 -0
  184. data/vendor/datatable/media/js/jquery-ui-1.8.14.custom.min.js +789 -0
  185. data/vendor/datatable/media/js/jquery.dataTables.js +7347 -0
  186. data/vendor/datatable/media/js/jquery.dataTables.min.js +151 -0
  187. metadata +270 -0
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Generating sql based on our DSL' do
4
+
5
+ # it 'should work' do
6
+ # Order.create!(:order_number => 32)
7
+ # datatable = OrdersIndex.new
8
+ # params = {}
9
+ # json = datatable.query(params).json
10
+ # json['aaRecords'][0][0].should == 32
11
+ # end
12
+
13
+ it 'should select two fields' do
14
+ class OrdersSimple < Datatable::Base
15
+ set_model Order
16
+
17
+ column :order_number
18
+ column :memo
19
+ end
20
+
21
+ orders = Order.arel_table
22
+ OrdersSimple.to_sql.should == Order.select(orders[:order_number]).select(orders[:memo]).to_sql
23
+ OrdersSimple.relation.should == Order.select(orders[:order_number]).select(orders[:memo])
24
+ end
25
+
26
+ it 'should handle a simple join' do
27
+ class OrdersSimple < Datatable::Base
28
+ set_model Order
29
+
30
+ column :memo
31
+
32
+ join :customer
33
+ end
34
+
35
+ orders = Order.arel_table
36
+ OrdersSimple.to_sql.should == Order.select(orders[:memo]).joins(:customer).to_sql
37
+ OrdersSimple.relation.should == Order.select(orders[:memo]).joins(:customer)
38
+ end
39
+
40
+ it 'should handle a join with an inner column' do
41
+ class OrdersSimple < Datatable::Base
42
+ set_model Order
43
+
44
+ column :memo
45
+
46
+ join :customer do
47
+ column :first_name
48
+ end
49
+
50
+ end
51
+
52
+ orders = Order.arel_table
53
+ customers = Arel::Table.new(:customers)
54
+ OrdersSimple.to_sql.should == Order.select(orders[:memo]).joins(:customer).select(customers[:first_name]).to_sql
55
+ OrdersSimple.relation.should == Order.select(orders[:memo]).joins(:customer).select(customers[:first_name])
56
+ end
57
+
58
+ end
59
+
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'adding links to active record datatables' do
4
+
5
+ before do
6
+ Object.send(:remove_const, :T) rescue nil
7
+ class T < Datatable::Base
8
+ set_model Order
9
+ column :id, :link_to => link_to('{{0}}', order_path('{{0}}'))
10
+ end
11
+ @params = {
12
+ 'iColumns' => 1,
13
+ "bSearchable_0" => true
14
+ }
15
+ end
16
+
17
+ it "adding link_to in block adds it to the column" do
18
+ t = T.query(@params)
19
+ T.columns['orders.id'][:link_to].should == "<a href=\"/orders/%7B%7B0%7D%7D\">{{0}}</a>"
20
+ end
21
+
22
+ end
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'basic query params and pagination' do
4
+
5
+ before do
6
+ class OrdersSimple < Datatable::Base
7
+ set_model Order
8
+ column :id
9
+ column :memo
10
+ join :customer do
11
+ column :first_name
12
+ end
13
+ end
14
+ @params = {}
15
+
16
+ @params['iColumns'] = 3
17
+
18
+ end
19
+
20
+ it "sEcho" do
21
+ echo = rand(239823)
22
+ params = {'sEcho' => echo }
23
+ OrdersSimple.new(params).to_json['sEcho'].should == echo
24
+ end
25
+
26
+ it 'should return the number of records when there are no records' do
27
+ OrdersSimple.new.to_json['iTotalRecords'].should == 0
28
+ OrdersSimple.new.to_json['iTotalDisplayRecords'].should == 0
29
+ end
30
+
31
+ it 'should return the number of records' do
32
+ 3.times{ Factory(:order) }
33
+ OrdersSimple.query(@params).to_json['iTotalRecords'].should == 3
34
+ OrdersSimple.query(@params).to_json['iTotalDisplayRecords'].should == 3
35
+ end
36
+
37
+ it 'should return valid aaData' do
38
+ class OrdersComplex < Datatable::Base
39
+ set_model Order
40
+ column :order_number
41
+ column :memo
42
+ join :customer do
43
+ column :first_name
44
+ end
45
+ end
46
+ @params['iColumns'] = 3
47
+
48
+ orders = [Factory(:order), Factory(:order)]
49
+ OrdersComplex.query(@params).to_json['aaData'].should == orders.map { |o| [o.order_number.to_s, o.memo, o.customer.first_name]}
50
+ end
51
+
52
+ it 'should return valid aaData in different order' do
53
+ class OrdersComplex < Datatable::Base
54
+ set_model Order
55
+ column :memo
56
+ column :order_number
57
+ end
58
+ @params['iColumns'] = 2
59
+ orders = [Factory(:order), Factory(:order)]
60
+ OrdersComplex.query(@params).to_json['aaData'].should == orders.map { |o| [o.memo, o.order_number.to_s]}
61
+ end
62
+
63
+ it "should provide first page" do
64
+ class OrdersComplex2 < Datatable::Base
65
+ set_model Order
66
+ column :id
67
+ end
68
+ @params['iColumns'] = 1
69
+
70
+ @params['iDisplayStart'] = 0
71
+ @params['iDisplayLength'] = 2
72
+ orders = [Factory(:order), Factory(:order), Factory(:order), Factory(:order)]
73
+ OrdersComplex2.query(@params).to_json['iTotalRecords'].should == 2
74
+ OrdersComplex2.query(@params).to_json['iTotalDisplayRecords'].should == 4
75
+ OrdersComplex2.query(@params).to_json['aaData'].should == orders[0..1].map {|o| [o.id.to_s] }
76
+ end
77
+
78
+ it "should provide second page" do
79
+ class OrdersComplex3 < Datatable::Base
80
+ set_model Order
81
+ column :id
82
+ end
83
+
84
+ @params['iColumns'] = 1
85
+ @params['iDisplayStart'] = 2
86
+ @params['iDisplayLength'] = 2
87
+
88
+ orders = [Factory(:order), Factory(:order), Factory(:order), Factory(:order)]
89
+ OrdersComplex3.query(@params).to_json['iTotalRecords'].should == 2
90
+ OrdersComplex3.query(@params).to_json['iTotalDisplayRecords'].should == 4
91
+ OrdersComplex3.query(@params).to_json['aaData'].should == Order.all[2..3].map {|o| [o.id.to_s] }
92
+ end
93
+
94
+ end
@@ -0,0 +1,180 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Operations on the ActiveRecord table' do
4
+ # Store/ retrive:
5
+ # data type
6
+ # ordering
7
+ # human title
8
+
9
+
10
+ # Column sorting
11
+ # input: an index to be sorted on
12
+ # array of columns to sort on and asc/desc
13
+ # [['asc', 1], ['desc', 3]]
14
+ #
15
+ # need to know what index a column is
16
+ # and from that index need to know the column name
17
+ # sometimes will need the table name
18
+
19
+ # Pass in params for sorting by various columns in various orders
20
+ # Test that records are returned in the correct order
21
+
22
+ before do
23
+ Object.send(:remove_const, :T) rescue nil
24
+
25
+ class T < Datatable::Base
26
+ set_model Order
27
+ column :id
28
+ column :order_number
29
+ column :memo
30
+ end
31
+
32
+ @params = {
33
+ "iColumns" => 4,
34
+ "bSearchable_0" => true,
35
+ "bSearchable_1" => true,
36
+ "bSearchable_2" => true,
37
+ "bSearchable_3" => true,
38
+ "bSortable_0" => true,
39
+ "bSortable_1" => true,
40
+ "bSortable_2" => true,
41
+ "bSortable_3" => true,
42
+ "sSearch_0" => nil,
43
+ "sSearch_1" => nil,
44
+ "sSearch_2" => nil,
45
+ "sSearch_3" => nil,
46
+ "sSearch" => nil }
47
+
48
+ Order.delete_all
49
+ @orders = [*0..20].map do
50
+ Factory(:order, :order_number => rand(2), :memo => rand(2).even? ? 'hello' : 'goodbye')
51
+ end
52
+ end
53
+
54
+ it 'should sort by one column' do
55
+ @params['iSortCol_0'] = 0
56
+ @params['sSortDir_0'] = 'desc' # Assume first col is ID
57
+ @params['iSortingCols'] = 1
58
+ T.query(@params).to_json['aaData'][0][0].should == Order.order("id desc").first.id.to_s
59
+ end
60
+
61
+ it 'should sort by multiple columns' do
62
+ @params['iSortCol_0'] = 2 # Memo
63
+ @params['sSortDir_0'] = 'asc'
64
+
65
+ @params['iSortCol_1'] = 0 # ID
66
+ @params['sSortDir_1'] = 'desc'
67
+
68
+ @params['iSortingCols'] = 2
69
+
70
+
71
+ T.query(@params).to_json['aaData'][0][0].should == Order.order('memo asc, id desc')[0].id.to_s
72
+ T.query(@params).to_json['aaData'][-1][0].should == Order.order('memo asc, id desc')[-1].id.to_s
73
+ end
74
+
75
+ it 'should sort ascending and descending' do
76
+ @params['iSortCol_0'] = 2 # Memo
77
+ @params['sSortDir_0'] = 'desc'
78
+
79
+ @params['iSortCol_1'] = 0 # ID
80
+ @params['sSortDir_1'] = 'asc'
81
+
82
+ @params['iSortingCols'] = 2
83
+
84
+
85
+ T.query(@params).to_json['aaData'][0][0].should == Order.order('memo desc, id asc')[0].id.to_s
86
+ T.query(@params).to_json['aaData'][-1][0].should == Order.order('memo desc, id asc')[-1].id.to_s
87
+ end
88
+
89
+ # Multi column searching
90
+ # input: a search term
91
+ # a way to search on all of the columns that are searchable
92
+ # need to know the datatype of whats in the columns
93
+ it 'should global search' do
94
+ # Assume memo and id are searchable
95
+ ## Pass in params for searching by the columns that are searchable
96
+ # Define which columns are searchable
97
+ # search using OR for each of those cols
98
+ # E.g. where int = num OR string LIKE str
99
+ # Types
100
+ end
101
+
102
+ it 'should global search string' do
103
+ # Memo is searchable
104
+ @params['sSearch'] = 'hel'
105
+ T.query(@params).to_json['aaData'][0][0].should == Order.where('memo LIKE ?', '%hel%')[0].id.to_s
106
+ T.query(@params).to_json['aaData'][0].map(&:first).should_not include(Order.where('memo NOT LIKE ?', '%hel%').map(&:id).map(&:to_s))
107
+ end
108
+
109
+ it 'should global search integer' do
110
+ # Id
111
+ order_id = Order.all[rand(Order.count)].id.to_s
112
+ @params['sSearch'] = order_id
113
+ T.query(@params).to_json['aaData'][0][0].should == order_id
114
+ T.query(@params).to_json['aaData'].length.should == 1
115
+ end
116
+
117
+ # Maybe: Test multiple results for integer
118
+
119
+ it 'should only search columns that are searchable' do
120
+ # ORder number is NOT searchable
121
+ # we need to make one value exist in 2 columsn for the test
122
+ #
123
+ Order.last.update_attribute(:order_number, Order.first.id)
124
+ @params['bSearchable_1'] = false
125
+ @params['sSearch'] = Order.first.id
126
+ T.query(@params).to_json['aaData'][0][0].should == Order.first.id.to_s
127
+ T.query(@params).to_json['aaData'].length.should == 1
128
+ end
129
+
130
+ it "shouldn't barf when no columns are searchable" do
131
+ @params['bSearchable_0'] = false
132
+ @params['bSearchable_1'] = false
133
+ @params['bSearchable_2'] = false
134
+ @params['sSearch'] = "foo"
135
+ T.query(@params)
136
+ end
137
+
138
+ # TODO
139
+ # it 'should deal w/ dates'
140
+
141
+ # Individual column searching
142
+ # input: index and a search term
143
+ # need to know what index a col is and the col name
144
+ # need to know the type
145
+ it 'should search by one string column' do
146
+ @params['bSearchable_2'] = true # col2 = memo
147
+ @params['sSearch_2'] = "hello"
148
+ T.query(@params).to_json['aaData'].length.should == Order.where('memo LIKE ?', '%hello%').count
149
+ T.query(@params).to_json['aaData'].map { |r| r[2] }.uniq.should == ['hello']
150
+ end
151
+
152
+ it 'should search by one integer column' do
153
+ @params['bSearchable_1'] = true
154
+ @params['sSearch_1'] = "1"
155
+ T.query(@params).to_json['aaData'].length.should == Order.where(:order_number => 1).count
156
+ T.query(@params).to_json['aaData'].map { |r| r[1] }.uniq.should == ["1"]
157
+ end
158
+
159
+ it 'should search by multiple columns' do
160
+ @params['bSearchable_1'] = true
161
+ @params['sSearch_1'] = "1"
162
+ @params['bSearchable_2'] = true
163
+ @params['sSearch_2'] = "hello"
164
+ T.query(@params).to_json['aaData'].length.should == Order.where('memo LIKE ?', '%hello%').where(:order_number => 1).count
165
+ T.query(@params).to_json['aaData'].map { |r| r[2] }.uniq.should == ['hello']
166
+ T.query(@params).to_json['aaData'].map { |r| r[1] }.uniq.should == ["1"]
167
+ end
168
+
169
+ it 'only searches - when someone actually types 0'
170
+
171
+ # Column ordering (store/retrieve)
172
+ # column names in order
173
+ # sometimes will need to have the table name
174
+ # ['col.table', 'col.table']
175
+ # {'table.column' => :string, ...}
176
+ it 'should allow manually setting the order of columns'
177
+ it 'should otherwise automatically set the order' # E.g. arel
178
+
179
+ end
180
+
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'config' do
4
+ it "shouldn't blow up when I call Datatable.config" do
5
+ Datatable::Base.config do |config|
6
+ config.foo = "bar"
7
+ end
8
+ Datatable::Base.config.foo.should == "bar"
9
+ end
10
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'sanitize all parameters used in sql' do
4
+
5
+ before do
6
+ Object.send(:remove_const, :T) rescue nil
7
+ class T < Datatable::Base
8
+ sql <<-SQL
9
+ SELECT
10
+ id,
11
+ order_number,
12
+ memo
13
+ FROM
14
+ orders
15
+ SQL
16
+ columns(
17
+ {'orders.id' => {:type => :integer}},
18
+ {'orders.order_number' => {:type => :integer }},
19
+ {'orders.memo' => {:type => :string }}
20
+ )
21
+ end
22
+
23
+ @params = {
24
+ "iColumns" => 3,
25
+ "bSearchable_0" => false,
26
+ "bSearchable_1" => false,
27
+ "bSearchable_2" => false,
28
+ "bSortable_0" => false,
29
+ "bSortable_1" => false,
30
+ "bSortable_2" => false,
31
+ "sSearch_0" => nil,
32
+ "sSearch_1" => nil,
33
+ "sSearch_2" => nil,
34
+ "sSearch" => nil
35
+ }
36
+ Order.delete_all
37
+ 20.times{ Factory(:order) }
38
+ end
39
+
40
+ it "sanitize sSearch" do
41
+ @params['sSearch'] = "'invalid sql"
42
+ T.query(@params).to_json
43
+ lambda{ T.query(@params) }.should_not raise_error
44
+ end
45
+
46
+ it "sanitize sSearch_#" do
47
+ @params['bSearchable_2'] = true
48
+ @params['sSearch_2'] = "'injected sql"
49
+ T.query(@params)
50
+ lambda{ T.query(@params) }.should_not raise_error
51
+ end
52
+
53
+ it "sanitize sSortDir_#" do
54
+ @params['sSortDir_2'] = "'injected sql"
55
+ T.query(@params).to_json
56
+ lambda{ T.query(@params) }.should_not raise_error
57
+ end
58
+
59
+ it "sanitize iDisplayLength" do
60
+ @params['iDisplayLength'] = "'injected sql"
61
+ lambda{ T.query(@params) }.should_not raise_error
62
+ end
63
+
64
+ it "sanitize iDisplayStart" do
65
+ @params['iDisplayStart'] = "'injected sql"
66
+ lambda{ T.query(@params) }.should_not raise_error
67
+ end
68
+
69
+
70
+
71
+
72
+
73
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'default response intelligently when no arguments are provided' do
4
+
5
+ # it's useful to have the datable respond with the first page and without
6
+ # any errors when the json is browsed directly for debugging purposes
7
+
8
+ it "should return default page size" do
9
+ # don't return all data decide on default page size
10
+ end
11
+
12
+ it "should not barf because iColumn is not set" do
13
+ # currently does
14
+ end
15
+
16
+ it "should be able to set the default sort direction" do
17
+ # most views will have an initially defined sort order
18
+ pending
19
+ end
20
+
21
+
22
+ end
@@ -0,0 +1,177 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'pagination with count()' do
4
+
5
+ before do
6
+ Object.send(:remove_const, :T) rescue nil
7
+ class T < Datatable::Base
8
+ count("SELECT COUNT(*) + 100 FROM orders")
9
+ sql("SELECT id FROM orders")
10
+ columns({"orders.id" => {:type => :integer, :link_to => link_to('{{0}}', order_path('{{0}}')) }})
11
+ end
12
+ @params = {
13
+ 'iColumns' => 1,
14
+ "bSearchable_0" => true
15
+ }
16
+ 4.times{ Factory(:order) }
17
+ end
18
+
19
+ describe "first page" do
20
+ before do
21
+ @params['iDisplayStart'] = 0
22
+ @params['iDisplayLength'] = 2
23
+ end
24
+
25
+ it "iTotalRecords correctly set" do
26
+ T.query(@params).to_json['iTotalRecords'].should == 2
27
+ end
28
+
29
+ it "iTotalDisplayRecords correctly set" do
30
+ T.query(@params).to_json['iTotalDisplayRecords'].should == 104
31
+ end
32
+
33
+ it "aaData contains dataset" do
34
+ T.query(@params).to_json['aaData'].should == Order.all[0..1].map {|o| [o.id.to_s] }
35
+ end
36
+ end
37
+
38
+ describe "second page" do
39
+ before do
40
+ @params['iDisplayStart'] = 2
41
+ @params['iDisplayLength'] = 2
42
+ end
43
+
44
+ it "iTotalRecords correctly set" do
45
+ T.query(@params).to_json['iTotalRecords'].should == 2
46
+ end
47
+
48
+ it "iTotalDisplayRecords correctly set" do
49
+ T.query(@params).to_json['iTotalDisplayRecords'].should == 104
50
+ end
51
+
52
+ it "aaData contains dataset" do
53
+ T.query(@params).to_json['aaData'].should == Order.all[2..3].map {|o| [o.id.to_s] }
54
+ end
55
+ end
56
+ end
57
+
58
+ describe 'pagination without count()' do
59
+
60
+ before do
61
+ Object.send(:remove_const, :T) rescue nil
62
+ class T < Datatable::Base
63
+ sql("SELECT id FROM orders")
64
+ columns({"orders.id" => {:type => :integer, :link_to => link_to('{{0}}', order_path('{{0}}')) }})
65
+ end
66
+ @params = {
67
+ 'iColumns' => 1,
68
+ "bSearchable_0" => true
69
+ }
70
+ 4.times{ Factory(:order) }
71
+ end
72
+
73
+ describe "first page" do
74
+ before do
75
+ @params['iDisplayStart'] = 0
76
+ @params['iDisplayLength'] = 2
77
+ end
78
+
79
+ it "iTotalRecords correctly set" do
80
+ T.query(@params).to_json['iTotalRecords'].should == 2
81
+ end
82
+
83
+ it "iTotalDisplayRecords correctly set" do
84
+ T.query(@params).to_json['iTotalDisplayRecords'].should == 4
85
+ end
86
+
87
+ it "aaData contains dataset" do
88
+ T.query(@params).to_json['aaData'].should == Order.all[0..1].map {|o| [o.id.to_s] }
89
+ end
90
+ end
91
+
92
+
93
+ describe "second page" do
94
+ before do
95
+ @params['iDisplayStart'] = 2
96
+ @params['iDisplayLength'] = 2
97
+ end
98
+ it "iTotalRecords correctly set" do
99
+ T.query(@params).to_json['iTotalRecords'].should == 2
100
+ end
101
+
102
+ it "iTotalDisplayRecords correctly set" do
103
+ T.query(@params).to_json['iTotalDisplayRecords'].should == 4
104
+ end
105
+
106
+ it "aaData contains dataset" do
107
+ T.query(@params).to_json['aaData'].should == Order.all[2..3].map {|o| [o.id.to_s] }
108
+ end
109
+ end
110
+
111
+ end
112
+
113
+
114
+ describe 'pagination with count() and where clause' do
115
+ before do
116
+ Object.send(:remove_const, :T) rescue nil
117
+ class T < Datatable::Base
118
+ count("SELECT COUNT(*) + 100 FROM orders")
119
+ sql("SELECT id FROM orders")
120
+ where("memo like 'foo'")
121
+ columns({"orders.id" => {:type => :integer, :link_to => link_to('{{0}}', order_path('{{0}}')) }})
122
+ end
123
+ @params = {
124
+ 'iColumns' => 1,
125
+ "bSearchable_0" => true
126
+ }
127
+ Factory(:order, :memo => 'foo')
128
+ Factory(:order, :memo => 'foo')
129
+ Factory(:order, :memo => 'foo')
130
+ Factory(:order, :memo => 'bar')
131
+ end
132
+
133
+ describe "first page" do
134
+ before do
135
+ @params['iDisplayStart'] = 0
136
+ @params['iDisplayLength'] = 2
137
+ end
138
+
139
+ it "iTotalRecords correctly set" do
140
+ T.query(@params).to_json['iTotalRecords'].should == 2
141
+ end
142
+
143
+ it "iTotalDisplayRecords correctly set" do
144
+ result = T.query(@params).to_json['iTotalDisplayRecords']
145
+ result.should == 103
146
+ end
147
+
148
+ it "aaData contains dataset" do
149
+ expected = Order.where("memo like 'foo'").all[0..1].map {|o| [o.id.to_s] }.sort
150
+ actual = T.query(@params).to_json['aaData'].sort
151
+ actual.should == expected
152
+ end
153
+ end
154
+
155
+ describe "second page" do
156
+ before do
157
+ @params['iDisplayStart'] = 2
158
+ @params['iDisplayLength'] = 2
159
+ end
160
+
161
+ it "iTotalRecords correctly set" do
162
+ T.query(@params).to_json['iTotalRecords'].should == 1
163
+ end
164
+
165
+ it "iTotalDisplayRecords correctly set" do
166
+ T.query(@params).to_json['iTotalDisplayRecords'].should == 103
167
+ end
168
+
169
+ it "aaData contains dataset" do
170
+ expected = Order.where("memo like 'foo'").all[2..3].map {|o| [o.id.to_s] }.sort
171
+ actual = T.query(@params).to_json['aaData'].sort
172
+ actual.should == expected
173
+ end
174
+ end
175
+
176
+ end
177
+
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+
3
+ describe "SQL defined datatable supports searching numbers as strings" do
4
+ pending "select id from orders where cast(id as text) like '%7%';"
5
+ end
6
+