create_rust_app/dev/
controller.rs1use crate::Database;
2use anyhow::{bail, Result};
3use diesel::{
4 migration::{Migration, MigrationSource},
5 query_dsl::RunQueryDsl,
6 sql_query,
7 sql_types::Text,
8};
9use diesel_migrations::{FileBasedMigrations, MigrationHarness};
10use serde::{Deserialize, Serialize};
11
12use super::{CreateRustAppMigration, MigrationStatus};
13
14#[derive(Debug, Deserialize, QueryableByName)]
15pub struct MyQueryResult {
16 #[diesel(sql_type=Text)]
17 pub json: String,
18}
19
20#[derive(Serialize, Deserialize)]
21pub struct MySqlQuery {
22 pub query: String,
23}
24
25#[derive(Serialize, Deserialize)]
26pub struct HealthCheckResponse {
27 pub message: String,
28}
29
30pub fn query_db(db: &Database, body: &MySqlQuery) -> Result<String, diesel::result::Error> {
38 let q = format!("SELECT json_agg(q) as json FROM ({}) q;", body.query);
39 let mut db = db.get_connection().unwrap();
40
41 Ok(sql_query(q.as_str())
42 .get_result::<MyQueryResult>(&mut db)?
43 .json)
44}
45
46#[must_use]
48pub fn is_connected(db: &Database) -> bool {
49 let Ok(mut db) = db.pool.clone().get() else {
50 return false;
51 };
52 let is_connected = sql_query("SELECT 1;").execute(&mut db);
53 is_connected.is_err()
54}
55
56#[must_use]
60pub fn get_migrations(db: &Database) -> Vec<CreateRustAppMigration> {
61 let mut db = db.pool.clone().get().unwrap();
63
64 let source = FileBasedMigrations::find_migrations_directory().unwrap();
65
66 #[cfg(feature = "database_sqlite")]
67 let file_migrations =
68 MigrationSource::<crate::database::DieselBackend>::migrations(&source).unwrap();
69 #[cfg(feature = "database_postgres")]
70 let file_migrations =
71 MigrationSource::<crate::database::DieselBackend>::migrations(&source).unwrap();
72
73 let db_migrations = MigrationHarness::applied_migrations(&mut db).unwrap();
74 let pending_migrations = MigrationHarness::pending_migrations(&mut db, source).unwrap();
75
76 let mut all_migrations = vec![];
77
78 for fm in &file_migrations {
79 all_migrations.push(CreateRustAppMigration {
80 name: fm.name().to_string(),
81 version: fm.name().version().to_string(),
82 status: MigrationStatus::Unknown,
83 });
84 }
85
86 for pm in &pending_migrations {
88 if let Some(existing) = all_migrations.iter_mut().find(|m| {
89 m.version
90 .eq_ignore_ascii_case(&pm.name().version().to_string())
91 }) {
92 existing.status = MigrationStatus::Pending;
93 }
94 }
95
96 for dm in &db_migrations {
97 match all_migrations
98 .iter_mut()
99 .find(|m| m.version.eq_ignore_ascii_case(&dm.to_string()))
100 {
101 Some(existing) => {
102 existing.status = MigrationStatus::Applied;
103 }
104 None => all_migrations.push(CreateRustAppMigration {
105 name: format!("{dm}_?"),
106 version: dm.to_string(),
107 status: MigrationStatus::AppliedButMissingLocally,
108 }),
109 }
110 }
111
112 all_migrations
113}
114
115#[must_use]
124pub fn needs_migration(db: &Database) -> bool {
125 let mut db = db.pool.clone().get().unwrap();
126
127 let source = FileBasedMigrations::find_migrations_directory().unwrap();
128 MigrationHarness::has_pending_migration(&mut db, source).unwrap()
129}
130
131pub fn migrate_db(db: &Database) -> Result<()> {
141 let mut db = db.pool.clone().get().unwrap();
142
143 let source = FileBasedMigrations::find_migrations_directory().unwrap();
144 let has_pending_migrations =
145 MigrationHarness::has_pending_migration(&mut db, source.clone()).unwrap();
146
147 if !has_pending_migrations {
148 return Ok(());
149 }
150
151 let op = MigrationHarness::run_pending_migrations(&mut db, source);
152 match op {
153 Ok(_) => Ok(()),
154 Err(err) => {
155 println!("{err:#?}");
156 bail!(err)
157 }
158 }
159}
160
161pub const fn health() {}