sequel_bitemporal 0.1.10 → 0.1.11

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.
@@ -3,13 +3,26 @@ module Sequel
3
3
  module Bitemporal
4
4
  def self.as_we_knew_it(time)
5
5
  raise ArgumentError, "requires a block" unless block_given?
6
- previous_point_in_time, @point_in_time = @point_in_time, time
6
+ key = :sequel_plugins_bitemporal_point_in_time
7
+ previous, Thread.current[key] = Thread.current[key], time.to_time
7
8
  yield
8
- @point_in_time = previous_point_in_time
9
+ Thread.current[key] = previous
9
10
  end
10
11
 
11
12
  def self.point_in_time
12
- @point_in_time || Time.now
13
+ Thread.current[:sequel_plugins_bitemporal_point_in_time] || Time.now
14
+ end
15
+
16
+ def self.at(time)
17
+ raise ArgumentError, "requires a block" unless block_given?
18
+ key = :sequel_plugins_bitemporal_now
19
+ previous, Thread.current[key] = Thread.current[key], time.to_time
20
+ yield
21
+ Thread.current[key] = previous
22
+ end
23
+
24
+ def self.now
25
+ Thread.current[:sequel_plugins_bitemporal_now] || Time.now
13
26
  end
14
27
 
15
28
  def self.configure(master, opts = {})
@@ -21,34 +34,40 @@ module Sequel
21
34
  master.one_to_many :versions, class: version, key: :master_id
22
35
  master.one_to_one :current_version, class: version, key: :master_id, :graph_block=>(proc do |j, lj, js|
23
36
  t = ::Sequel::Plugins::Bitemporal.point_in_time
37
+ n = ::Sequel::Plugins::Bitemporal.now
24
38
  e = :expired_at.qualify(j)
25
- (:created_at.qualify(j) <= t) & ({e=>nil} | (e > t)) & (:valid_from.qualify(j) <= t) & (:valid_to.qualify(j) > t)
39
+ (:created_at.qualify(j) <= t) & ({e=>nil} | (e > t)) & (:valid_from.qualify(j) <= n) & (:valid_to.qualify(j) > n)
26
40
  end) do |ds|
27
41
  t = ::Sequel::Plugins::Bitemporal.point_in_time
28
- ds.where{(created_at <= t) & ({expired_at=>nil} | (expired_at > t)) & (valid_from <= t) & (valid_to > t)}
42
+ n = ::Sequel::Plugins::Bitemporal.now
43
+ ds.where{(created_at <= t) & ({expired_at=>nil} | (expired_at > t)) & (valid_from <= n) & (valid_to > n)}
29
44
  end
30
45
  master.def_dataset_method :with_current_version do
31
46
  eager_graph(:current_version).where({current_version__id: nil}.sql_negate)
32
47
  end
33
48
  master.one_to_many :current_or_future_versions, class: version, key: :master_id, :graph_block=>(proc do |j, lj, js|
34
49
  t = ::Sequel::Plugins::Bitemporal.point_in_time
50
+ n = ::Sequel::Plugins::Bitemporal.now
35
51
  e = :expired_at.qualify(j)
36
- (:created_at.qualify(j) <= t) & ({e=>nil} | (e > t)) & (:valid_to.qualify(j) > t)
52
+ (:created_at.qualify(j) <= t) & ({e=>nil} | (e > t)) & (:valid_to.qualify(j) > n)
37
53
  end) do |ds|
38
54
  t = ::Sequel::Plugins::Bitemporal.point_in_time
39
- ds.where{(created_at <= t) & ({expired_at=>nil} | (expired_at > t)) & (valid_to > t)}
55
+ n = ::Sequel::Plugins::Bitemporal.now
56
+ ds.where{(created_at <= t) & ({expired_at=>nil} | (expired_at > t)) & (valid_to > n)}
40
57
  end
41
58
  master.def_dataset_method :with_current_or_future_versions do
42
59
  eager_graph(:current_or_future_versions).where({current_or_future_versions__id: nil}.sql_negate)
43
60
  end
44
61
  version.many_to_one :master, class: master, key: :master_id
45
62
  version.class_eval do
46
- def current?(now = Time.now)
63
+ def current?
64
+ t = ::Sequel::Plugins::Bitemporal.point_in_time
65
+ n = ::Sequel::Plugins::Bitemporal.now
47
66
  !new? &&
48
- created_at.to_time<=now &&
49
- (expired_at.nil? || expired_at.to_time>now) &&
50
- valid_from.to_time<=now &&
51
- valid_to.to_time>now
67
+ created_at.to_time<=t &&
68
+ (expired_at.nil? || expired_at.to_time>t) &&
69
+ valid_from.to_time<=n &&
70
+ valid_to.to_time>n
52
71
  end
53
72
  def destroy
54
73
  master.destroy_version self
@@ -96,6 +115,7 @@ module Sequel
96
115
  if !new? && attributes.delete(:partial_update) && current_version
97
116
  current_attributes = current_version.values.dup
98
117
  current_attributes.delete :valid_from
118
+ current_attributes.delete :valid_to
99
119
  attributes = current_attributes.merge attributes
100
120
  end
101
121
  attributes.delete :id
@@ -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.1.10"
6
+ s.version = "0.1.11"
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"
@@ -2,6 +2,8 @@ require "spec_helper"
2
2
 
3
3
  describe "Sequel::Plugins::Bitemporal" do
4
4
  before :all do
5
+ DB.drop_table(:room_versions) if DB.table_exists?(:room_versions)
6
+ DB.drop_table(:rooms) if DB.table_exists?(:rooms)
5
7
  DB.create_table! :rooms do
6
8
  primary_key :id
7
9
  end
@@ -31,8 +33,8 @@ describe "Sequel::Plugins::Bitemporal" do
31
33
  end
32
34
  before do
33
35
  Timecop.freeze 2009, 11, 28
34
- @master_class.truncate
35
36
  @version_class.truncate
37
+ @master_class.truncate
36
38
  end
37
39
  after do
38
40
  Timecop.return
@@ -325,13 +327,45 @@ describe "Sequel::Plugins::Bitemporal" do
325
327
  end
326
328
  it "allows to go back in time" do
327
329
  master = @master_class.new
328
- master.update_attributes name: "Single Standard", price: 98
330
+ master.update_attributes name: "Single Standard", price: 98, valid_to: Date.today+1
331
+ master.update_attributes name: "Single Standard", price: 95, valid_from: Date.today+1, valid_to: Date.today+2
332
+ master.update_attributes name: "Single Standard", price: 93, valid_from: Date.today+2, valid_to: Date.today+3
333
+ master.update_attributes name: "Single Standard", price: 91, valid_from: Date.today+3
329
334
  Timecop.freeze Date.today+1
330
335
  master.update_attributes price: 94, partial_update: true
336
+ master.update_attributes price: 96, partial_update: true, valid_from: Date.today+2
337
+ master.should have_versions %Q{
338
+ | name | price | created_at | expired_at | valid_from | valid_to | current |
339
+ | Single Standard | 98 | 2009-11-28 | | 2009-11-28 | 2009-11-29 | |
340
+ | Single Standard | 95 | 2009-11-28 | 2009-11-29 | 2009-11-29 | 2009-11-30 | |
341
+ | Single Standard | 93 | 2009-11-28 | | 2009-11-30 | 2009-12-01 | |
342
+ | Single Standard | 91 | 2009-11-28 | 2009-11-29 | 2009-12-01 | MAX DATE | |
343
+ | Single Standard | 94 | 2009-11-29 | | 2009-11-29 | 2009-11-30 | true |
344
+ | Single Standard | 96 | 2009-11-29 | | 2009-12-01 | MAX DATE | |
345
+ }
331
346
  master.current_version.price.should == 94
332
- Sequel::Plugins::Bitemporal.as_we_knew_it(Date.today-1) do
347
+ Sequel::Plugins::Bitemporal.at(Date.today-1) do
333
348
  master.current_version(true).price.should == 98
334
349
  end
350
+ Sequel::Plugins::Bitemporal.at(Date.today+1) do
351
+ master.current_version(true).price.should == 93
352
+ end
353
+ Sequel::Plugins::Bitemporal.at(Date.today+2) do
354
+ master.current_version(true).price.should == 96
355
+ end
356
+ Sequel::Plugins::Bitemporal.as_we_knew_it(Date.today-1) do
357
+ master.current_version(true).price.should == 95
358
+ master.current_version.should be_current
359
+ Sequel::Plugins::Bitemporal.at(Date.today-1) do
360
+ master.current_version(true).price.should == 98
361
+ end
362
+ Sequel::Plugins::Bitemporal.at(Date.today+1) do
363
+ master.current_version(true).price.should == 93
364
+ end
365
+ Sequel::Plugins::Bitemporal.at(Date.today+2) do
366
+ master.current_version(true).price.should == 91
367
+ end
368
+ end
335
369
  end
336
370
  it "allows eager loading with conditions on current or future versions" do
337
371
  master = @master_class.new
@@ -3,6 +3,8 @@ require "spec_helper"
3
3
  describe "Sequel::Plugins::Bitemporal" do
4
4
  let(:hour){ 3600 }
5
5
  before :all do
6
+ DB.drop_table(:room_versions) if DB.table_exists?(:room_versions)
7
+ DB.drop_table(:rooms) if DB.table_exists?(:rooms)
6
8
  DB.create_table! :rooms do
7
9
  primary_key :id
8
10
  end
@@ -32,11 +34,11 @@ describe "Sequel::Plugins::Bitemporal" do
32
34
  end
33
35
  before do
34
36
  Timecop.freeze 2009, 11, 28, 10
37
+ @version_class.truncate
38
+ @master_class.truncate
35
39
  end
36
40
  after do
37
41
  Timecop.return
38
- @master_class.truncate
39
- @version_class.truncate
40
42
  end
41
43
  it "checks version class is given" do
42
44
  lambda{
@@ -300,6 +302,16 @@ describe "Sequel::Plugins::Bitemporal" do
300
302
  master.destroy
301
303
  @master_class.eager_graph(:current_version).where("current_version.id IS NOT NULL").first.should be_nil
302
304
  end
305
+ it "allows loading masters with a current version" do
306
+ master_destroyed = @master_class.new
307
+ master_destroyed.update_attributes name: "Single Standard", price: 98
308
+ master_destroyed.destroy
309
+ master_with_current = @master_class.new
310
+ master_with_current.update_attributes name: "Single Standard", price: 94
311
+ master_with_future = @master_class.new
312
+ master_with_future.update_attributes name: "Single Standard", price: 94, valid_from: Time.now+2*hour
313
+ @master_class.with_current_version.all.should have(1).item
314
+ end
303
315
  it "gets pending or current version attributes" do
304
316
  master = @master_class.new
305
317
  master.attributes.should == {}
@@ -314,4 +326,42 @@ describe "Sequel::Plugins::Bitemporal" do
314
326
  master.pending_version.should be
315
327
  master.pending_or_current_version.name.should == "King Size"
316
328
  end
329
+ it "allows to go back in time" do
330
+ master = @master_class.new
331
+ master.update_attributes name: "Single Standard", price: 98
332
+ Timecop.freeze Time.now+1*hour
333
+ master.update_attributes price: 94, partial_update: true
334
+ master.current_version.price.should == 94
335
+ Sequel::Plugins::Bitemporal.as_we_knew_it(Time.now-1*hour) do
336
+ master.current_version(true).price.should == 98
337
+ end
338
+ end
339
+ it "allows eager loading with conditions on current or future versions" do
340
+ master = @master_class.new
341
+ master.update_attributes name: "Single Standard", price: 98
342
+ Timecop.freeze Time.now+1*hour
343
+ master.update_attributes name: "Single Standard", price: 99
344
+ master.update_attributes name: "Single Standard", price: 94, valid_from: Time.now+2*hour
345
+ res = @master_class.eager_graph(:current_or_future_versions).where({current_or_future_versions__id: nil}.sql_negate & {price: 99}).all.first
346
+ res.should be
347
+ res.current_or_future_versions.should have(1).item
348
+ res.current_or_future_versions.first.price.should == 99
349
+ res = @master_class.eager_graph(:current_or_future_versions).where({current_or_future_versions__id: nil}.sql_negate & {price: 94}).all.first
350
+ res.should be
351
+ res.current_or_future_versions.should have(1).item
352
+ res.current_or_future_versions.first.price.should == 94
353
+ Timecop.freeze Time.now+1*hour
354
+ master.destroy
355
+ @master_class.eager_graph(:current_or_future_versions).where({current_or_future_versions__id: nil}.sql_negate).all.should be_empty
356
+ end
357
+ it "allows loading masters with current or future versions" do
358
+ master_destroyed = @master_class.new
359
+ master_destroyed.update_attributes name: "Single Standard", price: 98
360
+ master_destroyed.destroy
361
+ master_with_current = @master_class.new
362
+ master_with_current.update_attributes name: "Single Standard", price: 94
363
+ master_with_future = @master_class.new
364
+ master_with_future.update_attributes name: "Single Standard", price: 94, valid_from: Time.now+2*hour
365
+ @master_class.with_current_or_future_versions.all.should have(2).item
366
+ end
317
367
  end
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.1.10
4
+ version: 0.1.11
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-11-11 00:00:00.000000000 Z
13
+ date: 2011-11-17 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: sequel
17
- requirement: &2158291240 !ruby/object:Gem::Requirement
17
+ requirement: &2165638640 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: '0'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *2158291240
25
+ version_requirements: *2165638640
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: sqlite3
28
- requirement: &2158290800 !ruby/object:Gem::Requirement
28
+ requirement: &2165638200 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
- version_requirements: *2158290800
36
+ version_requirements: *2165638200
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: rspec
39
- requirement: &2158290380 !ruby/object:Gem::Requirement
39
+ requirement: &2165637780 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,10 +44,10 @@ dependencies:
44
44
  version: '0'
45
45
  type: :development
46
46
  prerelease: false
47
- version_requirements: *2158290380
47
+ version_requirements: *2165637780
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: timecop
50
- requirement: &2158289960 !ruby/object:Gem::Requirement
50
+ requirement: &2165637360 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
53
  - - ! '>='
@@ -55,10 +55,10 @@ dependencies:
55
55
  version: '0'
56
56
  type: :development
57
57
  prerelease: false
58
- version_requirements: *2158289960
58
+ version_requirements: *2165637360
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: rake
61
- requirement: &2158289540 !ruby/object:Gem::Requirement
61
+ requirement: &2165636940 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
64
  - - ! '>='
@@ -66,7 +66,7 @@ dependencies:
66
66
  version: '0'
67
67
  type: :development
68
68
  prerelease: false
69
- version_requirements: *2158289540
69
+ version_requirements: *2165636940
70
70
  description: Bitemporal versioning for sequel, fully tested.
71
71
  email:
72
72
  - joseph.halter@thetalentbox.com
@@ -99,18 +99,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
99
  - - ! '>='
100
100
  - !ruby/object:Gem::Version
101
101
  version: '0'
102
- segments:
103
- - 0
104
- hash: -2412870867383750431
105
102
  required_rubygems_version: !ruby/object:Gem::Requirement
106
103
  none: false
107
104
  requirements:
108
105
  - - ! '>='
109
106
  - !ruby/object:Gem::Version
110
107
  version: '0'
111
- segments:
112
- - 0
113
- hash: -2412870867383750431
114
108
  requirements: []
115
109
  rubyforge_project:
116
110
  rubygems_version: 1.8.10