datasources_postgres/
lib.rs1mod alter_table_statement_renderer;
2mod bind;
3mod command;
4mod connection;
5mod converters;
6mod create_table_statement_renderer;
7mod create_trigger_statement_renderer;
8mod drop_routine_statement_renderer;
9mod driver;
10mod identity_insert_statement_renderer;
11mod default_value_converter;
12mod default_value_options;
13mod sql_generate;
14mod type_map;
15mod pg_value;
16mod reader;
17mod select_inserted_id_statement_text_renderer;
18mod sql_seed_statement_renderer;
19mod statement_renderer;
20mod stored_procedure_statement_renderer;
21mod transaction;
22
23pub use driver::PostgresDriver;
24
25#[cfg(test)]
26#[path = "../tests/isolate.rs"]
27mod isolate;
28#[cfg(test)]
29#[path = "../tests/contacts.rs"]
30mod contacts;
31#[cfg(test)]
32#[path = "../tests/integration.rs"]
33mod integration;
34#[cfg(test)]
35#[path = "../tests/repository_spec.rs"]
36mod repository_spec;
37#[cfg(test)]
38#[path = "../tests/generate_sql.rs"]
39mod generate_sql;
40#[cfg(test)]
41#[path = "../tests/generate_sql_casing.rs"]
42mod generate_sql_casing;
43#[cfg(test)]
44#[path = "../tests/generate_sql_mapping.rs"]
45mod generate_sql_mapping;
46
47#[cfg(test)]
48mod tests {
49 use crate::bind::{param_type, to_postgres};
50 use crate::connection::isolation_sql;
51 use crate::converters::BinaryConverter;
52 use tokio_postgres::types::Type;
53 use crate::command::PostgresCommand;
54 use crate::connection::PostgresConnection;
55 use crate::transaction::PostgresTransaction;
56 use datasources::{
57 Row, create, downcast_connection, register, reset, Command, Connection,
58 Driver, IsolationLevel, Transaction, TypeConverter, Value,
59 };
60 use std::collections::HashMap;
61 use std::sync::Arc;
62
63 struct With(Option<String>);
64
65 impl Driver for With {
66 fn connection(&self, _: Option<&HashMap<String, String>>) -> Arc<dyn Connection> {
67 Arc::new(PostgresConnection::new(self.0.clone(), None))
68 }
69
70 fn command(&self, connection: Arc<dyn Connection>) -> Arc<dyn Command> {
71 connection.create_command()
72 }
73
74 fn transaction(
75 &self,
76 connection: Arc<dyn Connection>,
77 isolation: IsolationLevel,
78 ) -> Arc<dyn Transaction> {
79 let conn = downcast_connection::<PostgresConnection>(connection).expect("postgres");
80 Arc::new(PostgresTransaction::new(conn.share(), isolation))
81 }
82
83 fn row_type_converters(
84 &self,
85 ) -> HashMap<
86 String,
87 Box<
88 dyn datasources::TypeConverter<datasources::Value, datasources::Value>
89 + Send
90 + Sync,
91 >,
92 > {
93 crate::converters::row_type_converters()
94 }
95 }
96
97 #[tokio::test]
98 async fn postgres_command_and_repository() {
99 let (sql, values) = to_postgres(
100 "SELECT * FROM t WHERE id = $id AND n = $id",
101 &HashMap::from([("id".into(), Value::Int(1))]),
102 );
103 assert_eq!(sql, "SELECT * FROM t WHERE id = $1 AND n = $1");
104 assert_eq!(values, vec![Value::Int(1)]);
105 let (seed, _) = to_postgres(
106 "INSERT INTO \"contact_sources\" (\"name\") VALUES ('Manual')",
107 &HashMap::new(),
108 );
109 assert_eq!(seed, "INSERT INTO \"contact_sources\" (\"name\") VALUES ('Manual')");
110 let (legacy, _) = to_postgres("SELECT * FROM OldContactsTbl", &HashMap::new());
111 assert_eq!(legacy, "SELECT * FROM \"OldContactsTbl\"");
112 let (_, missing) = to_postgres("SELECT $missing", &HashMap::new());
113 assert_eq!(missing, vec![Value::Null]);
114 let stamp = Value::from("2020-01-02T03:04:05.000Z");
115 assert_eq!(param_type(&stamp), Type::UNKNOWN);
116 assert_eq!(
117 param_type(&Value::DateTime(
118 chrono::DateTime::parse_from_rfc3339("2020-01-02T03:04:05.000Z")
119 .unwrap()
120 .with_timezone(&chrono::Utc)
121 )),
122 Type::TIMESTAMPTZ
123 );
124 assert_eq!(param_type(&Value::from("ada")), Type::UNKNOWN);
125 assert!(matches!(
126 BinaryConverter.convert(&Value::from("AQ==")).unwrap(),
127 Value::Binary(_)
128 ));
129 assert_eq!(param_type(&Value::from("AA==")), Type::UNKNOWN);
130 assert_eq!(param_type(&Value::Binary(vec![0])), Type::BYTEA);
131 assert_eq!(param_type(&Value::Int(1)), Type::INT4);
132 assert_eq!(param_type(&Value::Int(i64::MAX)), Type::INT8);
133 assert_eq!(
134 isolation_sql(IsolationLevel::ReadUncommitted),
135 "READ UNCOMMITTED"
136 );
137 assert_eq!(
138 isolation_sql(IsolationLevel::ReadCommitted),
139 "READ COMMITTED"
140 );
141 assert_eq!(
142 isolation_sql(IsolationLevel::RepeatableRead),
143 "REPEATABLE READ"
144 );
145 assert_eq!(isolation_sql(IsolationLevel::Serializable), "SERIALIZABLE");
146 let conn = Arc::new(PostgresConnection::new(
147 Some("postgres://db/app".into()),
148 Some("s".into()),
149 ));
150 assert_eq!(conn.schema.as_deref(), Some("s"));
151 let command = PostgresCommand::new(conn.clone());
152 command
153 .execute_native(&datasources::Native::new(""), None)
154 .await
155 .unwrap();
156 command
157 .execute_reader_native(&datasources::Native::new(""), None)
158 .await
159 .unwrap();
160 assert!(conn.start_transaction(None).await.is_err());
161 conn.close().await.unwrap();
162 assert!(conn.ensure_open().is_err());
163 let defaulted = PostgresConnection::new(None, None);
164 assert_eq!(defaulted.url, "");
165 let options = HashMap::from([(
166 "DATASOURCE_URL".into(),
167 "postgres://db/app?schema=s".into(),
168 )]);
169 let from = downcast_connection::<PostgresConnection>(PostgresConnection::from_options(
170 Some(&options),
171 ))
172 .expect("postgres");
173 assert_eq!(from.url, "postgres://db/app?schema=s");
174 assert_eq!(from.schema.as_deref(), Some("s"));
175 assert_eq!(
176 crate::connection::connect_url("postgres://db/app?schema=s"),
177 "postgres://db/app"
178 );
179 assert_eq!(
180 crate::connection::connect_url(
181 "postgres://ds:ds@127.0.0.1:15432/datasources?schema=ds_x"
182 ),
183 "postgres://ds:ds@127.0.0.1:15432/datasources"
184 );
185 reset();
186 register("postgres", Arc::new(With(Some("postgres://db/app".into()))));
187 let ds = create(Some(&HashMap::from([(
188 "PROVIDER".into(),
189 "postgres".into(),
190 )])))
191 .unwrap();
192 assert_eq!(ds.provider(), "postgres");
193 assert!(ds.create_command(None).await.is_err());
194 ds.create_repository::<Row>(None, None);
195 let closed = Arc::new(PostgresConnection::new(None, None));
196 assert!(PostgresCommand::new(closed)
197 .execute_native(&datasources::Native::new("x"), None)
198 .await
199 .is_err());
200 }
201}