activerecord-bitemporal 4.3.0 → 5.0.1

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
  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