Skip to content

Commit

Permalink
feat: Implement of_sql_type qualifier on have_db_column matcher (#…
Browse files Browse the repository at this point in the history
…1555)

This commit intends to implement the `of_sql_type` qualifier on the
`have_db_column` matcher. The implementation is quite simple and is
following the pattern of the `HaveDbColumnMatcher` class.

This commit closes this issue
#1432
  • Loading branch information
matsales28 committed May 2, 2023
1 parent bddc9c0 commit 0394a10
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 6 deletions.
52 changes: 46 additions & 6 deletions lib/shoulda/matchers/active_record/have_db_column_matcher.rb
Expand Up @@ -48,6 +48,30 @@ module ActiveRecord
# should have_db_column(:camera_aperture).of_type(:decimal)
# end
#
# ##### of_sql_type
#
# Use `of_sql_type` to assert that a column is defined as a certain sql_type.
#
# class CreatePhones < ActiveRecord::Migration
# def change
# create_table :phones do |t|
# t.string :camera_aperture, limit: 36
# end
# end
# end
#
# # RSpec
# RSpec.describe Phone, type: :model do
# it do
# should have_db_column(:camera_aperture).of_sql_type('varchar(36)')
# end
# end
#
# # Minitest (Shoulda)
# class PhoneTest < ActiveSupport::TestCase
# should have_db_column(:camera_aperture).of_sql_type('varchar(36)')
# end
#
# ##### with_options
#
# Use `with_options` to assert that a column has been defined with
Expand Down Expand Up @@ -96,6 +120,11 @@ def of_type(column_type)
self
end

def of_sql_type(sql_column_type)
@options[:sql_column_type] = sql_column_type
self
end

def with_options(opts = {})
validate_options(opts)
OPTIONS.each do |attribute|
Expand All @@ -110,6 +139,7 @@ def matches?(subject)
@subject = subject
column_exists? &&
correct_column_type? &&
correct_sql_column_type? &&
correct_precision? &&
correct_limit? &&
correct_default? &&
Expand All @@ -129,12 +159,9 @@ def failure_message_when_negated

def description
desc = "have db column named #{@column}"
if @options.key?(:column_type)
desc << " of type #{@options[:column_type]}"
end
if @options.key?(:precision)
desc << " of precision #{@options[:precision]}"
end
desc << " of type #{@options[:column_type]}" if @options.key?(:column_type)
desc << " of sql_type #{@options[:sql_column_type]}" if @options.key?(:sql_column_type)
desc << " of precision #{@options[:precision]}" if @options.key?(:precision)
desc << " of limit #{@options[:limit]}" if @options.key?(:limit)
desc << " of default #{@options[:default]}" if @options.key?(:default)
desc << " of null #{@options[:null]}" if @options.key?(:null)
Expand Down Expand Up @@ -178,6 +205,19 @@ def correct_column_type?
end
end

def correct_sql_column_type?
return true unless @options.key?(:sql_column_type)

if matched_column.sql_type.to_s == @options[:sql_column_type].to_s
true
else
@missing =
"#{model_class} has a db column named #{@column} " <<
"of sql type #{matched_column.sql_type}, not #{@options[:sql_column_type]}."
false
end
end

def correct_precision?
return true unless @options.key?(:precision)

Expand Down
Expand Up @@ -26,6 +26,42 @@
end
end

context '#of_sql_type' do
it 'accepts a column of correct type' do
sql_column_type = postgresql? ? 'character varying(36)' : 'varchar(36)'
expect(with_table(:nickname, :string, limit: 36)).
to have_db_column(:nickname).of_sql_type(sql_column_type)
end

it 'rejects a nonexistent database column' do
sql_column_type = postgresql? ? 'character varying(36)' : 'varchar(36)'
assertion = lambda do
expect(with_table(:nickname, :string, limit: 36)).
to have_db_column(:superhero).of_sql_type(sql_column_type)
end

message = <<-MESSAGE
Expected Employee to have db column named superhero of sql_type #{sql_column_type} (Employee does not have a db column named superhero.)
MESSAGE

expect(&assertion).to fail_with_message(message)
end

it 'rejects a column of wrong sql type' do
sql_column_type = postgresql? ? 'character varying(36)' : 'varchar(36)'
assertion = lambda do
expect(with_table(:nickname, :string, limit: 36)).
to have_db_column(:nickname).of_sql_type('varchar')
end

message = <<-MESSAGE
Expected Employee to have db column named nickname of sql_type varchar (Employee has a db column named nickname of sql type #{sql_column_type}, not varchar.)
MESSAGE

expect(&assertion).to fail_with_message(message)
end
end

context 'with precision option' do
it 'accepts a column of correct precision' do
expect(with_table(:salary, :decimal, precision: 5)).
Expand Down

0 comments on commit 0394a10

Please sign in to comment.