Skip to content

Commit 3f6d277

Browse files
committed
Merge pull request #7 from moufmouf/1.1
Adding documentation regarding path ambiguities
2 parents b9a8677 + 66c58e0 commit 3f6d277

File tree

3 files changed

+62
-1
lines changed

3 files changed

+62
-1
lines changed

doc/images/shortest_path.png

28.1 KB
Loading

doc/images/shortest_path.pptx

46.6 KB
Binary file not shown.

doc/magic_join.md

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,75 @@ From this shortest path, it can build the correct JOINs.
5858

5959
Now that you understand the concept, you should understand the power and the limits of MagicJoin.
6060

61-
- MagicJoin **cannot generate queries with recursive relationships** (like a parent/child relationship)
61+
- MagicJoin **cannot generate queries with recursive relationships** (like a parent/child relationship). This is
62+
because parent/child relationships are represented by loops in the dependency graph, and a loop is never the
63+
shortest path.
6264
- MagicJoin assumes you are looking for the shortest path between 2 tables
6365
- This is 80% of the case true
6466
- If you are in the remaining 20%, do not use MagicJoin
6567

6668
<div class="alert alert-warning">MagicJoin is meant to be used on the 80% of the cases where writing joins is trivial
6769
and boring. If you have complex joins, do not try to use MagicJoin. Go back to pure SQL instead.</div>
6870

71+
If you are looking for details on how this shortest path is computed, have a look at
72+
[mouf/schema-analyzer](http://mouf-php.com/packages/mouf/schema-analyzer/README.md) which is the package in charge
73+
of computing that shortest path.
74+
75+
###Ambiguity exceptions and fine-tuning
76+
77+
Sometimes, there can be 2 possible paths that link 2 tables and that are equally short.
78+
In this case, rather than choosing a path at random, MagicQuery will let you know there is a problem by issuing
79+
a `ShortestPathAmbiguityException`.
80+
81+
![Ambiguity in paths](images/shortest_path.png)
82+
83+
Let's have a look at the example above. We have *products* that are part of a *store*. Stores are part of a *district*.
84+
Both *districts* and *products* have a *status*.
85+
86+
Now, let's have a look at this query:
87+
88+
```sql
89+
SELECT products.* FROM MAGICJOIN(products) WHERE district.name = 'NY';
90+
```
91+
92+
Very obviously, we want all the products from the district. Bu for MagicJoin, this is far from obvious.
93+
There are really 2 paths from products to district. One is going through the "store" table and one through the "status"
94+
table. Those paths are equally short.
95+
96+
We need to *hint* MagicJoin into understanding that the "status" table is irrelevant.
97+
98+
To do this, we must first provide to MagicJoin an instance of `SchemaAnalyzer`. [`SchemaAnalyzer` is the underlying
99+
package that is in charge of computing the shortest path.](http://mouf-php.com/packages/mouf/schema-analyzer/README.md)
100+
101+
```php
102+
use Mouf\Database\MagicQuery;
103+
use Mouf\Database\SchemaAnalyzer\SchemaAnalyzer;
104+
105+
// $conn is a Doctrine DBAL connection.
106+
// $cache is a Doctrine Cache
107+
108+
// Get a SchemaAnalyzer object.
109+
$schemaAnalyzer = new SchemaAnalyzer($conn->getSchemaManager(), $cache, "some_unique_key");
110+
111+
// On SchemaAnalyzer, let's modify the cost of the "status" table to make it unlikely to be used:
112+
$schemaAnalyzer->setTableCostModifier("status", SchemaAnalyzer::WEIGHT_IRRELEVANT);
113+
114+
// Get a MagicQuery object.
115+
$magicQuery = new MagicQuery($conn, $cache, $schemaAnalyzer);
116+
117+
$completeSql = $magicQuery->build("SELECT products.* FROM MAGICJOIN(products) WHERE district.name = 'NY'");
118+
```
119+
120+
The call to `setTableCostModifier` above will explain to MagicJoin that the *status* table is mostly irrelevant,
121+
and that it should most of the time be avoided.
122+
123+
You can also set a *cost* on a single foreign key rather than on a table. For instance:
124+
125+
```php
126+
// Avoid using the "status_id" foreign_key from the "products" table.
127+
$schemaAnalyzer->setForeignKeyCost("products", "status_id", SchemaAnalyzer::WEIGHT_IRRELEVANT);
128+
```
129+
69130
###With great power comes great responsibility
70131

71132
MagicJoin is a powerful feature because it can **guess** what you want to do. Please be wise while using it.

0 commit comments

Comments
 (0)