Skip to main content

datasources_postgres/
lib.rs

1mod 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}