Skip to content

Commit

Permalink
Branches: REPL backslash commands for branches (#1284)
Browse files Browse the repository at this point in the history
  • Loading branch information
quinchs authored Apr 16, 2024
1 parent 7732492 commit 318b321
Show file tree
Hide file tree
Showing 15 changed files with 150 additions and 43 deletions.
2 changes: 1 addition & 1 deletion src/branch/current.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crossterm::style::Stylize;
use crate::branch::context::Context;
use crate::branch::option::Current;
use crate::connect::Connection;


pub async fn main(
options: &Current,
Expand Down
41 changes: 27 additions & 14 deletions src/branch/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

use crate::branch::context::Context;
use crate::branch::option::{BranchCommand, Command};
use crate::branch::{create, current, drop, list, merge, rebase, rename, switch, wipe};
Expand All @@ -10,31 +11,43 @@ use edgedb_tokio::get_project_dir;
pub async fn branch_main(options: &Options, cmd: &BranchCommand) -> anyhow::Result<()> {
let context = create_context().await?;

run_branch_command(&cmd.subcommand, options, &context, None).await
}

pub async fn run_branch_command(cmd: &Command, options: &Options, context: &Context, connection: Option<&mut Connection>) -> anyhow::Result<()> {
let mut connector: Connector = options.conn_params.clone();

// match commands that don't require a connection to run, then match the ones that do with a connection.
match &cmd.subcommand {
match &cmd {
Command::Switch(switch) => switch::main(switch, &context, &mut connector).await,
Command::Wipe(wipe) => wipe::main(wipe, &context, &mut connector).await,
Command::Current(current) => current::main(current, &context).await,
command => {
let mut connection = connector.connect().await?;
verify_server_can_use_branches(&mut connection).await?;

match command {
Command::Create(create) => create::main(create, &context, &mut connection).await,
Command::Drop(drop) => drop::main(drop, &context, &mut connection).await,
Command::List(list) => list::main(list, &context, &mut connection).await,
Command::Rename(rename) => rename::main(rename, &context, &mut connection, &options).await,
Command::Rebase(rebase) => rebase::main(rebase, &context, &mut connection, &options).await,
Command::Merge(merge) => merge::main(merge, &context, &mut connection, &options).await,
unhandled => anyhow::bail!("unimplemented branch command '{:?}'", unhandled)
match connection {
Some(conn) => run_branch_command1(command, conn, context, options).await,
None => {
let mut conn = connector.connect().await?;
run_branch_command1(command, &mut conn, context, options).await
}
}
}
}
}

async fn create_context() -> anyhow::Result<Context> {
async fn run_branch_command1(command: &Command, connection: &mut Connection, context: &Context, options: &Options) -> anyhow::Result<()> {
verify_server_can_use_branches(connection).await?;

match command {
Command::Create(create) => create::main(create, &context, connection).await,
Command::Drop(drop) => drop::main(drop, &context, connection).await,
Command::List(list) => list::main(list, &context, connection).await,
Command::Rename(rename) => rename::main(rename, &context, connection, &options).await,
Command::Rebase(rebase) => rebase::main(rebase, &context, connection, &options).await,
Command::Merge(merge) => merge::main(merge, &context, connection, &options).await,
unhandled => anyhow::bail!("unimplemented branch command '{:?}'", unhandled)
}
}

pub async fn create_context() -> anyhow::Result<Context> {
let project_dir = get_project_dir(None, true).await?;
Context::new(project_dir.as_ref()).await
}
Expand Down
2 changes: 1 addition & 1 deletion src/branch/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod context;
pub mod context;
mod create;
mod drop;
mod list;
Expand Down
17 changes: 17 additions & 0 deletions src/branch/option.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@

use crate::commands::parser::BranchingCmd;
use crate::options::ConnectionOptions;

#[derive(clap::Args, Debug, Clone)]
pub struct BranchCommand {
#[command(flatten)]
pub conn: ConnectionOptions,

#[command(subcommand)]
pub subcommand: Command,
}
Expand All @@ -17,6 +24,16 @@ pub enum Command {
Current(Current)
}

impl From<&BranchingCmd> for Command {
fn from(cmd: &BranchingCmd) -> Self {
match cmd {
BranchingCmd::Create(args) => Command::Create(args.clone()),
BranchingCmd::Drop(args) => Command::Drop(args.clone()),
BranchingCmd::Wipe(args) => Command::Wipe(args.clone()),
}
}
}

/// Creates a new branch and switches to it.
#[derive(clap::Args, Debug, Clone)]
pub struct Create {
Expand Down
7 changes: 4 additions & 3 deletions src/commands/backslash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Introspection
\d [-v] NAME Describe schema object
\ds Describe whole schema (alias: \describe schema)
\l List databases (alias: \list databases)
\l List databases/branches (alias: \list branches)
\ls [-sc] [PATTERN] List scalar types (alias: \list scalars)
\lt [-sc] [PATTERN] List object types (alias: \list types)
\lr [-c] [PATTERN] List roles (alias: \list roles)
Expand All @@ -63,7 +63,7 @@ Editing
Defaults to vi (Notepad in Windows).
Connection
\c, \connect [DBNAME] Connect to database DBNAME
\c, \connect [DBNAME] Connect to database/branch DBNAME
Settings
\set [OPTION [VALUE]] Show/change settings. Type \set to list
Expand Down Expand Up @@ -306,7 +306,7 @@ impl CommandCache {
let mut aliases = BTreeMap::new();
aliases.insert("d", &["describe", "object"][..]);
aliases.insert("ds", &["describe", "schema"]);
aliases.insert("l", &["list", "databases"]);
aliases.insert("l", &["list", "branches"]);
aliases.insert("ls", &["list", "scalars"]);
aliases.insert("lt", &["list", "types"]);
aliases.insert("lr", &["list", "roles"]);
Expand All @@ -322,6 +322,7 @@ impl CommandCache {
aliases.insert("quit", &["exit"]);
aliases.insert("?", &["help"]);
aliases.insert("h", &["help"]);
aliases.insert("branch", &["branching"]);
let mut setting_cmd = None;
let commands: BTreeMap<_,_> = clap.get_subcommands_mut()
.map(|cmd| {
Expand Down
10 changes: 10 additions & 0 deletions src/commands/branching.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use crate::branch;
use crate::commands::parser::BranchingCmd;
use crate::connect::Connection;
use crate::commands::Options;

pub async fn main(connection: &mut Connection, cmd: &BranchingCmd, options: &Options) -> anyhow::Result<()> {
let context = branch::main::create_context().await?;

branch::main::run_branch_command(&cmd.into(), options, &context, Some(connection)).await
}
10 changes: 8 additions & 2 deletions src/commands/execute.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::connect::Connection;
use edgedb_tokio::server_params::PostgresAddress;

use crate::analyze;
use crate::{analyze, options};
use crate::commands::parser::{Common, DatabaseCmd, ListCmd, DescribeCmd};
use crate::commands::{self, Options};
use crate::commands::{self, branching, Options};
use crate::migrations::options::{MigrationCmd};
use crate::migrations;
use crate::print;
Expand All @@ -29,6 +29,9 @@ pub async fn common(cli: &mut Connection, cmd: &Common, options: &Options)
}
ListCmd::Databases => {
commands::list_databases(cli, &options).await?;
},
ListCmd::Branches => {
commands::list_branches(cli, &options).await?;
}
ListCmd::Scalars(c) => {
commands::list_scalar_types(cli, &options,
Expand Down Expand Up @@ -91,6 +94,9 @@ pub async fn common(cli: &mut Connection, cmd: &Common, options: &Options)
DatabaseCmd::Wipe(w) => {
commands::database::wipe(cli, w, &options).await?;
}
},
Branching(branching) => {
branching::main(cli, &branching.subcommand, &options).await?
}
Migrate(params) => {
migrations::migrate(cli, &options, params).await?;
Expand Down
27 changes: 27 additions & 0 deletions src/commands/list_branches.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use crate::commands::list_databases::get_databases;
use crate::commands::{list, list_databases, Options};
use crate::connect::Connection;
use crate::print;

pub async fn get_branches(cli: &mut Connection) -> anyhow::Result<Vec<String>> {
get_databases(cli).await
}

pub async fn list_branches(cli: &mut Connection, options: &Options)
-> Result<(), anyhow::Error>
{
let version = cli.get_version().await?;

if version.specific().major <= 4 {
print::warn(format!("Branches are not supported in EdgeDB {}, printing list of databases instead", version));
return list_databases(cli, options).await;
}

list_branches0(cli, options).await
}

pub async fn list_branches0(cli: &mut Connection, options: &Options) -> Result<(), anyhow::Error> {
let databases = get_branches(cli).await?;
list::print(databases, "List of branches", options).await?;
Ok(())
}
10 changes: 10 additions & 0 deletions src/commands/list_databases.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crate::commands::Options;
use crate::commands::list;
use crate::commands::list_branches::{list_branches0};
use crate::connect::Connection;
use crate::print;


pub async fn get_databases(cli: &mut Connection) -> anyhow::Result<Vec<String>>
Expand All @@ -15,6 +17,14 @@ pub async fn get_databases(cli: &mut Connection) -> anyhow::Result<Vec<String>>
pub async fn list_databases(cli: &mut Connection, options: &Options)
-> Result<(), anyhow::Error>
{
let version = cli.get_version().await?;


if version.specific().major >= 5 {
print::warn(format!("Databases are not supported in EdgeDB {}, printing list of branches instead", version));
return list_branches0(cli, options).await;
}

let databases = get_databases(cli).await?;
list::print(databases, "List of databases", options).await?;
Ok(())
Expand Down
3 changes: 3 additions & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ pub mod cli;
pub mod options;
pub mod parser;
mod ui;
mod list_branches;
mod branching;

pub use self::configure::configure;
pub use self::dump::{dump, dump_all};
Expand All @@ -32,6 +34,7 @@ pub use self::describe_schema::describe_schema;
pub use self::list_aliases::list_aliases;
pub use self::list_casts::list_casts;
pub use self::list_databases::list_databases;
pub use self::list_branches::list_branches;
pub use self::list_indexes::list_indexes;
pub use self::list_modules::list_modules;
pub use self::list_object_types::list_object_types;
Expand Down
27 changes: 26 additions & 1 deletion src/commands/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub enum Common {

/// Database commands
Database(Database),
Branching(Branching),
/// Describe database schema or object
Describe(Describe),

Expand Down Expand Up @@ -96,8 +97,10 @@ pub enum ListCmd {
Aliases(ListAliases),
/// Display list of casts defined in the schema
Casts(ListCasts),
/// Display list of databases for an EdgeDB instance
/// On EdgeDB < 5.x: Display list of databases for an EdgeDB instance
Databases,
/// On EdgeDB >= 5.x: Display list of branches for an EdgeDB instance
Branches,
/// Display list of indexes defined in the schema
Indexes(ListIndexes),
/// Display list of modules defined in the schema
Expand All @@ -110,6 +113,28 @@ pub enum ListCmd {
Types(ListTypes),
}

#[derive(clap::Args, Clone, Debug)]
#[command(version = "help_expand")]
#[command(disable_version_flag=true)]
pub struct Branching {
#[command(flatten)]
pub conn: ConnectionOptions,

#[command(subcommand)]
pub subcommand: BranchingCmd,
}

#[derive(clap::Subcommand, Clone, Debug)]
pub enum BranchingCmd {
/// Create a new branch
Create(crate::branch::option::Create),
/// Delete a branch along with its data
Drop(crate::branch::option::Drop),
/// Delete a branches data and reset its schema while
/// preserving the branch itself (its cfg::DatabaseConfig)
/// and existing migration scripts
Wipe(crate::branch::option::Wipe),
}

#[derive(clap::Args, Clone, Debug)]
#[command(version = "help_expand")]
Expand Down
18 changes: 9 additions & 9 deletions src/migrations/create.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::borrow::Cow;
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::slice::Iter;

use anyhow::Context as _;
use colorful::Colorful;
Expand Down Expand Up @@ -106,12 +107,11 @@ pub enum MigrationKey {
Fixup { target_revision: String },
}

pub trait MigrationToText {
type StatementsIter<'a>: Iterator<Item = &'a String> where Self: 'a;
pub trait MigrationToText<'a, T: Iterator<Item = &'a String> = std::iter::Once<&'a String>> {
fn key(&self) -> &MigrationKey;
fn parent(&self) -> anyhow::Result<&str>;
fn id(&self) -> anyhow::Result<&str>;
fn statements<'a>(&'a self) -> Self::StatementsIter<'a>;
fn statements(&'a self) -> T;
}

#[derive(Debug)]
Expand Down Expand Up @@ -165,9 +165,7 @@ impl FutureMigration {
}
}

impl MigrationToText for FutureMigration {
type StatementsIter<'a> = std::slice::Iter<'a, String>;

impl<'a> MigrationToText<'a, Iter<'a, String> > for FutureMigration {
fn key(&self) -> &MigrationKey {
&self.key
}
Expand All @@ -188,7 +186,7 @@ impl MigrationToText for FutureMigration {
}).map(|s| &s[..])
}

fn statements<'a>(&'a self) -> Self::StatementsIter<'a> {
fn statements(&'a self) -> Iter<'a, String> {
self.statements.iter()
}
}
Expand Down Expand Up @@ -699,9 +697,10 @@ async fn run_interactive(_ctx: &Context, cli: &mut Connection,
Ok(FutureMigration::new(key, descr))
}

pub async fn write_migration(ctx: &Context, descr: &impl MigrationToText,
pub async fn write_migration<'a, T>(ctx: &Context, descr: &'a impl MigrationToText<'a, T>,
verbose: bool)
-> anyhow::Result<()>
where T : Iterator<Item = &'a String>
{
let filename = match &descr.key() {
MigrationKey::Index(idx) => {
Expand All @@ -717,9 +716,10 @@ pub async fn write_migration(ctx: &Context, descr: &impl MigrationToText,
}

#[context("could not write migration file {}", filepath.display())]
async fn _write_migration(descr: &impl MigrationToText, filepath: &Path,
async fn _write_migration<'a, T>(descr: &'a impl MigrationToText<'a, T>, filepath: &Path,
verbose: bool)
-> anyhow::Result<()>
where T : Iterator<Item = &'a String>
{
let id = descr.id()?;
let dir = filepath.parent().unwrap();
Expand Down
7 changes: 3 additions & 4 deletions src/migrations/extract.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::iter::Once;
use fs_err as fs;

use crate::commands::{ExitCode, Options};
Expand All @@ -14,9 +15,7 @@ pub struct DatabaseMigration {
pub migration: db_migration::DBMigration,
}

impl MigrationToText for DatabaseMigration {
type StatementsIter<'a> = std::iter::Once<&'a String>;

impl<'a> MigrationToText<'a, Once<&'a String>> for DatabaseMigration {
fn key(&self) -> &MigrationKey {
&self.key
}
Expand All @@ -35,7 +34,7 @@ impl MigrationToText for DatabaseMigration {
Ok(&self.migration.name)
}

fn statements<'a>(&'a self) -> Self::StatementsIter<'a> {
fn statements(&'a self) -> Once<&'a String> {
std::iter::once(&self.migration.script)
}
}
Expand Down
Loading

0 comments on commit 318b321

Please sign in to comment.