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 error -- cast from Array(String) to String #895

Merged
merged 4 commits into from
Oct 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions db/migrations/20221015145114_create_tokens.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class CreateTokens::V20221015145114 < Avram::Migrator::Migration::V1
def migrate
create table_for(Token) do
primary_key id : Int64

add_timestamps

add name : String
add scopes : Array(String)
end
end

def rollback
drop table_for(Token)
end
end
10 changes: 5 additions & 5 deletions spec/avram/operations/define_attribute_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,14 @@ describe "attribute in operations" do
end

it "includes attribute errors when calling SaveOperation#valid?" do
params = Avram::Params.new({"terms_of_service" => ["not a boolean"]})
params = Avram::Params.new({"terms_of_service" => "not a boolean"})
operation = SaveOperationWithAttributes.new(params)
operation.setup_required_database_columns
operation.valid?.should be_false
end

it "can still save to the database" do
params = Avram::Params.new({"password_confirmation" => ["password"], "terms_of_service" => ["1"]})
params = Avram::Params.new({"password_confirmation" => "password", "terms_of_service" => "1"})
operation = SaveOperationWithAttributes.new(params)
operation.setup_required_database_columns
operation.save.should eq true
Expand Down Expand Up @@ -204,7 +204,7 @@ describe "file_attribute in operation" do
end

it "gracefully handles invalid params" do
params = Avram::Params.new({"thumb" => ["not a file"]})
params = Avram::Params.new({"thumb" => "not a file"})
operation = OperationWithAttributes.new(params)
operation.thumb.value.should be_nil
operation.thumb.errors.first.should eq "is invalid"
Expand All @@ -213,15 +213,15 @@ describe "file_attribute in operation" do
save_operation.thumb.value.should be_nil
save_operation.thumb.errors.first.should eq "is invalid"

params = Avram::Params.new({"biometric_confirmation" => ["not a file"]})
params = Avram::Params.new({"biometric_confirmation" => "not a file"})
post = PostFactory.create
delete_operation = DeleteOperationWithAttributes.new(post, params)
delete_operation.biometric_confirmation.value.should be_nil
delete_operation.biometric_confirmation.errors.first.should eq "is invalid"
end

it "includes file attribute errors when calling SaveOperation#valid?" do
params = Avram::Params.new({"thumb" => ["not a file"]})
params = Avram::Params.new({"thumb" => "not a file"})
operation = SaveOperationWithAttributes.new(params)
operation.setup_required_database_columns
operation.valid?.should be_false
Expand Down
4 changes: 2 additions & 2 deletions spec/avram/operations/operation_needs_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe "Avram::Operation needs" do
end

it "allows params to be passed in along with named args for needs" do
params = Avram::Params.new({"title" => ["test"], "published" => ["true"]})
params = Avram::Params.new({"title" => "test", "published" => "true"})

OperationWithNeeds.run(params, tags: ["one", "two"], id: 3) do |operation, value|
value.should eq "one, two"
Expand All @@ -74,7 +74,7 @@ end

describe "Avram::SaveOperation needs" do
it "sets up a method arg for save, update, and new" do
params = Avram::Params.new({"name" => ["Paul"]})
params = Avram::Params.new({"name" => "Paul"})
UserFactory.create
user = UserQuery.new.first

Expand Down
63 changes: 57 additions & 6 deletions spec/avram/params_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -39,39 +39,90 @@ end
describe Avram::Paramable do
describe "#has_key_for?" do
it "returns true for the Operation with the proper key" do
params = NestedParams.new({"test_operation_with_default_param_key:title" => ["Test"]})
params = NestedParams.new({"test_operation_with_default_param_key:title" => "Test"})

params.has_key_for?(TestOperationWithDefaultParamKey).should be_true
end

it "returns true for the Operation with a custom key" do
params = NestedParams.new({"test_op:title" => ["Test"]})
params = NestedParams.new({"test_op:title" => "Test"})

params.has_key_for?(TestOperationWithCustomParamKey).should be_true
end

it "returns false for the Operation with the improper key" do
params = NestedParams.new({"bad_key:title" => ["Test"]})
params = NestedParams.new({"bad_key:title" => "Test"})

params.has_key_for?(TestOperationWithDefaultParamKey).should be_false
end

it "returns false for the Operation with no key" do
params = NestedParams.new({"title" => ["Test"]})
params = NestedParams.new({"title" => "Test"})

params.has_key_for?(TestOperationWithDefaultParamKey).should be_false
end

it "returns true for the SaveOperation with the proper key" do
params = NestedParams.new({"user:name" => ["Test"]})
params = NestedParams.new({"user:name" => "Test"})

params.has_key_for?(SaveUser).should be_true
end

it "returns false for the SaveOperation with the improper key" do
params = NestedParams.new({"author:name" => ["Test"]})
params = NestedParams.new({"author:name" => "Test"})

params.has_key_for?(SaveUser).should be_false
end
end
end

private class SaveToken < Token::SaveOperation
permit_columns :name, :scopes
end

describe Avram::Params do
it "accepts hashes with all string values" do
name = "Auth token"
params = Avram::Params.new({"name" => name})

SaveToken.create(params) do |_, token|
token.should be_a(Token)

token.try do |_token|
_token.name.should eq(name)
end
end
end

it "accepts hashes with all array values" do
scopes = ["profile", "openid"]
params = Avram::Params.new({"scopes" => scopes})

SaveToken.create(params) do |_, token|
token.should be_a(Token)

token.try do |_token|
_token.scopes.should eq(scopes)
end
end
end

it "accepts hashes with a mixture of array and string values" do
name = "Auth token"
scopes = ["profile", "openid"]

params = Avram::Params.new({
"name" => name,
"scopes" => scopes,
})

SaveToken.create(params) do |_, token|
token.should be_a(Token)

token.try do |_token|
_token.name.should eq(name)
_token.scopes.should eq(scopes)
end
end
end
end
9 changes: 9 additions & 0 deletions spec/support/models/token.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Token < BaseModel
table do
column name : String = "Secret"
column scopes : Array(String) = ["email"]
end
end

class TokenQuery < Token::BaseQuery
end
28 changes: 17 additions & 11 deletions src/avram/params.cr
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
class Avram::Params
include Avram::Paramable

@hash : Hash(String, Array(String))
@hash : Hash(String, Array(String) | String) | \
Hash(String, Array(String)) | \
Hash(String, String)
Comment on lines +4 to +6
Copy link
Member

Choose a reason for hiding this comment

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

oh, interesting! I think this is where I got tripped up before. I didn't think to also do a union of each one. Nice 👍


def initialize
@hash = {} of String => Array(String)
@hash = {} of String => String
end

def initialize(@hash)
Expand All @@ -15,9 +17,9 @@ class Avram::Params
end

def nested(key : String) : Hash(String, String)
Hash(String, String).new.tap do |h|
@hash.each do |k, v|
h[k] = v.first?.to_s
Hash(String, String).new.tap do |params|
@hash.each do |_key, _value|
params[_key] = _value if _value.is_a?(String)
end
end
end
Expand All @@ -27,7 +29,11 @@ class Avram::Params
end

def nested_arrays(key : String) : Hash(String, Array(String))
@hash
Hash(String, Array(String)).new.tap do |params|
@hash.each do |_key, _value|
params[_key] = _value if _value.is_a?(Array)
end
end
end

def many_nested?(key : String) : Array(Hash(String, String))
Expand All @@ -39,19 +45,19 @@ class Avram::Params
end

def get?(key : String)
@hash[key]?.try(&.first?)
@hash[key]?.try { |value| value if value.is_a?(String) }
end

def get(key : String)
@hash[key].first
get?(key).not_nil!
end

def get_all?(key : String)
@hash[key]? || [] of String
@hash[key]?.try { |value| value if value.is_a?(Array) }
end

def get_all(key : String)
@hash[key]
get_all?(key).not_nil!
end

def nested_file?(key : String) : Hash(String, String)
Expand All @@ -63,6 +69,6 @@ class Avram::Params
end

def get_all_files(key : String)
@hash[key]
get_all(key)
end
end