sequel_bitemporal 0.1.10 → 0.1.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -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