IndexRequestService.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OC\FilesMetadata\Service;
  8. use OCP\DB\Exception as DbException;
  9. use OCP\DB\QueryBuilder\IQueryBuilder;
  10. use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException;
  11. use OCP\FilesMetadata\Exceptions\FilesMetadataTypeException;
  12. use OCP\FilesMetadata\Model\IFilesMetadata;
  13. use OCP\FilesMetadata\Model\IMetadataValueWrapper;
  14. use OCP\IDBConnection;
  15. use Psr\Log\LoggerInterface;
  16. /**
  17. * manage sql request to the metadata_index table
  18. */
  19. class IndexRequestService {
  20. public const TABLE_METADATA_INDEX = 'files_metadata_index';
  21. public function __construct(
  22. private IDBConnection $dbConnection,
  23. private LoggerInterface $logger,
  24. ) {
  25. }
  26. /**
  27. * update the index for a specific metadata key
  28. *
  29. * @param IFilesMetadata $filesMetadata metadata
  30. * @param string $key metadata key to update
  31. *
  32. * @throws DbException
  33. */
  34. public function updateIndex(IFilesMetadata $filesMetadata, string $key): void {
  35. $fileId = $filesMetadata->getFileId();
  36. try {
  37. $metadataType = $filesMetadata->getType($key);
  38. } catch (FilesMetadataNotFoundException $e) {
  39. return;
  40. }
  41. /**
  42. * might look harsh, but a lot simpler than comparing current indexed data, as we can expect
  43. * conflict with a change of types.
  44. * We assume that each time one random metadata were modified we can drop all index for this
  45. * key and recreate them.
  46. * To make it slightly cleaner, we'll use transaction
  47. */
  48. $this->dbConnection->beginTransaction();
  49. try {
  50. $this->dropIndex($fileId, $key);
  51. match ($metadataType) {
  52. IMetadataValueWrapper::TYPE_STRING => $this->insertIndexString($fileId, $key, $filesMetadata->getString($key)),
  53. IMetadataValueWrapper::TYPE_INT => $this->insertIndexInt($fileId, $key, $filesMetadata->getInt($key)),
  54. IMetadataValueWrapper::TYPE_BOOL => $this->insertIndexBool($fileId, $key, $filesMetadata->getBool($key)),
  55. IMetadataValueWrapper::TYPE_STRING_LIST => $this->insertIndexStringList($fileId, $key, $filesMetadata->getStringList($key)),
  56. IMetadataValueWrapper::TYPE_INT_LIST => $this->insertIndexIntList($fileId, $key, $filesMetadata->getIntList($key))
  57. };
  58. } catch (FilesMetadataNotFoundException|FilesMetadataTypeException|DbException $e) {
  59. $this->dbConnection->rollBack();
  60. $this->logger->warning('issue while updateIndex', ['exception' => $e, 'fileId' => $fileId, 'key' => $key]);
  61. }
  62. $this->dbConnection->commit();
  63. }
  64. /**
  65. * insert a new entry in the metadata_index table for a string value
  66. *
  67. * @param int $fileId file id
  68. * @param string $key metadata key
  69. * @param string $value metadata value
  70. *
  71. * @throws DbException
  72. */
  73. private function insertIndexString(int $fileId, string $key, string $value): void {
  74. $qb = $this->dbConnection->getQueryBuilder();
  75. $qb->insert(self::TABLE_METADATA_INDEX)
  76. ->setValue('meta_key', $qb->createNamedParameter($key))
  77. ->setValue('meta_value_string', $qb->createNamedParameter($value))
  78. ->setValue('file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT));
  79. $qb->executeStatement();
  80. }
  81. /**
  82. * insert a new entry in the metadata_index table for an int value
  83. *
  84. * @param int $fileId file id
  85. * @param string $key metadata key
  86. * @param int $value metadata value
  87. *
  88. * @throws DbException
  89. */
  90. public function insertIndexInt(int $fileId, string $key, int $value): void {
  91. $qb = $this->dbConnection->getQueryBuilder();
  92. $qb->insert(self::TABLE_METADATA_INDEX)
  93. ->setValue('meta_key', $qb->createNamedParameter($key))
  94. ->setValue('meta_value_int', $qb->createNamedParameter($value, IQueryBuilder::PARAM_INT))
  95. ->setValue('file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT));
  96. $qb->executeStatement();
  97. }
  98. /**
  99. * insert a new entry in the metadata_index table for a bool value
  100. *
  101. * @param int $fileId file id
  102. * @param string $key metadata key
  103. * @param bool $value metadata value
  104. *
  105. * @throws DbException
  106. */
  107. public function insertIndexBool(int $fileId, string $key, bool $value): void {
  108. $qb = $this->dbConnection->getQueryBuilder();
  109. $qb->insert(self::TABLE_METADATA_INDEX)
  110. ->setValue('meta_key', $qb->createNamedParameter($key))
  111. ->setValue('meta_value_int', $qb->createNamedParameter(($value) ? '1' : '0', IQueryBuilder::PARAM_INT))
  112. ->setValue('file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT));
  113. $qb->executeStatement();
  114. }
  115. /**
  116. * insert entries in the metadata_index table for list of string
  117. *
  118. * @param int $fileId file id
  119. * @param string $key metadata key
  120. * @param string[] $values metadata values
  121. *
  122. * @throws DbException
  123. */
  124. public function insertIndexStringList(int $fileId, string $key, array $values): void {
  125. foreach ($values as $value) {
  126. $this->insertIndexString($fileId, $key, $value);
  127. }
  128. }
  129. /**
  130. * insert entries in the metadata_index table for list of int
  131. *
  132. * @param int $fileId file id
  133. * @param string $key metadata key
  134. * @param int[] $values metadata values
  135. *
  136. * @throws DbException
  137. */
  138. public function insertIndexIntList(int $fileId, string $key, array $values): void {
  139. foreach ($values as $value) {
  140. $this->insertIndexInt($fileId, $key, $value);
  141. }
  142. }
  143. /**
  144. * drop indexes related to a file id
  145. * if a key is specified, only drop entries related to it
  146. *
  147. * @param int $fileId file id
  148. * @param string $key metadata key
  149. *
  150. * @throws DbException
  151. */
  152. public function dropIndex(int $fileId, string $key = ''): void {
  153. $qb = $this->dbConnection->getQueryBuilder();
  154. $expr = $qb->expr();
  155. $qb->delete(self::TABLE_METADATA_INDEX)
  156. ->where($expr->eq('file_id', $qb->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
  157. if ($key !== '') {
  158. $qb->andWhere($expr->eq('meta_key', $qb->createNamedParameter($key)));
  159. }
  160. $qb->executeStatement();
  161. }
  162. }