Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[POC] Implement inner join autorewrite #643

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 4 additions & 3 deletions src/Collection/DbalCollection.php
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,13 @@ public function orderBy($expression, string $direction = ICollection::ASC): ICol

foreach ($expression as $subExpression => $subDirection) {
$collection->ordering[] = [
$helper->processExpression($collection->queryBuilder, $subExpression, null),
$helper->processExpression($collection->queryBuilder, $subExpression, filterableJoin: false, aggregator: null),
$subDirection,
];
}
} else {
$collection->ordering[] = [
$helper->processExpression($collection->queryBuilder, $expression, null),
$helper->processExpression($collection->queryBuilder, $expression, filterableJoin: false, aggregator: null),
$direction,
];
}
Expand Down Expand Up @@ -325,7 +325,8 @@ public function getQueryBuilder(): QueryBuilder
$expression = $helper->processExpression(
$this->queryBuilder,
$args,
null,
filterableJoin: true,
aggregator: null,
);
$joins = $expression->joins;
if ($expression->isHavingClause) {
Expand Down
29 changes: 27 additions & 2 deletions src/Collection/Functions/BaseCompareFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Nextras\Orm\Collection\Aggregations\IDbalAggregator;
use Nextras\Orm\Collection\Functions\Result\ArrayExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalExpressionResult;
use Nextras\Orm\Collection\Functions\Result\DbalTableJoin;
use Nextras\Orm\Collection\Helpers\ArrayCollectionHelper;
use Nextras\Orm\Collection\Helpers\DbalQueryBuilderHelper;
use Nextras\Orm\Entity\IEntity;
Expand Down Expand Up @@ -59,12 +60,13 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
bool $filterableJoin,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult
{
assert(count($args) === 2);

$expression = $helper->processExpression($builder, $args[0], $aggregator);
$expression = $helper->processExpression($builder, $args[0], $filterableJoin, $aggregator);

if ($expression->valueNormalizer !== null) {
$cb = $expression->valueNormalizer;
Expand All @@ -73,7 +75,30 @@ public function processDbalExpression(
$value = $args[1];
}

return $this->evaluateInDb($expression, $value, $expression->dbalModifier ?? '%any');
$hasJoins = count($expression->joins) > 0;
$expression = $this->evaluateInDb($expression, $value, $expression->dbalModifier ?? '%any');

// Let's inline the condition to the join if it is allowed & if there is any join.
if (!$filterableJoin || !$hasJoins || $expression->isHavingClause) {
return $expression;
}

$joins = $expression->joins;
/** @var DbalTableJoin $lastJoin */
$lastJoin = array_pop($joins);
$joins[] = $lastJoin->withCondition($expression->expression, ...$expression->args);

return new DbalExpressionResult(
expression: "(1=1)",
args: [],
joins: $joins,
groupBy: [],
aggregator: null,
isHavingClause: false,
propertyMetadata: null,
valueNormalizer: null,
dbalModifier: null,
);
}


Expand Down
3 changes: 2 additions & 1 deletion src/Collection/Functions/BaseNumericAggregateFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
bool $filterableJoin,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult
{
Expand All @@ -63,6 +64,6 @@ public function processDbalExpression(
throw new InvalidStateException("Cannot apply two aggregations simultaneously.");
}

return $helper->processExpression($builder, $args[0], $this->aggregator)->applyAggregator($builder);
return $helper->processExpression($builder, $args[0], $filterableJoin, $this->aggregator)->applyAggregator($builder);
}
}
1 change: 1 addition & 0 deletions src/Collection/Functions/CollectionFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
bool $filterableJoin,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult;
}
3 changes: 2 additions & 1 deletion src/Collection/Functions/CompareLikeFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,13 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
bool $filterableJoin,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult
{
assert(count($args) === 2);

$expression = $helper->processExpression($builder, $args[0], $aggregator);
$expression = $helper->processExpression($builder, $args[0], $filterableJoin, $aggregator);

$likeExpression = $args[1];
assert($likeExpression instanceof LikeExpression);
Expand Down
2 changes: 2 additions & 0 deletions src/Collection/Functions/ConjunctionOperatorFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
bool $filterableJoin,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult
{
Expand All @@ -113,6 +114,7 @@ public function processDbalExpression(
helper: $helper,
builder: $builder,
args: $args,
filterableJoin: $filterableJoin,
aggregator: $aggregator,
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/Collection/Functions/DisjunctionOperatorFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
bool $filterableJoin,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult
{
Expand All @@ -106,6 +107,7 @@ public function processDbalExpression(
helper: $helper,
builder: $builder,
args: $args,
filterableJoin: false,
aggregator: $aggregator,
);
}
Expand Down
1 change: 1 addition & 0 deletions src/Collection/Functions/FetchPropertyFunction.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ public function processDbalExpression(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
bool $filterableJoin,
?IDbalAggregator $aggregator = null,
): DbalExpressionResult
{
Expand Down
3 changes: 2 additions & 1 deletion src/Collection/Functions/JunctionFunctionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ protected function processQueryBuilderExpressionWithModifier(
DbalQueryBuilderHelper $helper,
QueryBuilder $builder,
array $args,
bool $filterableJoin,
?IDbalAggregator $aggregator,
): DbalExpressionResult
{
Expand All @@ -77,7 +78,7 @@ protected function processQueryBuilderExpressionWithModifier(
}

foreach ($normalized as $collectionFunctionArgs) {
$expression = $helper->processExpression($builder, $collectionFunctionArgs, $aggregator);
$expression = $helper->processExpression($builder, $collectionFunctionArgs, $filterableJoin, $aggregator);
$expression = $expression->applyAggregator($builder);
$processedArgs[] = $expression->getArgumentsForExpansion();
$joins = array_merge($joins, $expression->joins);
Expand Down
36 changes: 30 additions & 6 deletions src/Collection/Functions/Result/DbalTableJoin.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
string $onExpression,
array $onArgs,
IConventions $conventions,
public readonly bool $inner = false,
)
{
$this->toExpression = $toExpression;
Expand All @@ -55,13 +56,36 @@
}


public function applyJoin(QueryBuilder $queryBuilder): void
public function withCondition(string $expression, ...$expresionArgs): DbalTableJoin

Check failure on line 59 in src/Collection/Functions/Result/DbalTableJoin.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.1)

Method Nextras\Orm\Collection\Functions\Result\DbalTableJoin::withCondition() has parameter $expresionArgs with no type specified.

Check failure on line 59 in src/Collection/Functions/Result/DbalTableJoin.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.2)

Method Nextras\Orm\Collection\Functions\Result\DbalTableJoin::withCondition() has parameter $expresionArgs with no type specified.

Check failure on line 59 in src/Collection/Functions/Result/DbalTableJoin.php

View workflow job for this annotation

GitHub Actions / PHPStan (8.3)

Method Nextras\Orm\Collection\Functions\Result\DbalTableJoin::withCondition() has parameter $expresionArgs with no type specified.
{
$queryBuilder->joinLeft(
"$this->toExpression AS [$this->toAlias]",
$this->onExpression,
...$this->toArgs,
...$this->onArgs,
return new self(
toExpression: $this->toExpression,
toArgs: $this->toArgs,
toAlias: $this->toAlias,
onExpression: "$this->onExpression AND $expression",
onArgs: array_merge($this->onArgs, $expresionArgs),
conventions: $this->conventions,
inner: true,
);
}


public function applyJoin(QueryBuilder $queryBuilder): void
{
if ($this->inner) {
$queryBuilder->joinInner(
"$this->toExpression AS [$this->toAlias]",
$this->onExpression,
...$this->toArgs,
...$this->onArgs,
);
} else {
$queryBuilder->joinLeft(
"$this->toExpression AS [$this->toAlias]",
$this->onExpression,
...$this->toArgs,
...$this->onArgs,
);
}
}
}
6 changes: 4 additions & 2 deletions src/Collection/Helpers/DbalQueryBuilderHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ public function __construct(
public function processExpression(
QueryBuilder $builder,
array|string $expression,
bool $filterableJoin,
?IDbalAggregator $aggregator,
): DbalExpressionResult
{
Expand All @@ -85,7 +86,7 @@ public function processExpression(
$collectionFunction = $this->repository->getCollectionFunction($function);
}

return $collectionFunction->processDbalExpression($this, $builder, $expression, $aggregator);
return $collectionFunction->processDbalExpression($this, $builder, $expression, $filterableJoin, $aggregator);
}


Expand Down Expand Up @@ -143,7 +144,7 @@ public function mergeJoins(string $dbalModifier, array $joins): array
/** @var array<array<DbalTableJoin>> $aggregated */
$aggregated = [];
foreach ($joins as $join) {
$hash = md5(Json::encode([$join->onExpression, $join->onArgs]));
$hash = md5(Json::encode([$join->onExpression, $join->onArgs, $join->inner]));
/**
* We aggregate only by alias as we assume that having a different alias
* for different select-from expressions is a responsibility of the query-helper/user.
Expand All @@ -170,6 +171,7 @@ public function mergeJoins(string $dbalModifier, array $joins): array
onExpression: $dbalModifier,
onArgs: [$args],
conventions: $first->conventions,
inner: $first->inner,
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ START TRANSACTION;
INSERT INTO "books" ("title", "author_id", "translator_id", "next_part", "ean_id", "publisher_id", "published_at", "printed_at", "price", "price_currency", "orig_price_cents", "orig_price_currency") VALUES ('Books 5', 1, 2, NULL, NULL, 1, '2021-12-31 23:59:59.000000'::timestamp, NULL, NULL, NULL, NULL, NULL);
SELECT CURRVAL('books_id_seq');
COMMIT;
SELECT "books".* FROM "books" AS "books" LEFT JOIN "public"."authors" AS "author" ON ("books"."author_id" = "author"."id") LEFT JOIN "public"."authors" AS "translator" ON ("books"."translator_id" = "translator"."id") WHERE (("author"."name" = 'Writer 1') AND ("translator"."web" = 'http://example.com/2'));
SELECT "books".* FROM "books" AS "books" INNER JOIN "public"."authors" AS "author" ON ("books"."author_id" = "author"."id" AND "author"."name" = 'Writer 1') INNER JOIN "public"."authors" AS "translator" ON ("books"."translator_id" = "translator"."id" AND "translator"."web" = 'http://example.com/2') WHERE (((1=1)) AND ((1=1)));
Original file line number Diff line number Diff line change
@@ -1 +1 @@
SELECT "books".* FROM "books" AS "books" LEFT JOIN "public"."authors" AS "author" ON ("books"."author_id" = "author"."id") WHERE (("author"."name" = 'Writer 1') AND ("author"."web" = 'http://example.com/1'));
SELECT "books".* FROM "books" AS "books" INNER JOIN "public"."authors" AS "author" ON (("books"."author_id" = "author"."id" AND "author"."name" = 'Writer 1') AND ("books"."author_id" = "author"."id" AND "author"."web" = 'http://example.com/1')) WHERE (((1=1)) AND ((1=1)));
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
SELECT COUNT(*) AS count FROM (SELECT "books"."id" FROM "books" AS "books" LEFT JOIN "public"."authors" AS "author" ON ("books"."author_id" = "author"."id") WHERE (("author"."name" = 'Writer 1')) ORDER BY "books"."id" ASC LIMIT 5) temp;
SELECT COUNT(*) AS count FROM (SELECT "tag_followers"."tag_id", "tag_followers"."author_id" FROM "tag_followers" AS "tag_followers" LEFT JOIN "tags" AS "tag" ON ("tag_followers"."tag_id" = "tag"."id") WHERE (("tag"."name" = 'Tag 1')) ORDER BY "tag_followers"."tag_id" ASC LIMIT 3) temp;
SELECT COUNT(*) AS count FROM (SELECT "books"."id" FROM "books" AS "books" INNER JOIN "public"."authors" AS "author" ON ("books"."author_id" = "author"."id" AND "author"."name" = 'Writer 1') WHERE (((1=1))) ORDER BY "books"."id" ASC LIMIT 5) temp;
SELECT COUNT(*) AS count FROM (SELECT "tag_followers"."tag_id", "tag_followers"."author_id" FROM "tag_followers" AS "tag_followers" INNER JOIN "tags" AS "tag" ON ("tag_followers"."tag_id" = "tag"."id" AND "tag"."name" = 'Tag 1') WHERE (((1=1))) ORDER BY "tag_followers"."tag_id" ASC LIMIT 3) temp;
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ SELECT CURRVAL('eans_id_seq');
INSERT INTO "books" ("title", "author_id", "translator_id", "next_part", "ean_id", "publisher_id", "published_at", "printed_at", "price", "price_currency", "orig_price_cents", "orig_price_currency") VALUES ('Book 5', 1, NULL, 4, 2, 1, '2021-12-31 23:59:59.000000'::timestamp, NULL, NULL, NULL, NULL, NULL);
SELECT CURRVAL('books_id_seq');
COMMIT;
SELECT "books".* FROM "books" AS "books" LEFT JOIN "books" AS "nextPart" ON ("books"."next_part" = "nextPart"."id") LEFT JOIN "eans" AS "nextPart_ean" ON ("nextPart"."ean_id" = "nextPart_ean"."id") LEFT JOIN "books" AS "previousPart" ON ("books"."id" = "previousPart"."next_part") LEFT JOIN "eans" AS "previousPart_ean" ON ("previousPart"."ean_id" = "previousPart_ean"."id") WHERE (("nextPart_ean"."code" = '123') AND ("previousPart_ean"."code" = '456'));
SELECT "books".* FROM "books" AS "books" LEFT JOIN "books" AS "nextPart" ON ("books"."next_part" = "nextPart"."id") INNER JOIN "eans" AS "nextPart_ean" ON ("nextPart"."ean_id" = "nextPart_ean"."id" AND "nextPart_ean"."code" = '123') LEFT JOIN "books" AS "previousPart" ON ("books"."id" = "previousPart"."next_part") INNER JOIN "eans" AS "previousPart_ean" ON ("previousPart"."ean_id" = "previousPart_ean"."id" AND "previousPart_ean"."code" = '456') WHERE (((1=1)) AND ((1=1)));
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
SELECT "tags".* FROM "tags" AS "tags" WHERE (("tags"."id" = 1));
SELECT "books_x_tags"."book_id", "books_x_tags"."tag_id" FROM "books" AS "books" LEFT JOIN "public"."authors" AS "author" ON ("books"."author_id" = "author"."id") LEFT JOIN "books_x_tags" AS "books_x_tags" ON ("books_x_tags"."book_id" = "books"."id") WHERE ((("author"."id" = 1))) AND ("books_x_tags"."tag_id" IN (1));
SELECT "books_x_tags"."book_id", "books_x_tags"."tag_id" FROM "books" AS "books" INNER JOIN "public"."authors" AS "author" ON ("books"."author_id" = "author"."id" AND "author"."id" = 1) LEFT JOIN "books_x_tags" AS "books_x_tags" ON ("books_x_tags"."book_id" = "books"."id") WHERE ((((1=1)))) AND ("books_x_tags"."tag_id" IN (1));
SELECT "books".* FROM "books" AS "books" WHERE (("books"."id" IN (1)));
SELECT "books_x_tags"."tag_id", COUNT(DISTINCT "books_x_tags"."book_id") AS "count" FROM "books" AS "books" LEFT JOIN "public"."authors" AS "author" ON ("books"."author_id" = "author"."id") LEFT JOIN "books_x_tags" AS "books_x_tags" ON ("books_x_tags"."book_id" = "books"."id") WHERE ((("author"."id" = 1))) AND ("books_x_tags"."tag_id" IN (1)) GROUP BY "books_x_tags"."tag_id";
SELECT "books_x_tags"."tag_id", COUNT(DISTINCT "books_x_tags"."book_id") AS "count" FROM "books" AS "books" INNER JOIN "public"."authors" AS "author" ON ("books"."author_id" = "author"."id" AND "author"."id" = 1) LEFT JOIN "books_x_tags" AS "books_x_tags" ON ("books_x_tags"."book_id" = "books"."id") WHERE ((((1=1)))) AND ("books_x_tags"."tag_id" IN (1)) GROUP BY "books_x_tags"."tag_id";
SELECT "books_x_tags"."book_id", "books_x_tags"."tag_id" FROM "books" AS "books" LEFT JOIN "public"."authors" AS "author" ON ("books"."author_id" = "author"."id") LEFT JOIN "tag_followers" AS "author_tagFollowers_any" ON ("author"."id" = "author_tagFollowers_any"."author_id") LEFT JOIN "public"."authors" AS "author_tagFollowers_author_any" ON (("author_tagFollowers_any"."author_id" = "author_tagFollowers_author_any"."id") AND "author_tagFollowers_author_any"."id" = 1) LEFT JOIN "books_x_tags" AS "books_x_tags" ON ("books_x_tags"."book_id" = "books"."id") WHERE "books_x_tags"."tag_id" IN (1) GROUP BY "books"."id", "books_x_tags"."book_id", "books_x_tags"."tag_id" HAVING ((COUNT("author_tagFollowers_author_any"."id") > 0));
SELECT "books".* FROM "books" AS "books" WHERE (("books"."id" IN (1)));
SELECT "books_x_tags"."tag_id", COUNT(DISTINCT "books_x_tags"."book_id") AS "count" FROM "books" AS "books" LEFT JOIN "public"."authors" AS "author" ON ("books"."author_id" = "author"."id") LEFT JOIN "tag_followers" AS "author_tagFollowers_any" ON ("author"."id" = "author_tagFollowers_any"."author_id") LEFT JOIN "public"."authors" AS "author_tagFollowers_author_any" ON (("author_tagFollowers_any"."author_id" = "author_tagFollowers_author_any"."id") AND "author_tagFollowers_author_any"."id" = 1) LEFT JOIN "books_x_tags" AS "books_x_tags" ON ("books_x_tags"."book_id" = "books"."id") WHERE "books_x_tags"."tag_id" IN (1) GROUP BY "books"."id", "books_x_tags"."tag_id" HAVING ((COUNT("author_tagFollowers_author_any"."id") > 0));
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ INSERT INTO "users" ("id") VALUES (123);
COMMIT;
START TRANSACTION;
INSERT INTO "users" ("id") VALUES (124);
INSERT INTO "users_x_users" ("my_friends_id", "friends_with_me_id") VALUES (124, 123);
INSERT INTO "users_x_users" ("friends_with_me_id", "my_friends_id") VALUES (124, 123);
COMMIT;
SELECT "users_x_users"."my_friends_id", "users_x_users"."friends_with_me_id" FROM "users" AS "users" LEFT JOIN "users_x_users" AS "users_x_users" ON ("users_x_users"."my_friends_id" = "users"."id") WHERE "users_x_users"."friends_with_me_id" IN (123);
SELECT "users".* FROM "users" AS "users" WHERE (("users"."id" IN (124)));
SELECT "users_x_users"."friends_with_me_id", "users_x_users"."my_friends_id" FROM "users" AS "users" LEFT JOIN "users_x_users" AS "users_x_users" ON ("users_x_users"."friends_with_me_id" = "users"."id") WHERE "users_x_users"."my_friends_id" IN (123);
SELECT "users".* FROM "users" AS "users" WHERE (("users"."id" IN (124)));
SELECT "users_x_users"."my_friends_id", "users_x_users"."friends_with_me_id" FROM "users" AS "users" LEFT JOIN "users_x_users" AS "users_x_users" ON ("users_x_users"."my_friends_id" = "users"."id") WHERE "users_x_users"."friends_with_me_id" IN (123);
Original file line number Diff line number Diff line change
@@ -1 +1 @@
SELECT "books".* FROM "books" AS "books" LEFT JOIN "books_x_tags" AS "books_x_tags" ON ("books"."id" = "books_x_tags"."book_id") LEFT JOIN "tags" AS "tags_any" ON (("books_x_tags"."tag_id" = "tags_any"."id") AND "tags_any"."id" = 1) LEFT JOIN "publishers" AS "publisher" ON ("books"."publisher_id" = "publisher"."publisher_id") GROUP BY "books"."id", "publisher"."name" HAVING ((COUNT("tags_any"."id") > 0) AND ("publisher"."name" = 'Nextras publisher A'));
SELECT "books".* FROM "books" AS "books" LEFT JOIN "books_x_tags" AS "books_x_tags" ON ("books"."id" = "books_x_tags"."book_id") LEFT JOIN "tags" AS "tags_any" ON (("books_x_tags"."tag_id" = "tags_any"."id") AND "tags_any"."id" = 1) INNER JOIN "publishers" AS "publisher" ON ("books"."publisher_id" = "publisher"."publisher_id" AND "publisher"."name" = 'Nextras publisher A') GROUP BY "books"."id" HAVING ((COUNT("tags_any"."id") > 0) AND ((1=1)));
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ SELECT CURRVAL('eans_id_seq');
INSERT INTO "books" ("title", "author_id", "translator_id", "next_part", "ean_id", "publisher_id", "published_at", "printed_at", "price", "price_currency", "orig_price_cents", "orig_price_currency") VALUES ('GoT', 1, NULL, NULL, 1, 1, '2021-12-31 23:59:59.000000'::timestamp, NULL, NULL, NULL, NULL, NULL);
SELECT CURRVAL('books_id_seq');
COMMIT;
SELECT COUNT(*) AS count FROM (SELECT "eans"."id" FROM "eans" AS "eans" LEFT JOIN "books" AS "book" ON ("eans"."id" = "book"."ean_id") WHERE (("book"."title" = 'GoT'))) temp;
SELECT "eans".* FROM "eans" AS "eans" LEFT JOIN "books" AS "book" ON ("eans"."id" = "book"."ean_id") WHERE (("book"."title" = 'GoT')) ORDER BY "book"."title" ASC;
SELECT COUNT(*) AS count FROM (SELECT "eans"."id" FROM "eans" AS "eans" INNER JOIN "books" AS "book" ON (("eans"."id" = "book"."ean_id" AND "book"."title" = 'GoT') AND ("eans"."id" = "book"."ean_id")) WHERE (((1=1)))) temp;
SELECT "eans".* FROM "eans" AS "eans" INNER JOIN "books" AS "book" ON (("eans"."id" = "book"."ean_id" AND "book"."title" = 'GoT') AND ("eans"."id" = "book"."ean_id")) WHERE (((1=1))) ORDER BY "book"."title" ASC;
Loading
Loading