pg2any_lib 0.11.0

PostgreSQL to Any database library with Change Data Capture (CDC) and logical replication support
Documentation
#[cfg(feature = "sqlserver")]
mod sqlserver_bulk_insert {
    use pg2any_lib::destinations::bulk_insert::{
        build_multi_value_insert, detect_bulk_insert_batch,
    };

    #[test]
    fn test_detect_bracket_quoted_inserts() {
        let stmts = vec![
            "INSERT INTO [dbo].[users] ([id], [name]) VALUES (1, 'alice');".to_string(),
            "INSERT INTO [dbo].[users] ([id], [name]) VALUES (2, 'bob');".to_string(),
            "INSERT INTO [dbo].[users] ([id], [name]) VALUES (3, 'carol');".to_string(),
        ];
        let result = detect_bulk_insert_batch(&stmts);
        assert!(
            result.is_some(),
            "Should detect bracket-quoted INSERT batch"
        );
        let parsed = result.unwrap();
        assert_eq!(parsed.table, "[dbo].[users]");
        assert_eq!(parsed.columns, vec!["[id]", "[name]"]);
        assert_eq!(parsed.rows.len(), 3);
        assert_eq!(parsed.rows[0], vec!["1", "'alice'"]);
    }

    #[test]
    fn test_detect_bracket_quoted_large_batch() {
        let stmts: Vec<String> = (0..500)
            .map(|i| {
                format!(
                    "INSERT INTO [cdc_db].[dbo].[orders] ([id], [amount], [status]) VALUES ({}, {}.50, 'pending');",
                    i, i
                )
            })
            .collect();

        let result = detect_bulk_insert_batch(&stmts);
        assert!(result.is_some());
        let parsed = result.unwrap();
        assert_eq!(parsed.table, "[cdc_db].[dbo].[orders]");
        assert_eq!(parsed.columns.len(), 3);
        assert_eq!(parsed.rows.len(), 500);
    }

    #[test]
    fn test_detect_mixed_tables_returns_none() {
        let stmts = vec![
            "INSERT INTO [dbo].[t1] ([id]) VALUES (1);".to_string(),
            "INSERT INTO [dbo].[t2] ([id]) VALUES (2);".to_string(),
        ];
        let result = detect_bulk_insert_batch(&stmts);
        assert!(result.is_none());
    }

    #[test]
    fn test_build_multi_value_insert_brackets() {
        let table = "[dbo].[users]";
        let columns = vec!["[id]".to_string(), "[name]".to_string()];
        let rows = vec![
            vec!["1".to_string(), "'alice'".to_string()],
            vec!["2".to_string(), "'bob'".to_string()],
        ];
        let sql = build_multi_value_insert(table, &columns, &rows);
        assert_eq!(
            sql,
            "INSERT INTO [dbo].[users] ([id], [name]) VALUES (1, 'alice'), (2, 'bob');"
        );
    }

    #[test]
    fn test_null_values_in_batch() {
        let stmts = vec![
            "INSERT INTO [dbo].[t] ([id], [name], [age]) VALUES (1, NULL, 25);".to_string(),
            "INSERT INTO [dbo].[t] ([id], [name], [age]) VALUES (2, 'bob', NULL);".to_string(),
        ];
        let result = detect_bulk_insert_batch(&stmts);
        assert!(result.is_some());
        let parsed = result.unwrap();
        assert_eq!(parsed.rows[0], vec!["1", "NULL", "25"]);
        assert_eq!(parsed.rows[1], vec!["2", "'bob'", "NULL"]);
    }

    #[test]
    fn test_string_with_special_characters() {
        let stmts = vec![
            "INSERT INTO [dbo].[t] ([id], [val]) VALUES (1, 'it''s a test');".to_string(),
            "INSERT INTO [dbo].[t] ([id], [val]) VALUES (2, 'hello, world');".to_string(),
        ];
        let result = detect_bulk_insert_batch(&stmts);
        assert!(result.is_some());
        let parsed = result.unwrap();
        assert_eq!(parsed.rows[0][1], "'it''s a test'");
        assert_eq!(parsed.rows[1][1], "'hello, world'");
    }

    #[test]
    fn test_multi_value_insert_with_nulls() {
        let table = "[dbo].[users]";
        let columns = vec![
            "[id]".to_string(),
            "[name]".to_string(),
            "[age]".to_string(),
        ];
        let rows = vec![
            vec!["1".to_string(), "'alice'".to_string(), "30".to_string()],
            vec!["2".to_string(), "NULL".to_string(), "25".to_string()],
        ];
        let sql = build_multi_value_insert(table, &columns, &rows);
        assert_eq!(
            sql,
            "INSERT INTO [dbo].[users] ([id], [name], [age]) VALUES (1, 'alice', 30), (2, NULL, 25);"
        );
    }

    #[test]
    fn test_three_part_table_name() {
        let stmts = vec![
            "INSERT INTO [mydb].[dbo].[orders] ([id], [total]) VALUES (1, 99.99);".to_string(),
            "INSERT INTO [mydb].[dbo].[orders] ([id], [total]) VALUES (2, 150.00);".to_string(),
        ];
        let result = detect_bulk_insert_batch(&stmts);
        assert!(result.is_some());
        let parsed = result.unwrap();
        assert_eq!(parsed.table, "[mydb].[dbo].[orders]");
    }

    #[test]
    fn test_large_batch_performance() {
        let stmts: Vec<String> = (0..2000)
            .map(|i| {
                format!(
                    "INSERT INTO [dbo].[perf_test] ([id], [value], [label]) VALUES ({}, {}.5, 'item_{}');",
                    i, i, i
                )
            })
            .collect();

        let result = detect_bulk_insert_batch(&stmts);
        assert!(result.is_some());
        let parsed = result.unwrap();
        assert_eq!(parsed.rows.len(), 2000);
    }

    #[test]
    fn test_non_insert_statements_return_none() {
        let stmts = vec!["UPDATE [dbo].[t] SET [name] = 'new' WHERE [id] = 1;".to_string()];
        let result = detect_bulk_insert_batch(&stmts);
        assert!(result.is_none());
    }

    #[test]
    fn test_empty_batch() {
        let stmts: Vec<String> = vec![];
        let result = detect_bulk_insert_batch(&stmts);
        assert!(result.is_none());
    }
}