reifydb-catalog 0.4.10

Database catalog and metadata management for ReifyDB
Documentation
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2025 ReifyDB

use reifydb_core::{
	interface::catalog::migration::{Migration, MigrationAction, MigrationEvent},
	key::{migration::MigrationKey, migration_event::MigrationEventKey},
};
use reifydb_transaction::transaction::{Transaction, admin::AdminTransaction};
use reifydb_type::fragment::Fragment;

use crate::{
	CatalogStore, Result,
	error::{CatalogError, CatalogObjectKind},
	store::{
		migration::shape::{migration as migration_shape, migration_event as event_shape},
		sequence::system::SystemSequence,
	},
};

pub struct MigrationToCreate {
	pub name: String,
	pub body: String,
	pub rollback_body: Option<String>,
}

impl CatalogStore {
	pub(crate) fn create_migration(txn: &mut AdminTransaction, to_create: MigrationToCreate) -> Result<Migration> {
		// Check for duplicate name
		if let Some(_existing) =
			CatalogStore::find_migration_by_name(&mut Transaction::Admin(&mut *txn), &to_create.name)?
		{
			return Err(CatalogError::AlreadyExists {
				kind: CatalogObjectKind::Migration,
				namespace: String::new(),
				name: to_create.name,
				fragment: Fragment::None,
			}
			.into());
		}

		let migration_id = SystemSequence::next_migration_id(txn)?;

		let mut row = migration_shape::SHAPE.allocate();
		migration_shape::SHAPE.set_u64(&mut row, migration_shape::ID, migration_id);
		migration_shape::SHAPE.set_utf8(&mut row, migration_shape::NAME, &to_create.name);
		migration_shape::SHAPE.set_utf8(&mut row, migration_shape::BODY, &to_create.body);
		migration_shape::SHAPE.set_utf8(
			&mut row,
			migration_shape::ROLLBACK_BODY,
			to_create.rollback_body.as_deref().unwrap_or(""),
		);

		txn.set(&MigrationKey::encoded(migration_id), row)?;

		Ok(Migration {
			id: migration_id,
			name: to_create.name,
			body: to_create.body,
			rollback_body: to_create.rollback_body,
		})
	}

	pub(crate) fn create_migration_event(
		txn: &mut AdminTransaction,
		migration: &Migration,
		action: MigrationAction,
	) -> Result<MigrationEvent> {
		let event_id = SystemSequence::next_migration_event_id(txn)?;

		let mut row = event_shape::SHAPE.allocate();
		event_shape::SHAPE.set_u64(&mut row, event_shape::ID, event_id);
		event_shape::SHAPE.set_u64(&mut row, event_shape::MIGRATION_ID, migration.id);
		event_shape::SHAPE.set_u8(
			&mut row,
			event_shape::ACTION,
			match action {
				MigrationAction::Applied => 0,
				MigrationAction::Rollback => 1,
			},
		);

		txn.set(&MigrationEventKey::encoded(event_id), row)?;

		Ok(MigrationEvent {
			id: event_id,
			migration_id: migration.id,
			action,
		})
	}
}