mongoid-metastamp 0.0.1 → 0.0.2
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/LICENSE +20 -0
- data/README.md +143 -17
- data/lib/mongoid/metastamp/time.rb +25 -20
- data/lib/mongoid/metastamp/version.rb +1 -1
- data/mongoid-metastamp.gemspec +2 -2
- data/spec/time_compatibility_spec.rb +70 -0
- data/spec/time_search_spec.rb +211 -0
- data/spec/time_storage_spec.rb +222 -0
- metadata +11 -6
- data/spec/metastamp_spec.rb +0 -57
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) Peter Gumeson
|
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.md
CHANGED
@@ -1,31 +1,157 @@
|
|
1
1
|
Mongoid Metastamp
|
2
2
|
=========================
|
3
3
|
|
4
|
-
|
4
|
+
Provides Mongoid with enhanced meta-timestamps that store additional parsed time metadata,
|
5
|
+
allowing more powerful querying on specific time fields and across normalized time zones.
|
6
|
+
|
5
7
|
|
6
8
|
What It Does
|
7
9
|
=========================
|
8
10
|
(Or why would I want to use this?)
|
9
11
|
|
10
|
-
Storing simple timestamps is all well and good if
|
11
|
-
|
12
|
+
Storing simple timestamps is all well and good if your queries are simple or involve just one timezone.
|
13
|
+
But sometimes you need to search across multiple locations while
|
14
|
+
ignoring timezone offsets. For example:
|
15
|
+
|
16
|
+
* Find all flights that depart from any airport between 1:00pm and 2:00pm local time.
|
17
|
+
* Return all employees that clocked in after 8:00am at either the Denver or San Diego location.
|
18
|
+
|
19
|
+
Other times you want to be able to query very specific parts of the
|
20
|
+
date/time that typically can't be accessed without parsing it:
|
21
|
+
|
22
|
+
* Find all transactions that occured on weekday afternoons in 2011.
|
23
|
+
* Return all users that signed up in January for the last 3 years.
|
24
|
+
|
25
|
+
Typically to do these things, you'd need to add a bunch of of complex time ranges to your query.
|
26
|
+
Or you might query the entire range and loop through each result, running additional tests on the parsed time.
|
27
|
+
|
28
|
+
Using mongoid-metastamp gives you a custom time field type that is normalized beforehand,
|
29
|
+
and then stored in a MongoDB friendly way for easy querying.
|
30
|
+
|
31
|
+
|
32
|
+
Installation
|
33
|
+
=========================
|
34
|
+
|
35
|
+
In your Gemfile
|
36
|
+
|
37
|
+
```
|
38
|
+
gem 'mongoid-metastamp'
|
39
|
+
```
|
40
|
+
|
41
|
+
```
|
42
|
+
$ bundle install
|
43
|
+
```
|
44
|
+
|
45
|
+
Usage
|
46
|
+
=========================
|
47
|
+
|
48
|
+
For the most part, `Mongoid::Metastamp::Time` fields can be used just like regular `Time` fields:
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
class MyEvent
|
52
|
+
include Mongoid::Document
|
53
|
+
field :starts_at, type: Mongoid::Metastamp::Time
|
54
|
+
field :ends_at, type: Mongoid::Metastamp::Time
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
MyEvent.create(starts_at: Time.now, ends_at: Time.now + 1.day)
|
60
|
+
|
61
|
+
event = MyEvent.where(:starts_at.lt => Time.now, :ends_at.gt => Time.now).one
|
62
|
+
event.starts_at # => Time
|
63
|
+
event.ends_at # => Time
|
64
|
+
```
|
65
|
+
|
66
|
+
Data Stored
|
67
|
+
=========================
|
68
|
+
|
69
|
+
When you define a `Mongoid::Metastamp::Time` field, the following meta fields also get stored inside its hash:
|
12
70
|
|
13
|
-
|
14
|
-
|
71
|
+
* `time` (Date)
|
72
|
+
* `normalized` (Date)
|
73
|
+
* `year` (Int)
|
74
|
+
* `month` (Int)
|
75
|
+
* `day` (Int)
|
76
|
+
* `wday` (Int)
|
77
|
+
* `hour` (Int)
|
78
|
+
* `min` (Int)
|
79
|
+
* `sec` (Int)
|
80
|
+
* `zone` (String)
|
81
|
+
* `offset` (Int)
|
15
82
|
|
16
|
-
|
83
|
+
|
84
|
+
The `time` meta-field stores whatever you assign the field to.
|
85
|
+
It will also be the value deserialized when you access the field.
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
field :timestamp, type: Mongoid::Metastamp::Time
|
89
|
+
```
|
90
|
+
|
91
|
+
For a field called `timestamp`, you can access the raw metadata fields like this:
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
event = MyEvent.new(starts_at: "2011-10-05 10:00:00 -0700")
|
95
|
+
event['timestamp']['month'] # => 10
|
96
|
+
event['timestamp']['day'] # => 5
|
97
|
+
event['timestamp']['year'] # => 2011
|
98
|
+
event['timestamp']['zone'] # => "-07:00"
|
99
|
+
```
|
100
|
+
|
101
|
+
The `normalized` meta-field is the time normalized to a UTC value.
|
102
|
+
This is useful when you want to query ignoring local offsets.
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
eastern_event = MyEvent.new(timestamp: "2011-10-05 10:00:00 -0400")
|
106
|
+
pacific_event = MyEvent.new(timestamp: "2011-10-05 10:00:00 -0700")
|
107
|
+
|
108
|
+
eastern_event['timestamp']['time'] # => 2011-10-05 14:00:00 UTC
|
109
|
+
eastern_event['timestamp']['normalized'] # => 2011-10-05 10:00:00 UTC
|
110
|
+
|
111
|
+
pacific_event['timestamp']['time'] # => 2011-10-05 17:00:00 UTC
|
112
|
+
pacific_event['timestamp']['normalized'] # => 2011-10-05 10:00:00 UTC
|
113
|
+
```
|
114
|
+
|
115
|
+
|
116
|
+
Querying
|
17
117
|
=========================
|
18
|
-
(What metadata should we store?)
|
19
118
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
119
|
+
Since the `time` meta-field is the default, it can be queried as either `timestamp` or `timestamp.time`:
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
good_old_days = Day.where(:timestamp.lt => 20.years.ago)
|
123
|
+
```
|
124
|
+
|
125
|
+
or...
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
good_old_days = Day.where("timestamp.time" => { '$lt' => 20.years.ago })
|
129
|
+
```
|
130
|
+
|
131
|
+
The other meta-fields need to be queried with the full syntax:
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
hump_days = Day.where("timestamp.wday" => 5)
|
135
|
+
=> Only Wednesdays
|
136
|
+
|
137
|
+
after_noon_delights = Delight.where("timestamp.hour" => { '$gte' => 12, '$lte' => 15 })
|
138
|
+
=> Only between 12pm and 3pm
|
139
|
+
```
|
140
|
+
See [search specs](https://github.com/sporkd/mongoid-metastamp/blob/master/spec/time_search_spec.rb)
|
141
|
+
for more complete examples.
|
142
|
+
|
143
|
+
|
144
|
+
Todo
|
145
|
+
======
|
146
|
+
|
147
|
+
* Add custom finders and scopes
|
148
|
+
* Migration tasks for existing time fields
|
149
|
+
* Additional types
|
150
|
+
|
151
|
+
|
152
|
+
License
|
153
|
+
========
|
29
154
|
|
155
|
+
Copyright (c) 2011 Peter Gumeson.
|
156
|
+
See [LICENSE](https://github.com/sporkd/mongoid-metastamp/blob/master/LICENSE) for full license.
|
30
157
|
|
31
|
-
(More to come)
|
@@ -8,40 +8,45 @@ module Mongoid #:nodoc:
|
|
8
8
|
|
9
9
|
def deserialize(object)
|
10
10
|
return nil if object.blank?
|
11
|
-
super(object
|
11
|
+
return super(object) if object.instance_of?(::Time)
|
12
|
+
super(object['time'])
|
12
13
|
end
|
13
14
|
|
14
15
|
def serialize(object)
|
16
|
+
return nil if object.blank?
|
15
17
|
time = super(object)
|
16
|
-
|
18
|
+
date_time = parse_datetime(object)
|
17
19
|
{
|
18
|
-
|
19
|
-
normalized:
|
20
|
-
year:
|
21
|
-
month:
|
22
|
-
day:
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
time: time,
|
21
|
+
normalized: date_time.to_s.to_time,
|
22
|
+
year: date_time.year,
|
23
|
+
month: date_time.month,
|
24
|
+
day: date_time.day,
|
25
|
+
wday: date_time.wday,
|
26
|
+
hour: date_time.hour,
|
27
|
+
min: date_time.min,
|
28
|
+
sec: date_time.sec,
|
29
|
+
zone: date_time.zone,
|
30
|
+
offset: date_time.utc_offset
|
31
|
+
}.stringify_keys
|
27
32
|
end
|
28
33
|
|
29
34
|
protected
|
30
35
|
|
31
|
-
def
|
32
|
-
case
|
36
|
+
def parse_datetime(value)
|
37
|
+
case value
|
33
38
|
when ::String
|
34
|
-
|
35
|
-
when ::
|
36
|
-
|
39
|
+
::DateTime.parse(value)
|
40
|
+
when ::Time
|
41
|
+
offset = ActiveSupport::TimeZone.seconds_to_utc_offset(value.utc_offset)
|
42
|
+
::DateTime.new(value.year, value.month, value.day, value.hour, value.min, value.sec, offset)
|
37
43
|
when ::Date
|
38
|
-
|
44
|
+
::DateTime.new(value.year, value.month, value.day)
|
39
45
|
when ::Array
|
40
|
-
|
46
|
+
::DateTime.new(*value)
|
41
47
|
else
|
42
|
-
|
48
|
+
value
|
43
49
|
end
|
44
|
-
::Time.parse(time.iso8601.sub(/-(\d\d:\d\d)$/, "-00:00"))
|
45
50
|
end
|
46
51
|
end
|
47
52
|
end
|
data/mongoid-metastamp.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.authors = ["Peter Gumeson"]
|
10
10
|
s.email = ["gumeson@gmail.com"]
|
11
11
|
s.homepage = "http://rubygems.org/gems/mongoid-metastamp"
|
12
|
-
s.summary = %q{ Store and query more useful information about your Mongoid timestamps }
|
13
|
-
s.description = %q{ Provides enhanced meta-timestamps
|
12
|
+
s.summary = %q{ Store and query more useful information about your Mongoid timestamps. }
|
13
|
+
s.description = %q{ Provides Mongoid with enhanced meta-timestamps that store additional parsed time metadata, allowing more powerful querying on specific time fields and across normalized time zones. }
|
14
14
|
|
15
15
|
s.rubyforge_project = "mongoid-metastamp"
|
16
16
|
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe "Mongoid::Metastamp::Time" do
|
6
|
+
|
7
|
+
let :two_pm_pacific do
|
8
|
+
"2011-10-05T14:00:00-07:00"
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "compatibility with Time class" do
|
12
|
+
|
13
|
+
class Legacy
|
14
|
+
include Mongoid::Document
|
15
|
+
field :timestamp, type: Time
|
16
|
+
end
|
17
|
+
|
18
|
+
let :instance do
|
19
|
+
Legacy.create(timestamp: two_pm_pacific).reload
|
20
|
+
end
|
21
|
+
|
22
|
+
context "before upgrade" do
|
23
|
+
|
24
|
+
it "should have a timestamp" do
|
25
|
+
instance.timestamp.should == Time.parse(two_pm_pacific)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should store timestamp as a Time" do
|
29
|
+
instance['timestamp'].class.should == Time
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
context "after Mongoid::Metastamp upgrade" do
|
35
|
+
|
36
|
+
before :each do
|
37
|
+
instance
|
38
|
+
Legacy.field(:timestamp, type: Mongoid::Metastamp::Time)
|
39
|
+
end
|
40
|
+
|
41
|
+
let :legacy do
|
42
|
+
Legacy.find(instance.id)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should still be able to read legacy timestamps" do
|
46
|
+
legacy.timestamp.should == Time.parse(two_pm_pacific)
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "updating timestamp with the same time" do
|
50
|
+
|
51
|
+
before :each do
|
52
|
+
legacy.update_attribute(:timestamp, two_pm_pacific)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should now store timestamp as a Hash" do
|
56
|
+
legacy['timestamp'].class.should == Hash
|
57
|
+
legacy['timestamp']['time'].should == Time.parse(two_pm_pacific)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should still be compatible with the legacy timestamp" do
|
61
|
+
legacy.timestamp.should == Time.parse(two_pm_pacific)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe "Mongoid::Metastamp::Time" do
|
6
|
+
|
7
|
+
let :ten_am_utc do
|
8
|
+
"2011-10-05T10:00:00-00:00"
|
9
|
+
end
|
10
|
+
|
11
|
+
let :ten_am_eastern do
|
12
|
+
"2011-10-05T10:00:00-04:00"
|
13
|
+
end
|
14
|
+
|
15
|
+
let :ten_am_pacific do
|
16
|
+
"2011-10-05T10:00:00-07:00"
|
17
|
+
end
|
18
|
+
|
19
|
+
context "given a 10:00 eastern and a 10:00 pacific timestamp" do
|
20
|
+
|
21
|
+
before :each do
|
22
|
+
@eastern_event = Event.create(timestamp: ten_am_eastern)
|
23
|
+
@pacific_event = Event.create(timestamp: ten_am_pacific)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "searching by timestamp" do
|
27
|
+
|
28
|
+
it "should not return any events when searching a 10:00 UTC range" do
|
29
|
+
Event.where(
|
30
|
+
:timestamp.gt => Time.parse(ten_am_utc) - 1.second,
|
31
|
+
:timestamp.lt => Time.parse(ten_am_utc) + 1.second
|
32
|
+
).to_a.should == []
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should only return the ET event when searching a 10:00 ET range" do
|
36
|
+
Event.where(
|
37
|
+
:timestamp.gt => Time.parse(ten_am_eastern) - 1.second,
|
38
|
+
:timestamp.lt => Time.parse(ten_am_eastern) + 1.second
|
39
|
+
).to_a.should == [@eastern_event]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should only return the PT event when searching a 10:00 PT range" do
|
43
|
+
Event.where(
|
44
|
+
:timestamp.gt => Time.parse(ten_am_pacific) - 1.second,
|
45
|
+
:timestamp.lt => Time.parse(ten_am_pacific) + 1.second
|
46
|
+
).to_a.should == [@pacific_event]
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "searching by timestamp.time" do
|
52
|
+
|
53
|
+
it "should not return any events when searching a 10:00 UTC range" do
|
54
|
+
Event.where(
|
55
|
+
"timestamp.time" => {
|
56
|
+
'$gt' => Time.parse(ten_am_utc) - 1.second,
|
57
|
+
'$lt' => Time.parse(ten_am_utc) + 1.second
|
58
|
+
}
|
59
|
+
).to_a.should == []
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should only return the ET event when searching a 10:00 ET range" do
|
63
|
+
Event.where(
|
64
|
+
"timestamp.time" => {
|
65
|
+
'$gt' => Time.parse(ten_am_eastern) - 1.second,
|
66
|
+
'$lt' => Time.parse(ten_am_eastern) + 1.second
|
67
|
+
}
|
68
|
+
).to_a.should == [@eastern_event]
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should only return the PT event when searching a 10:00 PT range" do
|
72
|
+
Event.where(
|
73
|
+
"timestamp.time" => {
|
74
|
+
'$gt' => Time.parse(ten_am_pacific) - 1.second,
|
75
|
+
'$lt' => Time.parse(ten_am_pacific) + 1.second
|
76
|
+
}
|
77
|
+
).to_a.should == [@pacific_event]
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "searching by timestamp.normalized" do
|
83
|
+
|
84
|
+
it "should return both events when searching a 10:00 UTC range" do
|
85
|
+
Event.where(
|
86
|
+
"timestamp.normalized" => {
|
87
|
+
'$gt' => Time.parse(ten_am_utc) - 1.second,
|
88
|
+
'$lt' => Time.parse(ten_am_utc) + 1.second
|
89
|
+
}
|
90
|
+
).to_a.should == [@eastern_event, @pacific_event]
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should not return any events when searching a 10:00 ET range" do
|
94
|
+
Event.where(
|
95
|
+
"timestamp.normalized" => {
|
96
|
+
'$gt' => Time.parse(ten_am_eastern) - 1.second,
|
97
|
+
'$lt' => Time.parse(ten_am_eastern) + 1.second
|
98
|
+
}
|
99
|
+
).to_a.should == []
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should not return any events when searching a 10:00 PT range" do
|
103
|
+
Event.where(
|
104
|
+
"timestamp.normalized" => {
|
105
|
+
'$gt' => Time.parse(ten_am_pacific) - 1.second,
|
106
|
+
'$lt' => Time.parse(ten_am_pacific) + 1.second
|
107
|
+
}
|
108
|
+
).to_a.should == []
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "searching by timestamp.year" do
|
114
|
+
|
115
|
+
it "should not return any events for 2010" do
|
116
|
+
Event.where("timestamp.year" => 2010).count.should == 0
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should return both events for 2011" do
|
120
|
+
Event.where("timestamp.year" => 2011).count.should == 2
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
describe "searching by timestamp.month" do
|
126
|
+
|
127
|
+
it "should not return any events when before October" do
|
128
|
+
Event.where("timestamp.month" => {'$lt' => 10}).count.should == 0
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should return both events for October" do
|
132
|
+
Event.where("timestamp.month" => 10).count.should == 2
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "searching by timestamp.day" do
|
138
|
+
|
139
|
+
it "should not return any events when after the 5th" do
|
140
|
+
Event.where("timestamp.day" => {'$gt' => 5}).count.should == 0
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should return both events for the 5th" do
|
144
|
+
Event.where("timestamp.day" => 5).count.should == 2
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "searching by timestamp.wday" do
|
150
|
+
|
151
|
+
it "should not return any events when thurs - tues" do
|
152
|
+
Event.where("timestamp.wday" => {'$gte' => 4, '$lte' => 2}).count.should == 0
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should return both events for wed" do
|
156
|
+
Event.where("timestamp.wday" => 3).count.should == 2
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "searching by timestamp.hour" do
|
162
|
+
|
163
|
+
it "should not return any events when before 10 AM" do
|
164
|
+
Event.where("timestamp.hour" => {'$lt' => 10}).count.should == 0
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should return both events for 10 AM" do
|
168
|
+
Event.where("timestamp.hour" => 10).count.should == 2
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "searching by timestamp.min" do
|
174
|
+
|
175
|
+
it "should not return any events when after 1 minute" do
|
176
|
+
Event.where("timestamp.min" => {'$gte' => 1}).count.should == 0
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should return both events for 0" do
|
180
|
+
Event.where("timestamp.min" => 0).count.should == 2
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
describe "searching by timestamp.sec" do
|
186
|
+
|
187
|
+
it "should not return any events when after 1 second" do
|
188
|
+
Event.where("timestamp.sec" => {'$gte' => 1}).count.should == 0
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should return both events for 0" do
|
192
|
+
Event.where("timestamp.sec" => 0).count.should == 2
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
describe "searching by timestamp.zone" do
|
198
|
+
|
199
|
+
it "should return only the eastern event when searching -04:00" do
|
200
|
+
Event.where("timestamp.zone" => "-04:00").to_a.should == [@eastern_event]
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should return only the pacific event when searching -07:00" do
|
204
|
+
Event.where("timestamp.zone" => "-07:00").to_a.should == [@pacific_event]
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
#encoding: utf-8
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
describe "Mongoid::Metastamp::Time" do
|
6
|
+
|
7
|
+
context "when storing nil" do
|
8
|
+
|
9
|
+
context "on initialization" do
|
10
|
+
|
11
|
+
let :event do
|
12
|
+
Event.new(timestamp: nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "on serialization" do
|
16
|
+
|
17
|
+
it "should store timestamp as nil" do
|
18
|
+
event['timestamp'].should == nil
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "on deserialization" do
|
24
|
+
|
25
|
+
it "timestamp should return nil" do
|
26
|
+
event.timestamp.should == nil
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
context "on creation" do
|
34
|
+
|
35
|
+
let :event do
|
36
|
+
Event.create(timestamp: nil).reload
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "on serialization" do
|
40
|
+
|
41
|
+
it "should store timestamp as nil" do
|
42
|
+
event['timestamp'].should == nil
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "on deserialization" do
|
48
|
+
|
49
|
+
it "timestamp should return nil" do
|
50
|
+
event.timestamp.should == nil
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
[0, 12, 23].each do |hour|
|
60
|
+
|
61
|
+
["+00:00", "-04:00", "-07:00", "+13:00"].each do |zone|
|
62
|
+
|
63
|
+
time_utc = Time.new(2011, 12, 31, hour, 0, 0, '-00:00')
|
64
|
+
time = Time.new(2011, 12, 31, hour, 0, 0, zone)
|
65
|
+
|
66
|
+
context "storing time #{ time }" do
|
67
|
+
|
68
|
+
{
|
69
|
+
"String" => time.to_s,
|
70
|
+
"iso8601" => time.iso8601,
|
71
|
+
"Time" => time
|
72
|
+
}.each do |format, timestamp|
|
73
|
+
|
74
|
+
context "formatted as #{ format } (#{ timestamp })" do
|
75
|
+
|
76
|
+
context "on initialization" do
|
77
|
+
|
78
|
+
let :event do
|
79
|
+
Event.new(timestamp: timestamp)
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "on serialization" do
|
83
|
+
|
84
|
+
it "should store timestamp.time" do
|
85
|
+
event['timestamp']['time'].should == time
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should store timestamp.normalized" do
|
89
|
+
event['timestamp']['normalized'].should == time_utc
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should store timestamp.year as 2011" do
|
93
|
+
event['timestamp']['year'].should == 2011
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should store timestamp.month as 12" do
|
97
|
+
event['timestamp']['month'].should == 12
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should store timestamp.day as 31" do
|
101
|
+
event['timestamp']['day'].should == 31
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should store timestamp.wday as 6 (Saturday)" do
|
105
|
+
event['timestamp']['wday'].should == 6
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should store timestamp.hour as #{ hour }" do
|
109
|
+
event['timestamp']['hour'].should == hour
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should store timestamp.min as 0" do
|
113
|
+
event['timestamp']['min'].should == 0
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should store timestamp.sec as 0" do
|
117
|
+
event['timestamp']['sec'].should == 0
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should store timestamp.zone as #{ zone }" do
|
121
|
+
event['timestamp']['zone'].should == zone
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should store timestamp.offset as #{ (zone.to_i * 60 * 60) }" do
|
125
|
+
event['timestamp']['offset'].should == (zone.to_i * 60 * 60)
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "on deserialization" do
|
131
|
+
|
132
|
+
it "timestamp should return #{ time }" do
|
133
|
+
event.timestamp.should == time
|
134
|
+
end
|
135
|
+
|
136
|
+
it "timestamp should return time in UTC" do
|
137
|
+
event.timestamp.zone.should == "UTC"
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
context "on creation" do
|
145
|
+
|
146
|
+
let :event do
|
147
|
+
Event.create(timestamp: timestamp).reload
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "on serialization" do
|
151
|
+
|
152
|
+
it "should store timestamp.time" do
|
153
|
+
event['timestamp']['time'].should == time
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should store timestamp.normalized" do
|
157
|
+
event['timestamp']['normalized'].should == time_utc
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should store timestamp.year as 2011" do
|
161
|
+
event['timestamp']['year'].should == 2011
|
162
|
+
end
|
163
|
+
|
164
|
+
it "should store timestamp.month as 12" do
|
165
|
+
event['timestamp']['month'].should == 12
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should store timestamp.day as 31" do
|
169
|
+
event['timestamp']['day'].should == 31
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should store timestamp.wday as 6 (Saturday)" do
|
173
|
+
event['timestamp']['wday'].should == 6
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should store timestamp.hour as #{ hour }" do
|
177
|
+
event['timestamp']['hour'].should == hour
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should store timestamp.min as 0" do
|
181
|
+
event['timestamp']['min'].should == 0
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should store timestamp.sec as 0" do
|
185
|
+
event['timestamp']['sec'].should == 0
|
186
|
+
end
|
187
|
+
|
188
|
+
it "should store timestamp.zone as #{ zone }" do
|
189
|
+
event['timestamp']['zone'].should == zone
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should store timestamp.offset as #{ (zone.to_i * 60 * 60) }" do
|
193
|
+
event['timestamp']['offset'].should == (zone.to_i * 60 * 60)
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
describe "on deserialization" do
|
199
|
+
|
200
|
+
it "timestamp should return #{ time }" do
|
201
|
+
event.timestamp.should == time
|
202
|
+
end
|
203
|
+
|
204
|
+
it "timestamp should return time in UTC" do
|
205
|
+
event.timestamp.zone.should == "UTC"
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: mongoid-metastamp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Peter Gumeson
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-10-
|
13
|
+
date: 2011-10-11 00:00:00 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -57,7 +57,7 @@ dependencies:
|
|
57
57
|
version: "2.6"
|
58
58
|
type: :development
|
59
59
|
version_requirements: *id004
|
60
|
-
description: " Provides enhanced meta-timestamps
|
60
|
+
description: " Provides Mongoid with enhanced meta-timestamps that store additional parsed time metadata, allowing more powerful querying on specific time fields and across normalized time zones. "
|
61
61
|
email:
|
62
62
|
- gumeson@gmail.com
|
63
63
|
executables: []
|
@@ -70,6 +70,7 @@ files:
|
|
70
70
|
- .gitignore
|
71
71
|
- .rspec
|
72
72
|
- Gemfile
|
73
|
+
- LICENSE
|
73
74
|
- README.md
|
74
75
|
- Rakefile
|
75
76
|
- lib/mongoid-metastamp.rb
|
@@ -78,9 +79,11 @@ files:
|
|
78
79
|
- lib/mongoid/metastamp/time.rb
|
79
80
|
- lib/mongoid/metastamp/version.rb
|
80
81
|
- mongoid-metastamp.gemspec
|
81
|
-
- spec/metastamp_spec.rb
|
82
82
|
- spec/models/event.rb
|
83
83
|
- spec/spec_helper.rb
|
84
|
+
- spec/time_compatibility_spec.rb
|
85
|
+
- spec/time_search_spec.rb
|
86
|
+
- spec/time_storage_spec.rb
|
84
87
|
has_rdoc: true
|
85
88
|
homepage: http://rubygems.org/gems/mongoid-metastamp
|
86
89
|
licenses: []
|
@@ -108,8 +111,10 @@ rubyforge_project: mongoid-metastamp
|
|
108
111
|
rubygems_version: 1.6.2
|
109
112
|
signing_key:
|
110
113
|
specification_version: 3
|
111
|
-
summary: Store and query more useful information about your Mongoid timestamps
|
114
|
+
summary: Store and query more useful information about your Mongoid timestamps.
|
112
115
|
test_files:
|
113
|
-
- spec/metastamp_spec.rb
|
114
116
|
- spec/models/event.rb
|
115
117
|
- spec/spec_helper.rb
|
118
|
+
- spec/time_compatibility_spec.rb
|
119
|
+
- spec/time_search_spec.rb
|
120
|
+
- spec/time_storage_spec.rb
|
data/spec/metastamp_spec.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
#encoding: utf-8
|
2
|
-
|
3
|
-
require "spec_helper"
|
4
|
-
|
5
|
-
describe Mongoid::Metastamp do
|
6
|
-
|
7
|
-
let :ten_am_utc do
|
8
|
-
"2011-10-05T10:00:00-00:00"
|
9
|
-
end
|
10
|
-
|
11
|
-
let :ten_am_eastern do
|
12
|
-
"2011-10-05T10:00:00-04:00"
|
13
|
-
end
|
14
|
-
|
15
|
-
let :ten_am_pacific do
|
16
|
-
"2011-10-05T10:00:00-07:00"
|
17
|
-
end
|
18
|
-
|
19
|
-
describe "with custom field of type Mongoid::Metastamp::Time" do
|
20
|
-
|
21
|
-
context "named timestamp" do
|
22
|
-
|
23
|
-
context "when set to 10:00 AM PST" do
|
24
|
-
|
25
|
-
let :pst_event do
|
26
|
-
Event.create(timestamp: ten_am_pacific)
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should have a timestamp field" do
|
30
|
-
pst_event.should respond_to(:timestamp)
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should deserialize the timestamp as 10 AM PST" do
|
34
|
-
pst_event.timestamp.should == Time.parse(ten_am_pacific)
|
35
|
-
end
|
36
|
-
|
37
|
-
it "should be searchable by timestamp.in_zone" do
|
38
|
-
Event.where(
|
39
|
-
"timestamp.in_zone" => { '$gt' => Time.parse(ten_am_pacific) - 1.minute },
|
40
|
-
"timestamp.in_zone" => { '$lt' => Time.parse(ten_am_pacific) + 1.minute }
|
41
|
-
).should == [pst_event]
|
42
|
-
end
|
43
|
-
|
44
|
-
it "should be searchable by timestamp.normalized" do
|
45
|
-
Event.where(
|
46
|
-
"timestamp.normalized" => { '$gt' => Time.parse(ten_am_utc) - 1.minute },
|
47
|
-
"timestamp.normalized" => { '$lt' => Time.parse(ten_am_utc) + 1.minute }
|
48
|
-
).should == [pst_event]
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|