chrono_model 1.2.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +19 -20
- data/README.md +62 -40
- data/lib/active_record/connection_adapters/chronomodel_adapter.rb +17 -11
- data/lib/active_record/tasks/chronomodel_database_tasks.rb +64 -23
- data/lib/chrono_model/adapter/ddl.rb +168 -153
- data/lib/chrono_model/adapter/indexes.rb +99 -94
- data/lib/chrono_model/adapter/migrations.rb +81 -104
- data/lib/chrono_model/adapter/migrations_modules/legacy.rb +41 -0
- data/lib/chrono_model/adapter/migrations_modules/stable.rb +41 -0
- data/lib/chrono_model/adapter/tsrange.rb +20 -5
- data/lib/chrono_model/adapter/upgrade.rb +89 -91
- data/lib/chrono_model/adapter.rb +64 -31
- data/lib/chrono_model/chrono.rb +17 -0
- data/lib/chrono_model/conversions.rb +15 -9
- data/lib/chrono_model/db_console.rb +9 -0
- data/lib/chrono_model/json.rb +9 -6
- data/lib/chrono_model/patches/as_of_time_holder.rb +2 -2
- data/lib/chrono_model/patches/as_of_time_relation.rb +2 -2
- data/lib/chrono_model/patches/association.rb +15 -12
- data/lib/chrono_model/patches/batches.rb +17 -0
- data/lib/chrono_model/patches/db_console.rb +20 -4
- data/lib/chrono_model/patches/join_node.rb +4 -4
- data/lib/chrono_model/patches/preloader.rb +41 -11
- data/lib/chrono_model/patches/relation.rb +53 -8
- data/lib/chrono_model/patches.rb +3 -1
- data/lib/chrono_model/railtie.rb +29 -24
- data/lib/chrono_model/time_gate.rb +3 -3
- data/lib/chrono_model/time_machine/history_model.rb +65 -31
- data/lib/chrono_model/time_machine/time_query.rb +65 -49
- data/lib/chrono_model/time_machine/timeline.rb +52 -28
- data/lib/chrono_model/time_machine.rb +66 -25
- data/lib/chrono_model/utilities.rb +3 -3
- data/lib/chrono_model/version.rb +3 -1
- data/lib/chrono_model.rb +31 -36
- metadata +39 -136
- data/.gitignore +0 -21
- data/.rspec +0 -2
- data/.travis.yml +0 -41
- data/Gemfile +0 -4
- data/README.sql +0 -161
- data/Rakefile +0 -25
- data/chrono_model.gemspec +0 -33
- data/gemfiles/rails_5.0.gemfile +0 -6
- data/gemfiles/rails_5.1.gemfile +0 -6
- data/gemfiles/rails_5.2.gemfile +0 -6
- data/spec/aruba/dbconsole_spec.rb +0 -25
- data/spec/aruba/fixtures/database_with_default_username_and_password.yml +0 -14
- data/spec/aruba/fixtures/database_without_username_and_password.yml +0 -11
- data/spec/aruba/fixtures/empty_structure.sql +0 -27
- data/spec/aruba/fixtures/migrations/56/20160812190335_create_impressions.rb +0 -10
- data/spec/aruba/fixtures/migrations/56/20171115195229_add_temporal_extension_to_impressions.rb +0 -10
- data/spec/aruba/fixtures/railsapp/config/application.rb +0 -17
- data/spec/aruba/fixtures/railsapp/config/boot.rb +0 -5
- data/spec/aruba/fixtures/railsapp/config/environments/development.rb +0 -38
- data/spec/aruba/migrations_spec.rb +0 -48
- data/spec/aruba/rake_task_spec.rb +0 -71
- data/spec/chrono_model/adapter/base_spec.rb +0 -157
- data/spec/chrono_model/adapter/ddl_spec.rb +0 -243
- data/spec/chrono_model/adapter/indexes_spec.rb +0 -72
- data/spec/chrono_model/adapter/migrations_spec.rb +0 -312
- data/spec/chrono_model/conversions_spec.rb +0 -43
- data/spec/chrono_model/history_models_spec.rb +0 -32
- data/spec/chrono_model/json_ops_spec.rb +0 -59
- data/spec/chrono_model/time_machine/as_of_spec.rb +0 -188
- data/spec/chrono_model/time_machine/changes_spec.rb +0 -50
- data/spec/chrono_model/time_machine/counter_cache_race_spec.rb +0 -46
- data/spec/chrono_model/time_machine/default_scope_spec.rb +0 -37
- data/spec/chrono_model/time_machine/history_spec.rb +0 -104
- data/spec/chrono_model/time_machine/keep_cool_spec.rb +0 -27
- data/spec/chrono_model/time_machine/manipulations_spec.rb +0 -84
- data/spec/chrono_model/time_machine/model_identification_spec.rb +0 -46
- data/spec/chrono_model/time_machine/sequence_spec.rb +0 -74
- data/spec/chrono_model/time_machine/sti_spec.rb +0 -100
- data/spec/chrono_model/time_machine/time_query_spec.rb +0 -261
- data/spec/chrono_model/time_machine/timeline_spec.rb +0 -63
- data/spec/chrono_model/time_machine/timestamps_spec.rb +0 -43
- data/spec/chrono_model/time_machine/transactions_spec.rb +0 -69
- data/spec/config.travis.yml +0 -5
- data/spec/config.yml.example +0 -9
- data/spec/spec_helper.rb +0 -33
- data/spec/support/adapter/helpers.rb +0 -53
- data/spec/support/adapter/structure.rb +0 -44
- data/spec/support/aruba.rb +0 -44
- data/spec/support/connection.rb +0 -70
- data/spec/support/matchers/base.rb +0 -56
- data/spec/support/matchers/column.rb +0 -99
- data/spec/support/matchers/function.rb +0 -79
- data/spec/support/matchers/index.rb +0 -69
- data/spec/support/matchers/schema.rb +0 -39
- data/spec/support/matchers/table.rb +0 -275
- data/spec/support/time_machine/helpers.rb +0 -47
- data/spec/support/time_machine/structure.rb +0 -111
- data/sql/json_ops.sql +0 -56
- data/sql/uninstall-json_ops.sql +0 -24
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'support/time_machine/structure'
|
3
|
-
|
4
|
-
describe 'models with counter cache' do
|
5
|
-
include ChronoTest::TimeMachine::Helpers
|
6
|
-
|
7
|
-
adapter.create_table 'sections', temporal: true, no_journal: %w( articles_count ) do |t|
|
8
|
-
t.string :name
|
9
|
-
t.integer :articles_count, default: 0
|
10
|
-
end
|
11
|
-
|
12
|
-
adapter.create_table 'articles', temporal: true do |t|
|
13
|
-
t.string :title
|
14
|
-
t.references :section
|
15
|
-
end
|
16
|
-
|
17
|
-
class ::Section < ActiveRecord::Base
|
18
|
-
include ChronoModel::TimeMachine
|
19
|
-
|
20
|
-
has_many :articles
|
21
|
-
end
|
22
|
-
|
23
|
-
class ::Article < ActiveRecord::Base
|
24
|
-
include ChronoModel::TimeMachine
|
25
|
-
|
26
|
-
belongs_to :section, counter_cache: true
|
27
|
-
end
|
28
|
-
|
29
|
-
describe 'are not subject to race condition if no_journal is set on the counter cache column' do
|
30
|
-
specify do
|
31
|
-
section = Section.create!
|
32
|
-
|
33
|
-
expect(section.articles_count).to eq(0)
|
34
|
-
Article.create!(section_id: section.id)
|
35
|
-
expect(section.reload.articles_count).to eq(1)
|
36
|
-
|
37
|
-
num_threads = 10
|
38
|
-
|
39
|
-
expect {
|
40
|
-
Array.new(num_threads).map do
|
41
|
-
Thread.new { Article.create!(section_id: section.id) }
|
42
|
-
end.each(&:join)
|
43
|
-
}.to_not raise_error
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'support/time_machine/structure'
|
3
|
-
|
4
|
-
describe ChronoModel::TimeMachine do
|
5
|
-
include ChronoTest::TimeMachine::Helpers
|
6
|
-
|
7
|
-
# Set up database structure
|
8
|
-
#
|
9
|
-
adapter.create_table 'defoos', :temporal => true do |t|
|
10
|
-
t.string :name
|
11
|
-
t.boolean :active
|
12
|
-
end
|
13
|
-
|
14
|
-
class ::Defoo < ActiveRecord::Base
|
15
|
-
include ChronoModel::TimeMachine
|
16
|
-
|
17
|
-
default_scope proc { where(:active => true) }
|
18
|
-
end
|
19
|
-
|
20
|
-
active = ts_eval { Defoo.create! :name => 'active 1', :active => true }
|
21
|
-
ts_eval(active) { update_attributes! :name => 'active 2' }
|
22
|
-
|
23
|
-
hidden = ts_eval { Defoo.create! :name => 'hidden 1', :active => false }
|
24
|
-
ts_eval(hidden) { update_attributes! :name => 'hidden 2' }
|
25
|
-
|
26
|
-
describe 'it honors default_scopes' do
|
27
|
-
it { expect(Defoo.as_of(active.ts[0]).map(&:name)).to eq ['active 1'] }
|
28
|
-
it { expect(Defoo.as_of(active.ts[1]).map(&:name)).to eq ['active 2'] }
|
29
|
-
it { expect(Defoo.as_of(hidden.ts[0]).map(&:name)).to eq ['active 2'] }
|
30
|
-
it { expect(Defoo.as_of(hidden.ts[1]).map(&:name)).to eq ['active 2'] }
|
31
|
-
|
32
|
-
it { expect(Defoo.unscoped.as_of(active.ts[0]).map(&:name)).to eq ['active 1'] }
|
33
|
-
it { expect(Defoo.unscoped.as_of(active.ts[1]).map(&:name)).to eq ['active 2'] }
|
34
|
-
it { expect(Defoo.unscoped.as_of(hidden.ts[0]).map(&:name)).to eq ['active 2', 'hidden 1'] }
|
35
|
-
it { expect(Defoo.unscoped.as_of(hidden.ts[1]).map(&:name)).to eq ['active 2', 'hidden 2'] }
|
36
|
-
end
|
37
|
-
end
|
@@ -1,104 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'support/time_machine/structure'
|
3
|
-
|
4
|
-
describe ChronoModel::TimeMachine do
|
5
|
-
include ChronoTest::TimeMachine::Helpers
|
6
|
-
|
7
|
-
describe '.history' do
|
8
|
-
let(:foo_history) {
|
9
|
-
['foo', 'foo bar', 'new foo', 'foo 0', 'foo 1']
|
10
|
-
}
|
11
|
-
|
12
|
-
let(:bar_history) {
|
13
|
-
['bar', 'foo bar', 'bar bar', 'new bar', 'bar 0', 'bar 1']
|
14
|
-
}
|
15
|
-
|
16
|
-
it { expect(Foo.history.all.map(&:name)).to eq foo_history }
|
17
|
-
it { expect(Bar.history.all.map(&:name)).to eq bar_history }
|
18
|
-
|
19
|
-
it { expect(Foo.history.first).to be_a(Foo::History) }
|
20
|
-
it { expect(Bar.history.first).to be_a(Bar::History) }
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
describe '#history' do
|
25
|
-
describe 'returns historical instances' do
|
26
|
-
it { expect($t.foo.history.size).to eq(3) }
|
27
|
-
it { expect($t.foo.history.map(&:name)).to eq ['foo', 'foo bar', 'new foo'] }
|
28
|
-
|
29
|
-
it { expect($t.bar.history.size).to eq(4) }
|
30
|
-
it { expect($t.bar.history.map(&:name)).to eq ['bar', 'foo bar', 'bar bar', 'new bar'] }
|
31
|
-
end
|
32
|
-
|
33
|
-
describe 'does not return read only records' do
|
34
|
-
it { expect($t.foo.history.all?(&:readonly?)).to be(false) }
|
35
|
-
it { expect($t.bar.history.all?(&:readonly?)).to be(false) }
|
36
|
-
end
|
37
|
-
|
38
|
-
describe 'takes care of associated records' do
|
39
|
-
subject { $t.foo.history.map {|f| f.bars.first.try(:name)} }
|
40
|
-
it { is_expected.to eq [nil, 'foo bar', 'new bar'] }
|
41
|
-
end
|
42
|
-
|
43
|
-
describe 'does not return read only associated records' do
|
44
|
-
it { expect($t.foo.history[2].bars.all?(&:readonly?)).to_not be(true) }
|
45
|
-
it { expect($t.bar.history.all? {|b| b.foo.readonly?}).to_not be(true) }
|
46
|
-
end
|
47
|
-
|
48
|
-
describe 'allows a custom select list' do
|
49
|
-
it { expect($t.foo.history.select(:id).first.attributes.keys).to eq %w( id ) }
|
50
|
-
end
|
51
|
-
|
52
|
-
describe 'does not add as_of_time when there are aggregates' do
|
53
|
-
it { expect($t.foo.history.select('max(id)').to_sql).to_not match(/as_of_time/) }
|
54
|
-
|
55
|
-
it { expect($t.foo.history.except(:order).select('max(id) as foo, min(id) as bar').group('id').first.attributes.keys).to eq %w( id foo bar ) }
|
56
|
-
end
|
57
|
-
|
58
|
-
context '.sorted' do
|
59
|
-
describe 'orders by recorded_at, hid' do
|
60
|
-
it { expect($t.foo.history.sorted.to_sql).to match(/order by .+"recorded_at" ASC, .+"hid" ASC/i) }
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
describe '#current_version' do
|
67
|
-
describe 'on plain records' do
|
68
|
-
subject { $t.foo.current_version }
|
69
|
-
it { is_expected.to eq $t.foo }
|
70
|
-
end
|
71
|
-
|
72
|
-
describe 'from #as_of' do
|
73
|
-
subject { $t.foo.as_of(Time.now) }
|
74
|
-
it { is_expected.to eq $t.foo }
|
75
|
-
end
|
76
|
-
|
77
|
-
describe 'on historical records' do
|
78
|
-
subject { $t.foo.history.sample.current_version }
|
79
|
-
it { is_expected.to eq $t.foo }
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
|
84
|
-
describe '#historical?' do
|
85
|
-
subject { record.historical? }
|
86
|
-
|
87
|
-
describe 'on plain records' do
|
88
|
-
let(:record) { $t.foo }
|
89
|
-
it { is_expected.to be(false) }
|
90
|
-
end
|
91
|
-
|
92
|
-
describe 'on historical records' do
|
93
|
-
describe 'from #history' do
|
94
|
-
let(:record) { $t.foo.history.first }
|
95
|
-
it { is_expected.to be(true) }
|
96
|
-
end
|
97
|
-
|
98
|
-
describe 'from #as_of' do
|
99
|
-
let(:record) { $t.foo.as_of(Time.now) }
|
100
|
-
it { is_expected.to be(true) }
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'support/time_machine/structure'
|
3
|
-
|
4
|
-
describe ChronoModel::TimeMachine do
|
5
|
-
include ChronoTest::TimeMachine::Helpers
|
6
|
-
|
7
|
-
describe 'does not interfere with AR standard behaviour' do
|
8
|
-
let(:all_foos) { [ $t.foo ] + $t.foos }
|
9
|
-
let(:all_bars) { [ $t.bar ] + $t.bars }
|
10
|
-
|
11
|
-
it { expect(Foo.count).to eq all_foos.size }
|
12
|
-
it { expect(Bar.count).to eq all_bars.size }
|
13
|
-
|
14
|
-
it { expect(Foo.includes(bars: :sub_bars)).to eq all_foos }
|
15
|
-
it { expect(Foo.includes(:bars).preload(bars: :sub_bars)).to eq all_foos }
|
16
|
-
|
17
|
-
it { expect(Foo.includes(:bars).first.name).to eq 'new foo' }
|
18
|
-
it { expect(Foo.includes(:bars).as_of($t.foo.ts[0]).first.name).to eq 'foo' }
|
19
|
-
|
20
|
-
it { expect(Foo.joins(:bars).map(&:bars).flatten).to eq all_bars }
|
21
|
-
it { expect(Foo.joins(:bars).first.bars.joins(:sub_bars).first.name).to eq 'new bar' }
|
22
|
-
|
23
|
-
it { expect(Foo.joins(bars: :sub_bars).first.bars.joins(:sub_bars).first.sub_bars.first.name).to eq 'new sub-bar' }
|
24
|
-
|
25
|
-
it { expect(Foo.first.bars.includes(:sub_bars)).to eq [ $t.bar ] }
|
26
|
-
end
|
27
|
-
end
|
@@ -1,84 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'support/time_machine/structure'
|
3
|
-
|
4
|
-
describe ChronoModel::TimeMachine do
|
5
|
-
include ChronoTest::TimeMachine::Helpers
|
6
|
-
|
7
|
-
describe '#save' do
|
8
|
-
subject { $t.bar.history.first }
|
9
|
-
|
10
|
-
it do
|
11
|
-
with_revert do
|
12
|
-
subject.name = 'modified bar history'
|
13
|
-
subject.save
|
14
|
-
subject.reload
|
15
|
-
|
16
|
-
is_expected.to be_a(Bar::History)
|
17
|
-
expect(subject.name).to eq 'modified bar history'
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe '#save!' do
|
23
|
-
subject { $t.bar.history.second }
|
24
|
-
|
25
|
-
it do
|
26
|
-
with_revert do
|
27
|
-
subject.name = 'another modified bar history'
|
28
|
-
subject.save
|
29
|
-
subject.reload
|
30
|
-
|
31
|
-
is_expected.to be_a(Bar::History)
|
32
|
-
expect(subject.name).to eq 'another modified bar history'
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
describe '#destroy' do
|
38
|
-
describe 'on historical records' do
|
39
|
-
subject { $t.foo.history.first.destroy }
|
40
|
-
it { expect { subject }.to raise_error(ActiveRecord::ReadOnlyRecord) }
|
41
|
-
end
|
42
|
-
|
43
|
-
describe 'on current records' do
|
44
|
-
rec = nil
|
45
|
-
before(:all) do
|
46
|
-
rec = ts_eval { Foo.create!(:name => 'alive foo', :fooity => 42) }
|
47
|
-
ts_eval(rec) { update_attributes!(:name => 'dying foo') }
|
48
|
-
end
|
49
|
-
after(:all) do
|
50
|
-
rec.history.delete_all
|
51
|
-
end
|
52
|
-
|
53
|
-
subject { rec.destroy }
|
54
|
-
|
55
|
-
it { expect { subject }.to_not raise_error }
|
56
|
-
it { expect { rec.reload }.to raise_error(ActiveRecord::RecordNotFound) }
|
57
|
-
|
58
|
-
describe 'does not delete its history' do
|
59
|
-
subject { record.name }
|
60
|
-
|
61
|
-
context do
|
62
|
-
let(:record) { rec.as_of(rec.ts.first) }
|
63
|
-
it { is_expected.to eq 'alive foo' }
|
64
|
-
end
|
65
|
-
|
66
|
-
context do
|
67
|
-
let(:record) { rec.as_of(rec.ts.last) }
|
68
|
-
it { is_expected.to eq 'dying foo' }
|
69
|
-
end
|
70
|
-
|
71
|
-
context do
|
72
|
-
let(:record) { Foo.as_of(rec.ts.first).where(:fooity => 42).first }
|
73
|
-
it { is_expected.to eq 'alive foo' }
|
74
|
-
end
|
75
|
-
|
76
|
-
context do
|
77
|
-
subject { Foo.history.where(:fooity => 42).map(&:name) }
|
78
|
-
it { is_expected.to eq ['alive foo', 'dying foo'] }
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'support/time_machine/structure'
|
3
|
-
|
4
|
-
describe ChronoModel::TimeMachine do
|
5
|
-
include ChronoTest::TimeMachine::Helpers
|
6
|
-
|
7
|
-
adapter.create_table 'plains' do |t|
|
8
|
-
t.string :foo
|
9
|
-
end
|
10
|
-
|
11
|
-
class ::Plain < ActiveRecord::Base
|
12
|
-
end
|
13
|
-
|
14
|
-
describe '.chrono?' do
|
15
|
-
subject { model.chrono? }
|
16
|
-
|
17
|
-
context 'on a temporal model' do
|
18
|
-
let(:model) { Foo }
|
19
|
-
it { is_expected.to be(true) }
|
20
|
-
end
|
21
|
-
|
22
|
-
context 'on a plain model' do
|
23
|
-
let(:model) { Plain }
|
24
|
-
it { is_expected.to be(false) }
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
describe '.history?' do
|
29
|
-
subject { model.history? }
|
30
|
-
|
31
|
-
context 'on a temporal parent model' do
|
32
|
-
let(:model) { Foo }
|
33
|
-
it { is_expected.to be(false) }
|
34
|
-
end
|
35
|
-
|
36
|
-
context 'on a temporal history model' do
|
37
|
-
let(:model) { Foo::History }
|
38
|
-
it { is_expected.to be(true) }
|
39
|
-
end
|
40
|
-
|
41
|
-
context 'on a plain model' do
|
42
|
-
let(:model) { Plain }
|
43
|
-
it { expect { subject }.to raise_error(NoMethodError) }
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'support/time_machine/structure'
|
3
|
-
|
4
|
-
describe ChronoModel::TimeMachine do
|
5
|
-
include ChronoTest::TimeMachine::Helpers
|
6
|
-
|
7
|
-
describe '#pred' do
|
8
|
-
context 'on the first history entry' do
|
9
|
-
subject { $t.foo.history.first.pred }
|
10
|
-
it { is_expected.to be(nil) }
|
11
|
-
end
|
12
|
-
|
13
|
-
context 'on the second history entry' do
|
14
|
-
subject { $t.foo.history.second.pred }
|
15
|
-
it { is_expected.to eq $t.foo.history.first }
|
16
|
-
end
|
17
|
-
|
18
|
-
context 'on the last history entry' do
|
19
|
-
subject { $t.foo.history.last.pred }
|
20
|
-
it { is_expected.to eq $t.foo.history[$t.foo.history.size - 2] }
|
21
|
-
end
|
22
|
-
|
23
|
-
context 'on records having history' do
|
24
|
-
subject { $t.bar.pred }
|
25
|
-
it { expect(subject.name).to eq 'bar bar' }
|
26
|
-
end
|
27
|
-
|
28
|
-
context 'when there is enough history' do
|
29
|
-
subject { $t.bar.pred.pred.pred.pred }
|
30
|
-
it { expect(subject.name).to eq 'bar' }
|
31
|
-
end
|
32
|
-
|
33
|
-
context 'when no history is recorded' do
|
34
|
-
let(:record) { Bar.create!(:name => 'quuuux') }
|
35
|
-
|
36
|
-
subject { record.pred }
|
37
|
-
|
38
|
-
it { is_expected.to be(nil) }
|
39
|
-
|
40
|
-
after { record.destroy.history.delete_all }
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe '#succ' do
|
45
|
-
context 'on the first history entry' do
|
46
|
-
subject { $t.foo.history.first.succ }
|
47
|
-
|
48
|
-
it { is_expected.to eq $t.foo.history.second }
|
49
|
-
end
|
50
|
-
|
51
|
-
context 'on the second history entry' do
|
52
|
-
subject { $t.foo.history.second.succ }
|
53
|
-
|
54
|
-
it { is_expected.to eq $t.foo.history.third }
|
55
|
-
end
|
56
|
-
|
57
|
-
context 'on the last history entry' do
|
58
|
-
subject { $t.foo.history.last.succ }
|
59
|
-
|
60
|
-
it { is_expected.to be(nil) }
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
describe '#first' do
|
65
|
-
subject { $t.foo.history.sample.first }
|
66
|
-
it { is_expected.to eq $t.foo.history.first }
|
67
|
-
end
|
68
|
-
|
69
|
-
describe '#last' do
|
70
|
-
subject { $t.foo.history.sample.last }
|
71
|
-
it { is_expected.to eq $t.foo.history.last }
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
@@ -1,100 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'support/time_machine/structure'
|
3
|
-
|
4
|
-
# STI cases
|
5
|
-
#
|
6
|
-
# - https://github.com/ifad/chronomodel/issues/5
|
7
|
-
# - https://github.com/ifad/chronomodel/issues/47
|
8
|
-
#
|
9
|
-
describe 'models with STI' do
|
10
|
-
include ChronoTest::TimeMachine::Helpers
|
11
|
-
|
12
|
-
adapter.create_table 'elements', :temporal => true do |t|
|
13
|
-
t.string :title
|
14
|
-
t.string :type
|
15
|
-
end
|
16
|
-
|
17
|
-
class ::Element < ActiveRecord::Base
|
18
|
-
include ChronoModel::TimeMachine
|
19
|
-
end
|
20
|
-
|
21
|
-
class ::Publication < Element
|
22
|
-
end
|
23
|
-
|
24
|
-
describe '.descendants' do
|
25
|
-
subject { Element.descendants }
|
26
|
-
|
27
|
-
it { is_expected.to_not include(Element::History) }
|
28
|
-
it { is_expected.to include(Publication) }
|
29
|
-
end
|
30
|
-
|
31
|
-
describe '.descendants_with_history' do
|
32
|
-
subject { Element.descendants_with_history }
|
33
|
-
|
34
|
-
it { is_expected.to include(Element::History) }
|
35
|
-
it { is_expected.to include(Publication) }
|
36
|
-
end
|
37
|
-
|
38
|
-
describe 'timeline' do
|
39
|
-
let(:publication) do
|
40
|
-
pub = ts_eval { Publication.create! :title => 'wrong title' }
|
41
|
-
ts_eval(pub) { update_attributes! :title => 'correct title' }
|
42
|
-
|
43
|
-
pub
|
44
|
-
end
|
45
|
-
|
46
|
-
it { expect(publication.history.map(&:title)).to eq ['wrong title', 'correct title'] }
|
47
|
-
end
|
48
|
-
|
49
|
-
describe 'identity' do
|
50
|
-
adapter.create_table 'animals', temporal: true do |t|
|
51
|
-
t.string :type
|
52
|
-
end
|
53
|
-
|
54
|
-
class ::Animal < ActiveRecord::Base
|
55
|
-
include ChronoModel::TimeMachine
|
56
|
-
end
|
57
|
-
|
58
|
-
class ::Dog < Animal
|
59
|
-
end
|
60
|
-
|
61
|
-
class ::Goat < Animal
|
62
|
-
end
|
63
|
-
|
64
|
-
before do
|
65
|
-
Dog.create!
|
66
|
-
@later = Time.new
|
67
|
-
Goat.create!
|
68
|
-
end
|
69
|
-
|
70
|
-
after do
|
71
|
-
tables = ['temporal.animals', 'history.animals']
|
72
|
-
ActiveRecord::Base.connection.execute "truncate #{tables.join(', ')} cascade"
|
73
|
-
end
|
74
|
-
|
75
|
-
specify "select" do
|
76
|
-
expect(Animal.first).to be_a(Animal)
|
77
|
-
expect(Animal.as_of(@later).first).to be_a(Animal)
|
78
|
-
|
79
|
-
expect(Animal.where(type: 'Dog').first).to be_a(Dog)
|
80
|
-
expect(Dog.first).to be_a(Dog)
|
81
|
-
expect(Dog.as_of(@later).first).to be_a(Dog)
|
82
|
-
|
83
|
-
expect(Animal.where(type: 'Goat').first).to be_a(Goat)
|
84
|
-
expect(Goat.first).to be_a(Goat)
|
85
|
-
expect(Goat.as_of(@later).first).to be(nil)
|
86
|
-
expect(Goat.as_of(Time.now).first).to be_a(Goat)
|
87
|
-
end
|
88
|
-
|
89
|
-
specify "count" do
|
90
|
-
expect(Animal.count).to eq(2)
|
91
|
-
expect(Animal.as_of(@later).count).to eq(1)
|
92
|
-
|
93
|
-
expect(Dog.count).to eq(1)
|
94
|
-
expect(Dog.as_of(@later).count).to eq(1)
|
95
|
-
|
96
|
-
expect(Goat.count).to eq(1)
|
97
|
-
expect(Goat.as_of(@later).count).to eq(0)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|