Skip to content

Commit

Permalink
IBX-6824: Added ability to perform queries across multiple tables
Browse files Browse the repository at this point in the history
  • Loading branch information
Steveb-p authored Oct 31, 2023
1 parent a9d2b50 commit 7b81570
Show file tree
Hide file tree
Showing 19 changed files with 761 additions and 111 deletions.
104 changes: 104 additions & 0 deletions .github/workflows/backend-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,107 @@ jobs:

- name: Run test suite
run: composer run-script --timeout=600 test

integration-tests-postgres:
name: PostgreSQL integration tests
needs: tests
services:
postgres:
image: postgres:11
ports:
- 5432
env:
POSTGRES_PASSWORD: postgres
POSTGRES_DB: testdb
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
--tmpfs /var/lib/postgresql/data
runs-on: "ubuntu-22.04"
timeout-minutes: 20

strategy:
matrix:
php:
- '7.4'
- '8.0'
- '8.2'

steps:
- uses: actions/checkout@v3

- name: Setup PHP Action
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: none
extensions: pdo_pgsql, gd
tools: cs2pr

- uses: ramsey/composer-install@v2
with:
dependency-versions: highest

- name: Setup problem matchers for PHPUnit
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"

- name: Run integration test suite on Postgres
run: composer run-script --timeout=600 test-integration
env:
SEARCH_ENGINE: legacy
DATABASE_URL: "pgsql://postgres:postgres@localhost:${{ job.services.postgres.ports[5432] }}/testdb?server_version=10"

integration-tests-mysql:
name: MySQL integration tests
needs: tests
services:
mysql:
image: mysql:8.0
ports:
- 3306/tcp
env:
MYSQL_RANDOM_ROOT_PASSWORD: true
MYSQL_USER: mysql
MYSQL_PASSWORD: mysql
MYSQL_DATABASE: testdb
options: >-
--health-cmd="mysqladmin ping"
--health-interval=10s
--health-timeout=5s
--health-retries=5
--tmpfs=/var/lib/mysql
runs-on: "ubuntu-22.04"
timeout-minutes: 20

strategy:
matrix:
php:
- '7.4'
- '8.0'
- '8.2'

steps:
- uses: actions/checkout@v3

- name: Setup PHP Action
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
coverage: none
extensions: pdo_mysql, gd
tools: cs2pr

- uses: ramsey/composer-install@v2
with:
dependency-versions: highest

- name: Setup problem matchers for PHPUnit
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"

- name: Run integration test suite vs MySQL
run: composer run-script --timeout=600 test-integration
env:
SEARCH_ENGINE: legacy
DATABASE_URL: "mysql://mysql:[email protected]:${{ job.services.mysql.ports[3306] }}/testdb"
11 changes: 8 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,13 @@
"symfony/yaml": "^5.4"
},
"require-dev": {
"phpunit/phpunit": "^9.0",
"dama/doctrine-test-bundle": "^6.7",
"ibexa/code-style": "^1.1",
"ibexa/test-core": "0.1.x-dev",
"phpstan/phpstan": "^1.4",
"phpstan/phpstan-phpunit": "^1.0"
"phpstan/phpstan-phpunit": "^1.0",
"phpunit/phpunit": "^9.0",
"symfony/phpunit-bridge": "^5.4"
},
"autoload": {
"psr-4": {
Expand All @@ -41,6 +44,7 @@
"fix-cs": "php-cs-fixer fix --config=.php-cs-fixer.php --show-progress=dots",
"check-cs": "@fix-cs --dry-run",
"test": "phpunit -c phpunit.xml.dist",
"test-integration": "phpunit -c phpunit.integration.xml",
"phpstan": "phpstan analyse -c phpstan.neon"
},
"scripts-descriptions": {
Expand All @@ -55,6 +59,7 @@
}
},
"config": {
"allow-plugins": false
"allow-plugins": false,
"sort-packages": true
}
}
25 changes: 25 additions & 0 deletions phpunit.integration.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.5/phpunit.xsd"
bootstrap="tests/integration/bootstrap.php"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
failOnWarning="true"
verbose="true">
<php>
<env name="KERNEL_CLASS" value="Ibexa\Tests\Integration\CorePersistence\Kernel" />
<env name="SEARCH_ENGINE" value="legacy" />
<env name="DATABASE_URL" value="sqlite://i@i/var/test.db" />
<env name="SYMFONY_DEPRECATIONS_HELPER" value="max[self]=0&amp;max[direct]=0&amp;verbose=0"/>
</php>
<testsuites>
<testsuite name="integration">
<directory>tests/integration</directory>
</testsuite>
</testsuites>
<extensions>
<extension class="DAMA\DoctrineTestBundle\PHPUnit\PHPUnitExtension" />
</extensions>
<listeners>
<listener class="Symfony\Bridge\PhpUnit\SymfonyTestsListener"/>
</listeners>
</phpunit>
8 changes: 0 additions & 8 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
failOnWarning="true"
colors="true">
<testsuites>
<testsuite name="bundle">
<directory>tests/bundle</directory>
</testsuite>
<testsuite name="integration">
<directory>tests/integration</directory>
</testsuite>
<testsuite name="lib">
<directory>tests/lib</directory>
</testsuite>
Expand Down
3 changes: 3 additions & 0 deletions src/contracts/Gateway/AbstractDoctrineDatabase.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ protected function getTableAlias(): string
return $this->getTableName();
}

/**
* @throws \Ibexa\Contracts\CorePersistence\Exception\MappingExceptionInterface
*/
abstract protected function buildMetadata(): DoctrineSchemaMetadataInterface;

public function getMetadata(): DoctrineSchemaMetadataInterface
Expand Down
44 changes: 44 additions & 0 deletions src/contracts/Gateway/AbstractDoctrineRelationship.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

/**
* @copyright Copyright (C) Ibexa AS. All rights reserved.
* @license For full copyright and license information view LICENSE file distributed with this source code.
*/
declare(strict_types=1);

namespace Ibexa\Contracts\CorePersistence\Gateway;

abstract class AbstractDoctrineRelationship implements DoctrineRelationshipInterface
{
/** @var class-string */
protected string $relationshipClass;

/** @var non-empty-string */
protected string $foreignProperty;

/** @var non-empty-string */
protected string $foreignKeyColumn;

/** @var non-empty-string */
protected string $relatedClassIdColumn;

public function getRelationshipClass(): string
{
return $this->relationshipClass;
}

public function getRelatedClassIdColumn(): string
{
return $this->relatedClassIdColumn;
}

public function getForeignProperty(): string
{
return $this->foreignProperty;
}

public function getForeignKeyColumn(): string
{
return $this->foreignKeyColumn;
}
}
30 changes: 9 additions & 21 deletions src/contracts/Gateway/DoctrineOneToManyRelationship.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,10 @@

namespace Ibexa\Contracts\CorePersistence\Gateway;

final class DoctrineOneToManyRelationship implements DoctrineRelationshipInterface
{
/** @var class-string */
private string $relationshipClass;

/** @var non-empty-string */
private string $foreignProperty;

/** @var non-empty-string */
private string $relatedClassIdColumn;
use LogicException;

final class DoctrineOneToManyRelationship extends AbstractDoctrineRelationship
{
/**
* @param class-string $relationshipClass
* @param non-empty-string $foreignProperty
Expand All @@ -34,23 +27,18 @@ public function __construct(
$this->relatedClassIdColumn = $relatedClassIdColumn;
}

public function getRelationshipClass(): string
{
return $this->relationshipClass;
}

public function getRelatedClassIdColumn(): string
public function getForeignKeyColumn(): string
{
return $this->relatedClassIdColumn;
return '';
}

public function getForeignProperty(): string
public function setJoinType(string $joinType): void
{
return $this->foreignProperty;
throw new LogicException('Intentionally not implemented.');
}

public function getForeignKeyColumn(): string
public function getJoinType(): string
{
return '';
return DoctrineRelationship::JOIN_TYPE_JOINED;
}
}
52 changes: 23 additions & 29 deletions src/contracts/Gateway/DoctrineRelationship.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,55 +11,49 @@
/**
* @internal
*/
final class DoctrineRelationship implements DoctrineRelationshipInterface
final class DoctrineRelationship extends AbstractDoctrineRelationship
{
/** @var class-string */
private string $relationshipClass;
public const JOIN_TYPE_SUB_SELECT = 'subselect';

/** @var non-empty-string */
private string $foreignProperty;
public const JOIN_TYPE_JOINED = 'joined';

/** @var non-empty-string */
private string $foreignKeyColumn;

/** @var non-empty-string */
private string $relatedClassIdColumn;
/** @phpstan-var self::JOIN_TYPE_* */
private string $joinType;

/**
* @param class-string $relationshipClass
* @param non-empty-string $foreignProperty
* @param non-empty-string $foreignKeyColumn
* @param non-empty-string $relatedClassIdColumn
* @phpstan-param class-string $relationshipClass
* @phpstan-param non-empty-string $foreignProperty
* @phpstan-param non-empty-string $foreignKeyColumn
* @phpstan-param non-empty-string $relatedClassIdColumn
* @phpstan-param self::JOIN_TYPE_* $joinType
*/
public function __construct(
string $relationshipClass,
string $foreignProperty,
string $foreignKeyColumn,
string $relatedClassIdColumn
string $relatedClassIdColumn,
string $joinType = self::JOIN_TYPE_SUB_SELECT
) {
$this->relationshipClass = $relationshipClass;
$this->foreignProperty = $foreignProperty;
$this->foreignKeyColumn = $foreignKeyColumn;
$this->relatedClassIdColumn = $relatedClassIdColumn;
$this->setJoinType($joinType);
}

public function getRelationshipClass(): string
{
return $this->relationshipClass;
}

public function getRelatedClassIdColumn(): string
{
return $this->relatedClassIdColumn;
}

public function getForeignProperty(): string
/**
* @phpstan-param self::JOIN_TYPE_* $joinType
*/
public function setJoinType(string $joinType): void
{
return $this->foreignProperty;
$this->joinType = $joinType;
}

public function getForeignKeyColumn(): string
/**
* @phpstan-return self::JOIN_TYPE_*
*/
public function getJoinType(): string
{
return $this->foreignKeyColumn;
return $this->joinType;
}
}
4 changes: 4 additions & 0 deletions src/contracts/Gateway/DoctrineRelationshipInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,8 @@ public function getForeignProperty(): string;
* @return non-empty-string
*/
public function getForeignKeyColumn(): string;

public function setJoinType(string $joinType): void;

public function getJoinType(): string;
}
3 changes: 3 additions & 0 deletions src/contracts/Gateway/GatewayInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*/
interface GatewayInterface
{
/**
* @throws \Ibexa\Contracts\CorePersistence\Exception\MappingExceptionInterface
*/
public function getMetadata(): DoctrineSchemaMetadataInterface;

public function countAll(): int;
Expand Down
Loading

0 comments on commit 7b81570

Please sign in to comment.