#!/usr/bin/env qore
# -*- mode: qore; indent-tabs-mode: nil -*-

%new-style
%enable-all-warnings
%require-types
%strict-args

%requires ../../../../qlib/Util.qm
%requires ../../../../qlib/Logger.qm
%requires ../../../../qlib/DataProvider
%requires ../../../../qlib/SqlUtil
%requires ../../../../qlib/MysqlSqlUtil.qm

%requires ./SqlUtilTestBase.qm

%try-module mysql
%define NoMysql
%endtry

%exec-class MysqlTest

class MysqlTestSchema inherits SqlUtilTestSchema {
    public {
        const SchemaName = "MysqlTestSchema";
        const SchemaVersion = "1.0";
    }

    private {
        const GenericOptions = (
            "replace": True,
        );

        const IndexOptions = {};

        const ColumnOptions = {};

        const T_MysqlTest = (
            "columns": (
                "id": c_number(14, True, "an example comment with 'quotes'"),
                "id_": c_number(14, True),
                "null_f": c_varchar(69),
                "blob_f": c_blob(True),
                "clob_f": c_clob(True),
            ),
            "primary_key": ("name": "pk_mysql_test", "columns": ("id")),
        );

        const Tables = (
            "mysql_test": T_MysqlTest,
        );
    }

    constructor(AbstractDatasource ds, *string dts, *string its) : SqlUtilTestSchema(ds, dts, its) {
    }

    private string getNameImpl() {
        return SchemaName;
    }

    private string getVersionImpl() {
        return SchemaVersion;
    }

    private *hash getTablesImpl() {
        return doTables(Tables, MysqlTest::CustomColumns);
    }

    private *hash getIndexOptionsImpl() {
        return IndexOptions;
    }

    private *hash getGenericOptionsImpl() {
        return GenericOptions;
    }

    private *hash getColumnOptionsImpl() {
        return ColumnOptions;
    }
}

class MysqlTestAutoIncrementNegativeSchema inherits AbstractSchema {
    constructor(AbstractDatasource ds, *string dts, *string its)
        : AbstractSchema(ds, dts, its) {
    }

    string getNameImpl() { return "MysqlTestAutoIncrementNegativeSchema"; }
    string getVersionImpl() { return "1.0"; }

    private *hash getTablesImpl() {
        return {
            "mysql_test_auto_increment" : {
                "columns": {
                    "id": c_number(14, C_NOT_NULL) + { "auto_increment" : True, },
                },
                "primary_key" : { "name" : "pk_mysql_test_auto_increment", "columns" : "id" },
            },
        };
    }
}

class MysqlTestAutoIncrementPositiveSchema inherits AbstractSchema {

    constructor(AbstractDatasource ds, *string dts, *string its)
        : AbstractSchema(ds, dts, its)
    {
    }

    string getNameImpl() { return "MysqlTestAutoIncrementPositiveSchema"; }
    string getVersionImpl() { return "1.0"; }

    private *hash getTablesImpl() {
        return {
            "mysql_test_auto_increment" : {
                "columns": {
                    "id": c_int(C_NOT_NULL) + { "auto_increment" : True, },
                },
                "primary_key" : { "name" : "pk_mysql_test_auto_increment", "columns" : "id" },
            },
        };
    }
}

class MysqlTest inherits SqlTestBase {
    public {
        const CustomColumns = (
            "varchar": (
                "value": "hello",
                "size": "20",
            ),
            "char": (
                "value": "hello",
                "size": "20",
            ),
            "decimal": (
                "size": 15,
                "scale": 2,
                "value": 400.95n,
            ),
            "decimal_def": (
                "type": "decimal",
                "value": 401,
            ),

            "tinyint": 10,
            "smallint": 512,
            "mediumint": 192932,
            "int": 49349839,
            "bigint": 34839203948394,
            "float": 1.5,
            "double": 3.1415927,

            "date": 2016-02-11,
            "datetime": 2016-02-11T09:26:14,
            "timestamp": 2016-02-11T09:26:14,
            "time": 09:26:52,
            "year": 2016, # XXX: this is likely just an integer

            "binary": (
                "value": <bead>,
                "size": 2, # must be 2 as default is 1
            ),
            "varbinary": (
                "value": <bead>,
                "size": 10,
            ),

            "tinyblob": <bead>,
            "blob": <bead>,
            "mediumblob": <bead>,
            # temporarily disabled due to a bug on rhel7 handling logblob columns with mariadb
            #"longblob": <bead>,

            "tinytext": "test",
            "mediumtext": "test",
            # temporarily disabled due to a bug on rhel7 handling logtext columns with mariadb
            #"longtext": "test",

            #"bit": 100,
        );
    }

    constructor() : SqlTestBase("MysqlTest", "1.0", \ARGV, MyOpts) {
        Datasource ds;
        try {
            ds = getDatasource();
        } catch (hash ex) {
            if (m_options.verbose)
                printf("%s: %s\n", ex.err, ex.desc);
            # skip tests if we can't create the datasource
        }

        if (ds) {
            initTestData(CustomColumns);

            { # Make sure the DB is clear before doing the tests.
                MysqlTable t = new MysqlTable(ds, "mysql_test");
                if (t.checkExistence())
                    t.dropCommit();
            }

            # create the test schema
            schema = new MysqlTestSchema(ds);

            schema.align(False, m_options.verbose, m_options.verbose > 0);

            # get table object
            table = (new Table(schema.getDatasource(), "mysql_test")).getTable();

            # this feature can be enabled for MariaDB >= 10.2. Let's hope it will be recived in MySQL too
            # addTestCase("analytic/window functions", \testAnalyticFunctions());

            addTestCase("test create table with auto increment - negative", \testCreateTableWithAutoIncrementNegative());
            addTestCase("test create table with auto increment - positive", \testCreateTableWithAutoIncrementPositive());
        }

        set_return_value(main());
    }

    private string getResultSetSql() {
        testSkip("does not support result set output binds");
        return "";
    }

    private testCreateTableWithAutoIncrementNegative() {
        MysqlTestAutoIncrementNegativeSchema schema(table.getDatasource());
        assertThrows("MYSQL-COLUMN-ERROR",
                     "AUTO_INCREMENT can be used only with a subset of types",
                     sub() { schema.align(False, m_options.verbose, m_options.verbose > 0); });
    }

    private testCreateTableWithAutoIncrementPositive() {
        MysqlTestAutoIncrementPositiveSchema schema(table.getDatasource());
        schema.align(False, m_options.verbose, m_options.verbose > 0);
        assertEq(True, True, "schema alignment works");
    }

    private usageIntern() {
        TestReporter::usageIntern(OptionColumn);
        printOption("-c,--conn=ARG", "set DB connection argument (ex: \"mysql:user/pass@db\")", OptionColumn);
    }

    Datasource getDatasource() {
        if (!m_options.connstr)
            m_options.connstr = ENV.QORE_DB_CONNSTR_MYSQL;
        Datasource ds(m_options.connstr);
        if (ds.getDriverName() != "mysql")
            throw "MYSQL-ERROR", sprintf("cannot execute the mysql tests on a connection using driver %y", ds.getDriverName());
        ds.open();
        return ds;
    }
}
