sequel_bitemporal 0.9.0 → 0.9.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: 4f44bf401ad71c80c9815ff7d2e3508edf8e5bdbef4112b36bf86d06a6d02523
4
- data.tar.gz: 19b320461ebbdac3b2e7ace0117ffa2921180dd602b59e5145d2c1771987d993
3
+ metadata.gz: 7f6daa2d7f025cd1281e8cbfc7235d0a6ddd85d2251f8d9195d85cc5340aafb3
4
+ data.tar.gz: 5d5de257ee011436a1c3959206c31c985d6b11597d63fcab468876865394f9ee
5
5
  SHA512:
6
- metadata.gz: 1e9928807145999a4ba2215b10e3169bb26e63bc42137c28b9fc05ad6ac9a2e66f10c69ccdda40ae1ae8d7bbfabad0f1f921122fc3e0bb155da559b335ffa97f
7
- data.tar.gz: a7fac94af384e4478fd9d6f98a6381bf03278e1310d8d97dff5bea449f2e3c5baeb962e3552774535a14b0a021a5b0ce22d76b659b08f7fcf9fe9a17a36d31dc
6
+ metadata.gz: '0309ac260a37ec550e417efb01eaa72120583a5c26c6306f52c15910d36c8dc24f9e74d39319f763e3a566192ddd5887b0b022ce747f820beee388a444726dc8'
7
+ data.tar.gz: f4f61ba42c6510bcc744f96a27ca9a91fe965762ce4ec6206720441346ec1e5402475e27e87a7b838d342898c47df99a1e8025abf5ebce59691250417bc0015f
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.3.1
1
+ 2.5.3
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  sequel_bitemporal
2
2
  =================
3
3
 
4
- [![Build Status](https://travis-ci.org/TalentBox/sequel_bitemporal.png?branch=master)](https://travis-ci.org/TalentBox/sequel_bitemporal)
4
+ [![Build Status](https://travis-ci.org/TalentBox/sequel_bitemporal.svg?branch=master)](https://travis-ci.org/TalentBox/sequel_bitemporal)
5
5
 
6
- Bitemporal versioning for sequel.
6
+ Bitemporal versioning for [Sequel].
7
7
 
8
8
  Dependencies
9
9
  ------------
@@ -47,7 +47,12 @@ Thanks to Evgeniy L (@fiscal-cliff) for his contributions:
47
47
  Thanks to Ksenia Zalesnaya (@ksenia-zalesnaya) for her contributions:
48
48
  - define setter methods for versioned columns
49
49
 
50
+ Thanks to Denis Kalesnikov (@DenisKem) for his contributions:
51
+ - allow composite primary key
52
+
50
53
  License
51
54
  -------
52
55
 
53
56
  sequel_bitemporal is Copyright © 2011 TalentBox SA. It is free software, and may be redistributed under the terms specified in the LICENSE file.
57
+
58
+ [Sequel]: http://sequel.jeremyevans.net/
data/Rakefile CHANGED
@@ -3,4 +3,4 @@ require "rspec/core/rake_task"
3
3
  RSpec::Core::RakeTask.new("spec").tap do |config|
4
4
  config.rspec_opts = "--color"
5
5
  end
6
- task :default => :spec
6
+ task :default => :spec
@@ -31,19 +31,25 @@ module Sequel
31
31
  Thread.current[THREAD_NOW_KEY] || DateTime.now
32
32
  end
33
33
 
34
- def self.bitemporal_version_columns
35
- @bitemporal_version_columns ||= [:master_id, :valid_from, :valid_to, :created_at, :expired_at]
34
+ def self.version_foreign_keys(master = nil)
35
+ return :master_id unless master
36
+ primary_key = [*master.primary_key]
37
+ primary_key.size > 1 ? primary_key : :master_id
36
38
  end
37
39
 
38
- def self.bitemporal_excluded_columns
39
- @bitemporal_excluded_columns ||= [:id, *bitemporal_version_columns]
40
+ def self.bitemporal_version_columns(master = nil)
41
+ [*version_foreign_keys(master), :valid_from, :valid_to, :created_at, :expired_at]
42
+ end
43
+
44
+ def self.bitemporal_excluded_columns(master = nil)
45
+ [:id, *bitemporal_version_columns(master)]
40
46
  end
41
47
 
42
48
  def self.configure(master, opts = {})
43
49
  version = opts[:version_class]
44
50
  raise Error, "please specify version class to use for bitemporal plugin" unless version
45
51
  return version.db.log_info("Version table does not exist for #{version.name}") unless version.db.table_exists?(version.table_name)
46
- missing = bitemporal_version_columns - version.columns
52
+ missing = bitemporal_version_columns(master) - version.columns
47
53
  raise Error, "bitemporal plugin requires the following missing column#{"s" if missing.size>1} on version class: #{missing.join(", ")}" unless missing.empty?
48
54
 
49
55
  if Sequel::Plugins::Bitemporal.jdbc?(master.db)
@@ -76,7 +82,7 @@ module Sequel
76
82
  @audit_updated_by_method = opts.fetch(:audit_updated_by_method){ :updated_by }
77
83
  @propagate_per_column = opts.fetch(:propagate_per_column, false)
78
84
  @version_uses_string_nilifier = version.plugins.map(&:to_s).include? "Sequel::Plugins::StringNilifier"
79
- @excluded_columns = Sequel::Plugins::Bitemporal.bitemporal_excluded_columns
85
+ @excluded_columns = Sequel::Plugins::Bitemporal.bitemporal_excluded_columns(master)
80
86
  @excluded_columns += Array opts[:excluded_columns] if opts[:excluded_columns]
81
87
  @use_ranges = if opts[:ranges]
82
88
  db = self.db
@@ -100,8 +106,8 @@ module Sequel
100
106
  end
101
107
  end
102
108
  end
103
- master.one_to_many :versions, class: version, key: :master_id, graph_alias_base: master.versions_alias
104
- master.one_to_one :current_version, class: version, key: :master_id, graph_alias_base: master.current_version_alias, :graph_block=>(proc do |j, lj, js|
109
+ master.one_to_many :versions, class: version, key: version_foreign_keys(master), graph_alias_base: master.versions_alias
110
+ master.one_to_one :current_version, class: version, key: version_foreign_keys(master), graph_alias_base: master.current_version_alias, :graph_block=>(proc do |j, lj, js|
105
111
  t = Sequel.delay{ ::Sequel::Plugins::Bitemporal.point_in_time }
106
112
  n = Sequel.delay{ ::Sequel::Plugins::Bitemporal.now }
107
113
  if master.use_ranges
@@ -135,7 +141,7 @@ module Sequel
135
141
  )
136
142
  )
137
143
  end
138
- master.one_to_many :current_or_future_versions, class: version, key: :master_id, :graph_block=>(proc do |j, lj, js|
144
+ master.one_to_many :current_or_future_versions, class: version, key: version_foreign_keys(master), :graph_block=>(proc do |j, lj, js|
139
145
  t = Sequel.delay{ ::Sequel::Plugins::Bitemporal.point_in_time }
140
146
  n = Sequel.delay{ ::Sequel::Plugins::Bitemporal.now }
141
147
  if master.use_ranges
@@ -169,7 +175,7 @@ module Sequel
169
175
  Sequel.negate(Sequel.qualify(:current_or_future_versions, :id) => nil)
170
176
  )
171
177
  end
172
- version.many_to_one :master, class: master, key: :master_id
178
+ version.many_to_one :master, class: master, key: version_foreign_keys(master)
173
179
  version.class_eval do
174
180
  if Sequel::Plugins::Bitemporal.jdbc?(master.db)
175
181
  plugin :typecast_on_load, *columns
@@ -319,7 +325,13 @@ module Sequel
319
325
 
320
326
  def attributes=(attributes)
321
327
  @pending_version ||= begin
322
- current_attributes = {master_id: id}
328
+ current_attributes =
329
+ if composite_primary_key?
330
+ version_values
331
+ else
332
+ { master_id: id }
333
+ end
334
+
323
335
  current_version.keys.each do |key|
324
336
  next if excluded_columns.include? key
325
337
  current_attributes[key] = current_version.send key
@@ -329,6 +341,10 @@ module Sequel
329
341
  pending_version.set_all attributes
330
342
  end
331
343
 
344
+ def version_values
345
+ version_foreign_keys.map { |k| [k, public_send(k)] }.to_h
346
+ end
347
+
332
348
  def update_attributes(attributes={})
333
349
  self.attributes = attributes
334
350
  if save raise_on_failure: false
@@ -364,6 +380,10 @@ module Sequel
364
380
  _refresh_set_values @values
365
381
  end
366
382
 
383
+ def composite_primary_key?
384
+ [*primary_key].size > 1
385
+ end
386
+
367
387
  def destroy
368
388
  point_in_time = ::Sequel::Plugins::Bitemporal.point_in_time
369
389
  versions_dataset.where(
@@ -471,6 +491,10 @@ module Sequel
471
491
  @propagated_during_last_save ||= []
472
492
  end
473
493
 
494
+ def version_foreign_keys
495
+ composite_primary_key? ? primary_key : :master_id
496
+ end
497
+
474
498
  private
475
499
 
476
500
  def prepare_pending_version
@@ -608,7 +632,7 @@ module Sequel
608
632
  columns.detect do |column|
609
633
  new_value = pending_version.send column
610
634
  case column
611
- when :id, :master_id, :created_at, :expired_at
635
+ when :id, :created_at, :expired_at, *version_foreign_keys
612
636
  false
613
637
  when :valid_from
614
638
  pending_version.values.has_key?(:valid_from) && (
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "sequel_bitemporal"
6
- s.version = "0.9.0"
6
+ s.version = "0.9.1"
7
7
  s.authors = ["Joseph HALTER", "Jonathan TRON"]
8
8
  s.email = ["joseph.halter@thetalentbox.com", "jonathan.tron@thetalentbox.com"]
9
9
  s.homepage = "https://github.com/TalentBox/sequel_bitemporal"
@@ -1,6 +1,6 @@
1
1
  require "spec_helper"
2
2
 
3
- describe "Sequel::Plugins::Bitemporal" do
3
+ RSpec.describe "Sequel::Plugins::Bitemporal" do
4
4
  before :all do
5
5
  db_setup
6
6
  end
@@ -791,7 +791,7 @@ describe "Sequel::Plugins::Bitemporal" do
791
791
  end
792
792
  end
793
793
 
794
- describe "Sequel::Plugins::Bitemporal", "with audit" do
794
+ RSpec.describe "Sequel::Plugins::Bitemporal", "with audit" do
795
795
  before :all do
796
796
  @audit_class = Class.new do
797
797
  def self.audit(*args); end
@@ -889,7 +889,7 @@ describe "Sequel::Plugins::Bitemporal", "with audit" do
889
889
  end
890
890
  end
891
891
  end
892
- describe "Sequel::Plugins::Bitemporal", "with audit, specifying how to get the author" do
892
+ RSpec.describe "Sequel::Plugins::Bitemporal", "with audit, specifying how to get the author" do
893
893
  before :all do
894
894
  @audit_class = Class.new do
895
895
  def self.audit(*args); end
@@ -1,6 +1,6 @@
1
1
  require "spec_helper"
2
2
  if DbHelpers.pg?
3
- describe "Sequel::Plugins::Bitemporal", "with ranges" do
3
+ RSpec.describe "Sequel::Plugins::Bitemporal", "with ranges" do
4
4
  before :all do
5
5
  db_setup ranges: true
6
6
  end
@@ -637,7 +637,7 @@ if DbHelpers.pg?
637
637
  end
638
638
  end
639
639
 
640
- describe "Sequel::Plugins::Bitemporal", "with audit and ranges" do
640
+ RSpec.describe "Sequel::Plugins::Bitemporal", "with audit and ranges" do
641
641
  before :all do
642
642
  @audit_class = Class.new do
643
643
  def self.audit(*args); end
@@ -735,7 +735,7 @@ if DbHelpers.pg?
735
735
  end
736
736
  end
737
737
  end
738
- describe "Sequel::Plugins::Bitemporal", "with audit, ranges, specifying how to get the author" do
738
+ RSpec.describe "Sequel::Plugins::Bitemporal", "with audit, ranges, specifying how to get the author" do
739
739
  before :all do
740
740
  @audit_class = Class.new do
741
741
  def self.audit(*args); end
@@ -1,7 +1,7 @@
1
1
  require "spec_helper"
2
2
  require "json"
3
3
 
4
- describe "Sequel::Plugins::Bitemporal", :skip_jdbc_sqlite do
4
+ RSpec.describe "Sequel::Plugins::Bitemporal", :skip_jdbc_sqlite do
5
5
  before :all do
6
6
  db_setup
7
7
  @version_class.instance_eval do
@@ -1,6 +1,6 @@
1
1
  require "spec_helper"
2
2
 
3
- describe "Sequel::Plugins::Bitemporal" do
3
+ RSpec.describe "Sequel::Plugins::Bitemporal" do
4
4
  let(:hour){ 3600 }
5
5
  before :all do
6
6
  db_setup use_time: true
@@ -381,7 +381,7 @@ describe "Sequel::Plugins::Bitemporal" do
381
381
  expect(@master_class.with_current_or_future_versions.all.size).to eq(2)
382
382
  end
383
383
  end
384
- describe "Sequel::Plugins::Bitemporal", "with audit" do
384
+ RSpec.describe "Sequel::Plugins::Bitemporal", "with audit" do
385
385
  before :all do
386
386
  @audit_class = Class.new
387
387
  db_setup use_time: true, audit_class: @audit_class
@@ -435,7 +435,7 @@ describe "Sequel::Plugins::Bitemporal", "with audit" do
435
435
  end
436
436
  end
437
437
 
438
- describe "Sequel::Plugins::Bitemporal", "with audit, specifying how to get the author" do
438
+ RSpec.describe "Sequel::Plugins::Bitemporal", "with audit, specifying how to get the author" do
439
439
  before :all do
440
440
  @audit_class = Class.new
441
441
  db_setup use_time: true, audit_class: @audit_class, audit_updated_by_method: :author
@@ -1,6 +1,6 @@
1
1
  require "spec_helper"
2
2
  if DbHelpers.pg?
3
- describe "Sequel::Plugins::Bitemporal" do
3
+ RSpec.describe "Sequel::Plugins::Bitemporal" do
4
4
  let(:hour){ 3600 }
5
5
  before :all do
6
6
  db_setup use_time: true, ranges: true
@@ -381,7 +381,7 @@ if DbHelpers.pg?
381
381
  expect(@master_class.with_current_or_future_versions.all.size).to eq(2)
382
382
  end
383
383
  end
384
- describe "Sequel::Plugins::Bitemporal", "with audit" do
384
+ RSpec.describe "Sequel::Plugins::Bitemporal", "with audit" do
385
385
  before :all do
386
386
  @audit_class = Class.new
387
387
  db_setup use_time: true, audit_class: @audit_class, ranges: true
@@ -435,7 +435,7 @@ if DbHelpers.pg?
435
435
  end
436
436
  end
437
437
 
438
- describe "Sequel::Plugins::Bitemporal", "with audit, specifying how to get the author" do
438
+ RSpec.describe "Sequel::Plugins::Bitemporal", "with audit, specifying how to get the author" do
439
439
  before :all do
440
440
  @audit_class = Class.new
441
441
  db_setup(
@@ -0,0 +1,59 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "Sequel::Plugins::Bitemporal", "composite_primary_key" do
4
+ before :all do
5
+ setup_composite_primary_key
6
+ end
7
+
8
+ describe "::version_foreign_keys" do
9
+ context "when is invoked without args" do
10
+ it "returns master_id" do
11
+ expect(Sequel::Plugins::Bitemporal.bitemporal_excluded_columns).to(
12
+ eq([:id, :master_id, :valid_from, :valid_to, :created_at, :expired_at])
13
+ )
14
+ end
15
+ end
16
+ end
17
+
18
+ describe "missing required foreign keys in version table" do
19
+ ERROR_TEXT = "bitemporal plugin requires the following missing columns on version class: department_id, team_id"
20
+
21
+ it "raises error" do
22
+ expect do
23
+ setup_composite_primary_key(with_foreign_key: false)
24
+ end.to raise_error Sequel::Error, ERROR_TEXT
25
+ end
26
+ end
27
+
28
+ describe "versions work correctly" do
29
+ let(:master) { @master_class.new(name: "john Smith") }
30
+ let(:junior) { "Junior Ruby-developer" }
31
+ let(:senior) { "Senior Ruby-developer" }
32
+ let(:two_years_in_seconds) { 2 * 365 * 24 * 60 * 60 }
33
+
34
+ before do
35
+ setup_composite_primary_key
36
+ master.department_id = 1
37
+ master.team_id = 1
38
+ master.save
39
+
40
+ Sequel::Plugins::Bitemporal.at(Time.now) do
41
+ master.update_attributes(position: junior)
42
+ end
43
+
44
+ Sequel::Plugins::Bitemporal.at(Time.now + two_years_in_seconds) do
45
+ master.update_attributes(position: senior)
46
+ end
47
+ end
48
+
49
+ specify do
50
+ Sequel::Plugins::Bitemporal.at(Time.now) do
51
+ expect(master.reload.position).to eq(junior)
52
+ end
53
+
54
+ Sequel::Plugins::Bitemporal.at(Time.now + two_years_in_seconds) do
55
+ expect(master.reload.position).to eq(senior)
56
+ end
57
+ end
58
+ end
59
+ end
data/spec/spec_helper.rb CHANGED
@@ -35,6 +35,7 @@ end
35
35
  RSpec.configure do |config|
36
36
  config.include DbHelpers
37
37
  config.filter_run_excluding rspec_exclusions
38
+ config.disable_monkey_patching!
38
39
  config.before :each do
39
40
  db_truncate
40
41
  end
data/spec/support/db.rb CHANGED
@@ -63,6 +63,48 @@ module DbHelpers
63
63
  end
64
64
  end
65
65
 
66
+ def setup_composite_primary_key(with_foreign_key: true)
67
+ DB.drop_table(:employee_versions) if DB.table_exists?(:employee_versions)
68
+ DB.drop_table(:employees) if DB.table_exists?(:employees)
69
+
70
+ DB.create_table! :employees do
71
+ Integer :department_id
72
+ Integer :team_id
73
+ primary_key [:department_id, :team_id]
74
+ String :name, null: false
75
+ end
76
+
77
+ DB.create_table! :employee_versions do
78
+ if with_foreign_key
79
+ Integer :department_id
80
+ Integer :team_id
81
+
82
+ foreign_key [:department_id, :team_id], :employees
83
+ end
84
+
85
+ primary_key :id
86
+ String :position
87
+ Date :created_at
88
+ Date :expired_at
89
+ Date :valid_from
90
+ Date :valid_to
91
+ end
92
+
93
+ @version_class = Class.new Sequel::Model do
94
+ set_dataset :employee_versions
95
+ end
96
+
97
+ bitemporal_options = {
98
+ version_class: @version_class,
99
+ key: [:department_id, :team_id]
100
+ }
101
+
102
+ @master_class = Class.new Sequel::Model do
103
+ set_dataset :employees
104
+ plugin :bitemporal, bitemporal_options
105
+ end
106
+ end
107
+
66
108
  def db_truncate
67
109
  if DbHelpers.pg?
68
110
  @version_class.truncate cascade: true
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sequel_bitemporal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joseph HALTER
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-11-29 00:00:00.000000000 Z
12
+ date: 2019-01-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sequel
@@ -98,6 +98,7 @@ files:
98
98
  - spec/bitemporal_serialization_spec.rb
99
99
  - spec/bitemporal_time_spec.rb
100
100
  - spec/bitemporal_time_with_range_spec.rb
101
+ - spec/composite_primary_key_spec.rb
101
102
  - spec/spec_helper.rb
102
103
  - spec/support/bitemporal_matchers.rb
103
104
  - spec/support/db.rb
@@ -131,6 +132,7 @@ test_files:
131
132
  - spec/bitemporal_serialization_spec.rb
132
133
  - spec/bitemporal_time_spec.rb
133
134
  - spec/bitemporal_time_with_range_spec.rb
135
+ - spec/composite_primary_key_spec.rb
134
136
  - spec/spec_helper.rb
135
137
  - spec/support/bitemporal_matchers.rb
136
138
  - spec/support/db.rb