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 +4 -4
- data/.ruby-version +1 -1
- data/README.md +7 -2
- data/Rakefile +1 -1
- data/lib/sequel/plugins/bitemporal.rb +36 -12
- data/sequel_bitemporal.gemspec +1 -1
- data/spec/bitemporal_date_spec.rb +3 -3
- data/spec/bitemporal_date_with_range_spec.rb +3 -3
- data/spec/bitemporal_serialization_spec.rb +1 -1
- data/spec/bitemporal_time_spec.rb +3 -3
- data/spec/bitemporal_time_with_range_spec.rb +3 -3
- data/spec/composite_primary_key_spec.rb +59 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/db.rb +42 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f6daa2d7f025cd1281e8cbfc7235d0a6ddd85d2251f8d9195d85cc5340aafb3
|
4
|
+
data.tar.gz: 5d5de257ee011436a1c3959206c31c985d6b11597d63fcab468876865394f9ee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0309ac260a37ec550e417efb01eaa72120583a5c26c6306f52c15910d36c8dc24f9e74d39319f763e3a566192ddd5887b0b022ce747f820beee388a444726dc8'
|
7
|
+
data.tar.gz: f4f61ba42c6510bcc744f96a27ca9a91fe965762ce4ec6206720441346ec1e5402475e27e87a7b838d342898c47df99a1e8025abf5ebce59691250417bc0015f
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.3
|
1
|
+
2.5.3
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
sequel_bitemporal
|
2
2
|
=================
|
3
3
|
|
4
|
-
[](https://travis-ci.org/TalentBox/sequel_bitemporal)
|
5
5
|
|
6
|
-
Bitemporal versioning for
|
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
@@ -31,19 +31,25 @@ module Sequel
|
|
31
31
|
Thread.current[THREAD_NOW_KEY] || DateTime.now
|
32
32
|
end
|
33
33
|
|
34
|
-
def self.
|
35
|
-
|
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.
|
39
|
-
|
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:
|
104
|
-
master.one_to_one :current_version, class: version, key:
|
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:
|
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:
|
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 =
|
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, :
|
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) && (
|
data/sequel_bitemporal.gemspec
CHANGED
@@ -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.
|
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,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
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.
|
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:
|
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
|