diff --git a/src/migrations/create.rs b/src/migrations/create.rs index 01386d942..0be52566e 100644 --- a/src/migrations/create.rs +++ b/src/migrations/create.rs @@ -1,145 +1,9 @@ -// module default { -// type SharesAName { -// # Change both to another scalar type, should return _ and tell user to choose between . and @ -// multi link some_link: SharesAName { -// shares_a_name: int64; -// } -// shares_a_name: int64; -// } -// - -// -// type DoesNotShareName { -// multi link other_link: DoesNotShareName { -// # Change this to another scalar type, should suggest cast with @ -// does_not_share_name: int64; -// } -// } - -// type TimeType { -// # Change to datetime, should suggest to_datetime function -// int_to_datetime: int64; -// } - -// type StrToArrayStr { -// # Change to array, should suggest a number of functions including -// # the user-defined one below -// s: array; -// } - -// function str_to_array_str(input: str) -> array using ( -// [input] -// ) - -// type ArrayToInt16 { -// # Todo: Change to int64, should recognize as array and suggest count() -// a: array; -// } -// } - use std::{ borrow::Cow, collections::{HashMap, BTreeMap}, path::{Path, PathBuf}, sync::Arc }; -#[derive(Clone, Debug, Default)] -pub struct InteractiveMigrationInfo { - cast_info: HashMap>, - function_info: Vec, - properties: PropertyInfo -} - -#[derive(Queryable, Debug, Clone, Default)] -pub struct PropertyInfo { - regular_properties: Vec, - link_properties: Vec, -} - -#[derive(Queryable, Debug, Clone)] -pub struct FunctionInfo { - name: String, - input: String, - returns: String -} - -// Returns all functions as long as the type returned input type does not equal output -// (Casts only required when changing to a new type) -// Currently returns 161 functions -async fn get_function_info(cli: &mut Connection) -> Result, Error> { - cli.query::( - r#"with fn := (select schema::Function filter count(.params.type.name) = 1), - select fn { - name, - input := array_join(array_agg((.params.type.name)), ''), - returns := .return_type.name - };"#, - &(), - ) - .await -} - -#[derive(Queryable, Debug, Clone)] -pub struct CastInfo { - from_type_name: String, - to_type_name: String -} - -async fn get_cast_info(cli: &mut Connection) -> Result>, Error> { - let cast_info: Vec = cli - .query( - "select schema::Cast { - from_type_name := .from_type.name, - to_type_name := .to_type.name - };", - &(), - ) - .await?; - let mut map = std::collections::HashMap::new(); - for cast in cast_info { - map.entry(cast.from_type_name) - .or_insert(Vec::new()) - .push(cast.to_type_name); - } - Ok(map) -} - -// If all_properties has the same link name at least twice and the name matches one inside -// link_properties, then there is both a regular and a link property of the same name -// Possible todo: get info on source too. e.g. if shares_a_name is both an object property and link -// property in a whole bunch of types (but only once per type), don't want the CLI to inform the -// user about the same name -async fn get_all_property_info(cli: &mut Connection) -> Result { - cli.query_required_single("with - all_props := (select schema::Property filter .builtin = false), - props := (select all_props filter .source is schema::ObjectType and .name != 'id'), - links := (select all_props filter .source is schema::Link and .name not in {'target', 'source'}), - select { regular_properties := props.name, link_properties := links.name };", &()).await -} - -// Don't want to fail CLI if migration info can't be found, just log and return default -async fn get_migration_info(cli: &mut Connection) -> InteractiveMigrationInfo { - let function_info = get_function_info(cli).await.unwrap_or_else(|e| { - println!("Failed to find function info: {e}"); - log::debug!("Failed to find function info: {e}"); - Default::default() - }); - let cast_info = get_cast_info(cli).await.unwrap_or_else(|e| { - log::debug!("Failed to find cast_info: {e}"); - Default::default() - }); - let properties = get_all_property_info(cli).await.unwrap_or_else(|e| { - log::debug!("Failed to find property info: {e}"); - Default::default() - }); - - InteractiveMigrationInfo { - cast_info, - function_info, - properties - } -} - use anyhow::Context as _; use colorful::Colorful; use edgedb_derive::Queryable; @@ -199,19 +63,19 @@ enum Choice { } -/// Example: -/// -/// "required_user_input": [ -/// { -/// "prompt": "Please specify a conversion expression to alter the type of property 'strength'", -/// "new_type": "std::str", -/// "old_type": "std::int64", -/// "placeholder": "cast_expr", -/// "pointer_name": "strength", -/// "new_type_is_object": false, -/// "old_type_is_object": false -/// } -/// ] +// Example: +// +// "required_user_input": [ +// { +// "prompt": "Please specify a conversion expression to alter the type of property 'strength'", +// "new_type": "std::str", +// "old_type": "std::int64", +// "placeholder": "cast_expr", +// "pointer_name": "strength", +// "new_type_is_object": false, +// "old_type_is_object": false +// } +// ] #[derive(Deserialize, Debug, Clone)] pub struct RequiredUserInput { placeholder: String, @@ -233,7 +97,7 @@ pub struct StatementProposal { // Example: // -// "proposed": { +// "proposed": { // "prompt": "did you alter the type of property 'strength' of link 'times'?", // "data_safe": false, // "prompt_id": "SetPropertyType PROPERTY default::__|strength@default|__||times&default||Time", @@ -254,7 +118,7 @@ pub struct Proposal { } // Returned from each DESCRIBE CURRENT SCHEMA AS JSON during a migration. -// e.g. +// Example: // // { // "parent": "m17emwiottbbfc4coo7ybcrkljr5bhdv46ouoyyjrsj4qwvg7w5ina", @@ -321,6 +185,96 @@ struct InteractiveMigration<'a> { confirmed: Vec, } +#[derive(Clone, Debug, Default)] +pub struct InteractiveMigrationInfo { + cast_info: HashMap>, + function_info: Vec, + properties: PropertyInfo +} + +#[derive(Queryable, Debug, Clone, Default)] +pub struct PropertyInfo { + regular_properties: Vec, + link_properties: Vec, +} + +#[derive(Queryable, Debug, Clone)] +pub struct FunctionInfo { + name: String, + input: String, + returns: String +} + +// Returns all functions as long as the type returned input type does not equal output +// (Casts only required when changing to a new type) +async fn get_function_info(cli: &mut Connection) -> Result, Error> { + cli.query::( + r#"with fn := (select schema::Function filter count(.params.type.name) = 1), + select fn { + name, + input := array_join(array_agg((.params.type.name)), ''), + returns := .return_type.name + };"#, + &(), + ) + .await +} + +#[derive(Queryable, Debug, Clone)] +pub struct CastInfo { + from_type_name: String, + to_type_name: String +} + +async fn get_cast_info(cli: &mut Connection) -> Result>, Error> { + let cast_info: Vec = cli + .query( + "select schema::Cast { + from_type_name := .from_type.name, + to_type_name := .to_type.name + };", + &(), + ) + .await?; + let mut map = std::collections::HashMap::new(); + for cast in cast_info { + map.entry(cast.from_type_name) + .or_insert(Vec::new()) + .push(cast.to_type_name); + } + Ok(map) +} + +async fn get_all_property_info(cli: &mut Connection) -> Result { + cli.query_required_single("with + all_props := (select schema::Property filter .builtin = false), + props := (select all_props filter .source is schema::ObjectType and .name != 'id'), + links := (select all_props filter .source is schema::Link and .name not in {'target', 'source'}), + select { regular_properties := props.name, link_properties := links.name };", &()).await +} + +// Don't want to fail CLI if migration info can't be found, just log and return default +async fn get_migration_info(cli: &mut Connection) -> InteractiveMigrationInfo { + let function_info = get_function_info(cli).await.unwrap_or_else(|e| { + log::debug!("Failed to find function info: {e}"); + Default::default() + }); + let cast_info = get_cast_info(cli).await.unwrap_or_else(|e| { + log::debug!("Failed to find cast_info: {e}"); + Default::default() + }); + let properties = get_all_property_info(cli).await.unwrap_or_else(|e| { + log::debug!("Failed to find property info: {e}"); + Default::default() + }); + + InteractiveMigrationInfo { + cast_info, + function_info, + properties + } +} + #[derive(Debug, thiserror::Error)] #[error("refused to input data required for placeholder")] struct Refused;