mordor 0.1.3 → 0.2.0

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.
@@ -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.