visual_query 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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