Module: Whodunit::Chronicles::Persistence

Included in:
Processor
Defined in:
lib/whodunit/chronicles/persistence.rb

Overview

Handles record persistence for different database adapters

Provides adapter-specific SQL for inserting chronicle records

Instance Method Summary collapse

Instance Method Details

#build_record_params(record) ⇒ Object (private)



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/whodunit/chronicles/persistence.rb', line 109

def build_record_params(record)
  [
    record[:table_name],
    record[:schema_name],
    record[:record_id].to_json,
    record[:action],
    record[:old_data]&.to_json,
    record[:new_data]&.to_json,
    record[:changes].to_json,
    record[:user_id],
    record[:user_type],
    record[:transaction_id],
    record[:sequence_number],
    record[:occurred_at],
    record[:created_at],
    record[:metadata].to_json,
  ]
end

#persist_record(record) ⇒ Object (private)



11
12
13
14
15
16
17
18
19
20
# File 'lib/whodunit/chronicles/persistence.rb', line 11

def persist_record(record)
  db_type = detect_database_type(@audit_database_url || Chronicles.config.database_url)

  case db_type
  when :postgresql
    persist_record_postgresql(record)
  when :mysql
    persist_record_mysql(record)
  end
end

#persist_record_mysql(record) ⇒ Object (private)



39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/whodunit/chronicles/persistence.rb', line 39

def persist_record_mysql(record)
  sql = <<~SQL
    INSERT INTO whodunit_chronicles_audits (
      table_name, schema_name, record_id, action, old_data, new_data, changes,
      user_id, user_type, transaction_id, sequence_number, occurred_at, created_at, metadata
    ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
  SQL

  params = build_record_params(record)
  @connection.execute(sql, *params)
  record[:id] = @connection.last_insert_id

  record
end

#persist_record_postgresql(record) ⇒ Object (private)



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/whodunit/chronicles/persistence.rb', line 22

def persist_record_postgresql(record)
  sql = <<~SQL
    INSERT INTO whodunit_chronicles_audits (
      table_name, schema_name, record_id, action, old_data, new_data, changes,
      user_id, user_type, transaction_id, sequence_number, occurred_at, created_at, metadata
    ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
    RETURNING id
  SQL

  params = build_record_params(record)
  result = @connection.exec_params(sql, params)
  record[:id] = result.first['id'].to_i
  result.clear

  record
end

#persist_records_batch(records) ⇒ Object (private)



54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/whodunit/chronicles/persistence.rb', line 54

def persist_records_batch(records)
  return records if records.empty?

  db_type = detect_database_type(@audit_database_url || Chronicles.config.database_url)

  case db_type
  when :postgresql
    persist_records_batch_postgresql(records)
  when :mysql
    persist_records_batch_mysql(records)
  end
end

#persist_records_batch_mysql(records) ⇒ Object (private)



99
100
101
102
103
104
105
106
107
# File 'lib/whodunit/chronicles/persistence.rb', line 99

def persist_records_batch_mysql(records)
  # For MySQL, we'll use individual inserts in a transaction for simplicity
  # A more optimized version could use VALUES() with multiple rows
  records.each do |record|
    persist_record_mysql(record)
  end

  records
end

#persist_records_batch_postgresql(records) ⇒ Object (private)



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/whodunit/chronicles/persistence.rb', line 67

def persist_records_batch_postgresql(records)
  # Use multi-row INSERT for better performance
  values_clauses = []
  all_params = []
  param_index = 1

  records.each do |record|
    param_positions = (param_index..(param_index + 13)).map { |i| "$#{i}" }.join(', ')
    values_clauses << "(#{param_positions})"
    all_params.concat(build_record_params(record))
    param_index += 14
  end

  sql = <<~SQL
    INSERT INTO whodunit_chronicles_audits (
      table_name, schema_name, record_id, action, old_data, new_data, changes,
      user_id, user_type, transaction_id, sequence_number, occurred_at, created_at, metadata
    ) VALUES #{values_clauses.join(', ')}
    RETURNING id
  SQL

  result = @connection.exec_params(sql, all_params)

  # Set IDs on the records
  result.each_with_index do |row, index|
    records[index][:id] = row['id'].to_i
  end

  result.clear
  records
end