// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

//! Tests for the `derive_dialect!` macro.

use sqlparser::ast::{
    BinaryOperator, Expr, FunctionArg, FunctionArgExpr, FunctionArguments, LambdaSyntax, Statement,
};
use sqlparser::derive_dialect;
use sqlparser::dialect::{Dialect, GenericDialect, MySqlDialect, PostgreSqlDialect};
use sqlparser::parser::Parser;
use sqlparser::test_utils::{expr_from_projection, only};

#[test]
fn test_method_overrides() {
    derive_dialect!(EnhancedGenericDialect, GenericDialect, overrides = {
        supports_order_by_all = true,
        supports_triple_quoted_string = true,
    });
    let dialect = EnhancedGenericDialect::new();

    // Overridden methods
    assert!(dialect.supports_order_by_all());
    assert!(dialect.supports_triple_quoted_string());

    // Non-overridden retains base behavior
    assert!(!dialect.supports_factorial_operator());

    // Parsing works with the overrides
    let result = Parser::new(&dialect)
        .try_with_sql("SELECT '''value''' FROM t ORDER BY ALL")
        .unwrap()
        .parse_statements();

    assert!(result.is_ok());
}

#[test]
fn test_preserve_type_id() {
    // Check the override works and the parser recognizes it as the base type
    derive_dialect!(
        PreservedTypeDialect,
        GenericDialect,
        preserve_type_id = true,
        overrides = { supports_order_by_all = true }
    );
    let dialect = PreservedTypeDialect::new();
    let d: &dyn Dialect = &dialect;

    assert!(dialect.supports_order_by_all());
    assert!(d.is::<GenericDialect>());
}

#[test]
fn test_different_base_dialects() {
    derive_dialect!(
        EnhancedMySqlDialect,
        MySqlDialect,
        overrides = { supports_order_by_all = true }
    );
    derive_dialect!(UniquePostgreSqlDialect, PostgreSqlDialect);

    let pg = UniquePostgreSqlDialect::new();
    let mysql = EnhancedMySqlDialect::new();

    // Inherit different base behaviors
    assert!(pg.supports_filter_during_aggregation()); // PostgreSQL feature
    assert!(mysql.supports_string_literal_backslash_escape()); // MySQL feature
    assert!(mysql.supports_order_by_all()); // Override

    // Each has unique TypeId
    let pg_ref: &dyn Dialect = &pg;
    let mysql_ref: &dyn Dialect = &mysql;
    assert!(pg_ref.is::<UniquePostgreSqlDialect>());
    assert!(!pg_ref.is::<PostgreSqlDialect>());
    assert!(mysql_ref.is::<EnhancedMySqlDialect>());
}

#[test]
fn test_identifier_quote_style_overrides() {
    derive_dialect!(
        BacktickGenericDialect,
        GenericDialect,
        overrides = { identifier_quote_style = '`' }
    );
    derive_dialect!(
        AnotherBacktickDialect,
        GenericDialect,
        overrides = { identifier_quote_style = '[' }
    );
    derive_dialect!(
        QuotelessPostgreSqlDialect,
        PostgreSqlDialect,
        preserve_type_id = true,
        overrides = { identifier_quote_style = None }
    );

    // Char literal (auto-wrapped in Some)
    assert_eq!(
        BacktickGenericDialect::new().identifier_quote_style("x"),
        Some('`')
    );
    // Another char literal
    assert_eq!(
        AnotherBacktickDialect::new().identifier_quote_style("x"),
        Some('[')
    );
    // None (overrides PostgreSQL's default '"')
    assert_eq!(
        QuotelessPostgreSqlDialect::new().identifier_quote_style("x"),
        None
    );
}

#[test]
fn test_lambda_keyword_syntax_with_json_arrow_operator() {
    // A custom dialect can opt into the `LAMBDA` keyword spelling of lambda
    // functions without giving up `->` as JSON member access. The two meet in
    // a single expression below: a lambda whose body is a JSON access.
    //
    // PostgreSqlDialect is used only as a convenient base that already gives
    // `->` its JSON meaning; nothing here is specific to PostgreSQL.
    derive_dialect!(
        LambdaPostgreSqlDialect,
        PostgreSqlDialect,
        overrides = { supports_lambda_keyword_syntax = true }
    );
    let dialect = LambdaPostgreSqlDialect::new();

    // Only the keyword spelling is enabled; the arrow spelling stays off.
    assert!(dialect.supports_lambda_keyword_syntax());
    assert!(!dialect.supports_lambda_functions());

    let sql = "SELECT transform(xs, lambda x : (x -> 'a')::INT + 1)";
    let ast = Parser::parse_sql(&dialect, sql).unwrap();
    assert_eq!(sql, ast[0].to_string());

    // Round-tripping alone would not distinguish a JSON access from a nested
    // lambda, since both print as `x -> 'a'`, so check the parsed shape.
    let Statement::Query(query) = &ast[0] else {
        panic!("unexpected statement {}", ast[0]);
    };
    let Expr::Function(func) =
        expr_from_projection(only(&query.body.as_select().unwrap().projection))
    else {
        panic!("expected a function call");
    };
    let FunctionArguments::List(args) = &func.args else {
        panic!("expected an argument list");
    };
    let [_, FunctionArg::Unnamed(FunctionArgExpr::Expr(Expr::Lambda(lambda)))] = &args.args[..]
    else {
        panic!("expected the second argument to be a lambda");
    };

    // The lambda came from the `LAMBDA` keyword, not from `->`.
    assert_eq!(LambdaSyntax::LambdaKeyword, lambda.syntax);

    // And the `->` in its body is still JSON member access.
    let Expr::BinaryOp {
        left,
        op: BinaryOperator::Plus,
        ..
    } = lambda.body.as_ref()
    else {
        panic!("expected the lambda body to be an addition");
    };
    let Expr::Cast { expr, .. } = left.as_ref() else {
        panic!("expected the left operand to be a cast");
    };
    let Expr::Nested(json_access) = expr.as_ref() else {
        panic!("expected the cast operand to be parenthesized");
    };
    let Expr::BinaryOp { op, .. } = json_access.as_ref() else {
        panic!("expected `->` to stay a binary operator");
    };
    assert_eq!(&BinaryOperator::Arrow, op);
}
