mongar 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/mongar.gemspec ADDED
@@ -0,0 +1,82 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "mongar"
8
+ s.version = "0.0.4"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Philippe Green"]
12
+ s.date = "2011-12-14"
13
+ s.description = "Replicates data from ActiveRecord (or other Ruby data mapping class) to MongoDB"
14
+ s.email = "phil@greenviewdata.com"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "lib/mongar.rb",
29
+ "lib/mongar/column.rb",
30
+ "lib/mongar/logger.rb",
31
+ "lib/mongar/mongo.rb",
32
+ "lib/mongar/mongo/collection.rb",
33
+ "lib/mongar/replica.rb",
34
+ "mongar.gemspec",
35
+ "spec/fixtures/configure.rb",
36
+ "spec/fixtures/full_configure.rb",
37
+ "spec/fixtures/sources.rb",
38
+ "spec/integration_spec.rb",
39
+ "spec/mongar/column_spec.rb",
40
+ "spec/mongar/mongo/collection_spec.rb",
41
+ "spec/mongar/mongo_spec.rb",
42
+ "spec/mongar/replica_spec.rb",
43
+ "spec/mongar_spec.rb",
44
+ "spec/spec_helper.rb"
45
+ ]
46
+ s.homepage = "http://github.com/gdi/mongar"
47
+ s.licenses = ["MIT"]
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"
51
+
52
+ if s.respond_to? :specification_version then
53
+ s.specification_version = 3
54
+
55
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
+ s.add_runtime_dependency(%q<linguistics>, [">= 0"])
57
+ s.add_runtime_dependency(%q<mongo>, [">= 0"])
58
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
59
+ s.add_development_dependency(%q<yard>, ["~> 0.6.0"])
60
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
61
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
62
+ s.add_development_dependency(%q<rcov>, [">= 0"])
63
+ else
64
+ s.add_dependency(%q<linguistics>, [">= 0"])
65
+ s.add_dependency(%q<mongo>, [">= 0"])
66
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
67
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
68
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
70
+ s.add_dependency(%q<rcov>, [">= 0"])
71
+ end
72
+ else
73
+ s.add_dependency(%q<linguistics>, [">= 0"])
74
+ s.add_dependency(%q<mongo>, [">= 0"])
75
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
76
+ s.add_dependency(%q<yard>, ["~> 0.6.0"])
77
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
78
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
79
+ s.add_dependency(%q<rcov>, [">= 0"])
80
+ end
81
+ end
82
+
@@ -0,0 +1,27 @@
1
+ Mongar.configure do
2
+ mongo :default do
3
+ database 'integration_spec'
4
+
5
+ status_collection 'stati'
6
+ end
7
+
8
+ replicate Domain do
9
+ column :name do
10
+ primary_index
11
+ end
12
+
13
+ column :client_id
14
+
15
+ set_deleted_finder do |last_replicated_date|
16
+ deleted_since last_replicated_date
17
+ end
18
+
19
+ set_updated_finder do |last_replicated_date|
20
+ updated_since last_replicated_date
21
+ end
22
+
23
+ set_created_finder do |last_replicated_date|
24
+ created_since last_replicated_date
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,60 @@
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
60
+ end
@@ -0,0 +1,62 @@
1
+ class Domain
2
+ attr_accessor :name, :client_id
3
+ attr_accessor :created_at, :updated_at, :deleted_at
4
+
5
+ def initialize(args = {})
6
+ args.each do |key, value|
7
+ self.send(:"#{key}=", value)
8
+ end
9
+ self.created_at = Time.now
10
+ end
11
+
12
+ def name=(val)
13
+ self.updated_at = Time.now
14
+ @name = val
15
+ end
16
+
17
+ def client_id=(val)
18
+ self.updated_at = Time.now
19
+ @client_id = val
20
+ end
21
+
22
+ class << self
23
+ def create(args)
24
+ @@items ||= []
25
+ d = Domain.new(args)
26
+ @@items << d
27
+ d
28
+ end
29
+
30
+ def deleted_since(last_replicated_date)
31
+ last_replicated_date ||= Time.parse("1/1/1900 00:00:00")
32
+ #puts "Deleted Since: #{last_replicated_date} #{@@items.length}"
33
+
34
+ @@items.find_all { |d| d.deleted_at && d.deleted_at > last_replicated_date }
35
+ end
36
+
37
+ def created_since(last_replicated_date)
38
+ last_replicated_date ||= Time.parse("1/1/1900 00:00:00")
39
+ #puts "Created Since: #{last_replicated_date}"
40
+
41
+ @@items.find_all { |d| !d.deleted_at && d.created_at && d.created_at > last_replicated_date }
42
+ end
43
+
44
+ def updated_since(last_replicated_date)
45
+ last_replicated_date ||= Time.parse("1/1/1900 00:00:00")
46
+ #puts "Updated Since: #{last_replicated_date}"
47
+
48
+ @@items.find_all { |d| !d.deleted_at && d.updated_at && d.updated_at > last_replicated_date }
49
+ end
50
+ end
51
+
52
+ def destroy
53
+ self.deleted_at = Time.now
54
+ #puts "I was deleted at #{deleted_at}"
55
+ end
56
+ end
57
+
58
+ class Client
59
+ end
60
+
61
+ class EmailAddress
62
+ end
@@ -0,0 +1,51 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ require File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', 'sources'))
4
+
5
+ describe "Mongar" do
6
+ before(:all) do
7
+ mongo = Mongar::Mongo.new(:name => :default,
8
+ :database => :integration_spec)
9
+ mongo.connection!.drop_database('integration_spec')
10
+ end
11
+ describe "run" do
12
+ before do
13
+ config_path = File.expand_path(File.join(File.dirname(__FILE__), 'fixtures', 'configure.rb'))
14
+ @mongar = eval(File.read(config_path))
15
+
16
+ @collection = Mongar::Mongo.databases[:default].db['domains']
17
+ end
18
+
19
+ it "should add, delete, and update items properly" do
20
+ # inserts
21
+ domain = Domain.create(:name => "test.com", :client_id => 1)
22
+ @mongar.run
23
+ @collection.find_one({ :name => 'test.com' }).should include({'name' => 'test.com', 'client_id' => 1})
24
+
25
+ # updates
26
+ sleep 1
27
+ domain.client_id = 2
28
+ @mongar.run
29
+ @collection.find_one({ :name => 'test.com' }).should include({'name' => 'test.com', 'client_id' => 2})
30
+
31
+ # deletes
32
+ sleep 1
33
+ domain.destroy
34
+ @mongar.run
35
+ @collection.find_one({:name => "test.com"}).should be_nil
36
+
37
+ collection = Mongar::Mongo.databases[:default].db['stati']
38
+ collection.find_one({ :collection_name => 'domains' }).should_not be_nil
39
+ end
40
+
41
+ it "should handle an item that was added, updated, and deleted between runs" do
42
+ domain = Domain.create(:name => "test1.com", :client_id => 1)
43
+ domain.client_id = 2
44
+ domain.destroy
45
+
46
+ @mongar.run
47
+
48
+ @collection.find_one({:name => "test1.com"}).should be_nil
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,50 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Mongar::Replica" do
4
+ before do
5
+ @column = Mongar::Column.new(:name => :first_name)
6
+ end
7
+ describe "#name" do
8
+ it "should return the column name" do
9
+ @column.name.should == :first_name
10
+ end
11
+ end
12
+ describe "#transform" do
13
+ it "should optionally take a symbol, and set transformation to a block that executes that procedure" do
14
+ @column.transform :downcase
15
+ @column.transform_this("Something").should == 'something'
16
+ end
17
+ it "should optionally take a block" do
18
+ @column.transform do |value|
19
+ value.nil? ? 0 : value
20
+ end
21
+ @column.transform_this(nil).should == 0
22
+ @column.transform_this(1).should == 1
23
+ end
24
+ it "should take both a block and a symbol if you wish" do
25
+ @column.transform :reverse do
26
+ downcase
27
+ end
28
+ @column.transform_this("Something").should == 'gnihtemos'
29
+ end
30
+ it "should return the original value if there is no transformation specified" do
31
+ @column.transform_this("blah").should == "blah"
32
+ end
33
+ end
34
+ describe "#index" do
35
+ before do
36
+ @column.index
37
+ end
38
+ it "should set column#indexed? to true" do
39
+ @column.indexed?.should be_true
40
+ end
41
+ end
42
+ describe "#primary_index" do
43
+ before do
44
+ @column.primary_index
45
+ end
46
+ it "should set column#primary_index? to true" do
47
+ @column.primary_index?.should be_true
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,201 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe "Mongar::Mongo::Collection" do
4
+ after(:all) do
5
+ # Completely clear out the database
6
+ mongo = Mongar::Mongo.new(:name => :default,
7
+ :database => :mongar_test)
8
+ mongo.connection!.drop_database('mongar_test')
9
+ end
10
+
11
+ before do
12
+ @mongo = Mongar::Mongo.new(:name => :default,
13
+ :database => :mongar_test)
14
+
15
+ @mongo.db.collections.each do |collection|
16
+ collection.remove
17
+ end
18
+
19
+ Mongar::Mongo.databases[:default] = @mongo
20
+ @replica = Mongar::Replica.new(:mongodb_name => :default)
21
+ @collection = Mongar::Mongo::Collection.new(:name => 'clients', :replica => @replica)
22
+
23
+ @existing_key = { :id => 123 }
24
+ @existing_document = { :id => 123, :name => 'Otis' }
25
+
26
+ @new_key = { :id => 1234 }
27
+ @new_document = { :id => 1234, :name => 'George' }
28
+ end
29
+
30
+ describe ".new" do
31
+ it "should return a new collection" do
32
+ @collection.should be_a_kind_of(Mongar::Mongo::Collection)
33
+ end
34
+ end
35
+
36
+ describe "#database" do
37
+ it "should not be nil" do
38
+ @collection.database.should_not be_nil
39
+ end
40
+ end
41
+
42
+ describe "#find" do
43
+ before do
44
+ @collection.create!({ :id => 2, :test => 1 })
45
+ end
46
+ it "should return nil if it can't find the document" do
47
+ @collection.find({ :id => 1 }).should be_nil
48
+ end
49
+ it "should return the document found" do
50
+ @collection.find({ :id => 2 }).should include({"id"=>2, "test"=>1})
51
+ end
52
+ end
53
+
54
+ describe "#create_or_update" do
55
+ it "should update an existing document" do
56
+ @collection.create_or_update(@existing_key, @existing_document).should be_true
57
+ end
58
+ it "should create a new document" do
59
+ @collection.create_or_update(@new_key, @new_document).should be_true
60
+ @collection.find({:id => 1234}).should_not be_nil
61
+ end
62
+ end
63
+
64
+ describe "#create_or_update!" do
65
+ it "should call create_or_update and return true on success" do
66
+ @collection.should_receive(:create_or_update).with({ :a => 1 }, { :a => 1, :b => 2 }).and_return(true)
67
+ @collection.create_or_update!({ :a => 1 }, { :a => 1, :b => 2 }).should be_true
68
+ end
69
+
70
+ it "should call create_or_update and raise an error on failure" do
71
+ @collection.stub!(:create_or_update).with({ :a => 1 }, { :a => 1, :b => 2 }).and_return(false)
72
+ lambda { @collection.create_or_update!({ :a => 1 }, { :a => 1, :b => 2 }) }.should raise_error
73
+ end
74
+ end
75
+
76
+ describe "#mark_all_items_pending_deletion" do
77
+ before do
78
+ @collection.create_or_update(@new_key, @new_document)
79
+ end
80
+
81
+ it "should mark every item with { :pending_deletion => true }" do
82
+ @collection.mark_all_items_pending_deletion
83
+ updated_doc = @collection.find(@new_key)
84
+ updated_doc['pending_deletion'].should be_true
85
+ end
86
+ end
87
+
88
+ describe "#mark_all_items_pending_deletion!" do
89
+ it "should call mark_all_items_pending_deletion and return true on success" do
90
+ @collection.should_receive(:mark_all_items_pending_deletion).and_return(true)
91
+ @collection.mark_all_items_pending_deletion!({}, {}).should be_true
92
+ end
93
+
94
+ it "should call mark_all_items_pending_deletion and raise an error on failure" do
95
+ @collection.stub!(:mark_all_items_pending_deletion).and_return(false)
96
+ lambda { @collection.mark_all_items_pending_deletion!({}, {}) }.should raise_error
97
+ end
98
+ end
99
+
100
+ describe "#delete_all_items_pending_deletion" do
101
+ before do
102
+ @collection.create!({ :id => 1, :test => 1, :pending_deletion => true })
103
+ @collection.create!({ :id => 2, :test => 1, :pending_deletion => false })
104
+ @collection.create!({ :id => 3, :test => 1 })
105
+ end
106
+
107
+ it "should delete all items where { :pending_deletion => true }" do
108
+ @collection.delete_all_items_pending_deletion
109
+ @collection.find({ :id => 1 }).should be_nil
110
+ end
111
+ it "should not delete items where { :pending_deletion => false }" do
112
+ @collection.delete_all_items_pending_deletion
113
+ @collection.find({ :id => 2 }).should_not be_nil
114
+ end
115
+ it "should not delete items where :pending_deletion key does not exist" do
116
+ @collection.delete_all_items_pending_deletion
117
+ @collection.find({ :id => 3 }).should_not be_nil
118
+ end
119
+ end
120
+
121
+ describe "#delete_all_items_pending_deletion!" do
122
+ it "should call delete_all_items_pending_deletion and return true on success" do
123
+ @collection.should_receive(:delete_all_items_pending_deletion).and_return(true)
124
+ @collection.delete_all_items_pending_deletion!({}, {}).should be_true
125
+ end
126
+
127
+ it "should call delete_all_items_pending_deletion and raise an error on failure" do
128
+ @collection.stub!(:delete_all_items_pending_deletion).and_return(false)
129
+ lambda { @collection.delete_all_items_pending_deletion!({}, {}) }.should raise_error
130
+ end
131
+ end
132
+
133
+ describe "#delete" do
134
+ it "should delete a document" do
135
+ @collection.delete(@existing_key).should be_true
136
+ end
137
+
138
+ it "should return true even if the document didn't exist" do
139
+ @collection.delete({ :id => 83838 }).should be_true
140
+ end
141
+ end
142
+
143
+ describe "#delete!" do
144
+ it "should call delete and return true on success" do
145
+ @collection.should_receive(:delete).and_return(true)
146
+ @collection.delete!({}, {}).should be_true
147
+ end
148
+
149
+ it "should call delete and raise an error on failure" do
150
+ @collection.stub!(:delete).and_return(false)
151
+ lambda { @collection.delete!({}, {}) }.should raise_error
152
+ end
153
+ end
154
+
155
+ describe "#create" do
156
+ it "should create a new document" do
157
+ @collection.create(@new_document).should be_true
158
+ end
159
+ end
160
+
161
+ describe "#create!" do
162
+ it "should call create and return true on success" do
163
+ @collection.should_receive(:create).and_return(true)
164
+ @collection.create!({}, {}).should be_true
165
+ end
166
+
167
+ it "should call create and raise an error on failure" do
168
+ @collection.stub!(:create).and_return(false)
169
+ lambda { @collection.create!({}, {}) }.should raise_error
170
+ end
171
+ end
172
+
173
+ describe "#update" do
174
+ it "should update the document" do
175
+ @collection.update(@existing_key, { :name => 'Phil' }).should be_true
176
+ end
177
+ end
178
+
179
+ describe "#update!" do
180
+ it "should call update and return true on success" do
181
+ @collection.should_receive(:update).and_return(true)
182
+ @collection.update!({}, {}).should be_true
183
+ end
184
+
185
+ it "should call update and raise an error on failure" do
186
+ @collection.stub!(:update).and_return(false)
187
+ lambda { @collection.update!({}, {}) }.should raise_error
188
+ end
189
+ end
190
+
191
+ describe "#last_replicated_at" do
192
+ it "should return the last replicated_at date" do
193
+ response = @collection.last_replicated_at = Time.parse("1/1/2012 1:00:00")
194
+ @collection.last_replicated_at.should == Time.parse("1/1/2012 1:00:00")
195
+ end
196
+
197
+ it "should return 1/1/1902 00:00:00 if there was no last_replicated_at" do
198
+ @collection.last_replicated_at.should == Time.parse("1/1/1902 00:00:00")
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,91 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Mongar::Mongo" do
4
+ before do
5
+ @mongo = Mongar::Mongo.new(:name => :somedb,
6
+ :database => :mydb,
7
+ :user => 'mongouser',
8
+ :password => 'password',
9
+ :host => '127.0.0.99',
10
+ :port => 9999,
11
+ :status_collection => 'stati')
12
+ end
13
+
14
+ describe "#database" do
15
+ it "should set the database name if an argument is passed" do
16
+ @mongo.database(:something)
17
+ @mongo.instance_variable_get(:"@database").should == :something
18
+ end
19
+
20
+ it "should return the database name if no argument is passed" do
21
+ @mongo.database.should == :mydb
22
+ end
23
+ end
24
+
25
+ describe "#user" do
26
+ it "should set the user if an argument is passed" do
27
+ @mongo.user(:something)
28
+ @mongo.instance_variable_get(:"@user").should == :something
29
+ end
30
+
31
+ it "should return the user if no argument is passed" do
32
+ @mongo.user.should == 'mongouser'
33
+ end
34
+ end
35
+
36
+ describe "#password" do
37
+ it "should set the password if an argument is passed" do
38
+ @mongo.password(:something)
39
+ @mongo.instance_variable_get(:"@password").should == :something
40
+ end
41
+
42
+ it "should return the password if no argument is passed" do
43
+ @mongo.password.should == 'password'
44
+ end
45
+ end
46
+
47
+ describe "#host" do
48
+ it "should set the host if an argument is passed" do
49
+ @mongo.host(:something)
50
+ @mongo.instance_variable_get(:"@host").should == :something
51
+ end
52
+
53
+ it "should return the host if no argument is passed" do
54
+ @mongo.host.should == '127.0.0.99'
55
+ end
56
+
57
+ it "should default to 127.0.0.1" do
58
+ Mongar::Mongo.new.host.should == '127.0.0.1'
59
+ end
60
+ end
61
+
62
+ describe "#port" do
63
+ it "should set the port if an argument is passed" do
64
+ @mongo.port(:something)
65
+ @mongo.instance_variable_get(:"@port").should == :something
66
+ end
67
+
68
+ it "should return the port if no argument is passed" do
69
+ @mongo.port.should == 9999
70
+ end
71
+
72
+ it "should default to 27017" do
73
+ Mongar::Mongo.new.port.should == 27017
74
+ end
75
+ end
76
+
77
+ describe "#status_collection" do
78
+ it "should set the status_collection if an argument is passed" do
79
+ @mongo.status_collection(:something)
80
+ @mongo.instance_variable_get(:"@status_collection").should == :something
81
+ end
82
+
83
+ it "should return the status_collection if no argument is passed" do
84
+ @mongo.status_collection.should == 'stati'
85
+ end
86
+
87
+ it "should default to statuses" do
88
+ Mongar::Mongo.new.status_collection.should == 'statuses'
89
+ end
90
+ end
91
+ end