refactor(db): DRY object SELECT columns, consistent date json; test date + all-none round-trip
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+12
-17
@@ -13,13 +13,9 @@ use crate::audit;
|
||||
/// The entity_type recorded in the audit log for catalogue objects.
|
||||
const ENTITY_TYPE: &str = "object";
|
||||
|
||||
const SELECT_OBJECT_BY_ID: &str = "SELECT id, object_number, object_name, number_of_objects, brief_description, \
|
||||
current_location, current_owner, recorder, recording_date, visibility, \
|
||||
created_at, updated_at FROM object WHERE id = $1";
|
||||
|
||||
const SELECT_OBJECTS_ORDERED: &str = "SELECT id, object_number, object_name, number_of_objects, brief_description, \
|
||||
current_location, current_owner, recorder, recording_date, visibility, \
|
||||
created_at, updated_at FROM object ORDER BY object_number";
|
||||
const OBJECT_COLUMNS: &str = "id, object_number, object_name, number_of_objects, \
|
||||
brief_description, current_location, current_owner, recorder, recording_date, \
|
||||
visibility, created_at, updated_at";
|
||||
|
||||
/// Create an object and record a `created` audit entry, both on `conn`
|
||||
/// (pass a transaction connection `&mut *tx` so they commit atomically).
|
||||
@@ -74,7 +70,9 @@ pub async fn object_by_id<'e, E>(
|
||||
where
|
||||
E: sqlx::PgExecutor<'e>,
|
||||
{
|
||||
let row = sqlx::query(SELECT_OBJECT_BY_ID)
|
||||
let sql = format!("SELECT {OBJECT_COLUMNS} FROM object WHERE id = $1");
|
||||
|
||||
let row = sqlx::query(&sql)
|
||||
.bind(id.to_uuid())
|
||||
.fetch_optional(executor)
|
||||
.await?;
|
||||
@@ -88,9 +86,9 @@ where
|
||||
E: sqlx::PgExecutor<'e>,
|
||||
{
|
||||
// TODO: add LIMIT/keyset pagination before exposing this via the API.
|
||||
let rows = sqlx::query(SELECT_OBJECTS_ORDERED)
|
||||
.fetch_all(executor)
|
||||
.await?;
|
||||
let sql = format!("SELECT {OBJECT_COLUMNS} FROM object ORDER BY object_number");
|
||||
|
||||
let rows = sqlx::query(&sql).fetch_all(executor).await?;
|
||||
|
||||
rows.into_iter().map(map_object).collect()
|
||||
}
|
||||
@@ -137,17 +135,14 @@ fn field_values(input: &ObjectInput) -> Vec<(&'static str, Option<Value>)> {
|
||||
input.current_owner.as_ref().map(|v| json!(v)),
|
||||
),
|
||||
("recorder", input.recorder.as_ref().map(|v| json!(v))),
|
||||
(
|
||||
"recording_date",
|
||||
input
|
||||
.recording_date
|
||||
.and_then(|d| serde_json::to_value(d).ok()),
|
||||
),
|
||||
("recording_date", input.recording_date.map(|d| json!(d))),
|
||||
("visibility", Some(json!(input.visibility.as_str()))),
|
||||
]
|
||||
}
|
||||
|
||||
/// Audit changes for a newly created object: every set field as an `after` value.
|
||||
/// Unset (`None`) optional fields are omitted — absence is conveyed by their not
|
||||
/// appearing, consistent with `FieldChange`'s `None`-means-no-value convention.
|
||||
fn creation_changes(input: &ObjectInput) -> Vec<FieldChange> {
|
||||
field_values(input)
|
||||
.into_iter()
|
||||
|
||||
Reference in New Issue
Block a user