diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3ce5adb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +vendor diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..9781acb --- /dev/null +++ b/composer.json @@ -0,0 +1,22 @@ +{ + "name": "bit-badger/pdo-document", + "require": { + "netresearch/jsonmapper": "^4" + }, + "require-dev": { + "phpunit/phpunit": "^11" + }, + "autoload": { + "psr-4": { + "BitBadger\\PDODocument\\": "./src", + "BitBadger\\PDODocument\\Mapper\\": "./src/Mapper", + "BitBadger\\PDODocument\\Query\\": "./src/Query" + } + }, + "autoload-dev": { + "psr-4": { + "Test\\Unit\\": "./tests/unit", + "Test\\Integration\\": "./tests/integration" + } + } +} \ No newline at end of file diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..56df984 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1702 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "38b71eefd32cb528da22dd5908fb8d02", + "packages": [ + { + "name": "netresearch/jsonmapper", + "version": "v4.4.1", + "source": { + "type": "git", + "url": "https://github.com/cweiske/jsonmapper.git", + "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/132c75c7dd83e45353ebb9c6c9f591952995bbf0", + "reference": "132c75c7dd83e45353ebb9c6c9f591952995bbf0", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0", + "squizlabs/php_codesniffer": "~3.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "JsonMapper": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "OSL-3.0" + ], + "authors": [ + { + "name": "Christian Weiske", + "email": "cweiske@cweiske.de", + "homepage": "http://github.com/cweiske/jsonmapper/", + "role": "Developer" + } + ], + "description": "Map nested JSON structures onto PHP classes", + "support": { + "email": "cweiske@cweiske.de", + "issues": "https://github.com/cweiske/jsonmapper/issues", + "source": "https://github.com/cweiske/jsonmapper/tree/v4.4.1" + }, + "time": "2024-01-31T06:18:54+00:00" + } + ], + "packages-dev": [ + { + "name": "myclabs/deep-copy", + "version": "1.11.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2023-03-08T13:26:56+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.0.2", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13", + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2" + }, + "time": "2024-03-05T20:51:40+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "11.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "7e35a2cbcabac0e6865fd373742ea432a3c34f92" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e35a2cbcabac0e6865fd373742ea432a3c34f92", + "reference": "7e35a2cbcabac0e6865fd373742ea432a3c34f92", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.0", + "phpunit/php-text-template": "^4.0", + "sebastian/code-unit-reverse-lookup": "^4.0", + "sebastian/complexity": "^4.0", + "sebastian/environment": "^7.0", + "sebastian/lines-of-code": "^3.0", + "sebastian/version": "^5.0", + "theseer/tokenizer": "^1.2.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/11.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-12T15:35:40+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "99e95c94ad9500daca992354fa09d7b99abe2210" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/99e95c94ad9500daca992354fa09d7b99abe2210", + "reference": "99e95c94ad9500daca992354fa09d7b99abe2210", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T06:05:04+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5d8d9355a16d8cc5a1305b0a85342cfa420612be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5d8d9355a16d8cc5a1305b0a85342cfa420612be", + "reference": "5d8d9355a16d8cc5a1305b0a85342cfa420612be", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T06:05:50+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "d38f6cbff1cdb6f40b03c9811421561668cc133e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/d38f6cbff1cdb6f40b03c9811421561668cc133e", + "reference": "d38f6cbff1cdb6f40b03c9811421561668cc133e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T06:06:56+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "8a59d9e25720482ee7fcdf296595e08795b84dc5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8a59d9e25720482ee7fcdf296595e08795b84dc5", + "reference": "8a59d9e25720482ee7fcdf296595e08795b84dc5", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T06:08:01+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "11.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "d475be032238173ca3b0a516f5cc291d174708ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/d475be032238173ca3b0a516f5cc291d174708ae", + "reference": "d475be032238173ca3b0a516f5cc291d174708ae", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0", + "phpunit/php-file-iterator": "^5.0", + "phpunit/php-invoker": "^5.0", + "phpunit/php-text-template": "^4.0", + "phpunit/php-timer": "^7.0", + "sebastian/cli-parser": "^3.0", + "sebastian/code-unit": "^3.0", + "sebastian/comparator": "^6.0", + "sebastian/diff": "^6.0", + "sebastian/environment": "^7.0", + "sebastian/exporter": "^6.0", + "sebastian/global-state": "^7.0", + "sebastian/object-enumerator": "^6.0", + "sebastian/type": "^5.0", + "sebastian/version": "^5.0" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.1-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.1.3" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2024-04-24T06:34:25+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "00a74d5568694711f0222e54fb281e1d15fdf04a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/00a74d5568694711f0222e54fb281e1d15fdf04a", + "reference": "00a74d5568694711f0222e54fb281e1d15fdf04a", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:26:58+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "6634549cb8d702282a04a774e36a7477d2bd9015" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/6634549cb8d702282a04a774e36a7477d2bd9015", + "reference": "6634549cb8d702282a04a774e36a7477d2bd9015", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T05:50:41+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "df80c875d3e459b45c6039e4d9b71d4fbccae25d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/df80c875d3e459b45c6039e4d9b71d4fbccae25d", + "reference": "df80c875d3e459b45c6039e4d9b71d4fbccae25d", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T05:52:17+00:00" + }, + { + "name": "sebastian/comparator", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "bd0f2fa5b9257c69903537b266ccb80fcf940db8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/bd0f2fa5b9257c69903537b266ccb80fcf940db8", + "reference": "bd0f2fa5b9257c69903537b266ccb80fcf940db8", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T05:53:45+00:00" + }, + { + "name": "sebastian/complexity", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "88a434ad86150e11a606ac4866b09130712671f0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/88a434ad86150e11a606ac4866b09130712671f0", + "reference": "88a434ad86150e11a606ac4866b09130712671f0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T05:55:19+00:00" + }, + { + "name": "sebastian/diff", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "ab83243ecc233de5655b76f577711de9f842e712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ab83243ecc233de5655b76f577711de9f842e712", + "reference": "ab83243ecc233de5655b76f577711de9f842e712", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:30:33+00:00" + }, + { + "name": "sebastian/environment", + "version": "7.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "4eb3a442574d0e9d141aab209cd4aaf25701b09a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4eb3a442574d0e9d141aab209cd4aaf25701b09a", + "reference": "4eb3a442574d0e9d141aab209cd4aaf25701b09a", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/7.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-23T08:56:34+00:00" + }, + { + "name": "sebastian/exporter", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "f291e5a317c321c0381fa9ecc796fa2d21b186da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/f291e5a317c321c0381fa9ecc796fa2d21b186da", + "reference": "f291e5a317c321c0381fa9ecc796fa2d21b186da", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:28:20+00:00" + }, + { + "name": "sebastian/global-state", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "c3a307e832f2e69c7ef869e31fc644fde0e7cb3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/c3a307e832f2e69c7ef869e31fc644fde0e7cb3e", + "reference": "c3a307e832f2e69c7ef869e31fc644fde0e7cb3e", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-03-02T07:32:10+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "376c5b3f6b43c78fdc049740bca76a7c846706c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/376c5b3f6b43c78fdc049740bca76a7c846706c0", + "reference": "376c5b3f6b43c78fdc049740bca76a7c846706c0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T06:00:36+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f75f6c460da0bbd9668f43a3dde0ec0ba7faa678" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f75f6c460da0bbd9668f43a3dde0ec0ba7faa678", + "reference": "f75f6c460da0bbd9668f43a3dde0ec0ba7faa678", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T06:01:29+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "bb2a6255d30853425fd38f032eb64ced9f7f132d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/bb2a6255d30853425fd38f032eb64ced9f7f132d", + "reference": "bb2a6255d30853425fd38f032eb64ced9f7f132d", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T06:02:18+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "b75224967b5a466925c6d54e68edd0edf8dd4ed4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b75224967b5a466925c6d54e68edd0edf8dd4ed4", + "reference": "b75224967b5a466925c6d54e68edd0edf8dd4ed4", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T06:08:48+00:00" + }, + { + "name": "sebastian/type", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "b8502785eb3523ca0dd4afe9ca62235590020f3f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/b8502785eb3523ca0dd4afe9ca62235590020f3f", + "reference": "b8502785eb3523ca0dd4afe9ca62235590020f3f", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T06:09:34+00:00" + }, + { + "name": "sebastian/version", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "13999475d2cb1ab33cb73403ba356a814fdbb001" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/13999475d2cb1ab33cb73403ba356a814fdbb001", + "reference": "13999475d2cb1ab33cb73403ba356a814fdbb001", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-02-02T06:10:47+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/src/Configuration.php b/src/Configuration.php new file mode 100644 index 0000000..dc54040 --- /dev/null +++ b/src/Configuration.php @@ -0,0 +1,32 @@ +code == 0 ? '' : "[$this->code] "; + return __CLASS__ . ": $codeStr$this->message\n"; + } +} diff --git a/src/DocumentList.php b/src/DocumentList.php new file mode 100644 index 0000000..7d5d872 --- /dev/null +++ b/src/DocumentList.php @@ -0,0 +1,36 @@ + The query results as a lazily-iterated generator + */ + public function items(): Generator; + + /** + * Construct a new document list + * + * @param string $query The query to run to retrieve results + * @param array $parameters An associative array of parameters for the query + * @param Mapper $mapper A mapper to deserialize JSON documents + * @return static The `DocumentList`-implementing instance + */ + public static function create(string $query, array $parameters, Mapper $mapper): static; + + /** + * Clean up database connection resources + */ + public function __destruct(); +} diff --git a/src/Field.php b/src/Field.php new file mode 100644 index 0000000..38c7f10 --- /dev/null +++ b/src/Field.php @@ -0,0 +1,176 @@ +op) { + case Op::EX: + case Op::NEX: + break; + case Op::BT: + $existing["{$this->paramName}min"] = $this->value[0]; + $existing["{$this->paramName}max"] = $this->value[1]; + break; + default: + $existing[$this->paramName] = $this->value; + } + return $existing; + } + + /** + * Get the WHERE clause fragment for this parameter + * + * @return string The WHERE clause fragment for this parameter + */ + public function toWhere(): string + { + $criteria = match ($this->op) { + Op::EX, Op::NEX => '', + Op::BT => " {$this->paramName}min AND {$this->paramName}max", + default => " $this->paramName" + }; + $prefix = $this->qualifier == '' ? '' : "$this->qualifier."; + return "{$prefix}data->>'$this->fieldName' " . $this->op->toString() . $criteria; + } + + /** + * Create an equals (=) field criterion + * + * @param string $fieldName The name of the field against which the value will be compared + * @param mixed $value The value for which equality will be checked + * @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank) + * @return static The field with the requested criterion + */ + public static function EQ(string $fieldName, mixed $value, string $paramName = ''): static + { + return new static($fieldName, Op::EQ, $value, $paramName); + } + + /** + * Create a greater than (>) field criterion + * + * @param string $fieldName The name of the field against which the value will be compared + * @param mixed $value The value for the greater than comparison + * @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank) + * @return static The field with the requested criterion + */ + public static function GT(string $fieldName, mixed $value, string $paramName = ''): static + { + return new static($fieldName, Op::GT, $value, $paramName); + } + + /** + * Create a greater than or equal to (>=) field criterion + * + * @param string $fieldName The name of the field against which the value will be compared + * @param mixed $value The value for the greater than or equal to comparison + * @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank) + * @return static The field with the requested criterion + */ + public static function GE(string $fieldName, mixed $value, string $paramName = ''): static + { + return new static($fieldName, Op::GE, $value, $paramName); + } + + /** + * Create a less than (<) field criterion + * + * @param string $fieldName The name of the field against which the value will be compared + * @param mixed $value The value for the less than comparison + * @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank) + * @return static The field with the requested criterion + */ + public static function LT(string $fieldName, mixed $value, string $paramName = ''): static + { + return new static($fieldName, Op::LT, $value, $paramName); + } + + /** + * Create a less than or equal to (<=) field criterion + * + * @param string $fieldName The name of the field against which the value will be compared + * @param mixed $value The value for the less than or equal to comparison + * @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank) + * @return static The field with the requested criterion + */ + public static function LE(string $fieldName, mixed $value, string $paramName = ''): static + { + return new static($fieldName, Op::LE, $value, $paramName); + } + + /** + * Create a not equals (<>) field criterion + * + * @param string $fieldName The name of the field against which the value will be compared + * @param mixed $value The value for the not equals comparison + * @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank) + * @return static The field with the requested criterion + */ + public static function NE(string $fieldName, mixed $value, string $paramName = ''): static + { + return new static($fieldName, Op::NE, $value, $paramName); + } + + /** + * Create a BETWEEN field criterion + * + * @param string $fieldName The name of the field against which the value will be compared + * @param mixed $minValue The lower value for range + * @param mixed $maxValue The upper value for the range + * @param string $paramName The name of the parameter to which this should be bound (optional; generated if blank) + * @return static The field with the requested criterion + */ + public static function BT(string $fieldName, mixed $minValue, mixed $maxValue, string $paramName = ''): static + { + return new static($fieldName, Op::BT, [$minValue, $maxValue], $paramName); + } + + /** + * Create an exists (IS NOT NULL) field criterion + * + * @param string $fieldName The name of the field for which existence will be checked + * @return static The field with the requested criterion + */ + public static function EX(string $fieldName): static + { + return new static($fieldName, Op::EX, '', ''); + } + + /** + * Create a not exists (IS NULL) field criterion + * + * @param string $fieldName The name of the field for which non-existence will be checked + * @return static The field with the requested criterion + */ + public static function NEX(string $fieldName): static + { + return new static($fieldName, Op::NEX, '', ''); + } +} diff --git a/src/Mapper/ArrayMapper.php b/src/Mapper/ArrayMapper.php new file mode 100644 index 0000000..62f1286 --- /dev/null +++ b/src/Mapper/ArrayMapper.php @@ -0,0 +1,17 @@ + Provide a mapping from JSON + */ +class JsonMapper implements Mapper +{ + /** + * Constructor + * + * @param class-string $className The type of class to be returned by this mapping + * @param string $fieldName The name of the field (optional; defaults to `data`) + */ + public function __construct(public string $className, public string $fieldName = 'data') { } + + /** + * Map a result to a domain class instance + * + * @param array $result An associative array representing a single database result + * @return TDoc The document, deserialized from its JSON representation + * @throws DocumentException If the JSON cannot be deserialized + */ + public function map(array $result): mixed + { + try { + $json = json_decode($result[$this->fieldName]); + if (is_null($json)) { + throw new DocumentException("Could not map document for $this->className: " . json_last_error_msg()); + } + return (new \JsonMapper())->map($json, $this->className); + } catch (JsonMapper_Exception $ex) { + throw new DocumentException("Could not map document for $this->className", previous: $ex); + } + } +} diff --git a/src/Mapper/Mapper.php b/src/Mapper/Mapper.php new file mode 100644 index 0000000..5ed0ff2 --- /dev/null +++ b/src/Mapper/Mapper.php @@ -0,0 +1,19 @@ + + */ +class StringMapper implements Mapper +{ + /** + * Constructor + * + * @param string $fieldName The name of the field to be retrieved as a string + */ + public function __construct(public string $fieldName) { } + + /** + * @inheritDoc + */ + public function map(array $result): ?string + { + return match (false) { + key_exists($this->fieldName, $result) => null, + is_string($result[$this->fieldName]) => "{$result[$this->fieldName]}", + default => $result[$this->fieldName] + }; + } +} diff --git a/src/Op.php b/src/Op.php new file mode 100644 index 0000000..9352fb9 --- /dev/null +++ b/src/Op.php @@ -0,0 +1,48 @@ +) */ + case GT; + /** Greater Than or Equal To (>=) */ + case GE; + /** Less Than (<) */ + case LT; + /** Less Than or Equal To (<=) */ + case LE; + /** Not Equal to (<>) */ + case NE; + /** Between (BETWEEN) */ + case BT; + /** Exists (IS NOT NULL) */ + case EX; + /** Does Not Exist (IS NULL) */ + case NEX; + + /** + * Get the string representation of this operator + * + * @return string The operator to use in SQL statements + */ + public function toString(): string + { + return match ($this) { + Op::EQ => "=", + Op::GT => ">", + Op::GE => ">=", + Op::LT => "<", + Op::LE => "<=", + Op::NE => "<>", + Op::BT => "BETWEEN", + Op::EX => "IS NOT NULL", + Op::NEX => "IS NULL" + }; + } +} diff --git a/src/Query.php b/src/Query.php new file mode 100644 index 0000000..d9a265f --- /dev/null +++ b/src/Query.php @@ -0,0 +1,77 @@ + $it->toWhere(), $fields)); + } + + /** + * Create a WHERE clause fragment to implement an ID-based query + * + * @param string $paramName The parameter name where the value of the ID will be provided (optional; default @id) + * @return string The WHERE clause fragment to match by ID + */ + public static function whereById(string $paramName = '@id'): string + { + return self::whereByFields([Field::EQ(Configuration::idField(), 0, $paramName)]); + } + + /** + * Query to insert a document + * + * @param string $tableName The name of the table into which a document should be inserted + * @return string The INSERT statement for the given table + */ + public static function insert(string $tableName): string + { + return "INSERT INTO $tableName VALUES (@data)"; + } + + /** + * Query to save a document, inserting it if it does not exist and updating it if it does (AKA "upsert") + * + * @param string $tableName The name of the table into which a document should be saved + * @return string The INSERT...ON CONFLICT query for the document + */ + public static function save(string $tableName): string + { + return self::insert($tableName) + . " ON CONFLICT ((data->>'" . Configuration::idField() . "')) DO UPDATE SET data = EXCLUDED.data"; + } + + /** + * Query to update a document + * + * @param string $tableName The name of the table in which the document should be updated + * @return string The UPDATE query for the document + */ + public static function update(string $tableName): string + { + return "UPDATE $tableName SET data = @data WHERE " . self::whereById(); + } +} diff --git a/src/Query/Count.php b/src/Query/Count.php new file mode 100644 index 0000000..cc112f0 --- /dev/null +++ b/src/Query/Count.php @@ -0,0 +1,36 @@ +>'$fieldName')$direction"; + }, $fields)); + return "CREATE INDEX IF NOT EXISTS idx_{$tbl}_$indexName ON $tableName ($jsonFields)"; + } + + /** + * SQL statement to create a key index for a document table + * + * @param string $tableName The name of the table whose key should be ensured + * @return string The CREATE INDEX statement to ensure the key index exists + */ + public static function ensureKey(string $tableName): string + { + return str_replace('INDEX', 'UNIQUE INDEX', self::ensureIndexOn($tableName, 'key', [Configuration::idField()])); + } +} diff --git a/src/Query/Delete.php b/src/Query/Delete.php new file mode 100644 index 0000000..d171bb7 --- /dev/null +++ b/src/Query/Delete.php @@ -0,0 +1,36 @@ +assertEquals('id', Configuration::idField(), 'Default ID field should be "id"'); + } + + public function testUseIdFieldSucceeds() + { + try { + Configuration::useIdField('EyeDee'); + $this->assertEquals('EyeDee', Configuration::idField(), 'ID field should have been updated'); + } finally { + Configuration::useIdField('id'); + $this->assertEquals('id', Configuration::idField(), 'Default ID value should have been restored'); + } + } +} diff --git a/tests/unit/DocumentExceptionTest.php b/tests/unit/DocumentExceptionTest.php new file mode 100644 index 0000000..7103575 --- /dev/null +++ b/tests/unit/DocumentExceptionTest.php @@ -0,0 +1,46 @@ +assertNotNull($ex, 'The exception should not have been null'); + $this->assertEquals('Test Exception', $ex->getMessage(), 'Message not filled properly'); + $this->assertEquals(17, $ex->getCode(), 'Code not filled properly'); + $this->assertSame($priorEx, $ex->getPrevious(), 'Prior exception not filled properly'); + } + + public function testConstructorSucceedsWithoutCodeAndPriorException() + { + $ex = new DocumentException('Oops'); + $this->assertNotNull($ex, 'The exception should not have been null'); + $this->assertEquals('Oops', $ex->getMessage(), 'Message not filled properly'); + $this->assertEquals(0, $ex->getCode(), 'Code not filled properly'); + $this->assertNull($ex->getPrevious(), 'Prior exception should have been null'); + } + + public function testToStringSucceedsWithoutCode() + { + $ex = new DocumentException('Test failure'); + $this->assertEquals("BitBadger\PDODocument\DocumentException: Test failure\n", "$ex", + 'toString not generated correctly'); + } + + public function testToStringSucceedsWithCode() + { + $ex = new DocumentException('Oof', -6); + $this->assertEquals("BitBadger\PDODocument\DocumentException: [-6] Oof\n", "$ex", + 'toString not generated correctly'); + } +} diff --git a/tests/unit/FieldTest.php b/tests/unit/FieldTest.php new file mode 100644 index 0000000..8294534 --- /dev/null +++ b/tests/unit/FieldTest.php @@ -0,0 +1,257 @@ +assertEquals([], Field::EX('exists')->appendParameter([]), 'EX should not have appended a parameter'); + } + + #[TestDox('Append parameter succeeds for NEX')] + public function testAppendParameterSucceedsForNEX(): void + { + $this->assertEquals([], Field::NEX('absent')->appendParameter([]), 'NEX should not have appended a parameter'); + } + + #[TestDox('Append parameter succeeds for BT')] + public function testAppendParameterSucceedsForBT(): void + { + $this->assertEquals(['@nummin' => 5, '@nummax' => 9], Field::BT('exists', 5, 9, '@num')->appendParameter([]), + 'BT should have appended min and max parameters'); + } + + public function testAppendParameterSucceedsForOthers(): void + { + $this->assertEquals(['@test' => 33], Field::EQ('the_field', 33, '@test')->appendParameter([]), + 'Field parameter not returned correctly'); + } + + #[TestDox('To where succeeds for EX without qualifier')] + public function testToWhereSucceedsForEXWithoutQualifier(): void + { + $this->assertEquals("data->>'that_field' IS NOT NULL", Field::EX('that_field')->toWhere(), + 'WHERE fragment not generated correctly'); + } + + #[TestDox('To where succeeds for NEX without qualifier')] + public function testToWhereSucceedsForNEXWithoutQualifier(): void + { + $this->assertEquals("data->>'a_field' IS NULL", Field::NEX('a_field')->toWhere(), + 'WHERE fragment not generated correctly'); + } + + #[TestDox('To where succeeds for BT without qualifier')] + public function testToWhereSucceedsForBTWithoutQualifier(): void + { + $this->assertEquals("data->>'age' BETWEEN @agemin AND @agemax", Field::BT('age', 13, 17, '@age')->toWhere(), + 'WHERE fragment not generated correctly'); + } + + public function testToWhereSucceedsForOthersWithoutQualifier(): void + { + $this->assertEquals("data->>'some_field' = @value", Field::EQ('some_field', '', '@value')->toWhere(), + 'WHERE fragment not generated correctly'); + } + + public function testToWhereSucceedsWithQualifierNoParameter(): void + { + $field = Field::EX('no_field'); + $field->qualifier = 'test'; + $this->assertEquals("test.data->>'no_field' IS NOT NULL", $field->toWhere(), + 'WHERE fragment not generated correctly'); + } + + public function testToWhereSucceedsWithQualifierAndParameter(): void + { + $field = Field::LE('le_field', 18, '@it'); + $field->qualifier = 'q'; + $this->assertEquals("q.data->>'le_field' <= @it", $field->toWhere(), 'WHERE fragment not generated correctly'); + } + + #[TestDox('EQ succeeds without parameter')] + public function testEQSucceedsWithoutParameter(): void + { + $field = Field::EQ('my_test', 9); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('my_test', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::EQ, $field->op, 'Operation not filled correctly'); + $this->assertEquals(9, $field->value, 'Value not filled correctly'); + $this->assertEquals('', $field->paramName, 'Parameter name should have been blank'); + } + + #[TestDox('EQ succeeds with parameter')] + public function testEQSucceedsWithParameter(): void + { + $field = Field::EQ('another_test', 'turkey', '@test'); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('another_test', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::EQ, $field->op, 'Operation not filled correctly'); + $this->assertEquals('turkey', $field->value, 'Value not filled correctly'); + $this->assertEquals('@test', $field->paramName, 'Parameter name not filled correctly'); + } + + #[TestDox('GT succeeds without parameter')] + public function testGTSucceedsWithoutParameter(): void + { + $field = Field::GT('your_test', 4); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('your_test', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::GT, $field->op, 'Operation not filled correctly'); + $this->assertEquals(4, $field->value, 'Value not filled correctly'); + $this->assertEquals('', $field->paramName, 'Parameter name should have been blank'); + } + + #[TestDox('GT succeeds with parameter')] + public function testGTSucceedsWithParameter(): void + { + $field = Field::GT('more_test', 'chicken', '@value'); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('more_test', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::GT, $field->op, 'Operation not filled correctly'); + $this->assertEquals('chicken', $field->value, 'Value not filled correctly'); + $this->assertEquals('@value', $field->paramName, 'Parameter name not filled correctly'); + } + + #[TestDox('GE succeeds without parameter')] + public function testGESucceedsWithoutParameter(): void + { + $field = Field::GE('their_test', 6); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('their_test', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::GE, $field->op, 'Operation not filled correctly'); + $this->assertEquals(6, $field->value, 'Value not filled correctly'); + $this->assertEquals('', $field->paramName, 'Parameter name should have been blank'); + } + + #[TestDox('GE succeeds with parameter')] + public function testGESucceedsWithParameter(): void + { + $field = Field::GE('greater_test', 'poultry', '@cluck'); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('greater_test', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::GE, $field->op, 'Operation not filled correctly'); + $this->assertEquals('poultry', $field->value, 'Value not filled correctly'); + $this->assertEquals('@cluck', $field->paramName, 'Parameter name not filled correctly'); + } + + #[TestDox('LT succeeds without parameter')] + public function testLTSucceedsWithoutParameter(): void + { + $field = Field::LT('z', 32); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('z', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::LT, $field->op, 'Operation not filled correctly'); + $this->assertEquals(32, $field->value, 'Value not filled correctly'); + $this->assertEquals('', $field->paramName, 'Parameter name should have been blank'); + } + + #[TestDox('LT succeeds with parameter')] + public function testLTSucceedsWithParameter(): void + { + $field = Field::LT('additional_test', 'fowl', '@boo'); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('additional_test', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::LT, $field->op, 'Operation not filled correctly'); + $this->assertEquals('fowl', $field->value, 'Value not filled correctly'); + $this->assertEquals('@boo', $field->paramName, 'Parameter name not filled correctly'); + } + + #[TestDox('LE succeeds without parameter')] + public function testLESucceedsWithoutParameter(): void + { + $field = Field::LE('g', 87); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('g', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::LE, $field->op, 'Operation not filled correctly'); + $this->assertEquals(87, $field->value, 'Value not filled correctly'); + $this->assertEquals('', $field->paramName, 'Parameter name should have been blank'); + } + + #[TestDox('LE succeeds with parameter')] + public function testLESucceedsWithParameter(): void + { + $field = Field::LE('lesser_test', 'hen', '@woo'); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('lesser_test', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::LE, $field->op, 'Operation not filled correctly'); + $this->assertEquals('hen', $field->value, 'Value not filled correctly'); + $this->assertEquals('@woo', $field->paramName, 'Parameter name not filled correctly'); + } + + #[TestDox('NE succeeds without parameter')] + public function testNESucceedsWithoutParameter(): void + { + $field = Field::NE('j', 65); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('j', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::NE, $field->op, 'Operation not filled correctly'); + $this->assertEquals(65, $field->value, 'Value not filled correctly'); + $this->assertEquals('', $field->paramName, 'Parameter name should have been blank'); + } + + #[TestDox('NE succeeds with parameter')] + public function testNESucceedsWithParameter(): void + { + $field = Field::NE('unequal_test', 'egg', '@zoo'); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('unequal_test', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::NE, $field->op, 'Operation not filled correctly'); + $this->assertEquals('egg', $field->value, 'Value not filled correctly'); + $this->assertEquals('@zoo', $field->paramName, 'Parameter name not filled correctly'); + } + + #[TestDox('BT succeeds without parameter')] + public function testBTSucceedsWithoutParameter(): void + { + $field = Field::BT('k', 'alpha', 'zed'); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('k', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::BT, $field->op, 'Operation not filled correctly'); + $this->assertEquals(['alpha', 'zed'], $field->value, 'Value not filled correctly'); + $this->assertEquals('', $field->paramName, 'Parameter name should have been blank'); + } + + #[TestDox('BT succeeds with parameter')] + public function testBTSucceedsWithParameter(): void + { + $field = Field::BT('between_test', 18, 49, '@count'); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('between_test', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::BT, $field->op, 'Operation not filled correctly'); + $this->assertEquals([18, 49], $field->value, 'Value not filled correctly'); + $this->assertEquals('@count', $field->paramName, 'Parameter name not filled correctly'); + } + + #[TestDox('EX succeeds')] + public function testEXSucceeds(): void + { + $field = Field::EX('be_there'); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('be_there', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::EX, $field->op, 'Operation not filled correctly'); + $this->assertEquals('', $field->value, 'Value should have been blank'); + $this->assertEquals('', $field->paramName, 'Parameter name should have been blank'); + } + + #[TestDox('NEX succeeds')] + public function testNEXSucceeds(): void + { + $field = Field::NEX('be_absent'); + $this->assertNotNull($field, 'The field should not have been null'); + $this->assertEquals('be_absent', $field->fieldName, 'Field name not filled correctly'); + $this->assertEquals(Op::NEX, $field->op, 'Operation not filled correctly'); + $this->assertEquals('', $field->value, 'Value should have been blank'); + $this->assertEquals('', $field->paramName, 'Parameter name should have been blank'); + } +} diff --git a/tests/unit/Mapper/ArrayMapperTest.php b/tests/unit/Mapper/ArrayMapperTest.php new file mode 100644 index 0000000..51a8603 --- /dev/null +++ b/tests/unit/Mapper/ArrayMapperTest.php @@ -0,0 +1,19 @@ + 2, 'three' => 4, 'eight' => 'five']; + $mapped = (new ArrayMapper())->map($result); + $this->assertSame($result, $mapped, 'The array mapper should return the parameter given to it'); + } +} diff --git a/tests/unit/Mapper/JsonMapperTest.php b/tests/unit/Mapper/JsonMapperTest.php new file mode 100644 index 0000000..14e84ce --- /dev/null +++ b/tests/unit/Mapper/JsonMapperTest.php @@ -0,0 +1,57 @@ +assertEquals('data', $mapper->fieldName, 'Default field name should have been "data"'); + } + + public function testConstructorSucceedsWithSpecifiedField(): void + { + $mapper = new JsonMapper(Field::class, 'json'); + $this->assertEquals('json', $mapper->fieldName, 'Field name not recorded correctly'); + } + + #[TestDox('Map succeeds with valid JSON')] + public function testMapSucceedsWithValidJSON(): void + { + $doc = (new JsonMapper(TestDocument::class))->map(['data' => '{"id":7,"subDoc":{"id":22,"name":"tester"}}']); + $this->assertNotNull($doc, 'The document should not have been null'); + $this->assertEquals(7, $doc->id, 'ID not filled correctly'); + $this->assertNotNull($doc->subDoc, 'The sub-document should not have been null'); + $this->assertEquals(22, $doc->subDoc->id, 'Sub-document ID not filled correctly'); + $this->assertEquals('tester', $doc->subDoc->name, 'Sub-document name not filled correctly'); + } + + #[TestDox('Map fails with invalid JSON')] + public function testMapFailsWithInvalidJSON(): void + { + $this->expectException(DocumentException::class); + (new JsonMapper(TestDocument::class))->map(['data' => 'this is not valid']); + } +} diff --git a/tests/unit/Mapper/StringMapperTest.php b/tests/unit/Mapper/StringMapperTest.php new file mode 100644 index 0000000..57c1c0a --- /dev/null +++ b/tests/unit/Mapper/StringMapperTest.php @@ -0,0 +1,29 @@ + 'test_value']; + $mapper = new StringMapper('test_field'); + $this->assertEquals('test_value', $mapper->map($result), 'String value not returned correctly'); + } + + public function testMapSucceedsWhenFieldIsPresentAndNotString() + { + $result = ['a_number' => 6.7]; + $mapper = new StringMapper('a_number'); + $this->assertEquals('6.7', $mapper->map($result), 'Number value not returned correctly'); + } + + public function testMapSucceedsWhenFieldIsNotPresent() + { + $mapper = new StringMapper('something_else'); + $this->assertNull($mapper->map([]), 'Missing value not returned correctly'); + } +} diff --git a/tests/unit/OpTest.php b/tests/unit/OpTest.php new file mode 100644 index 0000000..3cb3106 --- /dev/null +++ b/tests/unit/OpTest.php @@ -0,0 +1,67 @@ +assertEquals('=', Op::EQ->toString(), 'EQ operator incorrect'); + } + + #[TestDox('To string succeeds for GT')] + public function testToStringSucceedsForGT(): void + { + $this->assertEquals('>', Op::GT->toString(), 'GT operator incorrect'); + } + + #[TestDox('To string succeeds for GE')] + public function testToStringSucceedsForGE(): void + { + $this->assertEquals('>=', Op::GE->toString(), 'GE operator incorrect'); + } + + #[TestDox('To string succeeds for LT')] + public function testToStringSucceedsForLT(): void + { + $this->assertEquals('<', Op::LT->toString(), 'LT operator incorrect'); + } + + #[TestDox('To string succeeds for LE')] + public function testToStringSucceedsForLE(): void + { + $this->assertEquals('<=', Op::LE->toString(), 'LE operator incorrect'); + } + + #[TestDox('To string succeeds for NE')] + public function testToStringSucceedsForNE(): void + { + $this->assertEquals('<>', Op::NE->toString(), 'NE operator incorrect'); + } + + #[TestDox('To string succeeds for BT')] + public function testToStringSucceedsForBT(): void + { + $this->assertEquals('BETWEEN', Op::BT->toString(), 'BT operator incorrect'); + } + + #[TestDox('To string succeeds for EX')] + public function testToStringSucceedsForEX(): void + { + $this->assertEquals('IS NOT NULL', Op::EX->toString(), 'EX operator incorrect'); + } + + #[TestDox('To string succeeds for NEX')] + public function testToStringSucceedsForNEX(): void + { + $this->assertEquals('IS NULL', Op::NEX->toString(), 'NEX operator incorrect'); + } +} diff --git a/tests/unit/Query/CountTest.php b/tests/unit/Query/CountTest.php new file mode 100644 index 0000000..d0b6223 --- /dev/null +++ b/tests/unit/Query/CountTest.php @@ -0,0 +1,26 @@ +assertEquals('SELECT COUNT(*) FROM a_table', Count::all('a_table'), + 'SELECT statement not generated correctly'); + } + + public function testByFieldsSucceeds() + { + $this->assertEquals("SELECT COUNT(*) FROM somewhere WHERE data->>'errors' > @errors", + Count::byFields('somewhere', [Field::GT('errors', 10, '@errors')])); + } +} diff --git a/tests/unit/Query/DefinitionTest.php b/tests/unit/Query/DefinitionTest.php new file mode 100644 index 0000000..680b2e1 --- /dev/null +++ b/tests/unit/Query/DefinitionTest.php @@ -0,0 +1,38 @@ +assertEquals('CREATE TABLE IF NOT EXISTS documents (data JSON NOT NULL)', + Definition::ensureTableFor('documents', 'JSON'), 'CREATE TABLE statement not generated correctly'); + } + + public function testEnsureIndexOnSucceedsWithoutSchemaSingleAscendingField(): void + { + $this->assertEquals("CREATE INDEX IF NOT EXISTS idx_test_fields ON test ((data->>'details'))", + Definition::ensureIndexOn('test', 'fields', ['details']), 'CREATE INDEX statement not generated correctly'); + } + + public function testEnsureIndexOnSucceedsWithSchemaMultipleFields(): void + { + $this->assertEquals( + "CREATE INDEX IF NOT EXISTS idx_testing_json ON sch.testing ((data->>'group'), (data->>'sub_group') DESC)", + Definition::ensureIndexOn('sch.testing', 'json', ['group', 'sub_group DESC']), + 'CREATE INDEX statement not generated correctly'); + } + + public function testEnsureKey(): void + { + $this->assertEquals("CREATE UNIQUE INDEX IF NOT EXISTS idx_tbl_key ON tbl ((data->>'id'))", + Definition::ensureKey('tbl'), 'CREATE INDEX statement for document key not generated correctly'); + } +} diff --git a/tests/unit/Query/DeleteTest.php b/tests/unit/Query/DeleteTest.php new file mode 100644 index 0000000..7921631 --- /dev/null +++ b/tests/unit/Query/DeleteTest.php @@ -0,0 +1,26 @@ +assertEquals("DELETE FROM over_there WHERE data->>'id' = @id", Delete::byId('over_there'), + 'DELETE statement not constructed correctly'); + } + + public function testByFieldsSucceeds(): void + { + $this->assertEquals("DELETE FROM my_table WHERE data->>'value' < @max AND data->>'value' >= @min", + Delete::byFields('my_table', [Field::LT('value', 99, '@max'), Field::GE('value', 18, '@min')]), + 'DELETE statement not constructed correctly'); + } +} diff --git a/tests/unit/Query/ExistsTest.php b/tests/unit/Query/ExistsTest.php new file mode 100644 index 0000000..dcbf023 --- /dev/null +++ b/tests/unit/Query/ExistsTest.php @@ -0,0 +1,32 @@ +assertEquals('SELECT EXISTS (SELECT 1 FROM abc WHERE def)', Exists::query('abc', 'def'), + 'Existence query not generated correctly'); + } + + public function testByIdSucceeds(): void + { + $this->assertEquals("SELECT EXISTS (SELECT 1 FROM dox WHERE data->>'id' = @id)", Exists::byId('dox'), + 'Existence query not generated correctly'); + } + + public function testByFieldsSucceeds(): void + { + $this->assertEquals("SELECT EXISTS (SELECT 1 FROM box WHERE data->>'status' <> @status)", + Exists::byFields('box', [Field::NE('status', 'occupied', '@status')]), + 'Existence query not generated correctly'); + } +} diff --git a/tests/unit/Query/FindTest.php b/tests/unit/Query/FindTest.php new file mode 100644 index 0000000..1811caf --- /dev/null +++ b/tests/unit/Query/FindTest.php @@ -0,0 +1,26 @@ +assertEquals("SELECT data FROM here WHERE data->>'id' = @id", Find::byId('here'), + 'SELECT query not generated correctly'); + } + + public function testByFieldsSucceeds(): void + { + $this->assertEquals("SELECT data FROM there WHERE data->>'active' = @act OR data->>'locked' = @lock", + Find::byFields('there', [Field::EQ('active', true, '@act'), Field::EQ('locked', true, '@lock')], 'OR'), + 'SELECT query not generated correctly'); + } +} diff --git a/tests/unit/QueryTest.php b/tests/unit/QueryTest.php new file mode 100644 index 0000000..afdd261 --- /dev/null +++ b/tests/unit/QueryTest.php @@ -0,0 +1,68 @@ +assertEquals('SELECT data FROM testing', Query::selectFromTable('testing'), + 'Query not constructed correctly'); + } + + public function testWhereByFieldsSucceedsForSingleField(): void + { + $this->assertEquals("data->>'test_field' <= @it", + Query::whereByFields([Field::LE('test_field', '', '@it')]), 'WHERE fragment not constructed correctly'); + } + + public function testWhereByFieldsSucceedsForMultipleFields(): void + { + $this->assertEquals("data->>'test_field' <= @it AND data->>'other_field' = @other", + Query::whereByFields([Field::LE('test_field', '', '@it'), Field::EQ('other_field', '', '@other')]), + 'WHERE fragment not constructed correctly'); + } + + public function testWhereByFieldsSucceedsForMultipleFieldsWithOr(): void + { + $this->assertEquals("data->>'test_field' <= @it OR data->>'other_field' = @other", + Query::whereByFields([Field::LE('test_field', '', '@it'), Field::EQ('other_field', '', '@other')], 'OR'), + 'WHERE fragment not constructed correctly'); + } + + public function testWhereByIdSucceedsWithDefaultParameter(): void + { + $this->assertEquals("data->>'id' = @id", Query::whereById(), 'WHERE fragment not constructed correctly'); + } + + public function testWhereByIdSucceedsWithSpecificParameter(): void + { + $this->assertEquals("data->>'id' = @di", Query::whereById('@di'), 'WHERE fragment not constructed correctly'); + } + + public function testInsertSucceeds(): void + { + $this->assertEquals('INSERT INTO my_table VALUES (@data)', Query::insert('my_table'), + 'INSERT statement not constructed correctly'); + } + + public function testSaveSucceeds(): void + { + $this->assertEquals( + "INSERT INTO test_tbl VALUES (@data) ON CONFLICT ((data->>'id')) DO UPDATE SET data = EXCLUDED.data", + Query::save('test_tbl'), 'INSERT ON CONFLICT statement not constructed correctly'); + } + + public function testUpdateSucceeds() + { + $this->assertEquals("UPDATE testing SET data = @data WHERE data->>'id' = @id", Query::update('testing'), + 'UPDATE statement not constructed correctly'); + } +}