chrono_model 0.5.2 → 0.5.3
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.
- data/.gitignore +1 -0
- data/.travis.yml +13 -0
- data/Gemfile +4 -0
- data/README.md +4 -0
- data/lib/chrono_model/version.rb +1 -1
- data/spec/adapter_spec.rb +2 -3
- data/spec/config.travis.yml +4 -0
- data/spec/spec_helper.rb +1 -3
- data/spec/support/connection.rb +1 -0
- data/spec/support/helpers.rb +40 -43
- data/spec/time_machine_spec.rb +34 -41
- metadata +8 -6
- data/Gemfile.lock +0 -60
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -8,6 +8,10 @@ This is a data structure for a
|
|
8
8
|
[Slowly-Changing Dimension Type 2](http://en.wikipedia.org/wiki/Slowly_changing_dimension#Type_2)
|
9
9
|
temporal database, implemented using only [PostgreSQL](http://www.postgresql.org) >= 9.0 features.
|
10
10
|
|
11
|
+
[](https://travis-ci.org/ifad/chronomodel)
|
12
|
+
[](https://gemnasium.com/ifad/chronomodel)
|
13
|
+
[](https://codeclimate.com/github/ifad/chronomodel)
|
14
|
+
|
11
15
|
All the history recording is done inside the database system, freeing the application code from
|
12
16
|
having to deal with it.
|
13
17
|
|
data/lib/chrono_model/version.rb
CHANGED
data/spec/adapter_spec.rb
CHANGED
@@ -46,7 +46,7 @@ describe ChronoModel::Adapter do
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
|
49
|
+
table 'test_table'
|
50
50
|
subject { table }
|
51
51
|
|
52
52
|
columns do
|
@@ -80,8 +80,7 @@ describe ChronoModel::Adapter do
|
|
80
80
|
end
|
81
81
|
|
82
82
|
describe '.rename_table' do
|
83
|
-
|
84
|
-
let(:renamed) { 'foo_table' }
|
83
|
+
renamed = 'foo_table'
|
85
84
|
subject { renamed }
|
86
85
|
|
87
86
|
context ':temporal => true' do
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/connection.rb
CHANGED
data/spec/support/helpers.rb
CHANGED
@@ -2,18 +2,17 @@ module ChronoTest::Helpers
|
|
2
2
|
|
3
3
|
module Adapter
|
4
4
|
def self.included(base)
|
5
|
-
base.let!(:adapter) { ChronoTest.connection }
|
6
5
|
base.extend DSL
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
base.instance_eval do
|
7
|
+
delegate :adapter, :to => ChronoTest
|
8
|
+
delegate :columns, :table, :to => DSL
|
9
|
+
end
|
11
10
|
end
|
12
11
|
|
13
12
|
module DSL
|
14
13
|
def with_temporal_table(&block)
|
15
14
|
context ':temporal => true' do
|
16
|
-
before(:all) { adapter.create_table(table, :temporal => true, &columns) }
|
15
|
+
before(:all) { adapter.create_table(table, :temporal => true, &DSL.columns) }
|
17
16
|
after(:all) { adapter.drop_table table }
|
18
17
|
|
19
18
|
instance_eval(&block)
|
@@ -22,64 +21,59 @@ module ChronoTest::Helpers
|
|
22
21
|
|
23
22
|
def with_plain_table(&block)
|
24
23
|
context ':temporal => false' do
|
25
|
-
before(:all) { adapter.create_table(table, :temporal => false, &columns) }
|
24
|
+
before(:all) { adapter.create_table(table, :temporal => false, &DSL.columns) }
|
26
25
|
after(:all) { adapter.drop_table table }
|
27
26
|
|
28
27
|
instance_eval(&block)
|
29
28
|
end
|
30
29
|
end
|
31
30
|
|
32
|
-
def
|
33
|
-
|
31
|
+
def self.table(table = nil)
|
32
|
+
@table = table if table
|
33
|
+
@table
|
34
34
|
end
|
35
35
|
|
36
|
-
|
37
|
-
|
36
|
+
def self.columns(&block)
|
37
|
+
@columns = block.call if block
|
38
|
+
@columns
|
38
39
|
end
|
40
|
+
delegate :columns, :table, :to => self
|
39
41
|
end
|
40
42
|
end
|
41
43
|
|
42
44
|
module TimeMachine
|
43
45
|
def self.included(base)
|
44
|
-
base.let!(:adapter) { ChronoTest.connection }
|
45
46
|
base.extend(DSL)
|
47
|
+
base.extend(self)
|
46
48
|
end
|
47
49
|
|
48
50
|
module DSL
|
49
51
|
def setup_schema!
|
50
52
|
# Set up database structure
|
51
53
|
#
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
t.references :foo
|
61
|
-
end
|
62
|
-
|
63
|
-
adapter.create_table 'bazs' do |t|
|
64
|
-
t.string :name
|
65
|
-
t.references :bar
|
66
|
-
end
|
67
|
-
|
68
|
-
adapter.create_table 'defoos', :temporal => true do |t|
|
69
|
-
t.string :name
|
70
|
-
t.boolean :active
|
71
|
-
end
|
72
|
-
|
73
|
-
adapter.create_table 'elements', :temporal => true do |t|
|
74
|
-
t.string :title
|
75
|
-
t.string :type
|
76
|
-
end
|
54
|
+
adapter.create_table 'foos', :temporal => true do |t|
|
55
|
+
t.string :name
|
56
|
+
t.integer :fooity
|
57
|
+
end
|
58
|
+
|
59
|
+
adapter.create_table 'bars', :temporal => true do |t|
|
60
|
+
t.string :name
|
61
|
+
t.references :foo
|
77
62
|
end
|
78
63
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
64
|
+
adapter.create_table 'bazs' do |t|
|
65
|
+
t.string :name
|
66
|
+
t.references :bar
|
67
|
+
end
|
68
|
+
|
69
|
+
adapter.create_table 'defoos', :temporal => true do |t|
|
70
|
+
t.string :name
|
71
|
+
t.boolean :active
|
72
|
+
end
|
73
|
+
|
74
|
+
adapter.create_table 'elements', :temporal => true do |t|
|
75
|
+
t.string :title
|
76
|
+
t.string :type
|
83
77
|
end
|
84
78
|
end
|
85
79
|
|
@@ -123,9 +117,12 @@ module ChronoTest::Helpers
|
|
123
117
|
}
|
124
118
|
|
125
119
|
def define_models!
|
126
|
-
|
120
|
+
Models.call
|
127
121
|
end
|
128
122
|
|
123
|
+
def adapter
|
124
|
+
ChronoTest.connection
|
125
|
+
end
|
129
126
|
end
|
130
127
|
|
131
128
|
# If a context object is given, evaluates the given
|
@@ -144,7 +141,7 @@ module ChronoTest::Helpers
|
|
144
141
|
define_method(:ts) { @_ts ||= [] }
|
145
142
|
end unless obj.methods.include?(:ts)
|
146
143
|
|
147
|
-
now =
|
144
|
+
now = ChronoTest.connection.select_value('select now()::timestamp')
|
148
145
|
obj.ts.push(Time.parse(now))
|
149
146
|
end
|
150
147
|
end
|
data/spec/time_machine_spec.rb
CHANGED
@@ -7,6 +7,25 @@ describe ChronoModel::TimeMachine do
|
|
7
7
|
setup_schema!
|
8
8
|
define_models!
|
9
9
|
|
10
|
+
# Set up two associated records, with intertwined updates
|
11
|
+
#
|
12
|
+
foo = ts_eval { Foo.create! :name => 'foo', :fooity => 1 }
|
13
|
+
ts_eval(foo) { update_attributes! :name => 'foo bar' }
|
14
|
+
|
15
|
+
#
|
16
|
+
bar = ts_eval { Bar.create! :name => 'bar', :foo => foo }
|
17
|
+
ts_eval(bar) { update_attributes! :name => 'foo bar' }
|
18
|
+
|
19
|
+
ts_eval(foo) { update_attributes! :name => 'new foo' }
|
20
|
+
|
21
|
+
ts_eval(bar) { update_attributes! :name => 'bar bar' }
|
22
|
+
ts_eval(bar) { update_attributes! :name => 'new bar' }
|
23
|
+
|
24
|
+
#
|
25
|
+
baz = Baz.create :name => 'baz', :bar => bar
|
26
|
+
|
27
|
+
# Specs start here
|
28
|
+
#
|
10
29
|
describe '.chrono_models' do
|
11
30
|
subject { ChronoModel::TimeMachine.chrono_models }
|
12
31
|
|
@@ -18,30 +37,6 @@ describe ChronoModel::TimeMachine do
|
|
18
37
|
} }
|
19
38
|
end
|
20
39
|
|
21
|
-
|
22
|
-
# Set up two associated records, with intertwined updates
|
23
|
-
#
|
24
|
-
let!(:foo) {
|
25
|
-
foo = ts_eval { Foo.create! :name => 'foo', :fooity => 1 }
|
26
|
-
ts_eval(foo) { update_attributes! :name => 'foo bar' }
|
27
|
-
}
|
28
|
-
|
29
|
-
let!(:bar) {
|
30
|
-
bar = ts_eval { Bar.create! :name => 'bar', :foo => foo }
|
31
|
-
ts_eval(bar) { update_attributes! :name => 'foo bar' }
|
32
|
-
|
33
|
-
ts_eval(foo) { update_attributes! :name => 'new foo' }
|
34
|
-
|
35
|
-
ts_eval(bar) { update_attributes! :name => 'bar bar' }
|
36
|
-
ts_eval(bar) { update_attributes! :name => 'new bar' }
|
37
|
-
}
|
38
|
-
|
39
|
-
let!(:baz) {
|
40
|
-
Baz.create :name => 'baz', :bar => bar
|
41
|
-
}
|
42
|
-
|
43
|
-
# Specs start here
|
44
|
-
#
|
45
40
|
describe '#as_of' do
|
46
41
|
describe 'accepts a Time instance' do
|
47
42
|
it { foo.as_of(Time.now).name.should == 'new foo' }
|
@@ -105,15 +100,11 @@ describe ChronoModel::TimeMachine do
|
|
105
100
|
end
|
106
101
|
|
107
102
|
describe 'it honors default_scopes' do
|
108
|
-
|
109
|
-
|
110
|
-
ts_eval(active) { update_attributes! :name => 'active 2' }
|
111
|
-
}
|
103
|
+
active = ts_eval { Defoo.create! :name => 'active 1', :active => true }
|
104
|
+
ts_eval(active) { update_attributes! :name => 'active 2' }
|
112
105
|
|
113
|
-
|
114
|
-
|
115
|
-
ts_eval(hidden) { update_attributes! :name => 'hidden 2' }
|
116
|
-
}
|
106
|
+
hidden = ts_eval { Defoo.create! :name => 'hidden 1', :active => false }
|
107
|
+
ts_eval(hidden) { update_attributes! :name => 'hidden 2' }
|
117
108
|
|
118
109
|
it { Defoo.as_of(active.ts[0]).map(&:name).should == ['active 1'] }
|
119
110
|
it { Defoo.as_of(active.ts[1]).map(&:name).should == ['active 2'] }
|
@@ -187,10 +178,8 @@ describe ChronoModel::TimeMachine do
|
|
187
178
|
end
|
188
179
|
|
189
180
|
context 'with STI models' do
|
190
|
-
|
191
|
-
|
192
|
-
ts_eval(pub) { update_attributes! :title => 'correct title' }
|
193
|
-
}
|
181
|
+
pub = ts_eval { Publication.create! :title => 'wrong title' }
|
182
|
+
ts_eval(pub) { update_attributes! :title => 'correct title' }
|
194
183
|
|
195
184
|
it { pub.history.map(&:title).should == ['wrong title', 'correct title'] }
|
196
185
|
end
|
@@ -271,10 +260,14 @@ describe ChronoModel::TimeMachine do
|
|
271
260
|
end
|
272
261
|
|
273
262
|
describe 'on current records' do
|
274
|
-
|
263
|
+
rec = nil
|
264
|
+
before(:all) do
|
275
265
|
rec = ts_eval { Foo.create!(:name => 'alive foo', :fooity => 42) }
|
276
266
|
ts_eval(rec) { update_attributes!(:name => 'dying foo') }
|
277
|
-
|
267
|
+
end
|
268
|
+
after(:all) do
|
269
|
+
rec.history.delete_all
|
270
|
+
end
|
278
271
|
|
279
272
|
subject { rec.destroy }
|
280
273
|
|
@@ -461,8 +454,8 @@ describe ChronoModel::TimeMachine do
|
|
461
454
|
|
462
455
|
# Class methods
|
463
456
|
context do
|
464
|
-
|
465
|
-
|
457
|
+
foos = Array.new(2) {|i| ts_eval { Foo.create! :name => "foo #{i}" } }
|
458
|
+
bars = Array.new(2) {|i| ts_eval { Bar.create! :name => "bar #{i}", :foo => foos[i] } }
|
466
459
|
|
467
460
|
after(:all) { foos.each(&:destroy); bars.each(&:destroy) }
|
468
461
|
|
@@ -504,7 +497,7 @@ describe ChronoModel::TimeMachine do
|
|
504
497
|
|
505
498
|
describe '.history' do
|
506
499
|
let(:foo_history) {
|
507
|
-
['foo', 'foo bar', 'new foo', '
|
500
|
+
['foo', 'foo bar', 'new foo', 'foo 0', 'foo 1']
|
508
501
|
}
|
509
502
|
|
510
503
|
let(:bar_history) {
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chrono_model
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2013-08-01 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
16
|
-
requirement: &
|
16
|
+
requirement: &74215960 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3.2'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *74215960
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: pg
|
27
|
-
requirement: &
|
27
|
+
requirement: &74215660 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,7 +32,7 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *74215660
|
36
36
|
description: Give your models as-of date temporal extensions. Built entirely for PostgreSQL
|
37
37
|
>= 9.0
|
38
38
|
email:
|
@@ -43,8 +43,8 @@ extra_rdoc_files: []
|
|
43
43
|
files:
|
44
44
|
- .gitignore
|
45
45
|
- .rspec
|
46
|
+
- .travis.yml
|
46
47
|
- Gemfile
|
47
|
-
- Gemfile.lock
|
48
48
|
- LICENSE
|
49
49
|
- README.md
|
50
50
|
- README.sql
|
@@ -62,6 +62,7 @@ files:
|
|
62
62
|
- lib/chrono_model/utils.rb
|
63
63
|
- lib/chrono_model/version.rb
|
64
64
|
- spec/adapter_spec.rb
|
65
|
+
- spec/config.travis.yml
|
65
66
|
- spec/config.yml.example
|
66
67
|
- spec/spec_helper.rb
|
67
68
|
- spec/support/connection.rb
|
@@ -98,6 +99,7 @@ specification_version: 3
|
|
98
99
|
summary: Temporal extensions (SCD Type II) for Active Record
|
99
100
|
test_files:
|
100
101
|
- spec/adapter_spec.rb
|
102
|
+
- spec/config.travis.yml
|
101
103
|
- spec/config.yml.example
|
102
104
|
- spec/spec_helper.rb
|
103
105
|
- spec/support/connection.rb
|
data/Gemfile.lock
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
chrono_model (0.5.0.beta)
|
5
|
-
activerecord (~> 3.2)
|
6
|
-
pg
|
7
|
-
|
8
|
-
GEM
|
9
|
-
remote: https://rubygems.org/
|
10
|
-
specs:
|
11
|
-
activemodel (3.2.8)
|
12
|
-
activesupport (= 3.2.8)
|
13
|
-
builder (~> 3.0.0)
|
14
|
-
activerecord (3.2.8)
|
15
|
-
activemodel (= 3.2.8)
|
16
|
-
activesupport (= 3.2.8)
|
17
|
-
arel (~> 3.0.2)
|
18
|
-
tzinfo (~> 0.3.29)
|
19
|
-
activesupport (3.2.8)
|
20
|
-
i18n (~> 0.6)
|
21
|
-
multi_json (~> 1.0)
|
22
|
-
arel (3.0.2)
|
23
|
-
builder (3.0.4)
|
24
|
-
coderay (1.0.8)
|
25
|
-
columnize (0.3.6)
|
26
|
-
debugger (1.2.1)
|
27
|
-
columnize (>= 0.3.1)
|
28
|
-
debugger-linecache (~> 1.1.1)
|
29
|
-
debugger-ruby_core_source (~> 1.1.4)
|
30
|
-
debugger-linecache (1.1.2)
|
31
|
-
debugger-ruby_core_source (>= 1.1.1)
|
32
|
-
debugger-ruby_core_source (1.1.4)
|
33
|
-
diff-lcs (1.1.3)
|
34
|
-
i18n (0.6.1)
|
35
|
-
method_source (0.8.1)
|
36
|
-
multi_json (1.3.6)
|
37
|
-
pg (0.14.1)
|
38
|
-
pry (0.9.10)
|
39
|
-
coderay (~> 1.0.5)
|
40
|
-
method_source (~> 0.8)
|
41
|
-
slop (~> 3.3.1)
|
42
|
-
rspec (2.11.0)
|
43
|
-
rspec-core (~> 2.11.0)
|
44
|
-
rspec-expectations (~> 2.11.0)
|
45
|
-
rspec-mocks (~> 2.11.0)
|
46
|
-
rspec-core (2.11.1)
|
47
|
-
rspec-expectations (2.11.3)
|
48
|
-
diff-lcs (~> 1.1.3)
|
49
|
-
rspec-mocks (2.11.3)
|
50
|
-
slop (3.3.3)
|
51
|
-
tzinfo (0.3.33)
|
52
|
-
|
53
|
-
PLATFORMS
|
54
|
-
ruby
|
55
|
-
|
56
|
-
DEPENDENCIES
|
57
|
-
chrono_model!
|
58
|
-
debugger
|
59
|
-
pry
|
60
|
-
rspec
|