orders search query also working now
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
//! Admin order list, detail, status updates, and manual carrier dispatch.
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use axum::extract::Query;
|
||||
use axum_extra::extract::cookie::CookieJar;
|
||||
use loco_rs::prelude::*;
|
||||
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, QueryFilter, QueryOrder, Set};
|
||||
@@ -30,18 +33,31 @@ async fn index(
|
||||
auth: auth::JWT,
|
||||
jar: CookieJar,
|
||||
ViewEngine(v): ViewEngine<TeraView>,
|
||||
Query(params): Query<HashMap<String, String>>,
|
||||
State(ctx): State<AppContext>,
|
||||
) -> Result<Response> {
|
||||
guard::current_admin(auth, &ctx).await?;
|
||||
let list = orders::Entity::find()
|
||||
.order_by_desc(orders::Column::CreatedAt)
|
||||
.all(&ctx.db)
|
||||
.await?;
|
||||
// Optional search over order number / customer / email / etc., otherwise the
|
||||
// full list newest first.
|
||||
let query = params.get("q").map(String::as_str).unwrap_or("").trim().to_string();
|
||||
let list = if query.is_empty() {
|
||||
orders::Entity::find()
|
||||
.order_by_desc(orders::Column::CreatedAt)
|
||||
.all(&ctx.db)
|
||||
.await?
|
||||
} else {
|
||||
orders::Entity::search(&ctx.db, &query, 500).await?
|
||||
};
|
||||
let rows: Vec<serde_json::Value> = list.iter().map(view::summary).collect();
|
||||
format::view(
|
||||
&v,
|
||||
"admin/orders/index.html",
|
||||
json!({ "orders": rows, "lang": current_lang(&jar) }),
|
||||
json!({
|
||||
"orders": rows,
|
||||
"query": query,
|
||||
"total": list.len(),
|
||||
"lang": current_lang(&jar),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -163,4 +163,45 @@ impl Model {}
|
||||
impl ActiveModel {}
|
||||
|
||||
// implement your custom finders, selectors oriented logic here
|
||||
impl Entity {}
|
||||
impl Entity {
|
||||
/// Admin order search: a diacritic- and case-insensitive substring match over
|
||||
/// the free-text order fields an admin would actually type — order number,
|
||||
/// email, customer name, company name, phone and tracking number. Backed by
|
||||
/// the trigram indexes from the `order_search_indexes` migration. Newest
|
||||
/// first, capped at `limit`. A blank query returns nothing (callers fall back
|
||||
/// to the full list).
|
||||
pub async fn search<C: sea_orm::ConnectionTrait>(
|
||||
db: &C,
|
||||
query: &str,
|
||||
limit: u64,
|
||||
) -> Result<Vec<Model>, DbErr> {
|
||||
let q = query.trim();
|
||||
if q.is_empty() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
// Treat the query literally: escape LIKE wildcards, then wrap in %…%.
|
||||
let escaped = q.replace('\\', "\\\\").replace('%', "\\%").replace('_', "\\_");
|
||||
let pattern = format!("%{escaped}%");
|
||||
|
||||
let sql = r#"
|
||||
SELECT * FROM orders o
|
||||
WHERE f_unaccent(o.order_number) ILIKE f_unaccent($1)
|
||||
OR f_unaccent(o.email) ILIKE f_unaccent($1)
|
||||
OR f_unaccent(COALESCE(o.customer_name,'')) ILIKE f_unaccent($1)
|
||||
OR f_unaccent(COALESCE(o.company_name,'')) ILIKE f_unaccent($1)
|
||||
OR f_unaccent(COALESCE(o.phone,'')) ILIKE f_unaccent($1)
|
||||
OR f_unaccent(COALESCE(o.tracking_number,'')) ILIKE f_unaccent($1)
|
||||
ORDER BY o.created_at DESC
|
||||
LIMIT $2
|
||||
"#;
|
||||
|
||||
Entity::find()
|
||||
.from_raw_sql(sea_orm::Statement::from_sql_and_values(
|
||||
db.get_database_backend(),
|
||||
sql,
|
||||
[pattern.into(), (limit as i64).into()],
|
||||
))
|
||||
.all(db)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user