Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
44f735a
chore(config): Add a base abstract config object
ollieread Mar 29, 2026
7f5fc24
chore(database.config): Add database config objects
ollieread Mar 29, 2026
dfbd869
chore(database): Add database exceptions
ollieread Mar 29, 2026
44adb7e
chore(database): Hardcode connection driver to MySQL
ollieread Mar 29, 2026
c382c9d
chore(database): Add persistent option to database config
ollieread Mar 29, 2026
205392e
chore(database): Create initial connection DTO
ollieread Mar 29, 2026
4e4b8bf
chore(database): Create connection factory
ollieread Mar 29, 2026
259ccf7
chore(database): Change default MySQL port
ollieread Mar 29, 2026
1bb2115
fix(database): Fix applying of connection options and default options
ollieread Mar 29, 2026
cb28f22
tests(database): Add connection and connection factory tests
ollieread Mar 29, 2026
fc95ea4
fix: Fix phpstan error
ollieread Mar 29, 2026
61e8a98
fix: Fix socket tests on github acitons
ollieread Mar 29, 2026
d2e69fe
build(composer): Add a tidy composer command
ollieread Mar 30, 2026
94e430a
feat(values): Add a value getter and value type getter contract
ollieread Mar 30, 2026
6e999ee
feat(database:query): Add initial query builder functionality
ollieread Mar 30, 2026
745603d
feat(engine:database): Require operator in query builder where methods
ollieread Mar 30, 2026
1cdec96
feat(engine:database): Complete query builder with tests and CI matrix
ollieread Mar 30, 2026
a341c65
test(engine:database): Achieve 100% code coverage and mutation score
ollieread Mar 30, 2026
46ce7e5
chore(database): Tidy-up of docblocks and fixes
ollieread Mar 30, 2026
e31b083
ci(github): Fix mariadb 11.4 tests on GitHub
ollieread Mar 30, 2026
0b62b77
chore(database:connections): Add a custom resolver for database conne…
ollieread Mar 31, 2026
1f8656e
feat(engine:database): Add schema abstraction for DDL generation
ollieread Mar 31, 2026
08ece67
test(engine:database): Fix escaped mutant in Connection::transaction
ollieread Mar 31, 2026
d97b24a
test(engine:database): Add tests for DatabaseResolver and Database at…
ollieread Mar 31, 2026
d73e4e8
feat(database:migrations): Initial migrations work
ollieread Mar 31, 2026
847b917
feat(engine:database): Add Column::char() type
ollieread Apr 1, 2026
7551b24
refactor(database): Remove all schema and migration functionality
ollieread Apr 1, 2026
82c9dac
chore(database): Small fixes and improvements
ollieread Apr 1, 2026
83ffba3
style: Code tidy
ollieread Apr 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 69 additions & 1 deletion .github/workflows/codecoverage.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,39 @@
name: Code Coverage
on: [ push, pull_request ]

on: [ pull_request ]

jobs:
run:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.4
env:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: engine_test
MYSQL_USER: engine
MYSQL_PASSWORD: secret
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=5s
--health-timeout=5s
--health-retries=10
mysql_secondary:
image: mysql:8.4
env:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: engine_test_port
MYSQL_USER: engine
MYSQL_PASSWORD: secret
ports:
- 3307:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=5s
--health-timeout=5s
--health-retries=10
steps:
- name: Checkout
uses: actions/checkout@v6
Expand All @@ -15,8 +46,45 @@ jobs:
- name: Install dependencies
run: composer self-update && composer install && composer dump-autoload

- name: Start MySQL socket container
run: |
mkdir -p /tmp/mysql_socket
chmod 777 /tmp/mysql_socket
docker run -d \
--name mysql_socket \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=engine_test_socket \
-e MYSQL_USER=engine \
-e MYSQL_PASSWORD=secret \
-v /tmp/mysql_socket:/var/run/mysqld \
mysql:8.4
for i in $(seq 1 30); do
docker exec mysql_socket mysqladmin ping -u root -psecret -h 127.0.0.1 --silent 2>/dev/null && break
sleep 2
done
for i in $(seq 1 10); do
[ -S /tmp/mysql_socket/mysqld.sock ] && break
sleep 1
done
[ -S /tmp/mysql_socket/mysqld.sock ] || { echo "ERROR: socket file not found"; docker logs mysql_socket; exit 1; }
docker exec mysql_socket mysql -u root -psecret -h 127.0.0.1 -e "
CREATE USER IF NOT EXISTS 'engine'@'localhost' IDENTIFIED BY 'secret';
GRANT ALL PRIVILEGES ON \`engine_test_socket\`.* TO 'engine'@'localhost';
FLUSH PRIVILEGES;
"

- name: Run tests and collect coverage
run: vendor/bin/phpunit --coverage-clover coverage.xml --log-junit junit.xml
env:
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_DATABASE: engine_test
DB_USERNAME: engine
DB_PASSWORD: secret
DB_PORT_SECONDARY: 3307
DB_DATABASE_SECONDARY: engine_test_port
DB_SOCKET: /tmp/mysql_socket/mysqld.sock
DB_DATABASE_SOCKET: engine_test_socket

- name: Upload coverage to Codecov
if: ${{ !cancelled() }}
Expand Down
138 changes: 138 additions & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
name: Integration Tests

on: [ pull_request ]

jobs:
connection:
name: Connection (MySQL 8.4)
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.4
env:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: engine_test
MYSQL_USER: engine
MYSQL_PASSWORD: secret
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=5s
--health-timeout=5s
--health-retries=10
mysql_secondary:
image: mysql:8.4
env:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: engine_test_port
MYSQL_USER: engine
MYSQL_PASSWORD: secret
ports:
- 3307:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=5s
--health-timeout=5s
--health-retries=10
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Set up php 8.5
uses: shivammathur/setup-php@v2
with:
php-version: '8.5'

- name: Install dependencies
run: composer self-update && composer install && composer dump-autoload

- name: Start MySQL socket container
run: |
mkdir -p /tmp/mysql_socket
chmod 777 /tmp/mysql_socket
docker run -d \
--name mysql_socket \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=engine_test_socket \
-e MYSQL_USER=engine \
-e MYSQL_PASSWORD=secret \
-v /tmp/mysql_socket:/var/run/mysqld \
mysql:8.4
for i in $(seq 1 30); do
docker exec mysql_socket mysqladmin ping -u root -psecret -h 127.0.0.1 --silent 2>/dev/null && break
sleep 2
done
for i in $(seq 1 10); do
[ -S /tmp/mysql_socket/mysqld.sock ] && break
sleep 1
done
[ -S /tmp/mysql_socket/mysqld.sock ] || { echo "ERROR: socket file not found"; docker logs mysql_socket; exit 1; }
docker exec mysql_socket mysql -u root -psecret -h 127.0.0.1 -e "
CREATE USER IF NOT EXISTS 'engine'@'localhost' IDENTIFIED BY 'secret';
GRANT ALL PRIVILEGES ON \`engine_test_socket\`.* TO 'engine'@'localhost';
FLUSH PRIVILEGES;
"

- name: Run connection integration tests
run: vendor/bin/phpunit --testsuite Integration --group connection-factory
env:
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_DATABASE: engine_test
DB_USERNAME: engine
DB_PASSWORD: secret
DB_PORT_SECONDARY: 3307
DB_DATABASE_SECONDARY: engine_test_port
DB_SOCKET: /tmp/mysql_socket/mysqld.sock
DB_DATABASE_SOCKET: engine_test_socket

query-builder:
name: Query Builder (${{ matrix.image }})
runs-on: ubuntu-latest
strategy:
matrix:
include:
- image: mysql:8.0
health_cmd: mysqladmin ping
- image: mysql:8.4
health_cmd: mysqladmin ping
- image: mariadb:10.11
health_cmd: mysqladmin ping
- image: mariadb:11.4
health_cmd: healthcheck.sh --connect --innodb_initialized
services:
database:
image: ${{ matrix.image }}
env:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: engine_test
MYSQL_USER: engine
MYSQL_PASSWORD: secret
ports:
- 3306:3306
options: >-
--health-cmd="${{ matrix.health_cmd }}"
--health-interval=5s
--health-timeout=5s
--health-retries=10
steps:
- name: Checkout
uses: actions/checkout@v6

- name: Set up php 8.5
uses: shivammathur/setup-php@v2
with:
php-version: '8.5'

- name: Install dependencies
run: composer self-update && composer install && composer dump-autoload

- name: Run query builder integration tests
run: vendor/bin/phpunit --testsuite Integration --group query-builder
env:
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_DATABASE: engine_test
DB_USERNAME: engine
DB_PASSWORD: secret
66 changes: 66 additions & 0 deletions .github/workflows/mutation-testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,35 @@ on: [ pull_request ]
jobs:
run:
runs-on: ubuntu-latest
services:
mysql:
image: mysql:8.4
env:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: engine_test
MYSQL_USER: engine
MYSQL_PASSWORD: secret
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=5s
--health-timeout=5s
--health-retries=10
mysql_secondary:
image: mysql:8.4
env:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: engine_test_port
MYSQL_USER: engine
MYSQL_PASSWORD: secret
ports:
- 3307:3306
options: >-
--health-cmd="mysqladmin ping"
--health-interval=5s
--health-timeout=5s
--health-retries=10
steps:
- name: Checkout
uses: actions/checkout@v6
Expand All @@ -18,5 +47,42 @@ jobs:
- name: Install dependencies
run: composer self-update && composer install && composer dump-autoload

- name: Start MySQL socket container
run: |
mkdir -p /tmp/mysql_socket
chmod 777 /tmp/mysql_socket
docker run -d \
--name mysql_socket \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=engine_test_socket \
-e MYSQL_USER=engine \
-e MYSQL_PASSWORD=secret \
-v /tmp/mysql_socket:/var/run/mysqld \
mysql:8.4
for i in $(seq 1 30); do
docker exec mysql_socket mysqladmin ping -u root -psecret -h 127.0.0.1 --silent 2>/dev/null && break
sleep 2
done
for i in $(seq 1 10); do
[ -S /tmp/mysql_socket/mysqld.sock ] && break
sleep 1
done
[ -S /tmp/mysql_socket/mysqld.sock ] || { echo "ERROR: socket file not found"; docker logs mysql_socket; exit 1; }
docker exec mysql_socket mysql -u root -psecret -h 127.0.0.1 -e "
CREATE USER IF NOT EXISTS 'engine'@'localhost' IDENTIFIED BY 'secret';
GRANT ALL PRIVILEGES ON \`engine_test_socket\`.* TO 'engine'@'localhost';
FLUSH PRIVILEGES;
"

- name: Run mutation testing
run: composer mutation
env:
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_DATABASE: engine_test
DB_USERNAME: engine
DB_PASSWORD: secret
DB_PORT_SECONDARY: 3307
DB_DATABASE_SECONDARY: engine_test_port
DB_SOCKET: /tmp/mysql_socket/mysqld.sock
DB_DATABASE_SOCKET: engine_test_socket
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/vendor
/composer.lock
/build
/tmp
.phpunit.result.cache
.php-cs-fixer.cache
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"scripts" : {
"test" : "@php vendor/bin/phpunit",
"mutation": "@php vendor/bin/infection --threads=max --no-progress",
"analyze" : "@php vendor/bin/phpstan analyse src --memory-limit=2G"
"analyze" : "@php vendor/bin/phpstan analyse src --memory-limit=2G",
"tidy" : "@php vendor/bin/php-cs-fixer fix"
}
}
45 changes: 45 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
services:
mysql:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: engine_test
MYSQL_USER: engine
MYSQL_PASSWORD: secret
ports:
- "3306:3306"
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
interval: 5s
timeout: 5s
retries: 10

mysql_secondary:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: engine_test_port
MYSQL_USER: engine
MYSQL_PASSWORD: secret
ports:
- "3307:3306"
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
interval: 5s
timeout: 5s
retries: 10

mysql_socket:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: engine_test_socket
MYSQL_USER: engine
MYSQL_PASSWORD: secret
volumes:
- ./tmp/mysql_socket:/var/run/mysqld
healthcheck:
test: [ "CMD", "mysqladmin", "ping", "-S", "/var/run/mysqld/mysqld.sock" ]
interval: 5s
timeout: 5s
retries: 10
Loading
Loading