+
Skip to content
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
7 changes: 6 additions & 1 deletion sea-orm-macros/src/derives/try_getable_from_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ pub fn expand_derive_from_json_query_result(ident: Ident) -> syn::Result<TokenSt
#[automatically_derived]
impl std::convert::From<#ident> for sea_orm::Value {
fn from(source: #ident) -> Self {
sea_orm::Value::Json(serde_json::to_value(&source).ok().map(|s| std::boxed::Box::new(s)))
sea_orm::Value::Json(
Some(std::boxed::Box::new(
serde_json::to_value(&source)
.expect(concat!("Failed to serialize '", stringify!(#ident), "'"))
))
)
}
}

Expand Down
24 changes: 8 additions & 16 deletions src/database/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ impl From<ExecResult> for ProxyExecResult {
match result.result {
#[cfg(feature = "sqlx-mysql")]
ExecResultHolder::SqlxMySql(result) => Self {
last_insert_id: result.last_insert_id() as u64,
last_insert_id: result.last_insert_id(),
rows_affected: result.rows_affected(),
},
#[cfg(feature = "sqlx-postgres")]
Expand All @@ -93,7 +93,7 @@ impl From<ExecResult> for ProxyExecResult {

/// Defines the structure of a Row for the [ProxyDatabase]
/// which is just a [BTreeMap]<[String], [Value]>
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Default)]
pub struct ProxyRow {
/// The values of the single row
pub values: BTreeMap<String, Value>,
Expand All @@ -106,14 +106,6 @@ impl ProxyRow {
}
}

impl Default for ProxyRow {
fn default() -> Self {
Self {
values: BTreeMap::new(),
}
}
}

impl From<BTreeMap<String, Value>> for ProxyRow {
fn from(values: BTreeMap<String, Value>) -> Self {
Self { values }
Expand Down Expand Up @@ -141,9 +133,9 @@ impl From<ProxyRow> for QueryResult {
}

#[cfg(feature = "with-json")]
impl Into<serde_json::Value> for ProxyRow {
fn into(self) -> serde_json::Value {
self.values
impl From<ProxyRow> for serde_json::Value {
fn from(val: ProxyRow) -> serde_json::Value {
val.values
.into_iter()
.map(|(k, v)| (k, sea_query::sea_value_to_json_value(&v)))
.collect()
Expand All @@ -154,11 +146,11 @@ impl Into<serde_json::Value> for ProxyRow {
pub fn from_query_result_to_proxy_row(result: &QueryResult) -> ProxyRow {
match &result.row {
#[cfg(feature = "sqlx-mysql")]
QueryResultRow::SqlxMySql(row) => crate::from_sqlx_mysql_row_to_proxy_row(&row),
QueryResultRow::SqlxMySql(row) => crate::from_sqlx_mysql_row_to_proxy_row(row),
#[cfg(feature = "sqlx-postgres")]
QueryResultRow::SqlxPostgres(row) => crate::from_sqlx_postgres_row_to_proxy_row(&row),
QueryResultRow::SqlxPostgres(row) => crate::from_sqlx_postgres_row_to_proxy_row(row),
#[cfg(feature = "sqlx-sqlite")]
QueryResultRow::SqlxSqlite(row) => crate::from_sqlx_sqlite_row_to_proxy_row(&row),
QueryResultRow::SqlxSqlite(row) => crate::from_sqlx_sqlite_row_to_proxy_row(row),
#[cfg(feature = "mock")]
QueryResultRow::Mock(row) => ProxyRow {
values: row.values.clone(),
Expand Down
15 changes: 14 additions & 1 deletion src/driver/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,10 @@ impl MockDatabaseConnector {

impl MockDatabaseConnection {
/// Create a connection to the [MockDatabase]
pub fn new<M: 'static>(m: M) -> Self
pub fn new<M>(m: M) -> Self
where
M: MockDatabaseTrait,
M: 'static,
{
Self {
execute_counter: AtomicUsize::new(0),
Expand Down Expand Up @@ -176,6 +177,10 @@ impl MockDatabaseConnection {
}

/// Create a statement block of SQL statements that execute together.
///
/// # Panics
///
/// Will panic if the lock cannot be acquired.
#[instrument(level = "trace")]
pub fn begin(&self) {
self.mocker
Expand All @@ -185,6 +190,10 @@ impl MockDatabaseConnection {
}

/// Commit a transaction atomically to the database
///
/// # Panics
///
/// Will panic if the lock cannot be acquired.
#[instrument(level = "trace")]
pub fn commit(&self) {
self.mocker
Expand All @@ -194,6 +203,10 @@ impl MockDatabaseConnection {
}

/// Roll back a faulty transaction
///
/// # Panics
///
/// Will panic if the lock cannot be acquired.
#[instrument(level = "trace")]
pub fn rollback(&self) {
self.mocker
Expand Down
16 changes: 7 additions & 9 deletions src/driver/sqlx_postgres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ pub(crate) fn from_sqlx_postgres_row_to_proxy_row(row: &sqlx::postgres::PgRow) -
row.try_get::<Vec<ipnetwork::IpNetwork>, _>(c.ordinal())
.expect("Failed to get ip address array")
.iter()
.map(|val| Value::IpNetwork(Some(Box::new(val.clone()))))
.map(|val| Value::IpNetwork(Some(Box::new(*val))))
.collect(),
)),
),
Expand Down Expand Up @@ -639,7 +639,7 @@ pub(crate) fn from_sqlx_postgres_row_to_proxy_row(row: &sqlx::postgres::PgRow) -
row.try_get::<Vec<chrono::NaiveDateTime>, _>(c.ordinal())
.expect("Failed to get timestamp array")
.iter()
.map(|val| Value::ChronoDateTime(Some(Box::new(val.clone()))))
.map(|val| Value::ChronoDateTime(Some(Box::new(*val))))
.collect(),
)),
),
Expand Down Expand Up @@ -675,7 +675,7 @@ pub(crate) fn from_sqlx_postgres_row_to_proxy_row(row: &sqlx::postgres::PgRow) -
row.try_get::<Vec<chrono::NaiveDate>, _>(c.ordinal())
.expect("Failed to get date array")
.iter()
.map(|val| Value::ChronoDate(Some(Box::new(val.clone()))))
.map(|val| Value::ChronoDate(Some(Box::new(*val))))
.collect(),
)),
),
Expand Down Expand Up @@ -711,7 +711,7 @@ pub(crate) fn from_sqlx_postgres_row_to_proxy_row(row: &sqlx::postgres::PgRow) -
row.try_get::<Vec<chrono::NaiveTime>, _>(c.ordinal())
.expect("Failed to get time array")
.iter()
.map(|val| Value::ChronoTime(Some(Box::new(val.clone()))))
.map(|val| Value::ChronoTime(Some(Box::new(*val))))
.collect(),
)),
),
Expand Down Expand Up @@ -747,9 +747,7 @@ pub(crate) fn from_sqlx_postgres_row_to_proxy_row(row: &sqlx::postgres::PgRow) -
row.try_get::<Vec<chrono::DateTime<chrono::Utc>>, _>(c.ordinal())
.expect("Failed to get timestamptz array")
.iter()
.map(|val| {
Value::ChronoDateTimeUtc(Some(Box::new(val.clone())))
})
.map(|val| Value::ChronoDateTimeUtc(Some(Box::new(*val))))
.collect(),
)),
),
Expand Down Expand Up @@ -785,7 +783,7 @@ pub(crate) fn from_sqlx_postgres_row_to_proxy_row(row: &sqlx::postgres::PgRow) -
row.try_get::<Vec<chrono::NaiveTime>, _>(c.ordinal())
.expect("Failed to get timetz array")
.iter()
.map(|val| Value::ChronoTime(Some(Box::new(val.clone()))))
.map(|val| Value::ChronoTime(Some(Box::new(*val))))
.collect(),
)),
),
Expand Down Expand Up @@ -817,7 +815,7 @@ pub(crate) fn from_sqlx_postgres_row_to_proxy_row(row: &sqlx::postgres::PgRow) -
row.try_get::<Vec<uuid::Uuid>, _>(c.ordinal())
.expect("Failed to get uuid array")
.iter()
.map(|val| Value::Uuid(Some(Box::new(val.clone()))))
.map(|val| Value::Uuid(Some(Box::new(*val))))
.collect(),
)),
),
Expand Down
17 changes: 16 additions & 1 deletion tests/common/features/json_struct.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use sea_orm::entity::prelude::*;
use sea_orm::FromJsonQueryResult;
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Serialize, Serializer};

#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
#[sea_orm(table_name = "json_struct")]
Expand All @@ -10,6 +10,7 @@ pub struct Model {
pub json: Json,
pub json_value: KeyValue,
pub json_value_opt: Option<KeyValue>,
pub json_non_serializable: Option<NonSerializableStruct>,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, FromJsonQueryResult)]
Expand All @@ -20,6 +21,20 @@ pub struct KeyValue {
pub notes: Option<String>,
}

#[derive(Clone, Debug, PartialEq, Deserialize, FromJsonQueryResult)]
pub struct NonSerializableStruct;

impl Serialize for NonSerializableStruct {
fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
Err(serde::ser::Error::custom(
"intentionally failing serialization",
))
}
}

#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
pub enum Relation {}

Expand Down
1 change: 1 addition & 0 deletions tests/common/features/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,7 @@ pub async fn create_json_struct_table(db: &DbConn) -> Result<ExecResult, DbErr>
.not_null(),
)
.col(ColumnDef::new(json_struct::Column::JsonValueOpt).json())
.col(ColumnDef::new(json_struct::Column::JsonNonSerializable).json())
.to_owned();

create_table(db, &stmt, JsonStruct).await
Expand Down
38 changes: 38 additions & 0 deletions tests/json_struct_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,47 @@ async fn main() -> Result<(), DbErr> {
create_tables(&ctx.db).await?;
insert_json_struct_1(&ctx.db).await?;
insert_json_struct_2(&ctx.db).await?;

ctx.delete().await;

Ok(())
}

#[sea_orm_macros::test]
#[should_panic(
expected = "Failed to serialize 'NonSerializableStruct': Error(\"intentionally failing serialization\", line: 0, column: 0)"
)]
async fn panic_on_non_serializable_insert() {
use json_struct::*;

let ctx = TestContext::new("json_struct_non_serializable_test").await;

let model = Model {
id: 1,
json: json!({
"id": 1,
"name": "apple",
"price": 12.01,
"notes": "hand picked, organic",
}),
json_value: KeyValue {
id: 1,
name: "apple".into(),
price: 12.01,
notes: Some("hand picked, organic".into()),
},
json_value_opt: Some(KeyValue {
id: 1,
name: "apple".into(),
price: 12.01,
notes: Some("hand picked, organic".into()),
}),
json_non_serializable: Some(NonSerializableStruct),
};

let _ = model.into_active_model().insert(&ctx.db).await;
}

pub async fn insert_json_struct_1(db: &DatabaseConnection) -> Result<(), DbErr> {
use json_struct::*;

Expand All @@ -41,6 +77,7 @@ pub async fn insert_json_struct_1(db: &DatabaseConnection) -> Result<(), DbErr>
price: 12.01,
notes: Some("hand picked, organic".into()),
}),
json_non_serializable: None,
};

let result = model.clone().into_active_model().insert(db).await?;
Expand Down Expand Up @@ -76,6 +113,7 @@ pub async fn insert_json_struct_2(db: &DatabaseConnection) -> Result<(), DbErr>
notes: None,
},
json_value_opt: None,
json_non_serializable: None,
};

let result = model.clone().into_active_model().insert(db).await?;
Expand Down
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载