From da8961dd302a0f78b9e35fbc7c94ee0bada92304 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Mon, 2 Oct 2023 18:04:51 +0530 Subject: [PATCH 01/20] Add AWS SDK Dependency --- composer.json | 3 +- composer.lock | 1075 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 953 insertions(+), 125 deletions(-) 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" } From 30dcb32702c6c17f5b0bf0a19a4b146fea3a8bd1 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Mon, 2 Oct 2023 21:08:30 +0530 Subject: [PATCH 02/20] add local dynamodb container to test the adapter --- docker-compose.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 296cd6095..c208db5ff 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -74,6 +74,15 @@ 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" + redis: image: redis:6.0-alpine container_name: utopia-redis From 5cb9953eb5a0fdd2dfa3432cd1ff268448a08d7d Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Mon, 2 Oct 2023 21:09:37 +0530 Subject: [PATCH 03/20] add template for adapter and test --- src/Database/Adapter/DynamoDB.php | 618 ++++++++++++++++++++++++ tests/Database/Adapter/DynamoDBTest.php | 60 +++ 2 files changed, 678 insertions(+) create mode 100644 src/Database/Adapter/DynamoDB.php create mode 100644 tests/Database/Adapter/DynamoDBTest.php diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php new file mode 100644 index 000000000..b90f3c4fa --- /dev/null +++ b/src/Database/Adapter/DynamoDB.php @@ -0,0 +1,618 @@ +client = $client; + } + + /** + * Ping Database + * + * @return bool + */ + public function ping(): bool + { + return true; + } + + /** + * Create Database + * + * @param string $name + * + * @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 + { + return true; + } + + /** + * List Databases + * + * @return array + */ + public function list(): array + { + return []; + } + + /** + * Delete Database + * + * @param string $name + * + * @return bool + */ + public function delete(string $name): bool + { + return true; + } + + /** + * 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 + { + return true; + } + + /** + * Delete Collection + * + * @param string $name + * + * @return bool + */ + public function deleteCollection(string $name): bool + { + 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 + { + 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 + { + 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 + { + return new Document(); + } + + /** + * Create Document + * + * @param string $collection + * @param Document $document + * + * @return Document + */ + public function createDocument(string $collection, Document $document): Document + { + return new Document(); + } + + /** + * Update Document + * + * @param string $collection + * @param Document $document + * + * @return Document + */ + public function updateDocument(string $collection, Document $document): Document + { + return new Document(); + } + + /** + * Delete Document + * + * @param string $collection + * @param string $id + * + * @return bool + */ + public function deleteDocument(string $collection, string $id): bool + { + return true; + } + + /** + * 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 + * + * @return int + */ + public function getLimitForString(): int + { + return 0; + } + + /** + * Get max INT limit + * + * @return int + */ + public function getLimitForInt(): int + { + return 0; + } + + /** + * Get maximum attributes limit. + * + * @return int + */ + public function getLimitForAttributes(): int + { + return 0; + } + + + /** + * Get maximum index limit. + * + * @return int + */ + public function getLimitForIndexes(): int + { + return 0; + } + + /** + * 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 true; + } + + /** + * 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 + { + return false; + } + + /** + * 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..48e989540 --- /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://localhost: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; + } + +} From 6469588d85b343b41c374b7e0ea7380eebab3152 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Tue, 3 Oct 2023 00:38:17 +0530 Subject: [PATCH 04/20] add create and exists function --- src/Database/Adapter/DynamoDB.php | 199 +++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 1 deletion(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index b90f3c4fa..a0244fc36 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -8,13 +8,33 @@ use Utopia\Database\Database; use Utopia\Database\Query; use Utopia\Database\Exception as DatabaseException; +use Aws\DynamoDb\Exception\DynamoDbException; use Aws\DynamoDb\DynamoDbClient as Client; class DynamoDB extends Adapter { + // Data types + public const VAR_STRING = 'S'; + public const VAR_NUMBER = 'N'; + public const VAR_BINARY = 'B'; + + // Index types + public const SIMPLE_INDEX = 'SIMPLE'; + public const COMPOSITE_INDEX = 'COMPOSITE'; protected Client $client; + /** + * @return Client + * + * @throws Exception + */ + protected function getClient(): Client + { + return $this->client; + } + + public function __construct(Client $client) { @@ -23,7 +43,8 @@ public function __construct(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 @@ -36,6 +57,7 @@ public function ping(): bool * * @param string $name * + * No concept of Database schemas in DynamoDb. * @return bool */ public function create(string $name): bool @@ -54,12 +76,23 @@ public function create(string $name): 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 @@ -72,6 +105,7 @@ public function list(): array * * @param string $name * + * No concept of Database schemas in DynamoDb. * @return bool */ public function delete(string $name): bool @@ -79,6 +113,25 @@ public function delete(string $name): bool return true; } + /** + * Get DynamoDb Type + * + * @param string $type + * @param int $size in chars + * + * @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 * @@ -89,6 +142,150 @@ public function delete(string $name): bool */ public function createCollection(string $name, array $attributes = [], array $indexes = []): bool { + $tableName = "{$this->getNamespace()}_{$this->filter($name)}"; + + $attributeDefinitions = [ + [ + 'AttributeName' => '_id', + 'AttributeType' => DynamoDB::VAR_NUMBER, + ], + [ + 'AttributeName' => '_uid', + 'AttributeType' => DynamoDB::VAR_STRING, + ], + [ + 'AttributeName' => '_createdAt', + 'AttributeType' => DynamoDB::VAR_NUMBER, + ], + [ + 'AttributeName' => '_updatedAt', + 'AttributeType' => DynamoDB::VAR_NUMBER, + ], + [ + 'AttributeName' => '_permissions', + 'AttributeType' => DynamoDB::VAR_STRING, + ] + ]; + + $permsAttributeDefinitions = [ + [ + 'AttributeName' => '_id', + 'AttributeType' => DynamoDB::VAR_NUMBER, + ], + [ + 'AttributeName' => '_type', + 'AttributeType' => DynamoDB::VAR_STRING, + ], + [ + 'AttributeName' => '_permission', + 'AttributeType' => DynamoDB::VAR_STRING, + ], + [ + 'AttributeName' => '_document', + 'AttributeType' => DynamoDB::VAR_STRING, + ] + ]; + + $globalIndexes = [ + [ + 'IndexName' => '_uid', + 'KeySchema' => [ + [ + 'AttributeName' => '_uid', + 'KeyType' => 'HASH', + ], + ], + 'Projection' => [ + 'ProjectionType' => 'ALL', + ], + ], + ]; + + $permsGlobalIndexes = [ + [ + 'IndexName' => "index_{$tableName}_ukey", + 'KeySchema' => [ + [ + 'AttributeName' => '_document', + 'KeyType' => 'HASH', + ], + [ + 'AttributeName' => '_permission', + 'KeyType' => 'RANGE' + ] + ], + 'Projection' => [ + 'ProjectionType' => 'ALL', + ], + ], + ]; + + foreach ($attributes as $attribute) { + $attrId = $this->filter($attribute->getId()); + $attrType = $this->getDynamoDbType($attribute->getAttribute('type')); + + $attributeDef = [ + 'AttributeName' => $attrId, + 'AttributeType' => $attrType, + ]; + + array_push($attributeDefinitions, $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', + ] + ]; + if ($indexType == DynamoDB::COMPOSITE_INDEX) { + array_push($globalIndex['KeySchema'], [ + 'AttributeName' => $indexAttributes[1], + 'KeyType' => 'RANGE', + ]); + } + array_push($globalIndexes, $globalIndex); + } + + $params = [ + 'TableName' => $tableName, + 'AttributeDefinitions' => $attributeDefinitions, + 'KeySchema' => [ + [ + 'AttributeName' => '_id', + 'KeyType' => 'HASH', + ], + ], + 'GlobalSecondaryIndexes' => $globalIndexes, + ]; + + $permsParams = [ + 'TableName' => "{$tableName}_perms", + 'AttributeDefinitions' => $permsAttributeDefinitions, + 'KeySchema' => [ + [ + 'AttributeName' => '_id', + 'KeyType' => 'HASH', + ], + ], + 'GlobalSecondaryIndexes' => $permsGlobalIndexes, + ]; + + $this->client->createTable($params); + $this->client->createTable($permsParams); + return true; } From f9d13226ddb0bea47d3dac7695d44b5835ba919d Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Tue, 3 Oct 2023 01:24:43 +0530 Subject: [PATCH 05/20] fix environment --- docker-compose.yml | 3 +++ src/Database/Adapter/DynamoDB.php | 1 - tests/Database/Adapter/DynamoDBTest.php | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index c208db5ff..aae8fad1d 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 diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index a0244fc36..4a28595cc 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -117,7 +117,6 @@ public function delete(string $name): bool * Get DynamoDb Type * * @param string $type - * @param int $size in chars * * @return string */ diff --git a/tests/Database/Adapter/DynamoDBTest.php b/tests/Database/Adapter/DynamoDBTest.php index 48e989540..76a83c1a9 100644 --- a/tests/Database/Adapter/DynamoDBTest.php +++ b/tests/Database/Adapter/DynamoDBTest.php @@ -42,7 +42,7 @@ public static function getDatabase(): Database $cache = new Cache(new RedisAdapter($redis)); $schema = 'utopiaTests'; // same as $this->testDatabase - $client = new Client(['region' => 'us-west-2', 'version' => 'latest', 'endpoint' => 'http://localhost:8012']); + $client = new Client(['region' => 'us-west-2', 'version' => 'latest', 'endpoint' => 'http://dynamodb:8012']); $database = new Database(new DynamoDB($client), $cache); $database->setDefaultDatabase($schema); From 6967f8e1a4a9b497799c226c6b60df5e4db60be4 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Tue, 3 Oct 2023 01:47:59 +0530 Subject: [PATCH 06/20] fix errors on CreateTable --- src/Database/Adapter/DynamoDB.php | 71 ++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 6 deletions(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index 4a28595cc..2d5f57c5f 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -198,11 +198,47 @@ public function createCollection(string $name, array $attributes = [], array $in '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', + ], + ], ]; $permsGlobalIndexes = [ [ - 'IndexName' => "index_{$tableName}_ukey", + 'IndexName' => "index_{$tableName}_document_permission", 'KeySchema' => [ [ 'AttributeName' => '_document', @@ -217,8 +253,26 @@ public function createCollection(string $name, array $attributes = [], array $in 'ProjectionType' => 'ALL', ], ], + [ + 'IndexName' => "index_{$tableName}_document_type", + 'KeySchema' => [ + [ + 'AttributeName' => '_document', + 'KeyType' => 'HASH', + ], + [ + 'AttributeName' => '_type', + 'KeyType' => 'RANGE' + ] + ], + 'Projection' => [ + 'ProjectionType' => 'ALL', + ], + ], ]; + $attributeDefMap = []; + foreach ($attributes as $attribute) { $attrId = $this->filter($attribute->getId()); $attrType = $this->getDynamoDbType($attribute->getAttribute('type')); @@ -228,7 +282,7 @@ public function createCollection(string $name, array $attributes = [], array $in 'AttributeType' => $attrType, ]; - array_push($attributeDefinitions, $attributeDef); + $attributeDefMap[$attrId] = $attributeDef; } foreach ($indexes as $index) { @@ -242,24 +296,28 @@ public function createCollection(string $name, array $attributes = [], array $in 'ProjectionType' => 'ALL', ], ]; - + $globalIndex['KeySchema'] = [ - [ - 'AttributeName' => $indexAttributes[0], - 'KeyType' => 'HASH', + [ + '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); } $params = [ 'TableName' => $tableName, + 'BillingMode' => 'PAY_PER_REQUEST', 'AttributeDefinitions' => $attributeDefinitions, 'KeySchema' => [ [ @@ -272,6 +330,7 @@ public function createCollection(string $name, array $attributes = [], array $in $permsParams = [ 'TableName' => "{$tableName}_perms", + 'BillingMode' => 'PAY_PER_REQUEST', 'AttributeDefinitions' => $permsAttributeDefinitions, 'KeySchema' => [ [ From b437ed92358732c5ab7c9410a9e1054ffbca5be7 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Sun, 8 Oct 2023 00:01:49 +0530 Subject: [PATCH 07/20] fix create collection as per mongo adapter --- src/Database/Adapter/DynamoDB.php | 76 +++---------------------------- 1 file changed, 6 insertions(+), 70 deletions(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index 2d5f57c5f..11e372dd7 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -142,6 +142,10 @@ protected function getDynamoDbType(string $type): string 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 = [ [ @@ -165,25 +169,6 @@ public function createCollection(string $name, array $attributes = [], array $in 'AttributeType' => DynamoDB::VAR_STRING, ] ]; - - $permsAttributeDefinitions = [ - [ - 'AttributeName' => '_id', - 'AttributeType' => DynamoDB::VAR_NUMBER, - ], - [ - 'AttributeName' => '_type', - 'AttributeType' => DynamoDB::VAR_STRING, - ], - [ - 'AttributeName' => '_permission', - 'AttributeType' => DynamoDB::VAR_STRING, - ], - [ - 'AttributeName' => '_document', - 'AttributeType' => DynamoDB::VAR_STRING, - ] - ]; $globalIndexes = [ [ @@ -236,41 +221,6 @@ public function createCollection(string $name, array $attributes = [], array $in ], ]; - $permsGlobalIndexes = [ - [ - 'IndexName' => "index_{$tableName}_document_permission", - 'KeySchema' => [ - [ - 'AttributeName' => '_document', - 'KeyType' => 'HASH', - ], - [ - 'AttributeName' => '_permission', - 'KeyType' => 'RANGE' - ] - ], - 'Projection' => [ - 'ProjectionType' => 'ALL', - ], - ], - [ - 'IndexName' => "index_{$tableName}_document_type", - 'KeySchema' => [ - [ - 'AttributeName' => '_document', - 'KeyType' => 'HASH', - ], - [ - 'AttributeName' => '_type', - 'KeyType' => 'RANGE' - ] - ], - 'Projection' => [ - 'ProjectionType' => 'ALL', - ], - ], - ]; - $attributeDefMap = []; foreach ($attributes as $attribute) { @@ -315,7 +265,7 @@ public function createCollection(string $name, array $attributes = [], array $in array_push($globalIndexes, $globalIndex); } - $params = [ + $createTableParams = [ 'TableName' => $tableName, 'BillingMode' => 'PAY_PER_REQUEST', 'AttributeDefinitions' => $attributeDefinitions, @@ -328,21 +278,7 @@ public function createCollection(string $name, array $attributes = [], array $in 'GlobalSecondaryIndexes' => $globalIndexes, ]; - $permsParams = [ - 'TableName' => "{$tableName}_perms", - 'BillingMode' => 'PAY_PER_REQUEST', - 'AttributeDefinitions' => $permsAttributeDefinitions, - 'KeySchema' => [ - [ - 'AttributeName' => '_id', - 'KeyType' => 'HASH', - ], - ], - 'GlobalSecondaryIndexes' => $permsGlobalIndexes, - ]; - - $this->client->createTable($params); - $this->client->createTable($permsParams); + $this->client->createTable($createTableParams); return true; } From 97838a6e7d0300021a2598ea123a644d8ffa120c Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Sun, 8 Oct 2023 00:02:50 +0530 Subject: [PATCH 08/20] add support for delete collection / attribute --- src/Database/Adapter/DynamoDB.php | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index 11e372dd7..3e7ccfb2d 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -292,6 +292,14 @@ public function createCollection(string $name, array $attributes = [], array $in */ 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; } @@ -338,6 +346,24 @@ public function updateAttribute(string $collection, string $id, string $type, in */ public function deleteAttribute(string $collection, string $id): bool { + $collection = $this->filter($collection); + $queryParams = [ + 'TableName' => "{$this->getNamespace()}_{$collection}", + 'ProjectionExpression' => '_id' + ]; + $items = ($this->client->query($queryParams))['Items']; + foreach ($items as $item) { + $updateParams = [ + 'TableName' => "{$this->getNamespace()}_{$collection}", + 'Key' => ['_id' => $item['_id']], // Replace with your primary key + 'UpdateExpression' => 'REMOVE ' . $id, + ]; + try { + $this->client->updateItem($updateParams); + } catch (DynamoDbException $e) { + return false; + } + } return true; } From c43c686d328e97e8467467f0e76e08bb7305adeb Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Sun, 8 Oct 2023 02:23:29 +0530 Subject: [PATCH 09/20] add dynamo db admin on port 8705 --- docker-compose.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index aae8fad1d..7e9a1a914 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -85,6 +85,19 @@ services: - 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 From 67170aa83353d8b9daeac175bb9f5b8d0a71f460 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Sun, 8 Oct 2023 02:24:54 +0530 Subject: [PATCH 10/20] fix delete and add renameAttribute --- src/Database/Adapter/DynamoDB.php | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index 3e7ccfb2d..7c2c001b1 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -347,6 +347,7 @@ public function updateAttribute(string $collection, string $id, string $type, in public function deleteAttribute(string $collection, string $id): bool { $collection = $this->filter($collection); + $id = $this->filter($id); $queryParams = [ 'TableName' => "{$this->getNamespace()}_{$collection}", 'ProjectionExpression' => '_id' @@ -355,8 +356,8 @@ public function deleteAttribute(string $collection, string $id): bool foreach ($items as $item) { $updateParams = [ 'TableName' => "{$this->getNamespace()}_{$collection}", - 'Key' => ['_id' => $item['_id']], // Replace with your primary key - 'UpdateExpression' => 'REMOVE ' . $id, + 'Key' => ['_id' => [ 'N' => $item['_id']]], // Replace with your primary key + 'UpdateExpression' => "REMOVE {$id}", ]; try { $this->client->updateItem($updateParams); @@ -377,6 +378,31 @@ public function deleteAttribute(string $collection, string $id): 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}", + ]; + $items = ($this->client->query($queryParams))['Items']; + foreach ($items as $item) { + $oldItemValues = $item[$old]; + $oldItemValue = null; + foreach ($oldItemValues as $value) { + $oldItemValue = $value; + } + $updateParams = [ + 'TableName' => "{$this->getNamespace()}_{$collection}", + 'Key' => ['_id' => [ 'N' => $item['_id']['N']]], // Replace with your primary key + 'UpdateExpression' => "SET {$new} = {$oldItemValue} REMOVE {$old}", + ]; + try { + $this->client->updateItem($updateParams); + } catch (DynamoDbException $e) { + return false; + } + } return true; } From 7fe211ef5d77769fe8b86b69d082ca9cb6f21910 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Sun, 8 Oct 2023 02:50:35 +0530 Subject: [PATCH 11/20] declare no support for relationships --- src/Database/Adapter/DynamoDB.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index 7c2c001b1..672c1263e 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -742,7 +742,7 @@ public function getSupportForTimeouts(): bool */ public function getSupportForRelationships(): bool { - return true; + return false; } /** From 42dba49b237b7a9923b12693532bb09e103933f6 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Sun, 8 Oct 2023 02:51:23 +0530 Subject: [PATCH 12/20] add get document --- src/Database/Adapter/DynamoDB.php | 72 ++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index 672c1263e..5f3eaaf15 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -508,7 +508,65 @@ public function deleteIndex(string $collection, string $id): bool */ public function getDocument(string $collection, string $id, array $queries = []): Document { - return new Document(); + $tableName = "{$this->getNamespace()}_{$collection}"; + $id = $this->filter($id); + + $selections = $this->getAttributeSelections($queries); + + $getItemParams = [ + 'TableName' => $tableName, + 'IndexName' => '_uid', + 'KeyConditionExpression' => '#uid = :uid', + 'ExpressionAttributeValues' => [ + ':uid' => [ + 'S' => $id, + ], + ], + 'ExpressionAttributeNames' => [ '#uid' => '_uid' ], + ]; + + if (!empty($selections) && !\in_array('*', $selections)) { + $getItemParams['ProjectionExpression'] = $this->getAttributeProjection($selections); + } + + $result = $this->client->query($getItemParams); + + $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'] = $result['_id']; + unset($document['_id']); + } + if (\array_key_exists('_uid', $document)) { + $document['$id'] = $document['_uid']; + unset($document['_uid']); + } + if (\array_key_exists('_createdAt', $document)) { + $document['$createdAt'] = $document['_createdAt']; + unset($document['_createdAt']); + } + if (\array_key_exists('_updatedAt', $document)) { + $document['$updatedAt'] = $document['_updatedAt']; + unset($document['_updatedAt']); + } + if (\array_key_exists('_permissions', $document)) { + $document['$permissions'] = json_decode($document['_permissions'] ?? '[]', true); + unset($document['_permissions']); + } + + return new Document($document); } /** @@ -831,7 +889,17 @@ public function getKeywords(): array */ protected function getAttributeProjection(array $selections, string $prefix = ''): mixed { - return false; + $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); } /** From 3f7bd05a8067ae1ea28d740c93445adb3b5e578c Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Mon, 9 Oct 2023 00:54:55 +0530 Subject: [PATCH 13/20] Change internal id type to string --- src/Database/Adapter/DynamoDB.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index 5f3eaaf15..88d5f3b7e 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -150,7 +150,7 @@ public function createCollection(string $name, array $attributes = [], array $in $attributeDefinitions = [ [ 'AttributeName' => '_id', - 'AttributeType' => DynamoDB::VAR_NUMBER, + 'AttributeType' => DynamoDB::VAR_STRING, ], [ 'AttributeName' => '_uid', @@ -356,7 +356,7 @@ public function deleteAttribute(string $collection, string $id): bool foreach ($items as $item) { $updateParams = [ 'TableName' => "{$this->getNamespace()}_{$collection}", - 'Key' => ['_id' => [ 'N' => $item['_id']]], // Replace with your primary key + 'Key' => ['_id' => [ 'S' => $item['_id']]], // Replace with your primary key 'UpdateExpression' => "REMOVE {$id}", ]; try { @@ -394,7 +394,7 @@ public function renameAttribute(string $collection, string $old, string $new): b } $updateParams = [ 'TableName' => "{$this->getNamespace()}_{$collection}", - 'Key' => ['_id' => [ 'N' => $item['_id']['N']]], // Replace with your primary key + 'Key' => ['_id' => [ 'S' => $item['_id']['S']]], // Replace with your primary key 'UpdateExpression' => "SET {$new} = {$oldItemValue} REMOVE {$old}", ]; try { From 14c27d0bc640db3127a79bcef7ae0e78a2cc037f Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Mon, 9 Oct 2023 00:58:27 +0530 Subject: [PATCH 14/20] add string int and index limits for dynamodb --- src/Database/Adapter/DynamoDB.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index 88d5f3b7e..271f7d5dd 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -673,22 +673,26 @@ public function getSizeOfCollection(string $collection): int /** * 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 0; + 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 0; + return PHP_INT_MAX; } /** @@ -705,11 +709,12 @@ public function getLimitForAttributes(): int /** * Get maximum index limit. * + * DynamoDb limit for Global Secondary Indexes. * @return int */ public function getLimitForIndexes(): int { - return 0; + return 20; } /** From 4192386d0d66380938cf09b3e44c7d4194c18c70 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Mon, 9 Oct 2023 01:02:35 +0530 Subject: [PATCH 15/20] fix get document --- src/Database/Adapter/DynamoDB.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index 271f7d5dd..5ea2ae45f 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -6,6 +6,7 @@ use Utopia\Database\Adapter; use Utopia\Database\Document; use Utopia\Database\Database; +use Utopia\Database\DateTime; use Utopia\Database\Query; use Utopia\Database\Exception as DatabaseException; use Aws\DynamoDb\Exception\DynamoDbException; @@ -546,7 +547,7 @@ public function getDocument(string $collection, string $id, array $queries = []) } if (\array_key_exists('_id', $document)) { - $document['$internalId'] = $result['_id']; + $document['$internalId'] = $document['_id']; unset($document['_id']); } if (\array_key_exists('_uid', $document)) { @@ -554,11 +555,13 @@ public function getDocument(string $collection, string $id, array $queries = []) unset($document['_uid']); } if (\array_key_exists('_createdAt', $document)) { - $document['$createdAt'] = $document['_createdAt']; + $epoch = $document['_createdAt']; + $document['$createdAt'] = DateTime::format(new \DateTime("@$epoch")); unset($document['_createdAt']); } if (\array_key_exists('_updatedAt', $document)) { - $document['$updatedAt'] = $document['_updatedAt']; + $epoch = $document['_updatedAt']; + $document['$updatedAt'] = DateTime::format(new \DateTime("@$epoch")); unset($document['_updatedAt']); } if (\array_key_exists('_permissions', $document)) { From fb8566d56d0c547deab16c88b12a05bbc851858b Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Mon, 9 Oct 2023 01:03:22 +0530 Subject: [PATCH 16/20] add create document and update document --- src/Database/Adapter/DynamoDB.php | 76 ++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index 5ea2ae45f..c129f5a15 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -18,6 +18,8 @@ class DynamoDB extends Adapter public const VAR_STRING = 'S'; public const VAR_NUMBER = 'N'; public const VAR_BINARY = 'B'; + public const VAR_NULL = 'NULL'; + public const VAR_BOOL = 'BOOL'; // Index types public const SIMPLE_INDEX = 'SIMPLE'; @@ -572,6 +574,36 @@ public function getDocument(string $collection, string $id, array $queries = []) 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 * @@ -582,7 +614,47 @@ public function getDocument(string $collection, string $id, array $queries = []) */ public function createDocument(string $collection, Document $document): Document { - return new 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); } /** @@ -595,7 +667,7 @@ public function createDocument(string $collection, Document $document): Document */ public function updateDocument(string $collection, Document $document): Document { - return new Document(); + return $this->createDocument($collection, $document); } /** From 718efd1f9d199a76f826953ac4e80e84ac463d48 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Sat, 14 Oct 2023 21:21:43 +0530 Subject: [PATCH 17/20] fix: $permissions assignment bug in createDocument --- src/Database/Adapter/DynamoDB.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index c129f5a15..e89b2bcf0 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -634,7 +634,7 @@ public function createDocument(string $collection, Document $document): Document unset($document['$updatedAt']); } if (\array_key_exists('$permissions', (array)$document)) { - $documentAttributes['_permissions'] = [ 'S' => json_encode($document['_permissions'] ?? []) ]; + $documentAttributes['_permissions'] = [ 'S' => json_encode($document['$permissions'] ?? []) ]; unset($document['$permissions']); } From 4f6d6a2128f0bb17ce9ca0c8b6697d51feb08b32 Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Sat, 14 Oct 2023 22:09:14 +0530 Subject: [PATCH 18/20] fix: delete and rename attribute to use scan --- src/Database/Adapter/DynamoDB.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index e89b2bcf0..2f01e49dc 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -353,9 +353,10 @@ public function deleteAttribute(string $collection, string $id): bool $id = $this->filter($id); $queryParams = [ 'TableName' => "{$this->getNamespace()}_{$collection}", - 'ProjectionExpression' => '_id' + 'ProjectionExpression' => '#id', + 'ExpressionAttributeNames' => [ '#id' => '_id' ], ]; - $items = ($this->client->query($queryParams))['Items']; + $items = ($this->client->scan($queryParams))['Items']; foreach ($items as $item) { $updateParams = [ 'TableName' => "{$this->getNamespace()}_{$collection}", @@ -386,9 +387,10 @@ public function renameAttribute(string $collection, string $old, string $new): b $new = $this->filter($new); $queryParams = [ 'TableName' => "{$this->getNamespace()}_{$collection}", - 'ProjectionExpression' => "_id, {$old}", + 'ProjectionExpression' => "#id, {$old}", + 'ExpressionAttributeNames' => [ '#id' => '_id' ], ]; - $items = ($this->client->query($queryParams))['Items']; + $items = ($this->client->scan($queryParams))['Items']; foreach ($items as $item) { $oldItemValues = $item[$old]; $oldItemValue = null; From 10f2762b794ed97547618323834741fe0669eb8f Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Sat, 14 Oct 2023 23:35:07 +0530 Subject: [PATCH 19/20] fix: get document with queries --- src/Database/Adapter/DynamoDB.php | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index 2f01e49dc..e5465fa6e 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -518,23 +518,26 @@ public function getDocument(string $collection, string $id, array $queries = []) $selections = $this->getAttributeSelections($queries); - $getItemParams = [ + $queryParams = [ 'TableName' => $tableName, 'IndexName' => '_uid', 'KeyConditionExpression' => '#uid = :uid', - 'ExpressionAttributeValues' => [ - ':uid' => [ - 'S' => $id, - ], - ], + 'ExpressionAttributeValues' => [ ':uid' => [ 'S' => $id ] ], 'ExpressionAttributeNames' => [ '#uid' => '_uid' ], ]; if (!empty($selections) && !\in_array('*', $selections)) { - $getItemParams['ProjectionExpression'] = $this->getAttributeProjection($selections); + $queryParams['ProjectionExpression'] = $this->getAttributeProjection($selections); + $queryParams['ExpressionAttributeNames'] = [ + '#uid' => '_uid', + '#id' => '_id', + '#createdAt' => '_createdAt', + '#updatedAt'=> '_updatedAt', + '#permissions' => '_permissions' + ]; } - $result = $this->client->query($getItemParams); + $result = $this->client->query($queryParams); $result = $result['Items']; @@ -971,7 +974,7 @@ public function getKeywords(): array */ protected function getAttributeProjection(array $selections, string $prefix = ''): mixed { - $projection = ['_uid', '_id', '_createdAt', '_updatedAt', '_permissions']; + $projection = ['#uid', '#id', '#createdAt', '#updatedAt', '#permissions']; foreach ($selections as $selection) { // Skip internal attributes since all are selected by default From 3c5b09a2b1c94498e997be689f211060572fdfab Mon Sep 17 00:00:00 2001 From: Ajwad Shaikh Date: Sat, 14 Oct 2023 23:35:23 +0530 Subject: [PATCH 20/20] feat: add deleteDocument support --- src/Database/Adapter/DynamoDB.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Database/Adapter/DynamoDB.php b/src/Database/Adapter/DynamoDB.php index e5465fa6e..c3df1f2f0 100644 --- a/src/Database/Adapter/DynamoDB.php +++ b/src/Database/Adapter/DynamoDB.php @@ -685,7 +685,13 @@ public function updateDocument(string $collection, Document $document): Document */ public function deleteDocument(string $collection, string $id): bool { - return true; + $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); } /**