//! Seed data: a representative subset of the Spectrum Cataloguing field set. //! //! Idempotent — each vocabulary and field definition is created only if a row with //! that key does not already exist. Vocabularies are seeded empty; their terms are //! populated by the organization or a later import. The inventory-minimum fields //! (object number, name, location, …) live in the typed object core, not here. use domain::{ AuditActor, AuthorityKind, FieldType, LocalizedLabel, NewFieldDefinition, VocabularyId, }; use crate::{fields, vocab}; /// Seed the Spectrum cataloguing vocabularies and field definitions on `conn`. /// Pass a transaction connection (`&mut *tx`) so the whole seed is atomic. pub async fn seed_spectrum_cataloguing(conn: &mut sqlx::PgConnection) -> Result<(), sqlx::Error> { let material = ensure_vocabulary(conn, "material").await?; let object_name = ensure_vocabulary(conn, "object_name").await?; let technique = ensure_vocabulary(conn, "technique").await?; let definitions = [ def( "object_type", FieldType::Term { vocabulary_id: object_name, }, "identification", &[("sv", "Sakord"), ("en", "Object type")], ), def( "title", FieldType::LocalizedText, "identification", &[("sv", "Titel"), ("en", "Title")], ), def( "comments", FieldType::Text, "identification", &[("sv", "Kommentarer"), ("en", "Comments")], ), def( "material", FieldType::Term { vocabulary_id: material, }, "description", &[("sv", "Material"), ("en", "Material")], ), def( "technique", FieldType::Term { vocabulary_id: technique, }, "description", &[("sv", "Teknik"), ("en", "Technique")], ), def( "physical_description", FieldType::Text, "description", &[("sv", "Fysisk beskrivning"), ("en", "Physical description")], ), def( "dimensions", FieldType::Text, "description", &[("sv", "Mått"), ("en", "Dimensions")], ), def( "inscription", FieldType::Text, "description", &[("sv", "Inskription"), ("en", "Inscription")], ), def( "content_description", FieldType::Text, "content", &[ ("sv", "Innehållsbeskrivning"), ("en", "Content description"), ], ), def( "production_date", FieldType::Date, "production", &[("sv", "Tillverkningsdatum"), ("en", "Production date")], ), def( "production_place", FieldType::Authority { kind: Some(AuthorityKind::Place), }, "production", &[("sv", "Tillverkningsplats"), ("en", "Production place")], ), def( "production_person", FieldType::Authority { kind: Some(AuthorityKind::Person), }, "production", &[("sv", "Tillverkare"), ("en", "Maker")], ), ]; for definition in &definitions { ensure_field_definition(conn, definition).await?; } Ok(()) } /// Get-or-create a vocabulary by key, returning its id. async fn ensure_vocabulary( conn: &mut sqlx::PgConnection, key: &str, ) -> Result { if let Some(existing) = vocab::vocabulary_by_key(&mut *conn, key).await? { Ok(existing.id) } else { Ok( vocab::create_vocabulary(&mut *conn, AuditActor::System, key) .await? .id, ) } } /// Create a field definition only if its key is not already present. async fn ensure_field_definition( conn: &mut sqlx::PgConnection, definition: &NewFieldDefinition, ) -> Result<(), sqlx::Error> { if fields::field_definition_by_key(&mut *conn, &definition.key) .await? .is_none() { fields::create_field_definition(&mut *conn, definition).await?; } Ok(()) } fn def( key: &str, field_type: FieldType, group: &str, label_pairs: &[(&str, &str)], ) -> NewFieldDefinition { NewFieldDefinition { key: key.to_owned(), field_type, required: false, group_key: Some(group.to_owned()), labels: label_pairs .iter() .map(|(lang, label)| LocalizedLabel { lang: (*lang).to_owned(), label: (*label).to_owned(), }) .collect(), } }