feat: starmelon compile Astrid.Pages.Route to html

Automatically convert SQL rows to JSON if the user does not manually
call json_object in the query themselves.
This commit is contained in:
YetAnotherMinion 2022-01-13 02:44:02 +00:00 committed by nobody
commit f882cf2c95
Signed by: GrocerPublishAgent
GPG key ID: D460CD54A9E3AB86
3 changed files with 103 additions and 20 deletions

View file

@ -340,11 +340,35 @@ pub(crate) fn run(
match stream.next().await {
None => break,
Some(Ok(row)) => {
use sqlx::ValueRef;
// If we only have one column and it is string type,
// then we can try to parse it as json
if row.len() == 1 {
match row.try_get::<String, _>(0) {
Ok(s) => acc.push(s),
// TODO set an error flag before returning this one
Err(_) => break,
Err(err) => {
failure = Some(AstridQueryError::Execute {
sql: sql.clone(),
message: err.to_string(),
});
break;
}
};
} else {
// Try to auto marshall the row into a javascript
// object to make it easier on our no-code users.
match try_marshal(&row) {
Ok(json) => acc.push(json.to_string()),
Err(err) => {
failure = Some(AstridQueryError::Execute {
sql: sql.clone(),
message: err.to_string(),
});
break;
}
}
}
}
Some(Err(err)) => {
eprintln!("got fetch_all sql error {:?}", err);
@ -358,11 +382,13 @@ pub(crate) fn run(
}
result.push(acc);
} else {
match sqlx::query(&sql)
.fetch_one(&db_pool)
.await
.and_then(|row| row.try_get::<String, _>(0))
{
match sqlx::query(&sql).fetch_one(&db_pool).await.and_then(|row| {
if row.len() == 1 {
row.try_get::<String, _>(0)
} else {
try_marshal(&row).map(|json| json.to_string())
}
}) {
Ok(s) => result.push(vec![s]),
Err(sqlx::Error::RowNotFound) => {
failure = Some(AstridQueryError::NotFound { sql });
@ -480,3 +506,62 @@ enum AstridQueryError {
sql: String,
},
}
fn try_marshal(row: &sqlx::sqlite::SqliteRow) -> Result<serde_json::Value, sqlx::Error> {
use serde_json::value::{Map, Number};
use serde_json::Value;
use sqlx::{Column, TypeInfo};
let mut object = Map::new();
for i in 0..row.len() {
let column = row.column(i);
let value = match column.type_info().name() {
"NULL" => Value::Null,
"TEXT" => Value::String(row.try_get::<String, _>(i)?),
"REAL" => {
let x = row.try_get::<f64, _>(i)?;
match Number::from_f64(x) {
Some(n) => Value::Number(n),
None => {
return Err(sqlx::Error::ColumnDecode {
index: column.name().to_owned(),
source: Box::new(StringError(format!("While parsing a SQL type `REAL` I expected a finite number but got {} instead ", x))),
});
}
}
}
//"BLOB" =>
"INTEGER" => Value::Number(row.try_get::<i64, _>(i)?.into()),
//"NUMERIC" =>
"BOOLEAN" => Value::Bool(row.try_get::<bool, _>(i)?),
//"DATE" =>
//"TIME" =>
//"DATETIME" =>
unknown => {
return Err(sqlx::Error::ColumnDecode {
index: column.name().to_owned(),
source: Box::new(StringError(format!("I don't know how to automatically convert the SQL type `{}`` into a JSON value.", unknown))),
});
}
};
object.insert(column.name().to_owned(), value);
}
Ok(Value::Object(object))
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct StringError(String);
impl ::std::fmt::Display for StringError {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
self.0.fmt(f)
}
}
impl std::error::Error for StringError {
#[inline]
fn description(&self) -> &str {
&self.0
}
}

View file

@ -49,7 +49,7 @@ pub(crate) fn generate(
#(" ")evalRoute (onStringOutput << encodeJson) flags #(target_module).route
}
OutputType::Bytes => {
#(" ")evalRoute (onStringOutput << encodeBytes) flags #(target_module).route
#(" ")evalRoute (onBytesOutput << encodeBytes) flags #(target_module).route
}
OutputType::Html => {
#(" ")evalRoute (onStringOutput << encodeHtml) flags #(target_module).route
@ -160,7 +160,7 @@ pub(crate) fn generate(
encodeSuccess : E.Value -> E.Value
encodeSuccess value =
E.object
[ ("ctor", E.string "Ok")
[ ("$", E.string "Ok")
, ("a", value)
]

View file

@ -145,15 +145,12 @@ function _Query_runDecoder(decoder, sql, xs)
case 1:
if (xs.length === 0) {
__Debug_assert("did not find any results");
return $elm$core$Result$Err($author$project$Astrid$Query$NotFound(sql));
}
var result = _Json_runOnString.f(decoder.a, xs[0]);
if (!$elm$core$Result$isOk(result))
{
__Debug_assert("did not find any results for fetch One");
__Debug_assert(sql);
return $elm$core$Result$Err(
A3(
$author$project$Astrid$Query$Decode,
@ -203,6 +200,7 @@ function _Query_runDecoder(decoder, sql, xs)
);
}
}
return $elm$core$Result$Ok(_Json_toElmArray(array));
}
}