mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-04-25 11:46:06 +02:00
feat(sql): Improve type decoding. Adds support for time and dates (#266)
* feat(sql): Improve type decoding. Adds support for time and dates * remove default feat * typo
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
#[cfg(feature = "mysql")]
|
||||
mod mysql;
|
||||
#[cfg(feature = "postgres")]
|
||||
mod postgres;
|
||||
#[cfg(feature = "sqlite")]
|
||||
mod sqlite;
|
||||
|
||||
#[cfg(feature = "mysql")]
|
||||
pub(crate) use mysql::to_json;
|
||||
|
||||
#[cfg(feature = "postgres")]
|
||||
pub(crate) use postgres::to_json;
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
pub(crate) use sqlite::to_json;
|
||||
@@ -0,0 +1,90 @@
|
||||
use serde_json::Value as JsonValue;
|
||||
use sqlx::{mysql::MySqlValueRef, TypeInfo, Value, ValueRef};
|
||||
use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
pub(crate) fn to_json(v: MySqlValueRef) -> Result<JsonValue, Error> {
|
||||
if v.is_null() {
|
||||
return Ok(JsonValue::Null);
|
||||
}
|
||||
|
||||
let res = match v.type_info().name() {
|
||||
"CHAR" | "VARCHAR" | "TINYTEXT" | "TEXT" | "MEDIUMTEXT" | "LONGTEXT" | "ENUM" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode() {
|
||||
JsonValue::String(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"FLOAT" | "DOUBLE" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f64>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"TINYINT" | "SMALLINT" | "INT" | "MEDIUMINT" | "BIGINT" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<i64>() {
|
||||
JsonValue::Number(v.into())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"TINYINT UNSIGNED" | "SMALLINT UNSIGNED" | "INT UNSIGNED" | "MEDIUMINT UNSIGNED"
|
||||
| "BIGINT UNSIGNED" | "YEAR" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<u64>() {
|
||||
JsonValue::Number(v.into())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"BOOLEAN" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode() {
|
||||
JsonValue::Bool(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"DATE" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<Date>() {
|
||||
JsonValue::String(v.to_string())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"TIME" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<Time>() {
|
||||
JsonValue::String(v.to_string())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"DATETIME" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<PrimitiveDateTime>() {
|
||||
JsonValue::String(v.to_string())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"TIMESTAMP" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<OffsetDateTime>() {
|
||||
JsonValue::String(v.to_string())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"JSON" => ValueRef::to_owned(&v).try_decode().unwrap_or_default(),
|
||||
"TINIYBLOB" | "MEDIUMBLOB" | "BLOB" | "LONGBLOB" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<Vec<u8>>() {
|
||||
JsonValue::Array(v.into_iter().map(|n| JsonValue::Number(n.into())).collect())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"NULL" => JsonValue::Null,
|
||||
_ => return Err(Error::UnsupportedDatatype(v.type_info().name().to_string())),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
use serde_json::Value as JsonValue;
|
||||
use sqlx::{postgres::PgValueRef, TypeInfo, Value, ValueRef};
|
||||
use time::{Date, OffsetDateTime, PrimitiveDateTime, Time};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
pub(crate) fn to_json(v: PgValueRef) -> Result<JsonValue, Error> {
|
||||
if v.is_null() {
|
||||
return Ok(JsonValue::Null);
|
||||
}
|
||||
|
||||
let res = match v.type_info().name() {
|
||||
"CHAR" | "VARCHAR" | "TEXT" | "NAME" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode() {
|
||||
JsonValue::String(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"FLOAT4" | "FLOAT8" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f64>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"INT2" | "INT4" | "INT8" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<i64>() {
|
||||
JsonValue::Number(v.into())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"BOOL" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode() {
|
||||
JsonValue::Bool(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"DATE" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<Date>() {
|
||||
JsonValue::String(v.to_string())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"TIME" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<Time>() {
|
||||
JsonValue::String(v.to_string())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"TIMESTAMP" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<PrimitiveDateTime>() {
|
||||
JsonValue::String(v.to_string())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"TIMESTAMPTZ" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<OffsetDateTime>() {
|
||||
JsonValue::String(v.to_string())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"JSON" | "JSONB" => ValueRef::to_owned(&v).try_decode().unwrap_or_default(),
|
||||
"BYTEA" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<Vec<u8>>() {
|
||||
JsonValue::Array(v.into_iter().map(|n| JsonValue::Number(n.into())).collect())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"VOID" => JsonValue::Null,
|
||||
_ => return Err(Error::UnsupportedDatatype(v.type_info().name().to_string())),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
use serde_json::Value as JsonValue;
|
||||
use sqlx::{sqlite::SqliteValueRef, TypeInfo, Value, ValueRef};
|
||||
use time::{Date, PrimitiveDateTime, Time};
|
||||
|
||||
use crate::Error;
|
||||
|
||||
pub(crate) fn to_json(v: SqliteValueRef) -> Result<JsonValue, Error> {
|
||||
if v.is_null() {
|
||||
return Ok(JsonValue::Null);
|
||||
}
|
||||
|
||||
let res = match v.type_info().name() {
|
||||
"TEXT" => {
|
||||
if let Ok(v) = v.to_owned().try_decode() {
|
||||
JsonValue::String(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"REAL" => {
|
||||
if let Ok(v) = v.to_owned().try_decode::<f64>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"INTEGER" | "NUMERIC" => {
|
||||
if let Ok(v) = v.to_owned().try_decode::<i64>() {
|
||||
JsonValue::Number(v.into())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"BOOLEAN" => {
|
||||
if let Ok(v) = v.to_owned().try_decode() {
|
||||
JsonValue::Bool(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"DATE" => {
|
||||
if let Ok(v) = v.to_owned().try_decode::<Date>() {
|
||||
JsonValue::String(v.to_string())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"TIME" => {
|
||||
if let Ok(v) = v.to_owned().try_decode::<Time>() {
|
||||
JsonValue::String(v.to_string())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"DATETIME" => {
|
||||
if let Ok(v) = v.to_owned().try_decode::<PrimitiveDateTime>() {
|
||||
JsonValue::String(v.to_string())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"BLOB" => {
|
||||
if let Ok(v) = v.to_owned().try_decode::<Vec<u8>>() {
|
||||
JsonValue::Array(v.into_iter().map(|n| JsonValue::Number(n.into())).collect())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"NULL" => JsonValue::Null,
|
||||
_ => return Err(Error::UnsupportedDatatype(v.type_info().name().to_string())),
|
||||
};
|
||||
|
||||
Ok(res)
|
||||
}
|
||||
+1
-10
@@ -14,15 +14,6 @@ compile_error!(
|
||||
"Database driver not defined. Please set the feature flag for the driver of your choice."
|
||||
);
|
||||
|
||||
#[cfg(any(
|
||||
all(feature = "sqlite", not(any(feature = "mysql", feature = "postgres"))),
|
||||
all(feature = "mysql", not(any(feature = "sqlite", feature = "postgres"))),
|
||||
all(feature = "postgres", not(any(feature = "sqlite", feature = "mysql"))),
|
||||
))]
|
||||
mod decode;
|
||||
mod plugin;
|
||||
#[cfg(any(
|
||||
all(feature = "sqlite", not(any(feature = "mysql", feature = "postgres"))),
|
||||
all(feature = "mysql", not(any(feature = "sqlite", feature = "postgres"))),
|
||||
all(feature = "postgres", not(any(feature = "sqlite", feature = "mysql"))),
|
||||
))]
|
||||
pub use plugin::*;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use futures::future::BoxFuture;
|
||||
use futures_core::future::BoxFuture;
|
||||
use serde::{ser::Serializer, Deserialize, Serialize};
|
||||
use serde_json::Value as JsonValue;
|
||||
use sqlx::{
|
||||
@@ -10,7 +10,7 @@ use sqlx::{
|
||||
migrate::{
|
||||
MigrateDatabase, Migration as SqlxMigration, MigrationSource, MigrationType, Migrator,
|
||||
},
|
||||
Column, Pool, Row, TypeInfo, ValueRef,
|
||||
Column, Pool, Row,
|
||||
};
|
||||
use tauri::{
|
||||
command,
|
||||
@@ -250,58 +250,7 @@ async fn select(
|
||||
for (i, column) in row.columns().iter().enumerate() {
|
||||
let v = row.try_get_raw(i)?;
|
||||
|
||||
let v = if v.is_null() {
|
||||
JsonValue::Null
|
||||
} else {
|
||||
// TODO: postgresql's JSON type
|
||||
match v.type_info().name() {
|
||||
"VARCHAR" | "STRING" | "TEXT" | "TINYTEXT" | "LONGTEXT" | "NVARCHAR"
|
||||
| "BIGVARCHAR" | "CHAR" | "BIGCHAR" | "NCHAR" | "DATETIME" | "DATE"
|
||||
| "TIME" | "YEAR" | "TIMESTAMP" => {
|
||||
if let Ok(s) = row.try_get(i) {
|
||||
JsonValue::String(s)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"BOOL" | "BOOLEAN" => {
|
||||
if let Ok(b) = row.try_get(i) {
|
||||
JsonValue::Bool(b)
|
||||
} else {
|
||||
let x: String = row.get(i);
|
||||
JsonValue::Bool(x.to_lowercase() == "true")
|
||||
}
|
||||
}
|
||||
"INT" | "NUMBER" | "INTEGER" | "BIGINT" | "INT2" | "INT4" | "INT8"
|
||||
| "NUMERIC" | "TINYINT" | "SMALLINT" | "MEDIUMINT" | "TINYINT UNSINGED"
|
||||
| "SMALLINT UNSINGED" | "INT UNSINGED" | "MEDIUMINT UNSINGED"
|
||||
| "BIGINT UNSINGED" => {
|
||||
if let Ok(n) = row.try_get::<i64, usize>(i) {
|
||||
JsonValue::Number(n.into())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"REAL" | "FLOAT" | "DOUBLE" | "FLOAT4" | "FLOAT8" => {
|
||||
if let Ok(n) = row.try_get::<f64, usize>(i) {
|
||||
JsonValue::from(n)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"BLOB" | "TINYBLOB" | "MEDIUMBLOB" | "LONGBLOB" | "BINARY" | "VARBINARY"
|
||||
| "BYTEA" => {
|
||||
if let Ok(n) = row.try_get::<Vec<u8>, usize>(i) {
|
||||
JsonValue::Array(
|
||||
n.into_iter().map(|n| JsonValue::Number(n.into())).collect(),
|
||||
)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::UnsupportedDatatype(v.type_info().name().to_string())),
|
||||
}
|
||||
};
|
||||
let v = crate::decode::to_json(v)?;
|
||||
|
||||
value.insert(column.name().to_string(), v);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user