use super::{alter, history, schema}; use crate::database::{Column, Kind, Migration, Plan, Sql, Statement}; use std::collections::BTreeMap; mod live; mod registry; const EMPTY: Plan = Plan { create: Sql::same(""), indexes: Sql::same(""), postgres_columns: &[], renames: &[], migrations: &[], seeds: &[], seed_revision: "empty", }; const fn column(name: &'static str, kind: &'static str) -> Column { Column { name, kind, default: None, nullable: false, generated: false, constraints: &[], } } const fn step( name: &'static str, revision: &'static str, drops: &'static [&'static str], ) -> Migration { Migration { name, revision, drops, before: &[], after: &[], } } #[test] fn migration_history_is_an_immutable_contiguous_prefix() { let plan = const { Plan { migrations: &[step("first", "one", &[]), step("second", "two", &[])], ..EMPTY } }; assert_eq!(history::validate(&[], &plan).unwrap(), 0); assert_eq!( history::validate(&[(0, "first".into(), "one".into())], &plan).unwrap(), 1 ); for records in [ vec![(1, "first".into(), "one".into())], vec![(0, "second".into(), "two".into())], vec![(0, "first".into(), "modified".into())], vec![ (0, "first".into(), "one".into()), (2, "second".into(), "two".into()), ], ] { assert_eq!( history::validate(&records, &plan).unwrap_err().kind, Kind::Migration ); } assert_eq!( history::validate(&[(0, "first".into(), "one".into())], &EMPTY) .unwrap_err() .kind, Kind::Migration ); } #[test] fn column_mapping_requires_exact_unused_drops_and_unambiguous_renames() { let old = BTreeMap::from([ ("id".into(), "bigint".into()), ("name".into(), "text".into()), ("removed".into(), "bigint".into()), ]); let plan = const { Plan { postgres_columns: &[ column("id", "bigint"), column("title", "text"), column("new", "uuid"), ], renames: &[("title", "name")], migrations: &[step("remove", "one", &["removed"])], ..EMPTY } }; assert_eq!( alter::sources(&old, &plan, 0).unwrap(), [Some("id"), Some("name"), None] ); assert_eq!( alter::sources(&old, &plan, 1).unwrap_err().kind, Kind::Migration ); let mut ambiguous = old.clone(); ambiguous.insert("title".into(), "text".into()); assert_eq!( alter::sources(&ambiguous, &plan, 0).unwrap_err().kind, Kind::Migration ); let missing = Plan { renames: &[("title", "absent")], ..plan }; assert_eq!( alter::sources(&old, &missing, 0).unwrap_err().kind, Kind::Migration ); let duplicated = Plan { postgres_columns: const { &[ column("id", "bigint"), column("title", "text"), column("other", "text"), ] }, renames: &[("title", "name"), ("other", "name")], ..missing }; assert_eq!( alter::sources(&old, &duplicated, 0).unwrap_err().kind, Kind::Migration ); } #[test] fn only_supported_storage_conversions_reach_postgres_ddl() { for (old, next) in [ ("text", "text"), ("numeric(6,2)", "numeric(8,3)"), ("numeric(8,3)", "numeric(6,2)"), ] { assert!(alter::conversion(old, next)); } for (old, next) in [ ("double precision", "bigint"), ("bigint", "double precision"), ("text", "uuid"), ("bigint", "numeric(8,2)"), ("bytea", "text"), ("numeric(6,2)", "numeric(3,4)"), ] { assert!(!alter::conversion(old, next)); } assert_eq!(schema::quote("a\"b"), "\"a\"\"b\""); }