rails_db_admin 2.0.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 (69) hide show
  1. data/GPL-3-LICENSE +674 -0
  2. data/README.md +5 -0
  3. data/Rakefile +30 -0
  4. data/app/assets/javascripts/rails_db_admin/application.js +9 -0
  5. data/app/assets/stylesheets/rails_db_admin/application.css +7 -0
  6. data/app/controllers/rails_db_admin/erp_app/desktop/base_controller.rb +182 -0
  7. data/app/controllers/rails_db_admin/erp_app/desktop/queries_controller.rb +173 -0
  8. data/app/helpers/rails_db_admin/application_helper.rb +4 -0
  9. data/app/views/layouts/application.html.erb +14 -0
  10. data/app/views/layouts/rails_db_admin/application.html.erb +14 -0
  11. data/config/initializers/rails_db_admin.rb +4 -0
  12. data/config/routes.rb +4 -0
  13. data/db/data_migrations/20110816005525_rails_db_admin_application.rb +31 -0
  14. data/lib/rails_db_admin.rb +15 -0
  15. data/lib/rails_db_admin/config.rb +27 -0
  16. data/lib/rails_db_admin/connection_handler.rb +17 -0
  17. data/lib/rails_db_admin/engine.rb +11 -0
  18. data/lib/rails_db_admin/extjs.rb +2 -0
  19. data/lib/rails_db_admin/extjs/json_column_builder.rb +139 -0
  20. data/lib/rails_db_admin/extjs/json_data_builder.rb +82 -0
  21. data/lib/rails_db_admin/query_support.rb +72 -0
  22. data/lib/rails_db_admin/table_support.rb +147 -0
  23. data/lib/rails_db_admin/version.rb +3 -0
  24. data/lib/tasks/rails_db_admin_tasks.rake +4 -0
  25. data/public/images/icons/rails_db_admin/rails_db_admin_16x16.png +0 -0
  26. data/public/images/icons/rails_db_admin/rails_db_admin_24x24.png +0 -0
  27. data/public/images/icons/rails_db_admin/rails_db_admin_32x32.png +0 -0
  28. data/public/images/icons/rails_db_admin/rails_db_admin_48x48.png +0 -0
  29. data/public/javascripts/erp_app/desktop/applications/rails_db_admin/database_combo.js +52 -0
  30. data/public/javascripts/erp_app/desktop/applications/rails_db_admin/module.js +429 -0
  31. data/public/javascripts/erp_app/desktop/applications/rails_db_admin/queries_tree_menu.js +86 -0
  32. data/public/javascripts/erp_app/desktop/applications/rails_db_admin/query_panel.js +206 -0
  33. data/public/javascripts/erp_app/desktop/applications/rails_db_admin/readonly_table_data_grid.js +27 -0
  34. data/public/javascripts/erp_app/desktop/applications/rails_db_admin/tables_tree_menu.js +87 -0
  35. data/public/stylesheets/erp_app/desktop/applications/rails_db_admin/rails_db_admin.css +10 -0
  36. data/spec/controllers/rails_db_admin/base_controller_spec.rb +481 -0
  37. data/spec/controllers/rails_db_admin/queries_controller_spec.rb +134 -0
  38. data/spec/dummy/Rakefile +7 -0
  39. data/spec/dummy/app/assets/javascripts/application.js +9 -0
  40. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  41. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  42. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  43. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  44. data/spec/dummy/config.ru +4 -0
  45. data/spec/dummy/config/application.rb +45 -0
  46. data/spec/dummy/config/boot.rb +10 -0
  47. data/spec/dummy/config/database.yml +14 -0
  48. data/spec/dummy/config/environment.rb +5 -0
  49. data/spec/dummy/config/environments/cucumber.rb +3 -0
  50. data/spec/dummy/config/environments/spec.rb +27 -0
  51. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  52. data/spec/dummy/config/initializers/inflections.rb +10 -0
  53. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  54. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  55. data/spec/dummy/config/initializers/session_store.rb +8 -0
  56. data/spec/dummy/config/initializers/wrap_parameters.rb +12 -0
  57. data/spec/dummy/config/locales/en.yml +5 -0
  58. data/spec/dummy/config/routes.rb +5 -0
  59. data/spec/dummy/public/404.html +26 -0
  60. data/spec/dummy/public/422.html +26 -0
  61. data/spec/dummy/public/500.html +26 -0
  62. data/spec/dummy/public/favicon.ico +0 -0
  63. data/spec/dummy/script/rails +6 -0
  64. data/spec/lib/rails_db_admin/extjs/json_column_builder_spec.rb +206 -0
  65. data/spec/lib/rails_db_admin/extjs/json_data_builder_spec.rb +201 -0
  66. data/spec/lib/rails_db_admin/query_support_spec.rb +40 -0
  67. data/spec/lib/rails_db_admin/table_support_spec.rb +349 -0
  68. data/spec/spec_helper.rb +60 -0
  69. metadata +183 -0
@@ -0,0 +1,4 @@
1
+ Rails.application.config.rails_db_admin.configure do |config|
2
+ config.query_location = File.join(Rails.root, 'lib', 'rails_db_admin', 'queries')
3
+ end
4
+ Rails.application.config.rails_db_admin.configure!
@@ -0,0 +1,4 @@
1
+ RailsDbAdmin::Engine.routes.draw do
2
+ match '/erp_app/desktop/base(/:action(/:table(/:id)))' => "erp_app/desktop/base"
3
+ match '/erp_app/desktop/queries(/:action(/:table(/:id)))' => "erp_app/desktop/queries"
4
+ end
@@ -0,0 +1,31 @@
1
+ class RailsDbAdminApplication
2
+
3
+ def self.up
4
+ if DesktopApplication.find_by_internal_identifier('rails_db_admin').nil?
5
+ rails_db_admin_app = DesktopApplication.create(
6
+ :description => 'RailsDbAdmin',
7
+ :icon => 'icon-rails_db_admin',
8
+ :javascript_class_name => 'Compass.ErpApp.Desktop.Applications.RailsDbAdmin',
9
+ :internal_identifier => 'rails_db_admin',
10
+ :shortcut_id => 'rails_db_admin-win'
11
+ )
12
+
13
+ rails_db_admin_app.preference_types << PreferenceType.iid('desktop_shortcut')
14
+ rails_db_admin_app.preference_types << PreferenceType.iid('autoload_application')
15
+ rails_db_admin_app.save
16
+
17
+ admin_user = User.find_by_username('admin')
18
+ admin_user.desktop.applications << rails_db_admin_app
19
+ admin_user.save
20
+
21
+ truenorth_user = User.find_by_username('truenorth')
22
+ truenorth_user.desktop.applications << rails_db_admin_app
23
+ truenorth_user.save
24
+ end
25
+ end
26
+
27
+ def self.down
28
+ DesktopApplication.find_by_internal_identifier('rails_db_admin').destroy
29
+ end
30
+
31
+ end
@@ -0,0 +1,15 @@
1
+ #compass libraries
2
+ require 'erp_app'
3
+ require 'erp_forms'
4
+
5
+ require 'rails_db_admin/config'
6
+ require 'rails_db_admin/extjs'
7
+ require 'rails_db_admin/connection_handler'
8
+ require 'rails_db_admin/query_support'
9
+ require 'rails_db_admin/table_support'
10
+ require "rails_db_admin/engine"
11
+
12
+ module RailsDbAdmin
13
+ end
14
+
15
+
@@ -0,0 +1,27 @@
1
+ module RailsDbAdmin
2
+ module Config
3
+ class << self
4
+ attr_accessor :query_location
5
+
6
+ def init!
7
+ @defaults = {:@query_location => nil}
8
+ end
9
+
10
+ def reset!
11
+ @defaults.each do |k,v|
12
+ instance_variable_set(k,v)
13
+ end
14
+ end
15
+
16
+ def configure(&blk)
17
+ @configure_blk = blk
18
+ end
19
+
20
+ def configure!
21
+ @configure_blk.call(self) if @configure_blk
22
+ end
23
+ end
24
+ init!
25
+ reset!
26
+ end
27
+ end
@@ -0,0 +1,17 @@
1
+ module RailsDbAdmin
2
+ class ConnectionHandler
3
+ def self.create_connection_class(database)
4
+ klass = nil
5
+
6
+ unless database.blank?
7
+ klass = Class.new ActiveRecord::Base
8
+ klass.establish_connection(database)
9
+ else
10
+ klass = ActiveRecord::Base
11
+ end
12
+
13
+ klass
14
+ end
15
+ end
16
+ end
17
+
@@ -0,0 +1,11 @@
1
+ module RailsDbAdmin
2
+ class Engine < Rails::Engine
3
+ isolate_namespace RailsDbAdmin
4
+
5
+ config.rails_db_admin = RailsDbAdmin::Config
6
+
7
+ initializer "rails_db_admin.merge_public" do |app|
8
+ app.middleware.insert_before Rack::Lock, ::ActionDispatch::Static, "#{root}/public"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,2 @@
1
+ require 'rails_db_admin/extjs/json_column_builder'
2
+ require 'rails_db_admin/extjs/json_data_builder'
@@ -0,0 +1,139 @@
1
+ module RailsDbAdmin
2
+ module Extjs
3
+ class JsonColumnBuilder
4
+ def self.build_column_from_column_obj(column)
5
+ self.send("build_#{column.type.to_s}_column", column.name)
6
+ end
7
+
8
+ #construct an array of column objects based on a
9
+ #AR connection.columns object
10
+ def self.build_grid_columns(columns, add_fake_id = false)
11
+ grid_columns = columns.collect do |column|
12
+ RailsDbAdmin::Extjs::JsonColumnBuilder.build_column_from_column_obj(column)
13
+ end
14
+ if add_fake_id
15
+ grid_columns << {:header => "fake_id",
16
+ :type => "number",
17
+ :dataIndex => "fake_id",
18
+ :hidden => true}
19
+ end
20
+ grid_columns
21
+ end
22
+
23
+ def self.build_store_fields(columns, add_fake_id = false)
24
+ grid_fields = columns.collect do |column|
25
+ {:name => column.name}
26
+ end
27
+
28
+ if add_fake_id
29
+ grid_fields << {:name => "fake_id"}
30
+ end
31
+
32
+ grid_fields
33
+ end
34
+
35
+ def self.build_readonly_column(column_name)
36
+ {
37
+ :header => column_name,
38
+ :type => 'string',
39
+ :dataIndex => column_name,
40
+ :width => 150
41
+ }
42
+ end
43
+
44
+
45
+ private
46
+
47
+ def self.build_boolean_column(column_name)
48
+ {
49
+ :header => column_name,
50
+ :type => 'boolean',
51
+ :dataIndex => column_name,
52
+ :width => 150,
53
+ :editor => {:xtype => 'booleancolumneditor'},
54
+ :renderer => NonEscapeJsonString.new("Compass.ErpApp.Desktop.Applications.RailsDbAdmin.renderBooleanColumn")
55
+ }
56
+ end
57
+
58
+ def self.build_date_column(column_name)
59
+ hash = {
60
+ :header => column_name,
61
+ :type => 'date',
62
+ :dataIndex => column_name,
63
+ :width => 150,
64
+ }
65
+ hash[:editor] = {:xtype => 'textfield'} if (column_name != "created_at" && column_name != "updated_at")
66
+
67
+ hash
68
+ end
69
+
70
+ def self.build_datetime_column(column_name)
71
+ hash = {
72
+ :header => column_name,
73
+ :type => 'date',
74
+ :dataIndex => column_name,
75
+ :width => 150,
76
+ }
77
+ hash[:editor] = {:xtype => 'textfield'} if (column_name != "created_at" && column_name != "updated_at")
78
+
79
+ hash
80
+ end
81
+
82
+ def self.build_string_column(column_name)
83
+ {
84
+ :header => column_name,
85
+ :type => 'string',
86
+ :dataIndex => column_name,
87
+ :width => 150,
88
+ :editor => {:xtype => 'textfield'}
89
+ }
90
+ end
91
+
92
+ def self.build_text_column(column_name)
93
+ {
94
+ :header => column_name,
95
+ :type => 'string',
96
+ :dataIndex => column_name,
97
+ :width => 150,
98
+ :editor => {:xtype => 'textarea'}
99
+ }
100
+ end
101
+
102
+ def self.build_integer_column(column_name)
103
+ hash = {
104
+ :header => column_name,
105
+ :type => 'number',
106
+ :dataIndex => column_name,
107
+ :width => 150,
108
+ }
109
+ hash[:editor] = {:xtype => 'textfield'} if column_name != "id"
110
+
111
+ hash
112
+ end
113
+
114
+ def self.build_decimal_column(column_name)
115
+ hash = {
116
+ :header => column_name,
117
+ :type => 'float',
118
+ :dataIndex => column_name,
119
+ :width => 150,
120
+ }
121
+ hash[:editor] = {:xtype => 'textfield'} if column_name != "id"
122
+
123
+ hash
124
+ end
125
+
126
+ def self.build_float_column(column_name)
127
+ hash = {
128
+ :header => column_name,
129
+ :type => 'float',
130
+ :dataIndex => column_name,
131
+ :width => 150,
132
+ }
133
+ hash[:editor] = {:xtype => 'textfield'} if column_name != "id"
134
+
135
+ hash
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,82 @@
1
+ module RailsDbAdmin
2
+ module Extjs
3
+ class JsonDataBuilder
4
+
5
+ def initialize(database_connection_class)
6
+ @connection = database_connection_class.connection
7
+ end
8
+
9
+ def build_json_data(options)
10
+ unless options[:table]
11
+ raise '!Error Must specify table'
12
+ end
13
+
14
+ total_count = self.get_total_count(options[:table])
15
+ arel_table = Arel::Table::new(options[:table])
16
+
17
+ if options[:limit] && options[:offset] && options[:order]
18
+ query = arel_table.project(Arel.sql('*')).order(options[:order]).
19
+ take(@connection.sanitize_limit(options[:limit])).
20
+ skip(options[:offset].to_i)
21
+ elsif options[:limit] && options[:order]
22
+ query = arel_table.project(Arel.sql('*')).order(options[:order]).
23
+ take(@connection.sanitize_limit(options[:limit]))
24
+ elsif options[:limit] && !options[:order]
25
+ query = arel_table.project(Arel.sql('*')).
26
+ take(@connection.sanitize_limit(options[:limit]))
27
+ elsif !options[:limit] && options[:order]
28
+ query = arel_table.project(Arel.sql('*')).order(options[:order])
29
+ else
30
+ query = arel_table.project(Arel.sql('*'))
31
+ end
32
+
33
+
34
+ rows = @connection.select_all(query.to_sql)
35
+ records = RailsDbAdmin::TableSupport.database_rows_to_hash(rows)
36
+
37
+ if !records.empty? && !records[0].has_key?("id")
38
+ records = RailsDbAdmin::TableSupport.add_fake_id_col(records)
39
+ end
40
+
41
+ {:totalCount => total_count, :data => records}
42
+ end
43
+
44
+ def get_row_data(table, id)
45
+ arel_table = Arel::Table::new(table)
46
+
47
+ query = arel_table.project(
48
+ Arel.sql('*')).where(arel_table[id[0].to_sym].eq(id[1]))
49
+
50
+ rows = @connection.select_all(query.to_sql)
51
+ records = RailsDbAdmin::TableSupport.database_rows_to_hash(rows)
52
+ records[0]
53
+ end
54
+
55
+ #This will retrieve data from tables without an
56
+ #'id' field. Will also add a 'fake_id' so that it can
57
+ #be used by editable ExtJS grids.
58
+ def get_row_data_no_id(table, row_hash)
59
+
60
+ arel_table = Arel::Table::new(table)
61
+ query = arel_table.project(Arel.sql('*'))
62
+ row_hash.each do |k, v|
63
+ query = query.where(arel_table[k.to_sym].eq(v))
64
+ end
65
+
66
+ rows = @connection.select_all(query.to_sql)
67
+ records = RailsDbAdmin::TableSupport.database_rows_to_hash(rows)
68
+ records = RailsDbAdmin::TableSupport.add_fake_id_col(records)
69
+ records[0]
70
+ end
71
+
72
+ def get_total_count(table)
73
+ total_count = 0
74
+ rows = @connection.select_all("SELECT COUNT(*) as count FROM #{table}")
75
+ records = RailsDbAdmin::TableSupport.database_rows_to_hash(rows)
76
+ total_count = records[0][:count]
77
+
78
+ total_count
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,72 @@
1
+ require 'fileutils'
2
+
3
+ module RailsDbAdmin
4
+ class QuerySupport
5
+ def initialize(database_connection_class, database_connection_name)
6
+ @path = File.join(Rails.application.config.rails_db_admin.query_location, database_connection_name)
7
+ @connection = database_connection_class.connection
8
+ end
9
+
10
+ def execute_sql(sql)
11
+ begin
12
+ rows = @connection.select_all(sql)
13
+ rescue => ex
14
+ return nil, nil, ex.message
15
+ end
16
+
17
+ values = []
18
+ columns = []
19
+
20
+ unless rows.nil? || rows.empty?
21
+ columns = rows[0].keys
22
+ rows.each do |row|
23
+ values << row
24
+ end
25
+ end
26
+
27
+ return columns, values, nil
28
+ end
29
+
30
+ def select_top_fifty(table)
31
+ #Actually, sanitizing here is pretty redundent since it's a constant...
32
+ ar = Arel::Table::new(table)
33
+ query = ar.project(Arel.sql('*')).take(50)
34
+ #query = "SELECT * FROM #{table} LIMIT #{@connection.sanitize_limit(50)}"
35
+
36
+ rows = @connection.select_all(query.to_sql)
37
+ records = RailsDbAdmin::TableSupport.database_rows_to_hash(rows)
38
+
39
+ return query.to_sql, records
40
+ end
41
+
42
+ def get_saved_query_names
43
+ query_files = []
44
+
45
+ if File.directory? @path
46
+ query_files = Dir.entries(@path)
47
+ query_files.delete_if{|name| name =~ /^\./}
48
+ query_files.each do |file_name|
49
+ file_name.gsub!('.sql', '')
50
+ end
51
+ end
52
+
53
+ query_files
54
+ end
55
+
56
+ def save_query(query, name)
57
+ FileUtils.mkdir_p(@path) unless File.directory? @path
58
+
59
+ file_path = File.join(@path, "#{name}.sql")
60
+ File.new(file_path, 'w') unless File.exist?(File.join(file_path))
61
+ File.open(file_path, 'w+'){|f| f.puts(query) }
62
+ end
63
+
64
+ def delete_query(name)
65
+ FileUtils.rm(File.join(@path, "#{name}.sql")) if File.exist?(File.join(@path, "#{name}.sql"))
66
+ end
67
+
68
+ def get_query(name)
69
+ File.open(File.join(@path, "#{name}.sql")) { |f| f.read } if File.exist?(File.join(@path, "#{name}.sql"))
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,147 @@
1
+ module RailsDbAdmin
2
+ class TableSupport
3
+
4
+ def initialize(database_connection_class)
5
+ @connection = database_connection_class.connection
6
+ end
7
+
8
+ def columns(table)
9
+ @columns ||= @connection.columns(table)
10
+ end
11
+
12
+ def update_table(table, id, data)
13
+ arel_table = Arel::Table::new(table)
14
+ clean_nulls!(table, data)
15
+ data = RailsDbAdmin::TableSupport.arel_attr(data, arel_table)
16
+
17
+ pk = id[0].to_sym
18
+ query = arel_table.where(arel_table[pk].eq(id[1])).compile_update(data)
19
+
20
+ @connection.execute(query.to_sql)
21
+ end
22
+
23
+ def update_table_without_id(table, data)
24
+ #makes all values strings
25
+ data[0].delete('fake_id')
26
+ data[1].delete('fake_id')
27
+ data.map! do |item|
28
+ item.each do |k,v|
29
+ item[k] = v.to_s
30
+ end
31
+ item
32
+ end
33
+
34
+ clean_nulls!(table, data)
35
+ changed_values = data[0].diff(data[1])
36
+
37
+ arel_table = Arel::Table::new(table)
38
+ updates = RailsDbAdmin::TableSupport.arel_attr(changed_values, arel_table)
39
+ query = arel_table
40
+
41
+ data[1].each do |k, v|
42
+ query = query.where(arel_table[k.to_sym].eq(v))
43
+ end
44
+ query = query.compile_update(updates)
45
+
46
+ @connection.execute(query.to_sql)
47
+ end
48
+
49
+ def delete_row(table, id)
50
+ arel_table = Arel::Table::new(table)
51
+ pk = id[0].to_sym
52
+ query = arel_table.where(arel_table[pk].eq(id[1])).compile_delete
53
+
54
+ @connection.execute(query.to_sql)
55
+ end
56
+
57
+ def insert_row(table, data, no_id=false)
58
+ clean_nulls!(table, data)
59
+ arel_table = Arel::Table::new(table)
60
+ data = RailsDbAdmin::TableSupport.arel_attr(data, arel_table)
61
+
62
+ sql = arel_table.compile_insert(data)
63
+ #TODO: Test with Oracle; ActiveRecord source indicates
64
+ #that we may need to pass in the id to use here
65
+ id = @connection.insert(sql.to_sql)
66
+
67
+ if no_id
68
+ #need to gen a random number for fake_id...
69
+ id = Random.rand(500-100) + 100
70
+ end
71
+ id
72
+ end
73
+
74
+ def primary_key(table)
75
+ [@connection.primary_key(table),nil]
76
+ end
77
+
78
+ def primary_key?(table)
79
+ @connection.supports_primary_key? && @connection.primary_key(table) != nil
80
+ end
81
+
82
+
83
+ def table_contains_column(table, column_name)
84
+
85
+ column_names = columns(table).map{|column| column.name.to_sym}
86
+
87
+ column_names.include?(column_name)
88
+ end
89
+
90
+ def clean_nulls!(table, data)
91
+ if data.class == Array
92
+ data.each {|x| clean_nulls!(table, x)}
93
+ end
94
+
95
+ data.collect do |k,v|
96
+ if v == "" || v == 0
97
+ column = columns(table).collect do |x|
98
+ if (x.name == k)
99
+ break x
100
+ end
101
+ end
102
+ if column.null
103
+ data[k] = nil
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ def self.database_rows_to_hash(rows)
110
+ records = []
111
+
112
+ rows.each do |row|
113
+ record = nil
114
+ row.each {|k, v|
115
+ record = record.nil? ? {k.to_sym => v} : record.merge({k.to_sym => v})
116
+ }
117
+ records << record
118
+ end
119
+
120
+ records.reverse
121
+ end
122
+
123
+ #Construct a hash of ARel relation objects as
124
+ #keys and assign with values for use in update
125
+ #calls
126
+ def self.arel_attr data, arel_table
127
+ cln_hsh = {}
128
+ data.each do |k,v|
129
+ cln_hsh[arel_table[k.to_sym]] = v
130
+ end
131
+ cln_hsh
132
+ end
133
+
134
+ #Accepts an array of table row hashes and adds a 'fake_id'
135
+ #field to each one with a generated number. Useful
136
+ #for prepraring many-to-many data to be edited in ExtJS
137
+ #grids
138
+ def self.add_fake_id_col(rows_hash)
139
+ nums = (1..(rows_hash.length)).to_a
140
+ result = rows_hash.map do |item|
141
+ item[:fake_id] = nums.shift
142
+ item
143
+ end
144
+ return result
145
+ end
146
+ end
147
+ end