supabase-plus 0.4.2

An extra set of tools for managing Supabase projects going beyond the possibilities of regular Supabase CLI
use std::{fs::File, io::Write, process::exit};

use crate::{abstraction::SupabaseProject, cli::CliSubcommand, commands::create::Bucket};
use async_trait::async_trait;
use chrono::Utc;
use promptuity::{
    Promptuity, Term,
    prompts::{Confirm, Input, Select, SelectOption},
    themes::FancyTheme,
};

#[async_trait]
impl CliSubcommand for Bucket {
    async fn run(self: Box<Self>) {
        let mut term = Term::default();
        let mut theme = FancyTheme::default();

        let (sql, timecode) = {
            let mut promptuity = Promptuity::new(&mut term, &mut theme);
            let _ = promptuity.term().clear();

            promptuity
                .with_intro("Creating bucket")
                .begin()
                .expect("Failed to start interactive mode");

            let name = promptuity
                .prompt(
                    Input::new("Please enter a slug for your new bucket")
                        .with_placeholder("cabinets"),
                )
                .ok()
                .unwrap_or_else(|| exit(0));

            let public = promptuity
                .prompt(
                    Select::new(
                        "Set the visibility of your bucket",
                        vec![
                            SelectOption::new("Public", true),
                            SelectOption::new("Private", false),
                        ],
                    )
                    .with_page_size(2),
                )
                .unwrap_or_else(|_| exit(0));

            let mime_type_limitation = promptuity
                .prompt(
                    Confirm::new("Would you also like to limit accepted mime types?")
                        .with_default(false),
                )
                .unwrap_or_else(|_| exit(0));

            let mut mime_types: Vec<String> = vec![];

            if mime_type_limitation {
                loop {
                    let hint = format!("{}", mime_types.clone().join(", "));

                    let ext = promptuity
                        .prompt(
                            Input::new(
                                "Please enter a file extension and we will guess the mime type",
                            )
                            .with_placeholder("jpg")
                            .with_hint(&hint),
                        )
                        .unwrap_or_else(|_| exit(0));

                    let Some(mime_type) = mime_guess::from_path(format!("_.{}", ext)).first()
                    else {
                        continue;
                    };

                    mime_types.push(mime_type.to_string());

                    let hint = format!("[{}]", mime_types.clone().join(", "));
                    let will_add_more = promptuity
                        .prompt(
                            Confirm::new("Would you like to add another mime type?")
                                .with_default(false)
                                .with_hint(hint),
                        )
                        .unwrap_or_else(|_| exit(0));

                    if !will_add_more {
                        break;
                    }
                }
            }

            let sql = format!(
                r#"INSERT INTO storage.buckets (id, name, public, allowed_mime_types) VALUES ('{0}', '{0}', {1}, '{{{2}}}'::text[]);"#,
                name,
                public,
                mime_types.join(", ")
            );

            let timecode = Utc::now().format("%Y%m%d%H%M%S").to_string();
            let migration_name = format!("{timecode}_create_{name}_bucket");

            let mut file = File::create(format!("supabase/migrations/{migration_name}.sql"))
                .expect("Failed to create migration file");

            file.write_all(sql.as_bytes())
                .expect("Failed to write to migration file");

            file.sync_all().expect("Failed to sync migration file");

            let shall_run = promptuity
                .prompt(
                    Confirm::new(
                        "Would you like to run this specific migration and set to applied?",
                    )
                    .with_default(true),
                )
                .unwrap_or_else(|_| exit(0));

            let _ = promptuity.finish();

            if !shall_run {
                println!("Migration file created successfully!");
                exit(0);
            }

            (sql, timecode)
        };

        SupabaseProject::run_query(&sql)
            .await
            .expect("Failed to run query");

        cmd!(
            "npx --yes supabase@latest migration repair --local --status applied {}",
            &timecode
        )
        .run()
        .unwrap();

        println!("Migration file created successfully, migration applied locally!");
    }
}
//