#!/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/FreetdsSqlUtil.qm

%requires ./SqlUtilTestBase.qm

%exec-class FreetdsTest

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

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

        const IndexOptions = {};

        const ColumnOptions = {};

        const T_SqlUtilTest = (
            "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_sqlutil_test", "columns": ("id")),
        );

        const Tables = (
            "sqlutil_test": T_SqlUtilTest,
        );
    }

    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, FreetdsTest::CustomColumns) + ("test_analytic_functions" : T_TestAnalyticFunctions);
    }

    private *hash getIndexOptionsImpl() {
        return IndexOptions;
    }

    private *hash getGenericOptionsImpl() {
        return GenericOptions;
    }

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

class FreetdsTest 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,
            ),

            "text": "test",

            "tinyint": 8,
            "smallint": 1024,
            "int": 12345,
            "float": 2.5,
            "real": 5.5,

            "date": ("value": 2015-01-01),
            "time": ("value": 12:45,),
            "datetime": 2015-01-01T12:45:00.450,
            "smalldatetime": 2015-01-01T12:45,

            # fake timestamp column for cop_trunc_date
            "timestamp": (
                "type": "datetime",
                "value": 2016-02-11T09:26:14.500,
                # note: The SQL Server datetime type only has a 1/300 ms (~3.33̅ ms) resolution
            ),

            "varbinary": <bead>,

            "image": <bead>,
        );
    }

    constructor() : SqlTestBase("FreetdsTest", "1.0", \ARGV, MyOpts) {
        Datasource ds;
        try {
            ds = getDatasource();
        } catch (hash<ExceptionInfo> 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.
                FreetdsTable t = new FreetdsTable(ds, "sqlutil_test");
                if (t.checkExistence())
                    t.dropCommit();
            }

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

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

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

            addTestCase("analytic/window functions", \testAnalyticFunctions());
        }

        set_return_value(main());
    }

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

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

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