Creates a new team with the given ID and parent actor group, or generates a new UUID if none is provided. # Errors - [`PrincipalAlreadyExists`] if a team with the given ID already exists - [`StoreError`] if a database error occurs [`PrincipalAlreadyExists`]: PrincipalError::PrincipalAlreadyExists [`StoreError`]: PrincipalError::StoreError
(
&mut self,
id: Option<Uuid>,
parent_id: ActorGroupId,
name: &str,
)
| 443 | /// [`PrincipalAlreadyExists`]: PrincipalError::PrincipalAlreadyExists |
| 444 | /// [`StoreError`]: PrincipalError::StoreError |
| 445 | pub async fn insert_team( |
| 446 | &mut self, |
| 447 | id: Option<Uuid>, |
| 448 | parent_id: ActorGroupId, |
| 449 | name: &str, |
| 450 | ) -> Result<TeamId, Report<PrincipalError>> { |
| 451 | let id = id.unwrap_or_else(Uuid::new_v4); |
| 452 | let transaction = self |
| 453 | .as_mut_client() |
| 454 | .transaction() |
| 455 | .await |
| 456 | .change_context(PrincipalError::StoreError)?; |
| 457 | |
| 458 | // First create the team |
| 459 | transaction |
| 460 | .execute( |
| 461 | "INSERT INTO team (id, parent_id, name) VALUES ($1, $2, $3)", |
| 462 | &[&id, &parent_id, &name], |
| 463 | ) |
| 464 | .instrument(tracing::info_span!( |
| 465 | "INSERT", |
| 466 | otel.kind = "client", |
| 467 | db.system = "postgresql", |
| 468 | peer.service = "Postgres", |
| 469 | )) |
| 470 | .await |
| 471 | .map_err(Report::new) |
| 472 | .map_err(|error| match error.current_context().code() { |
| 473 | Some(&SqlState::UNIQUE_VIOLATION) => { |
| 474 | error.change_context(PrincipalError::PrincipalAlreadyExists { |
| 475 | id: PrincipalId::ActorGroup(ActorGroupId::Team(TeamId::new(id))), |
| 476 | }) |
| 477 | } |
| 478 | Some(&SqlState::FOREIGN_KEY_VIOLATION) => { |
| 479 | error.change_context(PrincipalError::PrincipalNotFound { |
| 480 | id: PrincipalId::ActorGroup(parent_id), |
| 481 | }) |
| 482 | } |
| 483 | _ => error.change_context(PrincipalError::StoreError), |
| 484 | })?; |
| 485 | |
| 486 | // Set up all parent-child relationships in a single query |
| 487 | // First row creates the direct relationship with depth 1 |
| 488 | // Remaining rows create transitive relationships with proper depths |
| 489 | transaction |
| 490 | .execute( |
| 491 | "INSERT INTO team_hierarchy (parent_id, child_id, depth) |
| 492 | SELECT $1::uuid, $2::uuid, 1 |
| 493 | UNION ALL |
| 494 | SELECT parent_id, $2::uuid, depth + 1 |
| 495 | FROM team_hierarchy |
| 496 | WHERE child_id = $1::uuid", |
| 497 | &[&parent_id, &id], |
| 498 | ) |
| 499 | .instrument(tracing::info_span!( |
| 500 | "INSERT", |
| 501 | otel.kind = "client", |
| 502 | db.system = "postgresql", |