pgsync 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of pgsync might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +40 -8
- data/{bin → exe}/pgsync +0 -0
- data/lib/pgsync.rb +41 -32
- data/lib/pgsync/version.rb +1 -1
- data/pgsync.gemspec +2 -2
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12edffcbf1375d06f4a56916e2581053711b3a81
|
4
|
+
data.tar.gz: c1b08b53a4f0dd07d32d87d921400f3718aaa07e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6484259d1dd62dde1b95b8472ae487298dae7848a0e14a95f68efc75bc954a370eb8b2ed74121c26dcc98c46c365a00a823386c88abe27e3ca02e81bbfa363a
|
7
|
+
data.tar.gz: e510ca2717985f8d2f1fd0fc2e16219f81a63f6a55171911508e4def6bc22769267c99d393df02dea15713fe80e030dab67690808517179f5a717953fda99308
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# pgsync
|
2
2
|
|
3
|
-
|
3
|
+
Sync Postgres data to your local machine. Designed for:
|
4
|
+
|
5
|
+
- **speed** - up to 4x faster than traditional tools on a 4-core machine
|
6
|
+
- **security** - built-in methods to prevent sensitive data from ever leaving the server
|
7
|
+
- **convenience** - sync partial tables, groups of tables, and related records
|
4
8
|
|
5
9
|
:tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
|
6
10
|
|
@@ -26,16 +30,30 @@ Sync all tables
|
|
26
30
|
pgsync
|
27
31
|
```
|
28
32
|
|
33
|
+
**Note:** pgsync assumes your schema is already set up on your local machine. See the [schema section](#schema) if that’s not the case.
|
34
|
+
|
29
35
|
Sync specific tables
|
30
36
|
|
31
37
|
```sh
|
32
38
|
pgsync table1,table2
|
33
39
|
```
|
34
40
|
|
35
|
-
Sync specific rows
|
41
|
+
Sync specific rows (existing rows are overwritten)
|
42
|
+
|
43
|
+
```sh
|
44
|
+
pgsync products "where store_id = 1"
|
45
|
+
```
|
46
|
+
|
47
|
+
You can also preserve existing rows
|
36
48
|
|
37
49
|
```sh
|
38
|
-
pgsync products "
|
50
|
+
pgsync products "where store_id = 1" --preserve
|
51
|
+
```
|
52
|
+
|
53
|
+
Or truncate them
|
54
|
+
|
55
|
+
```sh
|
56
|
+
pgsync products "where store_id = 1" --truncate
|
39
57
|
```
|
40
58
|
|
41
59
|
### Exclude Tables
|
@@ -78,19 +96,21 @@ pgsync group1
|
|
78
96
|
|
79
97
|
You can also use groups to sync a specific record and associated records in other tables.
|
80
98
|
|
81
|
-
To get
|
99
|
+
To get product `123` with its reviews, last 10 coupons, and store, use:
|
82
100
|
|
83
101
|
```yml
|
84
102
|
groups:
|
85
|
-
|
86
|
-
|
87
|
-
|
103
|
+
product:
|
104
|
+
products: "where id = {1}"
|
105
|
+
reviews: "where product_id = {1}"
|
106
|
+
coupons: "where product_id = {1} order by created_at desc limit 10"
|
107
|
+
stores: "where id in (select store_id from products where id = {1})
|
88
108
|
```
|
89
109
|
|
90
110
|
And run:
|
91
111
|
|
92
112
|
```sh
|
93
|
-
pgsync
|
113
|
+
pgsync product:123
|
94
114
|
```
|
95
115
|
|
96
116
|
### Schema
|
@@ -161,6 +181,18 @@ To keep you from accidentally overwriting production, the destination is limited
|
|
161
181
|
|
162
182
|
To use another host, add `to_safe: true` to your `.pgsync.yml`.
|
163
183
|
|
184
|
+
## Setup Scripts
|
185
|
+
|
186
|
+
Use groups when possible to take advantage of parallelism.
|
187
|
+
|
188
|
+
For Ruby scripts, you may need to do:
|
189
|
+
|
190
|
+
```rb
|
191
|
+
Bundler.with_clean_env do
|
192
|
+
system "pgsync ..."
|
193
|
+
end
|
194
|
+
```
|
195
|
+
|
164
196
|
## Upgrading
|
165
197
|
|
166
198
|
Run:
|
data/{bin → exe}/pgsync
RENAMED
File without changes
|
data/lib/pgsync.rb
CHANGED
@@ -18,7 +18,6 @@ end
|
|
18
18
|
|
19
19
|
module PgSync
|
20
20
|
class Error < StandardError; end
|
21
|
-
class Rollback < StandardError; end
|
22
21
|
|
23
22
|
class Client
|
24
23
|
def initialize(args)
|
@@ -45,6 +44,10 @@ module PgSync
|
|
45
44
|
args.shift
|
46
45
|
opts[:setup] = true
|
47
46
|
deprecated "Use `psync --setup` instead"
|
47
|
+
when "schema"
|
48
|
+
args.shift
|
49
|
+
opts[:schema_only] = true
|
50
|
+
deprecated "Use `psync --schema-only` instead"
|
48
51
|
when "tables"
|
49
52
|
args.shift
|
50
53
|
opts[:tables] = args.shift
|
@@ -55,6 +58,18 @@ module PgSync
|
|
55
58
|
deprecated "Use `pgsync #{opts[:groups]}` instead"
|
56
59
|
end
|
57
60
|
|
61
|
+
if opts[:where]
|
62
|
+
opts[:sql] ||= String.new
|
63
|
+
opts[:sql] << " WHERE #{opts[:where]}"
|
64
|
+
deprecated "Use `\"WHERE #{opts[:where]}\"` instead"
|
65
|
+
end
|
66
|
+
|
67
|
+
if opts[:limit]
|
68
|
+
opts[:sql] ||= String.new
|
69
|
+
opts[:sql] << " LIMIT #{opts[:limit]}"
|
70
|
+
deprecated "Use `\"LIMIT #{opts[:limit]}\"` instead"
|
71
|
+
end
|
72
|
+
|
58
73
|
if opts[:setup]
|
59
74
|
setup(db_config_file(args[0]) || config_file || ".pgsync.yml")
|
60
75
|
else
|
@@ -75,17 +90,14 @@ module PgSync
|
|
75
90
|
|
76
91
|
tables = table_list(args, opts, from_uri)
|
77
92
|
|
78
|
-
if
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
restore_command = "psql -q -d #{to_url(destination_uri)}"
|
85
|
-
system("#{dump_command} | #{restore_command}")
|
86
|
-
end
|
93
|
+
if opts[:schema_only]
|
94
|
+
log "* Dumping schema"
|
95
|
+
tables = tables.keys.map { |t| "-t #{t}" }.join(" ")
|
96
|
+
dump_command = "pg_dump --verbose --schema-only --no-owner --no-acl --clean #{tables} #{to_url(source_uri)}"
|
97
|
+
restore_command = "psql -q -d #{to_url(destination_uri)}"
|
98
|
+
system("#{dump_command} | #{restore_command}")
|
87
99
|
|
88
|
-
|
100
|
+
log_completed(start_time)
|
89
101
|
else
|
90
102
|
with_connection(to_uri, timeout: 3) do |conn|
|
91
103
|
tables.keys.each do |table|
|
@@ -106,8 +118,7 @@ module PgSync
|
|
106
118
|
sync_table(table, opts.merge(table_opts), from_uri, to_uri)
|
107
119
|
end
|
108
120
|
|
109
|
-
|
110
|
-
log "Completed in #{time.round(1)}s"
|
121
|
+
log_completed(start_time)
|
111
122
|
end
|
112
123
|
end
|
113
124
|
end
|
@@ -135,8 +146,6 @@ module PgSync
|
|
135
146
|
extra_sequences = to_sequences - from_sequences
|
136
147
|
missing_sequences = from_sequences - to_sequences
|
137
148
|
|
138
|
-
where = opts[:where]
|
139
|
-
limit = opts[:limit]
|
140
149
|
sql_clause = String.new
|
141
150
|
|
142
151
|
@mutex.synchronize do
|
@@ -145,14 +154,6 @@ module PgSync
|
|
145
154
|
log " #{opts[:sql]}"
|
146
155
|
sql_clause << " #{opts[:sql]}"
|
147
156
|
end
|
148
|
-
if where
|
149
|
-
log " #{where}"
|
150
|
-
sql_clause << " WHERE #{opts[:where]}"
|
151
|
-
end
|
152
|
-
if limit
|
153
|
-
log " LIMIT #{limit}"
|
154
|
-
sql_clause << " LIMIT #{limit}"
|
155
|
-
end
|
156
157
|
log " Extra columns: #{extra_fields.join(", ")}" if extra_fields.any?
|
157
158
|
log " Missing columns: #{missing_fields.join(", ")}" if missing_fields.any?
|
158
159
|
log " Extra sequences: #{extra_sequences.join(", ")}" if extra_sequences.any?
|
@@ -173,7 +174,7 @@ module PgSync
|
|
173
174
|
end
|
174
175
|
|
175
176
|
copy_to_command = "COPY (SELECT #{copy_fields} FROM #{table}#{sql_clause}) TO STDOUT"
|
176
|
-
if !opts[:truncate] && (opts[:preserve] || !sql_clause.empty?)
|
177
|
+
if !opts[:truncate] && (opts[:overwrite] || opts[:preserve] || !sql_clause.empty?)
|
177
178
|
primary_key = self.primary_key(from_connection, table, "public")
|
178
179
|
abort "No primary key" unless primary_key
|
179
180
|
|
@@ -246,8 +247,8 @@ Options:}
|
|
246
247
|
o.string "-g", "--groups", "groups"
|
247
248
|
o.string "--from", "source"
|
248
249
|
o.string "--to", "destination"
|
249
|
-
o.string "--where", "where"
|
250
|
-
o.integer "--limit", "limit"
|
250
|
+
o.string "--where", "where", help: false
|
251
|
+
o.integer "--limit", "limit", help: false
|
251
252
|
o.string "--exclude", "exclude tables"
|
252
253
|
o.string "--config", "config file"
|
253
254
|
o.string "--db", "database"
|
@@ -255,6 +256,7 @@ Options:}
|
|
255
256
|
o.boolean "--to-safe", "accept danger", default: false
|
256
257
|
o.boolean "--debug", "debug", default: false
|
257
258
|
o.boolean "--list", "list", default: false
|
259
|
+
o.boolean "--overwrite", "overwrite existing rows", default: false, help: false
|
258
260
|
o.boolean "--preserve", "preserve existing rows", default: false
|
259
261
|
o.boolean "--truncate", "truncate existing rows", default: false
|
260
262
|
o.boolean "--schema-only", "schema only", default: false
|
@@ -520,11 +522,15 @@ Options:}
|
|
520
522
|
if table.is_a?(Array)
|
521
523
|
table, sql = table
|
522
524
|
end
|
523
|
-
tables
|
524
|
-
tables[table][:sql] = (boom || sql).to_s.gsub("{id}", cast(id)) if boom || sql
|
525
|
+
add_table(tables, table, id, boom || sql)
|
525
526
|
end
|
526
527
|
end
|
527
528
|
|
529
|
+
def add_table(tables, table, id, boom)
|
530
|
+
tables[table] = {}
|
531
|
+
tables[table][:sql] = boom.gsub("{id}", cast(id)).gsub("{1}", cast(id)) if boom
|
532
|
+
end
|
533
|
+
|
528
534
|
def table_list(args, opts, from_uri)
|
529
535
|
tables = nil
|
530
536
|
|
@@ -545,8 +551,7 @@ Options:}
|
|
545
551
|
tables ||= Hash.new { |hash, key| hash[key] = {} }
|
546
552
|
to_arr(opts[:tables]).each do |tag|
|
547
553
|
table, id = tag.split(":", 2)
|
548
|
-
tables
|
549
|
-
tables[table][:sql] = args[1].to_s.gsub("{id}", cast(id)) if args[1]
|
554
|
+
add_table(tables, table, id, args[1])
|
550
555
|
end
|
551
556
|
end
|
552
557
|
|
@@ -559,8 +564,7 @@ Options:}
|
|
559
564
|
if (t = (config["groups"] || {})[group])
|
560
565
|
add_tables(tables, t, id, args[1])
|
561
566
|
else
|
562
|
-
tables
|
563
|
-
tables[group][:sql] = args[1].to_s.gsub("{id}", cast(id)) if args[1]
|
567
|
+
add_table(tables, group, id, args[1])
|
564
568
|
end
|
565
569
|
end
|
566
570
|
end
|
@@ -585,5 +589,10 @@ Options:}
|
|
585
589
|
def deprecated(message)
|
586
590
|
log "[DEPRECATED] #{message}"
|
587
591
|
end
|
592
|
+
|
593
|
+
def log_completed(start_time)
|
594
|
+
time = Time.now - start_time
|
595
|
+
log "Completed in #{time.round(1)}s"
|
596
|
+
end
|
588
597
|
end
|
589
598
|
end
|
data/lib/pgsync/version.rb
CHANGED
data/pgsync.gemspec
CHANGED
@@ -14,8 +14,8 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
-
spec.bindir = "
|
18
|
-
spec.executables = spec.files.grep(%r{^
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_dependency "slop", ">= 4.2.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pgsync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-04-
|
11
|
+
date: 2016-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: slop
|
@@ -122,8 +122,8 @@ files:
|
|
122
122
|
- LICENSE.txt
|
123
123
|
- README.md
|
124
124
|
- Rakefile
|
125
|
-
- bin/pgsync
|
126
125
|
- config.yml
|
126
|
+
- exe/pgsync
|
127
127
|
- lib/pgsync.rb
|
128
128
|
- lib/pgsync/version.rb
|
129
129
|
- pgsync.gemspec
|