mongo_delegate 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Mike Harris
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,18 @@
1
+ = mongo_delegate
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but
13
+ bump version in a commit by itself I can ignore when I pull)
14
+ * Send me a pull request. Bonus points for topic branches.
15
+
16
+ == Copyright
17
+
18
+ Copyright (c) 2010 Mike Harris. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "mongo_delegate"
8
+ gem.summary = %Q{restful interface to delegate mongodb records}
9
+ gem.description = %Q{restful interface to delegate mongodb records}
10
+ gem.email = "mharris717@gmail.com"
11
+ gem.homepage = "http://github.com/mharris717/mongo_delegate"
12
+ gem.authors = ["Mike Harris"]
13
+ gem.add_development_dependency "rspec"
14
+ gem.add_development_dependency "rr"
15
+ %w(mharris_ext andand fattr mongo mongo_scope activesupport).each { |x| gem.add_dependency x }
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
20
+ end
21
+
22
+ require 'spec/rake/spectask'
23
+ Spec::Rake::SpecTask.new(:spec) do |spec|
24
+ spec.libs << 'lib' << 'spec'
25
+ spec.spec_files = FileList['spec/**/*_spec.rb']
26
+ end
27
+
28
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
29
+ spec.libs << 'lib' << 'spec'
30
+ spec.pattern = 'spec/**/*_spec.rb'
31
+ spec.rcov = true
32
+ end
33
+
34
+ task :spec => :check_dependencies
35
+
36
+ task :default => :spec
37
+
38
+ require 'rake/rdoctask'
39
+ Rake::RDocTask.new do |rdoc|
40
+ if File.exist?('VERSION')
41
+ version = File.read('VERSION')
42
+ else
43
+ version = ""
44
+ end
45
+
46
+ rdoc.rdoc_dir = 'rdoc'
47
+ rdoc.title = "mongo_delegate #{version}"
48
+ rdoc.rdoc_files.include('README*')
49
+ rdoc.rdoc_files.include('lib/**/*.rb')
50
+ end
51
+
52
+ Jeweler::GemcutterTasks.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,50 @@
1
+ class CompositeCursor
2
+ class FindOps
3
+ attr_accessor :res, :cursor
4
+ include FromHash
5
+ def options; cursor.options; end
6
+ fattr(:num_using) { res.map { |x| x[0].to_af.size }.sum }
7
+ fattr(:found_ids) { res.map { |x| x[1].to_af.map { |x| x['_id'] } }.flatten }
8
+ fattr(:ops) do
9
+ r = {}
10
+ r[:limit] = (options[:limit] - num_using) if options[:limit]
11
+ r[:skip] = [(options[:skip] - found_ids.size ),0].max if options[:skip]
12
+ r
13
+ end
14
+ def zero_limit?
15
+ ops[:limit] == 0
16
+ end
17
+ end
18
+
19
+ attr_accessor :colls, :selector, :options
20
+ include FromHash
21
+ include Enumerable
22
+ fattr(:rows) do
23
+ cursors.map { |x| x.to_af }.flatten
24
+ end
25
+ def each(&b)
26
+ rows.each(&b)
27
+ end
28
+ def count
29
+ rows.size
30
+ end
31
+ def first
32
+ rows.first
33
+ end
34
+ fattr(:cursors) do
35
+ colls.inject([]) do |res,coll|
36
+ ops = FindOps.new(:res => res, :cursor => self)
37
+ res + if !ops.zero_limit?
38
+ [[coll.scope_nin('_id' => ops.found_ids).find(selector,ops.ops),coll.find(selector)]]
39
+ else
40
+ []
41
+ end
42
+ end.map { |x| x[0] }
43
+ end
44
+ fattr(:unpruned_cursors) do
45
+ colls.map { |c| c.find(selector) }
46
+ end
47
+ fattr(:unpruned_rows) do
48
+ unpruned_cursors.map { |c| c.to_a }.flatten
49
+ end
50
+ end
@@ -0,0 +1,31 @@
1
+ require 'rubygems'
2
+ require 'mongo'
3
+ require 'mongo_scope'
4
+ require 'mharris_ext'
5
+ require 'active_support'
6
+ require 'andand'
7
+
8
+ %w(ext composite_cursor).each { |x| require File.join(File.dirname(__FILE__),x) }
9
+
10
+ module Mongo
11
+ class DelegatingCollection
12
+ include FromHash
13
+ include CollMod
14
+ attr_accessor :remote, :local
15
+ def find(selector={},options={})
16
+ CompositeCursor.new(:colls => [local,remote],:selector => selector, :options => options)
17
+ end
18
+ def find_one(selector = {},options = {})
19
+ find(selector,options.merge(:limit => 1)).first
20
+ end
21
+ def remove
22
+ colls.each { |x| x.remove }
23
+ end
24
+ def colls
25
+ [local,remote]
26
+ end
27
+ def save(d)
28
+ local.save(d.merge('_duplicate' => true))
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,18 @@
1
+ module Enumerable
2
+ def uniq_by(&b)
3
+ group_by(&b).values.map { |x| x.first }
4
+ end
5
+ end
6
+
7
+ module CollMod
8
+ def count
9
+ find.count
10
+ end
11
+ end
12
+
13
+ class Mongo::Cursor
14
+ fattr(:to_af) { to_a }
15
+ include Enumerable
16
+ end
17
+
18
+ Mongo::Collection.send(:include,CollMod)
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__),"mongo_delegate","delegating_collection")
@@ -0,0 +1,69 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ context Mongo::DelegatingCollection do
4
+ def setup_coll
5
+ @conn = Mongo::Connection.new
6
+ @d = Mongo::DelegatingCollection.new(:remote => @conn.db('dc-remote').collection('abc'), :local => @conn.db('dc-local').collection('abc'))
7
+ @d.remove
8
+ @remotes = %w(Ellen Randy Barbara).each { |x| @d.remote.save(:name => x) }
9
+ @locals = %w(Mike Lou Lowell).each { |x| @d.local.save(:name => x) }
10
+ @all = @remotes + @locals
11
+ end
12
+ context 'find' do
13
+ before { setup_coll }
14
+ it 'find returns all records' do
15
+ @d.find.count.should == @all.size
16
+ end
17
+ it 'find doesnt return dups' do
18
+ @d.local.save(@d.remote.find_one(:name => 'Randy'))
19
+ @d.find.count.should == @all.size
20
+ @d.find.unpruned_rows.size.should == @all.size + 1
21
+ end
22
+ it 'find calls find on remote with local ids' do
23
+ local_ids = @d.local.find.map { |x| x['_id'] }
24
+ mock.proxy(@d.remote).scope_nin('_id' => local_ids).times(1)
25
+ @d.find.rows
26
+ end
27
+ it 'find returns local precedence' do
28
+ r = @d.remote.find_one(:name => 'Randy').merge(:age => 'old')
29
+ @d.local.save(r)
30
+ @d.find_one(:name => 'Randy')['age'].should == 'old'
31
+ end
32
+ it 'respects limit' do
33
+ @d.find({},:limit => 4).count.should == 4
34
+ expected_names = @d.find.map { |x| x['name'] }[0...4].sort
35
+ @d.find({},:limit => 4).map { |x| x['name'] }.sort.should == expected_names
36
+ end
37
+ it 'doesnt query more colls after reaching limit' do
38
+ mock.proxy(@d.remote).find(anything,anything).times(0)
39
+ @d.find({},:limit => 2).rows
40
+ end
41
+ it 'respects skip' do
42
+ @d.find({},:skip => 1).count.should == 5
43
+ @d.find({},:skip => 1).map { |x| x['name'] }.sort.should == @all.reject { |x| x == 'Mike' }.sort
44
+ end
45
+ it 'respects skip whole collection' do
46
+ @d.find({},:skip => 4).count.should == 2
47
+ end
48
+ it 'wont return remote records that were skipped locally' do
49
+ @d.local.save(@d.remote.find_one(:name => 'Randy'))
50
+ @d.find({},:skip => 5).count.should == 1
51
+ end
52
+ it 'respects skip and limit' do
53
+ @d.find({},:skip => 1, :limit => 4).count.should == 4
54
+ end
55
+ # it 'count doesnt fetch records' do
56
+ # mock.instance_of(Mongo::Cursor).to_a.times(0)
57
+ # @d.count.should == 6
58
+ # end
59
+ end
60
+ context 'save' do
61
+ before { setup_coll }
62
+ it 'save uses local' do
63
+ @d.save(:name => 'Pat')
64
+ @d.count.should == @all.size + 1
65
+ @d.remote.count.should == @remotes.size
66
+ @d.local.count.should == @locals.size + 1
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,3 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --colour
2
+ -f s
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'mongo_delegate'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+ require 'rr'
7
+
8
+ Spec::Runner.configure do |config|
9
+ config.mock_with :rr
10
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongo_delegate
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Mike Harris
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-13 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: rr
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: mharris_ext
37
+ type: :runtime
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: andand
47
+ type: :runtime
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: fattr
57
+ type: :runtime
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ - !ruby/object:Gem::Dependency
66
+ name: mongo
67
+ type: :runtime
68
+ version_requirement:
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ version:
75
+ - !ruby/object:Gem::Dependency
76
+ name: mongo_scope
77
+ type: :runtime
78
+ version_requirement:
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: "0"
84
+ version:
85
+ - !ruby/object:Gem::Dependency
86
+ name: activesupport
87
+ type: :runtime
88
+ version_requirement:
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: "0"
94
+ version:
95
+ description: restful interface to delegate mongodb records
96
+ email: mharris717@gmail.com
97
+ executables: []
98
+
99
+ extensions: []
100
+
101
+ extra_rdoc_files:
102
+ - LICENSE
103
+ - README.rdoc
104
+ files:
105
+ - .document
106
+ - .gitignore
107
+ - LICENSE
108
+ - README.rdoc
109
+ - Rakefile
110
+ - VERSION
111
+ - lib/mongo_delegate.rb
112
+ - lib/mongo_delegate/composite_cursor.rb
113
+ - lib/mongo_delegate/delegating_collection.rb
114
+ - lib/mongo_delegate/ext.rb
115
+ - spec/delegating_collection_spec.rb
116
+ - spec/mongo_delegate_spec.rb
117
+ - spec/spec.opts
118
+ - spec/spec_helper.rb
119
+ has_rdoc: true
120
+ homepage: http://github.com/mharris717/mongo_delegate
121
+ licenses: []
122
+
123
+ post_install_message:
124
+ rdoc_options:
125
+ - --charset=UTF-8
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: "0"
133
+ version:
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: "0"
139
+ version:
140
+ requirements: []
141
+
142
+ rubyforge_project:
143
+ rubygems_version: 1.3.5
144
+ signing_key:
145
+ specification_version: 3
146
+ summary: restful interface to delegate mongodb records
147
+ test_files:
148
+ - spec/delegating_collection_spec.rb
149
+ - spec/mongo_delegate_spec.rb
150
+ - spec/spec_helper.rb