visual_query 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +59 -0
  4. data/Rakefile +23 -0
  5. data/app/assets/images/visual_query/ajax-loader.gif +0 -0
  6. data/app/assets/javascripts/visual_query/index.js +288 -0
  7. data/app/assets/stylesheets/visual_query/visual_query.css +161 -0
  8. data/app/controllers/queries_controller.rb +157 -0
  9. data/app/helpers/application_helper.rb +5 -0
  10. data/app/helpers/queries_helper.rb +43 -0
  11. data/app/views/queries/_columns.html.erb +5 -0
  12. data/app/views/queries/_command.html.erb +5 -0
  13. data/app/views/queries/_command_results_browser.html.erb +1 -0
  14. data/app/views/queries/_command_save.html.erb +1 -0
  15. data/app/views/queries/_commands_results.html.erb +2 -0
  16. data/app/views/queries/_filter.html.erb +6 -0
  17. data/app/views/queries/_list_all_relations.html.erb +8 -0
  18. data/app/views/queries/_list_joinable_relations.html.erb +10 -0
  19. data/app/views/queries/_list_relation.html.erb +8 -0
  20. data/app/views/queries/_name.html.erb +8 -0
  21. data/app/views/queries/_results.html.erb +14 -0
  22. data/app/views/queries/_results_column_filter.html.erb +3 -0
  23. data/app/views/queries/_results_column_hide.html.erb +3 -0
  24. data/app/views/queries/_results_column_human_name.html.erb +8 -0
  25. data/app/views/queries/_results_empty.html.erb +3 -0
  26. data/app/views/queries/_sort.html.erb +12 -0
  27. data/app/views/queries/_sort_condition.html.erb +18 -0
  28. data/app/views/queries/_url_root.html.erb +1 -0
  29. data/app/views/queries/_warning_large_result_set.html.erb +12 -0
  30. data/app/views/queries/filters/_boolean.html.erb +6 -0
  31. data/app/views/queries/filters/_date.html.erb +17 -0
  32. data/app/views/queries/filters/_datetime.html.erb +1 -0
  33. data/app/views/queries/filters/_decimal.html.erb +1 -0
  34. data/app/views/queries/filters/_integer.html.erb +1 -0
  35. data/app/views/queries/filters/_numeric.html.erb +6 -0
  36. data/app/views/queries/filters/_string.html.erb +1 -0
  37. data/app/views/queries/filters/_text.html.erb +6 -0
  38. data/app/views/queries/index.html.erb +39 -0
  39. data/app/views/queries/new.html.erb +27 -0
  40. data/app/views/queries/not_found.html.erb +1 -0
  41. data/app/views/queries/show.html.erb +40 -0
  42. data/app/views/queries/sql_form.html.erb +16 -0
  43. data/config/initializers/visual_query.rb +11 -0
  44. data/config/routes.rb +26 -0
  45. data/db/migrate/20130927090319_create_visual_query_schema.rb +9 -0
  46. data/db/migrate/20130927090400_create_visual_query_metadata_table.rb +16 -0
  47. data/lib/tasks/visual_query_tasks.rake +12 -0
  48. data/lib/tutuf/visual_query.rb +6 -0
  49. data/lib/tutuf/visual_query/base.rb +268 -0
  50. data/lib/tutuf/visual_query/common.rb +58 -0
  51. data/lib/tutuf/visual_query/metadata.rb +35 -0
  52. data/lib/tutuf/visual_query/single.rb +111 -0
  53. data/lib/tutuf/visual_query/sql.rb +20 -0
  54. data/lib/visual_query.rb +4 -0
  55. data/lib/visual_query/engine.rb +4 -0
  56. data/lib/visual_query/version.rb +3 -0
  57. data/test/dummy/README.rdoc +261 -0
  58. data/test/dummy/Rakefile +7 -0
  59. data/test/dummy/app/assets/javascripts/application.js +15 -0
  60. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  61. data/test/dummy/app/controllers/application_controller.rb +3 -0
  62. data/test/dummy/app/helpers/application_helper.rb +2 -0
  63. data/test/dummy/app/models/account.rb +3 -0
  64. data/test/dummy/app/models/address.rb +3 -0
  65. data/test/dummy/app/models/category.rb +3 -0
  66. data/test/dummy/app/models/composite_pk.rb +3 -0
  67. data/test/dummy/app/models/customer.rb +4 -0
  68. data/test/dummy/app/models/order.rb +4 -0
  69. data/test/dummy/app/models/person.rb +4 -0
  70. data/test/dummy/app/models/post.rb +3 -0
  71. data/test/dummy/app/models/product.rb +4 -0
  72. data/test/dummy/app/models/product_in.rb +3 -0
  73. data/test/dummy/app/models/product_out.rb +3 -0
  74. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  75. data/test/dummy/config.ru +4 -0
  76. data/test/dummy/config/application.rb +53 -0
  77. data/test/dummy/config/boot.rb +10 -0
  78. data/test/dummy/config/database.yml +12 -0
  79. data/test/dummy/config/environment.rb +5 -0
  80. data/test/dummy/config/environments/development.rb +29 -0
  81. data/test/dummy/config/environments/production.rb +65 -0
  82. data/test/dummy/config/environments/test.rb +33 -0
  83. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  84. data/test/dummy/config/initializers/inflections.rb +15 -0
  85. data/test/dummy/config/initializers/mime_types.rb +5 -0
  86. data/test/dummy/config/initializers/secret_token.rb +7 -0
  87. data/test/dummy/config/initializers/session_store.rb +8 -0
  88. data/test/dummy/config/initializers/visual_query.rb +1 -0
  89. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  90. data/test/dummy/config/locales/en.yml +5 -0
  91. data/test/dummy/config/routes.rb +3 -0
  92. data/test/dummy/db/migrate/20130927112446_create_tables.rb +77 -0
  93. data/test/dummy/db/structure.sql +651 -0
  94. data/test/dummy/log/development.log +1548 -0
  95. data/test/dummy/log/test.log +36575 -0
  96. data/test/dummy/public/404.html +26 -0
  97. data/test/dummy/public/422.html +26 -0
  98. data/test/dummy/public/500.html +25 -0
  99. data/test/dummy/public/favicon.ico +0 -0
  100. data/test/dummy/script/rails +6 -0
  101. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/-h/-hj2e_RSTanfbfrP0tso5Q7actRM6_clE5hetFlQ2y8.cache +1 -0
  102. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/3B/3B_zqoNDfkO8wvAME66zxm9KzQaeDVSjnH0qC08yufM.cache +1 -0
  103. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/5g/5g7dhxVp4YbZmFw_-T3aU2oYq2Z9Jgtps0CKneXYSS0.cache +2 -0
  104. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/6-/6-CtZO6uG0yfwU8-098Sdy2wnfO0W6DbFu6B6DKYuiw.cache +1 -0
  105. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/8k/8kFIVN4cTS9KCQt_UIF5s_rcY-bMYlQpM489D98hvP4.cache +1 -0
  106. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Au/AukU7t3xLnyCh7qW4u45q9YFmjVcYujmIFbnaOhF4Mo.cache +1 -0
  107. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Bm/Bmsq0vYQqlrtfq5s-W8kcfLvwcsPT_6_5XxXt9J_QOw.cache +1 -0
  108. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/CQ/CQLNg7a2TsUWgc7JXjDkjseMig_dPVm6AvqO2IWk5zg.cache +0 -0
  109. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/FX/FX9ZXN3HEHR5hPzvxW8rakWEt2ot4IPJyDB67O7KPZk.cache +2 -0
  110. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Hv/HvOStITEkFHlcJCgaDnND6wzPw4dMmdAdZB1Xm6JfSA.cache +0 -0
  111. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/NW/NWCtuFzfIgixavqY71NIAa4ajbsXxRuiLNjceHgQ24M.cache +2 -0
  112. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Ta/TaG641Ow168nkagg10mh6zuWS8RwWuawpHuMGakCVjU.cache +0 -0
  113. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/VN/VNCapNKJLeponthNeFJhaBYs92UBT3P8PugENHP0474.cache +2 -0
  114. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/VR/VRi0Hz7tc62H5Of9XVjyAk7vSNmMr8xeYowo6lSBnZg.cache +2 -0
  115. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Vg/Vgl_u6t3BvczgGi_ZJlyyo7xYSe-GgEshLofx-3QorI.cache +1 -0
  116. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Vq/VqGJMF3Cpvp3fw2IEIkE2tzdFo_OdcEmxN58BQwbVDY.cache +0 -0
  117. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/W6/W6DnXCIMHJ2i5hUkEiNeDLroWxW3VU18nq292n5jlts.cache +0 -0
  118. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Z7/Z7fH8ST-O3GMnDUKvtKHHTSObfH2Nbs0J1QS79i80yE.cache +0 -0
  119. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Zh/ZhrmuPgfbHthzikN8QSHR0Q0bLtSYS1Bzl9HauWeDfU.cache +0 -0
  120. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/bY/bYzYCY_bAGQGVGMbcxtKIhUYrgDQhmQVTmK50JrMNb8.cache +0 -0
  121. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/eT/eTmCDSnc2m9ER5Cn85g84xyTkVLWKLbbwPFQo8eUAIg.cache +0 -0
  122. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/h-/h-taE7cHlbq76GUb5kHenjih_y66mO0w0lIZs7vY-0s.cache +1 -0
  123. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ji/jikmiWyu-cXN_ZJ4hgLc3kuCAY-QJY2jmPeXS4_9vZY.cache +0 -0
  124. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/kC/kCijps52gsNlkYgT2Qzdz9UcSaxhcMGNfNL7MIiWk54.cache +1 -0
  125. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/kQ/kQt-OsUDJg_sl1be-FqJ6Vhw4XVguw9_msZEwXP0Nh0.cache +0 -0
  126. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/nd/ndbe-ZZWBqU5gLx5nxauCFvv963Zm3xqVEwVYQ7X_X8.cache +1 -0
  127. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/q6/q6BYa32YJF11eGVapO4ouNl6gayPIsARgMavlzZmoi0.cache +0 -0
  128. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/sm/sm7AdmddDYbFx4-eo_y_kaZspanmc-jiJeM8j2DXX5k.cache +1 -0
  129. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ux/uxPH9lLOW42lEQxJXnBizEObZReD8qkz6Eb6fdS6Ur4.cache +1 -0
  130. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/wn/wn0ayyM-chRdwEPI11SLkFT-7G2-GcOX8UIIC2kOWLY.cache +1 -0
  131. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/x7/x7KkTV3ibfIEysLB_ug5bfmnn2VLV_BldukPR3EoPBk.cache +0 -0
  132. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/xK/xKo0PfDcZuMh8oO-6Gr4j4S8eR2qUNY9Gau4kAxKIH0.cache +1 -0
  133. data/test/fixtures/accounts.yml +4 -0
  134. data/test/fixtures/categories.yml +3 -0
  135. data/test/fixtures/categories_posts.yml +3 -0
  136. data/test/fixtures/people.yml +8 -0
  137. data/test/fixtures/posts.yml +8 -0
  138. data/test/fixtures/product_ins.yml +15 -0
  139. data/test/fixtures/product_outs.yml +5 -0
  140. data/test/fixtures/products.yml +6 -0
  141. data/test/fixtures/saved_queries.rb +7 -0
  142. data/test/functional/queries_controller_test.rb +267 -0
  143. data/test/functional/routes_test.rb +111 -0
  144. data/test/integration/navigation_test.rb +10 -0
  145. data/test/test_helper.rb +15 -0
  146. data/test/unit/metadata_test.rb +10 -0
  147. data/test/unit/sql_test.rb +37 -0
  148. data/test/unit/visual_query_test.rb +648 -0
  149. 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
@@ -0,0 +1,10 @@
1
+ require 'test_helper'
2
+
3
+ class NavigationTest < ActionDispatch::IntegrationTest
4
+ fixtures :all
5
+
6
+ # test "the truth" do
7
+ # assert true
8
+ # end
9
+ end
10
+
@@ -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