google_cloud_spanner/
omni.rs1pub use crate::client::SpannerBuilderExt;
18
19#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
21#[non_exhaustive]
22pub enum InstanceType {
23 #[default]
25 Cloud,
26 Omni,
28}
29
30pub(crate) fn is_plaintext_endpoint(endpoint: &str) -> bool {
32 let trimmed = endpoint.trim();
33 if let Ok(parsed_url) = url::Url::parse(trimmed) {
34 parsed_url.scheme() == "http"
35 } else {
36 trimmed.starts_with("http://")
37 }
38}
39
40pub(crate) fn format_database_name(name: &str) -> String {
44 let trimmed = name.trim();
45 if trimmed.is_empty() {
46 return trimmed.to_string();
47 }
48
49 let parts: Vec<&str> = trimmed.split('/').collect();
50 match parts.as_slice() {
51 [
52 "projects",
53 _project,
54 "instances",
55 _instance,
56 "databases",
57 _database,
58 ] => trimmed.to_string(),
59 ["instances", instance, "databases", database] => {
60 format!(
61 "projects/default/instances/{}/databases/{}",
62 instance, database
63 )
64 }
65 ["databases", database] => {
66 format!("projects/default/instances/default/databases/{}", database)
67 }
68 [database] => {
69 format!("projects/default/instances/default/databases/{}", database)
70 }
71 _ => trimmed.to_string(),
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use crate::client::Spanner;
79
80 #[test]
81 fn test_format_database_name() {
82 assert_eq!(
83 format_database_name("projects/p/instances/i/databases/d"),
84 "projects/p/instances/i/databases/d"
85 );
86 assert_eq!(
87 format_database_name("instances/i/databases/d"),
88 "projects/default/instances/i/databases/d"
89 );
90 assert_eq!(
91 format_database_name("databases/d"),
92 "projects/default/instances/default/databases/d"
93 );
94 assert_eq!(
95 format_database_name("retail-sample"),
96 "projects/default/instances/default/databases/retail-sample"
97 );
98 }
99
100 #[test]
101 fn test_is_plaintext_endpoint() {
102 assert!(is_plaintext_endpoint("http://localhost:15000"));
103 assert!(!is_plaintext_endpoint("https://spanner.internal:15000"));
104 assert!(!is_plaintext_endpoint("127.0.0.1:15000"));
105 assert!(is_plaintext_endpoint("http://not a valid url:1234"));
106 }
107
108 #[tokio::test]
109 async fn test_spanner_with_instance_type() {
110 let spanner = Spanner::builder()
111 .with_instance_type(InstanceType::Omni)
112 .build()
113 .await
114 .expect("build client");
115 assert_eq!(spanner.instance_type(), InstanceType::Omni);
116 }
117
118 #[tokio::test]
119 #[ignore = "requires live Omni instance at localhost:15000"]
120 async fn test_query_local_omni_instance() {
121 let spanner = Spanner::builder()
122 .with_endpoint("http://localhost:15000")
123 .with_instance_type(InstanceType::Omni)
124 .build()
125 .await
126 .expect("build client");
127
128 let db_client = spanner
129 .database_client("retail-sample")
130 .build()
131 .await
132 .expect("build db client");
133
134 let tx = db_client.single_use().build();
135 let mut rs = tx
136 .execute_query("SELECT * FROM Products LIMIT 5")
137 .await
138 .expect("execute query");
139
140 let mut count = 0;
141 while let Some(row) = rs.next().await {
142 let row = row.expect("read row");
143 println!("Fetched Omni row {}: {:?}", count, row);
144 count += 1;
145 }
146 println!("Successfully queried Omni! Total rows fetched: {}", count);
147 }
148}