periodic_records 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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