visual_query 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +59 -0
- data/Rakefile +23 -0
- data/app/assets/images/visual_query/ajax-loader.gif +0 -0
- data/app/assets/javascripts/visual_query/index.js +288 -0
- data/app/assets/stylesheets/visual_query/visual_query.css +161 -0
- data/app/controllers/queries_controller.rb +157 -0
- data/app/helpers/application_helper.rb +5 -0
- data/app/helpers/queries_helper.rb +43 -0
- data/app/views/queries/_columns.html.erb +5 -0
- data/app/views/queries/_command.html.erb +5 -0
- data/app/views/queries/_command_results_browser.html.erb +1 -0
- data/app/views/queries/_command_save.html.erb +1 -0
- data/app/views/queries/_commands_results.html.erb +2 -0
- data/app/views/queries/_filter.html.erb +6 -0
- data/app/views/queries/_list_all_relations.html.erb +8 -0
- data/app/views/queries/_list_joinable_relations.html.erb +10 -0
- data/app/views/queries/_list_relation.html.erb +8 -0
- data/app/views/queries/_name.html.erb +8 -0
- data/app/views/queries/_results.html.erb +14 -0
- data/app/views/queries/_results_column_filter.html.erb +3 -0
- data/app/views/queries/_results_column_hide.html.erb +3 -0
- data/app/views/queries/_results_column_human_name.html.erb +8 -0
- data/app/views/queries/_results_empty.html.erb +3 -0
- data/app/views/queries/_sort.html.erb +12 -0
- data/app/views/queries/_sort_condition.html.erb +18 -0
- data/app/views/queries/_url_root.html.erb +1 -0
- data/app/views/queries/_warning_large_result_set.html.erb +12 -0
- data/app/views/queries/filters/_boolean.html.erb +6 -0
- data/app/views/queries/filters/_date.html.erb +17 -0
- data/app/views/queries/filters/_datetime.html.erb +1 -0
- data/app/views/queries/filters/_decimal.html.erb +1 -0
- data/app/views/queries/filters/_integer.html.erb +1 -0
- data/app/views/queries/filters/_numeric.html.erb +6 -0
- data/app/views/queries/filters/_string.html.erb +1 -0
- data/app/views/queries/filters/_text.html.erb +6 -0
- data/app/views/queries/index.html.erb +39 -0
- data/app/views/queries/new.html.erb +27 -0
- data/app/views/queries/not_found.html.erb +1 -0
- data/app/views/queries/show.html.erb +40 -0
- data/app/views/queries/sql_form.html.erb +16 -0
- data/config/initializers/visual_query.rb +11 -0
- data/config/routes.rb +26 -0
- data/db/migrate/20130927090319_create_visual_query_schema.rb +9 -0
- data/db/migrate/20130927090400_create_visual_query_metadata_table.rb +16 -0
- data/lib/tasks/visual_query_tasks.rake +12 -0
- data/lib/tutuf/visual_query.rb +6 -0
- data/lib/tutuf/visual_query/base.rb +268 -0
- data/lib/tutuf/visual_query/common.rb +58 -0
- data/lib/tutuf/visual_query/metadata.rb +35 -0
- data/lib/tutuf/visual_query/single.rb +111 -0
- data/lib/tutuf/visual_query/sql.rb +20 -0
- data/lib/visual_query.rb +4 -0
- data/lib/visual_query/engine.rb +4 -0
- data/lib/visual_query/version.rb +3 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/account.rb +3 -0
- data/test/dummy/app/models/address.rb +3 -0
- data/test/dummy/app/models/category.rb +3 -0
- data/test/dummy/app/models/composite_pk.rb +3 -0
- data/test/dummy/app/models/customer.rb +4 -0
- data/test/dummy/app/models/order.rb +4 -0
- data/test/dummy/app/models/person.rb +4 -0
- data/test/dummy/app/models/post.rb +3 -0
- data/test/dummy/app/models/product.rb +4 -0
- data/test/dummy/app/models/product_in.rb +3 -0
- data/test/dummy/app/models/product_out.rb +3 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +53 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +12 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +29 -0
- data/test/dummy/config/environments/production.rb +65 -0
- data/test/dummy/config/environments/test.rb +33 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/visual_query.rb +1 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/db/migrate/20130927112446_create_tables.rb +77 -0
- data/test/dummy/db/structure.sql +651 -0
- data/test/dummy/log/development.log +1548 -0
- data/test/dummy/log/test.log +36575 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/-h/-hj2e_RSTanfbfrP0tso5Q7actRM6_clE5hetFlQ2y8.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/3B/3B_zqoNDfkO8wvAME66zxm9KzQaeDVSjnH0qC08yufM.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/5g/5g7dhxVp4YbZmFw_-T3aU2oYq2Z9Jgtps0CKneXYSS0.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/6-/6-CtZO6uG0yfwU8-098Sdy2wnfO0W6DbFu6B6DKYuiw.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/8k/8kFIVN4cTS9KCQt_UIF5s_rcY-bMYlQpM489D98hvP4.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Au/AukU7t3xLnyCh7qW4u45q9YFmjVcYujmIFbnaOhF4Mo.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Bm/Bmsq0vYQqlrtfq5s-W8kcfLvwcsPT_6_5XxXt9J_QOw.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/CQ/CQLNg7a2TsUWgc7JXjDkjseMig_dPVm6AvqO2IWk5zg.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/FX/FX9ZXN3HEHR5hPzvxW8rakWEt2ot4IPJyDB67O7KPZk.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Hv/HvOStITEkFHlcJCgaDnND6wzPw4dMmdAdZB1Xm6JfSA.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/NW/NWCtuFzfIgixavqY71NIAa4ajbsXxRuiLNjceHgQ24M.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Ta/TaG641Ow168nkagg10mh6zuWS8RwWuawpHuMGakCVjU.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/VN/VNCapNKJLeponthNeFJhaBYs92UBT3P8PugENHP0474.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/VR/VRi0Hz7tc62H5Of9XVjyAk7vSNmMr8xeYowo6lSBnZg.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Vg/Vgl_u6t3BvczgGi_ZJlyyo7xYSe-GgEshLofx-3QorI.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Vq/VqGJMF3Cpvp3fw2IEIkE2tzdFo_OdcEmxN58BQwbVDY.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/W6/W6DnXCIMHJ2i5hUkEiNeDLroWxW3VU18nq292n5jlts.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Z7/Z7fH8ST-O3GMnDUKvtKHHTSObfH2Nbs0J1QS79i80yE.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Zh/ZhrmuPgfbHthzikN8QSHR0Q0bLtSYS1Bzl9HauWeDfU.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/bY/bYzYCY_bAGQGVGMbcxtKIhUYrgDQhmQVTmK50JrMNb8.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/eT/eTmCDSnc2m9ER5Cn85g84xyTkVLWKLbbwPFQo8eUAIg.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/h-/h-taE7cHlbq76GUb5kHenjih_y66mO0w0lIZs7vY-0s.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ji/jikmiWyu-cXN_ZJ4hgLc3kuCAY-QJY2jmPeXS4_9vZY.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/kC/kCijps52gsNlkYgT2Qzdz9UcSaxhcMGNfNL7MIiWk54.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/kQ/kQt-OsUDJg_sl1be-FqJ6Vhw4XVguw9_msZEwXP0Nh0.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/nd/ndbe-ZZWBqU5gLx5nxauCFvv963Zm3xqVEwVYQ7X_X8.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/q6/q6BYa32YJF11eGVapO4ouNl6gayPIsARgMavlzZmoi0.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/sm/sm7AdmddDYbFx4-eo_y_kaZspanmc-jiJeM8j2DXX5k.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ux/uxPH9lLOW42lEQxJXnBizEObZReD8qkz6Eb6fdS6Ur4.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/wn/wn0ayyM-chRdwEPI11SLkFT-7G2-GcOX8UIIC2kOWLY.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/x7/x7KkTV3ibfIEysLB_ug5bfmnn2VLV_BldukPR3EoPBk.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/xK/xKo0PfDcZuMh8oO-6Gr4j4S8eR2qUNY9Gau4kAxKIH0.cache +1 -0
- data/test/fixtures/accounts.yml +4 -0
- data/test/fixtures/categories.yml +3 -0
- data/test/fixtures/categories_posts.yml +3 -0
- data/test/fixtures/people.yml +8 -0
- data/test/fixtures/posts.yml +8 -0
- data/test/fixtures/product_ins.yml +15 -0
- data/test/fixtures/product_outs.yml +5 -0
- data/test/fixtures/products.yml +6 -0
- data/test/fixtures/saved_queries.rb +7 -0
- data/test/functional/queries_controller_test.rb +267 -0
- data/test/functional/routes_test.rb +111 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/test_helper.rb +15 -0
- data/test/unit/metadata_test.rb +10 -0
- data/test/unit/sql_test.rb +37 -0
- data/test/unit/visual_query_test.rb +648 -0
- metadata +381 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
3
|
+
|
4
|
+
class RoutesTest < ActionController::TestCase
|
5
|
+
def setup
|
6
|
+
super
|
7
|
+
@routes = VisualQuery::Engine.routes
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_root
|
11
|
+
assert_routing({:method => :get, :path => ''},
|
12
|
+
{:controller=>"queries", :action=>"index"})
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_new
|
16
|
+
assert_routing({:method => :get, :path => '/new'},
|
17
|
+
{:controller=>"queries", :action=>"new"})
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_create
|
21
|
+
assert_routing({:method => :post, :path => ''},
|
22
|
+
{:controller=>"queries", :action=>"create"})
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_show
|
26
|
+
assert_routing({:method => :get, :path => '/some_query'},
|
27
|
+
{:controller=>"queries", :action=>"show", :name=>'some_query'})
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_delete
|
31
|
+
assert_routing({:method => :delete, :path => '/some_query'},
|
32
|
+
{:controller=>"queries", :action=>"destroy", :name=>'some_query'})
|
33
|
+
end
|
34
|
+
|
35
|
+
# Rails routing does not escape percent character %
|
36
|
+
#
|
37
|
+
# def test_show_with_special_characters
|
38
|
+
# assert_routing({:method => :get, :path => '/show/Long%20name%20with%20spaces,%20dot.%20and%25'},
|
39
|
+
# {:controller=>"queries", :action=>"show", :name=>"Long name with spaces, dot. and%"})
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# def test_delete_with_special_characters
|
43
|
+
# assert_routing({:method => :delete, :path => '/delete/Long%20name%20with%20spaces,%20dot.%20and%25'},
|
44
|
+
# {:controller=>"queries", :action=>"destroy", :name=>"Long name with spaces, dot. and%"})
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# def test_edit_sql_with_special_characters
|
48
|
+
# assert_routing({:method => :get, :path => '/edit_sql/Long%20name%20with%20spaces%20and%20dot.'},
|
49
|
+
# {:controller=>"queries", :action=>"edit_sql", :name=>"Long name with spaces and dot."})
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# def test_update_sql_with_special_characters
|
53
|
+
# assert_routing({:method => :put, :path => '/update_sql/Long%20name%20with%20spaces%20and%20dot.'},
|
54
|
+
# {:controller=>"queries", :action=>"update_sql", :name=>"Long name with spaces and dot."})
|
55
|
+
# end
|
56
|
+
|
57
|
+
def test_columns
|
58
|
+
assert_routing({:method => :get, :path => '/columns/Person'},
|
59
|
+
{:controller => "queries", :action => 'columns', :klass => 'Person'})
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_list_joinable
|
63
|
+
assert_routing({:method => :get, :path => '/list_joinable/Person'},
|
64
|
+
{:controller => "queries", :action => 'list_joinable', :klass => 'Person'})
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_join_data
|
68
|
+
assert_routing({:method => :get, :path => '/join_data/Person'},
|
69
|
+
{:controller => "queries", :action => 'join_data', :klass => 'Person'})
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_filter
|
73
|
+
assert_routing({:method => :get, :path => '/filter'},
|
74
|
+
{:controller => "queries", :action => 'filter'})
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_remove_filter
|
78
|
+
assert_routing({:method => :get, :path => '/remove_filter'},
|
79
|
+
{:controller => "queries", :action => 'remove_filter'})
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_sort_condition
|
83
|
+
assert_routing({:method => :get, :path => '/sort_condition'},
|
84
|
+
{:controller => "queries", :action => 'sort_condition'})
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_new_sql
|
88
|
+
assert_routing({:method => :get, :path => '/new_sql'},
|
89
|
+
{:controller=>"queries", :action=>"new_sql"})
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_edit_sql
|
93
|
+
assert_routing({:method => :get, :path => '/edit_sql/some_query'},
|
94
|
+
{:controller=>"queries", :action=>"edit_sql", :name => 'some_query'})
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_update_sql
|
98
|
+
assert_routing({:method => :put, :path => '/update_sql/some_query'},
|
99
|
+
{:controller=>"queries", :action=>"update_sql", :name => 'some_query'})
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_results_get
|
103
|
+
assert_routing({:method => :get, :path => '/results/some_query'},
|
104
|
+
{:controller=>"queries", :action=>"results", :name => 'some_query'})
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_results_post
|
108
|
+
assert_routing({:method => :post, :path => '/results/some_query'},
|
109
|
+
{:controller=>"queries", :action=>"results", :name => 'some_query'})
|
110
|
+
end
|
111
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require File.expand_path("../dummy/config/environment.rb", __FILE__)
|
2
|
+
require "rails/test_help"
|
3
|
+
|
4
|
+
# Load test data into the database
|
5
|
+
|
6
|
+
require File.expand_path("../fixtures/saved_queries.rb", __FILE__) if ActiveRecord::Base.connection.select_one("SELECT count(id) FROM tutuf_visual_query_metadata")['count'].to_i == 0
|
7
|
+
|
8
|
+
class ActiveSupport::TestCase
|
9
|
+
include ActiveRecord::TestFixtures
|
10
|
+
self.fixture_path = File.expand_path("../fixtures", __FILE__)
|
11
|
+
self.use_transactional_fixtures = true
|
12
|
+
self.use_instantiated_fixtures = false
|
13
|
+
|
14
|
+
fixtures :all
|
15
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
3
|
+
|
4
|
+
class MetadataTest < ActiveSupport::TestCase
|
5
|
+
def test_params_serialize_to_json_without_escaping_utf8
|
6
|
+
Tutuf::VisualQuery::Base.new('sql' => %{SELECT AVG(age) AS "възраст" FROM people}, 'query' => {'name' => "params_serialization"}).save
|
7
|
+
assert_equal %q!{"sql":"SELECT AVG(age) AS \"възраст\" FROM people","query":{"name":"params_serialization"}}!,
|
8
|
+
ActiveRecord::Base.connection.select_all(%{SELECT params FROM tutuf_visual_query_metadata WHERE name='params_serialization'}).first['params']
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
3
|
+
|
4
|
+
class VisualQueryTest < ActiveSupport::TestCase
|
5
|
+
def test_save_valid_sql_query
|
6
|
+
vqb = Tutuf::VisualQuery::Base.new('sql' => "SELECT AVG(age) AS average_age FROM people", 'query' => {'name' => "new raw sql query"})
|
7
|
+
assert vqb.valid?, "Metadata in test not valid - fix the test"
|
8
|
+
assert vqb.save, "Could not save valid raw sql query"
|
9
|
+
assert_equal ["average_age"], ActiveRecord::Base.connection.columns(%("#{Tutuf::VisualQuery::Base.schema}"."new raw sql query")).map(&:name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_filters
|
13
|
+
vqb = Tutuf::VisualQuery::Base.find_by_name("raw_sql")
|
14
|
+
assert_equal [], vqb.filters
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_results
|
18
|
+
vqb = Tutuf::VisualQuery::Base.new('sql' => "SELECT AVG(age) AS average_age FROM people", 'query' => {'name' => "new raw sql query"})
|
19
|
+
assert !vqb.to_a.empty?, "Results should not be empty"
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_update_sql_valid_when_original_is_sql
|
23
|
+
vqb = Tutuf::VisualQuery::Base.find_by_name('raw_sql')
|
24
|
+
assert vqb.update_sql('sql' => "SELECT MAX(age) AS max_age FROM people")
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_update_sql_valid_when_original_is_visual
|
28
|
+
vqb = Tutuf::VisualQuery::Base.find_by_name('first')
|
29
|
+
assert vqb.update_sql('sql' => "SELECT MAX(age) AS max_age FROM people")
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_update_sql_invalid
|
33
|
+
vqb = Tutuf::VisualQuery::Base.find_by_name('raw_sql')
|
34
|
+
assert !vqb.update_sql('sql' => "SELECT age FROM")
|
35
|
+
assert !vqb.errors.blank?
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,648 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
3
|
+
require 'csv'
|
4
|
+
|
5
|
+
class VisualQueryTest < ActiveSupport::TestCase
|
6
|
+
|
7
|
+
def test_klasses
|
8
|
+
assert_equal [Account, Address, Category, CompositePk, Customer, Order, Person, Post, Product, ProductIn, ProductOut],
|
9
|
+
Tutuf::VisualQuery::Base.klasses
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_joinable_relations_belongs_to
|
13
|
+
reflections = Tutuf::VisualQuery::Base.joinable_relations(Order)
|
14
|
+
assert_equal [ActiveRecord::Reflection::AssociationReflection,ActiveRecord::Reflection::AssociationReflection], reflections.collect{|r| r.class}
|
15
|
+
assert_equal [Customer, Customer], reflections.collect{|r| r.klass}
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_joinable_relations_has_many
|
19
|
+
reflection = Tutuf::VisualQuery::Base.joinable_relations(Customer).first
|
20
|
+
assert_equal Order, reflection.klass
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_joinable_relations_has_one
|
24
|
+
reflections = Tutuf::VisualQuery::Base.joinable_relations(Person).select{|r| r.klass == Address}
|
25
|
+
assert !reflections.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_joinable_relations_has_and_belongs_to_many
|
29
|
+
reflection = Tutuf::VisualQuery::Base.joinable_relations(Post).first
|
30
|
+
assert_equal Category, reflection.klass
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_columns_all_content
|
34
|
+
assert_equal %w(id title body), Tutuf::VisualQuery::Base.columns(Post)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_columns_not_all_content
|
38
|
+
assert_equal %w(id country city street addressable_type), Tutuf::VisualQuery::Base.columns(Address)
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_columns_with_composite_primary_key
|
42
|
+
assert_equal(%W(first_id second_id name), Tutuf::VisualQuery::Base.columns(CompositePk))
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_join_condition_on_belongs_to
|
46
|
+
assert_equal [[{'rel_name' => 'orders', 'col_name' => 'billing_customer_id'}, {'rel_name' => 'customers', 'col_name' => 'id'}]],
|
47
|
+
Tutuf::VisualQuery::Base.join_condition(Order.reflect_on_association(:billing_customer))
|
48
|
+
assert_equal [[{'rel_name' => 'orders', 'col_name' => 'shipping_customer_id'}, {'rel_name' => 'customers', 'col_name' => 'id'}]],
|
49
|
+
Tutuf::VisualQuery::Base.join_condition(Order.reflect_on_association(:shipping_customer))
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_join_condition_on_belongs_to_with_composite_primary_key
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_join_condition_on_has_many
|
56
|
+
assert_equal [[{'rel_name' => 'customers', 'col_name' => 'id'}, {'rel_name' => 'orders', 'col_name' => 'billing_customer_id'}]],
|
57
|
+
Tutuf::VisualQuery::Base.join_condition(Customer.reflect_on_association(:billing_orders))
|
58
|
+
assert_equal [[{'rel_name' => 'customers', 'col_name' => 'id'}, {'rel_name' => 'orders', 'col_name' => 'shipping_customer_id'}]],
|
59
|
+
Tutuf::VisualQuery::Base.join_condition(Customer.reflect_on_association(:shipping_orders))
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_join_condition_on_has_many_with_composite_primary_key
|
63
|
+
end
|
64
|
+
def test_join_condition_on_has_many_with_polymorphic_association
|
65
|
+
end
|
66
|
+
def test_join_condition_on_has_many_with_polymorphic_association_and_with_composite_primary_key
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_join_condition_on_has_one
|
70
|
+
assert_equal [[{'rel_name' => 'people', 'col_name' => 'id'}, {'rel_name' => 'accounts', 'col_name' => 'person_id'}]],
|
71
|
+
Tutuf::VisualQuery::Base.join_condition(Person.reflect_on_association(:account))
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_join_condition_on_has_one_with_composite_primary_key
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_join_condition_on_has_one_with_polymorphic_association
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_join_condition_on_has_one_with_polymorphic_association_and_with_composite_primary_key
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_join_condition_on_has_and_belongs_to_many
|
84
|
+
assert_equal [[{'rel_name' => 'posts', 'col_name' => 'id'}, {'rel_name' => 'categories_posts', 'col_name' => 'post_id'}],
|
85
|
+
[{'rel_name' => 'categories_posts', 'col_name' => 'category_id'}, {'rel_name' => 'categories', 'col_name' => 'id'}]],
|
86
|
+
Tutuf::VisualQuery::Base.join_condition(Post.reflect_on_association(:categories))
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_join_condition_on_has_and_belongs_to_many_with_composite_primary_key
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_join_condition_on_has_and_belongs_to_many_with_polymorphic_association
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_join_condition_on_has_and_belongs_to_many_with_polymorphic_association_and_with_composite_primary_key
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_results_one_relation
|
99
|
+
cols = [{'rel_name' => "people", 'col_name' => "id"},
|
100
|
+
{'rel_name' => "people", 'col_name' => "name"},
|
101
|
+
{'rel_name' => "people", 'col_name' => "age"}]
|
102
|
+
results = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
103
|
+
'all_columns' => cols,
|
104
|
+
'relations' => [{'rel_name' => "people"}]}).to_a
|
105
|
+
person = people(:john)
|
106
|
+
assert results.include?([person.id.to_s, person.name, person.age.to_s])
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_results_two_relations_has_one
|
110
|
+
cols = [{'rel_name' => "people", 'col_name' => "id"},
|
111
|
+
{'rel_name' => "people", 'col_name' => "name"},
|
112
|
+
{'rel_name' => "people", 'col_name' => "age"},
|
113
|
+
{'rel_name' => "accounts", 'col_name' => "id"},
|
114
|
+
{'rel_name' => "accounts", 'col_name' => "name"}]
|
115
|
+
results = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
116
|
+
'all_columns' => cols,
|
117
|
+
'relations' => [{'rel_name' => "people"}, {'rel_name' => "accounts"}],
|
118
|
+
'join_conditions' =>[{'left_rel_name' => "accounts",
|
119
|
+
'left_col_name' => "person_id",
|
120
|
+
'right_rel_name' => "people",
|
121
|
+
'right_col_name' => "id"}]}).to_a
|
122
|
+
person = people(:john)
|
123
|
+
account = accounts(:john)
|
124
|
+
assert_equal [person.id.to_s, person.name, person.age.to_s, account.id.to_s, account.name], results[0]
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_results_two_relations_has_and_belongs_to_many
|
128
|
+
cols = [{'rel_name' => "posts", 'col_name' => "title"},
|
129
|
+
{'rel_name' => "categories", 'col_name' => "name"}]
|
130
|
+
results = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
131
|
+
'all_columns' => cols,
|
132
|
+
'relations' => [{'rel_name' => "posts"},
|
133
|
+
{'rel_name' => "categories"},
|
134
|
+
{'rel_name' => "categories_posts"}],
|
135
|
+
'join_conditions' => [{'left_rel_name' => "posts",
|
136
|
+
'left_col_name' => "id",
|
137
|
+
'right_rel_name' => "categories_posts",
|
138
|
+
'right_col_name' => "post_id"},
|
139
|
+
{'left_rel_name' => "categories_posts",
|
140
|
+
'left_col_name' => "category_id",
|
141
|
+
'right_rel_name' => "categories",
|
142
|
+
'right_col_name' => "id"}]}).to_a
|
143
|
+
category = categories(:first)
|
144
|
+
post = posts(:first)
|
145
|
+
assert_equal [post.title, category.name], results[0]
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_results_two_relations_has_and_belongs_to_many_join_type_full
|
149
|
+
cols = [{'rel_name' => "posts", 'col_name' => "title"},
|
150
|
+
{'rel_name' => "categories", 'col_name' => "name"}]
|
151
|
+
results = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
152
|
+
'all_columns' => cols,
|
153
|
+
'relations' => [{'rel_name' => "posts"},
|
154
|
+
{'rel_name' => "categories"},
|
155
|
+
{'rel_name' => "categories_posts"}],
|
156
|
+
'join_conditions' => [{'left_rel_name' => "posts",
|
157
|
+
'left_col_name' => "id",
|
158
|
+
'right_rel_name' => "categories_posts",
|
159
|
+
'right_col_name' => "post_id",
|
160
|
+
'type' => "FULL"},
|
161
|
+
{'left_rel_name' => "categories_posts",
|
162
|
+
'left_col_name' => "category_id",
|
163
|
+
'right_rel_name' => "categories",
|
164
|
+
'right_col_name' => "id"}]}).to_a
|
165
|
+
category = categories(:first)
|
166
|
+
post = posts(:first)
|
167
|
+
assert_equal [post.title, category.name], results[0]
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_results_two_relations_has_and_belongs_to_many_join_type_invalid
|
171
|
+
cols = [{'rel_name' => "posts", 'col_name' => "title"},
|
172
|
+
{'rel_name' => "categories", 'col_name' => "name"}]
|
173
|
+
results = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
174
|
+
'all_columns' => cols,
|
175
|
+
'relations' => [{'rel_name' => "posts"},
|
176
|
+
{'rel_name' => "categories"},
|
177
|
+
{'rel_name' => "categories_posts"}],
|
178
|
+
'join_conditions' => [{'left_rel_name' => "posts",
|
179
|
+
'left_col_name' => "id",
|
180
|
+
'right_rel_name' => "categories_posts",
|
181
|
+
'right_col_name' => "post_id",
|
182
|
+
'type' => "NO SUCH"},
|
183
|
+
{'left_rel_name' => "categories_posts",
|
184
|
+
'left_col_name' => "category_id",
|
185
|
+
'right_rel_name' => "categories",
|
186
|
+
'right_col_name' => "id"}]}).to_a
|
187
|
+
category = categories(:first)
|
188
|
+
post = posts(:first)
|
189
|
+
assert_equal [post.title, category.name], results[0]
|
190
|
+
end
|
191
|
+
|
192
|
+
def test_results_one_relation_with_filter
|
193
|
+
cols = [{'rel_name' => "people", 'col_name' => "name"}]
|
194
|
+
results = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
195
|
+
'all_columns' => cols,
|
196
|
+
'relations' => [{'rel_name' => "people"}],
|
197
|
+
'filters' => [{'schema' => "public",
|
198
|
+
'rel_name' => "people",
|
199
|
+
'col_name' => "id",
|
200
|
+
'op' => "=",
|
201
|
+
'val' => people(:john).id}]}).to_a
|
202
|
+
assert_equal [[people(:john).name]], results
|
203
|
+
end
|
204
|
+
|
205
|
+
def test_results_with_hidden_columns
|
206
|
+
cols = [{'rel_name' => "people", 'col_name' => "name"},
|
207
|
+
{'rel_name' => "people", 'col_name' => "age"}]
|
208
|
+
results = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
209
|
+
'all_columns' => [{'rel_name' => "people", 'col_name' => "id"}] + cols,
|
210
|
+
'relations' => [{'rel_name' => "people"}]}).to_a
|
211
|
+
person = people(:john)
|
212
|
+
assert results.include?([nil, person.name, person.age.to_s])
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_results_balanced_query
|
216
|
+
cols = [{'rel_name' => "products", 'col_name' => "name"},
|
217
|
+
{'rel_name' => "product_ins", 'col_name' => "quantity"},
|
218
|
+
{'rel_name' => "product_outs", 'col_name' => "quantity"}]
|
219
|
+
results = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
220
|
+
'all_columns' => cols,
|
221
|
+
'relations' => [{'row' => 0, 'rel_name' => 'products'}, {'row' => 0, 'rel_name' => 'product_ins'},
|
222
|
+
{'row' => 1, 'rel_name' => 'products'}, {'row' => 1, 'rel_name' => 'product_outs'}],
|
223
|
+
'join_conditions' =>[{'left_rel_name' => "products", 'left_col_name' => "id",
|
224
|
+
'right_rel_name' => "product_ins", 'right_col_name' => "product_id",
|
225
|
+
'row' => 0},
|
226
|
+
{'left_rel_name' => "products", 'left_col_name' => "id",
|
227
|
+
'right_rel_name' => "product_outs", 'right_col_name' => "product_id",
|
228
|
+
'row' => 1}],
|
229
|
+
'rows' => [0, 1]
|
230
|
+
}).to_a
|
231
|
+
assert results.include?([products(:pencil).name, product_ins(:red_pencil).quantity.to_s, nil])
|
232
|
+
assert results.include?([products(:pencil).name, nil, product_outs(:red_pencil).quantity.to_s])
|
233
|
+
end
|
234
|
+
|
235
|
+
def test_results_balanced_query_with_hidden_columns
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
def query_for_results
|
240
|
+
cols = [{'rel_name' => "people", 'col_name' => "name", 'save_name' => "name"},
|
241
|
+
{'rel_name' => "people", 'col_name' => "age", 'save_name' => "age"}]
|
242
|
+
query = Tutuf::VisualQuery::Base.new('columns' => cols,
|
243
|
+
'all_columns' => cols,
|
244
|
+
'relations' => [{'rel_name'=>"people", 'row' => 0}],
|
245
|
+
'rows' => [0],
|
246
|
+
'query' => {'name' => "query for results"},
|
247
|
+
'action' => "create")
|
248
|
+
query.save
|
249
|
+
query
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_results_saved_query
|
253
|
+
assert_equal [["John Atanasoff", "34"], ["Джон Атанасов", "34"]],
|
254
|
+
query_for_results.to_a
|
255
|
+
end
|
256
|
+
|
257
|
+
def test_to_csv
|
258
|
+
assert_equal "name,age\nJohn Atanasoff,34\nДжон Атанасов,34\n",
|
259
|
+
query_for_results.to_csv
|
260
|
+
end
|
261
|
+
|
262
|
+
def test_to_json_without_escaping
|
263
|
+
assert_equal %q([{"name":"John Atanasoff","age":"34"},{"name":"Джон Атанасов","age":"34"}]),
|
264
|
+
query_for_results.to_json
|
265
|
+
end
|
266
|
+
|
267
|
+
def test_sort_no_direction
|
268
|
+
cols = [{'rel_name' => "people", 'col_name' => "id"}]
|
269
|
+
results = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
270
|
+
'all_columns' => cols,
|
271
|
+
'relations' => [{'rel_name' => "people"}],
|
272
|
+
'sort_conditions' => {"0"=> cols[0]}}).to_a
|
273
|
+
assert_equal [["1"], ["2"]], results[0..1]
|
274
|
+
end
|
275
|
+
|
276
|
+
def test_sort_ascending
|
277
|
+
cols = [{'rel_name' => "people", 'col_name' => "id"}]
|
278
|
+
results = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
279
|
+
'all_columns' => cols,
|
280
|
+
'relations' => [{'rel_name' => "people"}],
|
281
|
+
'sort_conditions' => {"0" => cols[0].merge('direction' => 'ASC')}}).to_a
|
282
|
+
assert_equal [["1"], ["2"]], results[0..1]
|
283
|
+
end
|
284
|
+
|
285
|
+
def test_sort_descending
|
286
|
+
cols = [{'rel_name' => "people", 'col_name' => "id"}]
|
287
|
+
results = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
288
|
+
'all_columns' => cols,
|
289
|
+
'relations' => [{'rel_name' => "people"}],
|
290
|
+
'sort_conditions' => {"0" => cols[0].merge('direction' => 'DESC')}}).to_a
|
291
|
+
assert_equal [["2"], ["1"]], [results[-2], results[-1]]
|
292
|
+
end
|
293
|
+
|
294
|
+
def test_sort_with_empty_condition
|
295
|
+
cols = [{'rel_name' => "people", 'col_name' => "id"}]
|
296
|
+
results = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
297
|
+
'all_columns' => cols,
|
298
|
+
'relations' => [{'rel_name' => "people"}],
|
299
|
+
'sort_conditions' => {"0"=> cols[0],
|
300
|
+
"1"=>{'rel_name' => "", 'col_name' => ""}}}).to_a
|
301
|
+
assert_equal [["1"], ["2"]], results[0..1]
|
302
|
+
end
|
303
|
+
|
304
|
+
def test_sort_sql_injection_in_relation_name
|
305
|
+
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_sort_sql_injection_in_column_name
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_sort_sql_injection_in_direction
|
313
|
+
|
314
|
+
end
|
315
|
+
|
316
|
+
def test_sort_balanced_query
|
317
|
+
cols = [{'rel_name' => "products", 'col_name' => "id"},
|
318
|
+
{'rel_name' => "product_ins", 'col_name' => "buy_price"},
|
319
|
+
{'rel_name' => "product_outs", 'col_name' => "sale_price"}]
|
320
|
+
results = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
321
|
+
'all_columns' => cols,
|
322
|
+
'relations' => [{'row' => 0, 'rel_name' => 'products'}, {'row' => 0, "rel_name" => 'product_ins'},
|
323
|
+
{'row' => 1, 'rel_name' => 'products'}, {'row' => 1, 'rel_name' => 'product_outs'}],
|
324
|
+
'join_conditions' =>[{'left_rel_name' => "products", 'left_col_name' => "id",
|
325
|
+
'right_rel_name' => "product_ins", 'right_col_name' => "product_id",
|
326
|
+
'row' => 0},
|
327
|
+
{'left_rel_name' => "products", 'left_col_name' => "id",
|
328
|
+
'right_rel_name' => "product_outs", 'right_col_name' => "product_id",
|
329
|
+
'row' => 1}],
|
330
|
+
'sort_conditions' => {"0" => {'rel_name' => "products", 'col_name' => "id"},
|
331
|
+
"1" => {'rel_name' => "product_ins", 'col_name' => "id"}},
|
332
|
+
'rows' => [0, 1]
|
333
|
+
}).to_a
|
334
|
+
assert_equal [ [products(:pencil).id.to_s, product_ins(:red_pencil).buy_price.to_s, nil],
|
335
|
+
[products(:pencil).id.to_s, product_ins(:blue_pencil).buy_price.to_s, nil],
|
336
|
+
[products(:bottle).id.to_s, product_ins(:bottle_700_ml).buy_price.to_s, nil],
|
337
|
+
[products(:pencil).id.to_s, nil, product_outs(:red_pencil).sale_price.to_s ]],
|
338
|
+
results[0..3]
|
339
|
+
end
|
340
|
+
|
341
|
+
def test_parsed_filters_with_empty_condition
|
342
|
+
assert_equal %("schema"."relation"."column" >= '2008-06-01'),
|
343
|
+
Tutuf::VisualQuery::Single.new({'filters' => [ { 'schema' => "schema",
|
344
|
+
'rel_name' => "relation",
|
345
|
+
'col_name' => "column",
|
346
|
+
'op' => "<=",
|
347
|
+
'val' => ""},
|
348
|
+
{ 'schema' => "schema",
|
349
|
+
'rel_name' => "relation",
|
350
|
+
'col_name' => "column",
|
351
|
+
'op' => ">=",
|
352
|
+
'val' => "2008-06-01"}]}).parsed_filters
|
353
|
+
end
|
354
|
+
|
355
|
+
def test_parsed_filters_with_all_nonempty_conditions
|
356
|
+
assert_equal %("schema"."relation"."column" <= '2008-07-01' AND "schema"."relation"."column" >= '2008-06-01'),
|
357
|
+
Tutuf::VisualQuery::Single.new({'filters' => [{'schema' => "schema",
|
358
|
+
'rel_name' => "relation",
|
359
|
+
'col_name' => "column",
|
360
|
+
'op' => "<=",
|
361
|
+
'val' => "2008-07-01"},
|
362
|
+
{'schema' => "schema",
|
363
|
+
'rel_name' => "relation",
|
364
|
+
'col_name' => "column",
|
365
|
+
'op' => ">=",
|
366
|
+
'val' => "2008-06-01"}]}).parsed_filters
|
367
|
+
end
|
368
|
+
|
369
|
+
def test_sql_injection_in_columns_semicolon
|
370
|
+
cols = [{'col_name' => %q(name; DELETE FROM schema_info;), 'rel_name' => "people"}]
|
371
|
+
vqb = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
372
|
+
'all_columns' => cols,
|
373
|
+
'relations' => ['rel_name' => "people"]})
|
374
|
+
assert_equal 'SELECT "people"."name; DELETE FROM schema_info;" FROM "people"', vqb.query
|
375
|
+
assert_raise(ActiveRecord::StatementInvalid){vqb.to_a}
|
376
|
+
end
|
377
|
+
|
378
|
+
def test_sql_injection_in_columns_semicolon_and_double_quote
|
379
|
+
cols = [{'col_name' => %q(name"; DELETE FROM schema_info;), 'rel_name' => "people"}]
|
380
|
+
vqb = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
381
|
+
'all_columns' => cols,
|
382
|
+
'relations' => ['rel_name' => "people"]})
|
383
|
+
assert_equal 'SELECT "people"."name""; DELETE FROM schema_info;" FROM "people"', vqb.query
|
384
|
+
assert_raise(ActiveRecord::StatementInvalid){vqb.to_a}
|
385
|
+
end
|
386
|
+
|
387
|
+
def test_sql_injection_in_columns_semicolon_and_backslashed_double_quote
|
388
|
+
cols = [{'col_name' => %q(name\"; DELETE FROM schema_info;), 'rel_name' => "people"}]
|
389
|
+
vqb = Tutuf::VisualQuery::Base.new({'columns' => cols,
|
390
|
+
'all_columns' => cols,
|
391
|
+
'relations' => ['rel_name' => "people"]})
|
392
|
+
assert_equal 'SELECT "people"."name\\""; DELETE FROM schema_info;" FROM "people"', vqb.query
|
393
|
+
assert_raise(ActiveRecord::StatementInvalid){vqb.to_a}
|
394
|
+
end
|
395
|
+
|
396
|
+
def test_sql_injection_in_relations_semicolon
|
397
|
+
vqb = Tutuf::VisualQuery::Base.new({'relations' => ['rel_name' => %q(people; DELETE FROM schema_info;)]})
|
398
|
+
assert_equal 'SELECT FROM "people; DELETE FROM schema_info;"', vqb.query
|
399
|
+
assert_raise(ActiveRecord::StatementInvalid){vqb.to_a}
|
400
|
+
end
|
401
|
+
|
402
|
+
def test_sql_injection_in_relations_semicolon_and_double_quote
|
403
|
+
vqb = Tutuf::VisualQuery::Base.new({'relations' => ['rel_name' => %q(people"; DELETE FROM schema_info;)]})
|
404
|
+
assert_equal 'SELECT FROM "people""; DELETE FROM schema_info;"', vqb.query
|
405
|
+
assert_raise(ActiveRecord::StatementInvalid){vqb.to_a}
|
406
|
+
end
|
407
|
+
|
408
|
+
def test_sql_injection_in_relations_semicolon_and_backslashed_double_quote
|
409
|
+
vqb = Tutuf::VisualQuery::Base.new({'relations' => ['rel_name' => %q(people\"; DELETE FROM schema_info;)]})
|
410
|
+
assert_equal 'SELECT FROM "people\\""; DELETE FROM schema_info;"', vqb.query
|
411
|
+
assert_raise(ActiveRecord::StatementInvalid){vqb.to_a}
|
412
|
+
end
|
413
|
+
|
414
|
+
def test_sql_injection_in_join_conditions
|
415
|
+
|
416
|
+
end
|
417
|
+
|
418
|
+
def test_sql_injection_in_filters_schema
|
419
|
+
|
420
|
+
end
|
421
|
+
|
422
|
+
def test_sql_injection_in_filters_relation
|
423
|
+
|
424
|
+
end
|
425
|
+
|
426
|
+
def test_sql_injection_in_filters_column
|
427
|
+
|
428
|
+
end
|
429
|
+
|
430
|
+
def test_sql_injection_in_filters_operator
|
431
|
+
|
432
|
+
end
|
433
|
+
|
434
|
+
def test_sql_injection_in_filters_value
|
435
|
+
|
436
|
+
end
|
437
|
+
|
438
|
+
def test_columns_all_selected
|
439
|
+
assert_equal %q("rel"."col1","rel"."col2"),
|
440
|
+
Tutuf::VisualQuery::Single.new('columns' => [{'rel_name' => "rel", 'col_name'=>"col1"}, {'rel_name' => "rel", 'col_name'=>"col2"}],
|
441
|
+
'all_columns' => [{'rel_name' => "rel", 'col_name'=>"col1"}, {'rel_name' => "rel", 'col_name'=>"col2"}]).parsed_columns
|
442
|
+
end
|
443
|
+
|
444
|
+
def test_columns_not_all_selected
|
445
|
+
assert_equal %q("rel"."col1",NULL),
|
446
|
+
Tutuf::VisualQuery::Single.new('columns' => [{'rel_name' => "rel", 'col_name'=>"col1"}],
|
447
|
+
'all_columns' => [{'rel_name' => "rel", 'col_name'=>"col1"}, {'rel_name' => "rel", 'col_name'=>"col2"}]).parsed_columns
|
448
|
+
end
|
449
|
+
|
450
|
+
def test_columns_for_saving_selected_not_empty
|
451
|
+
assert_equal %q("rel"."col1" AS "rel:col1"),
|
452
|
+
Tutuf::VisualQuery::Single.new('columns' => [{'rel_name' => "rel", 'col_name'=>"col1", 'save_name' => "rel:col1"}],
|
453
|
+
'all_columns' => [{'rel_name' => "rel", 'col_name'=>"col1"}, {'rel_name' => "rel", 'col_name'=>"col2"}],
|
454
|
+
'action' => "create").parsed_columns
|
455
|
+
end
|
456
|
+
|
457
|
+
def test_columns_for_saving_selected_empty
|
458
|
+
assert_nil Tutuf::VisualQuery::Single.new('action' => "create").parsed_columns
|
459
|
+
assert_nil Tutuf::VisualQuery::Single.new('columns' => [], 'action' => "create").parsed_columns
|
460
|
+
end
|
461
|
+
|
462
|
+
def test_validate_name_cannot_be_empty_string
|
463
|
+
vqb = Tutuf::VisualQuery::Base.new('query' => {'name' => ""})
|
464
|
+
assert !vqb.valid?
|
465
|
+
assert vqb.errors[:name].any?
|
466
|
+
end
|
467
|
+
|
468
|
+
def test_validate_name_cannot_be_nil
|
469
|
+
vqb = Tutuf::VisualQuery::Base.new({})
|
470
|
+
assert !vqb.valid?
|
471
|
+
assert vqb.errors[:name].any?
|
472
|
+
end
|
473
|
+
|
474
|
+
def test_validate_name_cannot_be_more_than_63_chars
|
475
|
+
vqb = Tutuf::VisualQuery::Base.new('query' => {'name' => "z"*64})
|
476
|
+
assert !vqb.valid?
|
477
|
+
assert vqb.errors[:name].any?
|
478
|
+
end
|
479
|
+
|
480
|
+
def test_validate_name_must_be_unique
|
481
|
+
vqb = Tutuf::VisualQuery::Base.new('query' => {'name' => "first"})
|
482
|
+
assert !vqb.valid?
|
483
|
+
assert vqb.errors[:name].any?, "No errors when name is not unique"
|
484
|
+
end
|
485
|
+
|
486
|
+
def test_name_on_new
|
487
|
+
assert_equal "new query", Tutuf::VisualQuery::Base.new('query' => {'name' => "new query"}).name
|
488
|
+
end
|
489
|
+
|
490
|
+
def test_name_on_loading_from_db
|
491
|
+
assert_equal("first", Tutuf::VisualQuery::Base.find_by_name("first").name)
|
492
|
+
end
|
493
|
+
|
494
|
+
def test_is_new_on_new_object
|
495
|
+
assert Tutuf::VisualQuery::Base.new('query' => {'name' => "new query"}).new?
|
496
|
+
end
|
497
|
+
|
498
|
+
def test_is_new_on_existing_object
|
499
|
+
assert !Tutuf::VisualQuery::Base.find_by_name("first").new?
|
500
|
+
end
|
501
|
+
|
502
|
+
def test_save_valid_visual_query
|
503
|
+
vqb = Tutuf::VisualQuery::Base.new('columns' => [{'rel_name' => "addresses", 'col_name' => "country", 'save_name' => "cntr"}],
|
504
|
+
'relations' => [{'rel_name' => "addresses"}],
|
505
|
+
'action' => "create",
|
506
|
+
'query' => {'name' => "new query"})
|
507
|
+
assert vqb.valid?, "Metadata in test not valid - fix the test"
|
508
|
+
assert vqb.save, "Could not save valid query"
|
509
|
+
assert_equal ["cntr"], ActiveRecord::Base.connection.columns(%("#{Tutuf::VisualQuery::Base.schema}"."new query")).map(&:name)
|
510
|
+
end
|
511
|
+
|
512
|
+
def test_save_invalid_metadata_and_valid_sql_generated
|
513
|
+
vqb = Tutuf::VisualQuery::Base.new('relations' => ["people"])
|
514
|
+
assert !vqb.valid?, "Metadata in test valid - fix the test"
|
515
|
+
assert !vqb.save, "Saved although metadata is invalid"
|
516
|
+
end
|
517
|
+
|
518
|
+
def test_save_invalid_metadata_and_invalid_sql_generated
|
519
|
+
metadata_count = Tutuf::VisualQuery::Metadata.count
|
520
|
+
vqb = Tutuf::VisualQuery::Base.new('query' => {'name' => "new query"})
|
521
|
+
assert vqb.valid?, "Metadata in test not valid - fix the test"
|
522
|
+
assert_raises(ActiveRecord::StatementInvalid){vqb.save}
|
523
|
+
assert_equal metadata_count, Tutuf::VisualQuery::Metadata.count, "Metadata saved when query view not saved"
|
524
|
+
end
|
525
|
+
|
526
|
+
def test_save_balanced_query
|
527
|
+
|
528
|
+
end
|
529
|
+
|
530
|
+
def test_find_by_name_existing
|
531
|
+
assert Tutuf::VisualQuery::Base.find_by_name("first")
|
532
|
+
end
|
533
|
+
|
534
|
+
def test_find_by_name_not_existing
|
535
|
+
assert_nil Tutuf::VisualQuery::Base.find_by_name("new query")
|
536
|
+
end
|
537
|
+
|
538
|
+
def test_find_all
|
539
|
+
all_queries = Tutuf::VisualQuery::Base.find_all
|
540
|
+
assert_equal Tutuf::VisualQuery::Metadata.count, all_queries.size, "Number of queries found differs from number of saved metadata"
|
541
|
+
end
|
542
|
+
|
543
|
+
def test_columns_with_name_of_existing_query
|
544
|
+
columns = Tutuf::VisualQuery::Base.find_by_name("first").columns
|
545
|
+
assert_equal "first", columns.first['rel_name']
|
546
|
+
assert_equal "first", columns.first['rel_name']
|
547
|
+
assert_equal "people:age", columns.first['col_name']
|
548
|
+
assert_equal "people:age", columns.first['col_name']
|
549
|
+
end
|
550
|
+
|
551
|
+
def test_columns_with_name_of_nonexisting_query
|
552
|
+
vqb = Tutuf::VisualQuery::Base.new('query' => {'name' => "non existing"})
|
553
|
+
assert vqb.name
|
554
|
+
assert_raises(ActiveRecord::StatementInvalid){vqb.columns}
|
555
|
+
end
|
556
|
+
|
557
|
+
def test_columns_without_query_name
|
558
|
+
assert_nil Tutuf::VisualQuery::Base.new({}).columns
|
559
|
+
end
|
560
|
+
|
561
|
+
def test_schema
|
562
|
+
assert_equal(Tutuf::VisualQuery::Base.new({}).schema, Tutuf::VisualQuery::Base.schema)
|
563
|
+
end
|
564
|
+
|
565
|
+
def test_data_type_existing_column
|
566
|
+
assert_equal(:date, Tutuf::VisualQuery::Base.data_type('rel_name' => "customers", 'col_name' => "created_at"))
|
567
|
+
end
|
568
|
+
|
569
|
+
def test_data_type_exisitng_relation_nonexisting_column
|
570
|
+
assert_nil Tutuf::VisualQuery::Base.data_type('rel_name' => "people", 'col_name' => "non existing")
|
571
|
+
end
|
572
|
+
|
573
|
+
def test_data_type_nonexisitng_relation_nonexisting_column
|
574
|
+
assert_raise(ActiveRecord::StatementInvalid){Tutuf::VisualQuery::Base.data_type('rel_name' => "non existing", 'col_name' => "non existing")}
|
575
|
+
end
|
576
|
+
|
577
|
+
def test_quote_relation_name_with_schema
|
578
|
+
assert_equal(%q("schema"."relation"), Tutuf::VisualQuery::Base.quote_relation_name('schema' => "schema", 'rel_name' => "relation"))
|
579
|
+
end
|
580
|
+
|
581
|
+
def test_quote_relation_name_with_schema_nil
|
582
|
+
assert_equal(%q("relation"), Tutuf::VisualQuery::Base.quote_relation_name('rel_name' => "relation"))
|
583
|
+
end
|
584
|
+
|
585
|
+
def test_quote_relation_name_with_schema_empty
|
586
|
+
assert_equal(%q("relation"), Tutuf::VisualQuery::Base.quote_relation_name('schema' => "", 'rel_name' => "relation"))
|
587
|
+
end
|
588
|
+
|
589
|
+
def test_join_relations_has_and_belongs_to_many
|
590
|
+
assert_equal(["categories_posts", "categories"], Tutuf::VisualQuery::Base.join_relations(Post.reflect_on_association(:categories)))
|
591
|
+
end
|
592
|
+
|
593
|
+
def test_join_relations_has_many
|
594
|
+
assert_equal(["orders"], Tutuf::VisualQuery::Base.join_relations(Customer.reflect_on_association(:billing_orders)))
|
595
|
+
end
|
596
|
+
|
597
|
+
def test_join_relations_has_one
|
598
|
+
assert_equal(["accounts"], Tutuf::VisualQuery::Base.join_relations(Person.reflect_on_association(:account)))
|
599
|
+
end
|
600
|
+
|
601
|
+
def test_join_relations_belongs_to
|
602
|
+
assert_equal(["people"], Tutuf::VisualQuery::Base.join_relations(Account.reflect_on_association(:person)))
|
603
|
+
end
|
604
|
+
|
605
|
+
def test_large_result_set_really_large
|
606
|
+
vqb = Tutuf::VisualQuery::Base.new({})
|
607
|
+
vqb.instance_variable_set("@results", (1..vqb.max_result_length).map{|i| [1] } << [1] )
|
608
|
+
assert vqb.large_result_set?
|
609
|
+
end
|
610
|
+
|
611
|
+
def test_large_result_set_not_really_large
|
612
|
+
vqb = Tutuf::VisualQuery::Base.new({})
|
613
|
+
vqb.instance_variable_set("@results", (1..(vqb.max_result_length - 1)).map{|i| [1] })
|
614
|
+
assert !vqb.large_result_set?
|
615
|
+
end
|
616
|
+
|
617
|
+
def test_large_result_set_nil_results
|
618
|
+
vqb = Tutuf::VisualQuery::Base.new({})
|
619
|
+
assert !vqb.large_result_set?
|
620
|
+
end
|
621
|
+
|
622
|
+
def test_large_result_set_empty_results
|
623
|
+
vqb = Tutuf::VisualQuery::Base.new({})
|
624
|
+
vqb.instance_variable_set("@results", [])
|
625
|
+
assert !vqb.large_result_set?
|
626
|
+
end
|
627
|
+
|
628
|
+
def test_destroy
|
629
|
+
metadata_count = Tutuf::VisualQuery::Metadata.count
|
630
|
+
vqb = Tutuf::VisualQuery::Base.find_by_name("first")
|
631
|
+
assert vqb.destroy
|
632
|
+
assert_equal(metadata_count - 1, Tutuf::VisualQuery::Metadata.count)
|
633
|
+
assert_nil ActiveRecord::Base.connection.select_one("SELECT 1 FROM information_schema.views WHERE table_name='first' AND table_schema='#{Tutuf::VisualQuery::Base.schema}';")
|
634
|
+
end
|
635
|
+
|
636
|
+
def test_disable
|
637
|
+
metadata_count = Tutuf::VisualQuery::Metadata.count
|
638
|
+
Tutuf::VisualQuery::Base.disable
|
639
|
+
assert_equal metadata_count, Tutuf::VisualQuery::Metadata.count
|
640
|
+
assert_nil ActiveRecord::Base.connection.select_one("SELECT 1 FROM information_schema.views WHERE table_schema='#{Tutuf::VisualQuery::Base.schema}'")
|
641
|
+
end
|
642
|
+
|
643
|
+
def test_enable
|
644
|
+
Tutuf::VisualQuery::Base.disable
|
645
|
+
Tutuf::VisualQuery::Base.enable
|
646
|
+
assert ActiveRecord::Base.connection.select_one("SELECT 1 FROM information_schema.views WHERE table_name='first' AND table_schema='#{Tutuf::VisualQuery::Base.schema}';")
|
647
|
+
end
|
648
|
+
end
|