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