mongar 0.0.4

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/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