sq-dbsync 1.0.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.
- data/HISTORY.md +5 -0
- data/LICENSE +14 -0
- data/README.md +218 -0
- data/lib/sq/dbsync/all_tables_plan.rb +51 -0
- data/lib/sq/dbsync/batch_load_action.rb +95 -0
- data/lib/sq/dbsync/config.rb +12 -0
- data/lib/sq/dbsync/consistency_verifier.rb +70 -0
- data/lib/sq/dbsync/database/common.rb +91 -0
- data/lib/sq/dbsync/database/connection.rb +23 -0
- data/lib/sq/dbsync/database/mysql.rb +163 -0
- data/lib/sq/dbsync/database/postgres.rb +77 -0
- data/lib/sq/dbsync/error_handler.rb +59 -0
- data/lib/sq/dbsync/example_record_destroyer.rb +77 -0
- data/lib/sq/dbsync/incremental_load_action.rb +95 -0
- data/lib/sq/dbsync/load_action.rb +156 -0
- data/lib/sq/dbsync/loggers.rb +135 -0
- data/lib/sq/dbsync/manager.rb +241 -0
- data/lib/sq/dbsync/pipeline/simple_context.rb +15 -0
- data/lib/sq/dbsync/pipeline/threaded_context.rb +95 -0
- data/lib/sq/dbsync/pipeline.rb +80 -0
- data/lib/sq/dbsync/refresh_recent_load_action.rb +71 -0
- data/lib/sq/dbsync/schema_maker.rb +87 -0
- data/lib/sq/dbsync/static_table_plan.rb +42 -0
- data/lib/sq/dbsync/table_registry.rb +75 -0
- data/lib/sq/dbsync/tempfile_factory.rb +41 -0
- data/lib/sq/dbsync/version.rb +5 -0
- data/lib/sq/dbsync.rb +9 -0
- data/spec/acceptance/loading_spec.rb +237 -0
- data/spec/acceptance_helper.rb +2 -0
- data/spec/database_helper.rb +86 -0
- data/spec/integration/all_tables_plan_spec.rb +36 -0
- data/spec/integration/batch_load_action_spec.rb +229 -0
- data/spec/integration/consistency_verifier_spec.rb +54 -0
- data/spec/integration/database_connection_spec.rb +61 -0
- data/spec/integration/incremental_load_action_spec.rb +196 -0
- data/spec/integration/manager_spec.rb +109 -0
- data/spec/integration/schema_maker_spec.rb +119 -0
- data/spec/integration_helper.rb +43 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/unit/config_spec.rb +18 -0
- data/spec/unit/error_handler_spec.rb +52 -0
- data/spec/unit/pipeline_spec.rb +42 -0
- data/spec/unit/stream_logger_spec.rb +33 -0
- data/spec/unit_helper.rb +1 -0
- data/sq-dbsync.gemspec +32 -0
- metadata +188 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
require 'integration_helper'
|
|
2
|
+
|
|
3
|
+
require 'sq/dbsync/schema_maker'
|
|
4
|
+
require 'ostruct'
|
|
5
|
+
|
|
6
|
+
describe SQD::SchemaMaker do
|
|
7
|
+
let(:target) { test_target }
|
|
8
|
+
|
|
9
|
+
it 'creates a table with a compound index' do
|
|
10
|
+
index = {
|
|
11
|
+
index_on_col1: { columns: [:col1, :col2], unique: false }
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
plan = {
|
|
15
|
+
prefixed_table_name: :test_table,
|
|
16
|
+
table_name: :test_table,
|
|
17
|
+
columns: [:col1, :col2],
|
|
18
|
+
indexes: index,
|
|
19
|
+
schema: {
|
|
20
|
+
col1: { db_type: 'varchar(255)', primary_key: true },
|
|
21
|
+
col2: { db_type: 'varchar(255)', primary_key: false }
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
described_class.create_table(target, OpenStruct.new(plan))
|
|
26
|
+
|
|
27
|
+
target.indexes(:test_table).should == index
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'defaults primary key to id' do
|
|
31
|
+
plan = {
|
|
32
|
+
prefixed_table_name: :test_table,
|
|
33
|
+
table_name: :test_table,
|
|
34
|
+
columns: [:id],
|
|
35
|
+
schema: { id: {db_type: 'varchar(255)', primary_key: false }}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
described_class.create_table(target, OpenStruct.new(plan))
|
|
39
|
+
|
|
40
|
+
target.schema(:test_table)[0][1][:primary_key].should == true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'allows primary key override' do
|
|
44
|
+
plan = {
|
|
45
|
+
prefixed_table_name: :test_table,
|
|
46
|
+
table_name: :test_table,
|
|
47
|
+
columns: [:id, :col1],
|
|
48
|
+
primary_key: [:id, :col1],
|
|
49
|
+
schema: {
|
|
50
|
+
id: {db_type: 'varchar(255)', primary_key: false },
|
|
51
|
+
col1: {db_type: 'varchar(255)', primary_key: false }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
described_class.create_table(target, OpenStruct.new(plan))
|
|
56
|
+
|
|
57
|
+
target.schema(:test_table)[0][1][:primary_key].should == true
|
|
58
|
+
target.schema(:test_table)[1][1][:primary_key].should == true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
it 'creates a table with an enum column' do
|
|
63
|
+
plan = {
|
|
64
|
+
prefixed_table_name: :test_table,
|
|
65
|
+
table_name: :test_table,
|
|
66
|
+
columns: [:col1],
|
|
67
|
+
db_types: {:col1 => [:enum, %w(a b)]},
|
|
68
|
+
schema: { col1: { primary_key: true }}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
described_class.create_table(target, OpenStruct.new(plan))
|
|
72
|
+
|
|
73
|
+
target.schema(:test_table)[0][1][:db_type].should == "enum('a','b')"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'creates a table with non-id primary key' do
|
|
77
|
+
plan = {
|
|
78
|
+
prefixed_table_name: :test_table,
|
|
79
|
+
table_name: :test_table,
|
|
80
|
+
columns: [:col1],
|
|
81
|
+
schema: { col1: { db_type: 'varchar(255)', primary_key: true }}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
described_class.create_table(target, OpenStruct.new(plan))
|
|
85
|
+
|
|
86
|
+
target.schema(:test_table)[0][1][:primary_key].should == true
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'creates a table with a not-null column' do
|
|
90
|
+
plan = {
|
|
91
|
+
prefixed_table_name: :test_table,
|
|
92
|
+
table_name: :test_table,
|
|
93
|
+
columns: [:col1],
|
|
94
|
+
db_types: {:col1 => ['int(1) not null']},
|
|
95
|
+
schema: { col1: { primary_key: true }}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
described_class.create_table(target, OpenStruct.new(plan))
|
|
99
|
+
|
|
100
|
+
target.schema(:test_table)[0][1][:allow_null].should == false
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'creates a table with a composite primary key' do
|
|
104
|
+
plan = {
|
|
105
|
+
prefixed_table_name: :test_table,
|
|
106
|
+
table_name: :test_table,
|
|
107
|
+
columns: [:a, :b],
|
|
108
|
+
schema: {
|
|
109
|
+
a: { db_type: 'int', primary_key: true },
|
|
110
|
+
b: { db_type: 'int', primary_key: true }
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
described_class.create_table(target, OpenStruct.new(plan))
|
|
115
|
+
|
|
116
|
+
target.schema(:test_table)[0][1][:primary_key].should == true
|
|
117
|
+
target.schema(:test_table)[1][1][:primary_key].should == true
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'database_helper'
|
|
3
|
+
|
|
4
|
+
def create_source_table_with(*rows)
|
|
5
|
+
# Total hack to allow source db to be passed as optional first argument.
|
|
6
|
+
if rows[0].is_a?(Hash)
|
|
7
|
+
source_db = source
|
|
8
|
+
else
|
|
9
|
+
source_db = rows.shift
|
|
10
|
+
end
|
|
11
|
+
table_name = :test_table
|
|
12
|
+
|
|
13
|
+
source_db.create_table! table_name do
|
|
14
|
+
primary_key :id
|
|
15
|
+
String :col1
|
|
16
|
+
String :pii
|
|
17
|
+
DateTime :updated_at
|
|
18
|
+
DateTime :created_at
|
|
19
|
+
DateTime :imported_at
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
rows.each do |row|
|
|
23
|
+
source_db[table_name].insert(row)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def setup_target_table(last_synced_at)
|
|
28
|
+
target.create_table! :test_table do
|
|
29
|
+
Integer :id
|
|
30
|
+
String :col1
|
|
31
|
+
DateTime :updated_at
|
|
32
|
+
DateTime :created_at
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
target.add_index :test_table, :id, :unique => true
|
|
36
|
+
|
|
37
|
+
registry.ensure_storage_exists
|
|
38
|
+
registry.set(:test_table,
|
|
39
|
+
last_synced_at: last_synced_at,
|
|
40
|
+
last_row_at: last_synced_at,
|
|
41
|
+
last_batch_synced_at: last_synced_at
|
|
42
|
+
)
|
|
43
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
ENV['APP_ENV'] = 'test'
|
|
2
|
+
|
|
3
|
+
if ENV['COVERAGE'] != "0" && RUBY_PLATFORM != 'java'
|
|
4
|
+
require 'simplecov'
|
|
5
|
+
|
|
6
|
+
class SimpleCov::Formatter::MergedFormatter
|
|
7
|
+
def format(result)
|
|
8
|
+
SimpleCov::Formatter::HTMLFormatter.new.format(result)
|
|
9
|
+
File.open("coverage/covered_percent", "w") do |f|
|
|
10
|
+
f.puts result.source_files.covered_percent.to_i
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
SimpleCov.formatter = SimpleCov::Formatter::MergedFormatter
|
|
16
|
+
SimpleCov.start do
|
|
17
|
+
add_filter "/config/"
|
|
18
|
+
add_filter "/spec/"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module Sq
|
|
23
|
+
module Dbsync
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
SQD = Sq::Dbsync
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'unit_helper'
|
|
2
|
+
|
|
3
|
+
require 'sq/dbsync/config'
|
|
4
|
+
|
|
5
|
+
describe Sq::Dbsync::Config do
|
|
6
|
+
it 'provides a default error handler' do
|
|
7
|
+
described_class.make({})[:error_handler].should respond_to(:call)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'provides a default clock' do
|
|
11
|
+
described_class.make({})[:clock].().should be_instance_of(Time)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'provides a default logger' do
|
|
15
|
+
described_class.make({})[:logger].should \
|
|
16
|
+
be_a_kind_of(Sq::Dbsync::Loggers::Abstract)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'unit_helper'
|
|
2
|
+
|
|
3
|
+
require 'sq/dbsync/error_handler'
|
|
4
|
+
|
|
5
|
+
describe Sq::Dbsync::ErrorHandler do
|
|
6
|
+
let(:config) { {
|
|
7
|
+
sources: {
|
|
8
|
+
db_a: { password: 'redactme' },
|
|
9
|
+
db_b: { password: 'alsome' },
|
|
10
|
+
db_c: {}
|
|
11
|
+
},
|
|
12
|
+
target: { password: 'thistoo'},
|
|
13
|
+
}}
|
|
14
|
+
|
|
15
|
+
describe '#wrap' do
|
|
16
|
+
it 'redacts message' do
|
|
17
|
+
called = nil
|
|
18
|
+
config[:error_handler] = ->(ex) { called = ex }
|
|
19
|
+
handler = described_class.new(config)
|
|
20
|
+
->{
|
|
21
|
+
handler.wrap do
|
|
22
|
+
raise "redactme alsome thistoo notthis"
|
|
23
|
+
end
|
|
24
|
+
}.should raise_error("REDACTED REDACTED REDACTED notthis")
|
|
25
|
+
called.message.should == "REDACTED REDACTED REDACTED notthis"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe '#notify_error' do
|
|
30
|
+
it 'includes tag in exception message' do
|
|
31
|
+
called = nil
|
|
32
|
+
config[:error_handler] = ->(ex) { called = ex }
|
|
33
|
+
handler = described_class.new(config)
|
|
34
|
+
|
|
35
|
+
handler.notify_error(:test_table, RuntimeError.new('hello'))
|
|
36
|
+
|
|
37
|
+
called.message.should include('[test_table]')
|
|
38
|
+
called.message.should include('hello')
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'redacts message' do
|
|
42
|
+
called = nil
|
|
43
|
+
config[:error_handler] = ->(ex) { called = ex }
|
|
44
|
+
handler = described_class.new(config)
|
|
45
|
+
|
|
46
|
+
handler.notify_error(:test_table,
|
|
47
|
+
RuntimeError.new("redactme alsome thistoo notthis"))
|
|
48
|
+
|
|
49
|
+
called.message.should include("REDACTED REDACTED REDACTED notthis")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'unit_helper'
|
|
2
|
+
|
|
3
|
+
require 'sq/dbsync/pipeline'
|
|
4
|
+
|
|
5
|
+
shared_examples_for 'a pipeline' do
|
|
6
|
+
it 'passes tasks through each stage' do
|
|
7
|
+
ret = SQD::Pipeline.new([3, 4],
|
|
8
|
+
->(x) { x * x },
|
|
9
|
+
->(x) { x + x }
|
|
10
|
+
).run(described_class)
|
|
11
|
+
ret.should == [18, 32]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'returns errors' do
|
|
15
|
+
ret = SQD::Pipeline.new([1],
|
|
16
|
+
->(x) { raise("fail") }
|
|
17
|
+
).run(described_class)
|
|
18
|
+
ret.length.should == 1
|
|
19
|
+
ret = ret[0]
|
|
20
|
+
ret.should be_instance_of(SQD::Pipeline::Failure)
|
|
21
|
+
ret.wrapped_exception.should be_instance_of(RuntimeError)
|
|
22
|
+
ret.wrapped_exception.message.should == "fail"
|
|
23
|
+
ret.task.should == 1
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'handles errors in the middle of a pipeline' do
|
|
27
|
+
ret = SQD::Pipeline.new([1, 2],
|
|
28
|
+
->(x) { x == 1 ? 10 : raise("fail") },
|
|
29
|
+
->(x) { x + 1 }
|
|
30
|
+
).run(described_class)
|
|
31
|
+
ret[0].should == 11
|
|
32
|
+
ret[1].should be_instance_of(SQD::Pipeline::Failure)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe SQD::Pipeline::ThreadedContext do
|
|
37
|
+
it_should_behave_like 'a pipeline'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe SQD::Pipeline::SimpleContext do
|
|
41
|
+
it_should_behave_like 'a pipeline'
|
|
42
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'unit_helper'
|
|
2
|
+
|
|
3
|
+
require 'sq/dbsync/loggers'
|
|
4
|
+
|
|
5
|
+
describe SQD::Loggers::Stream do
|
|
6
|
+
let(:buffer) { "" }
|
|
7
|
+
let(:logger) { described_class.new(StringIO.new(buffer)) }
|
|
8
|
+
|
|
9
|
+
it 'logs :finished when no exception is raised' do
|
|
10
|
+
logger.measure(:ok) {}
|
|
11
|
+
buffer.should include('finished')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'logs :failed when exception is raised' do
|
|
15
|
+
lambda {
|
|
16
|
+
logger.measure(:fail) { raise("fail") }
|
|
17
|
+
}.should raise_error("fail")
|
|
18
|
+
buffer.should include('failed')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'logs error message when exception is raised' do
|
|
22
|
+
lambda {
|
|
23
|
+
logger.measure(:fail) { raise("oh no") }
|
|
24
|
+
}.should raise_error("oh no")
|
|
25
|
+
buffer.should include('oh no')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
it 'logs specified strings' do
|
|
30
|
+
logger.log('logging is good')
|
|
31
|
+
buffer.should include('logging is good')
|
|
32
|
+
end
|
|
33
|
+
end
|
data/spec/unit_helper.rb
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'spec_helper'
|
data/sq-dbsync.gemspec
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require File.expand_path('../lib/sq/dbsync/version', __FILE__)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |gem|
|
|
5
|
+
gem.authors = ["Xavier Shay"]
|
|
6
|
+
gem.email = ["xavier@squareup.com"]
|
|
7
|
+
gem.description =
|
|
8
|
+
%q{Column based, timestamp replication of MySQL and Postgres databases.}
|
|
9
|
+
gem.summary = %q{
|
|
10
|
+
Column based, timestamp replication of MySQL and Postgres databases. Uses
|
|
11
|
+
Ruby for the glue code but pushes the heavy lifting on to the database.
|
|
12
|
+
}
|
|
13
|
+
gem.homepage = "http://github.com/square/sq-dbsync"
|
|
14
|
+
|
|
15
|
+
gem.executables = []
|
|
16
|
+
gem.files = Dir.glob("{spec,lib}/**/*.rb") + %w(
|
|
17
|
+
README.md
|
|
18
|
+
HISTORY.md
|
|
19
|
+
LICENSE
|
|
20
|
+
sq-dbsync.gemspec
|
|
21
|
+
)
|
|
22
|
+
gem.test_files = Dir.glob("spec/**/*.rb")
|
|
23
|
+
gem.name = "sq-dbsync"
|
|
24
|
+
gem.require_paths = ["lib"]
|
|
25
|
+
gem.version = Sq::Dbsync::VERSION
|
|
26
|
+
gem.has_rdoc = false
|
|
27
|
+
gem.add_development_dependency 'rspec', '~> 2.0'
|
|
28
|
+
gem.add_development_dependency 'rake'
|
|
29
|
+
gem.add_development_dependency 'simplecov'
|
|
30
|
+
gem.add_development_dependency 'cane'
|
|
31
|
+
gem.add_dependency 'sequel'
|
|
32
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: sq-dbsync
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Xavier Shay
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-02-23 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: rspec
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ~>
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '2.0'
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ~>
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '2.0'
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: rake
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ! '>='
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '0'
|
|
38
|
+
type: :development
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ! '>='
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '0'
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: simplecov
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
none: false
|
|
50
|
+
requirements:
|
|
51
|
+
- - ! '>='
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ! '>='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
- !ruby/object:Gem::Dependency
|
|
63
|
+
name: cane
|
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
|
65
|
+
none: false
|
|
66
|
+
requirements:
|
|
67
|
+
- - ! '>='
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '0'
|
|
70
|
+
type: :development
|
|
71
|
+
prerelease: false
|
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
73
|
+
none: false
|
|
74
|
+
requirements:
|
|
75
|
+
- - ! '>='
|
|
76
|
+
- !ruby/object:Gem::Version
|
|
77
|
+
version: '0'
|
|
78
|
+
- !ruby/object:Gem::Dependency
|
|
79
|
+
name: sequel
|
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
|
81
|
+
none: false
|
|
82
|
+
requirements:
|
|
83
|
+
- - ! '>='
|
|
84
|
+
- !ruby/object:Gem::Version
|
|
85
|
+
version: '0'
|
|
86
|
+
type: :runtime
|
|
87
|
+
prerelease: false
|
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
89
|
+
none: false
|
|
90
|
+
requirements:
|
|
91
|
+
- - ! '>='
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: '0'
|
|
94
|
+
description: Column based, timestamp replication of MySQL and Postgres databases.
|
|
95
|
+
email:
|
|
96
|
+
- xavier@squareup.com
|
|
97
|
+
executables: []
|
|
98
|
+
extensions: []
|
|
99
|
+
extra_rdoc_files: []
|
|
100
|
+
files:
|
|
101
|
+
- spec/acceptance/loading_spec.rb
|
|
102
|
+
- spec/acceptance_helper.rb
|
|
103
|
+
- spec/database_helper.rb
|
|
104
|
+
- spec/integration/all_tables_plan_spec.rb
|
|
105
|
+
- spec/integration/batch_load_action_spec.rb
|
|
106
|
+
- spec/integration/consistency_verifier_spec.rb
|
|
107
|
+
- spec/integration/database_connection_spec.rb
|
|
108
|
+
- spec/integration/incremental_load_action_spec.rb
|
|
109
|
+
- spec/integration/manager_spec.rb
|
|
110
|
+
- spec/integration/schema_maker_spec.rb
|
|
111
|
+
- spec/integration_helper.rb
|
|
112
|
+
- spec/spec_helper.rb
|
|
113
|
+
- spec/unit/config_spec.rb
|
|
114
|
+
- spec/unit/error_handler_spec.rb
|
|
115
|
+
- spec/unit/pipeline_spec.rb
|
|
116
|
+
- spec/unit/stream_logger_spec.rb
|
|
117
|
+
- spec/unit_helper.rb
|
|
118
|
+
- lib/sq/dbsync/all_tables_plan.rb
|
|
119
|
+
- lib/sq/dbsync/batch_load_action.rb
|
|
120
|
+
- lib/sq/dbsync/config.rb
|
|
121
|
+
- lib/sq/dbsync/consistency_verifier.rb
|
|
122
|
+
- lib/sq/dbsync/database/common.rb
|
|
123
|
+
- lib/sq/dbsync/database/connection.rb
|
|
124
|
+
- lib/sq/dbsync/database/mysql.rb
|
|
125
|
+
- lib/sq/dbsync/database/postgres.rb
|
|
126
|
+
- lib/sq/dbsync/error_handler.rb
|
|
127
|
+
- lib/sq/dbsync/example_record_destroyer.rb
|
|
128
|
+
- lib/sq/dbsync/incremental_load_action.rb
|
|
129
|
+
- lib/sq/dbsync/load_action.rb
|
|
130
|
+
- lib/sq/dbsync/loggers.rb
|
|
131
|
+
- lib/sq/dbsync/manager.rb
|
|
132
|
+
- lib/sq/dbsync/pipeline/simple_context.rb
|
|
133
|
+
- lib/sq/dbsync/pipeline/threaded_context.rb
|
|
134
|
+
- lib/sq/dbsync/pipeline.rb
|
|
135
|
+
- lib/sq/dbsync/refresh_recent_load_action.rb
|
|
136
|
+
- lib/sq/dbsync/schema_maker.rb
|
|
137
|
+
- lib/sq/dbsync/static_table_plan.rb
|
|
138
|
+
- lib/sq/dbsync/table_registry.rb
|
|
139
|
+
- lib/sq/dbsync/tempfile_factory.rb
|
|
140
|
+
- lib/sq/dbsync/version.rb
|
|
141
|
+
- lib/sq/dbsync.rb
|
|
142
|
+
- README.md
|
|
143
|
+
- HISTORY.md
|
|
144
|
+
- LICENSE
|
|
145
|
+
- sq-dbsync.gemspec
|
|
146
|
+
homepage: http://github.com/square/sq-dbsync
|
|
147
|
+
licenses: []
|
|
148
|
+
post_install_message:
|
|
149
|
+
rdoc_options: []
|
|
150
|
+
require_paths:
|
|
151
|
+
- lib
|
|
152
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
153
|
+
none: false
|
|
154
|
+
requirements:
|
|
155
|
+
- - ! '>='
|
|
156
|
+
- !ruby/object:Gem::Version
|
|
157
|
+
version: '0'
|
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
159
|
+
none: false
|
|
160
|
+
requirements:
|
|
161
|
+
- - ! '>='
|
|
162
|
+
- !ruby/object:Gem::Version
|
|
163
|
+
version: '0'
|
|
164
|
+
requirements: []
|
|
165
|
+
rubyforge_project:
|
|
166
|
+
rubygems_version: 1.8.23
|
|
167
|
+
signing_key:
|
|
168
|
+
specification_version: 3
|
|
169
|
+
summary: Column based, timestamp replication of MySQL and Postgres databases. Uses
|
|
170
|
+
Ruby for the glue code but pushes the heavy lifting on to the database.
|
|
171
|
+
test_files:
|
|
172
|
+
- spec/acceptance/loading_spec.rb
|
|
173
|
+
- spec/acceptance_helper.rb
|
|
174
|
+
- spec/database_helper.rb
|
|
175
|
+
- spec/integration/all_tables_plan_spec.rb
|
|
176
|
+
- spec/integration/batch_load_action_spec.rb
|
|
177
|
+
- spec/integration/consistency_verifier_spec.rb
|
|
178
|
+
- spec/integration/database_connection_spec.rb
|
|
179
|
+
- spec/integration/incremental_load_action_spec.rb
|
|
180
|
+
- spec/integration/manager_spec.rb
|
|
181
|
+
- spec/integration/schema_maker_spec.rb
|
|
182
|
+
- spec/integration_helper.rb
|
|
183
|
+
- spec/spec_helper.rb
|
|
184
|
+
- spec/unit/config_spec.rb
|
|
185
|
+
- spec/unit/error_handler_spec.rb
|
|
186
|
+
- spec/unit/pipeline_spec.rb
|
|
187
|
+
- spec/unit/stream_logger_spec.rb
|
|
188
|
+
- spec/unit_helper.rb
|