dbviewer 0.5.0 → 0.5.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 628884438be23468b7910e2a13c14b2aa00cc6361f01cb09b53ecdcf1d8a0b78
4
- data.tar.gz: e9952d0c11ae3669b2604ac208f1a4ae224c37eb4d5f2b1074c4f284bb0bc24a
3
+ metadata.gz: d16f8924e91f06f61088b4948397aa23530cd6e4a89e00ab483cc047ea5fc492
4
+ data.tar.gz: 98091d292dfe7c42f0644dc1734fb298f532cfc6f99e0176ff1ae517c8db1cc8
5
5
  SHA512:
6
- metadata.gz: 369f106d728156712416e6d1f65c51e156ec1357e717c5cc4f95e9fe16dbe696e3a06b8c70a2ef2fd6ae559dd0e7ad7b73fc6a5b2e0ccc396a756633d733c2dd
7
- data.tar.gz: 273df74ea6e69b327b01faecb4b3572983fbd461ee042c41ba2402729482ead2b9ebaed117c95158ff01def2e1a1373aaf0fed75d8268d8546b0f3e38d2ff2ae
6
+ metadata.gz: a423fec219eaf8f40adde10a316cd4e45f33eb27d514ead5a0da735db3a475ac1ac430851cc347095106ca011dda72eae4ab68a01cba8ea8782ab132c99de8b6
7
+ data.tar.gz: 57594e053bf4bd1389da099fa91236af80e579bfc6f0ebd72da5081187c16a2343717c803632781bf39eb8d5281151cc8614def62c035b1b35dfd2f8946da631
@@ -5,7 +5,7 @@ module Dbviewer
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- helper_method :current_table?, :get_database_name if respond_to?(:helper_method)
8
+ helper_method :current_table?, :get_database_name, :get_adapter_name if respond_to?(:helper_method)
9
9
  end
10
10
 
11
11
  # Initialize the database manager
@@ -44,9 +44,33 @@ module Dbviewer
44
44
  "Database"
45
45
  end
46
46
 
47
+ # Get the name of the current database adapter
48
+ def get_adapter_name
49
+ adapter = database_manager.connection.adapter_name
50
+
51
+ # Format the adapter name for better display
52
+ case adapter.downcase
53
+ when /mysql/
54
+ "MySQL"
55
+ when /postgres/
56
+ "PostgreSQL"
57
+ when /sqlite/
58
+ "SQLite"
59
+ when /oracle/
60
+ "Oracle"
61
+ when /sqlserver/, /mssql/
62
+ "SQL Server"
63
+ else
64
+ adapter.titleize # Fallback to titleized version
65
+ end
66
+ rescue => e
67
+ Rails.logger.error("Error retrieving adapter name: #{e.message}")
68
+ "Unknown"
69
+ end
70
+
47
71
  # Fetch all tables with their stats
48
72
  # By default, don't include record counts for better performance on sidebar
49
- def fetch_tables_with_stats(include_record_counts = false)
73
+ def fetch_tables(include_record_counts = false)
50
74
  database_manager.tables.map do |table_name|
51
75
  table_stats = {
52
76
  name: table_name
@@ -62,7 +86,7 @@ module Dbviewer
62
86
  # Gather database analytics information
63
87
  def fetch_database_analytics
64
88
  # For analytics, we do need record counts
65
- tables = fetch_tables_with_stats(include_record_counts: true)
89
+ tables = fetch_tables(include_record_counts: true)
66
90
 
67
91
  # Calculate overall statistics
68
92
  analytics = {
@@ -77,48 +101,6 @@ module Dbviewer
77
101
  analytics
78
102
  end
79
103
 
80
- # Calculate approximate schema size
81
- def calculate_schema_size
82
- adapter = database_manager.connection.adapter_name.downcase
83
-
84
- case adapter
85
- when /mysql/
86
- query = <<-SQL
87
- SELECT
88
- SUM(data_length + index_length) AS size
89
- FROM
90
- information_schema.TABLES
91
- WHERE
92
- table_schema = DATABASE()
93
- SQL
94
- result = database_manager.execute_query(query).first
95
- result ? result["size"].to_i : nil
96
- when /postgres/
97
- query = <<-SQL
98
- SELECT pg_database_size(current_database()) AS size
99
- SQL
100
- result = database_manager.execute_query(query).first
101
- result ? result["size"].to_i : nil
102
- when /sqlite/
103
- # For SQLite, we need to use the special PRAGMA method without LIMIT
104
- # Get page count
105
- page_count_result = database_manager.execute_sqlite_pragma("page_count")
106
- page_count = page_count_result.first.values.first.to_i
107
-
108
- # Get page size
109
- page_size_result = database_manager.execute_sqlite_pragma("page_size")
110
- page_size = page_size_result.first.values.first.to_i
111
-
112
- # Calculate total size
113
- page_count * page_size
114
- else
115
- nil # Unsupported database type for size calculation
116
- end
117
- rescue => e
118
- Rails.logger.error("Error calculating database size: #{e.message}")
119
- nil
120
- end
121
-
122
104
  # Get column information for a specific table
123
105
  def fetch_table_columns(table_name)
124
106
  database_manager.table_columns(table_name)
@@ -2,12 +2,8 @@ module Dbviewer
2
2
  module Api
3
3
  class DatabaseController < BaseController
4
4
  def size
5
- begin
6
- size = calculate_schema_size
7
- render_success(schema_size: size)
8
- rescue => e
9
- render_error("Error calculating schema size: #{e.message}")
10
- end
5
+ size = database_manager.fetch_schema_size
6
+ render_success(schema_size: size)
11
7
  end
12
8
  end
13
9
  end
@@ -2,17 +2,27 @@ module Dbviewer
2
2
  module Api
3
3
  class QueriesController < BaseController
4
4
  def recent
5
- @recent_queries = if Dbviewer.configuration.enable_query_logging
6
- Dbviewer::Logger.instance.recent_queries(limit: 10)
7
- else
8
- []
9
- end
10
-
11
5
  render_success({
12
- enabled: Dbviewer.configuration.enable_query_logging,
13
- queries: @recent_queries
6
+ enabled: query_logging_enabled?,
7
+ queries: fetch_recent_queries
14
8
  })
15
9
  end
10
+
11
+ private
12
+
13
+ def fetch_recent_queries
14
+ return [] unless query_logging_enabled?
15
+
16
+ Dbviewer::Logger.instance.recent_queries(limit: queries_limit)
17
+ end
18
+
19
+ def query_logging_enabled?
20
+ Dbviewer.configuration.enable_query_logging
21
+ end
22
+
23
+ def queries_limit
24
+ 10
25
+ end
16
26
  end
17
27
  end
18
28
  end
@@ -2,38 +2,63 @@ module Dbviewer
2
2
  module Api
3
3
  class TablesController < BaseController
4
4
  def index
5
- tables = fetch_tables_with_stats(include_record_counts: false)
6
- render_success(total_tables: tables.size)
5
+ tables_count = fetch_tables_count
6
+ render_success(total_tables: tables_count)
7
7
  end
8
8
 
9
9
  def records
10
- tables = fetch_tables_with_stats(include_record_counts: true)
10
+ tables_stats = fetch_tables_stats
11
+ render_success(tables_stats)
12
+ end
11
13
 
12
- records_data = {
13
- total_records: tables.sum { |t| t[:record_count] },
14
- largest_tables: tables.sort_by { |t| -t[:record_count] }.first(10),
15
- empty_tables: tables.select { |t| t[:record_count] == 0 },
16
- avg_records_per_table: tables.any? ? (tables.sum { |t| t[:record_count] }.to_f / tables.size).round(1) : 0
17
- }
14
+ def relationships_count
15
+ total_relationships = calculate_total_relationships
16
+ render_success(total_relationships: total_relationships)
17
+ end
18
+
19
+ private
18
20
 
19
- render_success(records_data)
21
+ def fetch_tables_count
22
+ fetch_tables(include_record_counts: false).size
20
23
  end
21
24
 
22
- def relationships_count
23
- begin
24
- tables = fetch_tables_with_stats(include_record_counts: false)
25
- total_relationships = 0
26
-
27
- tables.each do |table|
28
- metadata = fetch_table_metadata(table[:name])
29
- total_relationships += metadata[:foreign_keys].size if metadata && metadata[:foreign_keys]
30
- end
31
-
32
- render_success(total_relationships: total_relationships)
33
- rescue => e
34
- render_error("Error calculating relationship count: #{e.message}")
25
+ def fetch_tables_stats
26
+ tables = fetch_tables(include_record_counts: true)
27
+
28
+ {
29
+ total_records: calculate_total_records(tables),
30
+ largest_tables: find_largest_tables(tables),
31
+ empty_tables: find_empty_tables(tables),
32
+ avg_records_per_table: calculate_average_records(tables)
33
+ }
34
+ end
35
+
36
+ def calculate_total_relationships
37
+ tables = fetch_tables(include_record_counts: false)
38
+
39
+ tables.sum do |table|
40
+ metadata = fetch_table_metadata(table[:name])
41
+ metadata&.dig(:foreign_keys)&.size || 0
35
42
  end
36
43
  end
44
+
45
+ def calculate_total_records(tables)
46
+ tables.sum { |table| table[:record_count] }
47
+ end
48
+
49
+ def find_largest_tables(tables, limit = 10)
50
+ tables.sort_by { |table| -table[:record_count] }.first(limit)
51
+ end
52
+
53
+ def find_empty_tables(tables)
54
+ tables.select { |table| table[:record_count] == 0 }
55
+ end
56
+
57
+ def calculate_average_records(tables)
58
+ return 0 if tables.empty?
59
+
60
+ (calculate_total_records(tables).to_f / tables.size).round(1)
61
+ end
37
62
  end
38
63
  end
39
64
  end
@@ -19,7 +19,7 @@ module Dbviewer
19
19
  end
20
20
 
21
21
  def set_tables
22
- @tables = fetch_tables_with_stats
22
+ @tables = fetch_tables
23
23
  end
24
24
  end
25
25
  end
@@ -6,7 +6,7 @@ module Dbviewer
6
6
  private
7
7
 
8
8
  def set_tables
9
- @tables = fetch_tables_with_stats(include_record_counts: true)
9
+ @tables = fetch_tables(include_record_counts: true)
10
10
  end
11
11
  end
12
12
  end
@@ -7,7 +7,7 @@ module Dbviewer
7
7
  before_action :set_global_filters, only: [ :show, :export_csv ]
8
8
 
9
9
  def index
10
- @tables = fetch_tables_with_stats(include_record_counts: true)
10
+ @tables = fetch_tables(include_record_counts: true)
11
11
  end
12
12
 
13
13
  def show
@@ -60,7 +60,7 @@ module Dbviewer
60
60
  def query
61
61
  @read_only_mode = true # Flag to indicate we're in read-only mode
62
62
  @columns = fetch_table_columns(@table_name)
63
- @tables = fetch_tables_with_stats # Fetch tables for sidebar
63
+ @tables = fetch_tables # Fetch tables for sidebar
64
64
 
65
65
  prepare_query
66
66
  execute_query
@@ -3,7 +3,7 @@
3
3
  <div class="col">
4
4
  <h1 class="h3 mb-2">Database Overview</h1>
5
5
  <p class="database-connection-info">
6
- Connected to database: <span class="badge rounded-pill database-name-badge"><%= get_database_name %></span>
6
+ Connected to <%= get_adapter_name %> database: <span class="badge rounded-pill database-name-badge"><%= get_database_name %></span>
7
7
  </p>
8
8
  </div>
9
9
  </div>
@@ -180,8 +180,48 @@ module Dbviewer
180
180
  @cache_manager.clear_all
181
181
  end
182
182
 
183
+ # Calculate the total size of the database schema
184
+ # @return [Integer, nil] Database size in bytes or nil if unsupported
185
+ def fetch_schema_size
186
+ case adapter_name
187
+ when /mysql/
188
+ fetch_mysql_size
189
+ when /postgres/
190
+ fetch_postgres_size
191
+ when /sqlite/
192
+ fetch_sqlite_size
193
+ else
194
+ nil # Unsupported database type for size calculation
195
+ end
196
+ end
197
+
183
198
  private
184
199
 
200
+ def fetch_mysql_size
201
+ query = "SELECT SUM(data_length + index_length) AS size FROM information_schema.TABLES WHERE table_schema = DATABASE()"
202
+ fetch_size_from_query(query)
203
+ end
204
+
205
+ def fetch_postgres_size
206
+ query = "SELECT pg_database_size(current_database()) AS size"
207
+ fetch_size_from_query(query)
208
+ end
209
+
210
+ def fetch_sqlite_size
211
+ page_count = fetch_sqlite_pragma_value("page_count")
212
+ page_size = fetch_sqlite_pragma_value("page_size")
213
+ page_count * page_size
214
+ end
215
+
216
+ def fetch_sqlite_pragma_value(pragma_name)
217
+ execute_sqlite_pragma(pragma_name).first.values.first.to_i
218
+ end
219
+
220
+ def fetch_size_from_query(query)
221
+ result = execute_query(query).first
222
+ result ? result["size"].to_i : nil
223
+ end
224
+
185
225
  # Ensure we have a valid database connection
186
226
  # @return [ActiveRecord::ConnectionAdapters::AbstractAdapter] The database connection
187
227
  def ensure_connection
@@ -20,8 +20,23 @@ module Dbviewer
20
20
  initializer "dbviewer.notifications" do
21
21
  ActiveSupport::Notifications.subscribe("sql.active_record") do |*args|
22
22
  event = ActiveSupport::Notifications::Event.new(*args)
23
+
24
+ next if skip_internal_query?(event)
25
+
23
26
  Logger.instance.add(event)
24
27
  end
25
28
  end
29
+
30
+ private
31
+
32
+ def skip_internal_query?(event)
33
+ caller_locations = caller_locations(1)
34
+ return false unless caller_locations
35
+
36
+ # Look for dbviewer in the call stack
37
+ caller_locations.any? { |l| l.path.include?("dbviewer") }
38
+ rescue
39
+ false
40
+ end
26
41
  end
27
42
  end
@@ -12,7 +12,6 @@ module Dbviewer
12
12
  def add(event)
13
13
  # Return early if query logging is disabled
14
14
  return unless Dbviewer.configuration.enable_query_logging
15
- return if QueryParser.should_skip_query?(event)
16
15
 
17
16
  current_time = Time.now
18
17
  @storage.add({
@@ -68,15 +68,5 @@ module Dbviewer
68
68
  rescue
69
69
  []
70
70
  end
71
-
72
- # Determine if a query should be skipped based on content
73
- def self.should_skip_query?(event)
74
- event.payload[:name] == "SCHEMA" ||
75
- event.payload[:sql].include?("SHOW TABLES") ||
76
- event.payload[:sql].include?("sqlite_master") ||
77
- event.payload[:sql].include?("information_schema") ||
78
- event.payload[:sql].include?("pg_catalog") ||
79
- from_dbviewer?(event)
80
- end
81
71
  end
82
72
  end
@@ -1,3 +1,3 @@
1
1
  module Dbviewer
2
- VERSION = "0.5.0"
2
+ VERSION = "0.5.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbviewer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wailan Tirajoh
@@ -100,7 +100,6 @@ files:
100
100
  - lib/dbviewer/table_query_params.rb
101
101
  - lib/dbviewer/version.rb
102
102
  - lib/generators/dbviewer/initializer_generator.rb
103
- - lib/generators/dbviewer/structured_api_generator.rb
104
103
  - lib/generators/dbviewer/templates/initializer.rb
105
104
  - lib/tasks/dbviewer_tasks.rake
106
105
  homepage: https://github.com/wailantirajoh/dbviewer
@@ -1,11 +0,0 @@
1
- module Dbviewer
2
- module Generators
3
- class StructuredApiGenerator < Rails::Generators::Base
4
- source_root File.expand_path("../templates", __FILE__)
5
-
6
- def create_initializer
7
- template "structured_api_initializer.rb", "config/initializers/dbviewer_structured_api.rb"
8
- end
9
- end
10
- end
11
- end