ballot 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Contributing.md +68 -0
- data/History.md +5 -0
- data/Licence.md +27 -0
- data/Manifest.txt +68 -0
- data/README.rdoc +264 -0
- data/Rakefile +71 -0
- data/bin/ballot_generator +9 -0
- data/lib/ballot.rb +25 -0
- data/lib/ballot/action_controller.rb +32 -0
- data/lib/ballot/active_record.rb +152 -0
- data/lib/ballot/active_record/votable.rb +145 -0
- data/lib/ballot/active_record/vote.rb +35 -0
- data/lib/ballot/active_record/voter.rb +99 -0
- data/lib/ballot/railtie.rb +19 -0
- data/lib/ballot/sequel.rb +170 -0
- data/lib/ballot/sequel/vote.rb +99 -0
- data/lib/ballot/votable.rb +445 -0
- data/lib/ballot/vote.rb +129 -0
- data/lib/ballot/voter.rb +320 -0
- data/lib/ballot/words.rb +32 -0
- data/lib/generators/ballot.rb +40 -0
- data/lib/generators/ballot/install/install_generator.rb +27 -0
- data/lib/generators/ballot/install/templates/active_record/migration.rb +19 -0
- data/lib/generators/ballot/install/templates/sequel/migration.rb +25 -0
- data/lib/generators/ballot/standalone.rb +89 -0
- data/lib/generators/ballot/standalone/support.rb +70 -0
- data/lib/generators/ballot/summary/summary_generator.rb +27 -0
- data/lib/generators/ballot/summary/templates/active_record/migration.rb +15 -0
- data/lib/generators/ballot/summary/templates/sequel/migration.rb +20 -0
- data/lib/sequel/plugins/ballot_votable.rb +180 -0
- data/lib/sequel/plugins/ballot_voter.rb +125 -0
- data/test/active_record/ballot_votable_test.rb +16 -0
- data/test/active_record/ballot_voter_test.rb +13 -0
- data/test/active_record/rails_generator_test.rb +28 -0
- data/test/active_record/votable_voter_test.rb +19 -0
- data/test/generators/rails-activerecord/Rakefile +2 -0
- data/test/generators/rails-activerecord/app/.keep +0 -0
- data/test/generators/rails-activerecord/bin/rails +5 -0
- data/test/generators/rails-activerecord/config/application.rb +17 -0
- data/test/generators/rails-activerecord/config/boot.rb +3 -0
- data/test/generators/rails-activerecord/config/database.yml +12 -0
- data/test/generators/rails-activerecord/config/environment.rb +3 -0
- data/test/generators/rails-activerecord/config/routes.rb +3 -0
- data/test/generators/rails-activerecord/config/secrets.yml +5 -0
- data/test/generators/rails-activerecord/db/seeds.rb +1 -0
- data/test/generators/rails-activerecord/log/.keep +0 -0
- data/test/generators/rails-sequel/Rakefile +2 -0
- data/test/generators/rails-sequel/app/.keep +0 -0
- data/test/generators/rails-sequel/bin/rails +5 -0
- data/test/generators/rails-sequel/config/application.rb +14 -0
- data/test/generators/rails-sequel/config/boot.rb +3 -0
- data/test/generators/rails-sequel/config/database.yml +12 -0
- data/test/generators/rails-sequel/config/environment.rb +3 -0
- data/test/generators/rails-sequel/config/routes.rb +3 -0
- data/test/generators/rails-sequel/config/secrets.yml +5 -0
- data/test/generators/rails-sequel/db/seeds.rb +1 -0
- data/test/generators/rails-sequel/log/.keep +0 -0
- data/test/minitest_config.rb +14 -0
- data/test/sequel/ballot_votable_test.rb +45 -0
- data/test/sequel/ballot_voter_test.rb +42 -0
- data/test/sequel/rails_generator_test.rb +25 -0
- data/test/sequel/votable_voter_test.rb +19 -0
- data/test/sequel/vote_test.rb +105 -0
- data/test/support/active_record_setup.rb +145 -0
- data/test/support/generators_setup.rb +129 -0
- data/test/support/sequel_setup.rb +164 -0
- data/test/support/shared_examples/votable_examples.rb +630 -0
- data/test/support/shared_examples/voter_examples.rb +600 -0
- metadata +333 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest_config'
|
4
|
+
|
5
|
+
describe 'RailsGenerator' do
|
6
|
+
describe 'for Sequel' do
|
7
|
+
let(:orm_name) { 'sequel' }
|
8
|
+
let(:orm_version) { Sequel::VERSION }
|
9
|
+
let(:rails_version) { ActiveRecord::VERSION::STRING }
|
10
|
+
|
11
|
+
test_ballot_install(
|
12
|
+
generate: %r{create\s+db/migrate/\d+_install_ballot_vote_migration},
|
13
|
+
contents: /Sequel.migration.*create_table :ballot_votes do/m
|
14
|
+
)
|
15
|
+
|
16
|
+
test_ballot_summary_votable(
|
17
|
+
generate: %r{create\s+db/migrate/\d+_ballot_cache_for_votable},
|
18
|
+
contents: %r{
|
19
|
+
Sequel.migration.*
|
20
|
+
alter_table\s+:'votables'.*
|
21
|
+
add_column\s+:cached_ballot_summary,
|
22
|
+
}mx
|
23
|
+
)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest_config'
|
4
|
+
|
5
|
+
describe SequelVotableVoter do
|
6
|
+
describe_ballot_voter do
|
7
|
+
let(:voter) { SequelVotableVoter.create(name: 'I can vote!') }
|
8
|
+
let(:voter2) { SequelVotableVoter.create(name: 'I, too, can vote!') }
|
9
|
+
let(:votable) { voter2 }
|
10
|
+
let(:votable2) { voter }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe_ballot_votable do
|
14
|
+
let(:voter) { SequelVotableVoter.create(name: 'I can vote!') }
|
15
|
+
let(:voter2) { SequelVotableVoter.create(name: 'I, too, can vote!') }
|
16
|
+
let(:votable) { voter2 }
|
17
|
+
let(:votable2) { voter }
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest_config'
|
4
|
+
|
5
|
+
describe Ballot::Sequel::Vote do
|
6
|
+
before do
|
7
|
+
voter.cast_up_ballot_for votable
|
8
|
+
voter.cast_up_ballot_for votable2
|
9
|
+
voter.cast_up_ballot_for votable_cache
|
10
|
+
voter2.cast_down_ballot_for votable
|
11
|
+
voter2.cast_down_ballot_for votable2
|
12
|
+
voter2.cast_down_ballot_for votable_cache
|
13
|
+
expected_votes # Force the query now
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:expected_votes) {
|
17
|
+
[
|
18
|
+
Ballot::Sequel::Vote[1],
|
19
|
+
Ballot::Sequel::Vote[2],
|
20
|
+
Ballot::Sequel::Vote[3],
|
21
|
+
Ballot::Sequel::Vote[4],
|
22
|
+
Ballot::Sequel::Vote[5],
|
23
|
+
Ballot::Sequel::Vote[6]
|
24
|
+
]
|
25
|
+
}
|
26
|
+
|
27
|
+
describe 'dataset_module' do
|
28
|
+
it 'provides an up subset' do
|
29
|
+
assert_equal 3, Ballot::Sequel::Vote.dataset.up.count
|
30
|
+
assert_equal 3, Ballot::Sequel::Vote.up.count
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'provides a down subset' do
|
34
|
+
assert_equal 3, Ballot::Sequel::Vote.dataset.down.count
|
35
|
+
assert_equal 3, Ballot::Sequel::Vote.down.count
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'provides a for_type filter' do
|
39
|
+
assert_empty Ballot::Sequel::Vote.dataset.for_type('SequelNotVotable')
|
40
|
+
assert_empty Ballot::Sequel::Vote.for_type(SequelNotVotable)
|
41
|
+
refute_empty Ballot::Sequel::Vote.dataset.for_type('SequelVotable')
|
42
|
+
refute_empty Ballot::Sequel::Vote.for_type(SequelVotable)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'provides a by_type filter' do
|
46
|
+
assert_empty Ballot::Sequel::Vote.dataset.by_type('SequelNotVoter')
|
47
|
+
assert_empty Ballot::Sequel::Vote.by_type(SequelNotVoter)
|
48
|
+
refute_empty Ballot::Sequel::Vote.dataset.by_type('SequelVoter')
|
49
|
+
refute_empty Ballot::Sequel::Vote.by_type(SequelVoter)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe 'votable association' do
|
54
|
+
it 'defines #votable= correctly' do
|
55
|
+
v = Ballot::Sequel::Vote.new
|
56
|
+
v.votable = votable
|
57
|
+
assert_equal votable.id, v.votable_id
|
58
|
+
assert_equal Ballot::Sequel.type_name(votable), v.votable_type
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'defines votable_dataset correctly' do
|
62
|
+
assert_equal votable, voter.ballots_by.first.votable
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'defines eager loading correctly' do
|
66
|
+
sqls = capture_sql {
|
67
|
+
actual = Ballot::Sequel::Vote.eager(:votable).all
|
68
|
+
assert_equal expected_votes, actual
|
69
|
+
assert_equal [ votable, votable2, votable_cache ], actual.shift(3).map(&:votable)
|
70
|
+
assert_equal [ votable, votable2, votable_cache ], actual.shift(3).map(&:votable)
|
71
|
+
}
|
72
|
+
|
73
|
+
assert_match(/SELECT \* FROM `ballot_votes`/, sqls.shift)
|
74
|
+
assert_match(/SELECT \* FROM `votables` WHERE \(`id` IN \(1, 2\)\)/, sqls.shift)
|
75
|
+
assert_match(/SELECT \* FROM `votable_caches` WHERE \(`id` IN \(1\)\)/, sqls.shift)
|
76
|
+
assert_empty sqls
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'voter association' do
|
81
|
+
it 'defines #voter= correctly' do
|
82
|
+
v = Ballot::Sequel::Vote.new
|
83
|
+
v.voter = voter
|
84
|
+
assert_equal voter.id, v.voter_id
|
85
|
+
assert_equal Ballot::Sequel.type_name(voter), v.voter_type
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'defines voter_dataset correctly' do
|
89
|
+
assert_equal voter, votable.ballots_for_dataset.first.voter
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'defines eager loading correctly' do
|
93
|
+
sqls = capture_sql {
|
94
|
+
actual = Ballot::Sequel::Vote.eager(:voter).all
|
95
|
+
assert_equal expected_votes, actual
|
96
|
+
assert_equal [ voter ] * 3, actual.shift(3).map(&:voter)
|
97
|
+
assert_equal [ voter2 ] * 3, actual.shift(3).map(&:voter)
|
98
|
+
}
|
99
|
+
|
100
|
+
assert_match(/SELECT \* FROM `ballot_votes`/, sqls.shift)
|
101
|
+
assert_match(/SELECT \* FROM `voters` WHERE \(`id` IN \(1, 2\)\)/, sqls.shift)
|
102
|
+
assert_empty sqls
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
if RUBY_ENGINE == 'jruby'
|
6
|
+
require 'activerecord-jdbcsqlite3-adapter'
|
7
|
+
else
|
8
|
+
require 'sqlite3'
|
9
|
+
end
|
10
|
+
|
11
|
+
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
|
12
|
+
|
13
|
+
ActiveRecord::Schema.verbose = false
|
14
|
+
ActiveRecord::Schema.define(version: 1) do
|
15
|
+
create_table :ballot_votes do |t|
|
16
|
+
t.references :votable, polymorphic: true
|
17
|
+
t.references :voter, polymorphic: true
|
18
|
+
|
19
|
+
t.boolean :vote
|
20
|
+
t.string :scope
|
21
|
+
t.integer :weight
|
22
|
+
|
23
|
+
t.timestamps null: false, default: 'now()'
|
24
|
+
end
|
25
|
+
|
26
|
+
add_index :ballot_votes, %i(voter_id voter_type scope)
|
27
|
+
add_index :ballot_votes, %i(votable_id votable_type scope)
|
28
|
+
|
29
|
+
%i(voters not_voters votables not_votables votable_voters).each do |table|
|
30
|
+
create_table table do |t|
|
31
|
+
t.string :name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
%i(sti_votables sti_not_votables).each do |table|
|
36
|
+
create_table table do |t|
|
37
|
+
t.string :name
|
38
|
+
t.string :type
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
create_table :votable_caches do |t|
|
43
|
+
t.string :name
|
44
|
+
|
45
|
+
if t.respond_to?(:jsonb)
|
46
|
+
t.jsonb :cached_ballot_summary
|
47
|
+
else
|
48
|
+
t.string :cached_ballot_summary
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
require 'ballot/active_record'
|
54
|
+
Ballot::ActiveRecord.inject!
|
55
|
+
|
56
|
+
class ARVoter < ActiveRecord::Base
|
57
|
+
self.table_name = 'voters'
|
58
|
+
acts_as_ballot :voter
|
59
|
+
end
|
60
|
+
|
61
|
+
class ARNotVoter < ActiveRecord::Base
|
62
|
+
self.table_name = 'not_voters'
|
63
|
+
end
|
64
|
+
|
65
|
+
class ARVotable < ActiveRecord::Base
|
66
|
+
self.table_name = 'votables'
|
67
|
+
acts_as_ballot :votable
|
68
|
+
end
|
69
|
+
|
70
|
+
class ARNotVotable < ActiveRecord::Base
|
71
|
+
self.table_name = 'not_votables'
|
72
|
+
end
|
73
|
+
|
74
|
+
class ARVotableVoter < ActiveRecord::Base
|
75
|
+
self.table_name = 'votable_voters'
|
76
|
+
acts_as_ballot :voter
|
77
|
+
acts_as_ballot :votable
|
78
|
+
end
|
79
|
+
|
80
|
+
class ARStiVotable < ActiveRecord::Base
|
81
|
+
self.table_name = 'sti_votables'
|
82
|
+
acts_as_ballot :votable
|
83
|
+
end
|
84
|
+
|
85
|
+
class ARChildOfStiVotable < ARStiVotable
|
86
|
+
end
|
87
|
+
|
88
|
+
class ARStiNotVotable < ActiveRecord::Base
|
89
|
+
self.table_name = 'sti_not_votables'
|
90
|
+
end
|
91
|
+
|
92
|
+
class ARVotableChildOfStiNotVotable < ARStiNotVotable
|
93
|
+
acts_as_ballot :votable
|
94
|
+
end
|
95
|
+
|
96
|
+
class ARVotableCache < ActiveRecord::Base
|
97
|
+
self.table_name = 'votable_caches'
|
98
|
+
acts_as_ballot :votable
|
99
|
+
end
|
100
|
+
|
101
|
+
class ARABoringClass
|
102
|
+
end
|
103
|
+
|
104
|
+
class Minitest::ActiveRecordSpec < Minitest::HooksSpec
|
105
|
+
register_spec_type(/ActiveRecord|\AAR/, self)
|
106
|
+
|
107
|
+
AbortTransaction = Class.new(StandardError)
|
108
|
+
|
109
|
+
def around
|
110
|
+
ActiveRecord::Base.connection.transaction do
|
111
|
+
super
|
112
|
+
fail AbortTransaction
|
113
|
+
end
|
114
|
+
rescue AbortTransaction
|
115
|
+
true # This transaction has been deliberately aborted.
|
116
|
+
end
|
117
|
+
|
118
|
+
def votable_dataset(votable)
|
119
|
+
votable.ballots_for
|
120
|
+
end
|
121
|
+
|
122
|
+
def voter_dataset(voter)
|
123
|
+
voter.ballots_by
|
124
|
+
end
|
125
|
+
|
126
|
+
def ballot_type_name(item)
|
127
|
+
Ballot::ActiveRecord.type_name(item)
|
128
|
+
end
|
129
|
+
|
130
|
+
let(:voter) { ARVoter.create(name: 'I can vote!') }
|
131
|
+
let(:voter2) { ARVoter.create(name: 'I, too, can vote!') }
|
132
|
+
let(:not_voter) { ARNotVoter.create(name: 'I cannot vote!') }
|
133
|
+
|
134
|
+
let(:votable) { ARVotable.create(name: 'a votable model') }
|
135
|
+
let(:votable2) { ARVotable.create(name: 'a second votable model') }
|
136
|
+
let(:votable_cache) { ARVotableCache.create(name: 'a votable model with caching') }
|
137
|
+
let(:sti_votable) { ARStiVotable.create(name: 'a votable STI model') }
|
138
|
+
let(:child_of_sti_votable) {
|
139
|
+
ARChildOfStiVotable.create(name: 'a votable STI child model')
|
140
|
+
}
|
141
|
+
let(:votable_child_of_sti_not_votable) {
|
142
|
+
ARVotableChildOfStiNotVotable.create(name: 'a votable STI child of a non-votable')
|
143
|
+
}
|
144
|
+
let(:not_votable) { ARNotVotable.create(name: 'a non-votable model') }
|
145
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Minitest::RailsGeneratorSpec < Minitest::HooksSpec
|
4
|
+
register_spec_type(/RailsGenerator/, self)
|
5
|
+
|
6
|
+
let(:app_path) { "test/generators/rails-#{orm_name}" }
|
7
|
+
|
8
|
+
def around
|
9
|
+
ENV['RAILS_VERSION'] = rails_version
|
10
|
+
ENV['ORM_VERSION'] = orm_version
|
11
|
+
gemfile = File.join(File.expand_path(app_path), 'Gemfile')
|
12
|
+
|
13
|
+
Dir.chdir(app_path) do
|
14
|
+
without_current_bundler do
|
15
|
+
ENV['BUNDLE_GEMFILE'] = gemfile
|
16
|
+
system! 'git clean -fdx .'
|
17
|
+
system! 'gem install bundler'
|
18
|
+
if ENV['TRAVIS']
|
19
|
+
system! 'bundle --version'
|
20
|
+
system! 'bundle install'
|
21
|
+
end
|
22
|
+
system! 'bundle exec rake db:create'
|
23
|
+
system! 'bundle exec rails g model votable name'
|
24
|
+
run_migrations!
|
25
|
+
|
26
|
+
yield
|
27
|
+
end
|
28
|
+
end
|
29
|
+
ensure
|
30
|
+
ENV.delete('ORM_VERSION')
|
31
|
+
ENV.delete('RAILS_VERSION')
|
32
|
+
ENV.delete('BUNDLE_GEMFILE')
|
33
|
+
end
|
34
|
+
|
35
|
+
def without_current_bundler(&block)
|
36
|
+
if defined?(::Bundler)
|
37
|
+
Bundler.with_clean_env(&block)
|
38
|
+
else
|
39
|
+
yield
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def assert_subprocess_output(stdout = nil, stderr = nil)
|
44
|
+
out, err = capture_subprocess_io { yield }
|
45
|
+
|
46
|
+
err_msg = stderr.kind_of?(Regexp) ? :assert_match : :assert_equal if stderr
|
47
|
+
out_msg = stdout.kind_of?(Regexp) ? :assert_match : :assert_equal if stdout
|
48
|
+
|
49
|
+
y = send err_msg, stderr, err, 'In stderr' if err_msg
|
50
|
+
x = send out_msg, stdout, out, 'In stdout' if out_msg
|
51
|
+
|
52
|
+
(!stdout || x) && (!stderr || y)
|
53
|
+
end
|
54
|
+
|
55
|
+
def assert_contents(contents, filename)
|
56
|
+
contents_msg = contents.kind_of?(Regexp) ? :assert_match : :assert_equal
|
57
|
+
send contents_msg, contents, File.read(filename), 'In contents'
|
58
|
+
end
|
59
|
+
|
60
|
+
def run_migrations
|
61
|
+
system 'bundle exec rake db:migrate'
|
62
|
+
end
|
63
|
+
|
64
|
+
def run_migrations!
|
65
|
+
system! 'bundle exec rake db:migrate'
|
66
|
+
end
|
67
|
+
|
68
|
+
def system!(command)
|
69
|
+
output = capture_subprocess_io { system command }
|
70
|
+
fail output.join("\n") unless $?.success?
|
71
|
+
end
|
72
|
+
|
73
|
+
def rails_generate(*args)
|
74
|
+
system "bundle exec rails g #{args.join(' ')}"
|
75
|
+
end
|
76
|
+
|
77
|
+
class << self
|
78
|
+
def focus!
|
79
|
+
@focussed = true
|
80
|
+
end
|
81
|
+
|
82
|
+
def focussed?
|
83
|
+
!!@focussed
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_ballot_install(generate: nil, migrate: nil, contents: nil)
|
87
|
+
return unless ENV['CI'] || ENV['TEST_GENERATORS']
|
88
|
+
|
89
|
+
fail 'Contents must be provided' unless contents
|
90
|
+
|
91
|
+
focus if focussed?
|
92
|
+
it 'installs the ballot_votes table' do
|
93
|
+
assert_subprocess_output generate || '' do
|
94
|
+
rails_generate 'ballot:install'
|
95
|
+
end
|
96
|
+
|
97
|
+
assert_subprocess_output migrate || '' do
|
98
|
+
run_migrations
|
99
|
+
end
|
100
|
+
|
101
|
+
assert_contents contents,
|
102
|
+
Dir['db/migrate/*_install_ballot_vote_migration.rb'].first
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_ballot_summary_votable(generate: nil, migrate: nil, contents: nil)
|
107
|
+
return unless ENV['CI'] || ENV['TEST_GENERATORS']
|
108
|
+
|
109
|
+
fail 'Contents must be provided' unless contents
|
110
|
+
|
111
|
+
focus if focussed?
|
112
|
+
it 'adds the summary column to the votable table' do
|
113
|
+
assert_nil File.read('db/schema.rb').match(/cached_ballot_summary/)
|
114
|
+
|
115
|
+
assert_subprocess_output generate || '' do
|
116
|
+
rails_generate 'ballot:summary', 'votable'
|
117
|
+
end
|
118
|
+
|
119
|
+
assert_subprocess_output migrate || '' do
|
120
|
+
run_migrations
|
121
|
+
end
|
122
|
+
|
123
|
+
assert_contents contents,
|
124
|
+
Dir['db/migrate/*_ballot_cache_for_votable.rb'].first
|
125
|
+
assert_contents(/cached_ballot_summary/, 'db/schema.rb')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sequel'
|
4
|
+
|
5
|
+
DB = if RUBY_ENGINE == 'jruby'
|
6
|
+
Sequel.connect('jdbc:sqlite::memory:')
|
7
|
+
else
|
8
|
+
Sequel.sqlite
|
9
|
+
end
|
10
|
+
|
11
|
+
class SQLLogger
|
12
|
+
class << self
|
13
|
+
def sqls
|
14
|
+
Thread.current['sqls'] ||= []
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(_, msg)
|
18
|
+
sqls << msg
|
19
|
+
end
|
20
|
+
|
21
|
+
def clear
|
22
|
+
sqls.clear
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
DB.loggers << SQLLogger
|
28
|
+
|
29
|
+
DB.create_table? :ballot_votes do
|
30
|
+
primary_key :id
|
31
|
+
Integer :votable_id
|
32
|
+
String :votable_type
|
33
|
+
|
34
|
+
Integer :voter_id
|
35
|
+
String :voter_type
|
36
|
+
|
37
|
+
Boolean :vote
|
38
|
+
String :scope
|
39
|
+
Integer :weight
|
40
|
+
|
41
|
+
DateTime :created_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
42
|
+
DateTime :updated_at, null: false, default: Sequel::CURRENT_TIMESTAMP
|
43
|
+
end
|
44
|
+
|
45
|
+
%i(voters not_voters votables not_votables votable_voters).each do |table|
|
46
|
+
DB.create_table? table do
|
47
|
+
primary_key :id
|
48
|
+
String :name
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
%i(sti_votables sti_not_votables).each do |table|
|
53
|
+
DB.create_table? table do
|
54
|
+
primary_key :id
|
55
|
+
String :name
|
56
|
+
String :type
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
DB.create_table? :votable_caches do
|
61
|
+
primary_key :id
|
62
|
+
|
63
|
+
String :name
|
64
|
+
|
65
|
+
if Sequel.respond_to?(:pg_json)
|
66
|
+
if respond_to?(:jsonb)
|
67
|
+
jsonb :cached_ballot_summary
|
68
|
+
else
|
69
|
+
json :cached_ballot_summary
|
70
|
+
end
|
71
|
+
else
|
72
|
+
String :cached_ballot_summary
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
require 'ballot/sequel'
|
77
|
+
|
78
|
+
class SequelVoter < Sequel::Model(:voters)
|
79
|
+
plugin :ballot_voter
|
80
|
+
end
|
81
|
+
|
82
|
+
class SequelNotVoter < Sequel::Model(:not_voters)
|
83
|
+
end
|
84
|
+
|
85
|
+
class SequelVotable < Sequel::Model(:votables)
|
86
|
+
plugin :ballot_votable
|
87
|
+
end
|
88
|
+
|
89
|
+
class SequelNotVotable < Sequel::Model(:not_votables)
|
90
|
+
end
|
91
|
+
|
92
|
+
class SequelVotableVoter < Sequel::Model(:votable_voters)
|
93
|
+
plugin :ballot_voter
|
94
|
+
plugin :ballot_votable
|
95
|
+
end
|
96
|
+
|
97
|
+
class SequelStiVotable < Sequel::Model(:sti_votables)
|
98
|
+
plugin :single_table_inheritance, :type
|
99
|
+
plugin :ballot_votable
|
100
|
+
end
|
101
|
+
|
102
|
+
class SequelChildOfStiVotable < SequelStiVotable
|
103
|
+
end
|
104
|
+
|
105
|
+
class SequelStiNotVotable < Sequel::Model(:sti_not_votables)
|
106
|
+
plugin :single_table_inheritance, :type
|
107
|
+
end
|
108
|
+
|
109
|
+
class SequelVotableChildOfStiNotVotable < SequelStiNotVotable
|
110
|
+
plugin :ballot_votable
|
111
|
+
end
|
112
|
+
|
113
|
+
class SequelVotableCache < Sequel::Model(:votable_caches)
|
114
|
+
plugin :ballot_votable
|
115
|
+
end
|
116
|
+
|
117
|
+
class SequelABoringClass
|
118
|
+
end
|
119
|
+
|
120
|
+
class Minitest::SequelSpec < Minitest::HooksSpec
|
121
|
+
parallelize_me! unless RUBY_ENGINE == 'jruby'
|
122
|
+
|
123
|
+
register_spec_type(/Sequel/, self)
|
124
|
+
|
125
|
+
def around
|
126
|
+
Sequel::Model.db.transaction(rollback: :always, auto_savepoint: true) { super }
|
127
|
+
end
|
128
|
+
|
129
|
+
def capture_sql
|
130
|
+
SQLLogger.clear
|
131
|
+
yield
|
132
|
+
SQLLogger.sqls.dup
|
133
|
+
ensure
|
134
|
+
SQLLogger.clear
|
135
|
+
end
|
136
|
+
|
137
|
+
def votable_dataset(votable)
|
138
|
+
votable.ballots_for_dataset
|
139
|
+
end
|
140
|
+
|
141
|
+
def voter_dataset(voter)
|
142
|
+
voter.ballots_by_dataset
|
143
|
+
end
|
144
|
+
|
145
|
+
def ballot_type_name(item)
|
146
|
+
Ballot::Sequel.type_name(item)
|
147
|
+
end
|
148
|
+
|
149
|
+
let(:voter) { SequelVoter.create(name: 'I can vote!') }
|
150
|
+
let(:voter2) { SequelVoter.create(name: 'I, too, can vote!') }
|
151
|
+
let(:not_voter) { SequelNotVoter.create(name: 'I cannot vote!') }
|
152
|
+
|
153
|
+
let(:votable) { SequelVotable.create(name: 'a votable model') }
|
154
|
+
let(:votable2) { SequelVotable.create(name: 'a second votable model') }
|
155
|
+
let(:votable_cache) { SequelVotableCache.create(name: 'a votable model with caching') }
|
156
|
+
let(:sti_votable) { SequelStiVotable.create(name: 'a votable STI model') }
|
157
|
+
let(:child_of_sti_votable) {
|
158
|
+
SequelChildOfStiVotable.create(name: 'a votable STI child model')
|
159
|
+
}
|
160
|
+
let(:votable_child_of_sti_not_votable) {
|
161
|
+
SequelVotableChildOfStiNotVotable.create(name: 'a votable STI child of a non-votable')
|
162
|
+
}
|
163
|
+
let(:not_votable) { SequelNotVotable.create(name: 'a non-votable model') }
|
164
|
+
end
|