mongoid_occurrences 1.0.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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +19 -0
- data/CHANGELOG.md +17 -0
- data/Gemfile +11 -0
- data/Guardfile +5 -0
- data/README.md +147 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/mongoid_occurrences/aggregations/aggregation.rb +51 -0
- data/lib/mongoid_occurrences/aggregations/occurs_between.rb +33 -0
- data/lib/mongoid_occurrences/aggregations/occurs_from.rb +32 -0
- data/lib/mongoid_occurrences/aggregations/occurs_on.rb +32 -0
- data/lib/mongoid_occurrences/aggregations/occurs_until.rb +32 -0
- data/lib/mongoid_occurrences/daily_occurrence/has_scopes.rb +12 -0
- data/lib/mongoid_occurrences/daily_occurrence.rb +42 -0
- data/lib/mongoid_occurrences/has_fields_from_aggregation.rb +25 -0
- data/lib/mongoid_occurrences/has_occurrences.rb +51 -0
- data/lib/mongoid_occurrences/occurrence/has_daily_occurrences.rb +46 -0
- data/lib/mongoid_occurrences/occurrence/has_operators.rb +20 -0
- data/lib/mongoid_occurrences/occurrence/has_schedule.rb +54 -0
- data/lib/mongoid_occurrences/occurrence.rb +53 -0
- data/lib/mongoid_occurrences/queries/occurs_between.rb +34 -0
- data/lib/mongoid_occurrences/queries/occurs_from.rb +27 -0
- data/lib/mongoid_occurrences/queries/occurs_on.rb +29 -0
- data/lib/mongoid_occurrences/queries/occurs_until.rb +27 -0
- data/lib/mongoid_occurrences/queries/query.rb +27 -0
- data/lib/mongoid_occurrences/version.rb +3 -0
- data/lib/mongoid_occurrences.rb +19 -0
- data/mongoid_occurrences.gemspec +37 -0
- metadata +278 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b3eb3d953d69a2671b169b5871a250971b33c948b5d0d9d6a9ada698eb7bfed7
|
4
|
+
data.tar.gz: 0317f7a065c2dabbed6a4febd03e5920850d3b554044d3e2cc04fdf406c69987
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 506b446a5afc98f7308d89b4e64fb756c3ce3264243a6620daebd5f1e92d2df85c3d9ae3de0255529d623ebe7340be7e99fbffbe197d635299545015daaec0a5
|
7
|
+
data.tar.gz: 61ee2fe086a87f5e7f57e4edf7f34032a9fa62e75f94fd642b78201ded701870aab0c4d38590f384ab6a0eecaed8befff2f0e6f84bbabd7f3cb81b5d4af5c0f4
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
language: ruby
|
2
|
+
cache: bundler
|
3
|
+
script: 'bundle exec rake'
|
4
|
+
rvm:
|
5
|
+
- 2.5.1
|
6
|
+
services:
|
7
|
+
- mongodb
|
8
|
+
|
9
|
+
notifications:
|
10
|
+
email:
|
11
|
+
recipients:
|
12
|
+
- tomas.celizna@gmail.com
|
13
|
+
on_failure: change
|
14
|
+
on_success: never
|
15
|
+
|
16
|
+
matrix:
|
17
|
+
include:
|
18
|
+
- rvm: 2.5.1
|
19
|
+
env: MONGOID_VERSION=7
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# CHANGELOG
|
2
|
+
|
3
|
+
## 1.0.0
|
4
|
+
|
5
|
+
* [PR#4](https://github.com/tomasc/mongoid_occurrences/pull/4) Refactor to replace views with aggregations
|
6
|
+
|
7
|
+
## 0.2.0
|
8
|
+
|
9
|
+
* [PR#3](https://github.com/tomasc/mongoid_occurrences/pull/3) `all_day` becomes a field
|
10
|
+
|
11
|
+
## 0.1.1
|
12
|
+
|
13
|
+
* [PR#2](https://github.com/tomasc/mongoid_occurrences/pull/2) allow :assign_daily_occurrences to be triggerred manually
|
14
|
+
|
15
|
+
## 0.1.0
|
16
|
+
|
17
|
+
* initial release
|
data/Gemfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in mongoid_occurrences.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
case version = ENV['MONGOID_VERSION'] || '~> 7.0'
|
9
|
+
when /7/ then gem 'mongoid', '~> 7.0'
|
10
|
+
else gem 'mongoid', version
|
11
|
+
end
|
data/Guardfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
# Mongoid Occurrences
|
2
|
+
|
3
|
+
[](https://travis-ci.org/tomasc/mongoid_occurrences) [](http://badge.fury.io/rb/mongoid_occurrences) [](https://coveralls.io/r/tomasc/mongoid_occurrences)
|
4
|
+
|
5
|
+
Facilitates aggregations for events with multiple occurrences or a recurring schedule.
|
6
|
+
|
7
|
+
## Requirements
|
8
|
+
|
9
|
+
* Mongoid 7+
|
10
|
+
* MongoDB 3.4+
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
Add this line to your application's Gemfile:
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
gem 'mongoid_occurrences'
|
18
|
+
```
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
$ bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
$ gem install mongoid_occurrences
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
### Event
|
31
|
+
|
32
|
+
Define a Mongoid document that will embed occurrence definitions.
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
class Event
|
36
|
+
include Mongoid::Document
|
37
|
+
include MongoidOccurrences::HasOccurrences
|
38
|
+
|
39
|
+
embeds_many_occurrences class_name: "Occurrence"
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
43
|
+
This document will gain the `#assign_daily_occurrences!` method (automatically triggered `:after_validation`), which expands all occurrence definitions in the embedded relation called `#daily_occurrences`.
|
44
|
+
|
45
|
+
The class will also gain the following scopes, useful for querying for events based on the `#daily_occurrences`:
|
46
|
+
|
47
|
+
* `.occurs_between(dtstart, dtend)`
|
48
|
+
* `.occurs_from(dtstart)`
|
49
|
+
* `.occurs_on(day)`
|
50
|
+
* `.occurs_until(dtend)`
|
51
|
+
|
52
|
+
### Occurrence
|
53
|
+
|
54
|
+
Define a Mongoid document that defines the occurrence.
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
class Occurrence
|
58
|
+
include Mongoid::Document
|
59
|
+
include MongoidOccurrences::Occurrence
|
60
|
+
|
61
|
+
embedded_in_event class_name: 'Event'
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
This document will gain the `#dtstart`, `#dtend` and `#all_day` fields to define individual occurrences.
|
66
|
+
|
67
|
+
Recurring schedule is handled via the [IceCube](https://github.com/seejohnrun/ice_cube) and [MongoidIceCubeExtension](https://github.com/tomasc/mongoid_ice_cube_extension) gems. The model gains `#schedule`, and `#schedule_dtstart`, `#schedule_dtend` fields (with default values for schedule 1 year from now), along with `#recurrence_rule=` writer method.
|
68
|
+
|
69
|
+
It is possible to influence the way the occurrences are expanded into `#daily_occurrences` using the `#operator` enum field, which accepts the following values:
|
70
|
+
|
71
|
+
* `:append` – appends to the list of `#daily_occurrences` (default)
|
72
|
+
* `:replace` – replaces all occurrences that happen on the same day with itself
|
73
|
+
* `:remove` - removes all occurrences that happen on the same day
|
74
|
+
|
75
|
+
### Indexes
|
76
|
+
|
77
|
+
To optimize the performance of the above scope queries, you might want to add the following indexes:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
index :'daily_occurrences.ds' => 1
|
81
|
+
index :'daily_occurrences.de' => 1
|
82
|
+
```
|
83
|
+
|
84
|
+
### Aggregations
|
85
|
+
|
86
|
+
It is possible to aggregate (unwind) the events so that they are multiplied per daily occurrences. Example aggregations are included:
|
87
|
+
|
88
|
+
* `MongoidOccurrences::Aggregations::OccursBetween.instantiate(Event.criteria, dtstart, dtend)`
|
89
|
+
* `MongoidOccurrences::Aggregations::OccursFrom.instantiate(Event.criteria, dtstart)`
|
90
|
+
* `MongoidOccurrences::Aggregations::OccursOn.instantiate(Event.criteria, day)`
|
91
|
+
* `MongoidOccurrences::Aggregations::OccursUntil.instantiate(Event.criteria, dtend)`
|
92
|
+
|
93
|
+
The aggregations will add `#_dtstart`, `#_dtend` fields to the unwound documents. For easier access, mixin the `MongoidOccurrences::HasFieldsFromAggregation` to your `Event` class:
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
class Event
|
97
|
+
include Mongoid::Document
|
98
|
+
include MongoidOccurrences::HasFieldsFromAggregation
|
99
|
+
include MongoidOccurrences::HasOccurrences
|
100
|
+
|
101
|
+
embeds_many_occurrences class_name: "Occurrence"
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
This will automatically add `#dtstart` and `#dtend` fields with correct (demongoized) values, as well as the `#all_day?` method.
|
106
|
+
|
107
|
+
### Embedded events
|
108
|
+
|
109
|
+
If your events are itself embedded:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
class EventParent
|
113
|
+
embeds_many :events, class_name: 'Event'
|
114
|
+
end
|
115
|
+
```
|
116
|
+
|
117
|
+
Simply add the following scopes on the parent document:
|
118
|
+
|
119
|
+
```ruby
|
120
|
+
class EventParent
|
121
|
+
scope :occurs_between, ->(dtstart, dtend) { elem_match(events: Event.occurs_between(dtstart, dtend).selector) }
|
122
|
+
scope :occurs_from, ->(date_time) { elem_match(events: Event.occurs_from(date_time).selector) }
|
123
|
+
scope :occurs_on, ->(date_time) { elem_match(events: Event.occurs_on(date_time).selector) }
|
124
|
+
scope :occurs_until, ->(date_time) { elem_match(events: Event.occurs_until(date_time).selector) }
|
125
|
+
end
|
126
|
+
```
|
127
|
+
|
128
|
+
You will then need to write your own aggregations with an extra step to `$unwind` the embedded `#events`, and your indexes will need to be adjusted as follows:
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
index :'events.daily_occurrences.ds' => 1
|
132
|
+
index :'events.daily_occurrences.de' => 1
|
133
|
+
```
|
134
|
+
|
135
|
+
## Development
|
136
|
+
|
137
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
138
|
+
|
139
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
140
|
+
|
141
|
+
## Contributing
|
142
|
+
|
143
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/tomasc/mongoid_occurrences.
|
144
|
+
|
145
|
+
## License
|
146
|
+
|
147
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "mongoid_occurrences"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module MongoidOccurrences
|
2
|
+
module Aggregations
|
3
|
+
class Aggregation
|
4
|
+
def self.option(name, default_value=nil)
|
5
|
+
define_method(name) do
|
6
|
+
HashWithIndifferentAccess[options].fetch(name, default_value)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.instantiate(*args)
|
11
|
+
new(*args).instantiate
|
12
|
+
end
|
13
|
+
|
14
|
+
option :allow_disk_use, true
|
15
|
+
option :sort_key, :_dtstart
|
16
|
+
option :sort_order, :asc
|
17
|
+
|
18
|
+
def initialize(base_criteria, options = {})
|
19
|
+
@base_criteria = base_criteria
|
20
|
+
@options = options
|
21
|
+
end
|
22
|
+
|
23
|
+
def aggregation
|
24
|
+
base_criteria.klass
|
25
|
+
.collection
|
26
|
+
.aggregate(
|
27
|
+
(selectors + pipeline),
|
28
|
+
allow_disk_use: allow_disk_use
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def instantiate
|
33
|
+
aggregation.map do |doc|
|
34
|
+
base_criteria.klass.instantiate(doc)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def selectors
|
41
|
+
[
|
42
|
+
{ '$match' => { '$and' => [criteria.selector] } },
|
43
|
+
{ '$sort' => criteria.options[:sort] },
|
44
|
+
{ '$limit' => criteria.options[:limit] }
|
45
|
+
].map { |i| i.delete_if { |_, v| v.blank? } }.reject(&:blank?)
|
46
|
+
end
|
47
|
+
|
48
|
+
attr_reader :base_criteria, :options
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'mongoid_occurrences/aggregations/aggregation'
|
2
|
+
|
3
|
+
module MongoidOccurrences
|
4
|
+
module Aggregations
|
5
|
+
class OccursBetween < Aggregation
|
6
|
+
def initialize(base_criteria, dtstart, dtend, options = {})
|
7
|
+
@base_criteria = base_criteria
|
8
|
+
@dtstart = dtstart
|
9
|
+
@dtend = dtend
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def criteria
|
16
|
+
base_criteria.occurs_between(dtstart, dtend)
|
17
|
+
end
|
18
|
+
|
19
|
+
def pipeline
|
20
|
+
[
|
21
|
+
{ '$addFields' => { '_daily_occurrences' => '$daily_occurrences' } },
|
22
|
+
{ '$unwind' => { 'path' => '$_daily_occurrences' } },
|
23
|
+
{ '$addFields' => { '_dtstart' => '$_daily_occurrences.ds', '_dtend' => '$_daily_occurrences.de' } },
|
24
|
+
{ '$project' => { '_daily_occurrences' => 0 } },
|
25
|
+
{ '$match' => Queries::OccursBetween.criteria(base_criteria, dtstart, dtend, dtstart_field: '_dtstart', dtend_field: '_dtend').selector },
|
26
|
+
{ '$sort' => { sort_key => { asc: 1, desc: -1 }[sort_order] } }
|
27
|
+
]
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_reader :dtstart, :dtend, :options
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'mongoid_occurrences/aggregations/aggregation'
|
2
|
+
|
3
|
+
module MongoidOccurrences
|
4
|
+
module Aggregations
|
5
|
+
class OccursFrom < Aggregation
|
6
|
+
def initialize(base_criteria, date_time, options = {})
|
7
|
+
@base_criteria = base_criteria
|
8
|
+
@date_time = date_time
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def criteria
|
15
|
+
base_criteria.occurs_from(date_time)
|
16
|
+
end
|
17
|
+
|
18
|
+
def pipeline
|
19
|
+
[
|
20
|
+
{ '$addFields' => { '_daily_occurrences' => '$daily_occurrences' } },
|
21
|
+
{ '$unwind' => { 'path' => '$_daily_occurrences' } },
|
22
|
+
{ '$addFields' => { '_dtstart' => '$_daily_occurrences.ds', '_dtend' => '$_daily_occurrences.de' } },
|
23
|
+
{ '$project' => { '_daily_occurrences' => 0 } },
|
24
|
+
{ '$match' => Queries::OccursFrom.criteria(base_criteria, date_time, dtstart_field: '_dtstart').selector },
|
25
|
+
{ '$sort' => { sort_key => { asc: 1, desc: -1 }[sort_order] } }
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :date_time, :options
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'mongoid_occurrences/aggregations/aggregation'
|
2
|
+
|
3
|
+
module MongoidOccurrences
|
4
|
+
module Aggregations
|
5
|
+
class OccursOn < Aggregation
|
6
|
+
def initialize(base_criteria, date_time, options = {})
|
7
|
+
@base_criteria = base_criteria
|
8
|
+
@date_time = date_time
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def criteria
|
15
|
+
base_criteria.occurs_on(date_time)
|
16
|
+
end
|
17
|
+
|
18
|
+
def pipeline
|
19
|
+
[
|
20
|
+
{ '$addFields' => { '_daily_occurrences' => '$daily_occurrences' } },
|
21
|
+
{ '$unwind' => { 'path' => '$_daily_occurrences' } },
|
22
|
+
{ '$addFields' => { '_dtstart' => '$_daily_occurrences.ds', '_dtend' => '$_daily_occurrences.de' } },
|
23
|
+
{ '$project' => { '_daily_occurrences' => 0 } },
|
24
|
+
{ '$match' => Queries::OccursOn.criteria(base_criteria, date_time, dtstart_field: '_dtstart', dtend_field: '_dtend').selector },
|
25
|
+
{ '$sort' => { sort_key => { asc: 1, desc: -1 }[sort_order] } }
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :date_time, :options
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'mongoid_occurrences/aggregations/aggregation'
|
2
|
+
|
3
|
+
module MongoidOccurrences
|
4
|
+
module Aggregations
|
5
|
+
class OccursUntil < Aggregation
|
6
|
+
def initialize(base_criteria, date_time, options = {})
|
7
|
+
@base_criteria = base_criteria
|
8
|
+
@date_time = date_time
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def criteria
|
15
|
+
base_criteria.occurs_until(date_time)
|
16
|
+
end
|
17
|
+
|
18
|
+
def pipeline
|
19
|
+
[
|
20
|
+
{ '$addFields' => { '_daily_occurrences' => '$daily_occurrences' } },
|
21
|
+
{ '$unwind' => { 'path' => '$_daily_occurrences' } },
|
22
|
+
{ '$addFields' => { '_dtstart' => '$_daily_occurrences.ds', '_dtend' => '$_daily_occurrences.de' } },
|
23
|
+
{ '$project' => { '_daily_occurrences' => 0 } },
|
24
|
+
{ '$match' => Queries::OccursUntil.criteria(base_criteria, date_time, dtend_field: '_dtend').selector },
|
25
|
+
{ '$sort' => { sort_key => { asc: 1, desc: -1 }[sort_order] } }
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :date_time, :options
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module MongoidOccurrences
|
2
|
+
class DailyOccurrence
|
3
|
+
module HasScopes
|
4
|
+
def self.included(base)
|
5
|
+
base.scope :occurs_between, ->(dtstart, dtend) { Queries::OccursBetween.criteria(criteria, dtstart, dtend) }
|
6
|
+
base.scope :occurs_from, ->(dtstart) { Queries::OccursFrom.criteria(criteria, dtstart) }
|
7
|
+
base.scope :occurs_on, ->(day) { Queries::OccursOn.criteria(criteria, day) }
|
8
|
+
base.scope :occurs_until, ->(dtend) { Queries::OccursUntil.criteria(criteria, dtend) }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'mongoid_occurrences/daily_occurrence/has_scopes'
|
2
|
+
|
3
|
+
module MongoidOccurrences
|
4
|
+
class DailyOccurrence
|
5
|
+
include Mongoid::Document
|
6
|
+
include HasScopes
|
7
|
+
|
8
|
+
attr_accessor :operator
|
9
|
+
|
10
|
+
field :ds, as: :dtstart, type: DateTime
|
11
|
+
field :de, as: :dtend, type: DateTime
|
12
|
+
|
13
|
+
validates :dtstart, presence: true
|
14
|
+
validates :dtend, presence: true
|
15
|
+
|
16
|
+
def operator
|
17
|
+
@operator ||= :append
|
18
|
+
end
|
19
|
+
|
20
|
+
def all_day
|
21
|
+
dtstart.to_i == dtstart.beginning_of_day.to_i &&
|
22
|
+
dtend.to_i == dtend.end_of_day.to_i
|
23
|
+
end
|
24
|
+
alias all_day? all_day
|
25
|
+
|
26
|
+
def <=>(other)
|
27
|
+
sort_key <=> other.sort_key
|
28
|
+
end
|
29
|
+
|
30
|
+
def sort_key
|
31
|
+
[dtstart, dtend]
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_range
|
35
|
+
(dtstart..dtend)
|
36
|
+
end
|
37
|
+
|
38
|
+
def overlaps?(occurrence)
|
39
|
+
to_range.overlaps?(occurrence.to_range)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module MongoidOccurrences
|
2
|
+
module HasFieldsFromAggregation
|
3
|
+
def dtstart
|
4
|
+
@dtstart ||= DateTime.demongoize(
|
5
|
+
self['_dtstart'] ||
|
6
|
+
daily_occurrences.unscoped.order(dtstart: :asc).limit(1).pluck(:dtstart).first
|
7
|
+
)
|
8
|
+
end
|
9
|
+
|
10
|
+
def dtend
|
11
|
+
@dtend ||= DateTime.demongoize(
|
12
|
+
self['_dtend'] ||
|
13
|
+
daily_occurrences.unscoped.order(dtend: :desc).limit(1).pluck(:dtend).first
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def all_day
|
18
|
+
return unless dtstart && dtend
|
19
|
+
|
20
|
+
dtstart.to_i == dtstart.beginning_of_day.to_i &&
|
21
|
+
dtend.to_i == dtend.end_of_day.to_i
|
22
|
+
end
|
23
|
+
alias all_day? all_day
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module MongoidOccurrences
|
2
|
+
module HasOccurrences
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def embeds_many_occurrences(options = {})
|
9
|
+
field :_previous_occurences_cache_key, type: String
|
10
|
+
|
11
|
+
embeds_many :occurrences, class_name: options.fetch(:class_name)
|
12
|
+
accepts_nested_attributes_for :occurrences, allow_destroy: true, reject_if: :all_blank
|
13
|
+
|
14
|
+
embeds_many :daily_occurrences, class_name: 'MongoidOccurrences::DailyOccurrence', order: :dtstart.asc
|
15
|
+
|
16
|
+
after_validation :assign_occurrences_cache_key!
|
17
|
+
after_validation :assign_daily_occurrences!, if: :_previous_occurences_cache_key_changed?
|
18
|
+
|
19
|
+
scope :occurs_between, ->(dtstart, dtend) { elem_match(daily_occurrences: DailyOccurrence.occurs_between(dtstart, dtend).selector) }
|
20
|
+
scope :occurs_from, ->(dtstart) { elem_match(daily_occurrences: DailyOccurrence.occurs_from(dtstart).selector) }
|
21
|
+
scope :occurs_on, ->(day) { elem_match(daily_occurrences: DailyOccurrence.occurs_on(day).selector) }
|
22
|
+
scope :occurs_until, ->(dtend) { elem_match(daily_occurrences: DailyOccurrence.occurs_until(dtend).selector) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def occurences_cache_key
|
27
|
+
last_timestamp = occurrences.unscoped.order(updated_at: :desc).limit(1).pluck(:updated_at).first
|
28
|
+
"#{occurrences.unscoped.size}-#{last_timestamp.to_i}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def assign_daily_occurrences!
|
32
|
+
self.daily_occurrences = begin
|
33
|
+
res = occurrences.with_operators(:append).flat_map(&:daily_occurrences)
|
34
|
+
|
35
|
+
occurrences.with_operators(%i[remove replace]).flat_map(&:daily_occurrences).each do |occurrence|
|
36
|
+
res = res.reject { |res_occurrence| res_occurrence.overlaps?(occurrence) }
|
37
|
+
end
|
38
|
+
|
39
|
+
res += occurrences.with_operators(%i[replace]).flat_map(&:daily_occurrences)
|
40
|
+
|
41
|
+
res.sort
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def assign_occurrences_cache_key!
|
48
|
+
self._previous_occurences_cache_key = occurences_cache_key
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module MongoidOccurrences
|
2
|
+
module Occurrence
|
3
|
+
module HasDailyOccurrences
|
4
|
+
def daily_occurrences
|
5
|
+
adjust_dates_for_all_day!
|
6
|
+
|
7
|
+
daily_occurrences_from_schedule +
|
8
|
+
daily_occurrences_from_date_range
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def daily_occurrences_from_schedule
|
14
|
+
return [] unless dtstart? && dtend?
|
15
|
+
return [] unless recurring?
|
16
|
+
|
17
|
+
schedule.occurrences(schedule_dtend).map do |occurrence|
|
18
|
+
MongoidOccurrences::DailyOccurrence.new(
|
19
|
+
dtstart: occurrence.start_time.change(hour: dtstart.hour, min: dtstart.minute),
|
20
|
+
dtend: occurrence.end_time.change(hour: dtend.hour, min: dtend.minute),
|
21
|
+
operator: operator
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def daily_occurrences_from_date_range
|
27
|
+
return [] unless dtstart? && dtend?
|
28
|
+
return [] if recurring?
|
29
|
+
|
30
|
+
date_range = Range.new(dtstart.to_date, dtend.to_date)
|
31
|
+
is_single_day = (date_range.first == date_range.last)
|
32
|
+
|
33
|
+
date_range.map do |date|
|
34
|
+
occurence_dtstart = is_single_day || date == date_range.first ? dtstart : date.beginning_of_day
|
35
|
+
occurence_dtend = is_single_day || date == date_range.last ? dtend : date.end_of_day
|
36
|
+
|
37
|
+
MongoidOccurrences::DailyOccurrence.new(
|
38
|
+
dtstart: occurence_dtstart,
|
39
|
+
dtend: occurence_dtend,
|
40
|
+
operator: operator
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'mongoid/enum_attribute'
|
2
|
+
|
3
|
+
module MongoidOccurrences
|
4
|
+
module Occurrence
|
5
|
+
module HasOperators
|
6
|
+
def self.prepended(base)
|
7
|
+
base.scope :with_operators, ->(operators) { criteria.in(_operator: Array(operators)) }
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def embedded_in_event(options = {})
|
12
|
+
super(options)
|
13
|
+
|
14
|
+
include Mongoid::EnumAttribute
|
15
|
+
enum :operator, %i[append replace remove], default: :append
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module MongoidOccurrences
|
2
|
+
module Occurrence
|
3
|
+
module HasSchedule
|
4
|
+
SCHEDULE_DURATION = 1.year
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def embedded_in_event(options = {})
|
8
|
+
super(options)
|
9
|
+
|
10
|
+
field :schedule, type: MongoidIceCubeExtension::Schedule
|
11
|
+
field :schedule_dtstart, type: Time
|
12
|
+
field :schedule_dtend, type: Time
|
13
|
+
|
14
|
+
before_validation :nil_schedule, unless: :recurring?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def schedule_dtstart
|
19
|
+
read_attribute(:schedule_dtstart) ||
|
20
|
+
(dtstart.try(:to_time) || Time.now)
|
21
|
+
end
|
22
|
+
|
23
|
+
def schedule_dtend
|
24
|
+
read_attribute(:schedule_dtend) ||
|
25
|
+
(schedule_dtstart + SCHEDULE_DURATION)
|
26
|
+
end
|
27
|
+
|
28
|
+
def recurrence_rule
|
29
|
+
schedule&.recurrence_rules&.first
|
30
|
+
end
|
31
|
+
|
32
|
+
def recurrence_rule=(value)
|
33
|
+
case value
|
34
|
+
when NilClass, 'null'
|
35
|
+
@recurrence_rule = nil
|
36
|
+
self.schedule = nil
|
37
|
+
else
|
38
|
+
@recurrence_rule = IceCube::Rule.from_hash(JSON.parse(value))
|
39
|
+
self.schedule = IceCube::Schedule.new(schedule_dtstart) { |s| s.add_recurrence_rule(@recurrence_rule) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def recurring?
|
44
|
+
schedule.present?
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def nil_schedule
|
50
|
+
self.schedule = nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'mongoid_occurrences/occurrence/has_daily_occurrences'
|
2
|
+
require 'mongoid_occurrences/occurrence/has_operators'
|
3
|
+
require 'mongoid_occurrences/occurrence/has_schedule'
|
4
|
+
|
5
|
+
module MongoidOccurrences
|
6
|
+
module Occurrence
|
7
|
+
def self.included(base)
|
8
|
+
base.extend ClassMethods
|
9
|
+
|
10
|
+
base.include Mongoid::Timestamps::Updated
|
11
|
+
|
12
|
+
base.include HasDailyOccurrences
|
13
|
+
|
14
|
+
base.prepend HasOperators
|
15
|
+
base.singleton_class.prepend HasOperators::ClassMethods
|
16
|
+
|
17
|
+
base.prepend HasSchedule
|
18
|
+
base.singleton_class.prepend HasSchedule::ClassMethods
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
def embedded_in_event(options = {})
|
23
|
+
field :dtstart, type: DateTime
|
24
|
+
field :dtend, type: DateTime
|
25
|
+
field :all_day, type: Boolean
|
26
|
+
|
27
|
+
embedded_in :event, class_name: options.fetch(:class_name, nil), inverse_of: :occurrences
|
28
|
+
|
29
|
+
after_validation :adjust_dates_for_all_day!, if: :changed?
|
30
|
+
|
31
|
+
validates :dtstart, presence: true
|
32
|
+
validates :dtend, presence: true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def all_day
|
37
|
+
return super unless dtstart.present? && dtend.present?
|
38
|
+
return super unless super.nil?
|
39
|
+
|
40
|
+
dtstart.to_i == dtstart.beginning_of_day.to_i &&
|
41
|
+
dtend.to_i == dtend.end_of_day.to_i
|
42
|
+
end
|
43
|
+
alias all_day? all_day
|
44
|
+
|
45
|
+
def adjust_dates_for_all_day!
|
46
|
+
return unless all_day?
|
47
|
+
return unless dtstart? && dtend?
|
48
|
+
|
49
|
+
self.dtstart = dtstart.beginning_of_day
|
50
|
+
self.dtend = dtend.end_of_day
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'mongoid_occurrences/queries/query'
|
2
|
+
|
3
|
+
module MongoidOccurrences
|
4
|
+
module Queries
|
5
|
+
class OccursBetween < Query
|
6
|
+
option :dtstart_field, :dtstart
|
7
|
+
option :dtend_field, :dtend
|
8
|
+
|
9
|
+
def initialize(base_criteria, dtstart, dtend, options = {})
|
10
|
+
@base_criteria = base_criteria
|
11
|
+
@dtstart = dtstart
|
12
|
+
@dtend = dtend
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def criteria
|
17
|
+
base_criteria.lte(dtstart_field => adjusted_dtend)
|
18
|
+
.gte(dtend_field => adjusted_dtstart)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def adjusted_dtstart
|
24
|
+
dtstart.instance_of?(Date) ? dtstart.beginning_of_day : dtstart
|
25
|
+
end
|
26
|
+
|
27
|
+
def adjusted_dtend
|
28
|
+
dtend.instance_of?(Date) ? dtend.beginning_of_day : dtend
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :dtstart, :dtend, :options
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'mongoid_occurrences/queries/query'
|
2
|
+
|
3
|
+
module MongoidOccurrences
|
4
|
+
module Queries
|
5
|
+
class OccursFrom < Query
|
6
|
+
option :dtstart_field, :dtstart
|
7
|
+
|
8
|
+
def initialize(base_criteria, date_time, options = {})
|
9
|
+
@base_criteria = base_criteria
|
10
|
+
@date_time = date_time
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def criteria
|
15
|
+
base_criteria.gte(dtstart_field => adjusted_date_time)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def adjusted_date_time
|
21
|
+
date_time.instance_of?(Date) ? date_time.beginning_of_day : date_time
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :date_time, :options
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'mongoid_occurrences/queries/query'
|
2
|
+
|
3
|
+
module MongoidOccurrences
|
4
|
+
module Queries
|
5
|
+
class OccursOn < Query
|
6
|
+
def initialize(base_criteria, date_time, options = {})
|
7
|
+
@base_criteria = base_criteria
|
8
|
+
@date_time = date_time
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def criteria
|
13
|
+
OccursBetween.criteria(base_criteria, adjusted_dtstart, adjusted_dtend, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def adjusted_dtstart
|
19
|
+
date_time.instance_of?(Date) ? date_time.beginning_of_day : date_time
|
20
|
+
end
|
21
|
+
|
22
|
+
def adjusted_dtend
|
23
|
+
date_time.instance_of?(Date) ? date_time.end_of_day : date_time
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :date_time, :options
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'mongoid_occurrences/queries/query'
|
2
|
+
|
3
|
+
module MongoidOccurrences
|
4
|
+
module Queries
|
5
|
+
class OccursUntil < Query
|
6
|
+
option :dtend_field, :dtend
|
7
|
+
|
8
|
+
def initialize(base_criteria, date_time, options = {})
|
9
|
+
@base_criteria = base_criteria
|
10
|
+
@date_time = date_time
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def criteria
|
15
|
+
base_criteria.lte(dtend_field => adjusted_date_time)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def adjusted_date_time
|
21
|
+
date_time.instance_of?(Date) ? date_time.end_of_day : date_time
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :date_time, :options
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module MongoidOccurrences
|
2
|
+
module Queries
|
3
|
+
class Query
|
4
|
+
def initialize(base_criteria)
|
5
|
+
@base_criteria = base_criteria
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.criteria(*args)
|
9
|
+
new(*args).criteria
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.option(name, default_value=nil)
|
13
|
+
define_method(name) do
|
14
|
+
HashWithIndifferentAccess[options].fetch(name, default_value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def criteria
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_reader :base_criteria
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'mongoid_occurrences/version'
|
2
|
+
|
3
|
+
require 'mongoid'
|
4
|
+
require 'mongoid_ice_cube_extension'
|
5
|
+
|
6
|
+
require 'mongoid_occurrences/daily_occurrence'
|
7
|
+
require 'mongoid_occurrences/has_fields_from_aggregation'
|
8
|
+
require 'mongoid_occurrences/has_occurrences'
|
9
|
+
require 'mongoid_occurrences/occurrence'
|
10
|
+
|
11
|
+
require 'mongoid_occurrences/aggregations/occurs_between'
|
12
|
+
require 'mongoid_occurrences/aggregations/occurs_from'
|
13
|
+
require 'mongoid_occurrences/aggregations/occurs_on'
|
14
|
+
require 'mongoid_occurrences/aggregations/occurs_until'
|
15
|
+
|
16
|
+
require 'mongoid_occurrences/queries/occurs_between'
|
17
|
+
require 'mongoid_occurrences/queries/occurs_from'
|
18
|
+
require 'mongoid_occurrences/queries/occurs_on'
|
19
|
+
require 'mongoid_occurrences/queries/occurs_until'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'mongoid_occurrences/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'mongoid_occurrences'
|
7
|
+
spec.version = MongoidOccurrences::VERSION
|
8
|
+
spec.authors = ['Tomas Celizna', 'Asger Behncke Jacobsen']
|
9
|
+
spec.email = ['tomas.celizna@gmail.com', 'a@asgerbehnckejacobsen.dk']
|
10
|
+
|
11
|
+
spec.summary = 'Facilitates aggregations for events with multiple occurrences or a recurring schedule.'
|
12
|
+
spec.homepage = 'https://github.com/tomasc/mongoid_occurrences'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
16
|
+
f.match(%r{^(test|spec|features)/})
|
17
|
+
end
|
18
|
+
spec.bindir = 'exe'
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.add_dependency 'ice_cube'
|
23
|
+
spec.add_dependency 'mongoid', '>= 7.0.2', '< 8'
|
24
|
+
spec.add_dependency 'mongoid-enum_attribute'
|
25
|
+
spec.add_dependency 'mongoid_ice_cube_extension', '>= 0.1.1'
|
26
|
+
|
27
|
+
spec.add_development_dependency 'activesupport', '> 3.0'
|
28
|
+
spec.add_development_dependency 'bundler'
|
29
|
+
spec.add_development_dependency 'coveralls'
|
30
|
+
spec.add_development_dependency 'database_cleaner'
|
31
|
+
spec.add_development_dependency 'factory_bot', '~> 4.0'
|
32
|
+
spec.add_development_dependency 'guard'
|
33
|
+
spec.add_development_dependency 'guard-minitest'
|
34
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
35
|
+
spec.add_development_dependency 'minitest-implicit-subject'
|
36
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,278 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mongoid_occurrences
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tomas Celizna
|
8
|
+
- Asger Behncke Jacobsen
|
9
|
+
autorequire:
|
10
|
+
bindir: exe
|
11
|
+
cert_chain: []
|
12
|
+
date: 2019-01-15 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ice_cube
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: mongoid
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 7.0.2
|
35
|
+
- - "<"
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '8'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 7.0.2
|
45
|
+
- - "<"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '8'
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: mongoid-enum_attribute
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: mongoid_ice_cube_extension
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.1.1
|
69
|
+
type: :runtime
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.1.1
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: activesupport
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
type: :development
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.0'
|
90
|
+
- !ruby/object:Gem::Dependency
|
91
|
+
name: bundler
|
92
|
+
requirement: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
type: :development
|
98
|
+
prerelease: false
|
99
|
+
version_requirements: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: coveralls
|
106
|
+
requirement: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
type: :development
|
112
|
+
prerelease: false
|
113
|
+
version_requirements: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
- !ruby/object:Gem::Dependency
|
119
|
+
name: database_cleaner
|
120
|
+
requirement: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
type: :development
|
126
|
+
prerelease: false
|
127
|
+
version_requirements: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
- !ruby/object:Gem::Dependency
|
133
|
+
name: factory_bot
|
134
|
+
requirement: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '4.0'
|
139
|
+
type: :development
|
140
|
+
prerelease: false
|
141
|
+
version_requirements: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '4.0'
|
146
|
+
- !ruby/object:Gem::Dependency
|
147
|
+
name: guard
|
148
|
+
requirement: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
type: :development
|
154
|
+
prerelease: false
|
155
|
+
version_requirements: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
- !ruby/object:Gem::Dependency
|
161
|
+
name: guard-minitest
|
162
|
+
requirement: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
type: :development
|
168
|
+
prerelease: false
|
169
|
+
version_requirements: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
- !ruby/object:Gem::Dependency
|
175
|
+
name: minitest
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - "~>"
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '5.0'
|
181
|
+
type: :development
|
182
|
+
prerelease: false
|
183
|
+
version_requirements: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - "~>"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '5.0'
|
188
|
+
- !ruby/object:Gem::Dependency
|
189
|
+
name: minitest-implicit-subject
|
190
|
+
requirement: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
type: :development
|
196
|
+
prerelease: false
|
197
|
+
version_requirements: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
- !ruby/object:Gem::Dependency
|
203
|
+
name: rake
|
204
|
+
requirement: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - "~>"
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '10.0'
|
209
|
+
type: :development
|
210
|
+
prerelease: false
|
211
|
+
version_requirements: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - "~>"
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '10.0'
|
216
|
+
description:
|
217
|
+
email:
|
218
|
+
- tomas.celizna@gmail.com
|
219
|
+
- a@asgerbehnckejacobsen.dk
|
220
|
+
executables: []
|
221
|
+
extensions: []
|
222
|
+
extra_rdoc_files: []
|
223
|
+
files:
|
224
|
+
- ".gitignore"
|
225
|
+
- ".travis.yml"
|
226
|
+
- CHANGELOG.md
|
227
|
+
- Gemfile
|
228
|
+
- Guardfile
|
229
|
+
- README.md
|
230
|
+
- Rakefile
|
231
|
+
- bin/console
|
232
|
+
- bin/setup
|
233
|
+
- lib/mongoid_occurrences.rb
|
234
|
+
- lib/mongoid_occurrences/aggregations/aggregation.rb
|
235
|
+
- lib/mongoid_occurrences/aggregations/occurs_between.rb
|
236
|
+
- lib/mongoid_occurrences/aggregations/occurs_from.rb
|
237
|
+
- lib/mongoid_occurrences/aggregations/occurs_on.rb
|
238
|
+
- lib/mongoid_occurrences/aggregations/occurs_until.rb
|
239
|
+
- lib/mongoid_occurrences/daily_occurrence.rb
|
240
|
+
- lib/mongoid_occurrences/daily_occurrence/has_scopes.rb
|
241
|
+
- lib/mongoid_occurrences/has_fields_from_aggregation.rb
|
242
|
+
- lib/mongoid_occurrences/has_occurrences.rb
|
243
|
+
- lib/mongoid_occurrences/occurrence.rb
|
244
|
+
- lib/mongoid_occurrences/occurrence/has_daily_occurrences.rb
|
245
|
+
- lib/mongoid_occurrences/occurrence/has_operators.rb
|
246
|
+
- lib/mongoid_occurrences/occurrence/has_schedule.rb
|
247
|
+
- lib/mongoid_occurrences/queries/occurs_between.rb
|
248
|
+
- lib/mongoid_occurrences/queries/occurs_from.rb
|
249
|
+
- lib/mongoid_occurrences/queries/occurs_on.rb
|
250
|
+
- lib/mongoid_occurrences/queries/occurs_until.rb
|
251
|
+
- lib/mongoid_occurrences/queries/query.rb
|
252
|
+
- lib/mongoid_occurrences/version.rb
|
253
|
+
- mongoid_occurrences.gemspec
|
254
|
+
homepage: https://github.com/tomasc/mongoid_occurrences
|
255
|
+
licenses:
|
256
|
+
- MIT
|
257
|
+
metadata: {}
|
258
|
+
post_install_message:
|
259
|
+
rdoc_options: []
|
260
|
+
require_paths:
|
261
|
+
- lib
|
262
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
263
|
+
requirements:
|
264
|
+
- - ">="
|
265
|
+
- !ruby/object:Gem::Version
|
266
|
+
version: '0'
|
267
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
268
|
+
requirements:
|
269
|
+
- - ">="
|
270
|
+
- !ruby/object:Gem::Version
|
271
|
+
version: '0'
|
272
|
+
requirements: []
|
273
|
+
rubygems_version: 3.0.1
|
274
|
+
signing_key:
|
275
|
+
specification_version: 4
|
276
|
+
summary: Facilitates aggregations for events with multiple occurrences or a recurring
|
277
|
+
schedule.
|
278
|
+
test_files: []
|