feat(db): add object.fields jsonb column, read it into CatalogueObject
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,3 +15,4 @@ serde_json.workspace = true
|
||||
[dev-dependencies]
|
||||
tokio.workspace = true
|
||||
time.workspace = true
|
||||
serde_json.workspace = true
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Flexible field values for a catalogue object, keyed by field-definition key.
|
||||
ALTER TABLE object ADD COLUMN fields JSONB NOT NULL DEFAULT '{}'::jsonb;
|
||||
@@ -15,7 +15,7 @@ const ENTITY_TYPE: &str = "object";
|
||||
|
||||
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";
|
||||
visibility, fields, 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).
|
||||
@@ -110,6 +110,7 @@ fn map_object(row: sqlx::postgres::PgRow) -> Result<CatalogueObject, sqlx::Error
|
||||
recorder: row.try_get("recorder")?,
|
||||
recording_date: row.try_get("recording_date")?,
|
||||
visibility,
|
||||
fields: row.try_get("fields")?,
|
||||
created_at: row.try_get("created_at")?,
|
||||
updated_at: row.try_get("updated_at")?,
|
||||
})
|
||||
|
||||
@@ -116,3 +116,16 @@ async fn object_with_date_and_all_none_optionals_round_trips(pool: PgPool) {
|
||||
.any(|c| c.field == "recording_date")
|
||||
);
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn new_object_has_empty_fields(pool: PgPool) {
|
||||
let db = Db::from_pool(pool);
|
||||
let mut tx = db.pool().begin().await.unwrap();
|
||||
let id = catalog::create_object(&mut tx, AuditActor::System, &sample_input("LM-9"))
|
||||
.await
|
||||
.unwrap();
|
||||
tx.commit().await.unwrap();
|
||||
|
||||
let obj = catalog::object_by_id(db.pool(), id).await.unwrap().unwrap();
|
||||
assert_eq!(obj.fields, serde_json::json!({}));
|
||||
}
|
||||
|
||||
@@ -71,3 +71,16 @@ async fn migrate_creates_field_definition_tables(pool: PgPool) {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[sqlx::test]
|
||||
async fn migrate_adds_object_fields_column(pool: PgPool) {
|
||||
let db = Db::from_pool(pool);
|
||||
let exists: Option<bool> = sqlx::query_scalar(
|
||||
"SELECT true FROM information_schema.columns \
|
||||
WHERE table_name = 'object' AND column_name = 'fields'",
|
||||
)
|
||||
.fetch_optional(db.pool())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(exists, Some(true));
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ pub struct CatalogueObject {
|
||||
pub recorder: Option<String>,
|
||||
pub recording_date: Option<Date>,
|
||||
pub visibility: Visibility,
|
||||
/// Flexible field values (field key -> value), validated against the registry.
|
||||
pub fields: serde_json::Value,
|
||||
pub created_at: OffsetDateTime,
|
||||
pub updated_at: OffsetDateTime,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user