1use serde::Serialize;
4
5use crate::catalog_types::{ProjectBranchName, ResolveJournalPathRequest, ResourceAtSnapshot};
6use crate::namespace::{Namespace, resource_path};
7use crate::resources::connection::{ExternalConnection, ExternalConnectionId};
8use crate::{Error, Snapshot};
9
10#[derive(Clone, Debug, Serialize)]
12pub struct NamedConnection {
13 pub name: String,
15 #[serde(flatten)]
17 pub connection: ExternalConnection,
18}
19
20pub(crate) fn require_connection(
21 resource: &ResourceAtSnapshot,
22) -> Result<ExternalConnectionId, Error> {
23 resource.validate().map_err(Error::invalid)?;
24 if resource.descriptor.kind.0 != "connection"
25 || resource.descriptor.service.as_str() != "external-connection"
26 {
27 return Err(Error::invalid("resource is not a Connection"));
28 }
29 Ok(resource.descriptor.resource_id.0)
30}
31
32impl Snapshot {
33 pub async fn connection(&self, path: &str) -> Result<ExternalConnection, Error> {
38 let resolved = self
39 .project
40 .client
41 .catalog()
42 .resolve_journal_path(
43 &self.project.id,
44 self.commit_id,
45 &ResolveJournalPathRequest {
46 path: resource_path(path)?,
47 },
48 )
49 .await?;
50 if resolved.commit_id != self.commit_id {
51 return Err(Error::Protocol(
52 "Catalog changed the selected commit".into(),
53 ));
54 }
55 let resource = resolved
56 .resource
57 .ok_or_else(|| Error::NotFound(path.into()))?;
58 let id = require_connection(&resource)?;
59 Ok(self
60 .project
61 .client
62 .connections()
63 .read_connection(id)
64 .await?
65 .connection)
66 }
67
68 pub async fn connections(&self) -> Result<Vec<NamedConnection>, Error> {
73 let namespace = Namespace::read(self).await?;
74 let mut connections = Vec::new();
75 for (name, resource) in namespace.named("connection")? {
76 let id = require_connection(&resource)?;
77 connections.push(NamedConnection {
78 name,
79 connection: self
80 .project
81 .client
82 .connections()
83 .read_connection(id)
84 .await?
85 .connection,
86 });
87 }
88 Ok(connections)
89 }
90
91 pub(crate) async fn require_main_branch(&self) -> Result<(), Error> {
92 let main = self
93 .project
94 .client
95 .catalog()
96 .pin_journal(&self.project.id, &ProjectBranchName::main())
97 .await?;
98 main.validate().map_err(Error::invalid)?;
99 if self.branch_id != Some(main.branch_id) {
100 return Err(Error::invalid(
101 "Connections can only be created and dropped on the main branch",
102 ));
103 }
104 Ok(())
105 }
106}