activerecord-bitemporal 4.3.0 → 5.0.1
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 +4 -4
- data/.circleci/config.yml +13 -11
- data/.github/auto_assign.yml +0 -5
- data/Appraisals +4 -4
- data/CHANGELOG.md +34 -0
- data/activerecord-bitemporal.gemspec +2 -2
- data/gemfiles/{rails_6.0.gemfile → rails_7.1.gemfile} +1 -1
- data/lib/activerecord-bitemporal/bitemporal.rb +44 -31
- data/lib/activerecord-bitemporal/scope.rb +73 -166
- data/lib/activerecord-bitemporal/version.rb +1 -1
- data/lib/activerecord-bitemporal/visualizer.rb +5 -3
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0e6cafe3d918cd4bdf47c2610eaf3760cfcedbec0365a7675ef99790a05baaf
|
4
|
+
data.tar.gz: 79b7823949b22cbcacdfb75b561c70808135ebd3dc1c6a5ff0ef8152c75b8d79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4331c2b17a26dfea76b5c1c85a6a0feac925a1c0b7d634fa734e35e5f7732e0d49d04172ae4bf6af5ae62b213481bd09da7807312f241578e72f2a9ee952f640
|
7
|
+
data.tar.gz: 98ffa072e196a6af9b61ef01ee5e7d8e3ef83a94abd8f666738831783b35bb16551fd0bd1d561f76a6a55aa522d4609274ec3e6a6a78d311b7c76e53c860b1c4
|
data/.circleci/config.yml
CHANGED
@@ -9,13 +9,14 @@ jobs:
|
|
9
9
|
type: string
|
10
10
|
docker:
|
11
11
|
- image: ruby:<< parameters.ruby-version >>
|
12
|
+
environment:
|
13
|
+
BUNDLE_GEMFILE: gemfiles/<< parameters.gemfile >>.gemfile
|
12
14
|
- image: cimg/postgres:11.16
|
13
15
|
steps:
|
14
16
|
- checkout
|
15
17
|
- run: gem install bundler
|
16
18
|
- run: bundle install
|
17
|
-
- run: bundle exec
|
18
|
-
- run: bundle exec appraisal << parameters.gemfile >> rspec
|
19
|
+
- run: bundle exec rspec
|
19
20
|
|
20
21
|
workflows:
|
21
22
|
test:
|
@@ -24,16 +25,17 @@ workflows:
|
|
24
25
|
matrix:
|
25
26
|
parameters:
|
26
27
|
ruby-version:
|
27
|
-
- '2.7'
|
28
28
|
- '3.0'
|
29
29
|
- '3.1'
|
30
|
+
- '3.2'
|
31
|
+
- '3.3'
|
30
32
|
gemfile:
|
31
|
-
-
|
32
|
-
-
|
33
|
-
-
|
34
|
-
-
|
33
|
+
- rails_6.1
|
34
|
+
- rails_7.0
|
35
|
+
- rails_7.1
|
36
|
+
- rails_main
|
35
37
|
exclude:
|
36
|
-
- ruby-version: '3.
|
37
|
-
gemfile:
|
38
|
-
- ruby-version: '3.
|
39
|
-
gemfile:
|
38
|
+
- ruby-version: '3.2'
|
39
|
+
gemfile: rails_6.1
|
40
|
+
- ruby-version: '3.3'
|
41
|
+
gemfile: rails_6.1
|
data/.github/auto_assign.yml
CHANGED
@@ -6,15 +6,10 @@ addAssignees: false
|
|
6
6
|
|
7
7
|
# A list of reviewers to be added to pull requests (GitHub user name)
|
8
8
|
reviewers:
|
9
|
-
- Dooor
|
10
|
-
- QWYNG
|
11
|
-
- bonobono555
|
12
9
|
- krororo
|
13
10
|
- lighty
|
14
11
|
- mkmn
|
15
|
-
- motsat
|
16
12
|
- osyo-manga
|
17
|
-
- wakasa51
|
18
13
|
- wata727
|
19
14
|
- yono
|
20
15
|
|
data/Appraisals
CHANGED
@@ -4,10 +4,6 @@ appraise "rails-main" do
|
|
4
4
|
gem "rails", git: 'https://github.com/rails/rails.git', branch: "main"
|
5
5
|
end
|
6
6
|
|
7
|
-
appraise "rails-6.0" do
|
8
|
-
gem "rails", "~> 6.0.2"
|
9
|
-
end
|
10
|
-
|
11
7
|
appraise "rails-6.1" do
|
12
8
|
gem "rails", "~> 6.1.0"
|
13
9
|
end
|
@@ -15,3 +11,7 @@ end
|
|
15
11
|
appraise "rails-7.0" do
|
16
12
|
gem "rails", "~> 7.0.1"
|
17
13
|
end
|
14
|
+
|
15
|
+
appraise "rails-7.1" do
|
16
|
+
gem "rails", "~> 7.1.0"
|
17
|
+
end
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,39 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 5.0.1
|
4
|
+
|
5
|
+
- [Fix a typo #157](https://github.com/kufu/activerecord-bitemporal/pull/157)
|
6
|
+
- [Remove unneeded unscope values #159](https://github.com/kufu/activerecord-bitemporal/pull/159)
|
7
|
+
- [Remove unused `without_ignore` option #160](https://github.com/kufu/activerecord-bitemporal/pull/160)
|
8
|
+
- [update auto assign #161](https://github.com/kufu/activerecord-bitemporal/pull/161)
|
9
|
+
|
10
|
+
## 5.0.0
|
11
|
+
|
12
|
+
### Breaking Changed
|
13
|
+
|
14
|
+
- [CI against Ruby 3.2, 3.3, Drop Ruby 2.7 and Rails 6.0 #150](https://github.com/kufu/activerecord-bitemporal/pull/150)
|
15
|
+
|
16
|
+
### Added
|
17
|
+
|
18
|
+
- [Support date type of valid time #149](https://github.com/kufu/activerecord-bitemporal/pull/149)
|
19
|
+
- [Add support Rails 7.1 #151](https://github.com/kufu/activerecord-bitemporal/pull/151)
|
20
|
+
- [Add Persistence#bitemporal_at and ActiveRecord::Bitemporal.bitemporal_at #152](https://github.com/kufu/activerecord-bitemporal/pull/152)
|
21
|
+
|
22
|
+
### Changed
|
23
|
+
|
24
|
+
### Deprecated
|
25
|
+
|
26
|
+
### Removed
|
27
|
+
|
28
|
+
### Fixed
|
29
|
+
|
30
|
+
- [Fix deleted time order between associations #154](https://github.com/kufu/activerecord-bitemporal/pull/154)
|
31
|
+
|
32
|
+
### Chores
|
33
|
+
|
34
|
+
- [Don't use appraisal in CI #145](https://github.com/kufu/activerecord-bitemporal/pull/145)
|
35
|
+
- [Remove code for Active Record 6.0 #153](https://github.com/kufu/activerecord-bitemporal/pull/153)
|
36
|
+
|
3
37
|
## 4.3.0
|
4
38
|
|
5
39
|
### Added
|
@@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
|
|
14
14
|
spec.description = %q{Enable ActiveRecord models to be handled as BiTemporal Data Model.}
|
15
15
|
spec.homepage = "https://github.com/kufu/activerecord-bitemporal"
|
16
16
|
spec.license = "Apache 2.0"
|
17
|
-
spec.required_ruby_version = ">=
|
17
|
+
spec.required_ruby_version = ">= 3.0"
|
18
18
|
|
19
19
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
20
20
|
f.match(%r{^(test|spec|features)/})
|
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
24
|
spec.require_paths = ["lib"]
|
25
25
|
|
26
|
-
spec.add_dependency "activerecord", ">= 6.
|
26
|
+
spec.add_dependency "activerecord", ">= 6.1"
|
27
27
|
|
28
28
|
spec.add_development_dependency "bundler"
|
29
29
|
spec.add_development_dependency "rake", "~> 13.0"
|
@@ -68,6 +68,10 @@ module ActiveRecord
|
|
68
68
|
bitemporal_option[:valid_datetime]&.in_time_zone
|
69
69
|
end
|
70
70
|
|
71
|
+
def valid_date
|
72
|
+
valid_datetime&.to_date
|
73
|
+
end
|
74
|
+
|
71
75
|
def ignore_valid_datetime(&block)
|
72
76
|
with_bitemporal_option(ignore_valid_datetime: true, valid_datetime: nil, &block)
|
73
77
|
end
|
@@ -88,6 +92,14 @@ module ActiveRecord
|
|
88
92
|
with_bitemporal_option(ignore_transaction_datetime: true, transaction_datetime: nil, &block)
|
89
93
|
end
|
90
94
|
|
95
|
+
def bitemporal_at(datetime, &block)
|
96
|
+
transaction_at(datetime) { valid_at(datetime, &block) }
|
97
|
+
end
|
98
|
+
|
99
|
+
def bitemporal_at!(datetime, &block)
|
100
|
+
transaction_at!(datetime) { valid_at!(datetime, &block) }
|
101
|
+
end
|
102
|
+
|
91
103
|
def merge_by(option)
|
92
104
|
option_ = option.dup
|
93
105
|
if bitemporal_option_storage[:force_valid_datetime]
|
@@ -224,6 +236,10 @@ module ActiveRecord
|
|
224
236
|
with_bitemporal_option(transaction_datetime: datetime, &block)
|
225
237
|
end
|
226
238
|
|
239
|
+
def bitemporal_at(datetime, &block)
|
240
|
+
transaction_at(datetime) { valid_at(datetime, &block) }
|
241
|
+
end
|
242
|
+
|
227
243
|
def bitemporal_option_merge_with_association!(other)
|
228
244
|
bitemporal_option_merge!(other)
|
229
245
|
|
@@ -238,6 +254,10 @@ module ActiveRecord
|
|
238
254
|
bitemporal_option[:valid_datetime]&.in_time_zone
|
239
255
|
end
|
240
256
|
|
257
|
+
def valid_date
|
258
|
+
valid_datetime&.to_date
|
259
|
+
end
|
260
|
+
|
241
261
|
def transaction_datetime
|
242
262
|
bitemporal_option[:transaction_datetime]&.in_time_zone
|
243
263
|
end
|
@@ -336,16 +356,17 @@ module ActiveRecord
|
|
336
356
|
end || false
|
337
357
|
end
|
338
358
|
|
339
|
-
def destroy(force_delete: false, operated_at:
|
359
|
+
def destroy(force_delete: false, operated_at: nil)
|
340
360
|
return super() if force_delete
|
341
361
|
|
342
|
-
target_datetime = valid_datetime || operated_at
|
343
|
-
|
344
|
-
duplicated_instance = self.class.find_at_time(target_datetime, self.id).dup
|
345
|
-
|
346
362
|
ActiveRecord::Base.transaction(requires_new: true, joinable: false) do
|
347
363
|
@destroyed = false
|
348
364
|
_run_destroy_callbacks {
|
365
|
+
operated_at ||= Time.current
|
366
|
+
target_datetime = valid_datetime || operated_at
|
367
|
+
|
368
|
+
duplicated_instance = self.class.find_at_time(target_datetime, self.id).dup
|
369
|
+
|
349
370
|
@destroyed = update_transaction_to(operated_at)
|
350
371
|
@previously_force_updated = force_update?
|
351
372
|
|
@@ -375,6 +396,18 @@ module ActiveRecord
|
|
375
396
|
false
|
376
397
|
end
|
377
398
|
|
399
|
+
if Gem::Version.new("7.1.0") <= ActiveRecord.version
|
400
|
+
# MEMO: Since Rails 7.1 #_find_record refers to a record with find_by!(@primary_key => id)
|
401
|
+
# But if @primary_key is "id", it can't refer to the intended record, so we hack it to refer to the record based on self.class.bitemporal_id_key
|
402
|
+
# see: https://github.com/rails/rails/blob/v7.1.0/activerecord/lib/active_record/persistence.rb#L1152-#L1171
|
403
|
+
def _find_record(*)
|
404
|
+
tmp_primary_key, @primary_key = @primary_key, self.class.bitemporal_id_key
|
405
|
+
super
|
406
|
+
ensure
|
407
|
+
@primary_key = tmp_primary_key
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
378
411
|
module ::ActiveRecord::Persistence
|
379
412
|
# MEMO: Must be override ActiveRecord::Persistence#reload
|
380
413
|
alias_method :active_record_bitemporal_original_reload, :reload unless method_defined? :active_record_bitemporal_original_reload
|
@@ -403,7 +436,7 @@ module ActiveRecord
|
|
403
436
|
@previously_force_updated = false
|
404
437
|
self
|
405
438
|
end
|
406
|
-
|
439
|
+
else
|
407
440
|
def reload(options = nil)
|
408
441
|
return active_record_bitemporal_original_reload(options) unless self.class.bi_temporal_model?
|
409
442
|
|
@@ -427,29 +460,6 @@ module ActiveRecord
|
|
427
460
|
@previously_force_updated = false
|
428
461
|
self
|
429
462
|
end
|
430
|
-
else
|
431
|
-
def reload(options = nil)
|
432
|
-
return active_record_bitemporal_original_reload(options) unless self.class.bi_temporal_model?
|
433
|
-
|
434
|
-
self.class.connection.clear_query_cache
|
435
|
-
|
436
|
-
fresh_object =
|
437
|
-
ActiveRecord::Bitemporal.with_bitemporal_option(**bitemporal_option) {
|
438
|
-
if options && options[:lock]
|
439
|
-
self.class.unscoped { self.class.lock(options[:lock]).bitemporal_default_scope.find(id) }
|
440
|
-
else
|
441
|
-
self.class.unscoped { self.class.bitemporal_default_scope.find(id) }
|
442
|
-
end
|
443
|
-
}
|
444
|
-
|
445
|
-
@attributes = fresh_object.instance_variable_get("@attributes")
|
446
|
-
@new_record = false
|
447
|
-
# NOTE: Hook to copying swapped_id
|
448
|
-
@_swapped_id_previously_was = nil
|
449
|
-
@_swapped_id = fresh_object.swapped_id
|
450
|
-
@previously_force_updated = false
|
451
|
-
self
|
452
|
-
end
|
453
463
|
end
|
454
464
|
end
|
455
465
|
|
@@ -567,7 +577,7 @@ module ActiveRecord
|
|
567
577
|
target_datetime
|
568
578
|
# NOTE: 新規作成時以外では target_datetime の値を基準としてバリデーションする
|
569
579
|
# 更新時にバリデーションする場合、valid_from の時間ではなくて target_datetime の時間を基準としているため
|
570
|
-
#
|
580
|
+
# valid_from を基準としてしまうと整合性が取れなくなってしまう
|
571
581
|
elsif !record.new_record?
|
572
582
|
target_datetime
|
573
583
|
else
|
@@ -579,10 +589,13 @@ module ActiveRecord
|
|
579
589
|
valid_from = record.valid_from if record.force_update?
|
580
590
|
|
581
591
|
valid_to = record.valid_to.yield_self { |valid_to|
|
592
|
+
# NOTE: `cover?` may give incorrect results, when the time zone is not UTC and `valid_from` is date type
|
593
|
+
# Therefore, cast to type of `valid_from`
|
594
|
+
record_valid_time = finder_class.type_for_attribute(:valid_from).cast(record.valid_datetime)
|
582
595
|
# レコードを更新する時に valid_datetime が valid_from ~ valid_to の範囲外だった場合、
|
583
596
|
# 一番近い未来の履歴レコードを参照して更新する
|
584
597
|
# という仕様があるため、それを考慮して valid_to を設定する
|
585
|
-
if (
|
598
|
+
if (record_valid_time && (record.valid_from..record.valid_to).cover?(record_valid_time)) == false && (record.persisted?)
|
586
599
|
finder_class.ignore_valid_datetime.where(bitemporal_id: record.bitemporal_id).valid_from_gt(target_datetime).order(valid_from: :asc).first.valid_from
|
587
600
|
else
|
588
601
|
valid_to
|
@@ -47,26 +47,9 @@ module ActiveRecord::Bitemporal
|
|
47
47
|
end
|
48
48
|
}
|
49
49
|
|
50
|
-
def
|
50
|
+
def each_operatable_node(nodes = predicates, &block)
|
51
51
|
if block
|
52
52
|
each_operatable_node(nodes).each(&block)
|
53
|
-
else
|
54
|
-
Enumerator.new { |y|
|
55
|
-
Array(nodes).each { |node|
|
56
|
-
case node
|
57
|
-
when Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
|
58
|
-
y << node if node && node.left.respond_to?(:relation)
|
59
|
-
when Arel::Nodes::Grouping
|
60
|
-
each_operatable_node(node.expr) { |node| y << node }
|
61
|
-
end
|
62
|
-
}
|
63
|
-
}
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def each_operatable_node_6_1(nodes = predicates, &block)
|
68
|
-
if block
|
69
|
-
each_operatable_node_6_1(nodes).each(&block)
|
70
53
|
else
|
71
54
|
Enumerator.new { |y|
|
72
55
|
Array(nodes).each { |node|
|
@@ -74,26 +57,18 @@ module ActiveRecord::Bitemporal
|
|
74
57
|
when Arel::Nodes::LessThan, Arel::Nodes::LessThanOrEqual, Arel::Nodes::GreaterThan, Arel::Nodes::GreaterThanOrEqual
|
75
58
|
y << node if node && node.left.respond_to?(:relation)
|
76
59
|
when Arel::Nodes::And
|
77
|
-
|
60
|
+
each_operatable_node(node.children) { |node| y << node }
|
78
61
|
when Arel::Nodes::Binary
|
79
|
-
|
80
|
-
|
62
|
+
each_operatable_node(node.left) { |node| y << node }
|
63
|
+
each_operatable_node(node.right) { |node| y << node }
|
81
64
|
when Arel::Nodes::Unary
|
82
|
-
|
65
|
+
each_operatable_node(node.expr) { |node| y << node }
|
83
66
|
end
|
84
67
|
}
|
85
68
|
}
|
86
69
|
end
|
87
70
|
end
|
88
71
|
|
89
|
-
def each_operatable_node(nodes = predicates, &block)
|
90
|
-
if Gem::Version.new("6.1.0") <= ActiveRecord.version
|
91
|
-
each_operatable_node_6_1(nodes, &block)
|
92
|
-
else
|
93
|
-
each_operatable_node_6_0(nodes, &block)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
72
|
def bitemporal_query_hash(*names)
|
98
73
|
each_operatable_node
|
99
74
|
.select { |node| names.include? node.left.name.to_s }
|
@@ -126,31 +101,6 @@ module ActiveRecord::Bitemporal
|
|
126
101
|
end
|
127
102
|
}
|
128
103
|
|
129
|
-
if ActiveRecord.version < Gem::Version.new("6.1.0")
|
130
|
-
class WhereClauseWithCheckTable < ActiveRecord::Relation::WhereClause
|
131
|
-
using NodeBitemporalInclude
|
132
|
-
|
133
|
-
def bitemporal_include?(column)
|
134
|
-
!!predicates.grep(::Arel::Nodes::Node).find do |node|
|
135
|
-
node.bitemporal_include?(column)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
private
|
140
|
-
|
141
|
-
def except_predicates(columns)
|
142
|
-
columns = Array(columns)
|
143
|
-
predicates.reject do |node|
|
144
|
-
::Arel::Nodes::Node === node && node.bitemporal_include?(*columns)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def where_clause
|
150
|
-
WhereClauseWithCheckTable.new(super.send(:predicates))
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
104
|
module MergeWithExceptBitemporalDefaultScope
|
155
105
|
using BitemporalChecker
|
156
106
|
def merge(other)
|
@@ -166,6 +116,10 @@ module ActiveRecord::Bitemporal
|
|
166
116
|
bitemporal_clause[:valid_datetime]&.in_time_zone
|
167
117
|
end
|
168
118
|
|
119
|
+
def valid_date
|
120
|
+
valid_datetime&.to_date
|
121
|
+
end
|
122
|
+
|
169
123
|
def transaction_datetime
|
170
124
|
bitemporal_clause[:transaction_datetime]&.in_time_zone
|
171
125
|
end
|
@@ -239,118 +193,80 @@ module ActiveRecord::Bitemporal
|
|
239
193
|
end
|
240
194
|
}
|
241
195
|
|
242
|
-
|
243
|
-
module
|
244
|
-
refine ::
|
245
|
-
|
246
|
-
|
247
|
-
def _ignore_#{column}
|
248
|
-
unscope(where: "\#{table.name}.#{column}")
|
249
|
-
.tap { |relation| relation.merge!(bitemporal_value[:through].unscoped._ignore_#{column}) if bitemporal_value[:through] }
|
250
|
-
end
|
251
|
-
|
252
|
-
def _except_#{column}
|
253
|
-
return self unless where_clause.bitemporal_include?("\#{table.name}.#{column}")
|
254
|
-
all._ignore_#{column}.tap { |relation|
|
255
|
-
relation.unscope_values.delete({ where: "\#{table.name}.#{column}" })
|
256
|
-
}
|
257
|
-
end
|
258
|
-
STR
|
259
|
-
|
260
|
-
[
|
261
|
-
:lt, # column < datetime
|
262
|
-
:lteq, # column <= datetime
|
263
|
-
:gt, # column > datetime
|
264
|
-
:gteq # column >= datetime
|
265
|
-
].each { |op|
|
266
|
-
module_eval <<-STR, __FILE__, __LINE__ + 1
|
267
|
-
def _#{column}_#{op}(datetime, without_ignore: false)
|
268
|
-
target_datetime = datetime&.in_time_zone || Time.current
|
269
|
-
relation = self.tap { |relation| break relation._ignore_#{column} unless without_ignore }
|
270
|
-
relation.bitemporal_where_bind!(:#{column}, :#{op}, target_datetime)
|
271
|
-
.tap { |relation| relation.merge!(bitemporal_value[:through].unscoped._#{column}_#{op}(target_datetime)) if bitemporal_value[:through] }
|
272
|
-
end
|
273
|
-
STR
|
274
|
-
}
|
275
|
-
}
|
276
|
-
end
|
277
|
-
end
|
278
|
-
else
|
279
|
-
module ActiveRecordRelationScope
|
280
|
-
module EqualAttributeName
|
281
|
-
refine ::Object do
|
282
|
-
def equal_attribute_name(*)
|
283
|
-
false
|
284
|
-
end
|
196
|
+
module ActiveRecordRelationScope
|
197
|
+
module EqualAttributeName
|
198
|
+
refine ::Object do
|
199
|
+
def equal_attribute_name(*)
|
200
|
+
false
|
285
201
|
end
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
202
|
+
end
|
203
|
+
refine ::Hash do
|
204
|
+
def equal_attribute_name(other)
|
205
|
+
self[:where].equal_attribute_name(other)
|
290
206
|
end
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
207
|
+
end
|
208
|
+
refine ::Array do
|
209
|
+
def equal_attribute_name(other)
|
210
|
+
first.equal_attribute_name(other)
|
295
211
|
end
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
212
|
+
end
|
213
|
+
refine ::String do
|
214
|
+
def equal_attribute_name(other)
|
215
|
+
self == other.to_s
|
300
216
|
end
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
217
|
+
end
|
218
|
+
refine ::Symbol do
|
219
|
+
def equal_attribute_name(other)
|
220
|
+
self.to_s == other.to_s
|
305
221
|
end
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
222
|
+
end
|
223
|
+
refine ::Arel::Attributes::Attribute do
|
224
|
+
def equal_attribute_name(other)
|
225
|
+
"#{relation.name}.#{name}" == other.to_s
|
310
226
|
end
|
311
227
|
end
|
228
|
+
end
|
312
229
|
|
313
|
-
|
314
|
-
|
315
|
-
|
230
|
+
refine ::ActiveRecord::Relation do
|
231
|
+
using EqualAttributeName
|
232
|
+
using NodeBitemporalInclude
|
316
233
|
|
317
|
-
|
318
|
-
|
319
|
-
|
234
|
+
def bitemporal_rewhere_bind(attr_name, operator, value, table = self.table)
|
235
|
+
rewhere(table[attr_name].public_send(operator, predicate_builder.build_bind_attribute(attr_name, value)))
|
236
|
+
end
|
320
237
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
238
|
+
%i(valid_from valid_to transaction_from transaction_to).each { |column|
|
239
|
+
module_eval <<-STR, __FILE__, __LINE__ + 1
|
240
|
+
def _ignore_#{column}
|
241
|
+
unscope(where: :"\#{table.name}.#{column}")
|
242
|
+
.tap { |relation| relation.unscope!(where: bitemporal_value[:through].arel_table["#{column}"]) if bitemporal_value[:through] }
|
243
|
+
end
|
327
244
|
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
245
|
+
def _except_#{column}
|
246
|
+
return self unless where_clause.send(:predicates).find { |node|
|
247
|
+
node.bitemporal_include?("\#{table.name}.#{column}")
|
248
|
+
}
|
249
|
+
_ignore_#{column}.tap { |relation|
|
250
|
+
relation.unscope_values.reject! { |query| query.equal_attribute_name("\#{table.name}.#{column}") }
|
251
|
+
}
|
252
|
+
end
|
253
|
+
STR
|
254
|
+
|
255
|
+
[
|
256
|
+
:lt, # column < datetime
|
257
|
+
:lteq, # column <= datetime
|
258
|
+
:gt, # column > datetime
|
259
|
+
:gteq # column >= datetime
|
260
|
+
].each { |op|
|
261
|
+
module_eval <<-STR, __FILE__, __LINE__ + 1
|
262
|
+
def _#{column}_#{op}(datetime)
|
263
|
+
target_datetime = datetime&.in_time_zone || Time.current
|
264
|
+
bitemporal_rewhere_bind("#{column}", :#{op}, target_datetime)
|
265
|
+
.tap { |relation| break relation.bitemporal_rewhere_bind("#{column}", :#{op}, target_datetime, bitemporal_value[:through].arel_table) if bitemporal_value[:through] }
|
335
266
|
end
|
336
267
|
STR
|
337
|
-
|
338
|
-
[
|
339
|
-
:lt, # column < datetime
|
340
|
-
:lteq, # column <= datetime
|
341
|
-
:gt, # column > datetime
|
342
|
-
:gteq # column >= datetime
|
343
|
-
].each { |op|
|
344
|
-
module_eval <<-STR, __FILE__, __LINE__ + 1
|
345
|
-
def _#{column}_#{op}(datetime,**)
|
346
|
-
target_datetime = datetime&.in_time_zone || Time.current
|
347
|
-
bitemporal_rewhere_bind("#{column}", :#{op}, target_datetime)
|
348
|
-
.tap { |relation| break relation.bitemporal_rewhere_bind("#{column}", :#{op}, target_datetime, bitemporal_value[:through].arel_table) if bitemporal_value[:through] }
|
349
|
-
end
|
350
|
-
STR
|
351
|
-
}
|
352
268
|
}
|
353
|
-
|
269
|
+
}
|
354
270
|
end
|
355
271
|
end
|
356
272
|
using ActiveRecordRelationScope
|
@@ -439,14 +355,9 @@ module ActiveRecord::Bitemporal
|
|
439
355
|
relation.bitemporal_value[:with_transaction_datetime] = :default_scope
|
440
356
|
end
|
441
357
|
|
442
|
-
# Calling scope was slow, so don't call scope
|
443
|
-
relation.unscope_values += [
|
444
|
-
{ where: "#{table.name}.transaction_from" },
|
445
|
-
{ where: "#{table.name}.transaction_to" }
|
446
|
-
]
|
447
358
|
relation = relation
|
448
|
-
._transaction_from_lteq(transaction_datetime || datetime
|
449
|
-
._transaction_to_gt(transaction_datetime || datetime
|
359
|
+
._transaction_from_lteq(transaction_datetime || datetime)
|
360
|
+
._transaction_to_gt(transaction_datetime || datetime)
|
450
361
|
else
|
451
362
|
relation.tap { |relation| relation.without_transaction_datetime unless ActiveRecord::Bitemporal.transaction_datetime }
|
452
363
|
end
|
@@ -459,13 +370,9 @@ module ActiveRecord::Bitemporal
|
|
459
370
|
relation.bitemporal_value[:with_valid_datetime] = :default_scope
|
460
371
|
end
|
461
372
|
|
462
|
-
relation.unscope_values += [
|
463
|
-
{ where: "#{table.name}.valid_from" },
|
464
|
-
{ where: "#{table.name}.valid_to" }
|
465
|
-
]
|
466
373
|
relation = relation
|
467
|
-
._valid_from_lteq(valid_datetime || datetime
|
468
|
-
._valid_to_gt(valid_datetime || datetime
|
374
|
+
._valid_from_lteq(valid_datetime || datetime)
|
375
|
+
._valid_to_gt(valid_datetime || datetime)
|
469
376
|
else
|
470
377
|
relation.tap { |relation| relation.without_valid_datetime unless ActiveRecord::Bitemporal.valid_datetime }
|
471
378
|
end
|
@@ -49,7 +49,8 @@ module ActiveRecord::Bitemporal
|
|
49
49
|
prev_valid_times.each do |valid_time|
|
50
50
|
headers.print('|', line: line, column: columns[valid_time])
|
51
51
|
end
|
52
|
-
|
52
|
+
valid_time_str = valid_time.kind_of?(Date) ? valid_time.strftime('%F') : valid_time.strftime('%F %T.%3N')
|
53
|
+
headers.print("| #{valid_time_str}", line: line, column: columns[valid_time])
|
53
54
|
prev_valid_times << valid_time
|
54
55
|
end
|
55
56
|
|
@@ -92,13 +93,14 @@ module ActiveRecord::Bitemporal
|
|
92
93
|
end
|
93
94
|
end
|
94
95
|
|
96
|
+
valid_label = valid_times[0].kind_of?(Date) ? 'valid_date' : 'valid_datetime'
|
95
97
|
transaction_label = 'transaction_datetime'
|
96
98
|
right_margin = time_length + 1 - transaction_label.size
|
97
99
|
|
98
100
|
label = if right_margin >= 0
|
99
|
-
"#{transaction_label + ' ' * right_margin}|
|
101
|
+
"#{transaction_label + ' ' * right_margin}| #{valid_label}"
|
100
102
|
else
|
101
|
-
"#{transaction_label[0...right_margin]}|
|
103
|
+
"#{transaction_label[0...right_margin]}| #{valid_label}"
|
102
104
|
end
|
103
105
|
|
104
106
|
"#{label}\n#{headers.to_s}\n#{body.to_s}"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-bitemporal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- SmartHR
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-05-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '6.
|
19
|
+
version: '6.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '6.
|
26
|
+
version: '6.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -159,9 +159,9 @@ files:
|
|
159
159
|
- bin/console
|
160
160
|
- bin/setup
|
161
161
|
- docker-compose.yml
|
162
|
-
- gemfiles/rails_6.0.gemfile
|
163
162
|
- gemfiles/rails_6.1.gemfile
|
164
163
|
- gemfiles/rails_7.0.gemfile
|
164
|
+
- gemfiles/rails_7.1.gemfile
|
165
165
|
- gemfiles/rails_main.gemfile
|
166
166
|
- lib/activerecord-bitemporal.rb
|
167
167
|
- lib/activerecord-bitemporal/bitemporal.rb
|
@@ -183,14 +183,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
183
183
|
requirements:
|
184
184
|
- - ">="
|
185
185
|
- !ruby/object:Gem::Version
|
186
|
-
version:
|
186
|
+
version: '3.0'
|
187
187
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
188
|
requirements:
|
189
189
|
- - ">="
|
190
190
|
- !ruby/object:Gem::Version
|
191
191
|
version: '0'
|
192
192
|
requirements: []
|
193
|
-
rubygems_version: 3.3.
|
193
|
+
rubygems_version: 3.3.27
|
194
194
|
signing_key:
|
195
195
|
specification_version: 4
|
196
196
|
summary: BiTemporal Data Model for ActiveRecord
|