db_wrapper 0.0.1
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 +7 -0
- data/.gitignore +7 -0
- data/Gemfile +2 -0
- data/README.md +33 -0
- data/Rakefile +6 -0
- data/benchmark/mysql_access.rb +30 -0
- data/benchmark/mysql_proxy.rb +9 -0
- data/db_wrapper.gemspec +21 -0
- data/lib/db_wrapper.rb +11 -0
- data/lib/db_wrapper/database_proxy.rb +54 -0
- data/lib/db_wrapper/listeners/client_listener.rb +22 -0
- data/lib/db_wrapper/listeners/crud.rb +11 -0
- data/lib/db_wrapper/listeners/simple_command_detector.rb +7 -0
- data/lib/db_wrapper/listeners_controller.rb +19 -0
- data/lib/db_wrapper/protocols/mysql_protocol.rb +10 -0
- data/lib/db_wrapper/util/underscore.rb +11 -0
- data/lib/db_wrapper/version.rb +3 -0
- data/spec/database_proxy_spec.rb +55 -0
- data/spec/listeners/client_listener_spec.rb +20 -0
- data/spec/listeners/crud_spec.rb +30 -0
- data/spec/listeners_controller_spec.rb +35 -0
- data/spec/protocols/mysql_protocol_spec.rb +29 -0
- data/spec/spec_helper.rb +8 -0
- metadata +127 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bd375ea049a96b97ec0275f07022f986d8bda96b
|
4
|
+
data.tar.gz: 4e8f284605c832eec9426b2b5f8d2675b089e3f9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e1a2f2347b482b5770952d859769c73075f744af21879565ffaac7d5a8ccd1b55c9cf0807a742a7b90461f69528398d44e539e1efc9b139b23ee259ecfd5adf2
|
7
|
+
data.tar.gz: 51a543f85b9ffdce8112e284b5b368c9bb71c4f6f7e0850f73709e6d0a07fee472be38be69b0e227cdce2cbde820a1f02eb2bf6c1a8dd0154c617bd2ae9c9423
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# db_wrapper #
|
2
|
+
|
3
|
+
## What is db_wrapper ? ##
|
4
|
+
|
5
|
+
db_wrapper is a Ruby gem that allows the creation of listeners to every database call you make in a transparent way.
|
6
|
+
|
7
|
+
## How does it work ? ##
|
8
|
+
|
9
|
+
It creates a super lightweight TCP proxy that will redirect every database call to the proxied database (in a **non blocking way**) to another process that will call the listeners you registered. Everything happens in a different process so the listeners won't impact the database query performance.
|
10
|
+
|
11
|
+
The fact that it works like a proxy allows you to create listeners without changing your application code and without needing to worry about performance.
|
12
|
+
|
13
|
+
## Which databases does it support ? ##
|
14
|
+
|
15
|
+
* Mysql
|
16
|
+
* PostgreSQL (future)
|
17
|
+
* MongoDB (future)
|
18
|
+
|
19
|
+
The protocol implementation is simple so you can easily extend it by yourself to support a
|
20
|
+
different database (and send me the pull request if you want)
|
21
|
+
|
22
|
+
## Next steps ##
|
23
|
+
* PostgreSQL protocol
|
24
|
+
* MongoDB protocol
|
25
|
+
* Examples and documentation
|
26
|
+
* Server listeners - Listeners that would get data sent from the server to the client, also in a non blocking way
|
27
|
+
|
28
|
+
## License and copyright ##
|
29
|
+
|
30
|
+
db_wrapper is copyrighted free software made available under the terms
|
31
|
+
of either the GPL or Ruby's License.
|
32
|
+
|
33
|
+
Copyright: (C) 2014 by Pedro Sena. All Rights Reserved.
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
require 'mysql2'
|
3
|
+
require_relative '../lib/db_wrapper'
|
4
|
+
|
5
|
+
client = Mysql2::Client.new host: '127.0.0.1', username: 'db_wrapper', password: 'db_wrapper', database: 'db_wrapper_benchmark'
|
6
|
+
|
7
|
+
insert = "insert into test values(null, 'some description here', now(), null)"
|
8
|
+
select = 'select * from test'
|
9
|
+
delete = 'delete from test'
|
10
|
+
update = "update test set description = 'another description'"
|
11
|
+
|
12
|
+
iterations = ARGV.first.to_i
|
13
|
+
|
14
|
+
Benchmark.bm do |bm|
|
15
|
+
|
16
|
+
bm.report('Proxied access') do
|
17
|
+
client = Mysql2::Client.new host: '127.0.0.1', username: 'db_wrapper', password: 'db_wrapper', database: 'db_wrapper_benchmark', port: 3307
|
18
|
+
iterations.times do
|
19
|
+
client.query select
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
bm.report('Direct access') do
|
24
|
+
client = Mysql2::Client.new host: '127.0.0.1', username: 'db_wrapper', password: 'db_wrapper', database: 'db_wrapper_benchmark', port: 3306
|
25
|
+
iterations.times do
|
26
|
+
client.query select
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require_relative '../lib/db_wrapper'
|
2
|
+
|
3
|
+
database_proxy = DBWrapper::DatabaseProxy.new '127.0.0.1', 3307, '127.0.0.1', 3306
|
4
|
+
database_proxy.protocol = DBWrapper::MysqlProtocol.new
|
5
|
+
database_proxy.add_client_listener(DBWrapper::Listeners::Select.new do
|
6
|
+
puts 'SelectListener found command: ' + command
|
7
|
+
end)
|
8
|
+
|
9
|
+
database_proxy.start!
|
data/db_wrapper.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path('../lib/db_wrapper/version', __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'db_wrapper'
|
5
|
+
spec.version = DBWrapper::VERSION
|
6
|
+
spec.date = '2014-01-24'
|
7
|
+
spec.description = spec.summary = 'Create custom ruby listeners/interceptors for any database'
|
8
|
+
spec.authors = ['Pedro Sena']
|
9
|
+
spec.email = 'sena.pedro@gmail.com'
|
10
|
+
spec.homepage = 'https://github.com/PedroSena/db_wrapper'
|
11
|
+
spec.license = 'MIT'
|
12
|
+
|
13
|
+
spec.add_development_dependency 'rspec'
|
14
|
+
spec.add_development_dependency 'em-http-request'
|
15
|
+
spec.add_dependency 'em-proxy'
|
16
|
+
spec.add_dependency 'log4r'
|
17
|
+
|
18
|
+
spec.files = `git ls-files`.split "\n"
|
19
|
+
spec.test_files = `git ls-files -- spec/*`.split "\n"
|
20
|
+
spec.require_paths = %w(lib)
|
21
|
+
end
|
data/lib/db_wrapper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/db_wrapper')
|
2
|
+
|
3
|
+
require 'em-proxy'
|
4
|
+
require 'log4r'
|
5
|
+
require 'socket'
|
6
|
+
|
7
|
+
Log = Log4r::Logger.new 'db_wrapper'
|
8
|
+
Log.add Log4r::Outputter.stderr
|
9
|
+
Log.level = Log4r::DEBUG
|
10
|
+
|
11
|
+
Gem.find_files("#{File.dirname(__FILE__)}/**/*.rb").each { |file| require file }
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module DBWrapper
|
2
|
+
class DatabaseProxy
|
3
|
+
|
4
|
+
attr_reader :host, :port, :database_host, :database_port, :listener_server_socket
|
5
|
+
attr_accessor :protocol
|
6
|
+
|
7
|
+
def initialize(host, port, database_host, database_port)
|
8
|
+
@host = host
|
9
|
+
@port = port
|
10
|
+
@database_host = database_host
|
11
|
+
@database_port = database_port
|
12
|
+
@client_listeners = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_client_listener(client_listener)
|
16
|
+
@client_listeners << client_listener
|
17
|
+
end
|
18
|
+
|
19
|
+
def start!
|
20
|
+
raise 'No protocol was given' if self.protocol.nil?
|
21
|
+
listener_server_port = create_listener_server.addr[1]
|
22
|
+
@listener_server_socket = TCPSocket.new(self.host, listener_server_port)
|
23
|
+
database_proxy = self
|
24
|
+
Proxy.start(host: @host, port: @port) do |conn|
|
25
|
+
conn.server :database, host: database_proxy.database_host, port: database_proxy.database_port, relay_server: true
|
26
|
+
|
27
|
+
conn.on_data do |data|
|
28
|
+
database_proxy.listener_server_socket.write_nonblock(data)
|
29
|
+
data
|
30
|
+
end
|
31
|
+
|
32
|
+
conn.on_finish do |server, name|
|
33
|
+
unbind if server == :database
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_listener_server
|
39
|
+
listener_server = TCPServer.new(host, 0) #Creates on first free port it can find
|
40
|
+
client_listeners_controller = ListenersController.new @client_listeners
|
41
|
+
fork do
|
42
|
+
Socket.accept_loop(listener_server) do |connection|
|
43
|
+
begin
|
44
|
+
while data = connection.readpartial(self.protocol.max_packet_size) do
|
45
|
+
client_listeners_controller.call_listeners(self.protocol, data)
|
46
|
+
end
|
47
|
+
rescue Interrupt; end #Thrown when you send a termination signal
|
48
|
+
end
|
49
|
+
end
|
50
|
+
listener_server
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#Base listener for all data sent from the client to the database
|
2
|
+
module DBWrapper
|
3
|
+
module Listeners
|
4
|
+
class ClientListener
|
5
|
+
|
6
|
+
attr_accessor :command
|
7
|
+
|
8
|
+
def initialize(&block)
|
9
|
+
@block = block
|
10
|
+
end
|
11
|
+
|
12
|
+
def perform
|
13
|
+
instance_eval(&@block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def listening?(query)
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'listeners/client_listener'
|
2
|
+
require 'listeners/simple_command_detector'
|
3
|
+
|
4
|
+
module DBWrapper
|
5
|
+
module Listeners
|
6
|
+
class Select < DBWrapper::Listeners::ClientListener; include DBWrapper::SimpleCommandDetector; end
|
7
|
+
class Insert < DBWrapper::Listeners::ClientListener; include DBWrapper::SimpleCommandDetector; end
|
8
|
+
class Update < DBWrapper::Listeners::ClientListener; include DBWrapper::SimpleCommandDetector; end
|
9
|
+
class Delete < DBWrapper::Listeners::ClientListener; include DBWrapper::SimpleCommandDetector; end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module DBWrapper
|
2
|
+
class ListenersController
|
3
|
+
|
4
|
+
def initialize(listeners)
|
5
|
+
@listeners = listeners
|
6
|
+
end
|
7
|
+
|
8
|
+
def call_listeners(protocol, raw_command)
|
9
|
+
return if @listeners.nil?
|
10
|
+
parsed_command = protocol.parse_command raw_command
|
11
|
+
return if parsed_command.empty?
|
12
|
+
@listeners.select { |listener| listener.listening?(parsed_command) }.each do |listener|
|
13
|
+
listener.command = parsed_command
|
14
|
+
listener.perform
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'em-http-request'
|
3
|
+
|
4
|
+
describe DBWrapper::DatabaseProxy do
|
5
|
+
|
6
|
+
let(:proxy) { DBWrapper::DatabaseProxy.new '127.0.0.1','3307', '127.0.0.1', '3306' }
|
7
|
+
|
8
|
+
it 'should allow only read of proxy and db connection data' do
|
9
|
+
%w(host port database_host database_port).each do |attr|
|
10
|
+
expect(proxy.send(attr.to_sym)).to_not be_nil
|
11
|
+
expect(proxy.respond_to?("#{attr}=".to_sym)).to be false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'calls the client listeners while running' do
|
16
|
+
called = false
|
17
|
+
EM.run do
|
18
|
+
EventMachine.add_timer(0.1) do
|
19
|
+
sock = TCPSocket.new '127.0.0.1', 3307
|
20
|
+
sock.send "\x10\x00\x00\x00\x03" + 'Select 1 from something;', 0
|
21
|
+
sock.close
|
22
|
+
end
|
23
|
+
EventMachine.add_timer(0.2) do
|
24
|
+
EM.stop
|
25
|
+
end
|
26
|
+
|
27
|
+
proxy.protocol = DBWrapper::MysqlProtocol.new
|
28
|
+
listener = DBWrapper::Listeners::Select.new do
|
29
|
+
called = true
|
30
|
+
end
|
31
|
+
proxy.add_client_listener(listener)
|
32
|
+
Socket.should_receive(:accept_loop) do |&block|
|
33
|
+
listener.perform
|
34
|
+
end
|
35
|
+
proxy.should_receive(:fork) do |&block|
|
36
|
+
block.call
|
37
|
+
end
|
38
|
+
proxy.start!
|
39
|
+
end
|
40
|
+
expect(called).to be true
|
41
|
+
end
|
42
|
+
|
43
|
+
describe 'add_client_listener' do
|
44
|
+
let(:listener) { DBWrapper::Listeners::Select.new do; end }
|
45
|
+
before(:each) do
|
46
|
+
proxy.add_client_listener listener
|
47
|
+
end
|
48
|
+
let(:client_listeners) { proxy.instance_variable_get(:@client_listeners) }
|
49
|
+
|
50
|
+
it 'adds a listener' do
|
51
|
+
expect(client_listeners.size).to eq 1
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DBWrapper::Listeners::ClientListener do
|
4
|
+
let(:client_listener) { DBWrapper::Listeners::ClientListener.new do; end }
|
5
|
+
it 'is listening to every query' do
|
6
|
+
['select 1 from a', 'insert into a(col1) values(1)', 'update a set col1=val1 where col1=something', 'delete from a where col1=something'].each do |query|
|
7
|
+
expect(client_listener.listening?(query)).to be true
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'executes the code block on perform' do
|
12
|
+
executed = false
|
13
|
+
listener = DBWrapper::Listeners::ClientListener.new do
|
14
|
+
executed = true
|
15
|
+
end
|
16
|
+
listener.perform
|
17
|
+
expect(executed).to be true
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DBWrapper::SimpleCommandDetector do
|
4
|
+
|
5
|
+
let(:commands) { ['select 1 from a', 'insert into a(col1) values(val1)', 'update a set col1=val1', 'delete from a'] }
|
6
|
+
|
7
|
+
%w(select insert update delete).each do |command|
|
8
|
+
describe "#{command}" do
|
9
|
+
it "listens only to #{command} commands" do
|
10
|
+
correct_command = commands.select { |sql_command| sql_command.start_with?(command) }.first
|
11
|
+
listener = get_listener(correct_command)
|
12
|
+
expect(listener.listening?(correct_command)).to be true
|
13
|
+
commands.reject { |sql_command| sql_command == correct_command }.each do |unallowed_command|
|
14
|
+
expect(listener.listening?(unallowed_command)).to be false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
#Object.const_get didnt work in rubinius =/
|
21
|
+
def get_listener(command)
|
22
|
+
case command.split(' ').first
|
23
|
+
when 'select' then DBWrapper::Listeners::Select.new
|
24
|
+
when 'insert' then DBWrapper::Listeners::Insert.new
|
25
|
+
when 'update' then DBWrapper::Listeners::Update.new
|
26
|
+
when 'delete' then DBWrapper::Listeners::Delete.new
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DBWrapper::ListenersController do
|
4
|
+
|
5
|
+
describe 'call_listeners' do
|
6
|
+
let(:listener) { DBWrapper::Listeners::Select.new { raise self.command } }
|
7
|
+
|
8
|
+
it 'calls #perform on the listener' do
|
9
|
+
module EventMachine
|
10
|
+
def self.defer(op = nil, callback = nil, &blk)
|
11
|
+
op.call
|
12
|
+
end
|
13
|
+
end
|
14
|
+
EM.run do
|
15
|
+
controller = DBWrapper::ListenersController.new [listener]
|
16
|
+
command = 'select 1 from a'
|
17
|
+
protocol = Object.new
|
18
|
+
allow(protocol).to receive(:parse_command).and_return(command)
|
19
|
+
allow(protocol).to receive(:detect_interested_observers).and_return([:select])
|
20
|
+
expect { controller.call_listeners protocol, command }.to raise_error(command)
|
21
|
+
EM.stop
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'will ignore if no listener is bound to specific command' do
|
26
|
+
controller = DBWrapper::ListenersController.new([])
|
27
|
+
command = 'select 1 from a'
|
28
|
+
protocol = Object.new
|
29
|
+
allow(protocol).to receive(:parse_command).and_return(command)
|
30
|
+
allow(protocol).to receive(:detect_interested_observers).and_return([:select])
|
31
|
+
controller.call_listeners protocol, command
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DBWrapper::MysqlProtocol do
|
4
|
+
let(:protocol) { DBWrapper::MysqlProtocol.new }
|
5
|
+
|
6
|
+
describe 'parse_command - removing non-sql data' do
|
7
|
+
def test_parse(clean_string, dirty_string)
|
8
|
+
expect(protocol.parse_command(dirty_string)).to eq clean_string
|
9
|
+
end
|
10
|
+
it 'parses a select command' do
|
11
|
+
clean_string = 'select a from b'
|
12
|
+
dirty_string = "\x10\x00\x00\x00\x03" + clean_string
|
13
|
+
test_parse clean_string, dirty_string
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'parses a insert command' do
|
17
|
+
clean_string = 'insert into a(col1) values(1)'
|
18
|
+
dirty_string = "\x1E\x00\x00\x00\x03" + clean_string
|
19
|
+
test_parse clean_string, dirty_string
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'parses a update command' do
|
23
|
+
clean_string = "update a set col1 = 'val1' where col1 > 1"
|
24
|
+
dirty_string = "*\x00\x00\x00\x03" + clean_string
|
25
|
+
test_parse clean_string, dirty_string
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: db_wrapper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pedro Sena
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: em-http-request
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: em-proxy
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: log4r
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Create custom ruby listeners/interceptors for any database
|
70
|
+
email: sena.pedro@gmail.com
|
71
|
+
executables: []
|
72
|
+
extensions: []
|
73
|
+
extra_rdoc_files: []
|
74
|
+
files:
|
75
|
+
- .gitignore
|
76
|
+
- Gemfile
|
77
|
+
- README.md
|
78
|
+
- Rakefile
|
79
|
+
- benchmark/mysql_access.rb
|
80
|
+
- benchmark/mysql_proxy.rb
|
81
|
+
- db_wrapper.gemspec
|
82
|
+
- lib/db_wrapper.rb
|
83
|
+
- lib/db_wrapper/database_proxy.rb
|
84
|
+
- lib/db_wrapper/listeners/client_listener.rb
|
85
|
+
- lib/db_wrapper/listeners/crud.rb
|
86
|
+
- lib/db_wrapper/listeners/simple_command_detector.rb
|
87
|
+
- lib/db_wrapper/listeners_controller.rb
|
88
|
+
- lib/db_wrapper/protocols/mysql_protocol.rb
|
89
|
+
- lib/db_wrapper/util/underscore.rb
|
90
|
+
- lib/db_wrapper/version.rb
|
91
|
+
- spec/database_proxy_spec.rb
|
92
|
+
- spec/listeners/client_listener_spec.rb
|
93
|
+
- spec/listeners/crud_spec.rb
|
94
|
+
- spec/listeners_controller_spec.rb
|
95
|
+
- spec/protocols/mysql_protocol_spec.rb
|
96
|
+
- spec/spec_helper.rb
|
97
|
+
homepage: https://github.com/PedroSena/db_wrapper
|
98
|
+
licenses:
|
99
|
+
- MIT
|
100
|
+
metadata: {}
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 2.1.11
|
118
|
+
signing_key:
|
119
|
+
specification_version: 4
|
120
|
+
summary: Create custom ruby listeners/interceptors for any database
|
121
|
+
test_files:
|
122
|
+
- spec/database_proxy_spec.rb
|
123
|
+
- spec/listeners/client_listener_spec.rb
|
124
|
+
- spec/listeners/crud_spec.rb
|
125
|
+
- spec/listeners_controller_spec.rb
|
126
|
+
- spec/protocols/mysql_protocol_spec.rb
|
127
|
+
- spec/spec_helper.rb
|