Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
44c19f9
Extract query lib
abnegate Mar 3, 2026
d942f2b
fix: resolve PHPStan type errors from query lib extraction
abnegate Mar 3, 2026
b0a1faf
fix: use static return types and remove PHPStan stubs
abnegate Mar 3, 2026
782ed2d
fix: update utopia-php/query to 0.1.1 for static return types
abnegate Mar 3, 2026
e130b88
(chore): switch to paratest and local query lib path dependency
abnegate Mar 12, 2026
6ae1a54
(refactor): extract enums, adapter features, hooks, and traits from D…
abnegate Mar 12, 2026
7910547
(refactor): decompose Database class and update adapters and validators
abnegate Mar 12, 2026
2e37e8e
(test): update tests and docs for Database class decomposition
abnegate Mar 12, 2026
4072192
(fix): add RetryClient proxy to suppress Swoole recv() EAGAIN warning…
abnegate Mar 12, 2026
801b29b
(refactor): use supports(Capability::Spatial) instead of instanceof S…
abnegate Mar 12, 2026
5339254
(fix): propagate tenantPerDocument setting to pooled adapter connections
abnegate Mar 12, 2026
aea4931
(fix): propagate relationship hook to Mirror source and destination d…
abnegate Mar 12, 2026
2546230
(style): remove section-style header comments
abnegate Mar 12, 2026
fe003f2
(chore): trigger CI
abnegate Mar 12, 2026
777f4d1
(chore): add workflow_dispatch trigger to tests workflow
abnegate Mar 12, 2026
574d55c
(chore): add workflow_dispatch trigger to linter and codeql workflows
abnegate Mar 12, 2026
18c883e
(fix): fix CI build context for query lib dependency and workflow_dis…
abnegate Mar 12, 2026
97400a8
(fix): checkout query lib dependency in linter and codeql CI workflows
abnegate Mar 12, 2026
1125cf1
(style): auto-fix lint issues with pint
abnegate Mar 12, 2026
ca2e1b6
(fix): use COMPOSER_MIRROR_PATH_REPOS in CI for proper query lib reso…
abnegate Mar 12, 2026
ae623f1
(style): fix pint issues for PHP 8.3 compatibility
abnegate Mar 12, 2026
64cf39e
(fix): patch composer.lock path in CI for proper query lib resolution
abnegate Mar 12, 2026
1830938
(fix): patch composer.lock path in Dockerfile for query lib resolution
abnegate Mar 12, 2026
213c8ef
(fix): replace symlinked query lib with copy in CI for PHPStan compat…
abnegate Mar 12, 2026
b202550
(fix): remove dump-autoload to preserve platform check from initial i…
abnegate Mar 12, 2026
1fc920f
(fix): use composer update in CodeQL CI for proper query lib resolution
abnegate Mar 12, 2026
6eda974
(fix): checkout feat-builder branch of query lib in CI workflows
abnegate Mar 12, 2026
9f2577f
(fix): force copy query lib in CodeQL CI to fix PHPStan symlink resol…
abnegate Mar 12, 2026
7344bf2
(fix): add debug output for CodeQL query lib resolution
abnegate Mar 12, 2026
08e737e
(fix): use PHP 8.4 container for CodeQL to support query lib syntax
abnegate Mar 12, 2026
940915b
(fix): update phpstan for PHP 8.4 compatibility in CodeQL CI
abnegate Mar 12, 2026
8c5bf27
(fix): upgrade to PHPStan 2.x for PHP 8.4 runtime compatibility in Co…
abnegate Mar 12, 2026
e44c71a
(fix): force copy query lib in Dockerfile and add diagnostics
abnegate Mar 12, 2026
16bb001
(chore): upgrade to PHPStan 2.x with baseline for PHP 8.4 query lib c…
abnegate Mar 12, 2026
d1ddad0
(fix): ensure query lib is copied into vendor in Docker final stage
abnegate Mar 12, 2026
0e6ec7c
(fix): ignore Swoole extension class errors in PHPStan for CI compati…
abnegate Mar 12, 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
22 changes: 19 additions & 3 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: "CodeQL"

on: [ pull_request ]
on: [ pull_request, workflow_dispatch ]
jobs:
lint:
name: CodeQL
Expand All @@ -11,10 +11,26 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 2
path: database

- name: Checkout query library
uses: actions/checkout@v4
with:
repository: utopia-php/query
ref: feat-builder
path: query

- run: git checkout HEAD^2
if: github.event_name == 'pull_request'
working-directory: database

- name: Run CodeQL
run: |
docker run --rm -v $PWD:/app -w /app phpswoole/swoole:5.1.8-php8.3-alpine sh -c \
"composer install --profile --ignore-platform-reqs && composer check"
docker run --rm -v $PWD/database:/app -v $PWD/query:/query -w /app -e COMPOSER_MIRROR_PATH_REPOS=1 php:8.4-cli-alpine sh -c \
"php -r \"copy('https://getcomposer.org/installer', '/tmp/composer-setup.php');\" && \
php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer && \
sed -i 's|\"url\": \"../query\"|\"url\": \"/query\"|' composer.json && \
sed -i 's|\"symlink\": true|\"symlink\": false|' composer.json && \
sed -i 's|\"url\": \"../query\"|\"url\": \"/query\"|' composer.lock && \
composer install --profile --ignore-platform-reqs && \
composer check"
21 changes: 18 additions & 3 deletions .github/workflows/linter.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: "Linter"

on: [ pull_request ]
on: [ pull_request, workflow_dispatch ]
jobs:
lint:
name: Linter
Expand All @@ -11,10 +11,25 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 2
path: database

- name: Checkout query library
uses: actions/checkout@v4
with:
repository: utopia-php/query
ref: feat-builder
path: query

- run: git checkout HEAD^2
if: github.event_name == 'pull_request'
working-directory: database

- name: Run Linter
run: |
docker run --rm -v $PWD:/app -w /app phpswoole/swoole:5.1.8-php8.3-alpine sh -c \
"composer install --profile --ignore-platform-reqs && composer lint"
docker run --rm -v $PWD/database:/app -v $PWD/query:/query -w /app -e COMPOSER_MIRROR_PATH_REPOS=1 phpswoole/swoole:5.1.8-php8.3-alpine sh -c \
"sed -i 's|\"url\": \"../query\"|\"url\": \"/query\"|' composer.json && \
sed -i 's|\"symlink\": true|\"symlink\": false|' composer.json && \
sed -i 's|\"url\": \"../query\"|\"url\": \"/query\"|' composer.lock && \
composer install --profile --ignore-platform-reqs && \
if [ -L vendor/utopia-php/query ]; then rm vendor/utopia-php/query && cp -r /query vendor/utopia-php/query; fi && \
composer lint"
21 changes: 17 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ concurrency:

env:
IMAGE: databases-dev
CACHE_KEY: databases-dev-${{ github.event.pull_request.head.sha }}
CACHE_KEY: databases-dev-${{ github.event.pull_request.head.sha || github.sha }}

on: [pull_request]
on: [pull_request, workflow_dispatch]

jobs:
setup:
Expand All @@ -17,6 +17,15 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
path: database

- name: Checkout query library
uses: actions/checkout@v4
with:
repository: utopia-php/query
ref: feat-builder
path: query

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
Expand All @@ -25,6 +34,7 @@ jobs:
uses: docker/build-push-action@v3
with:
context: .
file: database/Dockerfile
push: false
tags: ${{ env.IMAGE }}
load: true
Expand Down Expand Up @@ -60,7 +70,7 @@ jobs:
docker compose up -d --wait

- name: Run Unit Tests
run: docker compose exec tests vendor/bin/phpunit /usr/src/code/tests/unit
run: docker compose exec tests vendor/bin/paratest --configuration phpunit.xml --functional --processes 4 /usr/src/code/tests/unit

adapter_test:
name: Adapter Tests
Expand Down Expand Up @@ -103,4 +113,7 @@ jobs:
docker compose up -d --wait

- name: Run Tests
run: docker compose exec -T tests vendor/bin/phpunit /usr/src/code/tests/e2e/Adapter/${{matrix.adapter}}Test.php --debug
run: docker compose exec -T tests vendor/bin/paratest --configuration phpunit.xml --functional --processes 4 --exclude-group redis-destructive /usr/src/code/tests/e2e/Adapter/${{matrix.adapter}}Test.php

- name: Run Redis-Destructive Tests
run: docker compose exec -T tests vendor/bin/phpunit --configuration phpunit.xml --group redis-destructive /usr/src/code/tests/e2e/Adapter/${{matrix.adapter}}Test.php
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ Makefile
.envrc
.vscode
tmp
*.sql
26 changes: 20 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,28 @@ FROM composer:2.8 AS composer

WORKDIR /usr/local/src/

COPY composer.lock /usr/local/src/
COPY composer.json /usr/local/src/
COPY database/composer.lock /usr/local/src/
COPY database/composer.json /usr/local/src/

RUN composer install \
# Copy local query lib dependency (referenced as ../query in composer.json)
COPY query /usr/local/query

# Rewrite path repository to use copied location
RUN sed -i 's|"url": "../query"|"url": "/usr/local/query"|' /usr/local/src/composer.json \
&& sed -i 's|"symlink": true|"symlink": false|' /usr/local/src/composer.json \
&& sed -i 's|"url": "../query"|"url": "/usr/local/query"|' /usr/local/src/composer.lock

RUN COMPOSER_MIRROR_PATH_REPOS=1 composer install \
--ignore-platform-reqs \
--optimize-autoloader \
--no-plugins \
--no-scripts \
--prefer-dist

# Replace symlink with actual copy (composer path repos may still symlink)
RUN rm -rf /usr/local/src/vendor/utopia-php/query && \
cp -r /usr/local/query /usr/local/src/vendor/utopia-php/query

FROM php:8.4.18-cli-alpine3.22 AS compile

ENV PHP_REDIS_VERSION="6.3.0" \
Expand Down Expand Up @@ -105,14 +117,16 @@ RUN echo "opcache.enable_cli=1" >> $PHP_INI_DIR/php.ini
RUN echo "memory_limit=1024M" >> $PHP_INI_DIR/php.ini

COPY --from=composer /usr/local/src/vendor /usr/src/code/vendor
# Ensure query lib is copied (not symlinked) in vendor
COPY query /usr/src/code/vendor/utopia-php/query
COPY --from=swoole /usr/local/lib/php/extensions/no-debug-non-zts-20240924/swoole.so /usr/local/lib/php/extensions/no-debug-non-zts-20240924/
COPY --from=redis /usr/local/lib/php/extensions/no-debug-non-zts-20240924/redis.so /usr/local/lib/php/extensions/no-debug-non-zts-20240924/
COPY --from=pcov /usr/local/lib/php/extensions/no-debug-non-zts-20240924/pcov.so /usr/local/lib/php/extensions/no-debug-non-zts-20240924/
COPY --from=xdebug /usr/local/lib/php/extensions/no-debug-non-zts-20240924/xdebug.so /usr/local/lib/php/extensions/no-debug-non-zts-20240924/

COPY ./bin /usr/src/code/bin
COPY ./src /usr/src/code/src
COPY ./dev /usr/src/code/dev
COPY database/bin /usr/src/code/bin
COPY database/src /usr/src/code/src
COPY database/dev /usr/src/code/dev

# Add Debug Configs
RUN if [ "$DEBUG" = "true" ]; then cp /usr/src/code/dev/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini; fi
Expand Down
32 changes: 16 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -633,22 +633,22 @@ $database->createRelationship(
);

// Relationship onDelete types
Database::RELATION_MUTATE_CASCADE,
Database::RELATION_MUTATE_SET_NULL,
Database::RELATION_MUTATE_RESTRICT,
ForeignKeyAction::Cascade->value,
ForeignKeyAction::SetNull->value,
ForeignKeyAction::Restrict->value,

// Update the relationship with the default reference attributes
$database->updateRelationship(
collection: 'movies',
id: 'users',
onDelete: Database::RELATION_MUTATE_CASCADE
onDelete: ForeignKeyAction::Cascade->value
);

// Update the relationship with custom reference attributes
$database->updateRelationship(
collection: 'movies',
id: 'users',
onDelete: Database::RELATION_MUTATE_CASCADE,
onDelete: ForeignKeyAction::Cascade->value,
newKey: 'movies_id',
newTwoWayKey: 'users_id',
twoWay: true
Expand Down Expand Up @@ -755,25 +755,25 @@ $database->decreaseDocumentAttribute(
// Update the value of an attribute in a document

// Set types
Document::SET_TYPE_ASSIGN, // Assign the new value directly
Document::SET_TYPE_APPEND, // Append the new value to end of the array
Document::SET_TYPE_PREPEND // Prepend the new value to start of the array
SetType::Assign, // Assign the new value directly
SetType::Append, // Append the new value to end of the array
SetType::Prepend // Prepend the new value to start of the array
Note: Using append/prepend with an attribute which is not an array, it will be set to an array containing the new value.

$document->setAttribute(key: 'name', 'Chris Smoove')
->setAttribute(key: 'age', 33, Document::SET_TYPE_ASSIGN);
->setAttribute(key: 'age', 33, SetType::Assign);

$database->updateDocument(
collection: 'users',
id: $document->getId(),
collection: 'users',
id: $document->getId(),
document: $document
);
);

// Update the permissions of a document
$document->setAttribute('$permissions', Permission::read(Role::any()), Document::SET_TYPE_APPEND)
->setAttribute('$permissions', Permission::create(Role::any()), Document::SET_TYPE_APPEND)
->setAttribute('$permissions', Permission::update(Role::any()), Document::SET_TYPE_APPEND)
->setAttribute('$permissions', Permission::delete(Role::any()), Document::SET_TYPE_APPEND)
$document->setAttribute('$permissions', Permission::read(Role::any()), SetType::Append)
->setAttribute('$permissions', Permission::create(Role::any()), SetType::Append)
->setAttribute('$permissions', Permission::update(Role::any()), SetType::Append)
->setAttribute('$permissions', Permission::delete(Role::any()), SetType::Append)

$database->updateDocument(
collection: 'users',
Expand Down
3 changes: 2 additions & 1 deletion bin/tasks/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@
],
];

if (!isset($dbAdapters[$adapter])) {
if (! isset($dbAdapters[$adapter])) {
Console::error("Adapter '{$adapter}' not supported");

return;
}

Expand Down
28 changes: 12 additions & 16 deletions bin/tasks/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
$genresPool = ['fashion', 'food', 'travel', 'music', 'lifestyle', 'fitness', 'diy', 'sports', 'finance'];
$tagsPool = ['short', 'quick', 'easy', 'medium', 'hard'];


/**
* @Example
* docker compose exec tests bin/load --adapter=mariadb --limit=1000
Expand All @@ -35,11 +34,10 @@
->desc('Load database with mock data for testing')
->param('adapter', '', new Text(0), 'Database adapter')
->param('limit', 0, new Integer(true), 'Total number of records to add to database')
->param('name', 'myapp_' . uniqid(), new Text(0), 'Name of created database.', true)
->param('name', 'myapp_'.uniqid(), new Text(0), 'Name of created database.', true)
->param('sharedTables', false, new Boolean(true), 'Whether to use shared tables', true)
->action(function (string $adapter, int $limit, string $name, bool $sharedTables) {


$createSchema = function (Database $database): void {
if ($database->exists($database->getDatabase())) {
$database->delete($database->getDatabase());
Expand All @@ -61,14 +59,13 @@
$database->createIndex('articles', 'text', Database::INDEX_FULLTEXT, ['text']);
};


$start = null;
$namespace = '_ns';
$cache = new Cache(new NoCache());

Console::info("Filling {$adapter} with {$limit} records: {$name}");

//Runtime::enableCoroutine();
// Runtime::enableCoroutine();

$dbAdapters = [
'mariadb' => [
Expand Down Expand Up @@ -103,15 +100,16 @@
],
];

if (!isset($dbAdapters[$adapter])) {
if (! isset($dbAdapters[$adapter])) {
Console::error("Adapter '{$adapter}' not supported");

return;
}

$cfg = $dbAdapters[$adapter];
$dsn = ($cfg['dsn'])($cfg['host'], $cfg['port']);

//Co\run(function () use (&$start, $limit, $name, $sharedTables, $namespace, $cache, $cfg) {
// Co\run(function () use (&$start, $limit, $name, $sharedTables, $namespace, $cache, $cfg) {
$pdo = new PDO(
$dsn,
$cfg['user'],
Expand All @@ -132,7 +130,7 @@
->withHost($cfg['host'])
->withPort($cfg['port'])
->withDbName($name)
//->withCharset('utf8mb4')
// ->withCharset('utf8mb4')
->withUsername($cfg['user'])
->withPassword($cfg['pass']),
128
Expand All @@ -141,29 +139,27 @@
$start = \microtime(true);

for ($i = 0; $i < $limit / 1000; $i++) {
//\go(function () use ($cfg, $pool, $name, $namespace, $sharedTables, $cache) {
// \go(function () use ($cfg, $pool, $name, $namespace, $sharedTables, $cache) {
try {
//$pdo = $pool->get();
// $pdo = $pool->get();

$database = (new Database(new ($cfg['adapter'])($pdo), $cache))
->setDatabase($name)
->setNamespace($namespace)
->setSharedTables($sharedTables);

createDocuments($database);
//$pool->put($pdo);
// $pool->put($pdo);
} catch (\Throwable $error) {
Console::error('Coroutine error: ' . $error->getMessage());
Console::error('Coroutine error: '.$error->getMessage());
}
//});
// });
}

$time = microtime(true) - $start;
Console::success("Completed in {$time} seconds");
});



function createDocuments(Database $database): void
{
global $namesPool, $genresPool, $tagsPool;
Expand All @@ -176,7 +172,7 @@ function createDocuments(Database $database): void
$bytes = \random_bytes(intdiv($length + 1, 2));
$text = \substr(\bin2hex($bytes), 0, $length);
$tagCount = \mt_rand(1, count($tagsPool));
$tagKeys = (array)\array_rand($tagsPool, $tagCount);
$tagKeys = (array) \array_rand($tagsPool, $tagCount);
$tags = \array_map(fn ($k) => $tagsPool[$k], $tagKeys);

$documents[] = new Document([
Expand Down
Loading
Loading