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.
- data/.bundle/config +3 -0
- data/.gitignore +7 -0
- data/.rspec +1 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +83 -0
- data/MIT-LICENSE +20 -0
- data/README.md +135 -0
- data/Rakefile +27 -0
- data/TODO +71 -0
- data/datatable.gemspec +20 -0
- data/example_app/.DS_Store +0 -0
- data/example_app/.gitignore +6 -0
- data/example_app/.rspec +1 -0
- data/example_app/Gemfile +35 -0
- data/example_app/Gemfile.lock +126 -0
- data/example_app/Rakefile +7 -0
- data/example_app/app/controllers/application_controller.rb +3 -0
- data/example_app/app/controllers/orders_controller.rb +13 -0
- data/example_app/app/datatables/orders_index.rb +31 -0
- data/example_app/app/helpers/application_helper.rb +2 -0
- data/example_app/app/models/customer.rb +4 -0
- data/example_app/app/models/item.rb +4 -0
- data/example_app/app/models/order.rb +5 -0
- data/example_app/app/models/order_item.rb +4 -0
- data/example_app/app/models/sales_rep.rb +3 -0
- data/example_app/app/views/layouts/application.html.erb +12 -0
- data/example_app/app/views/orders/index.html.erb +14 -0
- data/example_app/config/application.rb +41 -0
- data/example_app/config/boot.rb +6 -0
- data/example_app/config/database.yml.mysql +20 -0
- data/example_app/config/database.yml.pg +20 -0
- data/example_app/config/environment.rb +5 -0
- data/example_app/config/environments/development.rb +28 -0
- data/example_app/config/environments/production.rb +49 -0
- data/example_app/config/environments/test.rb +35 -0
- data/example_app/config/initializers/backtrace_silencers.rb +7 -0
- data/example_app/config/initializers/datatable.rb +6 -0
- data/example_app/config/initializers/inflections.rb +10 -0
- data/example_app/config/initializers/mime_types.rb +5 -0
- data/example_app/config/initializers/secret_token.rb +9 -0
- data/example_app/config/initializers/session_store.rb +8 -0
- data/example_app/config/locales/en.yml +5 -0
- data/example_app/config/routes.rb +6 -0
- data/example_app/config.ru +4 -0
- data/example_app/db/migrate/20110429185712_create_customers.rb +15 -0
- data/example_app/db/migrate/20110429185742_create_sales_reps.rb +14 -0
- data/example_app/db/migrate/20110429185807_create_items.rb +15 -0
- data/example_app/db/migrate/20110429185913_create_orders.rb +15 -0
- data/example_app/db/migrate/20110429190005_create_order_items.rb +14 -0
- data/example_app/db/schema.rb +53 -0
- data/example_app/db/seeds.rb +49 -0
- data/example_app/lib/tasks/.gitkeep +0 -0
- data/example_app/lib/tasks/setup.rake +12 -0
- data/example_app/public/404.html +26 -0
- data/example_app/public/422.html +26 -0
- data/example_app/public/500.html +26 -0
- data/example_app/public/datatable/css/demo_page.css +99 -0
- data/example_app/public/datatable/css/demo_table.css +539 -0
- data/example_app/public/datatable/css/demo_table_jui.css +521 -0
- data/example_app/public/datatable/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/example_app/public/datatable/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/example_app/public/datatable/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/example_app/public/datatable/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/example_app/public/datatable/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/example_app/public/datatable/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/example_app/public/datatable/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/example_app/public/datatable/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/example_app/public/datatable/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/example_app/public/datatable/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/example_app/public/datatable/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/example_app/public/datatable/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/example_app/public/datatable/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/example_app/public/datatable/css/smoothness/jquery-ui-1.8.14.custom.css +568 -0
- data/example_app/public/datatable/images/back_disabled.jpg +0 -0
- data/example_app/public/datatable/images/back_enabled.jpg +0 -0
- data/example_app/public/datatable/images/favicon.ico +0 -0
- data/example_app/public/datatable/images/forward_disabled.jpg +0 -0
- data/example_app/public/datatable/images/forward_enabled.jpg +0 -0
- data/example_app/public/datatable/images/sort_asc.png +0 -0
- data/example_app/public/datatable/images/sort_asc_disabled.png +0 -0
- data/example_app/public/datatable/images/sort_both.png +0 -0
- data/example_app/public/datatable/images/sort_desc.png +0 -0
- data/example_app/public/datatable/images/sort_desc_disabled.png +0 -0
- data/example_app/public/datatable/js/jquery-ui-1.8.14.custom.min.js +789 -0
- data/example_app/public/datatable/js/jquery.dataTables.js +7347 -0
- data/example_app/public/datatable/js/jquery.dataTables.min.js +151 -0
- data/example_app/public/favicon.ico +0 -0
- data/example_app/public/flash/copy_cvs_xls.swf +0 -0
- data/example_app/public/flash/copy_cvs_xls_pdf.swf +0 -0
- data/example_app/public/images/rails.png +0 -0
- data/example_app/public/javascripts/application.js +2 -0
- data/example_app/public/javascripts/jquery.js +8936 -0
- data/example_app/public/javascripts/jquery.min.js +18 -0
- data/example_app/public/javascripts/jquery_ujs.js +316 -0
- data/example_app/public/robots.txt +5 -0
- data/example_app/public/stylesheets/.gitkeep +0 -0
- data/example_app/script/rails +6 -0
- data/example_app/spec/datatables/active_record_dsl_spec.rb +59 -0
- data/example_app/spec/datatables/active_record_link_to_spec.rb +22 -0
- data/example_app/spec/datatables/active_record_pagination_spec.rb +94 -0
- data/example_app/spec/datatables/active_record_table_operations_spec.rb +180 -0
- data/example_app/spec/datatables/config_spec.rb +10 -0
- data/example_app/spec/datatables/query_params_spec.rb +73 -0
- data/example_app/spec/datatables/sql_default_spec.rb +22 -0
- data/example_app/spec/datatables/sql_pagination_spec.rb +177 -0
- data/example_app/spec/datatables/sql_search_cast_spec.rb +6 -0
- data/example_app/spec/datatables/sql_search_global_spec.rb +107 -0
- data/example_app/spec/datatables/sql_search_individual_spec.rb +113 -0
- data/example_app/spec/datatables/sql_search_where_spec.rb +87 -0
- data/example_app/spec/datatables/sql_sorting_spec.rb +80 -0
- data/example_app/spec/datatables/sql_variables_spec.rb +104 -0
- data/example_app/spec/factories/customer_factory.rb +4 -0
- data/example_app/spec/factories/item_factory.rb +2 -0
- data/example_app/spec/factories/order_factory.rb +7 -0
- data/example_app/spec/factories/order_item_factory.rb +2 -0
- data/example_app/spec/factories/sales_rep_factory.rb +4 -0
- data/example_app/spec/helpers/aocolumn_spec.rb +239 -0
- data/example_app/spec/helpers/data_table_helper_spec.rb +148 -0
- data/example_app/spec/helpers/headings_spec.rb +71 -0
- data/example_app/spec/spec_helper.rb +29 -0
- data/generators.txt +6 -0
- data/images/datatable_screenshot.png +0 -0
- data/lib/datatable/active_record_dsl.rb +49 -0
- data/lib/datatable/errors.rb +5 -0
- data/lib/datatable/helper.rb +199 -0
- data/lib/datatable/railtie.rb +17 -0
- data/lib/datatable/version.rb +4 -0
- data/lib/datatable.rb +341 -0
- data/lib/generators/datatable/install_generator.rb +58 -0
- data/lib/generators/datatable/new_generator.rb +46 -0
- data/lib/generators/templates/datatable.rb +33 -0
- data/lib/generators/templates/datatable_initializer.rb +6 -0
- data/vendor/datatable/Readme.txt +11 -0
- data/vendor/datatable/extras/TableTools/media/css/TableTools.css +264 -0
- data/vendor/datatable/extras/TableTools/media/css/TableTools_JUI.css +182 -0
- data/vendor/datatable/extras/TableTools/media/images/background.png +0 -0
- data/vendor/datatable/extras/TableTools/media/images/collection.png +0 -0
- data/vendor/datatable/extras/TableTools/media/images/collection_hover.png +0 -0
- data/vendor/datatable/extras/TableTools/media/images/copy.png +0 -0
- data/vendor/datatable/extras/TableTools/media/images/copy_hover.png +0 -0
- data/vendor/datatable/extras/TableTools/media/images/csv.png +0 -0
- data/vendor/datatable/extras/TableTools/media/images/csv_hover.png +0 -0
- data/vendor/datatable/extras/TableTools/media/images/pdf.png +0 -0
- data/vendor/datatable/extras/TableTools/media/images/pdf_hover.png +0 -0
- data/vendor/datatable/extras/TableTools/media/images/print.png +0 -0
- data/vendor/datatable/extras/TableTools/media/images/print_hover.png +0 -0
- data/vendor/datatable/extras/TableTools/media/images/xls.png +0 -0
- data/vendor/datatable/extras/TableTools/media/images/xls_hover.png +0 -0
- data/vendor/datatable/extras/TableTools/media/js/TableTools.js +2410 -0
- data/vendor/datatable/extras/TableTools/media/js/TableTools.min.js +78 -0
- data/vendor/datatable/extras/TableTools/media/js/TableTools.min.js.gz +0 -0
- data/vendor/datatable/extras/TableTools/media/js/ZeroClipboard.js +365 -0
- data/vendor/datatable/extras/TableTools/media/swf/copy_cvs_xls.swf +0 -0
- data/vendor/datatable/extras/TableTools/media/swf/copy_cvs_xls_pdf.swf +0 -0
- data/vendor/datatable/license-bsd.txt +10 -0
- data/vendor/datatable/license-gpl2.txt +339 -0
- data/vendor/datatable/media/css/demo_page.css +99 -0
- data/vendor/datatable/media/css/demo_table.css +539 -0
- data/vendor/datatable/media/css/demo_table_jui.css +521 -0
- data/vendor/datatable/media/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/vendor/datatable/media/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/vendor/datatable/media/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/vendor/datatable/media/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/vendor/datatable/media/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/vendor/datatable/media/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/vendor/datatable/media/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/vendor/datatable/media/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/vendor/datatable/media/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/vendor/datatable/media/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/vendor/datatable/media/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/vendor/datatable/media/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/vendor/datatable/media/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/vendor/datatable/media/css/smoothness/jquery-ui-1.8.14.custom.css +568 -0
- data/vendor/datatable/media/images/back_disabled.jpg +0 -0
- data/vendor/datatable/media/images/back_enabled.jpg +0 -0
- data/vendor/datatable/media/images/favicon.ico +0 -0
- data/vendor/datatable/media/images/forward_disabled.jpg +0 -0
- data/vendor/datatable/media/images/forward_enabled.jpg +0 -0
- data/vendor/datatable/media/images/sort_asc.png +0 -0
- data/vendor/datatable/media/images/sort_asc_disabled.png +0 -0
- data/vendor/datatable/media/images/sort_both.png +0 -0
- data/vendor/datatable/media/images/sort_desc.png +0 -0
- data/vendor/datatable/media/images/sort_desc_disabled.png +0 -0
- data/vendor/datatable/media/js/jquery-ui-1.8.14.custom.min.js +789 -0
- data/vendor/datatable/media/js/jquery.dataTables.js +7347 -0
- data/vendor/datatable/media/js/jquery.dataTables.min.js +151 -0
- 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,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
|
+
|