datatable 0.1.0alpha2

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