diff --git a/composer.json b/composer.json index ae846a3ca..1d1ae4e66 100755 --- a/composer.json +++ b/composer.json @@ -35,7 +35,8 @@ "php": ">=8.0", "utopia-php/framework": "0.*.*", "utopia-php/cache": "0.8.*", - "utopia-php/mongo": "0.3.*" + "utopia-php/mongo": "0.3.*", + "aws/aws-sdk-php": "^3.282" }, "require-dev": { "fakerphp/faker": "^1.14", diff --git a/composer.lock b/composer.lock index 3ab0753d4..6afa4bf60 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,482 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6811aec6a1675620a039ab1a7c240a17", + "content-hash": "4025f6d44f24794e543f506e080712f0", "packages": [ + { + "name": "aws/aws-crt-php", + "version": "v1.2.2", + "source": { + "type": "git", + "url": "https://github.com/awslabs/aws-crt-php.git", + "reference": "2f1dc7b7eda080498be96a4a6d683a41583030e9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/2f1dc7b7eda080498be96a4a6d683a41583030e9", + "reference": "2f1dc7b7eda080498be96a4a6d683a41583030e9", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35||^5.6.3||^9.5", + "yoast/phpunit-polyfills": "^1.0" + }, + "suggest": { + "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality." + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "AWS SDK Common Runtime Team", + "email": "aws-sdk-common-runtime@amazon.com" + } + ], + "description": "AWS Common Runtime for PHP", + "homepage": "https://github.com/awslabs/aws-crt-php", + "keywords": [ + "amazon", + "aws", + "crt", + "sdk" + ], + "support": { + "issues": "https://github.com/awslabs/aws-crt-php/issues", + "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.2" + }, + "time": "2023-07-20T16:49:55+00:00" + }, + { + "name": "aws/aws-sdk-php", + "version": "3.282.0", + "source": { + "type": "git", + "url": "https://github.com/aws/aws-sdk-php.git", + "reference": "79a3ed5bb573f592823f8b1cffe0dbac3132e6b4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/79a3ed5bb573f592823f8b1cffe0dbac3132e6b4", + "reference": "79a3ed5bb573f592823f8b1cffe0dbac3132e6b4", + "shasum": "" + }, + "require": { + "aws/aws-crt-php": "^1.0.4", + "ext-json": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "guzzlehttp/guzzle": "^6.5.8 || ^7.4.5", + "guzzlehttp/promises": "^1.4.0 || ^2.0", + "guzzlehttp/psr7": "^1.9.1 || ^2.4.5", + "mtdowling/jmespath.php": "^2.6", + "php": ">=7.2.5", + "psr/http-message": "^1.0 || ^2.0" + }, + "require-dev": { + "andrewsville/php-token-reflection": "^1.4", + "aws/aws-php-sns-message-validator": "~1.0", + "behat/behat": "~3.0", + "composer/composer": "^1.10.22", + "dms/phpunit-arraysubset-asserts": "^0.4.0", + "doctrine/cache": "~1.4", + "ext-dom": "*", + "ext-openssl": "*", + "ext-pcntl": "*", + "ext-sockets": "*", + "nette/neon": "^2.3", + "paragonie/random_compat": ">= 2", + "phpunit/phpunit": "^5.6.3 || ^8.5 || ^9.5", + "psr/cache": "^1.0", + "psr/simple-cache": "^1.0", + "sebastian/comparator": "^1.2.3 || ^4.0", + "yoast/phpunit-polyfills": "^1.0" + }, + "suggest": { + "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications", + "doctrine/cache": "To use the DoctrineCacheAdapter", + "ext-curl": "To send requests using cURL", + "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages", + "ext-sockets": "To use client-side monitoring" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Aws\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Amazon Web Services", + "homepage": "http://aws.amazon.com" + } + ], + "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project", + "homepage": "http://aws.amazon.com/sdkforphp", + "keywords": [ + "amazon", + "aws", + "cloud", + "dynamodb", + "ec2", + "glacier", + "s3", + "sdk" + ], + "support": { + "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", + "issues": "https://github.com/aws/aws-sdk-php/issues", + "source": "https://github.com/aws/aws-sdk-php/tree/3.282.0" + }, + "time": "2023-09-28T18:09:20+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.8.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/1110f66a6530a40fe7aea0378fe608ee2b2248f9", + "reference": "1110f66a6530a40fe7aea0378fe608ee2b2248f9", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.1", + "guzzlehttp/psr7": "^1.9.1 || ^2.5.1", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "ext-curl": "*", + "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.29 || ^9.5.23", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.8.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2023-08-27T10:20:53+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "111166291a0f8130081195ac4556a5587d7f1b5d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/111166291a0f8130081195ac4556a5587d7f1b5d", + "reference": "111166291a0f8130081195ac4556a5587d7f1b5d", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.0.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2023-08-03T15:11:55+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.6.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/be45764272e8873c72dbe3d2edcfdfcc3bc9f727", + "reference": "be45764272e8873c72dbe3d2edcfdfcc3bc9f727", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.1", + "http-interop/http-factory-tests": "^0.9", + "phpunit/phpunit": "^8.5.29 || ^9.5.23" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.6.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2023-08-27T10:13:57+00:00" + }, { "name": "jean85/pretty-package-versions", "version": "2.0.5", @@ -16,30 +490,323 @@ }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af", - "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "url": "https://api.github.com/repos/Jean85/pretty-package-versions/zipball/ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "reference": "ae547e455a3d8babd07b96966b17d7fd21d9c6af", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.0.0", + "php": "^7.1|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^2.17", + "jean85/composer-provided-replaced-stub-package": "^1.0", + "phpstan/phpstan": "^0.12.66", + "phpunit/phpunit": "^7.5|^8.5|^9.4", + "vimeo/psalm": "^4.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Jean85\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Alessandro Lai", + "email": "alessandro.lai85@gmail.com" + } + ], + "description": "A library to get pretty versions strings of installed dependencies", + "keywords": [ + "composer", + "package", + "release", + "versions" + ], + "support": { + "issues": "https://github.com/Jean85/pretty-package-versions/issues", + "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5" + }, + "time": "2021-10-08T21:21:46+00:00" + }, + { + "name": "mongodb/mongodb", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/mongodb/mongo-php-library.git", + "reference": "b0bbd657f84219212487d01a8ffe93a789e1e488" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/b0bbd657f84219212487d01a8ffe93a789e1e488", + "reference": "b0bbd657f84219212487d01a8ffe93a789e1e488", + "shasum": "" + }, + "require": { + "ext-hash": "*", + "ext-json": "*", + "ext-mongodb": "^1.11.0", + "jean85/pretty-package-versions": "^1.2 || ^2.0.1", + "php": "^7.1 || ^8.0", + "symfony/polyfill-php80": "^1.19" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0", + "squizlabs/php_codesniffer": "^3.6", + "symfony/phpunit-bridge": "^5.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "MongoDB\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Andreas Braun", + "email": "andreas.braun@mongodb.com" + }, + { + "name": "Jeremy Mikola", + "email": "jmikola@gmail.com" + } + ], + "description": "MongoDB driver library", + "homepage": "https://jira.mongodb.org/browse/PHPLIB", + "keywords": [ + "database", + "driver", + "mongodb", + "persistence" + ], + "support": { + "issues": "https://github.com/mongodb/mongo-php-library/issues", + "source": "https://github.com/mongodb/mongo-php-library/tree/1.10.0" + }, + "time": "2021-10-20T22:22:37+00:00" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/bbb69a935c2cbb0c03d7f481a238027430f6440b", + "reference": "bbb69a935c2cbb0c03d7f481a238027430f6440b", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.7.0" + }, + "time": "2023-08-25T10:54:48+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "e616d01114759c4c489f93b099585439f795fe35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35", + "reference": "e616d01114759c4c489f93b099585439f795fe35", + "shasum": "" + }, + "require": { + "php": ">=7.0.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory/tree/1.0.2" + }, + "time": "2023-04-10T20:10:41+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", "shasum": "" }, "require": { - "composer-runtime-api": "^2.0.0", - "php": "^7.1|^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^2.17", - "jean85/composer-provided-replaced-stub-package": "^1.0", - "phpstan/phpstan": "^0.12.66", - "phpunit/phpunit": "^7.5|^8.5|^9.4", - "vimeo/psalm": "^4.3" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { "psr-4": { - "Jean85\\": "src/" + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -48,91 +815,218 @@ ], "authors": [ { - "name": "Alessandro Lai", - "email": "alessandro.lai85@gmail.com" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "A library to get pretty versions strings of installed dependencies", + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", "keywords": [ - "composer", - "package", - "release", - "versions" + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" ], "support": { - "issues": "https://github.com/Jean85/pretty-package-versions/issues", - "source": "https://github.com/Jean85/pretty-package-versions/tree/2.0.5" + "source": "https://github.com/php-fig/http-message/tree/2.0" }, - "time": "2021-10-08T21:21:46+00:00" + "time": "2023-04-04T09:54:51+00:00" }, { - "name": "mongodb/mongodb", - "version": "1.10.0", + "name": "ralouphie/getallheaders", + "version": "3.0.3", "source": { "type": "git", - "url": "https://github.com/mongodb/mongo-php-library.git", - "reference": "b0bbd657f84219212487d01a8ffe93a789e1e488" + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/b0bbd657f84219212487d01a8ffe93a789e1e488", - "reference": "b0bbd657f84219212487d01a8ffe93a789e1e488", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", "shasum": "" }, "require": { - "ext-hash": "*", - "ext-json": "*", - "ext-mongodb": "^1.11.0", - "jean85/pretty-package-versions": "^1.2 || ^2.0.1", - "php": "^7.1 || ^8.0", - "symfony/polyfill-php80": "^1.19" + "php": ">=5.6" }, "require-dev": { - "doctrine/coding-standard": "^9.0", - "squizlabs/php_codesniffer": "^3.6", - "symfony/phpunit-bridge": "^5.2" + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "shasum": "" + }, + "require": { + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.10.x-dev" + "dev-main": "3.4-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { "files": [ - "src/functions.php" + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-23T14:45:45+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.28.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "42292d99c55abe617799667f454222c54c60e229" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", + "reference": "42292d99c55abe617799667f454222c54c60e229", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" ], "psr-4": { - "MongoDB\\": "src/" + "Symfony\\Polyfill\\Mbstring\\": "" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache-2.0" + "MIT" ], "authors": [ { - "name": "Andreas Braun", - "email": "andreas.braun@mongodb.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Jeremy Mikola", - "email": "jmikola@gmail.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "MongoDB driver library", - "homepage": "https://jira.mongodb.org/browse/PHPLIB", + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", "keywords": [ - "database", - "driver", - "mongodb", - "persistence" + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" ], "support": { - "issues": "https://github.com/mongodb/mongo-php-library/issues", - "source": "https://github.com/mongodb/mongo-php-library/tree/1.10.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0" }, - "time": "2021-10-20T22:22:37+00:00" + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-07-28T09:04:16+00:00" }, { "name": "symfony/polyfill-php80", @@ -2426,73 +3320,6 @@ ], "time": "2021-10-14T19:39:28+00:00" }, - { - "name": "symfony/deprecation-contracts", - "version": "v3.3.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.3.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2023-05-23T14:45:45+00:00" - }, { "name": "theseer/tokenizer", "version": "1.2.1", @@ -2608,5 +3435,5 @@ "php": ">=8.0" }, "platform-dev": [], - "plugin-api-version": "2.2.0" + "plugin-api-version": "2.6.0" } diff --git a/docker-compose.yml b/docker-compose.yml index 296cd6095..7e9a1a914 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -16,6 +16,9 @@ services: - ./phpunit.xml:/usr/src/code/phpunit.xml ports: - "8708:8708" + environment: + AWS_ACCESS_KEY_ID: "DUMMYKEYID" + AWS_SECRET_ACCESS_KEY: "DUMMYSECRETKEY" adminer: image: adminer @@ -74,6 +77,28 @@ services: cap_add: - SYS_NICE + dynamodb: + image: amazon/dynamodb-local + container_name: dynamodb + command: "-jar DynamoDBLocal.jar -sharedDb -port 8012" + networks: + - database + ports: + - "8704:8012" + + dynamodb-admin: + image: aaronshaf/dynamodb-admin + container_name: dynamodb-admin + ports: + - "8705:8705" + environment: + DYNAMO_ENDPOINT: http://dynamodb:8012 + PORT: 8705 + AWS_ACCESS_KEY_ID: "DUMMYKEYID" + AWS_SECRET_ACCESS_KEY: "DUMMYSECRETKEY" + networks: + - database + redis: image: redis:6.0-alpine container_name: utopia-redis diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php new file mode 100644 index 000000000..c3df1f2f0 --- /dev/null +++ b/src/Database/Adapter/DynamoDB.php @@ -0,0 +1,1020 @@ +client; + } + + + + public function __construct(Client $client) + { + $this->client = $client; + } + + /** + * Ping Database + * + * DynamoDB is a managed database - If the DynamoDB client is successfully initialized, you can assume the service is accessible. + * @return bool + */ + public function ping(): bool + { + return true; + } + + /** + * Create Database + * + * @param string $name + * + * No concept of Database schemas in DynamoDb. + * @return bool + */ + public function create(string $name): bool + { + return true; + } + + /** + * Check if database exists + * Optionally check if collection exists in database + * + * @param string $database database name + * @param string $collection (optional) collection name + * + * @return bool + */ + public function exists(string $database, ?string $collection): bool + { + if (!\is_null($collection)) { + $collection = $this->filter($collection); + try { + $this->client->describeTable([ + 'TableName' => "{$this->getNamespace()}_{$collection}", + ]); + } catch (DynamoDbException $e) { + return false; + } + } + return true; + } + + /** + * List Databases + * + * No concept of Database schemas in DynamoDb. + * @return array + */ + public function list(): array + { + return []; + } + + /** + * Delete Database + * + * @param string $name + * + * No concept of Database schemas in DynamoDb. + * @return bool + */ + public function delete(string $name): bool + { + return true; + } + + /** + * Get DynamoDb Type + * + * @param string $type + * + * @return string + */ + protected function getDynamoDbType(string $type): string + { + if (in_array($type, array(Database::VAR_STRING, Database::VAR_RELATIONSHIP))) { + return DynamoDB::VAR_STRING; + } else if (in_array($type, array(Database::VAR_INTEGER, Database::VAR_FLOAT, Database::VAR_BOOLEAN, Database::VAR_DATETIME))) { + return DynamoDB::VAR_NUMBER; + } else { + throw new DatabaseException('Unknown Type: ' . $type); + } + } + + /** + * Create Collection + * + * @param string $name + * @param array $attributes (optional) + * @param array $indexes (optional) + * @return bool + */ + public function createCollection(string $name, array $attributes = [], array $indexes = []): bool + { + $tableName = "{$this->getNamespace()}_{$this->filter($name)}"; + + if ($name === Database::METADATA && $this->exists($this->getNamespace(), $name)) { + return true; + } + + $attributeDefinitions = [ + [ + 'AttributeName' => '_id', + 'AttributeType' => DynamoDB::VAR_STRING, + ], + [ + 'AttributeName' => '_uid', + 'AttributeType' => DynamoDB::VAR_STRING, + ], + [ + 'AttributeName' => '_createdAt', + 'AttributeType' => DynamoDB::VAR_NUMBER, + ], + [ + 'AttributeName' => '_updatedAt', + 'AttributeType' => DynamoDB::VAR_NUMBER, + ], + [ + 'AttributeName' => '_permissions', + 'AttributeType' => DynamoDB::VAR_STRING, + ] + ]; + + $globalIndexes = [ + [ + 'IndexName' => '_uid', + 'KeySchema' => [ + [ + 'AttributeName' => '_uid', + 'KeyType' => 'HASH', + ], + ], + 'Projection' => [ + 'ProjectionType' => 'ALL', + ], + ], + [ + 'IndexName' => '_createdAt', + 'KeySchema' => [ + [ + 'AttributeName' => '_createdAt', + 'KeyType' => 'HASH', + ], + ], + 'Projection' => [ + 'ProjectionType' => 'ALL', + ], + ], + [ + 'IndexName' => '_updatedAt', + 'KeySchema' => [ + [ + 'AttributeName' => '_updatedAt', + 'KeyType' => 'HASH', + ], + ], + 'Projection' => [ + 'ProjectionType' => 'ALL', + ], + ], + [ + 'IndexName' => '_permissions', + 'KeySchema' => [ + [ + 'AttributeName' => '_permissions', + 'KeyType' => 'HASH', + ], + ], + 'Projection' => [ + 'ProjectionType' => 'ALL', + ], + ], + ]; + + $attributeDefMap = []; + + foreach ($attributes as $attribute) { + $attrId = $this->filter($attribute->getId()); + $attrType = $this->getDynamoDbType($attribute->getAttribute('type')); + + $attributeDef = [ + 'AttributeName' => $attrId, + 'AttributeType' => $attrType, + ]; + + $attributeDefMap[$attrId] = $attributeDef; + } + + foreach ($indexes as $index) { + $indexId = $this->filter($index->getId()); + $indexType = $index->getAttribute('type'); + $indexAttributes = $index->getAttribute('attributes'); + + $globalIndex = [ + 'IndexName' => $indexId, + 'Projection' => [ + 'ProjectionType' => 'ALL', + ], + ]; + + $globalIndex['KeySchema'] = [ + [ + 'AttributeName' => $indexAttributes[0], + 'KeyType' => 'HASH', + ] + ]; + array_push($attributeDefinitions, $attributeDefMap[$indexAttributes[0]]); + + if ($indexType == DynamoDB::COMPOSITE_INDEX) { + array_push($globalIndex['KeySchema'], [ + 'AttributeName' => $indexAttributes[1], + 'KeyType' => 'RANGE', + ]); + array_push($attributeDefinitions, $attributeDefMap[$indexAttributes[1]]); + } + array_push($globalIndexes, $globalIndex); + } + + $createTableParams = [ + 'TableName' => $tableName, + 'BillingMode' => 'PAY_PER_REQUEST', + 'AttributeDefinitions' => $attributeDefinitions, + 'KeySchema' => [ + [ + 'AttributeName' => '_id', + 'KeyType' => 'HASH', + ], + ], + 'GlobalSecondaryIndexes' => $globalIndexes, + ]; + + $this->client->createTable($createTableParams); + + return true; + } + + /** + * Delete Collection + * + * @param string $name + * + * @return bool + */ + public function deleteCollection(string $name): bool + { + $name = $this->filter($name); + try { + $this->client->deleteTable([ + 'TableName' => "{$this->getNamespace()}_{$name}", + ]); + } catch (DynamoDbException $e) { + return false; + } + return true; + } + + /** + * Create Attribute + * + * @param string $collection + * @param string $id + * @param string $type + * @param int $size + * @param bool $signed + * @param bool $array + * @return bool + */ + public function createAttribute(string $collection, string $id, string $type, int $size, bool $signed = true, bool $array = false): bool + { + return true; + } + + /** + * Update Attribute + * + * @param string $collection + * @param string $id + * @param string $type + * @param int $size + * @param bool $signed + * @param bool $array + * + * @return bool + */ + public function updateAttribute(string $collection, string $id, string $type, int $size, bool $signed = true, bool $array = false): bool + { + return true; + } + + /** + * Delete Attribute + * + * @param string $collection + * @param string $id + * + * @return bool + */ + public function deleteAttribute(string $collection, string $id): bool + { + $collection = $this->filter($collection); + $id = $this->filter($id); + $queryParams = [ + 'TableName' => "{$this->getNamespace()}_{$collection}", + 'ProjectionExpression' => '#id', + 'ExpressionAttributeNames' => [ '#id' => '_id' ], + ]; + $items = ($this->client->scan($queryParams))['Items']; + foreach ($items as $item) { + $updateParams = [ + 'TableName' => "{$this->getNamespace()}_{$collection}", + 'Key' => ['_id' => [ 'S' => $item['_id']]], // Replace with your primary key + 'UpdateExpression' => "REMOVE {$id}", + ]; + try { + $this->client->updateItem($updateParams); + } catch (DynamoDbException $e) { + return false; + } + } + return true; + } + + /** + * Rename Attribute + * + * @param string $collection + * @param string $old + * @param string $new + * @return bool + */ + public function renameAttribute(string $collection, string $old, string $new): bool + { + $collection = $this->filter($collection); + $old = $this->filter($old); + $new = $this->filter($new); + $queryParams = [ + 'TableName' => "{$this->getNamespace()}_{$collection}", + 'ProjectionExpression' => "#id, {$old}", + 'ExpressionAttributeNames' => [ '#id' => '_id' ], + ]; + $items = ($this->client->scan($queryParams))['Items']; + foreach ($items as $item) { + $oldItemValues = $item[$old]; + $oldItemValue = null; + foreach ($oldItemValues as $value) { + $oldItemValue = $value; + } + $updateParams = [ + 'TableName' => "{$this->getNamespace()}_{$collection}", + 'Key' => ['_id' => [ 'S' => $item['_id']['S']]], // Replace with your primary key + 'UpdateExpression' => "SET {$new} = {$oldItemValue} REMOVE {$old}", + ]; + try { + $this->client->updateItem($updateParams); + } catch (DynamoDbException $e) { + return false; + } + } + return true; + } + + /** + * @param string $collection + * @param string $relatedCollection + * @param string $type + * @param bool $twoWay + * @param string $id + * @param string $twoWayKey + * @return bool + */ + public function createRelationship(string $collection, string $relatedCollection, string $type, bool $twoWay = false, string $id = '', string $twoWayKey = ''): bool + { + return true; + } + + /** + * Update Relationship + * + * @param string $collection + * @param string $relatedCollection + * @param string $type + * @param bool $twoWay + * @param string $key + * @param string $twoWayKey + * @param string|null $newKey + * @param string|null $newTwoWayKey + * @return bool + */ + public function updateRelationship(string $collection, string $relatedCollection, string $type, bool $twoWay, string $key, string $twoWayKey, ?string $newKey = null, ?string $newTwoWayKey = null): bool + { + return true; + } + + /** + * Delete Relationship + * + * @param string $collection + * @param string $relatedCollection + * @param string $type + * @param bool $twoWay + * @param string $key + * @param string $twoWayKey + * @param string $side + * @return bool + */ + public function deleteRelationship(string $collection, string $relatedCollection, string $type, bool $twoWay, string $key, string $twoWayKey, string $side): bool + { + return true; + } + + /** + * Rename Index + * + * @param string $collection + * @param string $old + * @param string $new + * @return bool + */ + public function renameIndex(string $collection, string $old, string $new): bool + { + return true; + } + + /** + * Create Index + * + * @param string $collection + * @param string $id + * @param string $type + * @param array $attributes + * @param array $lengths + * @param array $orders + * + * @return bool + */ + public function createIndex(string $collection, string $id, string $type, array $attributes, array $lengths, array $orders): bool + { + return true; + } + + /** + * Delete Index + * + * @param string $collection + * @param string $id + * + * @return bool + */ + public function deleteIndex(string $collection, string $id): bool + { + return true; + } + + /** + * Get Document + * + * @param string $collection + * @param string $id + * @param array $queries + * @return Document + */ + public function getDocument(string $collection, string $id, array $queries = []): Document + { + $tableName = "{$this->getNamespace()}_{$collection}"; + $id = $this->filter($id); + + $selections = $this->getAttributeSelections($queries); + + $queryParams = [ + 'TableName' => $tableName, + 'IndexName' => '_uid', + 'KeyConditionExpression' => '#uid = :uid', + 'ExpressionAttributeValues' => [ ':uid' => [ 'S' => $id ] ], + 'ExpressionAttributeNames' => [ '#uid' => '_uid' ], + ]; + + if (!empty($selections) && !\in_array('*', $selections)) { + $queryParams['ProjectionExpression'] = $this->getAttributeProjection($selections); + $queryParams['ExpressionAttributeNames'] = [ + '#uid' => '_uid', + '#id' => '_id', + '#createdAt' => '_createdAt', + '#updatedAt'=> '_updatedAt', + '#permissions' => '_permissions' + ]; + } + + $result = $this->client->query($queryParams); + + $result = $result['Items']; + + if (empty($result)) { + return new Document([]); + } + + $document = []; + + foreach ($result[0] as $resultKey => $resultAttributes) { + foreach ($resultAttributes as $attribute) { + $document[$resultKey] = $attribute; + } + } + + if (\array_key_exists('_id', $document)) { + $document['$internalId'] = $document['_id']; + unset($document['_id']); + } + if (\array_key_exists('_uid', $document)) { + $document['$id'] = $document['_uid']; + unset($document['_uid']); + } + if (\array_key_exists('_createdAt', $document)) { + $epoch = $document['_createdAt']; + $document['$createdAt'] = DateTime::format(new \DateTime("@$epoch")); + unset($document['_createdAt']); + } + if (\array_key_exists('_updatedAt', $document)) { + $epoch = $document['_updatedAt']; + $document['$updatedAt'] = DateTime::format(new \DateTime("@$epoch")); + unset($document['_updatedAt']); + } + if (\array_key_exists('_permissions', $document)) { + $document['$permissions'] = json_decode($document['_permissions'] ?? '[]', true); + unset($document['_permissions']); + } + + return new Document($document); + } + + protected function getAttributeValueType(mixed $attributeValue): string + { + $dataType = gettype($attributeValue); + if (\in_array($dataType, ['integer', 'double'])) { + return DynamoDB::VAR_NUMBER; + } else if (\in_array($dataType, ['boolean'])) { + return DynamoDB::VAR_BOOL; + } else if (\in_array($dataType, ['string', 'array', 'object'])) { + return DynamoDB::VAR_STRING; + } else if (\in_array($dataType, ['resource', 'unknown type'])) { + return DynamoDB::VAR_BINARY; + } else { + return DynamoDB::VAR_NULL; + } + } + + protected function getGuidv4($data = null): string { + // Generate 16 bytes (128 bits) of random data or use the data passed into the function. + $data = $data ?? random_bytes(16); + assert(strlen($data) == 16); + + // Set version to 0100 + $data[6] = chr(ord($data[6]) & 0x0f | 0x40); + // Set bits 6-7 to 10 + $data[8] = chr(ord($data[8]) & 0x3f | 0x80); + + // Output the 36 character UUID. + return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); + } + + /** + * Create Document + * + * @param string $collection + * @param Document $document + * + * @return Document + */ + public function createDocument(string $collection, Document $document): Document + { + $tableName = $this->getNamespace() . '_' . $this->filter($collection); + $internalId = $document->getInternalId(); + $documentUid = $document->getId(); + $document->removeAttribute('$internalId'); + + $documentAttributes = []; + + if (\array_key_exists('$id', (array)$document)) { + $documentAttributes['_uid'] = [ 'S' => $document['$id'] ]; + unset($document['$id']); + } + if (\array_key_exists('$createdAt', (array)$document)) { + $documentAttributes['_createdAt'] = [ 'N' => \strtotime($document['$createdAt']) ]; + unset($document['$createdAt']); + } + if (\array_key_exists('$updatedAt', (array)$document)) { + $documentAttributes['_updatedAt'] = [ 'N' => \strtotime($document['$updatedAt']) ]; + unset($document['$updatedAt']); + } + if (\array_key_exists('$permissions', (array)$document)) { + $documentAttributes['_permissions'] = [ 'S' => json_encode($document['$permissions'] ?? []) ]; + unset($document['$permissions']); + } + + if (empty($internalId)) { + $internalId = $this->getGuidv4(); + } + $documentAttributes['_id'] = [ 'S' => $internalId ]; + + foreach ((array)$document as $documentAttributeKey => $documentAttributeValue) { + $documentAttributes[$documentAttributeKey] = [ $this->getAttributeValueType($documentAttributeValue) => $documentAttributeValue]; + } + + // echo(json_encode($documentAttributes)); + + $this->client->putItem([ + 'Item' => $documentAttributes, + 'TableName' => $tableName, + ]); + + return $this->getDocument($collection, $documentUid); + } + + /** + * Update Document + * + * @param string $collection + * @param Document $document + * + * @return Document + */ + public function updateDocument(string $collection, Document $document): Document + { + return $this->createDocument($collection, $document); + } + + /** + * Delete Document + * + * @param string $collection + * @param string $id + * + * @return bool + */ + public function deleteDocument(string $collection, string $id): bool + { + $tableName = $this->getNamespace() . '_' . $this->filter($collection); + $document = $this->getDocument($collection, $id, [Query::select(['$id'])]); + $result = $this->client->deleteItem([ + 'Key' => [ '_id' => [ 'S' => $document->getInternalId() ] ], + 'TableName' => $tableName, + ]); + return (!!$result); + } + + /** + * Find Documents + * + * Find data sets using chosen queries + * + * @param string $collection + * @param array $queries + * @param int|null $limit + * @param int|null $offset + * @param array $orderAttributes + * @param array $orderTypes + * @param array $cursor + * @param string $cursorDirection + * @param int|null $timeout + * + * @return array + */ + public function find(string $collection, array $queries = [], ?int $limit = 25, ?int $offset = null, array $orderAttributes = [], array $orderTypes = [], array $cursor = [], string $cursorDirection = Database::CURSOR_AFTER, ?int $timeout = null): array + { + return []; + } + + /** + * Sum an attribute + * + * @param string $collection + * @param string $attribute + * @param array $queries + * @param int|null $max + * + * @return int|float + */ + public function sum(string $collection, string $attribute, array $queries = [], ?int $max = null, ?int $timeout = null): float|int + { + return 0; + } + + /** + * Count Documents + * + * @param string $collection + * @param array $queries + * @param int|null $max + * + * @return int + */ + public function count(string $collection, array $queries = [], ?int $max = null, ?int $timeout = null): int + { + return 0; + } + + /** + * Get Collection Size + * + * @param string $collection + * @return int + * @throws DatabaseException + */ + public function getSizeOfCollection(string $collection): int + { + return 0; + } + + /** + * Get max STRING limit + * + * DynamoDb string limits are governed by item size limit at 400 Kb - using MariaDB Limit for now. + * + * @return int + */ + public function getLimitForString(): int + { + return 4294967295; + } + + /** + * Get max INT limit + * + * The actual limit is 9.9999999999999999999999999999999999999E+125 but the PHP Limit is obviously much less. + * + * @return int + */ + public function getLimitForInt(): int + { + return PHP_INT_MAX; + } + + /** + * Get maximum attributes limit. + * + * @return int + */ + public function getLimitForAttributes(): int + { + return 0; + } + + + /** + * Get maximum index limit. + * + * DynamoDb limit for Global Secondary Indexes. + * @return int + */ + public function getLimitForIndexes(): int + { + return 20; + } + + /** + * Is schemas supported? + * + * @return bool + */ + public function getSupportForSchemas(): bool + { + return true; + } + + /** + * Is index supported? + * + * @return bool + */ + public function getSupportForIndex(): bool + { + return true; + } + + /** + * Is unique index supported? + * + * @return bool + */ + public function getSupportForUniqueIndex(): bool + { + return true; + } + + /** + * Is fulltext index supported? + * + * @return bool + */ + public function getSupportForFulltextIndex(): bool + { + return true; + } + + /** + * Is fulltext wildcard supported? + * + * @return bool + */ + public function getSupportForFulltextWildcardIndex(): bool + { + return true; + } + + + /** + * Does the adapter handle casting? + * + * @return bool + */ + public function getSupportForCasting(): bool + { + return true; + } + + /** + * Does the adapter handle array Contains? + * + * @return bool + */ + public function getSupportForQueryContains(): bool + { + return true; + } + + /** + * Are timeouts supported? + * + * @return bool + */ + public function getSupportForTimeouts(): bool + { + return true; + } + + /** + * Are relationships supported? + * + * @return bool + */ + public function getSupportForRelationships(): bool + { + return false; + } + + /** + * Get current attribute count from collection document + * + * @param Document $collection + * @return int + */ + public function getCountOfAttributes(Document $collection): int + { + return 0; + } + + /** + * Get current index count from collection document + * + * @param Document $collection + * @return int + */ + public function getCountOfIndexes(Document $collection): int + { + return 0; + } + + /** + * Returns number of attributes used by default. + * + * @return int + */ + public static function getCountOfDefaultAttributes(): int + { + return 0; + } + + /** + * Returns number of indexes used by default. + * + * @return int + */ + public static function getCountOfDefaultIndexes(): int + { + return 0; + } + + /** + * Get maximum width, in bytes, allowed for a SQL row + * Return 0 when no restrictions apply + * + * @return int + */ + public static function getDocumentSizeLimit(): int + { + return 0; + } + + /** + * Estimate maximum number of bytes required to store a document in $collection. + * Byte requirement varies based on column type and size. + * Needed to satisfy MariaDB/MySQL row width limit. + * Return 0 when no restrictions apply to row width + * + * @param Document $collection + * @return int + */ + public function getAttributeWidth(Document $collection): int + { + return 0; + } + + /** + * Get list of keywords that cannot be used + * + * @return array + */ + public function getKeywords(): array + { + return []; + } + + /** + * Get an attribute projection given a list of selected attributes + * + * @param array $selections + * @param string $prefix + * @return mixed + */ + protected function getAttributeProjection(array $selections, string $prefix = ''): mixed + { + $projection = ['#uid', '#id', '#createdAt', '#updatedAt', '#permissions']; + + foreach ($selections as $selection) { + // Skip internal attributes since all are selected by default + if (\in_array($selection, Database::INTERNAL_ATTRIBUTES)) { + continue; + } + + \array_push($projection, $selection); + } + return \implode(", ", $projection); + } + + /** + * Increase and Decrease Attribute Value + * + * @param string $collection + * @param string $id + * @param string $attribute + * @param int|float $value + * @param int|float|null $min + * @param int|float|null $max + * @return bool + * @throws Exception + */ + public function increaseDocumentAttribute(string $collection, string $id, string $attribute, int|float $value, int|float|null $min = null, int|float|null $max = null): bool + { + return true; + } + + /** + * @return int + */ + public function getMaxIndexLength(): int + { + return 0; + } +} \ No newline at end of file diff --git a/tests/Database/Adapter/DynamoDBTest.php b/tests/Database/Adapter/DynamoDBTest.php new file mode 100644 index 000000000..76a83c1a9 --- /dev/null +++ b/tests/Database/Adapter/DynamoDBTest.php @@ -0,0 +1,60 @@ +connect('redis', 6379); + $redis->flushAll(); + $cache = new Cache(new RedisAdapter($redis)); + + $schema = 'utopiaTests'; // same as $this->testDatabase + $client = new Client(['region' => 'us-west-2', 'version' => 'latest', 'endpoint' => 'http://dynamodb:8012']); + + $database = new Database(new DynamoDB($client), $cache); + $database->setDefaultDatabase($schema); + $database->setNamespace('myapp_' . uniqid()); + + if ($database->exists('utopiaTests')) { + $database->delete('utopiaTests'); + } + + $database->create(); + + return self::$database = $database; + } + +}