1use std::fmt;
4use std::sync::Arc;
5
6#[allow(unused_imports)]
7use crate::error::{Error, Result};
8use crate::schema::{Schema, SchemaPackage, Unbound};
9
10#[derive(Clone, PartialEq, Eq)]
12pub struct ConnectionOptions {
13 address: String,
14 database: String,
15 username: Option<String>,
16 password: Option<String>,
17 http_port: u16,
18 tls: bool,
19}
20
21impl fmt::Debug for ConnectionOptions {
22 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
23 formatter
24 .debug_struct("ConnectionOptions")
25 .field("address", &self.address)
26 .field("database", &self.database)
27 .field("username", &self.username)
28 .field("password", &self.password.as_ref().map(|_| "[REDACTED]"))
29 .field("http_port", &self.http_port)
30 .field("tls", &self.tls)
31 .finish()
32 }
33}
34
35impl ConnectionOptions {
36 #[must_use]
38 pub fn new(address: impl Into<String>, database: impl Into<String>) -> Self {
39 Self {
40 address: address.into(),
41 database: database.into(),
42 username: None,
43 password: None,
44 http_port: 8000,
45 tls: false,
46 }
47 }
48
49 #[must_use]
51 pub fn credentials(mut self, username: impl Into<String>, password: impl Into<String>) -> Self {
52 self.username = Some(username.into());
53 self.password = Some(password.into());
54 self
55 }
56
57 #[must_use]
59 pub fn http_port(mut self, port: u16) -> Self {
60 self.http_port = port;
61 self
62 }
63
64 #[must_use]
66 pub fn tls(mut self, enabled: bool) -> Self {
67 self.tls = enabled;
68 self
69 }
70
71 #[must_use]
73 pub fn address(&self) -> &str {
74 &self.address
75 }
76
77 #[must_use]
79 pub fn database(&self) -> &str {
80 &self.database
81 }
82
83 #[must_use]
85 pub fn get_http_port(&self) -> u16 {
86 self.http_port
87 }
88
89 #[must_use]
91 pub fn is_tls(&self) -> bool {
92 self.tls
93 }
94}
95
96impl From<(&str, &str)> for ConnectionOptions {
97 fn from((address, database): (&str, &str)) -> Self {
98 Self::new(address, database)
99 }
100}
101
102pub struct Database<S: Schema = Unbound> {
104 inner: type_bridge_orm::Database,
105 installed_schema: Option<Arc<type_bridge_orm::InstalledRuntimeProjection>>,
106 match_registry: Option<Arc<type_bridge_orm::DescriptorRegistry>>,
107 marker: std::marker::PhantomData<fn() -> S>,
108}
109
110fn build_match_registry(
111 installed: &type_bridge_orm::InstalledRuntimeProjection,
112) -> Result<Arc<type_bridge_orm::DescriptorRegistry>> {
113 installed
114 .match_registry()
115 .map(Arc::new)
116 .map_err(Error::from_orm)
117}
118
119impl Database<Unbound> {
120 #[cfg(feature = "typedb")]
122 pub async fn connect(options: impl Into<ConnectionOptions>) -> Result<Database<Unbound>> {
123 let opts = options.into();
124 let username = opts.username.as_deref().unwrap_or("admin");
125 let password = opts.password.as_deref().unwrap_or("password");
126 let orm_opts = type_bridge_orm::ConnectOptions {
127 http_port: opts.http_port,
128 tls: opts.tls,
129 ..type_bridge_orm::ConnectOptions::default()
130 };
131
132 let inner = type_bridge_orm::Database::connect_with_options(
133 &opts.address,
134 &opts.database,
135 username,
136 password,
137 orm_opts,
138 )
139 .await
140 .map_err(Error::from_orm)?;
141
142 Ok(Database {
143 inner,
144 installed_schema: None,
145 match_registry: None,
146 marker: std::marker::PhantomData,
147 })
148 }
149
150 #[allow(dead_code)]
152 pub(crate) fn from_orm_database(inner: type_bridge_orm::Database) -> Self {
153 Self {
154 inner,
155 installed_schema: None,
156 match_registry: None,
157 marker: std::marker::PhantomData,
158 }
159 }
160
161 pub fn with_schema<S: Schema>(self, schema: SchemaPackage<S>) -> Result<Database<S>> {
163 let installed = schema.verify_and_install()?;
164 let match_registry = build_match_registry(&installed)?;
165 Ok(Database {
166 inner: self.inner,
167 installed_schema: Some(installed),
168 match_registry: Some(match_registry),
169 marker: std::marker::PhantomData,
170 })
171 }
172}
173
174impl<S: Schema> Database<S> {
175 #[cfg(test)]
176 pub(crate) fn from_test_parts(
177 inner: type_bridge_orm::Database,
178 installed: type_bridge_orm::InstalledRuntimeProjection,
179 ) -> Self {
180 let installed = Arc::new(installed);
181 let match_registry =
182 build_match_registry(&installed).expect("test projection descriptors register");
183 Self {
184 inner,
185 installed_schema: Some(installed),
186 match_registry: Some(match_registry),
187 marker: std::marker::PhantomData,
188 }
189 }
190 #[cfg(test)]
191 pub(crate) fn from_test_unbound_parts(inner: type_bridge_orm::Database) -> Self {
192 Self {
193 inner,
194 installed_schema: None,
195 match_registry: None,
196 marker: std::marker::PhantomData,
197 }
198 }
199 pub fn entities<M>(&self) -> crate::entity_manager::EntityManager<'_, S, M>
201 where
202 M: crate::__codegen::EntityModel<Schema = S>,
203 {
204 crate::entity_manager::EntityManager::new(self)
205 }
206 pub fn relations<M>(&self) -> crate::relation_manager::RelationManager<'_, S, M>
208 where
209 M: crate::__codegen::RelationModel<Schema = S>,
210 {
211 crate::relation_manager::RelationManager::new(self)
212 }
213 pub async fn write(&self) -> Result<crate::transaction::WriteTransaction<'_, S>> {
218 crate::transaction::WriteTransaction::open(self).await
219 }
220 pub async fn read(&self) -> Result<crate::transaction::ReadTransaction<'_, S>> {
223 crate::transaction::ReadTransaction::open(self).await
224 }
225 #[must_use]
227 pub fn database_name(&self) -> &str {
228 self.inner.database_name()
229 }
230
231 #[must_use]
233 pub fn is_schema_bound(&self) -> bool {
234 self.installed_schema.is_some()
235 }
236
237 #[allow(dead_code)]
239 pub(crate) fn inner_orm(&self) -> &type_bridge_orm::Database {
240 &self.inner
241 }
242
243 #[allow(dead_code)]
245 pub(crate) fn installed_schema(
246 &self,
247 ) -> Option<&Arc<type_bridge_orm::InstalledRuntimeProjection>> {
248 self.installed_schema.as_ref()
249 }
250
251 #[allow(dead_code)]
253 pub(crate) fn match_registry(&self) -> Option<&Arc<type_bridge_orm::DescriptorRegistry>> {
254 self.match_registry.as_ref()
255 }
256}