在创建NamedTuples数组时键入Mismatch Crystal

似乎有类型不匹配的问题,但我无法绕过它,需要第二双眼睛,我发现在处理数据库时,Crystal类型不匹配错误几乎是不可读的 .

别名(accounts.cr)

alias CampaignDetail = NamedTuple(id: Int32, list_id: Int32, list_name: String, list_status: String, is_triggered: String, trigger_data: String, sender_id: Int32, sender_name: String)
alias Sender = Array(Array(Sender | CampaignDetail)) | Array(Sender | CampaignDetail) | Array(String | Int32 | Nil)
alias CombinedCampaign = Array({id: Int32,
                                list_id: Int32,
                                list_name: String,
                                list_status: String,
                                is_triggered: String,
                                trigger_data: String,
                                sender_id: Int32,
                                sender_name: String})

alias AccountDetails = Array(NamedTuple(id_access: Int32,
                                        account_id: Int32,
                                        account_company: String,
                                        redis_host: String,
                                        redis_password: String,
                                        redis_port: Int16,
                                        db_host: String,
                                        db_username: String,
                                        db_password: String,
                                        db_port: Int32))

操作代码(accounts.cr)

uncombined_campaign_data : Sender | CampaignDetail | CombinedCampaign
uncombined_campaign_data = Array(CampaignDetail).new
campaign_data : Array(CombinedCampaign)
campaign_data = Array(CombinedCampaign).new
@mysql_conn.db_proc(query_campaigns,
                    alternate_db: "*****_#{account[:account_id]}",
                    host: account[:db_host],
                    username: account[:db_username],
                    port: account[:db_port].to_s,
                    password: account[:db_password],
                    type: :select) do |results|

    uncombined_campaign_data << [results.read(Int32),
                                 results.read(Int32),
                                 results.read(String),
                                 results.read(String),
                                 results.read(String),
                                 results.read(String)
                                ]
end

query_sender = %{SELECT `sender`.`id`, `sender`.`name` FROM `******`.`sender`
                 WHERE `sender`.`id` IN (#{campaign_data.join(", ") {|campaign| "'" + campaign.not_nil![0].to_s+ "'" }})}

combined_campaign = CombinedCampaign.new
combined_campaign_data = Array(CombinedCampaign).new

@mysql_conn.db_proc(query_campaigns,
                    alternate_db: "**********#{account[:account_id]}",
                    host: account[:db_host],
                    username: account[:db_username],
                    port: account[:db_port].to_s,
                    password: account[:db_password],
                    type: :select) do |results|
    id = results.read(Int32)
    sender = results.read(String)
    campaign_data += campaign_data.map_with_index do |campaign, i|
        if campaign.not_nil![0] == id
            {
                id:           campaign[0].nil? ? 0 : campaign.as(Int32),
                list_id:      campaign[1].nil? ? 0 : campaign.as(Int32),
                list_name:    campaign[2].nil? ? "" : campaign.as(String),
                list_status:  campaign[3].nil? ? "" : campaign.as(String),
                is_triggered: campaign[4].nil? ? "" : campaign.as(String),
                trigger_data: campaign[5].nil? ? "" : campaign.as(String),
                sender_id:    id.nil? ? 0 : id.as(Int32),
                sender_name:  sender.nil? ? "" : sender.as(String)
            }
        else
            {

                id:            0,
                list_id:      0,
                list_name:    "",
                list_status:  "",
                is_triggered: "",
                trigger_data: "",
                sender_id:     0,
                sender_name:  ""
            }
        end
    end
    combined_campaign_data += combined_campaign
end
campaign_data = combined_campaign_data

错误

当我尝试修复时,在几个不同的错误之间循环:

in classes/accounts.cr:123: no overload matches 'Array(NamedTuple(id: Int32, list_id: Int32, list_name: String, list_status: String, is_triggered: String, trigger_data: String, sender_id: Int32, sender_name: String))#<<' with type Array(Int32 | String)
Overloads are:
 - Array(T)#<<(value : T)

    uncombined_campaign_data << [results.read(Int32),

in classes/accounts.cr:123: type must be (Array(Accounts::Sender | NamedTuple(id: Int32, list_id: Int32,
r_name: String)) | Array(Array(Accounts::Sender | NamedTuple(id: Int32, list_id: Int32, list_name: Strin
 | Array(Int32 | String | Nil) | Array(NamedTuple(id: Int32, list_id: Int32, list_name: String, list_sta
e(id: Int32, list_id: Int32, list_name: String, list_status: String, is_triggered: String, trigger_data:
ist_name: String, list_status: String, is_triggered: String, trigger_data: String, sender_id: Int32, sen
ring, is_triggered: String, trigger_data: String, sender_id: Int32, sender_name: String)))

    uncombined_campaign_data += [results.read(Int32),
    ^~~~~~~~~~~~~~~~~~~~~~~~

我不明白人们如何真正利用这些错误,因为它们总是削弱我的开发时间,花费很长时间试图解读huuuge类型的不匹配消息 .

如果有人可以帮忙解决这个问题,那将会很棒,而且如果你能提供关于如何最好地调试晶体编译/运行时错误的任何指针,因为它们有时几乎都不可读 .

回答(1)

3 years ago

你混淆了NamedTuple,Tuple和Array这三种不同的类型 .

由于您要附加到CampaignDetail数组,因此还必须使用相同的键附加NamedTuple:

uncombined_campaign_data << {id: results.read(Int32), list_id: … }