<?php

/**
 * This file is part of the Propel package.
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @license    MIT License
 */

require_once dirname(__FILE__) . '/PlatformMigrationTestProvider.php';
require_once dirname(__FILE__) . '/../../../../generator/lib/platform/PgsqlPlatform.php';
require_once dirname(__FILE__) . '/../../../../generator/lib/model/Column.php';
require_once dirname(__FILE__) . '/../../../../generator/lib/model/VendorInfo.php';

/**
 *
 * @package    generator.platform
 */
class PgsqlPlatformMigrationTest extends PlatformMigrationTestProvider
{

    /**
     * Get the Platform object for this class
     *
     * @return Platform
     */
    protected function getPlatform()
    {
        return new PgsqlPlatform();
    }

    /**
     * @dataProvider providerForTestGetModifyDatabaseDDL
     */
    public function testGetModifyDatabaseDDL($databaseDiff)
    {
        $expected = <<<END

DROP TABLE IF EXISTS "foo1" CASCADE;

ALTER TABLE "foo3" RENAME TO "foo4";

CREATE TABLE "foo5"
(
    "id" serial NOT NULL,
    "lkdjfsh" INTEGER,
    "dfgdsgf" TEXT,
    PRIMARY KEY ("id")
);

ALTER TABLE "foo2" RENAME COLUMN "bar" TO "bar1";

ALTER TABLE "foo2" ALTER COLUMN "baz" DROP NOT NULL;

ALTER TABLE "foo2" ADD "baz3" TEXT;

END;
        $this->assertEquals($expected, $this->getPlatform()->getModifyDatabaseDDL($databaseDiff));
    }

    /**
     * @dataProvider providerForTestGetRenameTableDDL
     */
    public function testGetRenameTableDDL($fromName, $toName)
    {
        $expected = '
ALTER TABLE "foo1" RENAME TO "foo2";
';
        $this->assertEquals($expected, $this->getPlatform()->getRenameTableDDL($fromName, $toName));
    }

    /**
     * @dataProvider providerForTestGetModifyTableDDL
     */
    public function testGetModifyTableDDL($tableDiff)
    {
        $expected = <<<END

ALTER TABLE "foo" DROP CONSTRAINT "foo1_FK_2";

ALTER TABLE "foo" DROP CONSTRAINT "foo1_FK_1";

DROP INDEX "bar_baz_FK";

DROP INDEX "bar_FK";

ALTER TABLE "foo" RENAME COLUMN "bar" TO "bar1";

ALTER TABLE "foo" ALTER COLUMN "baz" DROP NOT NULL;

ALTER TABLE "foo" ADD "baz3" TEXT;

CREATE INDEX "bar_FK" ON "foo" ("bar1");

CREATE INDEX "baz_FK" ON "foo" ("baz3");

ALTER TABLE "foo" ADD CONSTRAINT "foo1_FK_1"
    FOREIGN KEY ("bar1")
    REFERENCES "foo2" ("bar");

END;
        $this->assertEquals($expected, $this->getPlatform()->getModifyTableDDL($tableDiff));
    }

    /**
     * @dataProvider providerForTestGetModifyTableColumnsDDL
     */
    public function testGetModifyTableColumnsDDL($tableDiff)
    {
        $expected = <<<END

ALTER TABLE "foo" RENAME COLUMN "bar" TO "bar1";

ALTER TABLE "foo" ALTER COLUMN "baz" DROP NOT NULL;

ALTER TABLE "foo" ADD "baz3" TEXT;

END;
        $this->assertEquals($expected, $this->getPlatform()->getModifyTableColumnsDDL($tableDiff));
    }

    /**
     * @dataProvider providerForTestGetModifyTablePrimaryKeysDDL
     */
    public function testGetModifyTablePrimaryKeysDDL($tableDiff)
    {
        $expected = <<<END

ALTER TABLE "foo" DROP CONSTRAINT "foo_pkey";

ALTER TABLE "foo" ADD PRIMARY KEY ("id","bar");

END;
        $this->assertEquals($expected, $this->getPlatform()->getModifyTablePrimaryKeyDDL($tableDiff));
    }

    /**
     * @dataProvider providerForTestGetModifyTableIndicesDDL
     */
    public function testGetModifyTableIndicesDDL($tableDiff)
    {
        $expected = <<<END

DROP INDEX "bar_FK";

CREATE INDEX "baz_FK" ON "foo" ("baz");

DROP INDEX "bar_baz_FK";

CREATE INDEX "bar_baz_FK" ON "foo" ("id","bar","baz");

END;
        $this->assertEquals($expected, $this->getPlatform()->getModifyTableIndicesDDL($tableDiff));
    }

    /**
     * @dataProvider providerForTestGetModifyTableForeignKeysDDL
     */
    public function testGetModifyTableForeignKeysDDL($tableDiff)
    {
        $expected = <<<END

ALTER TABLE "foo1" DROP CONSTRAINT "foo1_FK_1";

ALTER TABLE "foo1" ADD CONSTRAINT "foo1_FK_5"
    FOREIGN KEY ("baz")
    REFERENCES "foo2" ("baz");

ALTER TABLE "foo1" DROP CONSTRAINT "foo1_FK_2";

ALTER TABLE "foo1" ADD CONSTRAINT "foo1_FK_2"
    FOREIGN KEY ("bar","id")
    REFERENCES "foo2" ("bar","id");

END;
        $this->assertEquals($expected, $this->getPlatform()->getModifyTableForeignKeysDDL($tableDiff));
    }

    /**
     * @dataProvider providerForTestGetModifyTableForeignKeysSkipSqlDDL
     */
    public function testGetModifyTableForeignKeysSkipSqlDDL($tableDiff)
    {
        $expected = <<<END

ALTER TABLE "foo1" DROP CONSTRAINT "foo1_FK_1";

END;
        $this->assertEquals($expected, $this->getPlatform()->getModifyTableForeignKeysDDL($tableDiff));
        $expected = <<<END

ALTER TABLE "foo1" ADD CONSTRAINT "foo1_FK_1"
    FOREIGN KEY ("bar")
    REFERENCES "foo2" ("bar");

END;
        $this->assertEquals($expected, $this->getPlatform()->getModifyTableForeignKeysDDL($tableDiff->getReverseDiff()));
    }

    /**
     * @dataProvider providerForTestGetModifyTableForeignKeysSkipSql2DDL
     */
    public function testGetModifyTableForeignKeysSkipSql2DDL($tableDiff)
    {
        $expected = '';
        $this->assertEquals($expected, $this->getPlatform()->getModifyTableForeignKeysDDL($tableDiff));
        $expected = '';
        $this->assertEquals($expected, $this->getPlatform()->getModifyTableForeignKeysDDL($tableDiff->getReverseDiff()));
    }

    /**
     * @dataProvider providerForTestGetRemoveColumnDDL
     */
    public function testGetRemoveColumnDDL($column)
    {
        $expected = '
ALTER TABLE "foo" DROP COLUMN "bar";
';
        $this->assertEquals($expected, $this->getPlatform()->getRemoveColumnDDL($column));
    }

    /**
     * @dataProvider providerForTestGetRenameColumnDDL
     */
    public function testGetRenameColumnDDL($fromColumn, $toColumn)
    {
        $expected = '
ALTER TABLE "foo" RENAME COLUMN "bar1" TO "bar2";
';
        $this->assertEquals($expected, $this->getPlatform()->getRenameColumnDDL($fromColumn, $toColumn));
    }

    /**
     * @dataProvider providerForTestGetModifyColumnDDL
     */
    public function testGetModifyColumnDDL($columnDiff)
    {
        $expected = '
ALTER TABLE "foo" ALTER COLUMN "bar" TYPE DOUBLE PRECISION;
';
        $this->assertEquals($expected, $this->getPlatform()->getModifyColumnDDL($columnDiff));
    }

    public function testGetModifyColumnDDLWithChangedTypeAndDefault()
    {
        $t1 = new Table('foo');
        $c1 = new Column('bar');
        $c1->getDomain()->copy($this->getPlatform()->getDomainForType('DOUBLE'));
        $c1->getDomain()->replaceSize(2);
        $t1->addColumn($c1);
        $t2 = new Table('foo');
        $c2 = new Column('bar');
        $c2->getDomain()->copy($this->getPlatform()->getDomainForType('DOUBLE'));
        $c2->getDomain()->replaceSize(3);
        $c2->getDomain()->setDefaultValue(new ColumnDefaultValue(-100, ColumnDefaultValue::TYPE_VALUE));
        $t2->addColumn($c2);
        $columnDiff = PropelColumnComparator::computeDiff($c1, $c2);
        $expected = <<<END

ALTER TABLE "foo" ALTER COLUMN "bar" TYPE DOUBLE PRECISION;

ALTER TABLE "foo" ALTER COLUMN "bar" SET DEFAULT -100;

END;
        $this->assertEquals($expected, $this->getPlatform()->getModifyColumnDDL($columnDiff));
    }

    /**
     * @dataProvider providerForTestGetModifyColumnsDDL
     */
    public function testGetModifyColumnsDDL($columnDiffs)
    {
        $expected = <<<END

ALTER TABLE "foo" ALTER COLUMN "bar1" TYPE DOUBLE PRECISION;

ALTER TABLE "foo" ALTER COLUMN "bar2" SET NOT NULL;

END;
        $this->assertEquals($expected, $this->getPlatform()->getModifyColumnsDDL($columnDiffs));
    }

    /**
     * @dataProvider providerForTestGetAddColumnDDL
     */
    public function testGetAddColumnDDL($column)
    {
        $expected = '
ALTER TABLE "foo" ADD "bar" INTEGER;
';
        $this->assertEquals($expected, $this->getPlatform()->getAddColumnDDL($column));
    }

    /**
     * @dataProvider providerForTestGetAddColumnsDDL
     */
    public function testGetAddColumnsDDL($columns)
    {
        $expected = <<<END

ALTER TABLE "foo" ADD "bar1" INTEGER;

ALTER TABLE "foo" ADD "bar2" DOUBLE PRECISION DEFAULT -1 NOT NULL;

END;
        $this->assertEquals($expected, $this->getPlatform()->getAddColumnsDDL($columns));
    }

    public function testGetModifyColumnDDLWithVarcharWithoutSize()
    {
        $t1 = new Table('foo');
        $c1 = new Column('bar');
        $c1->setTable($t1);
        $c1->getDomain()->copy($this->getPlatform()->getDomainForType('VARCHAR'));
        $c1->getDomain()->replaceSize(null);
        $c1->getDomain()->replaceScale(null);
        $t1->addColumn($c1);

        $schema = <<<EOF
<database name="test">
    <table name="foo">
        <column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" />
        <column name="bar" type="VARCHAR" />
    </table>
</database>
EOF;

        $table = $this->getDatabaseFromSchema($schema)->getTable('foo');
        $c2 = $table->getColumn('bar');
        $columnDiff = PropelColumnComparator::computeDiff($c1, $c2);
        $expected = false;
        $this->assertSame($expected, $columnDiff);
    }

public function testGetModifyColumnDDLWithVarcharWithoutSizeAndPlatform()
    {
        $t1 = new Table('foo');
        $c1 = new Column('bar');
        $c1->setTable($t1);
        $c1->getDomain()->copy($this->getPlatform()->getDomainForType('VARCHAR'));
        $c1->getDomain()->replaceSize(null);
        $c1->getDomain()->replaceScale(null);
        $t1->addColumn($c1);

        $schema = <<<EOF
<database name="test">
    <table name="foo">
        <column name="id" primaryKey="true" type="INTEGER" autoIncrement="true" />
        <column name="bar"/>
    </table>
</database>
EOF;

        $xtad = new XmlToAppData(null);
        $appData = $xtad->parseString($schema);
        $db = $appData->getDatabase();
        $table = $db->getTable('foo');
        $c2 = $table->getColumn('bar');
        $columnDiff = PropelColumnComparator::computeDiff($c1, $c2);
        $expected = false;
        $this->assertSame($expected, $columnDiff);
    }

    /**
     * @dataProvider providerForTestGetModifyColumnRemoveDefaultValueDDL
     */
    public function testGetModifyColumnRemoveDefaultValueDDL($columnDiffs)
    {
        $expected = <<<EOF

ALTER TABLE "test" ALTER COLUMN "test" DROP DEFAULT;

EOF;
        $this->assertEquals($expected, $this->getPlatform()->getModifyColumnDDL($columnDiffs));
    }

    /**
     * @dataProvider providerForTestGetModifyTableForeignKeysSkipSql3DDL
     */
    public function testGetModifyTableForeignKeysSkipSql3DDL($databaseDiff)
    {
        $this->assertFalse($databaseDiff);
    }

    /**
     * @dataProvider providerForTestGetModifyTableForeignKeysSkipSql4DDL
     */
    public function testGetModifyTableForeignKeysSkipSql4DDL($databaseDiff)
    {
        $this->assertFalse($databaseDiff);
    }

}
