Skip to content

Commit

Permalink
Merge pull request #10 from formal-php/fix-capabilities-for-orm
Browse files Browse the repository at this point in the history
Fix capabilities for orm
  • Loading branch information
Baptouuuu authored Jul 14, 2024
2 parents aec3390 + caed645 commit 55d6577
Show file tree
Hide file tree
Showing 14 changed files with 289 additions and 78 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/composer.lock
/vendor
/.cache
/tmp
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
# Changelog

## [Unreleased]

### Added

- `Formal\AccessLayer\Query\Delete::join()`

### Removed

- `Formal\AccessLayer\Driver::sqlite`

### Fixed

- Support for aliased table names when using `Formal\AccessLayer\Query\Delete`

## 3.0.0 - 2024-07-14

### Added
Expand Down
8 changes: 0 additions & 8 deletions documentation/connections/pdo.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,6 @@ To build an instance of it you only need the dsn to your database:
);
```

=== "SQLite"
```php
use Formal\AccessLayer\Connection\PDO;
use Innmind\Url\Url;

$connection = PDO::of(Url::of('sqlite:///path/to/database/file.sq3'));
```

When executing a [query](../queries/sql.md) through this connection it will return a [deferred `Sequence`](http://innmind.github.io/Immutable/structures/sequence/#defer) of rows. This means that the rows returned from the database are only loaded once you iterate over the sequence. (Queries with the named constructor `::onDemand()` will return a lazy `Sequence`).

!!! note ""
Expand Down
100 changes: 74 additions & 26 deletions proofs/connection/pdo.php
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,6 @@ static function($assert) use ($driver) {
$assert->same(
match ($driver) {
Driver::mysql => 'CONSTRAINT `FK_foo` FOREIGN KEY (`parent`) REFERENCES `parent_table`(`id`)',
Driver::sqlite => 'CONSTRAINT "FK_foo" FOREIGN KEY ("parent") REFERENCES "parent_table"("id")',
Driver::postgres => 'CONSTRAINT "FK_foo" FOREIGN KEY ("parent") REFERENCES "parent_table"("id")',
},
ForeignKey::of(Column\Name::of('parent'), $parent, Column\Name::of('id'))
Expand All @@ -405,6 +404,79 @@ static function($assert) use ($driver) {
},
);

yield test(
"Delete join({$driver->name})",
static function($assert) use ($connection) {
$parent = Table\Name::of('test_join_delete_parent')->as('parent');
$child = Table\Name::of('test_join_delete_child')->as('child');
$connection(CreateTable::ifNotExists(
$child->name(),
Column::of(
Column\Name::of('id'),
Column\Type::int(),
),
)->primaryKey(Column\Name::of('id')));
$connection(
CreateTable::ifNotExists(
$parent->name(),
Column::of(
Column\Name::of('id'),
Column\Type::int(),
),
Column::of(
Column\Name::of('child'),
Column\Type::int(),
),
)
->primaryKey(Column\Name::of('id'))
->foreignKey(
Column\Name::of('child'),
$child->name(),
Column\Name::of('id'),
),
);
$connection(Delete::from($parent->name()));
$connection(Delete::from($child->name()));
$connection(Insert::into(
$child->name(),
Row::of([
'id' => 2,
]),
));
$connection(Insert::into(
$parent->name(),
Row::of([
'id' => 1,
'child' => 2,
]),
));

$connection(
Delete::from($parent)
->join(
Join::left($child)->on(
Column\Name::of('child')->in($parent),
Column\Name::of('id')->in($child),
),
)
->where(Comparator\Property::of(
'child.id',
Sign::equality,
2,
)),
);

$rows = $connection(Select::from($child));
$assert->count(1, $rows);

$rows = $connection(Select::from($parent));
$assert->count(0, $rows);

$connection(DropTable::named($parent->name()));
$connection(DropTable::named($child->name()));
},
);

yield proof(
"Unique constraint({$driver->name})",
given(Set\Integers::between(0, 1_000_000)),
Expand Down Expand Up @@ -449,30 +521,13 @@ static function($assert, $int) use ($connection) {
},
);

$filter = match ($driver) {
Driver::sqlite => static fn($ensure) => \count(
\array_filter(
$ensure->properties(),
static fn($property) => $property instanceof Properties\MustThrowWhenValueDoesntFitTheSchema,
)
) === 0,
default => static fn() => true,
};

yield properties(
"PDO properties({$driver->name})",
Properties::any()->filter($filter),
Properties::any(),
$connections,
);

foreach (Properties::list() as $property) {
if (
$driver === Driver::sqlite &&
$property === Properties\MustThrowWhenValueDoesntFitTheSchema::class
) {
continue;
}

yield property(
$property,
$connections,
Expand All @@ -488,13 +543,6 @@ static function($assert, $int) use ($connection) {
Driver::mysql,
);

$tmp = \getcwd().'/tmp';

yield from $proofs(
Url::of("sqlite:$tmp/formal.sq3"),
Driver::sqlite,
);

$port = \getenv('POSTGRES_DB_PORT') ?: '5432';

yield from $proofs(
Expand Down
1 change: 1 addition & 0 deletions properties/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public static function list(): array
Connection\Update::class,
Connection\UpdateSpecificRow::class,
Connection\Delete::class,
Connection\DeleteWithAlias::class,
Connection\DeleteSpecificRow::class,
];
}
Expand Down
4 changes: 2 additions & 2 deletions properties/Connection/DeleteSpecificRow.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,9 @@ public function ensureHeldBy(Assert $assert, object $connection): object
]),
)));

$delete = Query\Delete::from(Table\Name::of('test'))->where(
$delete = Query\Delete::from(Table\Name::of('test')->as('alias'))->where(
Comparator\Property::of(
'id',
'alias.id',
Sign::equality,
$this->uuid1,
),
Expand Down
65 changes: 65 additions & 0 deletions properties/Connection/DeleteWithAlias.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php
declare(strict_types = 1);

namespace Properties\Formal\AccessLayer\Connection;

use Formal\AccessLayer\{
Query\SQL,
Query,
Table,
Row,
Connection,
};
use Innmind\BlackBox\{
Property,
Set,
Runner\Assert,
};

/**
* @implements Property<Connection>
*/
final class DeleteWithAlias implements Property
{
private string $uuid;

public function __construct(string $uuid)
{
$this->uuid = $uuid;
}

public static function any(): Set
{
return Set\Uuid::any()->map(static fn($uuid) => new self($uuid));
}

public function applicableTo(object $connection): bool
{
return true;
}

public function ensureHeldBy(Assert $assert, object $connection): object
{
$select = SQL::of('SELECT * FROM test');
$connection(Query\Insert::into(
Table\Name::of('test'),
Row::of([
'id' => $this->uuid,
'username' => 'foo',
'registerNumber' => 42,
]),
));

$sequence = $connection(Query\Delete::from(
Table\Name::of('test')->as('alias'),
));

$assert->count(0, $sequence);

$rows = $connection($select);

$assert->count(0, $rows);

return $connection;
}
}
27 changes: 8 additions & 19 deletions src/Connection/PDO.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ private function __construct(Url $dsn, array $options = [])
}

$this->driver = match ($dsn->scheme()->toString()) {
'sqlite' => Driver::sqlite,
'mysql' => Driver::mysql,
'pgsql' => Driver::postgres,
};
Expand All @@ -59,26 +58,16 @@ private function __construct(Url $dsn, array $options = [])
}
}

$pdoDsn = match ($this->driver) {
Driver::sqlite => \sprintf(
'sqlite:%s',
$dsn->path()->toString(),
),
default => \sprintf(
'%s:host=%s;port=%s;dbname=%s%s',
$dsn->scheme()->toString(),
$dsn->authority()->host()->toString(),
$dsn->authority()->port()->toString(),
\substr($dsn->path()->toString(), 1), // substring to remove leading '/'
$charset,
),
};
$pdoDsn = \sprintf(
'%s:host=%s;port=%s;dbname=%s%s',
$dsn->scheme()->toString(),
$dsn->authority()->host()->toString(),
$dsn->authority()->port()->toString(),
\substr($dsn->path()->toString(), 1), // substring to remove leading '/'
$charset,
);

$this->pdo = new \PDO($pdoDsn, $user, $password, $options);

if ($this->driver === Driver::sqlite) {
$this->pdo->query('PRAGMA foreign_keys = ON');
}
}

public function __invoke(Query $query): Sequence
Expand Down
2 changes: 0 additions & 2 deletions src/Driver.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
enum Driver
{
case mysql;
case sqlite;
case postgres;

/**
Expand All @@ -21,7 +20,6 @@ public function escapeName(string $name): string
{
return match ($this) {
self::mysql => "`$name`",
self::sqlite => "\"$name\"",
self::postgres => "\"$name\"",
};
}
Expand Down
Loading

0 comments on commit 55d6577

Please sign in to comment.