Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
* develop:
  specify next release
  fix name mapping not being applied
  add documentation on how to change the name
  add Aggregagtes::mapName()
  • Loading branch information
Baptouuuu committed Jul 26, 2024
2 parents 8dc79e6 + 127139a commit 9f20f28
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 12 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 3.1.0 - 2024-07-26

### Added

- `Formal\ORM\Definition\Aggregagtes::mapName()`

## 3.0.0 - 2024-07-14

### Added
Expand Down
37 changes: 37 additions & 0 deletions documentation/issues.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,43 @@ hide:

# Known issues

## Mapping

### Aggregate name collision

By default the ORM translate an Aggregate class to a simple name in the [adapter](adapters/index.md). For example the class `App\Domain\User` is translated to `user`. This allows to simplify reading the storage folders/tables/indexes.

For small projects this is fine. But for larger projects names collision may arise.

For example you may have the aggregates `App\Domain\Shipping\Product` and `App\Domain\Billing\Product` that would result in the same `product` name in the storage.

You can fix it like this:

```php
use Formal\ORM\{
Manager,
Definition\Aggregates,
Definition\Types,
};

$orm = Manager::of(
/* your storage adapter (1) */,
Aggregates::of(
Types::default(),
)->mapName(static fn(string $class) {
\App\Domain\Shipping\Product::class => 'shippingProduct',
\App\Domain\Billing\Product::class => 'billingProduct',
}),
);
```

1. see [Adapters](adapters/index.md)

!!! info ""
This also allows to fix the default casing of names. For example the class `App\Domain\DocumentTemplate` result in the name `documenttemplate`. Which is not very readable.

This behaviour won't be change for the time being to not break existing projects. But you can gradually fix this via the `mapName` method.

## Elasticsearch

### Searching with `endsWith`
Expand Down
28 changes: 28 additions & 0 deletions proofs/adapter/sql/showCreateTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,32 @@ static function($assert) {
->same($queries);
},
)->tag(Storage::sql);

yield test(
'Aggregate table name can be changed',
static function($assert) {
$show = ShowCreateTable::of(
Aggregates::of(Types::of(
Type\PointInTimeType::of(new Clock),
))->mapName(static fn($string) => match ($string) {
User::class => 'some_user',
}),
);

// the match above allows to make sure the map is only applied to
// aggregate classes and not entities or pproperties

$queries = $show(User::class)
->map(static fn($query) => $query->sql(Driver::mysql))
->toList();

$assert
->expected(
<<<SQL
CREATE TABLE `some_user` (`id` char(36) NOT NULL COMMENT 'UUID', `createdAt` char(32) NOT NULL COMMENT 'Date with timezone down to the microsecond', `name` longtext DEFAULT NULL COMMENT 'TODO adjust the type depending on your use case', `nameStr` longtext DEFAULT NULL COMMENT 'TODO adjust the type depending on your use case', `role` longtext DEFAULT NULL COMMENT 'TODO adjust the type depending on your use case', PRIMARY KEY (`id`))
SQL,
)
->in($queries);
},
)->tag(Storage::sql);
};
29 changes: 20 additions & 9 deletions src/Definition/Aggregate.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ final class Aggregate
{
/** @var class-string<T> */
private string $class;
/** @var non-empty-string */
private string $name;
/** @var Aggregate\Identity<T> */
private Aggregate\Identity $id;
/** @var Sequence<Aggregate\Property<T, mixed>> */
Expand All @@ -32,6 +34,7 @@ final class Aggregate

/**
* @param class-string<T> $class
* @param non-empty-string $name
* @param Aggregate\Identity<T> $id
* @param Sequence<Aggregate\Property<T, mixed>> $properties
* @param Sequence<Aggregate\Entity> $entities
Expand All @@ -40,13 +43,15 @@ final class Aggregate
*/
private function __construct(
string $class,
string $name,
Aggregate\Identity $id,
Sequence $properties,
Sequence $entities,
Sequence $optionals,
Sequence $collections,
) {
$this->class = $class;
$this->name = $name;
$this->id = $id;
$this->properties = $properties;
$this->entities = $entities;
Expand All @@ -58,12 +63,23 @@ private function __construct(
* @internal
* @template A
*
* @param callable(class-string): non-empty-string $mapName
* @param class-string<A> $class
*
* @return self<A>
*/
public static function of(Types $types, string $class): self
{
public static function of(
Types $types,
?callable $mapName,
string $class,
): self {
/** @var callable(class-string): non-empty-string */
$mapName ??= static fn(string $class): string => Str::of($class)
->split('\\')
->takeEnd(1)
->fold(new Concat)
->toLower()
->toString();
/** @var Parsing<A> Type lost due to the reduce */
$parsed = ReflectionClass::of($class)
->properties()
Expand All @@ -75,6 +91,7 @@ public static function of(Types $types, string $class): self
return $parsed->id()->match(
static fn($id) => new self(
$class,
$mapName($class),
$id,
$parsed->properties(),
$parsed->entities(),
Expand All @@ -98,13 +115,7 @@ public function class(): string
*/
public function name(): string
{
/** @var non-empty-string */
return Str::of($this->class)
->split('\\')
->takeEnd(1)
->fold(new Concat)
->toLower()
->toString();
return $this->name;
}

/**
Expand Down
26 changes: 23 additions & 3 deletions src/Definition/Aggregates.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,31 @@
final class Aggregates
{
private Types $types;
/** @var ?callable(class-string): non-empty-string */
private $mapName;

private function __construct(Types $types)
/**
* @param callable(class-string): non-empty-string $mapName
*/
private function __construct(Types $types, ?callable $mapName)
{
$this->types = $types;
$this->mapName = $mapName;
}

public static function of(Types $types): self
{
return new self($types);
return new self($types, null);
}

/**
* @psalm-mutation-free
*
* @param callable(class-string): non-empty-string $map
*/
public function mapName(callable $map): self
{
return new self($this->types, $map);
}

/**
Expand All @@ -26,6 +42,10 @@ public static function of(Types $types): self
*/
public function get(string $class): Aggregate
{
return Aggregate::of($this->types, $class);
return Aggregate::of(
$this->types,
$this->mapName,
$class,
);
}
}

0 comments on commit 9f20f28

Please sign in to comment.