postgres.rs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. use futures_util::{stream::FuturesUnordered, TryStreamExt};
  2. use rand::{rngs::SmallRng, SeedableRng, Rng, thread_rng};
  3. use crate::models::{World, Fortune};
  4. #[derive(Clone)]
  5. pub struct Postgres(sqlx::PgPool);
  6. impl Postgres {
  7. pub async fn init() -> impl ohkami::FrontFang {
  8. pub struct UsePostgres(Postgres);
  9. impl ohkami::FrontFang for UsePostgres {
  10. type Error = std::convert::Infallible;
  11. #[inline(always)]
  12. async fn bite(&self, req: &mut ohkami::Request) -> Result<(), Self::Error> {
  13. req.memorize(self.0.clone());
  14. Ok(())
  15. }
  16. }
  17. macro_rules! load_env {
  18. ($($name:ident as $t:ty)*) => {
  19. $(
  20. #[allow(non_snake_case)]
  21. let $name = ::std::env::var(stringify!($name))
  22. .expect(concat!(
  23. "Failed to load environment variable ",
  24. "`", stringify!($name), "`"
  25. ))
  26. .parse::<$t>()
  27. .unwrap();
  28. )*
  29. };
  30. } load_env! {
  31. MAX_CONNECTIONS as u32
  32. MIN_CONNECTIONS as u32
  33. DATABASE_URL as String
  34. }
  35. UsePostgres(Self(
  36. sqlx::postgres::PgPoolOptions::new()
  37. .max_connections(MAX_CONNECTIONS)
  38. .min_connections(MIN_CONNECTIONS)
  39. .connect(&DATABASE_URL).await
  40. .unwrap()
  41. ))
  42. }
  43. }
  44. impl Postgres {
  45. pub async fn select_random_world(&self) -> World {
  46. let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
  47. sqlx::query_as(
  48. "SELECT id, randomnumber FROM World WHERE id = $1")
  49. .bind((rng.gen::<u32>() % 10_000 + 1) as i32)
  50. .fetch_one(&self.0).await
  51. .expect("Failed to fetch a world")
  52. }
  53. pub async fn select_all_fortunes(&self) -> Vec<Fortune> {
  54. sqlx::query_as(
  55. "SELECT id, message FROM Fortune")
  56. .fetch_all(&self.0).await
  57. .expect("Failed to fetch fortunes")
  58. }
  59. pub async fn select_n_random_worlds(&self, n: usize) -> Vec<World> {
  60. let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
  61. let selects = FuturesUnordered::new();
  62. for _ in 0..n {
  63. selects.push(
  64. sqlx::query_as(
  65. "SELECT id, randomnumber FROM World WHERE id = $1")
  66. .bind((rng.gen::<u32>() % 10_000 + 1) as i32)
  67. .fetch_one(&self.0)
  68. )
  69. }
  70. selects.try_collect().await.expect("Failed to fetch worlds")
  71. }
  72. pub async fn update_random_ids_of_worlds(&self, worlds: &mut Vec<World>) {
  73. let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
  74. let updates = FuturesUnordered::new();
  75. for w in worlds {
  76. w.randomnumber = (rng.gen::<u32>() % 10_000 + 1) as i32;
  77. updates.push(
  78. sqlx::query(
  79. "UPDATE World SET randomnumber = $1 WHERE id = $2")
  80. .bind(w.randomnumber)
  81. .bind(w.id)
  82. .execute(&self.0)
  83. )
  84. }
  85. let _: sqlx::postgres::PgQueryResult = updates.try_collect().await.expect("Failed to fetch worlds");
  86. }
  87. }