Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue with blank strings and type extensions #381

Merged
merged 10 commits into from
Dec 2, 2020
24 changes: 12 additions & 12 deletions spec/type_extensions/array_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,32 @@ require "../spec_helper"

describe "Array" do
it "parses Array(Bool) from Array(String)" do
result = Bool::Lucky.parse(["true"])
result.value.should eq([true])
result = Bool::Lucky.parse!(["true"])
result.should eq([true])
end

it "parses Array(String)" do
result = String::Lucky.parse(["test"])
result.value.should eq(["test"])
result = String::Lucky.parse!(["test"])
result.should eq(["test"])
end

it "parses Array(Int32) from Array(String)" do
result = Int32::Lucky.parse(["10"])
result.value.should eq([10])
result = Int32::Lucky.parse!(["10"])
result.should eq([10])
end

it "parses Array(Int16) from Array(String)" do
result = Int16::Lucky.parse(["1"])
result.value.should eq([1_i16])
result = Int16::Lucky.parse!(["1"])
result.should eq([1_i16])
end

it "parses Array(Int64) from Array(String)" do
result = Int64::Lucky.parse(["1000"])
result.value.should eq([1000_i64])
result = Int64::Lucky.parse!(["1000"])
result.should eq([1000_i64])
end

it "parses Array(Float64) from Array(String)" do
result = Float64::Lucky.parse(["3.1415"])
result.value.should eq([3.1415])
result = Float64::Lucky.parse!(["3.1415"])
result.should eq([3.1415])
end
end
17 changes: 17 additions & 0 deletions spec/type_extensions/bool_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,21 @@ describe Bool do
true.blank?.should be_false
end
end

describe "parsing" do
it "parses empty string as nil" do
parse("").should be_a(Avram::Type::SuccessfulCast(Nil))
end

it "parses strings" do
parse("true").value.should eq(true)
parse("1").value.should eq(true)
parse("false").value.should eq(false)
parse("0").value.should eq(false)
end
jwoertink marked this conversation as resolved.
Show resolved Hide resolved
end
end

private def parse(value)
Bool::Lucky.parse(value)
end
14 changes: 11 additions & 3 deletions spec/type_extensions/enum_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,22 @@ require "../spec_helper"
include LazyLoadHelpers

describe "Enum" do
it "check enum" do
it "parses String enum" do
Issue::Status::Lucky.parse("1").value.should eq(Issue::Status.new(Issue::AvramStatus::Closed))
end
jwoertink marked this conversation as resolved.
Show resolved Hide resolved

it "parses empty String enum" do
Issue::Status::Lucky.parse("").should be_a(Avram::Type::SuccessfulCast(Nil))
end

it "checks enum" do
issue = IssueBox.create

issue.status.enum.should eq(Issue::AvramStatus::Opened)
issue.role.enum.should eq(Issue::AvramRole::Issue)
end

it "update enum" do
it "updates enum" do
issue = IssueBox.create

updated_issue = Issue::SaveOperation.update!(issue, status: Issue::Status.new(:closed))
Expand All @@ -19,7 +27,7 @@ describe "Enum" do
updated_issue.role.enum.should eq(Issue::AvramRole::Issue)
end

it "access enum methods" do
it "accesses enum methods" do
issue = IssueBox.create

issue.status.opened?.should eq(true)
Expand Down
19 changes: 0 additions & 19 deletions spec/type_extensions/int32_spec.cr

This file was deleted.

67 changes: 67 additions & 0 deletions spec/type_extensions/int_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
require "../spec_helper"

jwoertink marked this conversation as resolved.
Show resolved Hide resolved
describe "Int16" do
it "parses Int16 from String" do
result = Int16::Lucky.parse("10")
result.value.should eq(10_i16)
end

it "parses Int16 from Int32" do
result = Int16::Lucky.parse(400)
result.value.should eq(400_i16)
end

it "returns FailedCast when overflow from Int16 to Int32/64" do
result = Int16::Lucky.parse(1234556)
result.value.should eq(nil)
result.should be_a(Avram::Type::FailedCast)
end

it "returns nil if String is blank" do
result = Int16::Lucky.parse("")
result.value.should be_nil
result.should be_a(Avram::Type::SuccessfulCast(Nil))
end
end

describe "Int32" do
it "parses Int32 from String" do
result = Int32::Lucky.parse("10")
result.value.should eq(10)
end

it "parses Int32 from Int64" do
result = Int32::Lucky.parse(400_i64)
result.value.should eq(400)
end

it "returns FailedCast when overflow from Int64 to Int32" do
result = Int32::Lucky.parse(2147483648)
result.value.should eq(nil)
result.should be_a(Avram::Type::FailedCast)
end

it "returns nil if String is blank" do
result = Int32::Lucky.parse("")
result.value.should be_nil
result.should be_a(Avram::Type::SuccessfulCast(Nil))
end
end

describe "Int64" do
it "parses Int64 from String" do
result = Int64::Lucky.parse("10")
result.value.should eq(10_i64)
end

it "parses Int64 from Int32" do
result = Int64::Lucky.parse(400)
result.value.should eq(400_i64)
end

it "returns nil if String is blank" do
result = Int64::Lucky.parse("")
result.value.should be_nil
result.should be_a(Avram::Type::SuccessfulCast(Nil))
end
end
6 changes: 6 additions & 0 deletions spec/type_extensions/time_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ require "../spec_helper"

describe "Time column type" do
describe ".parse" do
it "returns nil if parsing an empty String" do
result = Time::Lucky.parse("")

result.should be_a(Avram::Type::SuccessfulCast(Nil))
end

it "casts various formats successfully" do
time = Time.local
times = {
Expand Down
4 changes: 4 additions & 0 deletions spec/type_extensions/uuid_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ require "../spec_helper"

describe "UUID column type" do
describe ".parse" do
it "returns successful cast if string is nil" do
UUID::Lucky.parse("").should be_a(Avram::Type::SuccessfulCast(Nil))
end

it "casts a UUID successfully" do
uuid = UUID.new("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11")
UUID::Lucky.parse(uuid).value.should eq uuid
Expand Down
2 changes: 2 additions & 0 deletions src/avram/charms/bool_extensions.cr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ struct Bool
include Avram::Type

def parse(value : String)
return parse(nil) if value.blank?

if %w(true 1).includes? value
SuccessfulCast(Bool).new true
elsif %w(false 0).includes? value
Expand Down
2 changes: 2 additions & 0 deletions src/avram/charms/enum_extensions.cr
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ macro avram_enum(enum_name, &block)
Lucky
end

def_equals @enum
getter :enum

# You may need to prefix with {{ @type }}
Expand Down Expand Up @@ -41,6 +42,7 @@ macro avram_enum(enum_name, &block)
end

def parse(value : String)
return parse(nil) if value.blank?
SuccessfulCast({{ enum_name }}).new({{ enum_name }}.new(value.to_i))
end

Expand Down
7 changes: 7 additions & 0 deletions src/avram/charms/int16_extensions.cr
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,14 @@ struct Int16
SuccessfulCast(Array(Int16)).new values
end

def parse(value : Int32)
SuccessfulCast(Int16).new value.to_i16
rescue OverflowError
FailedCast.new
end
jwoertink marked this conversation as resolved.
Show resolved Hide resolved

def parse(value : String)
return parse(nil) if value.blank?
SuccessfulCast(Int16).new value.to_i16
rescue ArgumentError
FailedCast.new
Expand Down
1 change: 1 addition & 0 deletions src/avram/charms/int32_extensions.cr
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ struct Int32
end

def parse(value : String)
return parse(nil) if value.blank?
SuccessfulCast(Int32).new value.to_i
rescue ArgumentError
FailedCast.new
Expand Down
1 change: 1 addition & 0 deletions src/avram/charms/int64_extensions.cr
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct Int64
end

def parse(value : String)
return parse(nil) if value.blank?
SuccessfulCast(Int64).new value.to_i64
rescue ArgumentError
FailedCast.new
Expand Down
4 changes: 3 additions & 1 deletion src/avram/charms/time_extensions.cr
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ struct Time
value
end

def parse(value : String) : SuccessfulCast(Time) | FailedCast
def parse(value : String) : SuccessfulCast(Time) | SuccessfulCast(Nil) | FailedCast
return parse(nil) if value.blank?

# Prefer user defined string formats
try_parsing_with_string_formats(value) ||
# Then try default formats
Expand Down
1 change: 1 addition & 0 deletions src/avram/charms/uuid_extensions.cr
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ struct UUID
end

def parse(value : String)
return parse(nil) if value.blank?
SuccessfulCast(UUID).new(UUID.new(value))
rescue
FailedCast.new
Expand Down
9 changes: 7 additions & 2 deletions src/avram/type.cr
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@ module Avram::Type
def parse(values : Array(String))
casts = values.map { |value| parse(value) }
if casts.all?(&.is_a?(SuccessfulCast))
values = casts.map { |c| c.as(SuccessfulCast).value }
parse(values)
casts.map(&.as(SuccessfulCast))
else
FailedCast.new
end
end

def parse!(values : Array(T)) forall T
values.map do |v|
parse!(v)
end
end

def parse!(value)
parse(value).as(SuccessfulCast).value
end
Expand Down
2 changes: 1 addition & 1 deletion src/avram/where.cr
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ module Avram::Where
end

abstract class ValueHoldingSqlClause < SqlClause
getter value : String | Array(String) | Array(Int32)
getter value : String | Array(String) | Array(Int32) | Nil
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was needed in order to get everything to compile. Though, adding it may lead to other issues. This was also brought up in a previous comment #27 (comment) But if we're going to treat nil as a SuccessfulCast, and treat empty strings as nil, then this just may be a side affect we deal with.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good news! UserQuery.new.name(nil) still raises a compile-time error saying to not do that. UserQuery.new.where(:name, nil) does work.


def initialize(@column, @value)
end
Expand Down