database_recorder 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/database_recorder/mysql2/client_ext.rb +2 -2
- data/lib/database_recorder/mysql2/recorder.rb +41 -25
- data/lib/database_recorder/mysql2/statement_ext.rb +1 -1
- data/lib/database_recorder/pg/connection_ext.rb +14 -18
- data/lib/database_recorder/pg/recorder.rb +37 -10
- data/lib/database_recorder/recording.rb +17 -6
- data/lib/database_recorder/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c43f3f7036d73a7133d4a79984dc7035ec2ccfcaccbf23b3e2f36053debc0f5
|
4
|
+
data.tar.gz: 0d8bc0cdf33d2626811f95bfac45b6dfce0383455a39b58940350048c9d92a70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 611e9419ea6c8f1e536c2b0ba5ad19b46327842e15032168c14db5ac8d109cca14a15bf000329538b894851bb51e6ceaf22fc5970356f31f2f3abd182cced339
|
7
|
+
data.tar.gz: 25eba80806a035ca9da8063a1d745e218b3a0851b008fb0b31b3036680c82758210fa596d3386d31daed0bbee72041242150bcadd37337a828918ee511c0fdb1
|
@@ -4,13 +4,13 @@ module DatabaseRecorder
|
|
4
4
|
module Mysql2
|
5
5
|
module ClientExt
|
6
6
|
def query(sql, options = {})
|
7
|
-
Recorder.
|
7
|
+
Recorder.store_query(self, sql: sql, source: :query) do
|
8
8
|
super
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
def prepare(*args)
|
13
|
-
Recorder.
|
13
|
+
Recorder.prepare_statement(self, sql: args[0], source: :prepare) do
|
14
14
|
super
|
15
15
|
end
|
16
16
|
end
|
@@ -12,29 +12,16 @@ module DatabaseRecorder
|
|
12
12
|
sql.match?(/information_schema.statistics/)
|
13
13
|
end
|
14
14
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
data = Recording.cached_query_for(sql)
|
22
|
-
return yield unless data # cache miss
|
15
|
+
def format_result(result)
|
16
|
+
{ 'count' => result.count, 'fields' => result.fields, 'values' => result.to_a } if result.is_a?(::Mysql2::Result)
|
17
|
+
# else
|
18
|
+
# last_insert_id = adapter.query('SELECT LAST_INSERT_ID() AS _dbr_last_insert_id').to_a
|
19
|
+
# { 'count' => last_insert_id.count, 'fields' => ['id'], 'values' => last_insert_id }
|
20
|
+
end
|
23
21
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
result_data =
|
28
|
-
if result.is_a? ::Mysql2::Result
|
29
|
-
{ 'count' => result.count, 'fields' => result.fields, 'values' => result.to_a }
|
30
|
-
# else
|
31
|
-
# last_insert_id = adapter.query('SELECT LAST_INSERT_ID() AS _dbr_last_insert_id').to_a
|
32
|
-
# { 'count' => last_insert_id.count, 'fields' => ['id'], 'values' => last_insert_id }
|
33
|
-
end
|
34
|
-
|
35
|
-
Recording.push(sql: sql, result: result_data)
|
36
|
-
end
|
37
|
-
end
|
22
|
+
def prepare_statement(adapter, sql: nil, name: nil, binds: nil, source: nil)
|
23
|
+
@last_prepared = Recording.push_prepared(name: name, sql: sql, binds: binds, source: source)
|
24
|
+
yield if !Config.replay_recordings || Recording.cache.nil?
|
38
25
|
end
|
39
26
|
|
40
27
|
def setup
|
@@ -47,9 +34,38 @@ module DatabaseRecorder
|
|
47
34
|
end
|
48
35
|
end
|
49
36
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
37
|
+
def store_prepared_statement(adapter, source:, binds:)
|
38
|
+
# sql = @last_prepared&.send(:[], 'sql')
|
39
|
+
sql = @last_prepared['sql']
|
40
|
+
Core.log_query(sql, source)
|
41
|
+
if Config.replay_recordings && !Recording.cache.nil?
|
42
|
+
data = Recording.cache.find { |query| query['sql'] == sql }
|
43
|
+
return yield unless data # cache miss
|
44
|
+
|
45
|
+
Recording.push(sql: data['sql'], binds: data['binds'], source: source)
|
46
|
+
RecordedResult.new(data['result'].slice('count', 'fields', 'values'))
|
47
|
+
else
|
48
|
+
yield.tap do |result|
|
49
|
+
Recording.update_prepared(sql: sql, binds: binds, result: format_result(result), source: source)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def store_query(adapter, sql:, source:)
|
55
|
+
return yield if ignore_query?(sql)
|
56
|
+
|
57
|
+
Core.log_query(sql, source)
|
58
|
+
if Config.replay_recordings && !Recording.cache.nil?
|
59
|
+
Recording.push(sql: sql, source: source)
|
60
|
+
data = Recording.cached_query_for(sql)
|
61
|
+
return yield unless data # cache miss
|
62
|
+
|
63
|
+
RecordedResult.new.prepare(data['result'].slice('count', 'fields', 'values')) if data['result']
|
64
|
+
else
|
65
|
+
yield.tap do |result|
|
66
|
+
Recording.push(sql: sql, result: format_result(result), source: source)
|
67
|
+
end
|
68
|
+
end
|
53
69
|
end
|
54
70
|
end
|
55
71
|
end
|
@@ -4,47 +4,43 @@ module DatabaseRecorder
|
|
4
4
|
module PG
|
5
5
|
module ConnectionExt
|
6
6
|
def async_exec(sql)
|
7
|
-
Recorder.
|
7
|
+
Recorder.store_query(sql: sql, source: :async_exec) do
|
8
8
|
super
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
def sync_exec(sql)
|
13
|
-
Recorder.
|
13
|
+
Recorder.store_query(sql: sql, source: :sync_exec) do
|
14
14
|
super
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
def exec(*args)
|
19
|
-
Recorder.
|
19
|
+
Recorder.store_query(sql: args[0], source: :exec) do
|
20
20
|
super
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
def
|
25
|
-
Recorder.
|
24
|
+
def exec_params(*args)
|
25
|
+
Recorder.store_query(sql: args[0], binds: args[1], source: :exec_params) do
|
26
26
|
super
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
Recorder.
|
30
|
+
def exec_prepared(*args)
|
31
|
+
Recorder.store_prepared_statement(name: args[0], binds: args[1], source: :exec_prepared) do
|
32
32
|
super
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# def sync_exec_params(*args)
|
42
|
-
# puts ">>> #{args[0]}"
|
43
|
-
# super
|
44
|
-
# end
|
36
|
+
def prepare(*args)
|
37
|
+
Recorder.prepare_statement(name: args[0], sql: args[1], source: :prepare) do
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
45
41
|
|
46
|
-
def
|
47
|
-
Recorder.
|
42
|
+
def query(*args)
|
43
|
+
Recorder.store_query(sql: args[0], source: :query) do
|
48
44
|
super
|
49
45
|
end
|
50
46
|
end
|
@@ -11,29 +11,56 @@ module DatabaseRecorder
|
|
11
11
|
sql.match?(/ pg_attribute |SHOW max_identifier_length|SHOW search_path/)
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
14
|
+
def format_result(result)
|
15
|
+
{ 'count' => result.count, 'fields' => result.fields, 'values' => result.values } if result
|
16
|
+
end
|
17
|
+
|
18
|
+
def prepare_statement(sql: nil, name: nil, binds: nil, source: nil)
|
19
|
+
Recording.push_prepared(name: name, sql: sql, binds: binds, source: source)
|
20
|
+
yield if !Config.replay_recordings || Recording.cache.nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
def setup
|
24
|
+
::PG::Connection.class_eval do
|
25
|
+
prepend ConnectionExt
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def store_prepared_statement(name: nil, sql: nil, binds: nil, source: nil)
|
30
|
+
if Config.replay_recordings && !Recording.cache.nil?
|
31
|
+
data = Recording.cache.find { |query| query['name'] == name }
|
32
|
+
return yield unless data # cache miss
|
33
|
+
|
34
|
+
Core.log_query(data['sql'], source)
|
35
|
+
Recording.push(sql: data['sql'], binds: data['binds'], source: source)
|
36
|
+
RecordedResult.new(data['result'].slice('count', 'fields', 'values'))
|
37
|
+
else
|
38
|
+
Core.log_query(sql, source)
|
39
|
+
yield.tap do |query_result|
|
40
|
+
result = format_result(query_result)
|
41
|
+
query = Recording.update_prepared(name: name, sql: sql, binds: binds, result: result, source: source)
|
42
|
+
Core.log_query(query['sql'], source)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def store_query(name: nil, sql: nil, binds: nil, source: nil)
|
15
48
|
return yield if ignore_query?(sql)
|
16
49
|
|
17
50
|
Core.log_query(sql, source)
|
51
|
+
@prepared_statement = nil
|
18
52
|
if Config.replay_recordings && !Recording.cache.nil?
|
19
|
-
Recording.push(sql: sql, binds: binds)
|
53
|
+
Recording.push(sql: sql, binds: binds, source: source)
|
20
54
|
data = Recording.cached_query_for(sql)
|
21
55
|
return yield unless data # cache miss
|
22
56
|
|
23
57
|
RecordedResult.new(data['result'].slice('count', 'fields', 'values'))
|
24
58
|
else
|
25
59
|
yield.tap do |result|
|
26
|
-
|
27
|
-
Recording.push(sql: sql, binds: binds, result: result_data)
|
60
|
+
Recording.push(name: name, sql: sql, binds: binds, result: format_result(result), source: source)
|
28
61
|
end
|
29
62
|
end
|
30
63
|
end
|
31
|
-
|
32
|
-
def setup
|
33
|
-
::PG::Connection.class_eval do
|
34
|
-
prepend ConnectionExt
|
35
|
-
end
|
36
|
-
end
|
37
64
|
end
|
38
65
|
end
|
39
66
|
end
|
@@ -5,7 +5,7 @@ require 'forwardable'
|
|
5
5
|
module DatabaseRecorder
|
6
6
|
class Recording
|
7
7
|
attr_accessor :cache, :entities
|
8
|
-
attr_reader :from_cache, :options, :queries, :started
|
8
|
+
attr_reader :from_cache, :options, :prepared_queries, :queries, :started
|
9
9
|
|
10
10
|
def initialize(options: {})
|
11
11
|
(@@instances ||= {})[Process.pid] = self
|
@@ -14,6 +14,7 @@ module DatabaseRecorder
|
|
14
14
|
@options = options
|
15
15
|
@queries = []
|
16
16
|
@search_index = 0
|
17
|
+
@@prepared_queries ||= {}
|
17
18
|
end
|
18
19
|
|
19
20
|
def cached_query_for(sql)
|
@@ -38,11 +39,16 @@ module DatabaseRecorder
|
|
38
39
|
@entities.shift
|
39
40
|
end
|
40
41
|
|
41
|
-
def push(sql:, binds: nil, result: nil,
|
42
|
+
def push(sql:, name: nil, binds: nil, result: nil, source: nil)
|
42
43
|
query = { 'name' => name, 'sql' => sql, 'binds' => binds, 'result' => result }.compact
|
43
44
|
@queries.push(query)
|
44
45
|
end
|
45
46
|
|
47
|
+
def push_prepared(name: nil, sql: nil, binds: nil, result: nil, source: nil)
|
48
|
+
query = { 'name' => name, 'sql' => sql, 'binds' => binds, 'result' => result }.compact
|
49
|
+
@@prepared_queries[name || sql] = query
|
50
|
+
end
|
51
|
+
|
46
52
|
def start
|
47
53
|
@started = true
|
48
54
|
storage = Config.storage&.new(self, name: options[:name])
|
@@ -55,15 +61,20 @@ module DatabaseRecorder
|
|
55
61
|
result
|
56
62
|
end
|
57
63
|
|
58
|
-
def
|
59
|
-
|
64
|
+
def update_prepared(name: nil, sql: nil, binds: nil, result: nil, source: nil)
|
65
|
+
query = @@prepared_queries[name || sql]
|
66
|
+
query['sql'] = sql if sql
|
67
|
+
query['binds'] = binds if binds
|
68
|
+
query['result'] = result if result
|
69
|
+
@queries.push(query)
|
70
|
+
query
|
60
71
|
end
|
61
72
|
|
62
73
|
class << self
|
63
74
|
extend Forwardable
|
64
75
|
|
65
|
-
def_delegators :current_instance, :cache, :cached_query_for, :from_cache, :new_entity, :
|
66
|
-
:queries, :
|
76
|
+
def_delegators :current_instance, :cache, :cached_query_for, :from_cache, :new_entity, :prepared_queries,
|
77
|
+
:pull_entity, :push, :push_prepared, :queries, :update_prepared
|
67
78
|
|
68
79
|
def current_instance
|
69
80
|
(@@instances ||= {})[Process.pid]
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: database_recorder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mattia Roccoberton
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-04-
|
11
|
+
date: 2022-04-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: coderay
|