activerecord-bitemporal 5.3.0 → 6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c660ad9554b7d5285a28f3efcd6a6c10e2b5e45b6922956e37f931ae807ba483
4
- data.tar.gz: 24646d6dc75344e11f613f70c7847639f8c86524ce3d1b178f4abb69dc60694f
3
+ metadata.gz: b36848b2facc997f9179abd32f96d7fde53cd9464f9009fa25a1ca5f13f57890
4
+ data.tar.gz: 8498da159a6e051841ce253b7051f0722b0cb33d2358fc13a1b3f5c0664cf1f7
5
5
  SHA512:
6
- metadata.gz: 39e0aea4e39482bcb929d0df586232413193f57a232ca7b2b928ca9aaef90d84fa88fc1edb925bcbff466864314beafa69e9caf36057ba7f4529019791d33698
7
- data.tar.gz: 84bc4e20042ffb77c2f317fcf6ce85b1b469edb338ec0a1346a9dd0008d1b01e49037503124778144521704ed97af904632bf91f424acc41448968d4beba0a5b
6
+ metadata.gz: bd8c531ad27a3ba0693d3923a00f62abb4b730251e235d0f3a78b449f2fdc7336052a4e5c0115748330e95a6f75eff2f20dcfc71d3fa1360d3d7e4c98c2b38af
7
+ data.tar.gz: fe72790fbcb1372f8127afe702cf2696f930c901aaa2b6243c913243b299a74917bca867d068e09039a6df001c942f7db81b0a3c64daa54a919bbdb4714de4ac
@@ -10,8 +10,8 @@ reviewers:
10
10
  - lighty
11
11
  - mkmn
12
12
  - osyo-manga
13
- - wata727
14
13
  - yono
14
+ - kumaie-shr
15
15
 
16
16
  # A list of keywords to be skipped the process that add reviewers if pull requests include it
17
17
  skipKeywords:
@@ -19,11 +19,11 @@ jobs:
19
19
  GEM_HOST_API_KEY: ${{ secrets.GEM_HOST_API_KEY }}
20
20
  GEM_HOST_OTP_CODE: ${{ github.event.inputs.rubygems-otp-code }}
21
21
  steps:
22
- - uses: actions/checkout@v4
22
+ - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
23
23
  with:
24
24
  fetch-depth: 0
25
25
 
26
- - uses: ruby/setup-ruby@v1
26
+ - uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
27
27
  with:
28
28
  ruby-version: '3.1'
29
29
  bundler-cache: true
@@ -15,19 +15,14 @@ jobs:
15
15
  fail-fast: false
16
16
  matrix:
17
17
  ruby-version:
18
- - '3.0'
19
18
  - '3.1'
20
19
  - '3.2'
21
20
  - '3.3'
21
+ - '3.4'
22
22
  gemfile:
23
- - rails_6.1
24
23
  - rails_7.0
25
24
  - rails_7.1
26
- exclude:
27
- - ruby-version: '3.2'
28
- gemfile: rails_6.1
29
- - ruby-version: '3.3'
30
- gemfile: rails_6.1
25
+ - rails_7.2
31
26
  services:
32
27
  postgres:
33
28
  image: postgres:14
@@ -45,9 +40,9 @@ jobs:
45
40
  BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
46
41
  steps:
47
42
  - name: Checkout
48
- uses: actions/checkout@v4
43
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
49
44
  - name: Setup Ruby
50
- uses: ruby/setup-ruby@v1
45
+ uses: ruby/setup-ruby@13e7a03dc3ac6c3798f4570bfead2aed4d96abfb # v1.244.0
51
46
  with:
52
47
  ruby-version: ${{ matrix.ruby-version }}
53
48
  bundler-cache: true
data/Appraisals CHANGED
@@ -1,13 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- appraise "rails-6.1" do
4
- gem "rails", "~> 6.1.0"
5
- end
6
-
7
3
  appraise "rails-7.0" do
8
4
  gem "rails", "~> 7.0.1"
5
+
6
+ # for Ruby 3.4
7
+ gem "base64"
8
+ gem "bigdecimal"
9
+ gem "mutex_m"
10
+
11
+ # NOTE: concurrent-ruby gem no longer loads the logger gem since v1.3.5.
12
+ # https://github.com/ruby-concurrency/concurrent-ruby/pull/1062
13
+ # https://github.com/rails/rails/pull/54264
14
+ gem "concurrent-ruby", "< 1.3.5"
9
15
  end
10
16
 
11
17
  appraise "rails-7.1" do
12
18
  gem "rails", "~> 7.1.0"
13
19
  end
20
+
21
+ appraise "rails-7.2" do
22
+ gem "rails", "~> 7.2.0"
23
+ end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # Changelog
2
2
 
3
+ ## 6.0.0
4
+
5
+ ### Breaking Changed
6
+
7
+ - [Add Ruby 3.4 and remove Ruby 3.0 in CI #185](https://github.com/kufu/activerecord-bitemporal/pull/185)
8
+ - [Drop support Rails 6.1 #192](https://github.com/kufu/activerecord-bitemporal/pull/192)
9
+
10
+ ### Added
11
+
12
+ - [CI against Rails 7.2 #164](https://github.com/kufu/activerecord-bitemporal/pull/164)
13
+ - [Support custom column names for valid time in .bitemporalize #200](https://github.com/kufu/activerecord-bitemporal/pull/200)
14
+
15
+ ### Changed
16
+
17
+ ### Deprecated
18
+
19
+ ### Removed
20
+
21
+ ### Fixed
22
+
23
+ - [Prevent where clauses from ignored by `ignore_valid_datetime` #190](https://github.com/kufu/activerecord-bitemporal/pull/190)
24
+
25
+ ### Chores
26
+
27
+ - [Add a note to the README that PostgreSQL is required to run the tests. #188](https://github.com/kufu/activerecord-bitemporal/pull/188)
28
+ - [Remove specs for Rails 5.x #191](https://github.com/kufu/activerecord-bitemporal/pull/191)
29
+ - [Update auto assgin member #193](https://github.com/kufu/activerecord-bitemporal/pull/193)
30
+ - [Pin GitHub Actions dependencies to specific commit hashes #194](https://github.com/kufu/activerecord-bitemporal/pull/194)
31
+ - [Bump ruby/setup-ruby from 1.227.0 to 1.229.0 #195](https://github.com/kufu/activerecord-bitemporal/pull/195)
32
+ - [Bump ruby/setup-ruby from 1.229.0 to 1.233.0 #197](https://github.com/kufu/activerecord-bitemporal/pull/197)
33
+ - [Bump ruby/setup-ruby from 1.233.0 to 1.235.0 #198](https://github.com/kufu/activerecord-bitemporal/pull/198)
34
+ - [Bump ruby/setup-ruby from 1.235.0 to 1.237.0 #199](https://github.com/kufu/activerecord-bitemporal/pull/199)
35
+ - [Bump ruby/setup-ruby from 1.237.0 to 1.238.0 #201](https://github.com/kufu/activerecord-bitemporal/pull/201)
36
+ - [Bump ruby/setup-ruby from 1.238.0 to 1.242.0 #202](https://github.com/kufu/activerecord-bitemporal/pull/202)
37
+ - [Bump ruby/setup-ruby from 1.242.0 to 1.244.0 #203](https://github.com/kufu/activerecord-bitemporal/pull/203)
38
+ - [Update auto assgin member #204](https://github.com/kufu/activerecord-bitemporal/pull/204)
39
+
3
40
  ## 5.3.0
4
41
 
5
42
  ### Added
data/README.md CHANGED
@@ -711,7 +711,7 @@ Employee.where(bitemporal_id: employee.bitemporal_id)
711
711
 
712
712
  ## Development
713
713
 
714
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
714
+ After checking out the repo, run `bin/setup` to install dependencies. And start PostgreSQL on port 5432. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
715
715
 
716
716
  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).
717
717
 
@@ -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 = ">= 3.0"
17
+ spec.required_ruby_version = ">= 3.1"
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.1"
26
+ spec.add_dependency "activerecord", ">= 7.0"
27
27
 
28
28
  spec.add_development_dependency "bundler"
29
29
  spec.add_development_dependency "rake", "~> 13.0"
@@ -4,5 +4,9 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
6
  gem "rails", "~> 7.0.1"
7
+ gem "base64"
8
+ gem "bigdecimal"
9
+ gem "mutex_m"
10
+ gem "concurrent-ruby", "< 1.3.5"
7
11
 
8
12
  gemspec path: "../"
@@ -3,6 +3,6 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
- gem "rails", "~> 6.1.0"
6
+ gem "rails", "~> 7.2.0"
7
7
 
8
8
  gemspec path: "../"
@@ -313,7 +313,7 @@ module ActiveRecord
313
313
  def _create_record(attribute_names = self.attribute_names)
314
314
  bitemporal_assign_initialize_value(valid_datetime: self.valid_datetime)
315
315
 
316
- ActiveRecord::Bitemporal.valid_at!(self.valid_from) {
316
+ ActiveRecord::Bitemporal.valid_at!(self[valid_from_key]) {
317
317
  super()
318
318
  }
319
319
  end
@@ -346,8 +346,8 @@ module ActiveRecord
346
346
  # update 後に新しく生成したインスタンスのデータを移行する
347
347
  @_swapped_id_previously_was = swapped_id
348
348
  @_swapped_id = after_instance.swapped_id
349
- self.valid_from = after_instance.valid_from
350
- self.valid_to = after_instance.valid_to
349
+ self[valid_from_key] = after_instance[valid_from_key]
350
+ self[valid_to_key] = after_instance[valid_to_key]
351
351
  self.transaction_from = after_instance.transaction_from
352
352
  self.transaction_to = after_instance.transaction_to
353
353
 
@@ -373,14 +373,14 @@ module ActiveRecord
373
373
  # force_update の場合は削除時の状態の履歴を残さない
374
374
  unless force_update?
375
375
  # 削除時の状態を履歴レコードとして保存する
376
- duplicated_instance.valid_to = target_datetime
376
+ duplicated_instance[valid_to_key] = target_datetime
377
377
  duplicated_instance.transaction_from = operated_at
378
378
  duplicated_instance.save_without_bitemporal_callbacks!(validate: false)
379
379
  if @destroyed
380
380
  @_swapped_id_previously_was = swapped_id
381
381
  @_swapped_id = duplicated_instance.swapped_id
382
- self.valid_from = duplicated_instance.valid_from
383
- self.valid_to = duplicated_instance.valid_to
382
+ self[valid_from_key] = duplicated_instance[valid_from_key]
383
+ self[valid_to_key] = duplicated_instance[valid_to_key]
384
384
  self.transaction_from = duplicated_instance.transaction_from
385
385
  self.transaction_to = duplicated_instance.transaction_to
386
386
  end
@@ -393,6 +393,7 @@ module ActiveRecord
393
393
  rescue => e
394
394
  @destroyed = false
395
395
  @_association_destroy_exception = ActiveRecord::RecordNotDestroyed.new("Failed to destroy the record: class=#{e.class}, message=#{e.message}", self)
396
+ @_association_destroy_exception.set_backtrace(e.backtrace)
396
397
  false
397
398
  end
398
399
 
@@ -411,55 +412,29 @@ module ActiveRecord
411
412
  module ::ActiveRecord::Persistence
412
413
  # MEMO: Must be override ActiveRecord::Persistence#reload
413
414
  alias_method :active_record_bitemporal_original_reload, :reload unless method_defined? :active_record_bitemporal_original_reload
414
- if Gem::Version.new("7.0.0.alpha") <= ActiveRecord.version
415
- def reload(options = nil)
416
- return active_record_bitemporal_original_reload(options) unless self.class.bi_temporal_model?
417
-
418
- self.class.connection.clear_query_cache
419
-
420
- fresh_object =
421
- ActiveRecord::Bitemporal.with_bitemporal_option(**bitemporal_option) {
422
- if apply_scoping?(options)
423
- _find_record(options)
424
- else
425
- self.class.unscoped { self.class.bitemporal_default_scope.scoping { _find_record(options) } }
426
- end
427
- }
415
+ def reload(options = nil)
416
+ return active_record_bitemporal_original_reload(options) unless self.class.bi_temporal_model?
428
417
 
429
- @association_cache = fresh_object.instance_variable_get(:@association_cache)
430
- @attributes = fresh_object.instance_variable_get(:@attributes)
431
- @new_record = false
432
- @previously_new_record = false
433
- # NOTE: Hook to copying swapped_id
434
- @_swapped_id_previously_was = nil
435
- @_swapped_id = fresh_object.swapped_id
436
- @previously_force_updated = false
437
- self
438
- end
439
- else
440
- def reload(options = nil)
441
- return active_record_bitemporal_original_reload(options) unless self.class.bi_temporal_model?
442
-
443
- self.class.connection.clear_query_cache
444
-
445
- fresh_object =
446
- ActiveRecord::Bitemporal.with_bitemporal_option(**bitemporal_option) {
447
- if options && options[:lock]
448
- self.class.unscoped { self.class.lock(options[:lock]).bitemporal_default_scope.find(id) }
449
- else
450
- self.class.unscoped { self.class.bitemporal_default_scope.find(id) }
451
- end
452
- }
418
+ self.class.connection.clear_query_cache
453
419
 
454
- @attributes = fresh_object.instance_variable_get(:@attributes)
455
- @new_record = false
456
- @previously_new_record = false
457
- # NOTE: Hook to copying swapped_id
458
- @_swapped_id_previously_was = nil
459
- @_swapped_id = fresh_object.swapped_id
460
- @previously_force_updated = false
461
- self
462
- end
420
+ fresh_object =
421
+ ActiveRecord::Bitemporal.with_bitemporal_option(**bitemporal_option) {
422
+ if apply_scoping?(options)
423
+ _find_record(options)
424
+ else
425
+ self.class.unscoped { self.class.bitemporal_default_scope.scoping { _find_record(options) } }
426
+ end
427
+ }
428
+
429
+ @association_cache = fresh_object.instance_variable_get(:@association_cache)
430
+ @attributes = fresh_object.instance_variable_get(:@attributes)
431
+ @new_record = false
432
+ @previously_new_record = false
433
+ # NOTE: Hook to copying swapped_id
434
+ @_swapped_id_previously_was = nil
435
+ @_swapped_id = fresh_object.swapped_id
436
+ @previously_force_updated = false
437
+ self
463
438
  end
464
439
  end
465
440
 
@@ -467,7 +442,7 @@ module ActiveRecord
467
442
 
468
443
  def bitemporal_assign_initialize_value(valid_datetime:, current_time: Time.current)
469
444
  # 自身の `valid_from` を設定
470
- self.valid_from = valid_datetime || current_time if self.valid_from == ActiveRecord::Bitemporal::DEFAULT_VALID_FROM
445
+ self[valid_from_key] = valid_datetime || current_time if self[valid_from_key] == ActiveRecord::Bitemporal::DEFAULT_VALID_FROM
471
446
 
472
447
  self.transaction_from = current_time if self.transaction_from == ActiveRecord::Bitemporal::DEFAULT_TRANSACTION_FROM
473
448
 
@@ -485,7 +460,7 @@ module ActiveRecord
485
460
  def bitemporal_build_update_records(valid_datetime:, current_time: Time.current, force_update: false)
486
461
  target_datetime = valid_datetime || current_time
487
462
  # NOTE: force_update の場合は自身のレコードを取得するような時間を指定しておく
488
- target_datetime = valid_from_changed? ? valid_from_was : valid_from if force_update
463
+ target_datetime = attribute_changed?(valid_from_key) ? attribute_was(valid_from_key) : self[valid_from_key] if force_update
489
464
 
490
465
  # 対象基準日において有効なレコード
491
466
  # NOTE: 論理削除対象
@@ -516,26 +491,26 @@ module ActiveRecord
516
491
  current_valid_record.assign_transaction_to(current_time)
517
492
 
518
493
  # 以前の履歴データは valid_to を詰めて保存
519
- before_instance.valid_to = target_datetime
494
+ before_instance[valid_to_key] = target_datetime
520
495
  if before_instance.valid_from_cannot_be_greater_equal_than_valid_to
521
- raise ValidDatetimeRangeError.new("valid_from #{before_instance.valid_from} can't be greater equal than valid_to #{before_instance.valid_to}")
496
+ raise ValidDatetimeRangeError.new("#{valid_from_key} #{before_instance[valid_from_key]} can't be greater equal than #{valid_to_key} #{before_instance[valid_to_key]}")
522
497
  end
523
498
  before_instance.transaction_from = current_time
524
499
 
525
500
  # 以降の履歴データは valid_from と valid_to を調整して保存する
526
- after_instance.valid_from = target_datetime
527
- after_instance.valid_to = current_valid_record.valid_to
501
+ after_instance[valid_from_key] = target_datetime
502
+ after_instance[valid_to_key] = current_valid_record[valid_to_key]
528
503
  if after_instance.valid_from_cannot_be_greater_equal_than_valid_to
529
- raise ValidDatetimeRangeError.new("valid_from #{after_instance.valid_from} can't be greater equal than valid_to #{after_instance.valid_to}")
504
+ raise ValidDatetimeRangeError.new("#{valid_from_key} #{after_instance[valid_from_key]} can't be greater equal than #{valid_to_key} #{after_instance[valid_to_key]}")
530
505
  end
531
506
  after_instance.transaction_from = current_time
532
507
 
533
508
  # 有効なレコードがない場合
534
509
  else
535
510
  # 一番近い未来にある Instance を取ってきて、その valid_from を valid_to に入れる
536
- nearest_instance = self.class.where(bitemporal_id: bitemporal_id).valid_from_gt(target_datetime).ignore_valid_datetime.order(valid_from: :asc).first
511
+ nearest_instance = self.class.where(bitemporal_id: bitemporal_id).ignore_valid_datetime.valid_from_gt(target_datetime).order(valid_from_key => :asc).first
537
512
  if nearest_instance.nil?
538
- message = "Update failed: Couldn't find #{self.class} with 'bitemporal_id'=#{self.bitemporal_id} and 'valid_from' < #{target_datetime}"
513
+ message = "Update failed: Couldn't find #{self.class} with 'bitemporal_id'=#{self.bitemporal_id} and '#{valid_from_key}' > #{target_datetime}"
539
514
  raise ActiveRecord::RecordNotFound.new(message, self.class, "bitemporal_id", self.bitemporal_id)
540
515
  end
541
516
 
@@ -546,8 +521,8 @@ module ActiveRecord
546
521
  before_instance = nil
547
522
 
548
523
  # 以降の履歴データは valid_from と valid_to を調整して保存する
549
- after_instance.valid_from = target_datetime
550
- after_instance.valid_to = nearest_instance.valid_from
524
+ after_instance[valid_from_key] = target_datetime
525
+ after_instance[valid_to_key] = nearest_instance[valid_from_key]
551
526
  after_instance.transaction_from = current_time
552
527
  end
553
528
 
@@ -569,7 +544,7 @@ module ActiveRecord
569
544
 
570
545
  target_datetime = record.valid_datetime || Time.current
571
546
 
572
- valid_from = record.valid_from.yield_self { |valid_from|
547
+ valid_from = record[record.valid_from_key].yield_self { |valid_from|
573
548
  # NOTE: valid_from が初期値の場合は現在の時間を基準としてバリデーションする
574
549
  # valid_from が初期値の場合は Persistence#_create_record に Time.current が割り当てられる為
575
550
  # バリデーション時と生成時で若干時間がずれてしまうことには考慮する
@@ -586,17 +561,17 @@ module ActiveRecord
586
561
  }
587
562
 
588
563
  # MEMO: `force_update` does not refer to `valid_datetime`
589
- valid_from = record.valid_from if record.force_update?
564
+ valid_from = record[record.valid_from_key] if record.force_update?
590
565
 
591
- valid_to = record.valid_to.yield_self { |valid_to|
566
+ valid_to = record[record.valid_to_key].yield_self { |valid_to|
592
567
  # NOTE: `cover?` may give incorrect results, when the time zone is not UTC and `valid_from` is date type
593
568
  # Therefore, cast to type of `valid_from`
594
- record_valid_time = finder_class.type_for_attribute(:valid_from).cast(record.valid_datetime)
569
+ record_valid_time = finder_class.type_for_attribute(record.valid_from_key).cast(record.valid_datetime)
595
570
  # レコードを更新する時に valid_datetime が valid_from ~ valid_to の範囲外だった場合、
596
571
  # 一番近い未来の履歴レコードを参照して更新する
597
572
  # という仕様があるため、それを考慮して valid_to を設定する
598
- if (record_valid_time && (record.valid_from...record.valid_to).cover?(record_valid_time)) == false && (record.persisted?)
599
- finder_class.ignore_valid_datetime.where(bitemporal_id: record.bitemporal_id).valid_from_gteq(target_datetime).order(valid_from: :asc).first.valid_from
573
+ if (record_valid_time && (record[record.valid_from_key]...record[record.valid_to_key]).cover?(record_valid_time)) == false && (record.persisted?)
574
+ finder_class.ignore_valid_datetime.where(bitemporal_id: record.bitemporal_id).valid_from_gteq(target_datetime).order(record.valid_from_key => :asc).first[record.valid_from_key]
600
575
  else
601
576
  valid_to
602
577
  end
@@ -86,9 +86,9 @@ module ActiveRecord::Bitemporal
86
86
 
87
87
  refine Relation do
88
88
  def bitemporal_clause(table_name = klass.table_name)
89
- node_hash = where_clause.bitemporal_query_hash("valid_from", "valid_to", "transaction_from", "transaction_to")
90
- valid_from = node_hash.dig(table_name, "valid_from", 1)
91
- valid_to = node_hash.dig(table_name, "valid_to", 1)
89
+ node_hash = where_clause.bitemporal_query_hash(valid_from_key, valid_to_key, "transaction_from", "transaction_to")
90
+ valid_from = node_hash.dig(table_name, valid_from_key, 1)
91
+ valid_to = node_hash.dig(table_name, valid_to_key, 1)
92
92
  transaction_from = node_hash.dig(table_name, "transaction_from", 1)
93
93
  transaction_to = node_hash.dig(table_name, "transaction_to", 1)
94
94
  {
@@ -255,19 +255,24 @@ module ActiveRecord::Bitemporal
255
255
  rewhere(table[attr_name].public_send(operator, predicate_builder.build_bind_attribute(attr_name, value)))
256
256
  end
257
257
 
258
- %i(valid_from valid_to transaction_from transaction_to).each { |column|
258
+ [
259
+ [:valid_from, "\#{valid_from_key}"], # Evaluate `valid_from/to_key` at runtime using `\#`
260
+ [:valid_to, "\#{valid_to_key}"],
261
+ [:transaction_from, "transaction_from"],
262
+ [:transaction_to, "transaction_to"]
263
+ ].each { |column, column_name|
259
264
  module_eval <<-STR, __FILE__, __LINE__ + 1
260
265
  def _ignore_#{column}
261
- unscope(where: :"\#{table.name}.#{column}")
262
- .tap { |relation| relation.unscope!(where: bitemporal_value[:through].arel_table["#{column}"]) if bitemporal_value[:through] }
266
+ unscope(where: :"\#{table.name}.#{column_name}")
267
+ .tap { |relation| relation.unscope!(where: bitemporal_value[:through].arel_table["#{column_name}"]) if bitemporal_value[:through] }
263
268
  end
264
269
 
265
270
  def _except_#{column}
266
271
  return self unless where_clause.send(:predicates).find { |node|
267
- node.bitemporal_include?("\#{table.name}.#{column}")
272
+ node.bitemporal_include?("\#{table.name}.#{column_name}")
268
273
  }
269
274
  _ignore_#{column}.tap { |relation|
270
- relation.unscope_values.reject! { |query| query.equal_attribute_name("\#{table.name}.#{column}") }
275
+ relation.unscope_values.reject! { |query| query.equal_attribute_name("\#{table.name}.#{column_name}") }
271
276
  }
272
277
  end
273
278
  STR
@@ -281,8 +286,8 @@ module ActiveRecord::Bitemporal
281
286
  module_eval <<-STR, __FILE__, __LINE__ + 1
282
287
  def _#{column}_#{op}(datetime)
283
288
  target_datetime = datetime&.in_time_zone || Time.current
284
- bitemporal_rewhere_bind("#{column}", :#{op}, target_datetime)
285
- .tap { |relation| break relation.bitemporal_rewhere_bind("#{column}", :#{op}, target_datetime, bitemporal_value[:through].arel_table) if bitemporal_value[:through] }
289
+ bitemporal_rewhere_bind("#{column_name}", :#{op}, target_datetime)
290
+ .tap { |relation| break relation.bitemporal_rewhere_bind("#{column_name}", :#{op}, target_datetime, bitemporal_value[:through].arel_table) if bitemporal_value[:through] }
286
291
  end
287
292
  STR
288
293
  }
@@ -428,17 +433,17 @@ module ActiveRecord::Bitemporal
428
433
  # beginless range
429
434
  if begin_
430
435
  # from < valid_to
431
- relation = relation.bitemporal_where_bind("valid_to", :gt, begin_.in_time_zone.to_datetime)
436
+ relation = relation.bitemporal_where_bind(valid_to_key, :gt, begin_.in_time_zone.to_datetime)
432
437
  end
433
438
 
434
439
  # endless range
435
440
  if end_
436
441
  if range.exclude_end?
437
442
  # valid_from < to
438
- relation = relation.bitemporal_where_bind("valid_from", :lt, end_.in_time_zone.to_datetime)
443
+ relation = relation.bitemporal_where_bind(valid_from_key, :lt, end_.in_time_zone.to_datetime)
439
444
  else
440
445
  # valid_from <= to
441
- relation = relation.bitemporal_where_bind("valid_from", :lteq, end_.in_time_zone.to_datetime)
446
+ relation = relation.bitemporal_where_bind(valid_from_key, :lteq, end_.in_time_zone.to_datetime)
442
447
  end
443
448
  end
444
449
 
@@ -453,14 +458,14 @@ module ActiveRecord::Bitemporal
453
458
  begin_, end_ = range.begin, range.end
454
459
 
455
460
  if begin_
456
- relation = relation.bitemporal_where_bind("valid_from", :gteq, begin_.in_time_zone.to_datetime)
461
+ relation = relation.bitemporal_where_bind(valid_from_key, :gteq, begin_.in_time_zone.to_datetime)
457
462
  end
458
463
 
459
464
  if end_
460
465
  if range.exclude_end?
461
466
  raise 'Range with excluding end is not supported'
462
467
  else
463
- relation = relation.bitemporal_where_bind("valid_to", :lteq, end_.in_time_zone.to_datetime)
468
+ relation = relation.bitemporal_where_bind(valid_to_key, :lteq, end_.in_time_zone.to_datetime)
464
469
  end
465
470
  end
466
471
 
@@ -476,10 +481,10 @@ module ActiveRecord::Bitemporal
476
481
  ignore_valid_datetime.bitemporal_for(*ids)
477
482
  }
478
483
  def self.bitemporal_most_future(id)
479
- bitemporal_histories(id).order(valid_from: :asc).last
484
+ bitemporal_histories(id).order(valid_from_key => :asc).last
480
485
  end
481
486
  def self.bitemporal_most_past(id)
482
- bitemporal_histories(id).order(valid_from: :asc).first
487
+ bitemporal_histories(id).order(valid_from_key => :asc).first
483
488
  end
484
489
  end
485
490
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ActiveRecord
4
4
  module Bitemporal
5
- VERSION = "5.3.0"
5
+ VERSION = "6.0.0"
6
6
  end
7
7
  end
@@ -22,7 +22,7 @@ module ActiveRecord::Bitemporal
22
22
  module_function
23
23
 
24
24
  def visualize(record, height: 10, width: 40, highlight: true)
25
- histories = record.class.ignore_bitemporal_datetime.bitemporal_for(record).order(:transaction_from, :valid_from)
25
+ histories = record.class.ignore_bitemporal_datetime.bitemporal_for(record).order(:transaction_from, record.valid_from_key)
26
26
 
27
27
  if highlight
28
28
  visualize_records(histories, [record], height: height, width: width)
@@ -36,7 +36,7 @@ module ActiveRecord::Bitemporal
36
36
  raise 'More than 3 relations are not supported' if relations.size >= 3
37
37
  records = relations.flatten
38
38
 
39
- valid_times = (records.map(&:valid_from) + records.map(&:valid_to)).sort.uniq
39
+ valid_times = (records.map { _1[_1.valid_from_key] } + records.map { _1[_1.valid_to_key] }).sort.uniq
40
40
  transaction_times = (records.map(&:transaction_from) + records.map(&:transaction_to)).sort.uniq
41
41
 
42
42
  time_length = Time.zone.now.strftime('%F %T.%3N').length
@@ -60,9 +60,11 @@ module ActiveRecord::Bitemporal
60
60
 
61
61
  relation.each do |record|
62
62
  line = lines[record.transaction_from]
63
- column = columns[record.valid_from]
63
+ valid_from = record[record.valid_from_key]
64
+ valid_to = record[record.valid_to_key]
65
+ column = columns[valid_from]
64
66
 
65
- width = columns[record.valid_to] - columns[record.valid_from] - 1
67
+ width = columns[valid_to] - columns[valid_from] - 1
66
68
  height = lines[record.transaction_to] - lines[record.transaction_from] - 1
67
69
 
68
70
  body.print("#{record.transaction_from.strftime('%F %T.%3N')} ", line: line)
@@ -92,8 +92,8 @@ module ActiveRecord::Bitemporal::Bitemporalize
92
92
  end
93
93
 
94
94
  def valid_from_cannot_be_greater_equal_than_valid_to
95
- if valid_from && valid_to && valid_from >= valid_to
96
- errors.add(:valid_from, "can't be greater equal than valid_to")
95
+ if self[valid_from_key] && self[valid_to_key] && self[valid_from_key] >= self[valid_to_key]
96
+ errors.add(valid_from_key, "can't be greater equal than #{valid_to_key}")
97
97
  end
98
98
  end
99
99
 
@@ -107,10 +107,15 @@ module ActiveRecord::Bitemporal::Bitemporalize
107
107
  def bitemporalize(
108
108
  enable_strict_by_validates_bitemporal_id: false,
109
109
  enable_default_scope: true,
110
- enable_merge_with_except_bitemporal_default_scope: false
110
+ enable_merge_with_except_bitemporal_default_scope: false,
111
+ valid_from_key: :valid_from,
112
+ valid_to_key: :valid_to
111
113
  )
114
+ return if ancestors.include? InstanceMethods
115
+
112
116
  extend ClassMethods
113
117
  include InstanceMethods
118
+ include ActiveRecord::Bitemporal
114
119
  include ActiveRecord::Bitemporal::Scope
115
120
  include ActiveRecord::Bitemporal::Callbacks
116
121
 
@@ -136,8 +141,11 @@ module ActiveRecord::Bitemporal::Bitemporalize
136
141
  @previously_force_updated = false
137
142
  end
138
143
 
139
- attribute :valid_from, default: ActiveRecord::Bitemporal::DEFAULT_VALID_FROM
140
- attribute :valid_to, default: ActiveRecord::Bitemporal::DEFAULT_VALID_TO
144
+ self.class_attribute :valid_from_key, :valid_to_key, instance_writer: false
145
+ self.valid_from_key = valid_from_key.to_s
146
+ self.valid_to_key = valid_to_key.to_s
147
+ attribute valid_from_key, default: ActiveRecord::Bitemporal::DEFAULT_VALID_FROM
148
+ attribute valid_to_key, default: ActiveRecord::Bitemporal::DEFAULT_VALID_TO
141
149
  attribute :transaction_from, default: ActiveRecord::Bitemporal::DEFAULT_TRANSACTION_FROM
142
150
  attribute :transaction_to, default: ActiveRecord::Bitemporal::DEFAULT_TRANSACTION_TO
143
151
 
@@ -147,8 +155,8 @@ module ActiveRecord::Bitemporal::Bitemporalize
147
155
  })
148
156
 
149
157
  # validations
150
- validates :valid_from, presence: true
151
- validates :valid_to, presence: true
158
+ validates valid_from_key, presence: true
159
+ validates valid_to_key, presence: true
152
160
  validates :transaction_from, presence: true
153
161
  validates :transaction_to, presence: true
154
162
  validate :valid_from_cannot_be_greater_equal_than_valid_to
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: 5.3.0
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SmartHR
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-01-16 00:00:00.000000000 Z
11
+ date: 2025-06-02 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.1'
19
+ version: '7.0'
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.1'
26
+ version: '7.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -146,9 +146,9 @@ files:
146
146
  - bin/console
147
147
  - bin/setup
148
148
  - compose.yml
149
- - gemfiles/rails_6.1.gemfile
150
149
  - gemfiles/rails_7.0.gemfile
151
150
  - gemfiles/rails_7.1.gemfile
151
+ - gemfiles/rails_7.2.gemfile
152
152
  - lib/activerecord-bitemporal.rb
153
153
  - lib/activerecord-bitemporal/bitemporal.rb
154
154
  - lib/activerecord-bitemporal/callbacks.rb
@@ -161,7 +161,7 @@ homepage: https://github.com/kufu/activerecord-bitemporal
161
161
  licenses:
162
162
  - Apache 2.0
163
163
  metadata: {}
164
- post_install_message:
164
+ post_install_message:
165
165
  rdoc_options: []
166
166
  require_paths:
167
167
  - lib
@@ -169,7 +169,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
169
169
  requirements:
170
170
  - - ">="
171
171
  - !ruby/object:Gem::Version
172
- version: '3.0'
172
+ version: '3.1'
173
173
  required_rubygems_version: !ruby/object:Gem::Requirement
174
174
  requirements:
175
175
  - - ">="
@@ -177,7 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
177
177
  version: '0'
178
178
  requirements: []
179
179
  rubygems_version: 3.3.27
180
- signing_key:
180
+ signing_key:
181
181
  specification_version: 4
182
182
  summary: BiTemporal Data Model for ActiveRecord
183
183
  test_files: []