diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml new file mode 100644 index 0000000..c43789d --- /dev/null +++ b/.github/workflows/phpunit.yml @@ -0,0 +1,90 @@ +name: PHPUnit + +on: [push, pull_request] + +jobs: + test: + runs-on: ubuntu-latest + + services: + mysql: + image: mysql:5.7 + env: + MYSQL_ALLOW_EMPTY_PASSWORD: yes + MYSQL_DATABASE: test + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + postgres: + image: postgres + env: + POSTGRES_PASSWORD: postgres + POSTGRES_USER: postgres + POSTGRES_DB: test + ports: + - 5432:5432 + options: + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + strategy: + fail-fast: true + matrix: + php: [ 8.0, 8.1, 8.2, 8.3, 8.4 ] + + name: PHP ${{ matrix.php }} + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + tools: composer:v2 + coverage: xdebug + + - name: Validate composer.json and composer.lock + run: composer validate + + - name: Install dependencies + if: steps.composer-cache.outputs.cache-hit != 'true' + run: composer install --prefer-dist --no-progress --no-suggest + + - name: Run test suite + run: ./vendor/bin/phpunit -v + + - name: Run Coveralls + env: + COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COVERALLS_PARALLEL: true + COVERALLS_FLAG_NAME: ${{ runner.os }} - ${{ matrix.php }} + run: ./vendor/bin/php-coveralls --coverage_clover=build/logs/clover.xml -v + + upload-coverage: + runs-on: ubuntu-latest + needs: [ test ] + steps: + - name: Coveralls Finished + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + parallel-finished: true + + semantic-release: + runs-on: ubuntu-latest + needs: [ test, upload-coverage ] + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 'lts/*' + + - name: Run semantic-release + if: github.repository == 'leeqvip/database' && github.event_name == 'push' + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + run: npx semantic-release \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cf47104 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +/vendor/ + +composer.lock + +.vscode +.idea +*.iml + +# coverage report +/build + +.phpunit.* +phpunit.xml \ No newline at end of file diff --git a/.releaserc.yml b/.releaserc.yml new file mode 100644 index 0000000..4a17b28 --- /dev/null +++ b/.releaserc.yml @@ -0,0 +1,4 @@ +plugins: + - "@semantic-release/commit-analyzer" + - "@semantic-release/release-notes-generator" + - "@semantic-release/github" \ No newline at end of file diff --git a/README.md b/README.md index c50d72c..7a93c9b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ # Database library for PHP +[![PHPUnit](https://github.com/leeqvip/database/actions/workflows/phpunit.yml/badge.svg)](https://github.com/leeqvip/database/actions/workflows/phpunit.yml) +[![Coverage Status](https://coveralls.io/repos/github/leeqvip/database/badge.svg)](https://coveralls.io/github/leeqvip/database) +[![Latest Stable Version](https://poser.pugx.org/leeqvip/database/v/stable)](https://packagist.org/packages/leeqvip/database) +[![Total Downloads](https://poser.pugx.org/leeqvip/database/downloads)](https://packagist.org/packages/leeqvip/database) +[![License](https://poser.pugx.org/leeqvip/database/license)](https://packagist.org/packages/leeqvip/database) + PDO database library for PHP. the current supported databases are: diff --git a/composer.json b/composer.json index 9c4b108..7589d13 100644 --- a/composer.json +++ b/composer.json @@ -1,21 +1,35 @@ { - "name": "leeqvip/database", - "keywords": ["pdo", "database", "orm", "framework"], - "description": "PDO database library", - "authors": [ - { - "name": "leeqvip", - "email": "leeqvip@gmail.com" - } - ], - "license": "Apache-2.0", - "require": { - "php": ">=5.4.0", - "ext-pdo": "*" - }, - "autoload": { - "psr-4": { - "Leeqvip\\Database\\": "src/" - } - } + "name": "leeqvip/database", + "keywords": [ + "pdo", + "database", + "orm", + "framework" + ], + "description": "PDO database library", + "authors": [ + { + "name": "leeqvip", + "email": "leeqvip@gmail.com" + } + ], + "license": "Apache-2.0", + "require": { + "php": ">=8.0", + "ext-pdo": "*" + }, + "require-dev": { + "phpunit/phpunit": "^9.6", + "php-coveralls/php-coveralls": "^2.7" + }, + "autoload": { + "psr-4": { + "Leeqvip\\Database\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..8db31af --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,34 @@ + + + + + ./src + + + + + + + + + ./tests/ + + + + + + + + + + + + + + + + + diff --git a/src/Connection.php b/src/Connection.php index 73b8b29..e7e7d22 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -37,7 +37,7 @@ public function __construct(array $config = []) $this->connector = new $connector(); } - public function getPdo() + public function getPdo(): PDO { if (is_null($this->pdo)) { $this->connect(); diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000..3997bea --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1 @@ +*.db \ No newline at end of file diff --git a/tests/ConnectionTest.php b/tests/ConnectionTest.php new file mode 100644 index 0000000..8119112 --- /dev/null +++ b/tests/ConnectionTest.php @@ -0,0 +1,85 @@ +getPDO(); + $pdo->exec("DROP TABLE IF EXISTS users"); + $pdo->exec(<<initConfig(); + $this->initDatabase(); + } + + protected function getConnection() + { + return new Connection($this->config); + } + + protected function getPDO(): \PDO + { + return $this->getConnection()->getPdo(); + } + + public function testQuery() + { + $this->init(); + $this->getPDO()->exec("INSERT INTO users (id, name, nickname, created_at) VALUES (100, 'alice', 'Small Flower', '2025-05-17 13:28:56')"); + + $users = $this->getConnection()->query("SELECT * FROM users"); + $this->assertCount(1, $users); + + $users = $this->getConnection()->query("SELECT * FROM users WHERE id = :id", ['id' => 100]); + $this->assertCount(1, $users); + + $this->assertEquals('100', $users[0]['id']); + $this->assertEquals('alice', $users[0]['name']); + $this->assertEquals('Small Flower', $users[0]['nickname']); + } + + public function testExecute() + { + $this->init(); + $conn = $this->getConnection(); + + $users = $conn->query("SELECT * FROM users"); + $this->assertCount(0, $users); + $conn->execute( + "INSERT INTO users (id, name, nickname, created_at) VALUES (:id, :name, :nickname, '2025-05-17 13:28:56')", + [ + 'id' => 200, + 'name' => 'bob', + 'nickname' => 'Small Angel', + ], + ); + + $users = $conn->query("SELECT * FROM users"); + $this->assertCount(1, $users); + + $this->assertEquals('200', $users[0]['id']); + $this->assertEquals('bob', $users[0]['name']); + $this->assertEquals('Small Angel', $users[0]['nickname']); + } +} diff --git a/tests/MysqlConnectionTest.php b/tests/MysqlConnectionTest.php new file mode 100644 index 0000000..a648863 --- /dev/null +++ b/tests/MysqlConnectionTest.php @@ -0,0 +1,22 @@ +config = [ + 'type' => 'mysql', // mysql,pgsql,sqlite,sqlsrv + 'hostname' => getenv('DB_HOST'), + 'database' => getenv('DB_DATABASE'), + 'username' => getenv('DB_USERNAME'), + 'password' => getenv('DB_PASSWORD'), + 'hostport' => getenv('DB_PORT'), + ]; + } +} diff --git a/tests/PostgresConnectionTest.php b/tests/PostgresConnectionTest.php new file mode 100644 index 0000000..764ce5c --- /dev/null +++ b/tests/PostgresConnectionTest.php @@ -0,0 +1,22 @@ +config = [ + 'type' => 'pgsql', // mysql,pgsql,sqlite,sqlsrv + 'hostname' => getenv('PG_HOST'), + 'database' => getenv('PG_DATABASE'), + 'username' => getenv('PG_USERNAME'), + 'password' => getenv('PG_PASSWORD'), + 'hostport' => getenv('PG_PORT'), + ]; + } +} diff --git a/tests/SqliteConnectionTest.php b/tests/SqliteConnectionTest.php new file mode 100644 index 0000000..2a4db58 --- /dev/null +++ b/tests/SqliteConnectionTest.php @@ -0,0 +1,19 @@ +config = [ + 'type' => 'sqlite', // mysql,pgsql,sqlite,sqlsrv + 'database' => __DIR__.'/test.db', + ]; + } +} +