-
-
Notifications
You must be signed in to change notification settings - Fork 530
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
Serialize QueryResult
into serde_json::Value
#4
Comments
Proposed use cases For let select_one: Value = cake::Entity::find() // Value::Object()
.one_json(db)
.await?;
let select_all: Value = cake::Entity::find() // Value::Array( Vec<Value::Object()> )
.all_json(db)
.await?; For let tuple_one: Value = cake::Entity::find() // Value::Array( Vec<Value::Object()> )
.left_join_and_select(filling::Entity)
.one_json(db)
.await?;
let tuple_all: Value = cake::Entity::find() // Value::Array( Vec<Value::Array( Value::Object() )> )
.left_join_and_select(filling::Entity)
.all_json(db)
.await?; |
We should not need to add new methods to selects. |
From what I understand there is no way user can get the |
To construct the // inside ModelTrait
fn serialize_query_result(row: &QueryResult, pre: &str) -> Result<serde_json::Value, Err>; This will be implemented inside |
No, we should not serialize via |
We can add an |
we should not serialize via Model |
We should directly convert from QueryResult into serde_json::Value |
To avoid unnecessary conversion? |
But still we need to know query result column type and its name. To support both
Perhaps we can add a new method inside trait // Serialize a row of query result
fn serialize_query_result(row: &QueryResult, pre: &str) -> Result<serde_json::Value, TypeErr>; Example custom select #[derive(Debug, FromQueryResult)]
struct SelectResult {
name: String,
num_of_fruits: i32,
}
print!("count fruits by cake: ");
let select = cake::Entity::find()
.left_join(fruit::Entity)
.select_only()
.column(cake::Column::Name)
.column_as(fruit::Column::Id.count(), "num_of_fruits")
.group_by(cake::Column::Name);
let results = select.into_model::<SelectResult>().all(db).await?; |
I reject the above proposal. The column list and info can be queried from the |
How about column type? SQLx just tell us the |
In our case there are only four possible
// Rather than getting the &str column type
assert_eq!(d.column(2).type_info().name(), "BOOLEAN");
// We can check for compatibility, starts from null, bool, number then finally string
assert!(<bool as Type<MySql>>::compatible(&d.column(2).type_info())); Seems above plan will not work as expected...
// `int` column is compatible with `bool`
impl Type<MySql> for bool {
fn type_info() -> MySqlTypeInfo {
// MySQL has no actual `BOOLEAN` type, the type is an alias of `TINYINT(1)`
MySqlTypeInfo {
flags: ColumnFlags::BINARY | ColumnFlags::UNSIGNED,
char_set: 63,
max_size: Some(1),
r#type: ColumnType::Tiny,
}
}
fn compatible(ty: &MySqlTypeInfo) -> bool {
matches!(
ty.r#type,
ColumnType::Tiny
| ColumnType::Short
| ColumnType::Long
| ColumnType::Int24
| ColumnType::LongLong
| ColumnType::Bit
)
}
}
// `int` type info
fn int_compatible(ty: &MySqlTypeInfo) -> bool {
matches!(
ty.r#type,
ColumnType::Tiny
| ColumnType::Short
| ColumnType::Long
| ColumnType::Int24
| ColumnType::LongLong
) && !ty.flags.contains(ColumnFlags::UNSIGNED)
}
impl Type<MySql> for i8 {
fn type_info() -> MySqlTypeInfo {
MySqlTypeInfo::binary(ColumnType::Tiny)
}
fn compatible(ty: &MySqlTypeInfo) -> bool {
int_compatible(ty)
}
} |
Wait... I can explicitly check type equality. #[async_trait]
impl Connection for &SqlxMySqlPoolConnection {
async fn query_one(&self, stmt: Statement) -> Result<QueryResult, QueryErr> {
debug_print!("{}", stmt);
let query = bind_query(sqlx::query(&stmt.sql), &stmt.values);
if let Ok(conn) = &mut self.pool.acquire().await {
if let Ok(row) = query.fetch_one(conn).await {
for col in row.columns() {
let col_type = col.type_info();
dbg!(col.name());
dbg!(<bool as Type<MySql>>::type_info().eq(col_type));
dbg!(<i8 as Type<MySql>>::type_info().eq(col_type));
dbg!(<i16 as Type<MySql>>::type_info().eq(col_type));
dbg!(<i32 as Type<MySql>>::type_info().eq(col_type));
dbg!(<i64 as Type<MySql>>::type_info().eq(col_type));
dbg!(<u8 as Type<MySql>>::type_info().eq(col_type));
dbg!(<u16 as Type<MySql>>::type_info().eq(col_type));
dbg!(<u32 as Type<MySql>>::type_info().eq(col_type));
dbg!(<u64 as Type<MySql>>::type_info().eq(col_type));
dbg!(<f32 as Type<MySql>>::type_info().eq(col_type));
dbg!(<f64 as Type<MySql>>::type_info().eq(col_type));
dbg!(<String as Type<MySql>>::type_info().eq(col_type));
}
return Ok(row.into());
}
}
Err(QueryErr)
}
// ...
} The example sqlx-mysql print...
|
To check for null value, simply... let col_type = col.type_info();
dbg!(col_type.is_null()); |
Sounds like a good plan. But it's better to try distinguish between i64 and f64 |
JSON is not a matter of Connector, and deserialization is not a matter of QueryResult. |
Cool refactor!! |
SelectTwo
, which becomes Vec<Vec>The text was updated successfully, but these errors were encountered: