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:
parent
cc4c1cf9d5
commit
f882cf2c95
3 changed files with 103 additions and 20 deletions
|
|
@ -340,11 +340,35 @@ pub(crate) fn run(
|
||||||
match stream.next().await {
|
match stream.next().await {
|
||||||
None => break,
|
None => break,
|
||||||
Some(Ok(row)) => {
|
Some(Ok(row)) => {
|
||||||
match row.try_get::<String, _>(0) {
|
use sqlx::ValueRef;
|
||||||
Ok(s) => acc.push(s),
|
// If we only have one column and it is string type,
|
||||||
// TODO set an error flag before returning this one
|
// then we can try to parse it as json
|
||||||
Err(_) => break,
|
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(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)) => {
|
Some(Err(err)) => {
|
||||||
eprintln!("got fetch_all sql error {:?}", err);
|
eprintln!("got fetch_all sql error {:?}", err);
|
||||||
|
|
@ -358,11 +382,13 @@ pub(crate) fn run(
|
||||||
}
|
}
|
||||||
result.push(acc);
|
result.push(acc);
|
||||||
} else {
|
} else {
|
||||||
match sqlx::query(&sql)
|
match sqlx::query(&sql).fetch_one(&db_pool).await.and_then(|row| {
|
||||||
.fetch_one(&db_pool)
|
if row.len() == 1 {
|
||||||
.await
|
row.try_get::<String, _>(0)
|
||||||
.and_then(|row| row.try_get::<String, _>(0))
|
} else {
|
||||||
{
|
try_marshal(&row).map(|json| json.to_string())
|
||||||
|
}
|
||||||
|
}) {
|
||||||
Ok(s) => result.push(vec![s]),
|
Ok(s) => result.push(vec![s]),
|
||||||
Err(sqlx::Error::RowNotFound) => {
|
Err(sqlx::Error::RowNotFound) => {
|
||||||
failure = Some(AstridQueryError::NotFound { sql });
|
failure = Some(AstridQueryError::NotFound { sql });
|
||||||
|
|
@ -480,3 +506,62 @@ enum AstridQueryError {
|
||||||
sql: String,
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ pub(crate) fn generate(
|
||||||
#(" ")evalRoute (onStringOutput << encodeJson) flags #(target_module).route
|
#(" ")evalRoute (onStringOutput << encodeJson) flags #(target_module).route
|
||||||
}
|
}
|
||||||
OutputType::Bytes => {
|
OutputType::Bytes => {
|
||||||
#(" ")evalRoute (onStringOutput << encodeBytes) flags #(target_module).route
|
#(" ")evalRoute (onBytesOutput << encodeBytes) flags #(target_module).route
|
||||||
}
|
}
|
||||||
OutputType::Html => {
|
OutputType::Html => {
|
||||||
#(" ")evalRoute (onStringOutput << encodeHtml) flags #(target_module).route
|
#(" ")evalRoute (onStringOutput << encodeHtml) flags #(target_module).route
|
||||||
|
|
@ -160,7 +160,7 @@ pub(crate) fn generate(
|
||||||
encodeSuccess : E.Value -> E.Value
|
encodeSuccess : E.Value -> E.Value
|
||||||
encodeSuccess value =
|
encodeSuccess value =
|
||||||
E.object
|
E.object
|
||||||
[ ("ctor", E.string "Ok")
|
[ ("$", E.string "Ok")
|
||||||
, ("a", value)
|
, ("a", value)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ function __Debug_assert(expr) {
|
||||||
|
|
||||||
function _Query_succeed(value)
|
function _Query_succeed(value)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
$: 0,
|
$: 0,
|
||||||
a: value
|
a: value
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -145,15 +145,12 @@ function _Query_runDecoder(decoder, sql, xs)
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
if (xs.length === 0) {
|
if (xs.length === 0) {
|
||||||
__Debug_assert("did not find any results");
|
|
||||||
return $elm$core$Result$Err($author$project$Astrid$Query$NotFound(sql));
|
return $elm$core$Result$Err($author$project$Astrid$Query$NotFound(sql));
|
||||||
}
|
}
|
||||||
var result = _Json_runOnString.f(decoder.a, xs[0]);
|
var result = _Json_runOnString.f(decoder.a, xs[0]);
|
||||||
|
|
||||||
if (!$elm$core$Result$isOk(result))
|
if (!$elm$core$Result$isOk(result))
|
||||||
{
|
{
|
||||||
__Debug_assert("did not find any results for fetch One");
|
|
||||||
__Debug_assert(sql);
|
|
||||||
return $elm$core$Result$Err(
|
return $elm$core$Result$Err(
|
||||||
A3(
|
A3(
|
||||||
$author$project$Astrid$Query$Decode,
|
$author$project$Astrid$Query$Decode,
|
||||||
|
|
@ -203,7 +200,8 @@ function _Query_runDecoder(decoder, sql, xs)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $elm$core$Result$Ok(_Json_toElmArray(array));
|
|
||||||
|
return $elm$core$Result$Ok(_Json_toElmArray(array));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue