Skip to content
Snippets Groups Projects
Commit 71dc5dc9 authored by Valentino Međimorec's avatar Valentino Međimorec
Browse files

Issue #3361705 by valic: Drupal 10 compatibility

parent 27f2ac3e
Branches
Tags
1 merge request!1Issue #3361705: Drupal 10 compatibility
name: 'Amazon DynamoDB'
type: module
description: 'Client interface for Amazon DynamoDB'
core_version_requirement: ^8.9 || ^9
core_version_requirement: ^8.9 || ^9 || ^10
package: Performance
name: 'Amazon DynamoDB Key/Value'
type: module
description: 'Amazon DynamoDB Key/Value storage implementation for Drupal 8/9'
core_version_requirement: ^8.9 || ^9
core_version_requirement: ^8.9 || ^9 || ^10
package: Performance
......@@ -3,7 +3,7 @@
namespace Drupal\dynamodb_keyvalue;
use Drupal\Core\Database\Connection;
use \Drupal\dynamodb_client\Connection as DynamoDB;
use Drupal\dynamodb_client\Connection as DynamoDB;
/**
* Migrates key/value entries from DB to DynamoDB.
......@@ -17,20 +17,20 @@ class MigrateDatabaseKeyValue {
*
* @var \Drupal\Core\Database\Connection
*/
protected $database;
protected Connection $database;
/**
* The dynamodb connection.
*
* @var \Drupal\dynamodb_client\Connection
*/
protected $dynamodb;
protected DynamoDB $dynamodb;
/**
* MigrateDatabaseKeyValue constructor.
*
* @param \Drupal\Core\Database\Connection $database
* The database connection
* The database connection.
* @param \Drupal\dynamodb_client\Connection $dynamodb
* The dynamodb connection.
*/
......@@ -42,10 +42,10 @@ class MigrateDatabaseKeyValue {
/**
* Migrate data from database to external destination.
*
* @param $type
* @param string $type
* Type of key value storage, regular or expire.
*/
public function run($type) {
public function run(string $type): void {
// Basic sanity checks.
if (!in_array($type, ['key_value', 'key_value_expire'])) {
......@@ -64,23 +64,22 @@ class MigrateDatabaseKeyValue {
$item = [
'collection' => ['S' => $set->collection],
'name' => ['S' => $set->name],
'value' => ['S' => $set->value]
'value' => ['S' => $set->value],
];
if ($type === 'key_value_expire') {
$item['expire'] = ['N' => $set->expire];
}
$items [] = [
'PutRequest' => [
'Item' => $item]
$items[] = [
'PutRequest' => ['Item' => $item],
];
}
$params = [
'RequestItems' => [
$type => $items,
]
],
];
$this->dynamodb->batchWriteItem($params);
......
......@@ -9,7 +9,7 @@ use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Site\Settings;
/**
* Class ClientFactory.
* DynamoDB client factory.
*/
class ClientFactory {
......@@ -19,12 +19,14 @@ class ClientFactory {
* @var string[]
* Array of site settings.
*/
protected $settings;
protected array $settings;
/**
* The dynamodb alias.
*
* @var string
*/
protected $alias;
protected string $alias;
/**
* The DynamoDB client.
......@@ -32,14 +34,15 @@ class ClientFactory {
* @var \Aws\DynamoDb\DynamoDbClient
* The DynamoDb client instance.
*/
protected $client;
protected DynamoDbClient $client;
/**
* Constructor.
*
* @param string $alias
* The dynamodb alias.
*/
public function __construct($alias = DynamoDb::DYNAMO_DB_DEFAULT) {
public function __construct(string $alias = DynamoDb::DYNAMO_DB_DEFAULT) {
$this->settings = Settings::get('dynamodb_client');
$this->alias = $alias;
}
......@@ -47,10 +50,10 @@ class ClientFactory {
/**
* Return a Client instance for a given alias.
*
* @return \Aws\DynamoDb\DynamoDbClient
* @return \Aws\DynamoDb\DynamoDbClient|null
* A Client instance for the chosen server.
*/
public function connect() {
public function connect(): ?DynamoDbClient {
if (!isset($this->settings[$this->alias])) {
throw new \InvalidArgumentException((string) (new FormattableMarkup('Nonexistent DynamoDB connection alias: @alias', [
'@alias' => $this->alias,
......@@ -71,7 +74,8 @@ class ClientFactory {
try {
$this->client[$this->alias] = new DynamoDbClient($connection_info);
} catch (DynamoDbException $e) {
}
catch (DynamoDbException $e) {
$this->client[$this->alias] = NULL;
}
......@@ -85,7 +89,7 @@ class ClientFactory {
* @return string
* Return Drupal instance name string.
*/
public function getInstanceId() {
public function getInstanceId(): string {
return $this->alias;
}
......
......@@ -2,7 +2,9 @@
namespace Drupal\dynamodb_client;
use Aws\DynamoDb\DynamoDbClient;
use Aws\DynamoDb\Exception\DynamoDbException;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\Site\Settings;
/**
......@@ -17,40 +19,41 @@ class Connection implements DynamoDbInterface {
*
* @var \Drupal\dynamodb_client\ClientFactory
*/
protected $clientFactory;
protected ClientFactory $clientFactory;
/**
* The DynamoDB connection.
*
* @var \Aws\DynamoDb\DynamoDbClient
*/
protected $dynamoDb;
protected DynamoDbClient $dynamoDb;
/**
* Drupal DynamoDB instance key.
*
* @var string
*/
protected $instanceId;
protected string $instanceId;
/**
* The logger channel service.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $loggerFactory;
protected LoggerChannelInterface $loggerFactory;
/**
* Static cache for consistent read option.
*
* @var []
* @var array
*/
protected $consistentRead;
protected array $consistentRead;
/**
* DrupalDynamoDb constructor.
*
* @param $clientFactory
* @param \Drupal\dynamodb_client\ClientFactory $clientFactory
* The client factory.
*/
public function __construct($clientFactory) {
$this->clientFactory = $clientFactory;
......@@ -61,7 +64,7 @@ class Connection implements DynamoDbInterface {
/**
* {@inheritdoc}
*/
public function query(array $params) {
public function query(array $params): array {
$output = [];
$limit = isset($params['Limit']);
......@@ -72,9 +75,9 @@ class Connection implements DynamoDbInterface {
do {
try {
// Add the ExclusiveStartKey if we got one back in the previous response
if(isset($results['LastEvaluatedKey'])) {
// Add the ExclusiveStartKey if we got one back in
// the previous response.
if (isset($results['LastEvaluatedKey'])) {
$params['ExclusiveStartKey'] = $results['LastEvaluatedKey'];
}
......@@ -83,19 +86,21 @@ class Connection implements DynamoDbInterface {
if (isset($results['Items'])) {
if ($limit) {
$output = $results['Items'];
} else {
}
else {
$output = array_merge($output, $results['Items']);
}
}
} catch (DynamoDbException $e) {
}
catch (DynamoDbException $e) {
$this->logger()->error($e);
}
// If there is LastEvaluatedKey in the response and initial parameters
// does not include limit, then there are more items matching this Query.
// Fetch them all.
} while(isset($results['LastEvaluatedKey']) && !$limit);
} while (isset($results['LastEvaluatedKey']) && !$limit);
return $output;
}
......@@ -103,7 +108,7 @@ class Connection implements DynamoDbInterface {
/**
* {@inheritdoc}
*/
public function scan(array $params) {
public function scan(array $params): array {
$output = [];
$limit = isset($params['Limit']);
......@@ -114,9 +119,9 @@ class Connection implements DynamoDbInterface {
do {
try {
// Add the ExclusiveStartKey if we got one back in the previous response
if(isset($results['LastEvaluatedKey'])) {
// Add the ExclusiveStartKey if we got one back
// in the previous response.
if (isset($results['LastEvaluatedKey'])) {
$params['ExclusiveStartKey'] = $results['LastEvaluatedKey'];
}
......@@ -125,19 +130,21 @@ class Connection implements DynamoDbInterface {
if (isset($results['Items'])) {
if ($limit) {
$output = $results['Items'];
} else {
}
else {
$output = array_merge($output, $results['Items']);
}
}
} catch (DynamoDbException $e) {
}
catch (DynamoDbException $e) {
$this->logger()->error($e);
}
// If there is LastEvaluatedKey in the response and initial parameters
// does not include limit, then there are more items matching this Query.
// Fetch them all.
} while(isset($results['LastEvaluatedKey']) && !$limit);
} while (isset($results['LastEvaluatedKey']) && !$limit);
return $output;
}
......@@ -145,7 +152,7 @@ class Connection implements DynamoDbInterface {
/**
* {@inheritdoc}
*/
public function getItem(array $params) {
public function getItem(array $params): array {
// Get consistent read settings.
if (!isset($params['ConsistentRead'])) {
$params['ConsistentRead'] = $this->isConsistentRead($params['TableName']);
......@@ -154,7 +161,8 @@ class Connection implements DynamoDbInterface {
try {
$result = $this->dynamoDb->getItem($params);
} catch (DynamoDbException $e) {
}
catch (DynamoDbException $e) {
$this->logger()->error($e);
}
return $result['Item'] ?? [];
......@@ -163,10 +171,11 @@ class Connection implements DynamoDbInterface {
/**
* {@inheritdoc}
*/
public function putItem(array $params) {
public function putItem(array $params): bool {
try {
$result = $this->dynamoDb->putItem($params);
} catch (DynamoDbException $e) {
}
catch (DynamoDbException $e) {
$this->logger()->error($e);
}
return isset($result['@metadata']);
......@@ -175,10 +184,11 @@ class Connection implements DynamoDbInterface {
/**
* {@inheritdoc}
*/
public function updateItem(array $params) {
public function updateItem(array $params): array {
try {
$result = $this->dynamoDb->updateItem($params);
} catch (DynamoDbException $e) {
}
catch (DynamoDbException $e) {
$this->logger()->error($e);
}
return $result['Attributes'] ?? [];
......@@ -187,10 +197,11 @@ class Connection implements DynamoDbInterface {
/**
* {@inheritdoc}
*/
public function deleteItem(array $params) {
public function deleteItem(array $params): array {
try {
$result = $this->dynamoDb->deleteItem($params);
} catch (DynamoDbException $e) {
}
catch (DynamoDbException $e) {
$this->logger()->error($e);
}
return $result['Attributes'] ?? [];
......@@ -199,10 +210,11 @@ class Connection implements DynamoDbInterface {
/**
* {@inheritdoc}
*/
public function batchWriteItem(array $params) {
public function batchWriteItem(array $params): bool {
try {
$result = $this->dynamoDb->batchWriteItem($params);
} catch (DynamoDbException $e) {
}
catch (DynamoDbException $e) {
$this->logger()->error($e);
}
return isset($result['@metadata']);
......@@ -211,14 +223,15 @@ class Connection implements DynamoDbInterface {
/**
* {@inheritdoc}
*/
public function batchGetItem(array $params) {
public function batchGetItem(array $params): array {
// Get consistent read settings.
if (!isset($params['ConsistentRead'])) {
$params['ConsistentRead'] = $this->isConsistentRead($params['TableName']);
}
try {
$results = $this->dynamoDb->batchGetItem($params);
} catch (DynamoDbException $e) {
}
catch (DynamoDbException $e) {
$this->logger()->error($e);
}
return $results['Responses'] ?? [];
......@@ -227,7 +240,7 @@ class Connection implements DynamoDbInterface {
/**
* {@inheritdoc}
*/
public function createTable(array $params) {
public function createTable(array $params): bool {
// If there is nothing specified on params, use global defined
// billing settings.
if (!isset($params['ProvisionedThroughput'], $params['BillingMode'])) {
......@@ -240,11 +253,12 @@ class Connection implements DynamoDbInterface {
'TableName' => $params['TableName'],
'@waiter' => [
'delay' => 3,
'maxAttempts' => 5
]
'maxAttempts' => 5,
],
]);
} catch (DynamoDbException $e) {
}
catch (DynamoDbException $e) {
$this->logger()->error($e);
return FALSE;
}
......@@ -254,10 +268,11 @@ class Connection implements DynamoDbInterface {
/**
* {@inheritdoc}
*/
public function updateTable(array $params) {
public function updateTable(array $params): bool {
try {
$this->dynamoDb->updateTable($params);
} catch (DynamoDbException $e) {
}
catch (DynamoDbException $e) {
$this->logger()->error($e);
return FALSE;
}
......@@ -267,17 +282,18 @@ class Connection implements DynamoDbInterface {
/**
* {@inheritdoc}
*/
public function deleteTable(array $params) {
public function deleteTable(array $params): bool {
try {
$this->dynamoDb->deleteTable($params);
$this->dynamoDb->waitUntil('TableNotExists', [
'TableName' => $params['TableName'],
'@waiter' => [
'delay' => 3,
'maxAttempts' => 5
]
'maxAttempts' => 5,
],
]);
} catch (DynamoDbException $e) {
}
catch (DynamoDbException $e) {
$this->logger()->error($e);
return FALSE;
}
......@@ -287,10 +303,11 @@ class Connection implements DynamoDbInterface {
/**
* {@inheritdoc}
*/
public function listTables(array $params) {
public function listTables(array $params): array {
try {
$this->dynamoDb->listTables($params);
} catch (DynamoDbException $e) {
}
catch (DynamoDbException $e) {
$this->logger()->error($e);
}
return $response['TableNames'] ?? [];
......@@ -299,7 +316,7 @@ class Connection implements DynamoDbInterface {
/**
* {@inheritdoc}
*/
public function getClient() {
public function getClient(): DynamoDbClient {
return $this->clientFactory->connect();
}
......@@ -312,7 +329,7 @@ class Connection implements DynamoDbInterface {
* @return bool
* Return true or false.
*/
protected function isConsistentRead($table) {
protected function isConsistentRead(string $table): bool {
// Reuse for same table and instance - useful for key_value, etc..
if (!isset($this->consistentRead[$this->instanceId])) {
$settings = Settings::get('dynamodb_client');
......@@ -334,7 +351,7 @@ class Connection implements DynamoDbInterface {
* @return array
* Return billing data.
*/
protected function getBillingMode($table) {
protected function getBillingMode(string $table): array {
$settings = Settings::get('dynamodb_client');
if (!isset($settings[$this->instanceId]['aws_billing'])) {
......@@ -348,8 +365,9 @@ class Connection implements DynamoDbInterface {
* Initialize dynamically logger service upon failure of DynamoDB query.
*
* @return \Drupal\Core\Logger\LoggerChannelInterface
* The logger.
*/
protected function logger() {
protected function logger(): LoggerChannelInterface {
if (!$this->loggerFactory) {
$this->loggerFactory = \Drupal::service('logger.factory')->get('dynamodb_client');
}
......
......@@ -2,6 +2,8 @@
namespace Drupal\dynamodb_client;
use Aws\DynamoDb\DynamoDbClient;
/**
* Main definition for establishing connection.
*
......@@ -22,16 +24,18 @@ final class DynamoDb {
public const DYNAMO_DB_BATCH_GET_LIMIT = 50;
/**
* An nested array of all active connections. It is keyed by database name
* and target.
* An nested array of all active connections.
*
* It is keyed by database name and target.
*
* @var []\Drupal\dynamodb_client\Connection
*/
protected static $connections = [];
/**
* An nested array of all active connections. It is keyed by database name
* and target.
* A nested array of all active connections.
*
* It is keyed by database name and target.
*
* @var []\Aws\DynamoDb\DynamoDbClient
*/
......@@ -46,7 +50,7 @@ final class DynamoDb {
* @return \Drupal\dynamodb_client\Connection
* Returns Drupal DynamoDB connection
*/
public static function database($alias = self::DYNAMO_DB_DEFAULT) {
public static function database(string $alias = self::DYNAMO_DB_DEFAULT): Connection {
if (!isset(self::$connections[$alias])) {
self::$connections[$alias] = new Connection(new ClientFactory($alias));
}
......@@ -60,10 +64,10 @@ final class DynamoDb {
* @param string $alias
* The database alias from Drupal settings.
*
* @return \Aws\DynamoDb\DynamoDbClient|null
* @return \Aws\DynamoDb\DynamoDbClient
* Returns AWS DynamoDB connection
*/
public static function rawDatabase($alias = self::DYNAMO_DB_DEFAULT) {
public static function rawDatabase(string $alias = self::DYNAMO_DB_DEFAULT): DynamoDbClient {
if (!isset(self::$rawConnections[$alias])) {
$client_factory = new ClientFactory($alias);
self::$rawConnections[$alias] = $client_factory->connect();
......
......@@ -2,6 +2,8 @@
namespace Drupal\dynamodb_client;
use Aws\DynamoDb\DynamoDbClient;
/**
* Interface for Drupal wrapper around DynamoDB service.
*
......@@ -20,10 +22,11 @@ interface DynamoDbInterface {
*
* @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html
*/
public function query(array $params);
public function query(array $params): array;
/**
* Scan DynamoDB table based on provided paramters.
* Scan DynamoDB table based on provided parameters.
*
* @param array $params
* DynamoDB query parameters.
*
......@@ -32,10 +35,10 @@ interface DynamoDbInterface {
*
* @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Scan.html
*/
public function scan(array $params);
public function scan(array $params): array;
/**
* Fetch single item from DynamoDB by it's keys.
* Fetch single item from DynamoDB by its keys.
*
* @param array $params
* DynamoDB query parameters.
......@@ -45,7 +48,7 @@ interface DynamoDbInterface {
*
* @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_GetItem.html
*/
public function getItem(array $params);
public function getItem(array $params): array;
/**
* Insert new or replaced old item in DynamoDB table.
......@@ -58,7 +61,7 @@ interface DynamoDbInterface {
*
* @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_PutItem.html
*/
public function putItem(array $params);
public function putItem(array $params): bool;
/**
* Update item attributes or create new item on DynamoDB table.
......@@ -71,7 +74,7 @@ interface DynamoDbInterface {
*
* @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateItem.html
*/
public function updateItem(array $params);
public function updateItem(array $params): array;
/**
* Delete item from DynamoDB table.
......@@ -84,7 +87,7 @@ interface DynamoDbInterface {
*
* @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_DeleteItem.html
*/
public function deleteItem(array $params);
public function deleteItem(array $params): array;
/**
* Batch put or delete multiple items on DynamoDB table.
......@@ -97,7 +100,7 @@ interface DynamoDbInterface {
*
* @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html
*/
public function batchWriteItem(array $params);
public function batchWriteItem(array $params): bool;
/**
* Batch get items from DynamoDB table by item keys.
......@@ -110,44 +113,44 @@ interface DynamoDbInterface {
*
* @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchGetItem.html
*/
public function batchGetItem(array $params);
public function batchGetItem(array $params): array;
/**
* Create DynamoDB table.
*
* @param array $params
* DynamoDB parameters.
* DynamoDB params.
*
* @return bool
* Return TRUE upon successful creating the table.
*
* @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_CreateTable.html
*/
public function createTable(array $params);
public function createTable(array $params): bool;
/**
* Update existing DynamoDB table.
*
* @param array $params
* DynamoDB parameters.
* DynamoDB params.
*
* @return bool
* Return TRUE upon successful updating the table.
*
* @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_UpdateTable.html
*/
public function updateTable(array $params);
public function updateTable(array $params): bool;
/**
* Deletes existing DynamoDB table.
*
* @param array $params
* DynamoDB parameters.
* DynamoDB params.
*
* @return bool
* Return TRUE upon successfully deletion of the table.
*/
public function deleteTable(array $params);
public function deleteTable(array $params): bool;
/**
* Fetch all DynamoDB tables from current server.
......@@ -160,7 +163,7 @@ interface DynamoDbInterface {
*
* @see https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ListTables.html
*/
public function listTables(array $params);
public function listTables(array $params): array;
/**
* Get direct DynamoDB connection client.
......@@ -168,6 +171,6 @@ interface DynamoDbInterface {
* @return \Aws\DynamoDb\DynamoDbClient
* Return DynamoDB client.
*/
public function getClient();
public function getClient(): DynamoDbClient;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment