mongar 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
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