ballot 1.0
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.
- 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
|