dbwatcher 1.1.2 → 1.1.3

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 (27) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/dbwatcher_manifest.js +1 -0
  3. data/app/assets/javascripts/dbwatcher/components/changes_table_hybrid.js +184 -97
  4. data/app/assets/javascripts/dbwatcher/components/timeline.js +211 -0
  5. data/app/assets/javascripts/dbwatcher/dbwatcher.js +5 -0
  6. data/app/assets/stylesheets/dbwatcher/application.css +298 -1
  7. data/app/assets/stylesheets/dbwatcher/application.scss +1 -0
  8. data/app/assets/stylesheets/dbwatcher/components/_timeline.scss +326 -0
  9. data/app/controllers/dbwatcher/api/v1/sessions_controller.rb +18 -4
  10. data/app/controllers/dbwatcher/sessions_controller.rb +1 -1
  11. data/app/views/dbwatcher/sessions/_layout.html.erb +5 -2
  12. data/app/views/dbwatcher/sessions/_summary.html.erb +1 -1
  13. data/app/views/dbwatcher/sessions/{_changes.html.erb → _tables.html.erb} +84 -5
  14. data/app/views/dbwatcher/sessions/_timeline.html.erb +260 -0
  15. data/app/views/dbwatcher/sessions/show.html.erb +3 -1
  16. data/app/views/layouts/dbwatcher/application.html.erb +1 -0
  17. data/config/routes.rb +2 -1
  18. data/lib/dbwatcher/services/analyzers/table_summary_builder.rb +102 -1
  19. data/lib/dbwatcher/services/api/{changes_data_service.rb → tables_data_service.rb} +6 -6
  20. data/lib/dbwatcher/services/timeline_data_service/enhancement_utilities.rb +100 -0
  21. data/lib/dbwatcher/services/timeline_data_service/entry_builder.rb +125 -0
  22. data/lib/dbwatcher/services/timeline_data_service/metadata_builder.rb +93 -0
  23. data/lib/dbwatcher/services/timeline_data_service.rb +130 -0
  24. data/lib/dbwatcher/storage/api/concerns/table_analyzer.rb +1 -1
  25. data/lib/dbwatcher/version.rb +1 -1
  26. data/lib/dbwatcher.rb +1 -1
  27. metadata +11 -4
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dbwatcher
4
+ module Services
5
+ class TimelineDataService
6
+ # Module for building timeline metadata
7
+ module MetadataBuilder
8
+ private
9
+
10
+ # Build timeline metadata
11
+ #
12
+ # @return [Hash] timeline metadata
13
+ def build_timeline_metadata
14
+ return {} if @timeline_entries.empty?
15
+
16
+ {
17
+ total_operations: @timeline_entries.length,
18
+ time_range: calculate_time_range,
19
+ session_duration: calculate_session_duration,
20
+ tables_affected: extract_affected_tables,
21
+ operation_counts: count_operations_by_type,
22
+ peak_activity_periods: find_peak_activity_periods
23
+ }
24
+ end
25
+
26
+ # Calculate time range for the session
27
+ #
28
+ # @return [Hash] time range with start and end
29
+ def calculate_time_range
30
+ return {} if @timeline_entries.empty?
31
+
32
+ start_time = Time.at(@timeline_entries.first[:raw_timestamp])
33
+ end_time = Time.at(@timeline_entries.last[:raw_timestamp])
34
+
35
+ {
36
+ start: start_time.iso8601,
37
+ end: end_time.iso8601
38
+ }
39
+ end
40
+
41
+ # Calculate total session duration
42
+ #
43
+ # @return [String] formatted session duration
44
+ def calculate_session_duration
45
+ return "00:00" if @timeline_entries.length < 2
46
+
47
+ duration = @timeline_entries.last[:raw_timestamp] - @timeline_entries.first[:raw_timestamp]
48
+ format_duration(duration)
49
+ end
50
+
51
+ # Extract list of affected tables
52
+ #
53
+ # @return [Array<String>] unique table names
54
+ def extract_affected_tables
55
+ @timeline_entries.map { |entry| entry[:table_name] }.uniq.sort
56
+ end
57
+
58
+ # Count operations by type
59
+ #
60
+ # @return [Hash] operation counts
61
+ def count_operations_by_type
62
+ @timeline_entries.group_by { |entry| entry[:operation] }
63
+ .transform_values(&:count)
64
+ end
65
+
66
+ # Find peak activity periods
67
+ #
68
+ # @return [Array<Hash>] peak activity periods
69
+ def find_peak_activity_periods
70
+ return [] if @timeline_entries.length < 10
71
+
72
+ # Group operations by 1-minute windows
73
+ windows = @timeline_entries.group_by do |entry|
74
+ timestamp = Time.at(entry[:raw_timestamp])
75
+ Time.new(timestamp.year, timestamp.month, timestamp.day, timestamp.hour, timestamp.min, 0)
76
+ end
77
+
78
+ # Find windows with more than average activity
79
+ average_ops = @timeline_entries.length / windows.length.to_f
80
+
81
+ windows.select { |_, ops| ops.length > average_ops * 1.5 }
82
+ .map do |window_start, ops|
83
+ {
84
+ start: window_start.iso8601,
85
+ end: (window_start + 1.minute).iso8601,
86
+ operations_count: ops.length
87
+ }
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "timeline_data_service/metadata_builder"
4
+ require_relative "timeline_data_service/entry_builder"
5
+ require_relative "timeline_data_service/enhancement_utilities"
6
+
7
+ module Dbwatcher
8
+ module Services
9
+ # Timeline Data Service for processing session data into chronological timeline format
10
+ #
11
+ # This service transforms session changes into a chronologically ordered timeline
12
+ # with enhanced metadata for visualization and filtering.
13
+ #
14
+ # @example
15
+ # service = TimelineDataService.new(session)
16
+ # result = service.call
17
+ # timeline = result[:timeline]
18
+ # metadata = result[:metadata]
19
+ class TimelineDataService
20
+ include MetadataBuilder
21
+ include EntryBuilder
22
+ include EnhancementUtilities
23
+ # Initialize the timeline data service
24
+ #
25
+ # @param session [Session] session object containing changes data
26
+ def initialize(session)
27
+ @session = session
28
+ @timeline_entries = []
29
+ @start_time = Time.current
30
+ end
31
+
32
+ # Process session data into timeline format
33
+ #
34
+ # @return [Hash] processed timeline data with metadata
35
+ def call
36
+ Rails.logger.info("Processing timeline data for session #{@session.id}")
37
+
38
+ validate_session_data
39
+ build_timeline_entries
40
+ sort_chronologically
41
+ enhance_with_metadata
42
+ result = build_result
43
+
44
+ Rails.logger.info(
45
+ "Timeline processing completed for session #{@session.id} (#{@timeline_entries.length} entries)"
46
+ )
47
+
48
+ result
49
+ rescue StandardError => e
50
+ Rails.logger.error("Timeline processing failed for session #{@session.id}: #{e.message}")
51
+ build_error_result(e)
52
+ end
53
+
54
+ private
55
+
56
+ # Validate session data before processing
57
+ #
58
+ # @raise [ArgumentError] if session data is invalid
59
+ def validate_session_data
60
+ raise ArgumentError, "Session is required" unless @session
61
+ raise ArgumentError, "Session ID is required" unless @session.id
62
+ raise ArgumentError, "Session changes are required" unless @session.changes
63
+ end
64
+
65
+ # Build timeline entries from session changes
66
+ #
67
+ # @return [void]
68
+ def build_timeline_entries
69
+ @session.changes.each_with_index do |change, index|
70
+ next unless valid_change?(change)
71
+
72
+ @timeline_entries << create_timeline_entry(change, index)
73
+ end
74
+ end
75
+
76
+ # Check if a change is valid for timeline processing
77
+ #
78
+ # @param change [Hash] change data
79
+ # @return [Boolean] true if change is valid
80
+ def valid_change?(change)
81
+ change.is_a?(Hash) &&
82
+ change[:table_name] &&
83
+ change[:operation] &&
84
+ change[:timestamp]
85
+ end
86
+
87
+ # Sort timeline entries chronologically
88
+ #
89
+ # @return [void]
90
+ def sort_chronologically
91
+ @timeline_entries.sort_by! { |entry| entry[:raw_timestamp] }
92
+ end
93
+
94
+ # Build final result hash
95
+ #
96
+ # @return [Hash] complete timeline result
97
+ def build_result
98
+ {
99
+ timeline: @timeline_entries,
100
+ metadata: build_timeline_metadata,
101
+ summary: build_timeline_summary,
102
+ errors: []
103
+ }
104
+ end
105
+
106
+ # Build timeline summary
107
+ #
108
+ # @return [Hash] timeline summary
109
+ def build_timeline_summary
110
+ {
111
+ total_entries: @timeline_entries.length,
112
+ processing_time: (Time.current - @start_time).round(3)
113
+ }
114
+ end
115
+
116
+ # Build error result
117
+ #
118
+ # @param error [StandardError] error that occurred
119
+ # @return [Hash] error result
120
+ def build_error_result(error)
121
+ {
122
+ timeline: [],
123
+ metadata: {},
124
+ summary: { error: error.message },
125
+ errors: [{ type: "processing_error", message: error.message }]
126
+ }
127
+ end
128
+ end
129
+ end
130
+ end
@@ -24,7 +24,7 @@ module Dbwatcher
24
24
  # @return [Hash] tables summary hash
25
25
  def build_tables_summary(session)
26
26
  # Delegate to new service while maintaining interface compatibility
27
- Dbwatcher::Services::Analyzers::TableSummaryBuilder.call(session)
27
+ Dbwatcher::Services::Analyzers::TableSummaryBuilder.new(session).call
28
28
  end
29
29
 
30
30
  # Process all changes in a session (legacy method for backward compatibility)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dbwatcher
4
- VERSION = "1.1.2"
4
+ VERSION = "1.1.3"
5
5
  end
data/lib/dbwatcher.rb CHANGED
@@ -74,7 +74,7 @@ require_relative "dbwatcher/services/diagram_system"
74
74
 
75
75
  # API services
76
76
  require_relative "dbwatcher/services/api/base_api_service"
77
- require_relative "dbwatcher/services/api/changes_data_service"
77
+ require_relative "dbwatcher/services/api/tables_data_service"
78
78
  require_relative "dbwatcher/services/api/summary_data_service"
79
79
  require_relative "dbwatcher/services/api/diagram_data_service"
80
80
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbwatcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Huy Nguyen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-09 00:00:00.000000000 Z
11
+ date: 2025-07-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -172,6 +172,7 @@ files:
172
172
  - app/assets/javascripts/dbwatcher/components/dashboard.js
173
173
  - app/assets/javascripts/dbwatcher/components/diagrams.js
174
174
  - app/assets/javascripts/dbwatcher/components/summary.js
175
+ - app/assets/javascripts/dbwatcher/components/timeline.js
175
176
  - app/assets/javascripts/dbwatcher/core/alpine_store.js
176
177
  - app/assets/javascripts/dbwatcher/core/api_client.js
177
178
  - app/assets/javascripts/dbwatcher/core/component_loader.js
@@ -190,6 +191,7 @@ files:
190
191
  - app/assets/stylesheets/dbwatcher/components/_forms.scss
191
192
  - app/assets/stylesheets/dbwatcher/components/_navigation.scss
192
193
  - app/assets/stylesheets/dbwatcher/components/_tabulator.scss
194
+ - app/assets/stylesheets/dbwatcher/components/_timeline.scss
193
195
  - app/assets/stylesheets/dbwatcher/core/_base.scss
194
196
  - app/assets/stylesheets/dbwatcher/core/_variables.scss
195
197
  - app/assets/stylesheets/dbwatcher/vendor/_tabulator_overrides.scss
@@ -212,11 +214,12 @@ files:
212
214
  - app/views/dbwatcher/dashboard/_system_info_content.html.erb
213
215
  - app/views/dbwatcher/dashboard/index.html.erb
214
216
  - app/views/dbwatcher/queries/index.html.erb
215
- - app/views/dbwatcher/sessions/_changes.html.erb
216
217
  - app/views/dbwatcher/sessions/_diagrams.html.erb
217
218
  - app/views/dbwatcher/sessions/_layout.html.erb
218
219
  - app/views/dbwatcher/sessions/_session_header.html.erb
219
220
  - app/views/dbwatcher/sessions/_summary.html.erb
221
+ - app/views/dbwatcher/sessions/_tables.html.erb
222
+ - app/views/dbwatcher/sessions/_timeline.html.erb
220
223
  - app/views/dbwatcher/sessions/index.html.erb
221
224
  - app/views/dbwatcher/sessions/show.html.erb
222
225
  - app/views/dbwatcher/shared/_badge.html.erb
@@ -244,9 +247,9 @@ files:
244
247
  - lib/dbwatcher/services/analyzers/session_data_processor.rb
245
248
  - lib/dbwatcher/services/analyzers/table_summary_builder.rb
246
249
  - lib/dbwatcher/services/api/base_api_service.rb
247
- - lib/dbwatcher/services/api/changes_data_service.rb
248
250
  - lib/dbwatcher/services/api/diagram_data_service.rb
249
251
  - lib/dbwatcher/services/api/summary_data_service.rb
252
+ - lib/dbwatcher/services/api/tables_data_service.rb
250
253
  - lib/dbwatcher/services/base_service.rb
251
254
  - lib/dbwatcher/services/dashboard_data_aggregator.rb
252
255
  - lib/dbwatcher/services/diagram_analyzers/base_analyzer.rb
@@ -281,6 +284,10 @@ files:
281
284
  - lib/dbwatcher/services/system_info/runtime_info_collector.rb
282
285
  - lib/dbwatcher/services/system_info/system_info_collector.rb
283
286
  - lib/dbwatcher/services/table_statistics_collector.rb
287
+ - lib/dbwatcher/services/timeline_data_service.rb
288
+ - lib/dbwatcher/services/timeline_data_service/enhancement_utilities.rb
289
+ - lib/dbwatcher/services/timeline_data_service/entry_builder.rb
290
+ - lib/dbwatcher/services/timeline_data_service/metadata_builder.rb
284
291
  - lib/dbwatcher/sql_logger.rb
285
292
  - lib/dbwatcher/storage.rb
286
293
  - lib/dbwatcher/storage/api/base_api.rb