rails_db_admin 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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