Class: Dbwatcher::Storage::QueryStorage

Inherits:
BaseStorage show all
Includes:
Concerns::Validatable, DateHelper
Defined in:
lib/dbwatcher/storage/query_storage.rb

Overview

Handles persistence and retrieval of database query logs

This class manages the storage of query data organized by date. Queries are stored in daily files with automatic cleanup and size limiting based on configuration. Follows Ruby style guide patterns for storage class organization.

Examples:

Basic usage

storage = QueryStorage.new
query = { sql: "SELECT * FROM users", timestamp: Time.current }
storage.save(query)
daily_queries = storage.find_by_date(Date.current)

Advanced filtering

queries = storage.find_by_date_range(1.week.ago..Time.current)
recent_queries = storage.recent(limit: 50)

Constant Summary collapse

DEFAULT_CLEANUP_DAYS =

Configuration constants

30
QUERIES_DIRECTORY =
"queries"
MAX_QUERIES_PER_FILE =
1000

Constants inherited from BaseStorage

BaseStorage::DEFAULT_PERMISSIONS, BaseStorage::JSON_FILE_EXTENSION

Instance Attribute Summary collapse

Attributes inherited from BaseStorage

#file_manager, #storage_path

Instance Method Summary collapse

Methods included from DateHelper

#cleanup_cutoff_date, #date_file_path, #format_date

Methods included from Concerns::Validatable

included, #valid_id?, #valid_name?, #validate_id!, #validate_name!, #validate_presence!

Methods included from Concerns::Timestampable

#age, included, #initialize_timestamps, #recently_created?, #recently_updated?, #touch_updated_at

Methods included from Concerns::ErrorHandler

#safe_operation, #with_error_handling

Constructor Details

#initialize(storage_path = nil) ⇒ QueryStorage

Initializes query storage with queries directory

Creates the queries directory if it doesn’t exist and sets up the necessary file structure for date-based organization.

Parameters:

  • storage_path (String, nil) (defaults to: nil)

    custom storage path (optional)



48
49
50
51
52
# File 'lib/dbwatcher/storage/query_storage.rb', line 48

def initialize(storage_path = nil)
  super
  @queries_path = File.join(self.storage_path, QUERIES_DIRECTORY)
  file_manager.ensure_directory(@queries_path)
end

Instance Attribute Details

#queries_pathString (readonly)

Returns path to queries directory.

Returns:

  • (String)

    path to queries directory



40
41
42
# File 'lib/dbwatcher/storage/query_storage.rb', line 40

def queries_path
  @queries_path
end

Instance Method Details

#cleanup_old_queries(days_to_keep = DEFAULT_CLEANUP_DAYS) ⇒ Integer

Removes old query files based on retention period

Parameters:

  • days_to_keep (Integer) (defaults to: DEFAULT_CLEANUP_DAYS)

    number of days of queries to retain

Returns:

  • (Integer)

    number of files removed



166
167
168
169
170
171
172
173
174
175
# File 'lib/dbwatcher/storage/query_storage.rb', line 166

def cleanup_old_queries(days_to_keep = DEFAULT_CLEANUP_DAYS)
  cutoff_date = cleanup_cutoff_date(days_to_keep)
  removed_count = 0

  cleanup_files_older_than(cutoff_date) do
    removed_count += 1
  end

  removed_count
end

#clear_allInteger

Clears all query logs

Returns:

  • (Integer)

    number of files removed



199
200
201
202
203
204
205
206
207
208
# File 'lib/dbwatcher/storage/query_storage.rb', line 199

def clear_all
  with_error_handling("clear all queries") do
    # Count files before deleting
    file_count = count_query_files

    safe_delete_directory(queries_path)

    file_count
  end
end

#countInteger

Counts total number of queries

Returns:

  • (Integer)

    total number of stored queries



139
140
141
142
143
# File 'lib/dbwatcher/storage/query_storage.rb', line 139

def count
  query_files.sum do |file|
    safe_read_json(file).size
  end
end

#count_by_date(date) ⇒ Integer

Counts queries for a specific date

Parameters:

  • date (Date, String)

    date to count queries for

Returns:

  • (Integer)

    number of queries for the date



149
150
151
# File 'lib/dbwatcher/storage/query_storage.rb', line 149

def count_by_date(date)
  find_by_date(date).size
end

#count_query_filesInteger

Counts the number of query files

Returns:

  • (Integer)

    number of query files



213
214
215
216
217
# File 'lib/dbwatcher/storage/query_storage.rb', line 213

def count_query_files
  return 0 unless Dir.exist?(@queries_path)

  query_files.count
end

#find_by_date(date) ⇒ Array<Hash>

Finds all queries for a specific date

Examples:

queries = storage.find_by_date(Date.current)
queries.each { |q| puts q[:sql] }

Parameters:

  • date (Date, String)

    the date to load queries for

Returns:

  • (Array<Hash>)

    array of query data for the specified date



100
101
102
103
# File 'lib/dbwatcher/storage/query_storage.rb', line 100

def find_by_date(date)
  query_file = date_file_path(@queries_path, date)
  safe_read_json(query_file)
end

#find_by_date_range(date_range) ⇒ Array<Hash>

Finds queries within a date range

Examples:

queries = storage.find_by_date_range(1.week.ago..Time.current)

Parameters:

  • date_range (Range)

    range of dates to search

Returns:

  • (Array<Hash>)

    array of query data within the date range



112
113
114
115
116
# File 'lib/dbwatcher/storage/query_storage.rb', line 112

def find_by_date_range(date_range)
  date_range.flat_map do |date|
    find_by_date(date)
  end
end

#load_for_date(date) ⇒ Array<Hash>

Deprecated.

Use #find_by_date instead

Loads all queries for a specific date (legacy method)

Parameters:

  • date (Date, String)

    the date to load queries for

Returns:

  • (Array<Hash>)

    array of query data



158
159
160
# File 'lib/dbwatcher/storage/query_storage.rb', line 158

def load_for_date(date)
  find_by_date(date)
end

#optimize_storageInteger

Optimizes storage by removing duplicate queries

Returns:

  • (Integer)

    number of duplicates removed



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/dbwatcher/storage/query_storage.rb', line 180

def optimize_storage
  duplicate_count = 0

  query_files.each do |file|
    queries = safe_read_json(file)
    unique_queries = queries.uniq { |q| [q[:sql], q[:timestamp]] }

    if unique_queries.size < queries.size
      duplicate_count += queries.size - unique_queries.size
      safe_write_json(file, unique_queries)
    end
  end

  duplicate_count
end

#recent(limit: 100) ⇒ Array<Hash>

Finds recent queries across all dates

Parameters:

  • limit (Integer) (defaults to: 100)

    maximum number of queries to return

Returns:

  • (Array<Hash>)

    array of recent query data



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/dbwatcher/storage/query_storage.rb', line 122

def recent(limit: 100)
  all_queries = []
  dates_descending.each do |date|
    daily_queries = find_by_date(date)
    all_queries.concat(daily_queries)
    break if all_queries.size >= limit
  end

  all_queries
    .sort_by { |q| q[:timestamp] }
    .reverse
    .first(limit)
end

#save(query) ⇒ Boolean

Saves a query to date-based storage

Validates the query and stores it in a daily file. Automatically applies size limits based on configuration to prevent excessive storage usage.

Examples:

query = { sql: "SELECT * FROM users", timestamp: Time.current }
storage.save(query) # => true

Parameters:

  • query (Hash)

    query data containing at least :sql and :timestamp

Returns:

  • (Boolean)

    true if saved successfully, false if invalid

Raises:



67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/dbwatcher/storage/query_storage.rb', line 67

def save(query)
  query_data = normalize_query_data(query)
  return false unless QueryValidator.valid?(query_data)

  date = format_date(query_data[:timestamp])
  query_file = date_file_path(@queries_path, date)

  queries = load_queries_from_file(query_file)
  queries = add_query_with_limits(queries, query_data)

  safe_write_json(query_file, queries)
end

#save!(query) ⇒ Boolean

Alternative save method that raises on failure

Parameters:

  • query (Hash)

    query data to save

Returns:

  • (Boolean)

    true if saved successfully

Raises:



86
87
88
89
90
# File 'lib/dbwatcher/storage/query_storage.rb', line 86

def save!(query)
  with_error_handling("save query") do
    save(query) or raise StorageError, "Failed to save query"
  end
end