Skip to content

query() with lazy iterators (2) #32

query() with lazy iterators (2)

query() with lazy iterators (2) #32

Workflow file for this run

name: CI
on:
push:
branches: [master, main]
pull_request:
branches: [master, main]
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-lint-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-lint-
- name: Check formatting
run: cargo fmt --all -- --check
- name: Run clippy
run: cargo clippy --all-targets --all-features -- -D warnings
test:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-test-
- name: Run tests
run: cargo test --all-features
build-extension:
name: Build PHP Extension
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
php: ['8.1', '8.2', '8.3', '8.4']
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
tools: none
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang llvm
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-php${{ matrix.php }}-cargo-build-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-php${{ matrix.php }}-cargo-build-
- name: Build PHP extension
working-directory: php-sqlx-cdylib
run: cargo build --release
- name: Install PHP extension
run: |
EXT_DIR=$(php -r "echo ini_get('extension_dir');")
echo "Extension directory: $EXT_DIR"
sudo cp php-sqlx-cdylib/target/release/libphp_sqlx_cdylib.so "$EXT_DIR/sqlx.so"
# Find the correct PHP ini scan directory
INI_DIR=$(php -r "echo PHP_CONFIG_FILE_SCAN_DIR;")
echo "INI scan directory: $INI_DIR"
if [ -n "$INI_DIR" ] && [ -d "$INI_DIR" ]; then
echo "extension=sqlx.so" | sudo tee "$INI_DIR/99-sqlx.ini"
else
# Fallback: add to main php.ini
PHP_INI=$(php -r "echo php_ini_loaded_file();")
echo "extension=sqlx.so" | sudo tee -a "$PHP_INI"
fi
- name: Verify extension loads
run: |
php -m
php -m | grep -i sqlx
integration-postgres:
name: Integration Tests (PostgreSQL)
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: test_db
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
tools: none
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang llvm
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-integration-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-integration-
- name: Build PHP extension
working-directory: php-sqlx-cdylib
run: cargo build --release
- name: Install PHP extension
run: |
EXT_DIR=$(php -r "echo ini_get('extension_dir');")
echo "Extension directory: $EXT_DIR"
sudo cp php-sqlx-cdylib/target/release/libphp_sqlx_cdylib.so "$EXT_DIR/sqlx.so"
INI_DIR=$(php -r "echo PHP_CONFIG_FILE_SCAN_DIR;")
echo "INI scan directory: $INI_DIR"
if [ -n "$INI_DIR" ] && [ -d "$INI_DIR" ]; then
echo "extension=sqlx.so" | sudo tee "$INI_DIR/99-sqlx.ini"
else
PHP_INI=$(php -r "echo php_ini_loaded_file();")
echo "extension=sqlx.so" | sudo tee -a "$PHP_INI"
fi
php -m | grep -i sqlx
- name: Run basic integration test
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/test_db
run: |
php -r "
require_once 'pdo.php';
\$pdo = new PdoEmulator\PDO('pgsql:host=localhost;dbname=test_db', 'postgres', 'postgres');
\$result = \$pdo->query('SELECT 1 as test')->fetch();
if (\$result['test'] != 1) {
echo 'FAILED: Unexpected result';
exit(1);
}
echo 'SUCCESS: PostgreSQL connection works' . PHP_EOL;
"
- name: Install PHPUnit
working-directory: tests
run: composer install --no-interaction --prefer-dist
- name: Run PHPUnit tests (PostgreSQL)
working-directory: tests
env:
POSTGRES_URL: postgres://postgres:postgres@localhost:5432/test_db
run: vendor/bin/phpunit --testsuite PostgreSQL --colors=always
- name: Test describeTable
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/test_db
run: |
php -r "
\$driver = Sqlx\DriverFactory::make('postgres://postgres:postgres@localhost:5432/test_db');
// Create a test table
\$driver->execute('DROP TABLE IF EXISTS test_describe_table');
\$driver->execute('CREATE TABLE test_describe_table (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255),
created_at TIMESTAMP DEFAULT NOW()
)');
// Test describeTable
\$columns = \$driver->describeTable('test_describe_table');
if (count(\$columns) !== 4) {
echo 'FAILED: Expected 4 columns, got ' . count(\$columns);
exit(1);
}
// Verify column structure
\$idCol = \$columns[0];
if (\$idCol['name'] !== 'id') {
echo 'FAILED: First column should be id';
exit(1);
}
if (\$idCol['ordinal'] !== 1) {
echo 'FAILED: First column ordinal should be 1';
exit(1);
}
// Cleanup
\$driver->execute('DROP TABLE test_describe_table');
echo 'SUCCESS: describeTable works correctly' . PHP_EOL;
"
- name: Test describeTable validation
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/test_db
run: |
php -r "
\$driver = Sqlx\DriverFactory::make('postgres://postgres:postgres@localhost:5432/test_db');
// Test invalid table name (SQL injection attempt)
try {
\$driver->describeTable('users; DROP TABLE users;--');
echo 'FAILED: Should have thrown exception for invalid table name';
exit(1); } catch (Sqlx\Exceptions\SqlxException \$e) {
if (\$e->getCode() !== Sqlx\Exceptions\SqlxException::VALIDATION) {
echo 'FAILED: Expected VALIDATION error code';
exit(1);
}
}
echo 'SUCCESS: describeTable validation works' . PHP_EOL;
"
integration-mysql:
name: Integration Tests (MySQL)
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8
env:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: test_db
ports:
- 3306:3306
options: >-
--health-cmd "mysqladmin ping -h localhost"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
tools: none
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang llvm
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-mysql-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-mysql-
- name: Build PHP extension
working-directory: php-sqlx-cdylib
run: cargo build --release
- name: Install PHP extension
run: |
EXT_DIR=$(php -r "echo ini_get('extension_dir');")
echo "Extension directory: $EXT_DIR"
sudo cp php-sqlx-cdylib/target/release/libphp_sqlx_cdylib.so "$EXT_DIR/sqlx.so"
INI_DIR=$(php -r "echo PHP_CONFIG_FILE_SCAN_DIR;")
echo "INI scan directory: $INI_DIR"
if [ -n "$INI_DIR" ] && [ -d "$INI_DIR" ]; then
echo "extension=sqlx.so" | sudo tee "$INI_DIR/99-sqlx.ini"
else
PHP_INI=$(php -r "echo php_ini_loaded_file();")
echo "extension=sqlx.so" | sudo tee -a "$PHP_INI"
fi
php -m | grep -i sqlx
- name: Run basic integration test
env:
DATABASE_URL: mysql://root:root@localhost:3306/test_db
run: |
php -r "
require_once 'pdo.php';
\$pdo = new PdoEmulator\PDO('mysql:host=localhost;dbname=test_db', 'root', 'root');
\$result = \$pdo->query('SELECT 1 as test')->fetch();
if (\$result['test'] != 1) {
echo 'FAILED: Unexpected result';
exit(1);
}
echo 'SUCCESS: MySQL connection works' . PHP_EOL;
"
- name: Install PHPUnit
working-directory: tests
run: composer install --no-interaction --prefer-dist
- name: Run PHPUnit tests (MySQL)
working-directory: tests
env:
MYSQL_URL: mysql://root:root@localhost:3306/test_db
run: vendor/bin/phpunit --testsuite MySQL --colors=always
- name: Test describeTable (MySQL)
env:
DATABASE_URL: mysql://root:root@localhost:3306/test_db
run: |
php -r "
\$driver = Sqlx\DriverFactory::make('mysql://root:root@localhost:3306/test_db');
// Create a test table
\$driver->execute('DROP TABLE IF EXISTS test_describe_table');
\$driver->execute('CREATE TABLE test_describe_table (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)');
// Test describeTable
\$columns = \$driver->describeTable('test_describe_table');
if (count(\$columns) !== 4) {
echo 'FAILED: Expected 4 columns, got ' . count(\$columns);
exit(1);
}
// Verify column structure
\$idCol = \$columns[0];
if (\$idCol['name'] !== 'id') {
echo 'FAILED: First column should be id';
exit(1);
}
// Cleanup
\$driver->execute('DROP TABLE test_describe_table');
echo 'SUCCESS: describeTable works correctly on MySQL' . PHP_EOL;
"
integration-mssql:
name: Integration Tests (MSSQL)
runs-on: ubuntu-latest
services:
mssql:
image: mcr.microsoft.com/mssql/server:2022-latest
env:
ACCEPT_EULA: Y
SA_PASSWORD: TestPassword123!
MSSQL_PID: Developer
ports:
- 1433:1433
options: >-
--health-cmd "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P TestPassword123! -C -Q 'SELECT 1'"
--health-interval 10s
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v4
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
tools: none
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y clang llvm
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-mssql-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-mssql-
- name: Build PHP extension
working-directory: php-sqlx-cdylib
run: cargo build --release
- name: Install PHP extension
run: |
EXT_DIR=$(php -r "echo ini_get('extension_dir');")
echo "Extension directory: $EXT_DIR"
sudo cp php-sqlx-cdylib/target/release/libphp_sqlx_cdylib.so "$EXT_DIR/sqlx.so"
INI_DIR=$(php -r "echo PHP_CONFIG_FILE_SCAN_DIR;")
echo "INI scan directory: $INI_DIR"
if [ -n "$INI_DIR" ] && [ -d "$INI_DIR" ]; then
echo "extension=sqlx.so" | sudo tee "$INI_DIR/99-sqlx.ini"
else
PHP_INI=$(php -r "echo php_ini_loaded_file();")
echo "extension=sqlx.so" | sudo tee -a "$PHP_INI"
fi
php -m | grep -i sqlx
- name: Create test database
run: |
# Install sqlcmd
curl https://packages.microsoft.com/keys/microsoft.asc | sudo tee /etc/apt/trusted.gpg.d/microsoft.asc
curl https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/prod.list | sudo tee /etc/apt/sources.list.d/mssql-release.list
sudo apt-get update
sudo ACCEPT_EULA=Y apt-get install -y mssql-tools18 unixodbc-dev
# Create test database
/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P 'TestPassword123!' -C -Q "CREATE DATABASE test_db"
- name: Run basic integration test
run: |
php -r "
\$driver = Sqlx\DriverFactory::make('mssql://sa:TestPassword123!@localhost:1433/test_db?trust_server_certificate=true');
\$result = \$driver->queryRow('SELECT 1 as test');
if (\$result->test != 1) {
echo 'FAILED: Unexpected result';
exit(1);
}
echo 'SUCCESS: MSSQL connection works' . PHP_EOL;
"
- name: Install PHPUnit
working-directory: tests
run: composer install --no-interaction --prefer-dist
- name: Run PHPUnit tests (MSSQL)
working-directory: tests
env:
MSSQL_URL: mssql://sa:TestPassword123!@localhost:1433/test_db?trust_server_certificate=true
run: vendor/bin/phpunit --testsuite MSSQL --colors=always
- name: Test describeTable (MSSQL)
run: |
php -r "
\$driver = Sqlx\DriverFactory::make('mssql://sa:TestPassword123!@localhost:1433/test_db?trust_server_certificate=true');
// Create a test table
\$driver->execute('IF OBJECT_ID(\\'test_describe_table\\', \\'U\\') IS NOT NULL DROP TABLE test_describe_table');
\$driver->execute('CREATE TABLE test_describe_table (
id INT IDENTITY(1,1) PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(255),
created_at DATETIME DEFAULT GETDATE()
)');
// Test describeTable
\$columns = \$driver->describeTable('test_describe_table');
if (count(\$columns) !== 4) {
echo 'FAILED: Expected 4 columns, got ' . count(\$columns);
exit(1);
}
// Verify column structure
\$idCol = \$columns[0];
if (\$idCol['name'] !== 'id') {
echo 'FAILED: First column should be id';
exit(1);
}
// Cleanup
\$driver->execute('DROP TABLE test_describe_table');
echo 'SUCCESS: describeTable works correctly on MSSQL' . PHP_EOL;
"