Commit 0ff47cca authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

1ere version du FunctionGenerator.

parent 2e4526a1
Loading
Loading
Loading
Loading
+210 −0
Original line number Diff line number Diff line
<?php

namespace UnicaenDbImport\CodeGenerator\PostgreSQL;

class FunctionGenerator
{
    /**
     * FunctionGenerator constructor.
     */
    public function __construct()
    {

    }

    public function generateFunctionSignature($destinTable, $sourceCodeColumn, array $columns)
    {
        $res = '';
        $res .= 'CREATE OR REPLACE FUNCTION register_for_import_' . $destinTable . '(' . PHP_EOL;
        $res .= $this->generateFunctionArgsList($sourceCodeColumn, $columns) . PHP_EOL;
        $res .= ') RETURNS TEXT AS';

        return $res;
    }

    public function generateFunctionArgsList($sourceCodeColumn, array $columns)
    {
        $sourceCols = array_merge([$sourceCodeColumn], $columns);
        $destinCols = array_merge([$sourceCodeColumn], $columns, ['deleted_on']);

        $sourceColsWithTypes = array_map(function ($col) {
            return 'src_' . $col . " varchar";
        }, $sourceCols);
        $destinColsWithTypes = array_map(function ($col) {
            return 'dest_' . $col . " varchar";
        }, $destinCols);

        $res = '';
        $res .= '  ' . implode(', ', $sourceColsWithTypes) . ',' . PHP_EOL;
        $res .= '  ' . implode(', ', $destinColsWithTypes);

        return $res;
    }

    public function generateFunctionBodyBeginning()
    {
        return <<<'EOT'
$Q$
DECLARE
  sql TEXT;
BEGIN
EOT;
    }

    public function generateMetaRequestAffectationForInsertOperation($destinTable, $sourceCodeColumn, $columns)
    {
        $cols = array_merge([$sourceCodeColumn], $columns);
        $destinCols = array_map(function ($col) {
            return 'dest_' . $col;
        }, $columns);

        $res = '';
        $res .= "sql = concat('insert into " . $destinTable . "(" . implode(', ', $cols) . ") values ', '($$', src_code, '$$";
        foreach ($destinCols as $col) {
            $res .= ", $$', " . $col . ", '$$";
        }
        $res .= ")');";

        return $res;
    }

    public function generateMetaRequestAffectationForUpdateOperation($destinTable, $field)
    {
        $res = '';
        $res .= "sql = concat('update $destinTable set $field = $$', src_$field, '$$, updated_on = now() where code = $$', dest_code, '$$ ;');";

        return $res;
    }

    public function generateMetaRequestAffectationForUndeleteOperation($destinTable, $sourceCodeColumn, $columns)
    {
        $res = '';
        $res .= "sql = concat('update $destinTable set ";
        foreach ($columns as $col) {
            $res .= "$col = $$', src_$col, '$$, ";
        }
        $res .= "updated_on = now(), deleted_on = null where code = $$', dest_code, '$$ ;');";

        return $res;
    }

    public function generateMetaRequestAffectationForDeleteOperation($destinTable)
    {
        $res = '';
        $res .= "sql = concat('update $destinTable set deleted_on = now() where code = $$', dest_code, '$$ ;');";

        return $res;
    }

    public function generateInsertIntoImportRegisterTableForInsertOperation($destinTable)
    {
        $res = '';
        $res .= "insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('insert', '$destinTable', '*', null, null, sql, now());";

        return $res;
    }

    public function generateInsertIntoImportRegisterTableForUpdateOperation($destinTable, $field)
    {
        $res = '';
        $res .= "insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('update', '$destinTable', '$field', src_$field, dest_$field, sql, now());";

        return $res;
    }

    public function generateInsertIntoImportRegisterTableForUndeleteOperation($destinTable)
    {
        $res = '';
        $res .= "insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('undelete', '$destinTable', '*', null, null, sql, now());";

        return $res;
    }

    public function generateInsertIntoImportRegisterTableForDeleteOperation($destinTable)
    {
        $res = '';
        $res .= "insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('delete', '$destinTable', '*', null, null, sql, now());";

        return $res;
    }

    public function generateFunctionBodyEnding()
    {
        return <<<'EOT'
END; $Q$
LANGUAGE plpgsql;
EOT;
    }

    public function generateBodyInnerMarkup($destinTable, $sourceCodeColumn, array $columns)
    {
        $insertOperationTemplate = <<<EOT
  IF (src_code IS NOT NULL AND dest_code IS NULL) THEN
    %s
    %s
  END IF;
EOT;
        $insertOperationMarkup = sprintf($insertOperationTemplate,
            $this->generateMetaRequestAffectationForInsertOperation($destinTable, $sourceCodeColumn, $columns),
            $this->generateInsertIntoImportRegisterTableForInsertOperation($destinTable)
        );


        $updateOperationMarkup = '';
        foreach ($columns as $col) {
            $template = <<<EOT
    IF (src_$col <> dest_$col) THEN
      %s
      %s
    END IF;
EOT;
            $updateOperationMarkup .= sprintf($template,
                $this->generateMetaRequestAffectationForUpdateOperation($destinTable, $col),
                $this->generateInsertIntoImportRegisterTableForUpdateOperation($destinTable, $col)
            );
            $updateOperationMarkup .= PHP_EOL;
        }
        $updateOperationMarkup = <<<EOT
  IF (src_code IS NOT NULL AND dest_code IS NOT NULL and dest_deleted_on IS NULL) THEN
$updateOperationMarkup
  END IF;
EOT;

        $undeleteOperationTemplate = <<<EOT
  IF (src_code IS NOT NULL AND dest_code IS NOT NULL and dest_deleted_on IS NOT NULL) THEN
    %s
    %s
  END IF;
EOT;
        $undeleteOperationMarkup = sprintf($undeleteOperationTemplate,
            $this->generateMetaRequestAffectationForUndeleteOperation($destinTable, $sourceCodeColumn, $columns),
            $this->generateInsertIntoImportRegisterTableForUndeleteOperation($destinTable)
        );

        $deleteOperationTemplate = <<<EOT
  IF (src_code IS NULL AND dest_code IS NOT NULL and dest_deleted_on IS NULL) THEN
    %s
    %s
  END IF;
EOT;
        $deleteOperationMarkup = sprintf($deleteOperationTemplate,
            $this->generateMetaRequestAffectationForDeleteOperation($destinTable),
            $this->generateInsertIntoImportRegisterTableForDeleteOperation($destinTable)
        );


        $res = <<<EOT
$insertOperationMarkup

$updateOperationMarkup

$undeleteOperationMarkup

$deleteOperationMarkup

  return 'done';
EOT;

        return $res;
    }
}
 No newline at end of file
+170 −0
Original line number Diff line number Diff line
<?php

namespace UnicaenDbImportUnitTest\CodeGenerator\PostgreSQL;

use UnicaenDbImport\CodeGenerator\PostgreSQL\FunctionGenerator;

class FunctionGeneratorTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @var FunctionGenerator
     */
    private $generator;

    protected function setUp()
    {
        $this->generator = new FunctionGenerator();
    }

    public function test_can_generate()
    {
        $res = $this->generator->generateFunctionArgsList('code', ['libelle', 'debut_validite']);

        self::assertEquals(<<<EOT
  src_code varchar, src_libelle varchar, src_debut_validite varchar,
  dest_code varchar, dest_libelle varchar, dest_debut_validite varchar, dest_deleted_on varchar
EOT
            ,
            $res);
    }

    public function test_can_Generate_Function_SIgnature()
    {
        $res = $this->generator->generateFunctionSignature('dest_table', 'code', ['libelle', 'debut_validite']);

        $expected = <<<EOT
CREATE OR REPLACE FUNCTION register_for_import_dest_table(
  src_code varchar, src_libelle varchar, src_debut_validite varchar,
  dest_code varchar, dest_libelle varchar, dest_debut_validite varchar, dest_deleted_on varchar
) RETURNS TEXT AS
EOT;
        self::assertEquals($expected, $res);

    }

    public function test_can_generateMetaRequestAffectationForInsertOperation()
    {
        $res = $this->generator->generateMetaRequestAffectationForInsertOperation('dest_table', 'code', ['libelle', 'debut_validite']);

        $expected = <<<EOT
sql = concat('insert into dest_table(code, libelle, debut_validite) values ', '($$', src_code, '$$, $$', dest_libelle, '$$, $$', dest_debut_validite, '$$)');
EOT;
        self::assertEquals($expected, $res);
    }

    public function test_can_generateMetaRequestAffectationForUpdateOperation()
    {
        $res = $this->generator->generateMetaRequestAffectationForUpdateOperation('dest_table', 'libelle');

        $expected = <<<EOT
sql = concat('update dest_table set libelle = $$', src_libelle, '$$, updated_on = now() where code = $$', dest_code, '$$ ;');
EOT;
        self::assertEquals($expected, $res);
    }

    public function test_can_generateMetaRequestAffectationForUndeleteOperation()
    {
        $res = $this->generator->generateMetaRequestAffectationForUndeleteOperation('dest_table', 'code', ['libelle', 'debut_validite']);

        $expected = <<<EOT
sql = concat('update dest_table set libelle = $$', src_libelle, '$$, debut_validite = $$', src_debut_validite, '$$, updated_on = now(), deleted_on = null where code = $$', dest_code, '$$ ;');
EOT;
        self::assertEquals($expected, $res);
    }

    public function test_can_generateMetaRequestAffectationForDeleteOperation()
    {
        $res = $this->generator->generateMetaRequestAffectationForDeleteOperation('dest_table');

        $expected = <<<EOT
sql = concat('update dest_table set deleted_on = now() where code = $$', dest_code, '$$ ;');
EOT;
        self::assertEquals($expected, $res);
    }

    public function test_can_generateInsertIntoImportRegisterTableForInsertOperation()
    {
        $res = $this->generator->generateInsertIntoImportRegisterTableForInsertOperation('dest_table');

        $expected = <<<EOT
insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('insert', 'dest_table', '*', null, null, sql, now());
EOT;
        self::assertEquals($expected, $res);

    }

    public function test_can_generateInsertIntoImportRegisterTableForUpdateOperation()
    {

        $res = $this->generator->generateInsertIntoImportRegisterTableForUpdateOperation('dest_table', 'libelle');
        $expected = <<<EOT
insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('update', 'dest_table', 'libelle', src_libelle, dest_libelle, sql, now());
EOT;
        self::assertEquals($expected, $res);

        $res = $this->generator->generateInsertIntoImportRegisterTableForUpdateOperation('dest_table', 'debut_validite');
        $expected = <<<EOT
insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('update', 'dest_table', 'debut_validite', src_debut_validite, dest_debut_validite, sql, now());
EOT;
        self::assertEquals($expected, $res);

    }

    public function test_can_generateInsertIntoImportRegisterTableForUndeleteOperation()
    {
        $res = $this->generator->generateInsertIntoImportRegisterTableForUndeleteOperation('dest_table');

        $expected = <<<EOT
insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('undelete', 'dest_table', '*', null, null, sql, now());
EOT;
        self::assertEquals($expected, $res);

    }

    public function test_can_generateInsertIntoImportRegisterTableForDeleteOperation()
    {
        $res = $this->generator->generateInsertIntoImportRegisterTableForDeleteOperation('dest_table');

        $expected = <<<EOT
insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('delete', 'dest_table', '*', null, null, sql, now());
EOT;
        self::assertEquals($expected, $res);
    }

    public function test_can_generateBodyInnerMarkup()
    {
        $res = $this->generator->generateBodyInnerMarkup('dest_table', 'code', ['libelle', 'debut_validite']);

        $expected = <<<EOT
  IF (src_code IS NOT NULL AND dest_code IS NULL) THEN
    sql = concat('insert into dest_table(code, libelle, debut_validite) values ', '($$', src_code, '$$, $$', dest_libelle, '$$, $$', dest_debut_validite, '$$)');
    insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('insert', 'dest_table', '*', null, null, sql, now());
  END IF;

  IF (src_code IS NOT NULL AND dest_code IS NOT NULL and dest_deleted_on IS NULL) THEN
    IF (src_libelle <> dest_libelle) THEN
      sql = concat('update dest_table set libelle = $$', src_libelle, '$$, updated_on = now() where code = $$', dest_code, '$$ ;');
      insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('update', 'dest_table', 'libelle', src_libelle, dest_libelle, sql, now());
    END IF;
    IF (src_debut_validite <> dest_debut_validite) THEN
      sql = concat('update dest_table set debut_validite = $$', src_debut_validite, '$$, updated_on = now() where code = $$', dest_code, '$$ ;');
      insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('update', 'dest_table', 'debut_validite', src_debut_validite, dest_debut_validite, sql, now());
    END IF;

  END IF;

  IF (src_code IS NOT NULL AND dest_code IS NOT NULL and dest_deleted_on IS NOT NULL) THEN
    sql = concat('update dest_table set libelle = $$', src_libelle, '$$, debut_validite = $$', src_debut_validite, '$$, updated_on = now(), deleted_on = null where code = $$', dest_code, '$$ ;');
    insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('undelete', 'dest_table', '*', null, null, sql, now());
  END IF;

  IF (src_code IS NULL AND dest_code IS NOT NULL and dest_deleted_on IS NULL) THEN
    sql = concat('update dest_table set deleted_on = now() where code = $$', dest_code, '$$ ;');
    insert into import_reg(operation, table_name, field_name, from_value, to_value, sql, created_on) values ('delete', 'dest_table', '*', null, null, sql, now());
  END IF;

  return 'done';
EOT;
        self::assertEquals($expected, $res);
    }
}
 No newline at end of file