mongar 0.0.6 → 0.0.7

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/README.rdoc CHANGED
@@ -1,89 +1,157 @@
1
1
  = mongar
2
2
 
3
- !! This is still fresh off the oven and hasn't been thoroughly tested yet in production. !!
3
+ Replicate data from MySQL, PostgreSQL, SQLite, etc to MongoDB!
4
4
 
5
- Ruby GEM to facilitate replicating data from ActiveRecord (or any data represented by a set of Ruby classes) to MongoDB.
5
+ Mongar will replicate data from ActiveRecord (or any data represented by a Ruby class) to MongoDB.
6
+ For example, if you have MySQL data represented by ActiveRecord, you can easily replicate it to
7
+ MongoDB.
6
8
 
7
9
  == Adding to a rails project
8
10
 
11
+ For now, you'll have to manually add Mongar to your Rails project. We'll work on a Railtie for Rails 3 soon.
12
+
9
13
  Put your Mongar config into config/mongar.rb (See Example Config below)
10
14
 
11
- Put the following code into script/mongar.rb
15
+ Put the following code into your Rakefile
12
16
 
13
17
  require 'mongar'
14
- mongar_config = File.join(Rails.root, 'config', 'mongar.rb')
15
- mongar = eval(File.read(mongar_config))
16
- mongar.run
17
18
 
18
- Run it with rails runner (rails 3.x) or script/runner (rails 2.x) script/mongar.rb
19
+ namespace :mongar do
20
+ desc "Run mongar replication"
21
+ task :run => :environment do
22
+ mongar_config = File.join(Rails.root, 'config', 'mongar.rb')
23
+ mongar = eval(File.read(mongar_config))
24
+ mongar.run
25
+ end
26
+ end
27
+
28
+ Run it with
29
+
30
+ rake mongar:run
31
+
32
+ == Assumptions
33
+
34
+ The default configuration assumes that you are using ActiveRecord and that are you using a plugin
35
+ similar to acts_as_paranoid that never deletes records from the database but only marks them as
36
+ deleted with a deleted_at column.
37
+
38
+ You can customize the finder methods that Mongar uses to accommodate any data model or your own
39
+ custom scopes.
40
+
41
+ == Minimal example config
42
+
43
+ Given an ActiveRecord model call Domain with two attributes name and client_id:
44
+
45
+ Mongar.configure do
46
+ mongo :default do
47
+ database 'mydb'
48
+ end
49
+
50
+ replicate Domain do
51
+ column :name do
52
+ primary_index
53
+ end
54
+
55
+ column :client_id
56
+ end
57
+ end
19
58
 
20
- == Example Config
59
+ == Full example Config
21
60
 
22
61
  Mongar.configure do
62
+ # Currently we only log to STDOUT, we have plans to use a
63
+ # plans to use a configurable logger.
64
+ # Valid log levels are :info and :debug
23
65
  log_level :debug
24
66
 
25
67
  mongo :default do
26
68
  database 'mydb'
27
- user 'mongouser'
28
- password 'password'
29
- host '127.0.0.1'
30
- port 27017
31
69
  end
32
70
 
33
71
  mongo :otherdb do
34
- database 'mydb'
72
+ database 'myotherdb'
35
73
  user 'mongouser'
36
74
  password 'password'
37
-
38
- status_collection :statuses
75
+ host '127.0.0.1'
76
+ port 27017
77
+
78
+ # By default Mongar uses the 'statuses' collection to
79
+ # keep track of the last replicated times, you can specify
80
+ # a custom collection name
81
+ status_collection :stati
39
82
  end
40
-
41
- replicate Domain => 'domains' do
42
- use_mongodb :otherdb
43
83
 
44
- full_refresh :every => 60.minutes
45
-
46
- column :uri do
84
+ # Minimal replica config to replicate the Domain model
85
+ # to the 'domains' mongo collection on the mongo db defined
86
+ # in the :default config above
87
+
88
+ replicate Domain do
89
+ column :name do
47
90
  primary_index
48
- transform :downcase
49
91
  end
50
-
51
- column :allow_anyone_to_anyone_policy
92
+
93
+ column :client_id
52
94
  end
53
95
 
54
- replicate Client do
55
- db_time_selector do
56
- current_time_on_db_server
57
- end
96
+ # Customized replica config to replicate the Client
97
+ # model to the 'customers' mongo collection on the db
98
+ # defined in the :otherdb config above
58
99
 
59
- column :id do
60
- primary_index
61
- end
62
-
63
- column :name
64
-
65
- column :employee_count do
66
- transform do |value|
67
- value.nil? ? 0 : value
68
- end
100
+ replicate Client => 'customers' do
101
+ # Use the other mongo database
102
+ use_mongodb :otherdb
103
+
104
+ # By default, Mongar will try to determine the time on the
105
+ # backend database. The supported ActiveRecord database adapters
106
+ # are MysqlAdapter, Mysql2Adapter, and SQLServerAdapter.
107
+ # You can use a custom function to determine the time on Client's
108
+ # backend database
109
+ db_time_selector do
110
+ # this will run Client#get_db_time
111
+ get_db_time
69
112
  end
70
- end
71
-
72
- replicate EmailAddress do
113
+
114
+ # Items are never deleted
73
115
  no_deleted_finder
116
+
117
+ # Customize your updated record finder. The block is
118
+ # run in the source class context
74
119
  set_updated_finder do |last_replicated_date|
75
120
  find(:all, :conditions => ['something > ?', last_replicated_date])
76
121
  end
122
+
123
+ # Custom created item finder
77
124
  set_created_finder do |last_replicated_date|
78
125
  created_scope(last_replicated_date)
79
126
  end
80
127
 
128
+ # Run a full refresh of all items in the database based
129
+ # a condition returned by the Proc
81
130
  full_refresh :if => Proc.new do |last_replicated_date|
82
131
  # class eval'ed code
83
132
  any_changes_since?(last_replicated_date)
84
133
  end
85
-
86
- column :address
134
+
135
+ # You can also refresh every N seconds
136
+ # full_refresh :every => 3600
137
+
138
+ # Define your columns
139
+ column :id do
140
+ # The 'primary index' column is used to find items in the mongo collection
141
+ primary_index
142
+ end
143
+
144
+ column :tag do
145
+ # Run the procedure :downcase on the value of Client#tag
146
+ transform :downcase
147
+ end
148
+
149
+ column :employee_count do
150
+ # Run a block transformation on the value of Client#employee_count
151
+ transform do |value|
152
+ value.nil? ? 0 : value
153
+ end
154
+ end
87
155
  end
88
156
  end
89
157
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.6
1
+ 0.0.7
@@ -38,7 +38,7 @@ class Mongar::Mongo
38
38
  end
39
39
 
40
40
  def last_replicated_at=(date)
41
- info "Saving #{name} last_replicated_at to #{date}"
41
+ info " * Updating #{name}.last_replicated_at to #{date}"
42
42
  status_collection.update({ :collection_name => name },
43
43
  { :collection_name => name, :last_replicated_at => date },
44
44
  { :upsert => true })
@@ -71,13 +71,13 @@ class Mongar::Mongo
71
71
  end
72
72
 
73
73
  def mark_all_items_pending_deletion
74
- info "Marking all items in #{name} for pending deletion"
74
+ info " * Marking all items in #{name} for pending deletion"
75
75
 
76
76
  collection.update({ '_id' => { '$exists' => true } }, { "$set" => { :pending_deletion => true } }, { :multi => true, :safe => true })
77
77
  end
78
78
 
79
79
  def delete_all_items_pending_deletion
80
- info "Deleting all items in #{name} that are pending deletion"
80
+ info " * Deleting all items in #{name} that are pending deletion"
81
81
 
82
82
  collection.remove({ :pending_deletion => true }, { :safe => true })
83
83
  end
@@ -30,8 +30,13 @@ class Mongar
30
30
  def run
31
31
  time = current_time_on_database_server
32
32
 
33
+ # Set the time back 1 second to make sure we don't miss any changes made mid-second
34
+ time -= 1 unless time.nil?
35
+
36
+ info "Replicating #{source.to_s} to #{destination.name}"
37
+
33
38
  if do_full_refresh?
34
- info "Running full refresh on Replica #{source.to_s} to #{destination.name}"
39
+ info " * Full refresh"
35
40
 
36
41
  destination.mark_all_items_pending_deletion!
37
42
 
@@ -41,7 +46,7 @@ class Mongar
41
46
  else
42
47
  last_replicated_at = destination.last_replicated_at
43
48
 
44
- info "Running incremental replication on Replica #{source.to_s} to #{destination.name} from #{last_replicated_at}"
49
+ info " * Incremental updates since #{last_replicated_at}"
45
50
 
46
51
  run_sync_for([:deleted, :created_or_updated, :updated], last_replicated_at)
47
52
  end
@@ -49,6 +54,8 @@ class Mongar
49
54
  end
50
55
 
51
56
  def run_sync_for(types, last_replicated_at)
57
+ info " * Syncing #{types.join(', ')} items"
58
+
52
59
  # find deleted
53
60
  find(:deleted, last_replicated_at).each do |deleted_item|
54
61
  destination.delete! source_object_to_primary_key_hash(deleted_item)
data/mongar.gemspec CHANGED
@@ -4,14 +4,14 @@
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
- s.name = "mongar"
8
- s.version = "0.0.6"
7
+ s.name = %q{mongar}
8
+ s.version = "0.0.7"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Philippe Green"]
12
- s.date = "2011-12-15"
13
- s.description = "Replicates data from ActiveRecord (or other Ruby data mapping class) to MongoDB"
14
- s.email = "phil@greenviewdata.com"
12
+ s.date = %q{2011-12-16}
13
+ s.description = %q{Replicates data from ActiveRecord (or other Ruby data mapping class) to MongoDB}
14
+ s.email = %q{phil@greenviewdata.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE.txt",
17
17
  "README.rdoc"
@@ -43,11 +43,11 @@ Gem::Specification.new do |s|
43
43
  "spec/mongar_spec.rb",
44
44
  "spec/spec_helper.rb"
45
45
  ]
46
- s.homepage = "http://github.com/gdi/mongar"
46
+ s.homepage = %q{http://github.com/gdi/mongar}
47
47
  s.licenses = ["MIT"]
48
48
  s.require_paths = ["lib"]
49
- s.rubygems_version = "1.8.10"
50
- s.summary = "Replicates data from ActiveRecord (or other Ruby data mapping class) to MongoDB"
49
+ s.rubygems_version = %q{1.6.2}
50
+ s.summary = %q{Replicates data from ActiveRecord (or other Ruby data mapping class) to MongoDB}
51
51
 
52
52
  if s.respond_to? :specification_version then
53
53
  s.specification_version = 3
@@ -1,60 +1,96 @@
1
- Mongar.configure do
2
- mongo :default do
3
- database 'mydb'
4
- user 'mongouser'
5
- password 'password'
6
- host '127.0.0.1'
7
- port 27017
8
- end
9
-
10
- mongo :otherdb do
11
- database 'mydb'
12
- user 'mongouser'
13
- password 'password'
14
-
15
- status_collection :statuses
16
- end
17
-
18
- replicate Domain => 'domains' do
19
- use_mongodb :otherdb
20
-
21
- full_refresh :every => 60.minutes
22
-
23
- column :uri do
24
- primary_index
25
- transform :downcase
26
- end
27
-
28
- column :allow_anyone_to_anyone_policy
29
- end
30
-
31
- replicate Client do
32
- column :id do
33
- primary_index
34
- end
35
-
36
- column :name
37
- end
38
-
39
- replicate EmailAddress do
40
- no_deleted_finder
41
- set_updated_finder do |last_replicated_date|
42
- find(:all, :conditions => ['something > ?', last_replicated_date])
43
- end
44
- set_created_finder do |last_replicated_date|
45
- created_scope(last_replicated_date)
46
- end
47
-
48
- full_refresh :if => Proc.new do |last_replicated_date|
49
- # class eval'ed code
50
- any_changes_since?(last_replicated_date)
51
- end
52
-
53
- column :address do
54
- index
55
- transform do |value|
56
- # some code to perform on the value
57
- end
58
- end
59
- end
1
+ Mongar.configure do
2
+ # Currently we only log to STDOUT, we have plans to use a
3
+ # plans to use a configurable logger.
4
+ # Valid log levels are :info and :debug
5
+ log_level :debug
6
+
7
+ mongo :default do
8
+ database 'mydb'
9
+ end
10
+
11
+ mongo :otherdb do
12
+ database 'myotherdb'
13
+ user 'mongouser'
14
+ password 'password'
15
+ host '127.0.0.1'
16
+ port 27017
17
+
18
+ # By default Mongar uses the 'statuses' collection to
19
+ # keep track of the last replicated times, you can specify
20
+ # a custom collection name
21
+ status_collection :stati
22
+ end
23
+
24
+ # Minimal replica config to replicate the Domain model
25
+ # to the 'domains' mongo collection on the mongo db defined
26
+ # in the :default config above
27
+
28
+ replicate Domain do
29
+ column :name do
30
+ primary_index
31
+ end
32
+
33
+ column :client_id
34
+ end
35
+
36
+ # Customized replica config to replicate the Client
37
+ # model to the 'customers' mongo collection on the db
38
+ # defined in the :otherdb config above
39
+
40
+ replicate Client => 'customers' do
41
+ # Use the other mongo database
42
+ use_mongodb :otherdb
43
+
44
+ # By default, Mongar will try to determine the time on the
45
+ # backend database. The supported ActiveRecord database adapters
46
+ # are MysqlAdapter, Mysql2Adapter, and SQLServerAdapter.
47
+ # You can use a custom function to determine the time on Client's
48
+ # backend database
49
+ db_time_selector do
50
+ # this will run Client#get_db_time
51
+ get_db_time
52
+ end
53
+
54
+ # Items are never deleted
55
+ no_deleted_finder
56
+
57
+ # Customize your updated record finder. The block is
58
+ # run in the source class context
59
+ set_updated_finder do |last_replicated_date|
60
+ find(:all, :conditions => ['something > ?', last_replicated_date])
61
+ end
62
+
63
+ # Custom created item finder
64
+ set_created_finder do |last_replicated_date|
65
+ created_scope(last_replicated_date)
66
+ end
67
+
68
+ # Run a full refresh of all items in the database based
69
+ # a condition returned by the Proc
70
+ full_refresh :if => Proc.new do |last_replicated_date|
71
+ # class eval'ed code
72
+ any_changes_since?(last_replicated_date)
73
+ end
74
+
75
+ # You can also refresh every N seconds
76
+ # full_refresh :every => 3600
77
+
78
+ # Define your columns
79
+ column :id do
80
+ # The 'primary index' column is used to find items in the mongo collection
81
+ primary_index
82
+ end
83
+
84
+ column :tag do
85
+ # Run the procedure :downcase on the value of Client#tag
86
+ transform :downcase
87
+ end
88
+
89
+ column :employee_count do
90
+ # Run a block transformation on the value of Client#employee_count
91
+ transform do |value|
92
+ value.nil? ? 0 : value
93
+ end
94
+ end
95
+ end
60
96
  end
@@ -96,7 +96,7 @@ describe "Mongar::Replica" do
96
96
  end
97
97
 
98
98
  it "should set the last replicated at time to the time the run started" do
99
- @collection.should_receive(:last_replicated_at=).with(@time)
99
+ @collection.should_receive(:last_replicated_at=).with(@time - 1)
100
100
  @replica.run
101
101
  end
102
102
  end
metadata CHANGED
@@ -1,13 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongar
3
3
  version: !ruby/object:Gem::Version
4
- hash: 19
5
4
  prerelease:
6
- segments:
7
- - 0
8
- - 0
9
- - 6
10
- version: 0.0.6
5
+ version: 0.0.7
11
6
  platform: ruby
12
7
  authors:
13
8
  - Philippe Green
@@ -15,114 +10,86 @@ autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
12
 
18
- date: 2011-12-15 00:00:00 Z
13
+ date: 2011-12-16 00:00:00 -05:00
14
+ default_executable:
19
15
  dependencies:
20
16
  - !ruby/object:Gem::Dependency
17
+ name: linguistics
21
18
  requirement: &id001 !ruby/object:Gem::Requirement
22
19
  none: false
23
20
  requirements:
24
21
  - - ">="
25
22
  - !ruby/object:Gem::Version
26
- hash: 3
27
- segments:
28
- - 0
29
23
  version: "0"
30
- version_requirements: *id001
31
- name: linguistics
32
- prerelease: false
33
24
  type: :runtime
25
+ prerelease: false
26
+ version_requirements: *id001
34
27
  - !ruby/object:Gem::Dependency
28
+ name: mongo
35
29
  requirement: &id002 !ruby/object:Gem::Requirement
36
30
  none: false
37
31
  requirements:
38
32
  - - ">="
39
33
  - !ruby/object:Gem::Version
40
- hash: 3
41
- segments:
42
- - 0
43
34
  version: "0"
44
- version_requirements: *id002
45
- name: mongo
46
- prerelease: false
47
35
  type: :runtime
36
+ prerelease: false
37
+ version_requirements: *id002
48
38
  - !ruby/object:Gem::Dependency
39
+ name: rspec
49
40
  requirement: &id003 !ruby/object:Gem::Requirement
50
41
  none: false
51
42
  requirements:
52
43
  - - ~>
53
44
  - !ruby/object:Gem::Version
54
- hash: 3
55
- segments:
56
- - 2
57
- - 3
58
- - 0
59
45
  version: 2.3.0
60
- version_requirements: *id003
61
- name: rspec
62
- prerelease: false
63
46
  type: :development
47
+ prerelease: false
48
+ version_requirements: *id003
64
49
  - !ruby/object:Gem::Dependency
50
+ name: yard
65
51
  requirement: &id004 !ruby/object:Gem::Requirement
66
52
  none: false
67
53
  requirements:
68
54
  - - ~>
69
55
  - !ruby/object:Gem::Version
70
- hash: 7
71
- segments:
72
- - 0
73
- - 6
74
- - 0
75
56
  version: 0.6.0
76
- version_requirements: *id004
77
- name: yard
78
- prerelease: false
79
57
  type: :development
58
+ prerelease: false
59
+ version_requirements: *id004
80
60
  - !ruby/object:Gem::Dependency
61
+ name: bundler
81
62
  requirement: &id005 !ruby/object:Gem::Requirement
82
63
  none: false
83
64
  requirements:
84
65
  - - ~>
85
66
  - !ruby/object:Gem::Version
86
- hash: 23
87
- segments:
88
- - 1
89
- - 0
90
- - 0
91
67
  version: 1.0.0
92
- version_requirements: *id005
93
- name: bundler
94
- prerelease: false
95
68
  type: :development
69
+ prerelease: false
70
+ version_requirements: *id005
96
71
  - !ruby/object:Gem::Dependency
72
+ name: jeweler
97
73
  requirement: &id006 !ruby/object:Gem::Requirement
98
74
  none: false
99
75
  requirements:
100
76
  - - ~>
101
77
  - !ruby/object:Gem::Version
102
- hash: 7
103
- segments:
104
- - 1
105
- - 6
106
- - 4
107
78
  version: 1.6.4
108
- version_requirements: *id006
109
- name: jeweler
110
- prerelease: false
111
79
  type: :development
80
+ prerelease: false
81
+ version_requirements: *id006
112
82
  - !ruby/object:Gem::Dependency
83
+ name: rcov
113
84
  requirement: &id007 !ruby/object:Gem::Requirement
114
85
  none: false
115
86
  requirements:
116
87
  - - ">="
117
88
  - !ruby/object:Gem::Version
118
- hash: 3
119
- segments:
120
- - 0
121
89
  version: "0"
122
- version_requirements: *id007
123
- name: rcov
124
- prerelease: false
125
90
  type: :development
91
+ prerelease: false
92
+ version_requirements: *id007
126
93
  description: Replicates data from ActiveRecord (or other Ruby data mapping class) to MongoDB
127
94
  email: phil@greenviewdata.com
128
95
  executables: []
@@ -158,6 +125,7 @@ files:
158
125
  - spec/mongar/replica_spec.rb
159
126
  - spec/mongar_spec.rb
160
127
  - spec/spec_helper.rb
128
+ has_rdoc: true
161
129
  homepage: http://github.com/gdi/mongar
162
130
  licenses:
163
131
  - MIT
@@ -171,7 +139,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
171
139
  requirements:
172
140
  - - ">="
173
141
  - !ruby/object:Gem::Version
174
- hash: 3
142
+ hash: -627046195
175
143
  segments:
176
144
  - 0
177
145
  version: "0"
@@ -180,14 +148,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
180
148
  requirements:
181
149
  - - ">="
182
150
  - !ruby/object:Gem::Version
183
- hash: 3
184
- segments:
185
- - 0
186
151
  version: "0"
187
152
  requirements: []
188
153
 
189
154
  rubyforge_project:
190
- rubygems_version: 1.8.10
155
+ rubygems_version: 1.6.2
191
156
  signing_key:
192
157
  specification_version: 3
193
158
  summary: Replicates data from ActiveRecord (or other Ruby data mapping class) to MongoDB