diff --git a/src/HasMetadataMatcher.php b/src/HasMetadataMatcher.php new file mode 100644 index 0000000..0758e6f --- /dev/null +++ b/src/HasMetadataMatcher.php @@ -0,0 +1,25 @@ + + * (c) 2016-2021 Sascha-Oliver Prolic + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Prooph\EventStore\Pdo; + +use Prooph\EventStore\Metadata\MetadataMatcher; + +/** + * Additional interface to be implemented for persistence strategies + * to to provide their own logic to create where clauses + */ +interface HasMetadataMatcher +{ + public function createWhereClause(?MetadataMatcher $metadataMatcher): array; +} diff --git a/src/MySqlEventStore.php b/src/MySqlEventStore.php index e295832..7b1f331 100644 --- a/src/MySqlEventStore.php +++ b/src/MySqlEventStore.php @@ -710,6 +710,10 @@ public function fetchCategoryNamesRegex(string $filter, int $limit = 20, int $of private function createWhereClause(?MetadataMatcher $metadataMatcher): array { + if ($this->persistenceStrategy instanceof HasMetadataMatcher) { + return $this->persistenceStrategy->createWhereClause($metadataMatcher); + } + $where = []; $values = []; diff --git a/src/PersistenceStrategy/MySqlSingleStreamStrategy.php b/src/PersistenceStrategy/MySqlSingleStreamStrategy.php index 4189cb1..35f35f1 100644 --- a/src/PersistenceStrategy/MySqlSingleStreamStrategy.php +++ b/src/PersistenceStrategy/MySqlSingleStreamStrategy.php @@ -15,6 +15,9 @@ use Iterator; use Prooph\Common\Messaging\MessageConverter; +use Prooph\EventStore\Metadata\FieldType; +use Prooph\EventStore\Metadata\MetadataMatcher; +use Prooph\EventStore\Metadata\Operator; use Prooph\EventStore\Pdo\DefaultMessageConverter; use Prooph\EventStore\Pdo\HasQueryHint; use Prooph\EventStore\Pdo\Util\Json; @@ -22,6 +25,12 @@ final class MySqlSingleStreamStrategy implements MySqlPersistenceStrategy, HasQueryHint { + private static $metadataFieldsToColumnMap = [ + '_aggregate_version' => 'aggregate_version', + '_aggregate_id' => 'aggregate_id', + '_aggregate_type' => 'aggregate_type', + ]; + /** * @var MessageConverter */ @@ -96,4 +105,80 @@ public function indexName(): string { return 'ix_query_aggregate'; } + + public function createWhereClause(?MetadataMatcher $metadataMatcher): array + { + $where = []; + $values = []; + + if (! $metadataMatcher) { + return [ + $where, + $values, + ]; + } + + foreach ($metadataMatcher->data() as $key => $match) { + /** @var FieldType $fieldType */ + $fieldType = $match['fieldType']; + $field = $match['field']; + /** @var Operator $operator */ + $operator = $match['operator']; + $value = $match['value']; + $parameters = []; + + if (\is_array($value)) { + foreach ($value as $k => $v) { + $parameters[] = ':metadata_' . $key . '_' . $k; + } + } else { + $parameters = [':metadata_' . $key]; + } + + $parameterString = \implode(', ', $parameters); + + $operatorStringEnd = ''; + + if ($operator->is(Operator::REGEX())) { + $operatorString = 'REGEXP'; + } elseif ($operator->is(Operator::IN())) { + $operatorString = 'IN ('; + $operatorStringEnd = ')'; + } elseif ($operator->is(Operator::NOT_IN())) { + $operatorString = 'NOT IN ('; + $operatorStringEnd = ')'; + } else { + $operatorString = $operator->getValue(); + } + + if ($fieldType->is(FieldType::METADATA()) && !array_key_exists($field, self::$metadataFieldsToColumnMap)) { + if (\is_bool($value)) { + $where[] = "metadata->\"$.$field\" $operatorString " . \var_export($value, true) . ' '. $operatorStringEnd; + continue; + } + + $where[] = "JSON_UNQUOTE(metadata->\"$.$field\") $operatorString $parameterString $operatorStringEnd"; + } else { + if (array_key_exists($field, self::$metadataFieldsToColumnMap)) { + $field = self::$metadataFieldsToColumnMap[$field]; + } + if (\is_bool($value)) { + $where[] = "$field $operatorString " . \var_export($value, true) . ' ' . $operatorStringEnd; + continue; + } + + $where[] = "$field $operatorString $parameterString $operatorStringEnd"; + } + + $value = (array) $value; + foreach ($value as $k => $v) { + $values[$parameters[$k]] = $v; + } + } + + return [ + $where, + $values, + ]; + } }