periodic_records 0.2.1 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f1685c4f8eea74df267aa354a27ccba8ba236530
4
- data.tar.gz: 3ed7467ca7261f600cece03aa886fb0e59b57bf4
3
+ metadata.gz: ebc5b792de6c66cc8f858666775da5acbbbf67f2
4
+ data.tar.gz: 5f60cdab069337f62b3af5516035845f77aee527
5
5
  SHA512:
6
- metadata.gz: 1d1aa12982eec539b6adb4dc1a6b7ddd9631c221a122d6995ad2827ecdc27aeaeb6f3ef06ffefc05e15747a303f42ca2323fe3d55bee99bce074e1e3e0d71d35
7
- data.tar.gz: be8021adfcf1f8341335ee20f466d06f5630a5dae7e368088ad9ab12026d162f9d8aa0f87511d8d06dedb93103032b209a4e3719a50661a7e65f8f5140bcd206
6
+ metadata.gz: 94286105001f6fa005c6f40d162fb5d5d6058069eb1a65c9983d77ed307ad6246bf1c511e5dc7109508431c925cbd38b006776025ceae40928362b77295ce5a4
7
+ data.tar.gz: 9b8072aacca8ed7e270662715b23d5dbdd19d043232a79d52e30922aa4eae30d2d7ac260d7b885e43e1c350d07396a0e274dc58c584abdb183888de29828ef83
data/.travis.yml CHANGED
@@ -1,3 +1,9 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2.2
3
+ - 2.2
4
+ - 2.3
5
+ - 2.4
6
+ - 2.5
7
+ env:
8
+ - "RAILS_VERSION=5.1.0"
9
+ - "RAILS_VERSION=5.2.0.beta2"
data/CHANGELOG.md CHANGED
@@ -3,6 +3,10 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project adheres to [Semantic Versioning](http://semver.org/).
5
5
 
6
+ ## [0.3.0] - 2018-01-16
7
+
8
+ - Support gapless records #2
9
+
6
10
  ## [0.2.1] - 2016-09-27
7
11
 
8
12
  - Relax dependencies for Rails 5 compatibility
data/Gemfile CHANGED
@@ -2,3 +2,8 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in periodic_records.gemspec
4
4
  gemspec
5
+
6
+ if ENV['RAILS_VERSION']
7
+ gem 'activerecord', "~> #{ENV['RAILS_VERSION']}"
8
+ gem 'activesupport', "~> #{ENV['RAILS_VERSION']}"
9
+ end
data/README.md CHANGED
@@ -15,25 +15,25 @@ employment history.
15
15
 
16
16
  Employees:
17
17
 
18
- id | name
19
- ---|------
20
- 1 | John
18
+ | id | name |
19
+ |:---|:-----|
20
+ | 1 | John |
21
21
 
22
22
  Employee assignments:
23
23
 
24
- id | employee_id | start_at | end_at | job_title
25
- ---|-------------|------------|------------|----------
26
- 1 | 1 | 2014-01-01 | 9999-01-01 | Developer
24
+ | id | employee_id | start_at | end_at | job_title |
25
+ |:---|:------------|:-----------|:-----------|:----------|
26
+ | 1 | 1 | 2014-01-01 | 9999-01-01 | Developer |
27
27
 
28
28
  Now John is promoted to "Senior Developer" and you create a new employee
29
29
  assignment record and this gem will take care of adjusting and splitting
30
30
  overlapping records. In this case it will adjust the `end_at` field for the
31
31
  previous assignment.
32
32
 
33
- id | employee_id | start_at | end_at | job_title
34
- ---|-------------|------------|------------|-----------------
35
- 1 | 1 | 2014-01-01 | 2018-05-04 | Developer
36
- 2 | 1 | 2018-05-05 | 9999-01-01 | Senior Developer
33
+ | id | employee_id | start_at | end_at | job_title |
34
+ |:---|:------------|:-----------|:-----------|:-----------------|
35
+ | 1 | 1 | 2014-01-01 | 2018-05-04 | Developer |
36
+ | 2 | 1 | 2018-05-05 | 9999-01-01 | Senior Developer |
37
37
 
38
38
 
39
39
  ## Installation
@@ -151,6 +151,60 @@ class AddEmployeeAssignmentsOverlappingDatesConstraint < ActiveRecord::Migration
151
151
  end
152
152
  ```
153
153
 
154
+ ## Gapless records
155
+
156
+ If you want to avoid gaps between records, you can include also `PeriodicRecords::Gapless`.
157
+
158
+ ```ruby
159
+ class EmployeeAssignment < ActiveRecord::Base
160
+ include PeriodicRecords::Model
161
+ include PeriodicRecords::Gapless
162
+
163
+ belongs_to :employee
164
+
165
+ def siblings
166
+ self.class.where(employee_id: employee_id).where.not(id: id)
167
+ end
168
+ end
169
+ ```
170
+
171
+ Example:
172
+
173
+ | id | employee_id | start_at | end_at | job_title |
174
+ |:---|:------------|:-----------|:-----------|:-----------------|
175
+ | 1 | 1 | 0001-01-01 | 2018-01-15 | Junior Developer |
176
+ | 2 | 1 | 2018-01-16 | 2018-02-15 | Developer |
177
+ | 3 | 1 | 2018-02-16 | 9999-01-01 | Senior Developer |
178
+
179
+ If you update #2 from `2018-01-16 - 2018-02-15` to `2018-01-20 - 2018-02-10`, it
180
+ will also adjust end at for #1 and start at for #3 to avoid gaps between records.
181
+
182
+ After (with `Gapless`):
183
+
184
+ | id | employee_id | start_at | end_at | job_title |
185
+ |:---|:------------|:-----------|:-----------|:-----------------|
186
+ | 1 | 1 | 0001-01-01 | 2018-01-19 | Junior Developer |
187
+ | 2 | 1 | 2018-01-20 | 2018-02-10 | Developer |
188
+ | 3 | 1 | 2018-02-11 | 9999-01-01 | Senior Developer |
189
+
190
+ After (without `Gapless`):
191
+
192
+ | id | employee_id | start_at | end_at | job_title |
193
+ |:---|:------------|:-----------|:-----------|:-----------------|
194
+ | 1 | 1 | 0001-01-01 | 2018-01-15 | Junior Developer |
195
+ | 2 | 1 | 2018-01-20 | 2018-02-10 | Developer |
196
+ | 3 | 1 | 2018-02-16 | 9999-01-01 | Senior Developer |
197
+
198
+ If you delete #2 then it will adjust end at for #1.
199
+
200
+ You will not be able to delete entry that is at the beginning (#1) or at the end (#3).
201
+
202
+ You will not be able to adjust start at for the beginning entry (#1).
203
+
204
+ You will not be able to adjust end at for the ending entry (#3).
205
+
206
+ For more examples see [gapless_spec.rb](spec/periodic_records/gapless_spec.rb]).
207
+
154
208
  ## Development
155
209
 
156
210
  After checking out the repo, run `bin/setup` to install dependencies.
@@ -0,0 +1,76 @@
1
+ module PeriodicRecords
2
+ module Gapless
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ validate :validate_gapless_start_at, if: :gapless?
7
+ validate :validate_gapless_end_at, if: :gapless?
8
+ after_save :adjust_gaps, if: :gapless?
9
+ before_destroy :before_gapless_destroy, if: :gapless?
10
+ after_destroy :after_gapless_destroy, if: :gapless?
11
+ end
12
+
13
+ private
14
+
15
+ def gapless?
16
+ true
17
+ end
18
+
19
+ def validate_gapless_start_at
20
+ if start_at_changed? && start_at_was == self.class::MIN
21
+ errors.add :start_at, :invalid
22
+ end
23
+ end
24
+
25
+ def validate_gapless_end_at
26
+ if end_at_changed? && end_at_was == self.class::MAX
27
+ errors.add :end_at, :invalid
28
+ end
29
+ end
30
+
31
+ def adjust_gaps
32
+ adjust_previous_gap
33
+ adjust_next_gap
34
+ end
35
+
36
+ def adjust_previous_gap
37
+ if saved_change_to_start_at? && start_at && start_at_before_last_save && start_at > start_at_before_last_save
38
+ previous_record = siblings.where(end_at: start_at_before_last_save - 1.day).first
39
+ if previous_record
40
+ previous_record.end_at = start_at - 1.day
41
+ previous_record.save(validate: false)
42
+ end
43
+ end
44
+ end
45
+
46
+ def adjust_next_gap
47
+ if saved_change_to_end_at? && end_at && end_at_before_last_save && end_at_before_last_save > end_at
48
+ next_record = siblings.where(start_at: end_at_before_last_save + 1.day).first
49
+ if next_record
50
+ next_record.start_at = end_at + 1.day
51
+ next_record.save(validate: false)
52
+ end
53
+ end
54
+ end
55
+
56
+ def before_gapless_destroy
57
+ if start_at == self.class::MIN
58
+ errors.add :start_at, :invalid
59
+ end
60
+ if end_at == self.class::MAX
61
+ errors.add :end_at, :invalid
62
+ end
63
+ unless errors.empty?
64
+ throw :abort
65
+ end
66
+ end
67
+
68
+ def after_gapless_destroy
69
+ previous_record = siblings.where(end_at: start_at - 1.day).first
70
+ if previous_record
71
+ previous_record.end_at = end_at
72
+ previous_record.save(validate: false)
73
+ end
74
+ end
75
+ end
76
+ end
@@ -49,7 +49,7 @@ module PeriodicRecords
49
49
  end
50
50
 
51
51
  def overlapping_records
52
- @overlapping_records ||= siblings.within_interval(start_at, end_at)
52
+ siblings.within_interval(start_at, end_at)
53
53
  end
54
54
 
55
55
  def adjust_overlapping_records
@@ -1,3 +1,3 @@
1
1
  module PeriodicRecords
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -1,5 +1,6 @@
1
1
  require "periodic_records/version"
2
2
  require "periodic_records/model"
3
+ require "periodic_records/gapless"
3
4
  require "periodic_records/associations"
4
5
 
5
6
  module PeriodicRecords
@@ -19,8 +19,8 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_runtime_dependency "activerecord", ">= 4"
23
- spec.add_runtime_dependency "activesupport", ">= 4"
22
+ spec.add_runtime_dependency "activerecord", ">= 5.1"
23
+ spec.add_runtime_dependency "activesupport", ">= 5.1"
24
24
 
25
25
  spec.add_development_dependency "bundler", "~> 1.9"
26
26
  spec.add_development_dependency "rake", "~> 10.0"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: periodic_records
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Edgars Beigarts
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2016-09-27 00:00:00.000000000 Z
12
+ date: 2018-01-16 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -17,28 +17,28 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '4'
20
+ version: '5.1'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: '4'
27
+ version: '5.1'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: activesupport
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: '4'
34
+ version: '5.1'
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: '4'
41
+ version: '5.1'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: bundler
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -115,6 +115,7 @@ files:
115
115
  - bin/setup
116
116
  - lib/periodic_records.rb
117
117
  - lib/periodic_records/associations.rb
118
+ - lib/periodic_records/gapless.rb
118
119
  - lib/periodic_records/model.rb
119
120
  - lib/periodic_records/version.rb
120
121
  - periodic_records.gemspec
@@ -138,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
139
  version: '0'
139
140
  requirements: []
140
141
  rubyforge_project:
141
- rubygems_version: 2.5.1
142
+ rubygems_version: 2.6.10
142
143
  signing_key:
143
144
  specification_version: 4
144
145
  summary: Support functions for ActiveRecord models with periodic entries