簡體   English   中英

sqlx:實現解碼和類型<db>對於相關的特征類型</db>

[英]sqlx: implementing Decode and Type<DB> for associated trait type

我正在嘗試創建一個庫,該庫從 SQL 數據庫中獲取多個標簽的值。 根據可以是 Analog 或 String 的 TagType - 我需要返回匹配的值類型。 我嘗試使用Tag特征中名為ValueType的關聯類型來實現這一點

這是我到目前為止所得到的:

use sqlx::Row;

pub trait Tag {
    type ValueType;

    fn name(&self) -> String;
    fn tagtype(&self) -> TagType;
}

pub enum TagType {
    Analog = 1,
    String = 3,
}

pub struct AnalogTag(String);
pub struct StringTag(String);

impl Tag for AnalogTag {
    type ValueType = f64;

    fn name(&self) -> String {
        self.0.to_string()
    }

    fn tagtype(&self) -> TagType {
        TagType::Analog
    }
}

impl Tag for StringTag {
    type ValueType = String;

    fn name(&self) -> String {
        self.0.to_string()
    }

    fn tagtype(&self) -> TagType {
        TagType::String
    }
}

pub struct Value<T> {
    pub val: T,
    pub quality: i8,
}

impl<T> Value<T> {
    fn new(val: T, quality: i8) -> Self {
        Self { val, quality }
    }
}

pub async fn get_actual_value<T: Tag>(
    db_pool: sqlx::MssqlPool,
    tag: T,
) -> Result<Value<T::ValueType>, sqlx::Error> {
    let table = match tag.tagtype() {
        TagType::Analog => "AnalogLive",
        TagType::String => "StringLive",
    };
    let result = sqlx::query("SELECT Value, Quality FROM @P1 WHERE Tagname = @P2")
        .bind(table)
        .bind(tag.name())
        .fetch_one(&db_pool)
        .await?;
    let val = result.get("Value");
    let quality: i8 = result.get("Quality");
    Ok(Value::new(val, quality))
}

無論如何,這是行不通的。 我需要實現sqlx::DecodeType<Mssql>特征,但不知道如何對作為特征Tag的關聯類型的ValueType執行此操作

特征sqlx::Decode<'_, Mssql>未實現<T as Tag>::ValueType特征Type<Mssql>未實現<T as Tag>::ValueType

任何幫助,將不勝感激!

編輯將代碼示例更新為最小的可重現示例

您在這里遇到了問題,您希望將僅在運行時已知的類型( TagType枚舉)轉換為在編譯時已知的類型( T::ValueType )。 這不是微不足道的,需要一些技巧。 您必須了解編譯器對tag.tagtype()將在編譯時返回的內容的了解為零。

幸運的是, result::get() function 已經為解決這個問題付出了艱苦的努力。

因此,對T::ValueType有一點額外的特征限制,你可以讓它工作:

use sqlx::Row;

pub trait Tag {
    type ValueType;

    fn name(&self) -> String;
    fn tagtype(&self) -> TagType;
}

pub enum TagType {
    Analog = 1,
    String = 3,
}

pub struct AnalogTag(String);
pub struct StringTag(String);

impl Tag for AnalogTag {
    type ValueType = f64;

    fn name(&self) -> String {
        self.0.to_string()
    }

    fn tagtype(&self) -> TagType {
        TagType::Analog
    }
}

impl Tag for StringTag {
    type ValueType = String;

    fn name(&self) -> String {
        self.0.to_string()
    }

    fn tagtype(&self) -> TagType {
        TagType::String
    }
}

pub struct Value<T> {
    pub val: T,
    pub quality: i8,
}

impl<T> Value<T> {
    fn new(val: T, quality: i8) -> Self {
        Self { val, quality }
    }
}

pub async fn get_actual_value<T>(
    db_pool: sqlx::MssqlPool,
    tag: T,
) -> Result<Value<T::ValueType>, sqlx::Error>
where
    T: Tag,
    for<'a> T::ValueType: sqlx::Decode<'a, sqlx::Mssql> + sqlx::Type<sqlx::Mssql>,
{
    let table = match tag.tagtype() {
        TagType::Analog => "AnalogLive",
        TagType::String => "StringLive",
    };
    let result = sqlx::query("SELECT Value, Quality FROM @P1 WHERE Tagname = @P2")
        .bind(table)
        .bind(tag.name())
        .fetch_one(&db_pool)
        .await?;
    let quality: i8 = result.get("Quality");

    let val: T::ValueType = result.get("Value");
    Ok(Value::new(val, quality))
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM