database_recorder 0.1.1 → 0.2.0
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 +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
|