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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff0157d808949658d0eb00a07b819670383ace1c7896537f6b6e5dfeda9e6c32
4
- data.tar.gz: 1e14b06aac74ca12b3db6ee75144078eef8e793eda6048c7179fd8ef3025b01d
3
+ metadata.gz: f0e6cafe3d918cd4bdf47c2610eaf3760cfcedbec0365a7675ef99790a05baaf
4
+ data.tar.gz: 79b7823949b22cbcacdfb75b561c70808135ebd3dc1c6a5ff0ef8152c75b8d79
5
5
  SHA512:
6
- metadata.gz: 6e6ba80c96e30d975d5a1fe5edff0f631e8e4793d98c97e0c859d57948f5919d5aa47ab2990a456712888e8e25913bb370fc0bf3640c9d04eef3686774a00370
7
- data.tar.gz: cd5d42d05eb0efe13355906b1547f86605aa1e327d1fae87aebb83475c4fe4162f2cba00875e92e6dcc497451d8a6c0bbe8bfffcbad543c972e5b229a05d0a60
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 appraisal << parameters.gemfile >> bundle install
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
- - rails-6.0
32
- - rails-6.1
33
- - rails-7.0
34
- - rails-main
33
+ - rails_6.1
34
+ - rails_7.0
35
+ - rails_7.1
36
+ - rails_main
35
37
  exclude:
36
- - ruby-version: '3.0'
37
- gemfile: rails-6.0
38
- - ruby-version: '3.1'
39
- gemfile: rails-6.0
38
+ - ruby-version: '3.2'
39
+ gemfile: rails_6.1
40
+ - ruby-version: '3.3'
41
+ gemfile: rails_6.1
@@ -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 = ">= 2.7.0"
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.0"
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"
@@ -3,6 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
- gem "rails", "~> 6.0.2"
6
+ gem "rails", "~> 7.1.0"
7
7
 
8
8
  gemspec path: "../"
@@ -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: Time.current)
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
- elsif Gem::Version.new("6.1.0") <= ActiveRecord.version
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
- # valdi_from を基準としてしまうと整合性が取れなくなってしまう
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 (record.valid_datetime && (record.valid_from..record.valid_to).cover?(record.valid_datetime)) == false && (record.persisted?)
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 each_operatable_node_6_0(nodes = predicates, &block)
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
- each_operatable_node_6_1(node.children) { |node| y << node }
60
+ each_operatable_node(node.children) { |node| y << node }
78
61
  when Arel::Nodes::Binary
79
- each_operatable_node_6_1(node.left) { |node| y << node }
80
- each_operatable_node_6_1(node.right) { |node| y << node }
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
- each_operatable_node_6_1(node.expr) { |node| y << node }
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
- if ActiveRecord.version < Gem::Version.new("6.1.0")
243
- module ActiveRecordRelationScope
244
- refine ::ActiveRecord::Relation do
245
- %i(valid_from valid_to transaction_from transaction_to).each { |column|
246
- module_eval <<-STR, __FILE__, __LINE__ + 1
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
- refine ::Hash do
287
- def equal_attribute_name(other)
288
- self[:where].equal_attribute_name(other)
289
- end
202
+ end
203
+ refine ::Hash do
204
+ def equal_attribute_name(other)
205
+ self[:where].equal_attribute_name(other)
290
206
  end
291
- refine ::Array do
292
- def equal_attribute_name(other)
293
- first.equal_attribute_name(other)
294
- end
207
+ end
208
+ refine ::Array do
209
+ def equal_attribute_name(other)
210
+ first.equal_attribute_name(other)
295
211
  end
296
- refine ::String do
297
- def equal_attribute_name(other)
298
- self == other.to_s
299
- end
212
+ end
213
+ refine ::String do
214
+ def equal_attribute_name(other)
215
+ self == other.to_s
300
216
  end
301
- refine ::Symbol do
302
- def equal_attribute_name(other)
303
- self.to_s == other.to_s
304
- end
217
+ end
218
+ refine ::Symbol do
219
+ def equal_attribute_name(other)
220
+ self.to_s == other.to_s
305
221
  end
306
- refine ::Arel::Attributes::Attribute do
307
- def equal_attribute_name(other)
308
- "#{relation.name}.#{name}" == other.to_s
309
- end
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
- refine ::ActiveRecord::Relation do
314
- using EqualAttributeName
315
- using NodeBitemporalInclude
230
+ refine ::ActiveRecord::Relation do
231
+ using EqualAttributeName
232
+ using NodeBitemporalInclude
316
233
 
317
- def bitemporal_rewhere_bind(attr_name, operator, value, table = self.table)
318
- rewhere(table[attr_name].public_send(operator, predicate_builder.build_bind_attribute(attr_name, value)))
319
- end
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
- %i(valid_from valid_to transaction_from transaction_to).each { |column|
322
- module_eval <<-STR, __FILE__, __LINE__ + 1
323
- def _ignore_#{column}
324
- unscope(where: :"\#{table.name}.#{column}")
325
- .tap { |relation| relation.unscope!(where: bitemporal_value[:through].arel_table["#{column}"]) if bitemporal_value[:through] }
326
- end
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
- def _except_#{column}
329
- return self unless where_clause.send(:predicates).find { |node|
330
- node.bitemporal_include?("\#{table.name}.#{column}")
331
- }
332
- _ignore_#{column}.tap { |relation|
333
- relation.unscope_values.reject! { |query| query.equal_attribute_name("\#{table.name}.#{column}") }
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
- end
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, without_ignore: true)
449
- ._transaction_to_gt(transaction_datetime || datetime, without_ignore: true)
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, without_ignore: true)
468
- ._valid_to_gt(valid_datetime || datetime, without_ignore: true)
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Bitemporal
5
- VERSION = "4.3.0"
5
+ VERSION = "5.0.1"
6
6
  end
7
7
  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
- headers.print("| #{valid_time.strftime('%F %T.%3N')}", line: line, column: columns[valid_time])
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}| valid_datetime"
101
+ "#{transaction_label + ' ' * right_margin}| #{valid_label}"
100
102
  else
101
- "#{transaction_label[0...right_margin]}| valid_datetime"
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.3.0
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: 2023-08-08 00:00:00.000000000 Z
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.0'
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.0'
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: 2.7.0
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.26
193
+ rubygems_version: 3.3.27
194
194
  signing_key:
195
195
  specification_version: 4
196
196
  summary: BiTemporal Data Model for ActiveRecord