[英]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::Decode
和Type<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.