drasi-bootstrap-mysql 0.2.6

MySQL bootstrap provider for Drasi
Documentation
// Copyright 2025 The Drasi Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Configuration types for the MySQL bootstrap provider.
//!
//! Shared types (TableKeyConfig, is_valid_identifier) come from drasi-mysql-common.

pub use drasi_mysql_common::{is_valid_identifier, TableKeyConfig};

/// MySQL bootstrap provider configuration
#[derive(Clone, PartialEq)]
pub struct MySqlBootstrapConfig {
    /// MySQL host
    pub host: String,

    /// MySQL port
    pub port: u16,

    /// Database name
    pub database: String,

    /// Database user
    pub user: String,

    /// Database password
    pub password: String,

    /// Tables to bootstrap
    pub tables: Vec<String>,

    /// Table key configurations
    pub table_keys: Vec<TableKeyConfig>,
}

impl std::fmt::Debug for MySqlBootstrapConfig {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("MySqlBootstrapConfig")
            .field("host", &self.host)
            .field("port", &self.port)
            .field("database", &self.database)
            .field("user", &self.user)
            .field("password", &"[REDACTED]")
            .field("tables", &self.tables)
            .field("table_keys", &self.table_keys)
            .finish()
    }
}

impl MySqlBootstrapConfig {
    /// Validate the configuration and return an error if invalid.
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - Database name is empty
    /// - User is empty
    /// - Port is 0
    /// - Tables list is empty
    /// - Tables contain invalid identifiers
    pub fn validate(&self) -> anyhow::Result<()> {
        if self.database.is_empty() {
            return Err(anyhow::anyhow!(
                "Validation error: database cannot be empty. \
                 Please specify the MySQL database name"
            ));
        }

        if self.user.is_empty() {
            return Err(anyhow::anyhow!(
                "Validation error: user cannot be empty. \
                 Please specify the MySQL user"
            ));
        }

        if self.port == 0 {
            return Err(anyhow::anyhow!(
                "Validation error: port cannot be 0. \
                 Please specify a valid port number (1-65535)"
            ));
        }

        if self.tables.is_empty() {
            return Err(anyhow::anyhow!(
                "Validation error: tables cannot be empty. \
                 Please configure at least one table to bootstrap"
            ));
        }

        for table in &self.tables {
            if !is_valid_identifier(table) {
                return Err(anyhow::anyhow!(
                    "Validation error: table '{table}' contains invalid characters. \
                     Only letters, numbers, and underscores are allowed"
                ));
            }
        }

        Ok(())
    }
}