diff --git a/src/FunctionMigration.php b/src/FunctionMigration.php index 407c2bc..cc41e84 100644 --- a/src/FunctionMigration.php +++ b/src/FunctionMigration.php @@ -35,6 +35,11 @@ final class FunctionMigration */ private $deterministic; + /** + * @var bool + */ + private $readsSqlData; + /** * @var ParameterOperation[] */ @@ -85,6 +90,7 @@ public static function drop(string $name): FunctionMigration * @param string $operation * @param ReturnTypeOperation $returnType * @param bool $deterministic + * @param bool $readsSqlData * @param array $parameterOperations * @param array $variableOperations * @param string|null $body @@ -94,6 +100,7 @@ private function __construct( string $operation, ReturnTypeOperation $returnType = null, bool $deterministic = false, + bool $readsSqlData = false, array $parameterOperations = [], array $variableOperations = [], string $body = null @@ -102,13 +109,14 @@ private function __construct( $this->operation = $operation; $this->returnType = $returnType; $this->deterministic = $deterministic; + $this->readsSqlData = $readsSqlData; $this->parameterOperations = $parameterOperations; $this->variableOperations = $variableOperations; $this->body = $body; } /** - * Pushes a new add parameter operation. + * Sets determinism for the function. * * @param bool $deterministic * @return $this @@ -124,6 +132,23 @@ public function isDeterministic(bool $deterministic): FunctionMigration return $this; } + /** + * Sets the reads sql data property of the function. + * + * @param bool $readsSqlData + * @return $this + */ + public function readsSqlData(bool $readsSqlData): FunctionMigration + { + if ($this->operation === FunctionOperation::DROP) { + throw new LogicException('Cannot set readsSqlData property in a drop migration.'); + } + + $this->readsSqlData = $readsSqlData; + + return $this; + } + /** * Sets the return type of the migration. * @@ -224,6 +249,7 @@ public function getOperation(): FunctionOperation $this->operation, $this->returnType, $this->deterministic, + $this->readsSqlData, $this->parameterOperations, $this->variableOperations, $this->body diff --git a/src/Operation/FunctionOperation.php b/src/Operation/FunctionOperation.php index de4c632..9d9a820 100644 --- a/src/Operation/FunctionOperation.php +++ b/src/Operation/FunctionOperation.php @@ -25,6 +25,11 @@ class FunctionOperation extends AbstractOperation */ private $deterministic; + /** + * @var bool + */ + private $readsSqlData; + /** * @var ParameterOperation[] */ @@ -47,6 +52,7 @@ class FunctionOperation extends AbstractOperation * @param string $operation * @param ReturnTypeOperation|null $returnType * @param bool $deterministic + * @param bool $readsSqlData * @param array $parameterOperations * @param array $variableOperations * @param string|null $body @@ -56,6 +62,7 @@ public function __construct( string $operation, ReturnTypeOperation $returnType = null, bool $deterministic = false, + bool $readsSqlData = false, array $parameterOperations = [], array $variableOperations = [], string $body = null @@ -64,6 +71,7 @@ public function __construct( $this->operation = $operation; $this->returnType = $returnType ?? new ReturnTypeOperation('string', ReturnTypeOperation::ADD); $this->deterministic = $deterministic; + $this->readsSqlData = $readsSqlData; $this->parameterOperations = $parameterOperations; $this->variableOperations = $variableOperations; $this->body = $body; @@ -147,6 +155,16 @@ public function getDeterministic(): bool return $this->deterministic; } + /** + * Returns the readsSqlData flag. + * + * @return bool + */ + public function getReadsSqlData(): bool + { + return $this->readsSqlData; + } + /** * Returns the parameter operations. * diff --git a/src/Statement/MysqlStatementBuilder.php b/src/Statement/MysqlStatementBuilder.php index a599146..e413aae 100644 --- a/src/Statement/MysqlStatementBuilder.php +++ b/src/Statement/MysqlStatementBuilder.php @@ -24,6 +24,7 @@ class MysqlStatementBuilder extends StatementBuilder ) RETURNS %s %s + %s BEGIN %s @@ -36,6 +37,7 @@ class MysqlStatementBuilder extends StatementBuilder ) RETURNS %s %s + %s BEGIN %s @@ -223,6 +225,10 @@ public function buildFunction(FunctionOperation $operation): string ? 'DETERMINISTIC' : 'NOT DETERMINISTIC'; + $readsSqlData = ($operation->getReadsSqlData()) + ? 'READS SQL DATA' + : ''; + $variables = array_map(function(VariableOperation $variableOperation) { return sprintf( 'DECLARE %s %s;', @@ -238,7 +244,8 @@ public function buildFunction(FunctionOperation $operation): string $this->buildIdentifier($operation->getName()), // NAME (for create) implode(',', $parameters), // PARAMETERS $returnType, // RETURN TYPE - $determinism, // [NOT] DETERMINISTIC + $determinism, // 'DETERMINISTIC' | 'NOT DETERMINISTIC' + $readsSqlData, // 'READS SQL DATA' | '' implode('', $variables), // VARIABLES $operation->getBody() // BODY ); @@ -249,7 +256,8 @@ public function buildFunction(FunctionOperation $operation): string $this->buildIdentifier($operation->getName()), // NAME (for create) implode(',', $parameters), // PARAMETERS $returnType, // RETURN TYPE - $determinism, // [NOT] DETERMINISTIC + $determinism, // 'DETERMINISTIC' | 'NOT DETERMINISTIC' + $readsSqlData, // 'READS SQL DATA' | '' implode('', $variables), // VARIABLES $operation->getBody() // BODY ); diff --git a/tests/Migrations/20200604_create_user_level_function.php b/tests/Migrations/20200604_create_user_level_function.php index 4e98088..435457c 100644 --- a/tests/Migrations/20200604_create_user_level_function.php +++ b/tests/Migrations/20200604_create_user_level_function.php @@ -3,6 +3,7 @@ return Exo\FunctionMigration::create('user_level') ->withReturnType('integer') ->addParameter('inputValue', ['type' => 'integer']) - ->isDeterministic(false) + ->isDeterministic(true) + ->readsSqlData(false) ->addVariable('suffixValue', ['length' => '20']) ->withBody('RETURN CONCAT(CAST(inputValue AS CHAR(25), suffixValue);'); diff --git a/tests/Operation/FunctionOperationTest.php b/tests/Operation/FunctionOperationTest.php index e434450..1201bbc 100644 --- a/tests/Operation/FunctionOperationTest.php +++ b/tests/Operation/FunctionOperationTest.php @@ -32,6 +32,7 @@ public function testCreate() $operation = new FunctionOperation('customer_level', FunctionOperation::CREATE, new ReturnTypeOperation('string', ReturnTypeOperation::ADD), true, + false, [ new ParameterOperation('arg1', ParameterOperation::ADD), new ParameterOperation('arg2', ParameterOperation::ADD, ['type' => 'integer']), @@ -48,6 +49,7 @@ public function testCreate() $this->assertEquals([], $operation->getReturnType()->getOptions()); $this->assertTrue($operation->getDeterministic()); + $this->assertFalse($operation->getReadsSqlData()); $this->assertCount(3, $operation->getParameterOperations()); @@ -77,6 +79,7 @@ public function testReplace() $base = new FunctionOperation('customer_level', FunctionOperation::CREATE, new ReturnTypeOperation('string', ReturnTypeOperation::ADD), true, + false, [ new ParameterOperation('arg1', ParameterOperation::ADD), new ParameterOperation('arg2', ParameterOperation::ADD, ['type' => 'integer']), @@ -89,6 +92,7 @@ public function testReplace() $new = new FunctionOperation('customer_level', FunctionOperation::REPLACE, new ReturnTypeOperation('integer', ReturnTypeOperation::ADD), false, + true, [], [], self::BODY_TWO @@ -103,6 +107,7 @@ public function testReplace() $this->assertEquals([], $operation->getReturnType()->getOptions()); $this->assertFalse($operation->getDeterministic()); + $this->assertTrue($operation->getReadsSqlData()); $this->assertCount(0, $operation->getParameterOperations()); @@ -116,6 +121,7 @@ public function testApplyDropToCreateOrReplace() $base = new FunctionOperation('any_name', FunctionOperation::REPLACE, new ReturnTypeOperation('string', ReturnTypeOperation::ADD), true, + false, [], [], self::BODY_ONE @@ -147,6 +153,7 @@ public function testReverseReplace() FunctionOperation::REPLACE, new ReturnTypeOperation('integer', ReturnTypeOperation::ADD), false, + true, [ new ParameterOperation('id', ParameterOperation::ADD, []), new ParameterOperation('email', ParameterOperation::ADD, ['type' => 'string', 'length' => 255]), @@ -164,6 +171,7 @@ public function testReverseReplace() FunctionOperation::REPLACE, new ReturnTypeOperation('string', ReturnTypeOperation::ADD), true, + false, [ new ParameterOperation('id', ParameterOperation::ADD, ['type' => 'uuid']), new ParameterOperation('username', ParameterOperation::ADD, ['type' => 'string', 'length' => 64]) @@ -205,6 +213,7 @@ public function testReverseDrop() FunctionOperation::REPLACE, new ReturnTypeOperation('integer', ReturnTypeOperation::ADD), false, + true, [ new ParameterOperation('id', ParameterOperation::ADD, []), new ParameterOperation('email', ParameterOperation::ADD, ['type' => 'string', 'length' => 255, 'first' => true]), diff --git a/tests/Statement/MysqlStatementBuilderTest.php b/tests/Statement/MysqlStatementBuilderTest.php index 7dbf805..f08fc80 100644 --- a/tests/Statement/MysqlStatementBuilderTest.php +++ b/tests/Statement/MysqlStatementBuilderTest.php @@ -122,6 +122,7 @@ public function provider() FunctionOperation::CREATE, new ReturnTypeOperation('string', ReturnTypeOperation::ADD, ['length' => 20]), true, + false, [ new ParameterOperation('inputValue1', ParameterOperation::ADD, ['length' => 32]), new ParameterOperation('inputValue2', ParameterOperation::ADD, ['length' => 32]) @@ -138,6 +139,7 @@ public function provider() 'inputValue1 VARCHAR(32),inputValue2 VARCHAR(32)', 'VARCHAR(20)', 'DETERMINISTIC', + '', 'DECLARE internalVarName1 INTEGER;DECLARE internalVarName2 INTEGER;', 'RETURN \'foo\';' ) @@ -147,6 +149,7 @@ public function provider() 'user_defined_function', FunctionOperation::REPLACE, new ReturnTypeOperation('string', ReturnTypeOperation::ADD, ['length' => 20]), + false, true, [new ParameterOperation('anotherInputValue', ParameterOperation::ADD, ['length' => 32])], [new VariableOperation('anotherVarName', VariableOperation::ADD, ['type' => 'integer'])], @@ -158,7 +161,8 @@ public function provider() '`user_defined_function`', 'anotherInputValue VARCHAR(32)', 'VARCHAR(20)', - 'DETERMINISTIC', + 'NOT DETERMINISTIC', + 'READS SQL DATA', 'DECLARE anotherVarName INTEGER;', 'RETURN \'foo\';' )