1pub mod engine;
4pub mod err;
5pub mod method;
6pub mod opt;
7
8mod conn;
9
10pub use method::query::Response;
11
12use crate::api::conn::DbResponse;
13use crate::api::conn::Router;
14use crate::api::err::Error;
15use crate::api::opt::Endpoint;
16use semver::BuildMetadata;
17use semver::VersionReq;
18use std::fmt::Debug;
19use std::future::Future;
20use std::future::IntoFuture;
21use std::marker::PhantomData;
22use std::pin::Pin;
23use std::sync::Arc;
24use std::sync::OnceLock;
25
26pub type Result<T> = std::result::Result<T, crate::Error>;
28
29const SUPPORTED_VERSIONS: (&str, &str) = (">=1.0.0-beta.9, <2.0.0", "20230701.55918b7c");
30
31pub trait Connection: conn::Connection {}
33
34#[derive(Debug)]
36#[must_use = "futures do nothing unless you `.await` or poll them"]
37pub struct Connect<C: Connection, Response> {
38 router: Arc<OnceLock<Router<C>>>,
39 address: Result<Endpoint>,
40 capacity: usize,
41 client: PhantomData<C>,
42 response_type: PhantomData<Response>,
43}
44
45impl<C, R> Connect<C, R>
46where
47 C: Connection,
48{
49 pub const fn with_capacity(mut self, capacity: usize) -> Self {
76 self.capacity = capacity;
77 self
78 }
79}
80
81impl<Client> IntoFuture for Connect<Client, Surreal<Client>>
82where
83 Client: Connection,
84{
85 type Output = Result<Surreal<Client>>;
86 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send + Sync>>;
87
88 fn into_future(self) -> Self::IntoFuture {
89 Box::pin(async move {
90 let client = Client::connect(self.address?, self.capacity).await?;
91 client.check_server_version().await?;
92 Ok(client)
93 })
94 }
95}
96
97impl<Client> IntoFuture for Connect<Client, ()>
98where
99 Client: Connection,
100{
101 type Output = Result<()>;
102 type IntoFuture = Pin<Box<dyn Future<Output = Self::Output> + Send + Sync>>;
103
104 fn into_future(self) -> Self::IntoFuture {
105 Box::pin(async move {
106 if self.router.get().is_some() {
108 return Err(Error::AlreadyConnected.into());
109 }
110 let arc = Client::connect(self.address?, self.capacity).await?.router;
111 let cell = Arc::into_inner(arc).expect("new connection to have no references");
112 let router = cell.into_inner().expect("router to be set");
113 self.router.set(router).map_err(|_| Error::AlreadyConnected)?;
114 let client = Surreal {
115 router: self.router,
116 };
117 client.check_server_version().await?;
118 Ok(())
119 })
120 }
121}
122
123#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
124pub(crate) enum ExtraFeatures {
125 Backup,
126 LiveQueries,
127}
128
129#[derive(Debug)]
131pub struct Surreal<C: Connection> {
132 router: Arc<OnceLock<Router<C>>>,
133}
134
135impl<C> Surreal<C>
136where
137 C: Connection,
138{
139 async fn check_server_version(&self) -> Result<()> {
140 let (versions, build_meta) = SUPPORTED_VERSIONS;
141 let req = VersionReq::parse(versions).expect("valid supported versions");
143 let build_meta = BuildMetadata::new(build_meta).expect("valid supported build metadata");
144 let version = self.version().await?;
145 let server_build = &version.build;
146 if !req.matches(&version) {
147 return Err(Error::VersionMismatch {
148 server_version: version,
149 supported_versions: versions.to_owned(),
150 }
151 .into());
152 } else if !server_build.is_empty() && server_build < &build_meta {
153 return Err(Error::BuildMetadataMismatch {
154 server_metadata: server_build.clone(),
155 supported_metadata: build_meta,
156 }
157 .into());
158 }
159 Ok(())
160 }
161}
162
163impl<C> Clone for Surreal<C>
164where
165 C: Connection,
166{
167 fn clone(&self) -> Self {
168 Self {
169 router: self.router.clone(),
170 }
171 }
172}
173
174trait OnceLockExt<C>
175where
176 C: Connection,
177{
178 fn with_value(value: Router<C>) -> OnceLock<Router<C>> {
179 let cell = OnceLock::new();
180 match cell.set(value) {
181 Ok(()) => cell,
182 Err(_) => unreachable!("don't have exclusive access to `cell`"),
183 }
184 }
185
186 fn extract(&self) -> Result<&Router<C>>;
187}
188
189impl<C> OnceLockExt<C> for OnceLock<Router<C>>
190where
191 C: Connection,
192{
193 fn extract(&self) -> Result<&Router<C>> {
194 let router = self.get().ok_or(Error::ConnectionUninitialised)?;
195 Ok(router)
196 }
197}