temporal_scopes 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +3 -1
- data/lib/temporal_scopes/has_temporal_scopes.rb +102 -15
- data/lib/temporal_scopes/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0bb59fb20ec57703464efa1db45f23340de3450
|
4
|
+
data.tar.gz: baeec6001c3138410bd94561be1339292948b4fb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3936bb8540a87a2f6aff81483a0e6ee5e3fa623466bb5c7c426097342280e74add1ff5b92b66c14c95f99b114d077ebade22b186b106ff7d27560c7c7cdc4c51
|
7
|
+
data.tar.gz: ff2003aff6d0c39d4a0fef33490dc95e73da1d2a062596b60ba6fb74e9d3c8f9c597626f2c10c457b2bf9efaee8711848c35ebb5454433b5542e8c1a312796d3
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# TemporalScopes [![Build Status](https://travis-ci.org/fiedl/temporal_scopes.svg?branch=master)](https://travis-ci.org/fiedl/temporal_scopes)
|
1
|
+
# TemporalScopes [![Build Status](https://travis-ci.org/fiedl/temporal_scopes.svg?branch=master)](https://travis-ci.org/fiedl/temporal_scopes) [![Gem Version](https://badge.fury.io/rb/temporal_scopes.svg)](http://badge.fury.io/rb/temporal_scopes)
|
2
2
|
|
3
3
|
Providing temporal scopes for an ActiveRecord model to allow queries by time. For example, `MyModel.now.where(...)`, `my_model.archive`, `MyModel.past.where(...)`.
|
4
4
|
|
@@ -50,7 +50,9 @@ Further [documentation can be found on rubydoc.info](http://rubydoc.info/github/
|
|
50
50
|
|
51
51
|
### Caveats
|
52
52
|
|
53
|
+
* This gem requires Rails 4.
|
53
54
|
* There is only one `valid_from` and one `valid_to` time per object. Therefore, you can't keep track of first archiving an object and later un-archiving it. Un-archiving an object loses the information of first archiving it.
|
55
|
+
* Currently, the future is not handled (`Article.future` and `article.archive at: 1.hour.from.now` do not work.) But this is planned to be implemented in the future.
|
54
56
|
|
55
57
|
## Installation
|
56
58
|
|
@@ -3,38 +3,125 @@ require 'active_record'
|
|
3
3
|
module TemporalScopes
|
4
4
|
module HasTemporalScopes
|
5
5
|
|
6
|
+
# Adds scopes and methods for handing temporal filtering.
|
7
|
+
#
|
8
|
+
# ## Make an `ActiveRecord` have temporal scopes
|
9
|
+
#
|
10
|
+
# class Article < ActiveRecord::Base
|
11
|
+
# has_temporal_scopes
|
12
|
+
#
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# ## Archive an object
|
16
|
+
#
|
17
|
+
# current_article = Article.create(title: 'My new article', body: 'Lorem ipsum')
|
18
|
+
#
|
19
|
+
# past_article = Article.create(title: 'My new article', body: 'Lorem ipsum')
|
20
|
+
# past_article.archive
|
21
|
+
#
|
22
|
+
# # or provide a datetime:
|
23
|
+
# past_article.archive at: 1.hour.ago
|
24
|
+
#
|
25
|
+
# ## Use temporal scopes for filtering
|
26
|
+
#
|
27
|
+
# Article.now # => [current_article]
|
28
|
+
# Article.past # => [past_article]
|
29
|
+
# Article.with_past # => [current_article, past_article]
|
30
|
+
#
|
31
|
+
# Note that the **default scope** is set to `now`.
|
32
|
+
#
|
33
|
+
# Article.all # => [current_article]
|
34
|
+
# Article.now # => [current_article]
|
35
|
+
# Article.with_past # => [current_article, past_article]
|
36
|
+
# Article.without_temporal_condition # => [current_article, past_article]
|
37
|
+
#
|
6
38
|
def has_temporal_scopes
|
7
39
|
|
8
|
-
scope :without_temporal_condition, -> {
|
9
|
-
relation = unscope(where: [:valid_from, :valid_to])
|
10
|
-
relation.where_values.delete_if { |query| query.to_sql.include?("\"valid_from\"") || query.to_sql.include?("\"valid_to\"") }
|
11
|
-
relation
|
12
|
-
}
|
13
|
-
|
14
|
-
scope :now, -> {
|
15
|
-
without_temporal_condition
|
16
|
-
.where(arel_table[:valid_from].eq(nil).or(arel_table[:valid_from].lteq(Time.zone.now)))
|
17
|
-
.where(arel_table[:valid_to].eq(nil).or(arel_table[:valid_to].gteq(Time.zone.now)))
|
18
|
-
}
|
19
|
-
scope :past, -> { without_temporal_condition.where('valid_to < ?', Time.zone.now) }
|
20
|
-
scope :with_past, -> { without_temporal_condition }
|
21
|
-
|
22
40
|
default_scope { now }
|
23
41
|
|
24
42
|
extend ClassMethods
|
25
43
|
include InstanceMethods
|
26
44
|
end
|
27
45
|
|
46
|
+
# The following class methods and scopes are added to
|
47
|
+
# `ActiveRecord::Base` classes that have been called
|
48
|
+
# `has_temporal_scopes` on.
|
49
|
+
#
|
28
50
|
module ClassMethods
|
51
|
+
|
52
|
+
# Removes temporal conditions from the query.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# Article.where(valid_to: 10.days.ago..1.day.ago) # => [] (due to default scope.)
|
56
|
+
# Article.without_temporal_condition.where(valid_to: 10.days.ago..1.day.ago) # returns the desired articles.
|
57
|
+
#
|
58
|
+
# @return [ActiveRecord::Relation] the relation without temporal conditions on `valid_from` and `valid_to`.
|
59
|
+
#
|
60
|
+
def without_temporal_condition
|
61
|
+
relation = unscope(where: [:valid_from, :valid_to])
|
62
|
+
relation.where_values.delete_if { |query| query.to_sql.include?("\"valid_from\"") || query.to_sql.include?("\"valid_to\"") } if relation && relation.where_values
|
63
|
+
relation
|
64
|
+
end
|
65
|
+
|
66
|
+
# Filters for only current objects.
|
67
|
+
#
|
68
|
+
# This is the default scope.
|
69
|
+
#
|
70
|
+
# @return [ActiveRecord::Relation] only current objects.
|
71
|
+
#
|
72
|
+
def now
|
73
|
+
without_temporal_condition
|
74
|
+
.where(arel_table[:valid_from].eq(nil).or(arel_table[:valid_from].lteq(Time.zone.now)))
|
75
|
+
.where(arel_table[:valid_to].eq(nil).or(arel_table[:valid_to].gteq(Time.zone.now)))
|
76
|
+
end
|
77
|
+
|
78
|
+
# Filters for only past objects.
|
79
|
+
#
|
80
|
+
# @return [ActiveRecord::Relation] only past objects.
|
81
|
+
#
|
82
|
+
# @example Getting only archived articles by an author.
|
83
|
+
# author.articles.past
|
84
|
+
#
|
85
|
+
def past
|
86
|
+
without_temporal_condition.where('valid_to < ?', Time.zone.now)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Removes the filters such that past and present
|
90
|
+
# objects are returned.
|
91
|
+
#
|
92
|
+
# @return [ActiveRecord::Relation] past and current objects.
|
93
|
+
#
|
94
|
+
def with_past
|
95
|
+
without_temporal_condition
|
96
|
+
end
|
97
|
+
|
29
98
|
end
|
30
|
-
|
99
|
+
|
100
|
+
# The following instance methods are added to
|
101
|
+
# `ActiveRecord::Base` objects, which classes have
|
102
|
+
# been called `has_temporal_scopes` on.
|
103
|
+
#
|
31
104
|
module InstanceMethods
|
32
105
|
|
106
|
+
# Archives an object, that is, makes it a past object.
|
107
|
+
#
|
108
|
+
# @param params [Hash] a hash of parameters.
|
109
|
+
# @option params :at [DateTime] (Time.zonw.now) when to archive the object, i.e. the time when the present object becomes a past object, i.e. expires.
|
110
|
+
#
|
111
|
+
# @return [ActiveRecord::Base] the archived object.
|
112
|
+
#
|
113
|
+
# @example Archiving an object now.
|
114
|
+
# article.archive
|
115
|
+
#
|
116
|
+
# @example Archiving an object with effect 4 hours ago.
|
117
|
+
# article.archive at: 4.hours.ago
|
118
|
+
#
|
33
119
|
def archive(params = {})
|
34
120
|
unless self.valid_to
|
35
121
|
archive_at = params[:at] || Time.zone.now
|
36
122
|
update_attribute(:valid_to, archive_at)
|
37
123
|
end
|
124
|
+
return self
|
38
125
|
end
|
39
126
|
|
40
127
|
end
|