mordor 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,19 @@
1
+ ## Introduction
2
+ Small library to add DataMapper style resources for MongoDB.
3
+
4
+ ```ruby
5
+ class ExampleResource
6
+ include Mordor::Resource
7
+
8
+ attribute :first, :index => true
9
+ attribute :second
10
+ attribute :third, :finder_method => :find_by_third_attribute
11
+ end
12
+ ```
13
+
14
+ This adds attr_accessors to the ExampleResource for each attribute, plus adds finder methods of the form
15
+ `find_by_{attribute}`. The naming convention can be overridden by using the optional `:finder_method` option,
16
+ as can be seen with the third attribute.
17
+
18
+ When the `:index => true` option is set, indices are ensured before each query on
19
+ the collection. Indices are descending by default, but this can be changed by also supplying a `:index_type => Mongo::ASCENDING` option.
@@ -7,22 +7,6 @@ module Mordor
7
7
  @cursor = cursor
8
8
  end
9
9
 
10
- def to_a
11
- array = []
12
- unless @cursor.is_a? Array
13
- @cursor.each do |element|
14
- if element.is_a? @klass
15
- array << element
16
- else
17
- array << @klass.new(element)
18
- end
19
- end
20
- else
21
- array = @cursor.dup
22
- end
23
- array
24
- end
25
-
26
10
  def each
27
11
  @cursor.each do |element|
28
12
  if element.is_a? @klass
@@ -31,21 +15,13 @@ module Mordor
31
15
  yield @klass.new(element)
32
16
  end
33
17
  end
18
+ @cursor.rewind! unless @cursor.is_a? Array
34
19
  end
35
20
 
36
- def first
37
- if @cursor.is_a? Array
38
- @cursor.first ? @klass.new(@cursor.first) : nil
39
- else
40
- result = @cursor.first
41
- @cursor.rewind!
42
- result ? @klass.new(result) : nil
43
- end
44
- end
45
-
46
- def size
47
- @cursor.count
21
+ def size(regard_limits_and_offsets = true)
22
+ @cursor.is_a?(Array) ? @cursor.count : @cursor.count(regard_limits_and_offsets)
48
23
  end
24
+ alias :count :size
49
25
 
50
26
  def method_missing(method, *args, &block)
51
27
  if @cursor.respond_to?(method)
@@ -55,15 +31,8 @@ module Mordor
55
31
  end
56
32
  end
57
33
 
58
- def to_json
59
- collection_name = @klass.collection_name.to_sym
60
- res = {
61
- collection_name => []
62
- }
63
- each do |elem|
64
- res[collection_name] << elem.to_hash
65
- end
66
- res.to_json
34
+ def to_json(*args)
35
+ to_a.to_json(*args)
67
36
  end
68
37
 
69
38
  def merge(other_collection)
@@ -28,7 +28,9 @@ module Mordor
28
28
  when Hash
29
29
  value = replace_params(value)
30
30
  when Date, DateTime
31
- value = value.to_time
31
+ value = value.to_time.getlocal
32
+ when Time
33
+ value = value.getlocal
32
34
  when BigDecimal
33
35
  value = value.to_f
34
36
  when Array
@@ -81,6 +83,10 @@ module Mordor
81
83
  result
82
84
  end
83
85
 
86
+ def to_json(*args)
87
+ to_hash.merge(:_id => _id).to_json(*args)
88
+ end
89
+
84
90
  module ClassMethods
85
91
  def create(attributes = {})
86
92
  resource = self.new(attributes)
@@ -89,7 +95,7 @@ module Mordor
89
95
  end
90
96
 
91
97
  def all(options = {})
92
- Collection.new(self, collection.find({}, options).to_a)
98
+ Collection.new(self, perform_collection_find({}, options))
93
99
  end
94
100
 
95
101
  def collection
@@ -105,7 +111,7 @@ module Mordor
105
111
  if id.is_a?(String)
106
112
  id = BSON::ObjectId.from_string(id)
107
113
  end
108
- if attributes = collection.find_one(:_id => id)
114
+ if attributes = perform_collection_find_one(:_id => id)
109
115
  new(attributes)
110
116
  else
111
117
  nil
@@ -116,12 +122,13 @@ module Mordor
116
122
  @connection ||= Mordor.connection
117
123
  end
118
124
 
125
+
119
126
  def find_by_id(id)
120
127
  get(id)
121
128
  end
122
129
 
123
130
  def find(query, options = {})
124
- Collection.new(self, collection.find(query, options).to_a)
131
+ Collection.new(self, perform_collection_find(query, options))
125
132
  end
126
133
 
127
134
  def find_by_day(day, options = {})
@@ -137,17 +144,21 @@ module Mordor
137
144
  end_of_day = (day.to_date + 1).to_datetime.to_date.to_time
138
145
  end
139
146
  hash = {:at => {'$gte' => start, '$lt' => end_of_day}}
140
- if options.keys.include?(:limit)
141
- cursor = collection.find({:at => {'$gte' => start, '$lt' => end_of_day}}, options).to_a
142
- else
143
- cursor = collection.find({:at => {'$gte' => start, '$lt' => end_of_day}})
144
- end
147
+ cursor = perform_collection_find({:at => {'$gte' => start, '$lt' => end_of_day}}, options)
145
148
  Collection.new(self, cursor)
146
149
  end
147
150
 
151
+
148
152
  def attribute(name, options = {})
149
- @attributes ||= []
153
+ @attributes ||= []
154
+ @indices ||= []
155
+ @index_types ||= {}
156
+
150
157
  @attributes << name unless @attributes.include?(name)
158
+ if options[:index]
159
+ @indices << name unless @indices.include?(name)
160
+ @index_types[name] = options[:index_type] ? options[:index_type] : Mongo::DESCENDING
161
+ end
151
162
 
152
163
  method_name = options.key?(:finder_method) ? options[:finder_method] : "find_by_#{name}"
153
164
 
@@ -156,15 +167,36 @@ module Mordor
156
167
  attr_accessor name
157
168
 
158
169
  def self.#{method_name}(value, options = {})
159
- if options.keys.include?(:limit)
160
- col = collection.find({:#{name} => value}, options).to_a
161
- else
162
- col = collection.find(:#{name} => value)
163
- end
170
+ col = perform_collection_find({:#{name} => value}, options)
164
171
  Collection.new(self, col)
165
172
  end
166
173
  EOS
167
174
  end
175
+
176
+ private
177
+ def perform_collection_find(query, options = {})
178
+ ensure_indices
179
+ collection.find(query, options)
180
+ end
181
+
182
+ def perform_collection_find_one(query, options = {})
183
+ ensure_indices
184
+ collection.find_one(query, options)
185
+ end
186
+
187
+ def ensure_indices
188
+ indices.each do |index|
189
+ collection.ensure_index( [ [index.to_s, index_types[index]] ] )
190
+ end
191
+ end
192
+
193
+ def indices
194
+ @indices ||= []
195
+ end
196
+
197
+ def index_types
198
+ @index_types ||= {}
199
+ end
168
200
  end
169
201
  end
170
202
  end
@@ -2,8 +2,8 @@ Gem::Specification.new do |s|
2
2
  s.name = "mordor"
3
3
 
4
4
  # Do not set the version and date field manually, this is done by the release script
5
- s.version = "0.1.3"
6
- s.date = "2011-11-15"
5
+ s.version = "0.2.0"
6
+ s.date = "2011-12-23"
7
7
 
8
8
  s.summary = "mordor"
9
9
  s.description = <<-eos
@@ -29,6 +29,6 @@ Gem::Specification.new do |s|
29
29
 
30
30
  # The files and test_files directives are set automatically by the release script.
31
31
  # Do not change them by hand, but make sure to add the files to the git repository.
32
- s.files = %w(.gitignore Gemfile Gemfile.lock README Rakefile lib/mordor.rb lib/mordor/collection.rb lib/mordor/resource.rb lib/mordor/version.rb mordor.gemspec spec/mordor/collection_spec.rb spec/mordor/connection_spec.rb spec/mordor/resource_spec.rb spec/spec.opts spec/spec_helper.rb tasks/github-gem.rake)
32
+ s.files = %w(.gitignore Gemfile Gemfile.lock README.md Rakefile lib/mordor.rb lib/mordor/collection.rb lib/mordor/resource.rb lib/mordor/version.rb mordor.gemspec spec/mordor/collection_spec.rb spec/mordor/connection_spec.rb spec/mordor/resource_spec.rb spec/spec.opts spec/spec_helper.rb tasks/github-gem.rake)
33
33
  end
34
34
 
@@ -4,9 +4,9 @@ describe "with respect to collections" do
4
4
  class TestResource
5
5
  include Mordor::Resource
6
6
 
7
- attribute :first
8
- attribute :second
9
- attribute :third, :finder_method => :find_by_third_attribute
7
+ attribute :first, :index => true
8
+ attribute :second, :index => true, :index_type => Mongo::ASCENDING
9
+ attribute :third, :finder_method => :find_by_third_attribute
10
10
  end
11
11
 
12
12
  describe "serialization" do
@@ -28,11 +28,82 @@ describe "with respect to collections" do
28
28
 
29
29
  json_collection = JSON.parse(json_collection)
30
30
 
31
- collection_name = TestResource.collection_name.to_sym.to_s
32
- json_collection.keys.should include collection_name
33
- json_collection[collection_name].should_not be_nil
34
- json_collection[collection_name].should be_a Array
35
- json_collection[collection_name].size.should == 5
31
+ json_collection.size.should == 5
32
+ end
33
+ end
34
+
35
+ describe "converting to array" do
36
+ before :all do
37
+ clean_sheet
38
+
39
+ 5.times do |index|
40
+ res = TestResource.new(:first => "#{index}_first", :second => "#{index}_second", :third => "#{index}_third")
41
+ res.save.should be_true
42
+ end
43
+ end
44
+
45
+ it "should be possible to convert a collection to an array" do
46
+ collection = TestResource.find_by_first("1_first")
47
+ collection.to_a.should be_a Array
48
+ end
49
+
50
+ it "should be possible to convert multiple times after iterating using each" do
51
+ collection = TestResource.find_by_first("1_first")
52
+ collection.each do |resource|
53
+ resource.first
54
+ end
55
+ array1 = collection.to_a
56
+ array2 = collection.to_a
57
+ array1.size.should == array2.size
58
+ end
59
+
60
+ it "should be possible to convert a collection to an array multiple times" do
61
+ collection = TestResource.find_by_first("1_first")
62
+ array1 = collection.to_a
63
+ array2 = collection.to_a
64
+ array1.size.should == array2.size
65
+ end
66
+
67
+ it "should convert the collection to an array with the same size" do
68
+ collection = TestResource.find_by_first("1_first")
69
+ collection_size = collection.size
70
+ collection.to_a.size.should == collection_size
71
+ end
72
+ end
73
+
74
+ describe "counting" do
75
+
76
+ before :all do
77
+ clean_sheet
78
+
79
+ 5.times do |index|
80
+ res = TestResource.new(:first => "#{index}_first", :second => "#{index}_second", :third => "#{index}_third")
81
+ res.save.should be_true
82
+ end
83
+ end
84
+
85
+ it "should default to taking in account limits" do
86
+ TestResource.find({}, {:limit => 3}).count.should == 3
87
+ end
88
+
89
+ it "should not take in account limits when requested" do
90
+ TestResource.find({}, {:limit => 3}).count(false).should == 5
91
+ end
92
+
93
+ it "should not take in account skips when requested" do
94
+ TestResource.find({}, {:skip => 2}).count(false).should == 5
95
+ end
96
+
97
+ it "should not take in account skips and limits when requested" do
98
+ TestResource.find({}, {:skip => 1, :limit => 3}).count(false).should == 5
99
+ end
100
+
101
+ it "should take in account skips by defaults" do
102
+ TestResource.find({}, {:skip => 2}).count.should == 3
103
+ end
104
+
105
+ it "should take in account skips and limits by default" do
106
+ TestResource.find({}, {:skip => 1, :limit => 3}).count.should == 3
36
107
  end
37
108
  end
38
109
 
@@ -1,12 +1,22 @@
1
1
  require File.join(File.dirname(__FILE__), '..', '/spec_helper.rb')
2
2
 
3
3
  describe "with respect to resources" do
4
- class TestResource
5
- include Mordor::Resource
4
+ before :each do
5
+ class TestResource
6
+ include Mordor::Resource
7
+
8
+ attribute :first, :index => true
9
+ attribute :second, :index => true, :index_type => Mongo::ASCENDING
10
+ attribute :third, :finder_method => :find_by_third_attribute
11
+
12
+ # Put this in here again to ensure the original method is still here
13
+ class_eval do
14
+ def self.ensure_indices
15
+ collection.ensure_index( indices.map{|index| [index.to_s, Mongo::DESCENDING]} ) if indices.any?
16
+ end
6
17
 
7
- attribute :first
8
- attribute :second
9
- attribute :third, :finder_method => :find_by_third_attribute
18
+ end
19
+ end
10
20
  end
11
21
 
12
22
  it "should create accessor methods for all attributes" do
@@ -23,6 +33,47 @@ describe "with respect to resources" do
23
33
  TestResource.methods.should include "find_by_third_attribute"
24
34
  end
25
35
 
36
+ it "should ensure indices when the option :index => true is given" do
37
+ TestResource.send(:indices).should include :first
38
+ end
39
+
40
+ it "should default to descending indices" do
41
+ TestResource.send(:index_types).keys.should include :first
42
+ TestResource.send(:index_types)[:first].should == Mongo::DESCENDING
43
+ end
44
+
45
+ it "should be possible to set index type using the 'index_type' option" do
46
+ TestResource.send(:index_types).keys.should include :second
47
+ TestResource.send(:index_types)[:second].should == Mongo::ASCENDING
48
+ end
49
+
50
+ it "should call ensure_index on the collection for each index when a query is performed" do
51
+ TestResource.class_eval do
52
+ def self.ensure_count
53
+ @count ||= 0
54
+ end
55
+
56
+ def self.ensure_count=(val)
57
+ @count = val
58
+ end
59
+
60
+ private
61
+ def self.do_ensure_indices
62
+ indices.each do |index|
63
+ collection.ensure_index( [ [index.to_s, index_types[index]] ] )
64
+ end
65
+ end
66
+
67
+ def self.ensure_indices
68
+ self.ensure_count = self.ensure_count + 1
69
+ self.do_ensure_indices
70
+ end
71
+ end
72
+ TestResource.create({:first => 'first', :second => 'second', :third => 'third'})
73
+ TestResource.all()
74
+ TestResource.ensure_count.should == 1
75
+ end
76
+
26
77
  context "with respect to replacing params" do
27
78
  before :each do
28
79
  clean_sheet
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mordor
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 23
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 1
9
- - 3
10
- version: 0.1.3
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Jan-Willem Koelewijn
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-11-15 00:00:00 +01:00
19
+ date: 2011-12-23 00:00:00 +01:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -174,7 +174,7 @@ files:
174
174
  - .gitignore
175
175
  - Gemfile
176
176
  - Gemfile.lock
177
- - README
177
+ - README.md
178
178
  - Rakefile
179
179
  - lib/mordor.rb
180
180
  - lib/mordor/collection.rb
data/README DELETED
@@ -1,13 +0,0 @@
1
- Small library to add DataMapper style resources for MongoDB.
2
-
3
- class ExampleResource
4
- include Mordor::Resource
5
-
6
- attribute :first
7
- attribute :second
8
- attribute :third, :finder_method => :find_by_third_attribute
9
- end
10
-
11
- This adds attr_accessors to the ExampleResource for each attribute, plus adds finder methods of the form
12
- find_by_{attribute}. The naming convention can be overridden by using the optional :finder_method option,
13
- as can be seen with the third attribute.