Skip to content

Commit

Permalink
Fix Field to SQL convert when materialized field is available
Browse files Browse the repository at this point in the history
  • Loading branch information
mvorisek committed Dec 20, 2022
1 parent 0a88e37 commit 168073e
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 5 deletions.
8 changes: 7 additions & 1 deletion src/Model/AggregateModel.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
use Atk4\Data\Model;
use Atk4\Data\Persistence;
use Atk4\Data\Persistence\Sql\Expression;
use Atk4\Data\Persistence\Sql\MaterializedField;
use Atk4\Data\Persistence\Sql\Query;

/**
Expand Down Expand Up @@ -90,6 +91,11 @@ public function setGroupBy(array $fields, array $aggregateExpressions = [])

$seed['expr'] = $this->table->expr($seed['expr'], $exprArgs);

// convert base model fields to aliases, they are always already materialized as the base model is SQL inner table
foreach ($seed['expr']->args['custom'] as $argK => $argV) {
$seed['expr']->args['custom'][$argK] = new MaterializedField($this->table, $argV);
}

$this->addExpression($name, $seed);
}

Expand Down Expand Up @@ -160,7 +166,7 @@ protected function initQueryGrouping(Query $query): void
if ($field instanceof Expression) {
$expression = $field;
} else {
$expression = $this->table->getField($field)->shortName /* TODO shortName should be used by DSQL automatically when in GROUP BY, HAVING, ... */;
$expression = new MaterializedField($this->table, $this->table->getField($field));
}

$query->group($expression);
Expand Down
3 changes: 3 additions & 0 deletions src/Model/EntityFieldPair.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Atk4\Data\Model;

use Atk4\Core\WarnDynamicPropertyTrait;
use Atk4\Data\Field;
use Atk4\Data\Model;

Expand All @@ -13,6 +14,8 @@
*/
class EntityFieldPair
{
use WarnDynamicPropertyTrait;

/** @var TModel */
private $entity;
/** @var string */
Expand Down
33 changes: 33 additions & 0 deletions src/Persistence/Sql/MaterializedField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Atk4\Data\Persistence\Sql;

use Atk4\Core\WarnDynamicPropertyTrait;
use Atk4\Data\Field;
use Atk4\Data\Model;
use Atk4\Data\Persistence\Sql\Expression;
use Atk4\Data\Persistence\Sql\Expressionable;

/**
* TODO shortName should be used by DSQL automatically when in GROUP BY, HAVING, ...
*/
class MaterializedField implements Expressionable
{
use WarnDynamicPropertyTrait;

protected Field $field;

public function __construct(Model $context, Field $field)
{
$field->getOwner()->assertIsModel($context);

$this->field = $field;
}

public function getDsqlExpression(Expression $expression): Expression
{
return $expression->expr('{}', [$this->field->shortName]);
}
}
20 changes: 16 additions & 4 deletions tests/ModelAggregateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,22 +121,30 @@ public function testGroupSelect3(): void
], $aggregate->export());
}

public function testGroupSelectExpr(): void
public function testGroupSelectExpression(): void
{
$aggregate = $this->createInvoiceAggregate();
$aggregate->addField('client');

$aggregate->table->ref('client_id')
->loadBy('name', 'Vinny')
->set('order', 21)
->save();
$aggregate->table->getReference('client_id')
->addField('order');

$aggregate->setGroupBy(['client_id'], [
's' => ['expr' => 'sum([amount])', 'type' => 'atk4_money'],
'amount' => ['expr' => 'sum([])', 'type' => 'atk4_money'],
'sum 1:1' => ['expr' => 'sum([order])', 'type' => 'integer'],
]);
self::fixAllNonAggregatedFieldsInGroupBy($aggregate);

$aggregate->addExpression('double', ['expr' => '[s] + [amount]', 'type' => 'atk4_money']);

static::assertSameExportUnordered([
['client' => 'Vinny', 'client_id' => 1, 's' => 19.0, 'amount' => 19.0, 'double' => 38.0],
['client' => 'Zoe', 'client_id' => 2, 's' => 4.0, 'amount' => 4.0, 'double' => 8.0],
['client' => 'Vinny', 'client_id' => 1, 's' => 19.0, 'amount' => 19.0, 'sum 1:1' => 42, 'double' => 38.0],
['client' => 'Zoe', 'client_id' => 2, 's' => 4.0, 'amount' => 4.0, 'sum 1:1' => null, 'double' => 8.0],
], $aggregate->export());
}

Expand Down Expand Up @@ -344,12 +352,16 @@ public function testAggregateFieldExpressionSql(): void
{
$aggregate = $this->createInvoiceAggregate();

$aggregate->table->getReference('client_id')
->addField('order');

$aggregate->setGroupBy([$aggregate->expr('{}', ['abc'])], [
'xyz' => ['expr' => 'sum([amount])'],
'sum 1:1' => ['expr' => 'sum([order])', 'type' => 'integer'],
]);

$this->assertSameSql(
'select sum(`amount`) `xyz` from (select `id`, `client_id`, `name`, `amount`, (select `name` from `client` `_c_2bfe9d72a4aa` where `id` = `invoice`.`client_id`) `client` from `invoice`) `_tm` group by `abc`',
'select sum(`amount`) `xyz`, sum(`order`) `sum 1:1` from (select `id`, `client_id`, `name`, `amount`, (select `name` from `client` `_c_2bfe9d72a4aa` where `id` = `invoice`.`client_id`) `client`, (select `order` from `client` `_c_2bfe9d72a4aa` where `id` = `invoice`.`client_id`) `order` from `invoice`) `_tm` group by `abc`',
$aggregate->action('select')->render()[0]
);
}
Expand Down

0 comments on commit 168073e

Please sign in to comment.