This is probably mostly meant for @elpete, but I would love to get input from other CFers as well.
I have been curious if it possible to define a Quick entity with properties spanning multiple tables. My understanding is that you can use subselects to grab data from other tables. If you want to get more than one column, you can add more subselect calls like this:
function scopeAddLastLogin( qb ) {
qb.addSubselect( "lastLoginDate", "logins.timestamp" );
qb.addSubselect( "lastLoginIPAddress", "logins.ipAddress" );
}
The downside of the above approach is that the underlying SQL that gets generated is not very efficient and looks something like this:
SELECT
[user].[id],
// subselect 1
(
SELECT
TOP (1) [logins].[timestamp]
FROM
[logins]
WHERE
(
[user].[id] = [logins].[userId]
)
) AS [lastLoginDate]
// subselect 2
(
SELECT
TOP (1) [logins].[ipAddress]
FROM
[logins]
WHERE
(
[user].[id] = [logins].[userId]
)
) AS [lastLoginIPAddress]
FROM
[user]
The same query would be more efficient (and readable) if it were written like this:
SELECT
[user].[id],
[logins].[timestamp] as [lastLoginDate],
[logins].[ipAddress] as [lastLoginIpAddress]
FROM
[user]
LEFT JOIN [logins] ON [user].[id] = [logins].[userId]
Quick already has the ability to JOIN
on different tables through the multi-table inheritence (MTI) pattern using discriminated entities.
Possible workaround (Views):
If the user has access to the database, they could probably use a view for this type of thing. However, it would be cooler if it could be done via Quick.
Idea 1:
Perhaps Quick could add some additional logic to detect multiple subselects from the same table and then dynamically create a join instead of multiple nested subselects. Alternatively, perhaps subselects should originate from a regular JOIN
statement similar to my second SQL example above.
Idea 2:
Alternatively, perhaps we could define one or more join tables in the component definition and then specify which table a particular property should originate from. For example:
component
extends="quick.models.BaseEntity"
accessors="true"
table="user"
left_joins="logins:id:userId" <-- comma separated list of tables to join + the PK and FK(s) to use
Then, when declaring properties, we could use the existing column
attribute to point to the joined table:
property name="id";
property name="lastLoginDate" column="logins.timestamp";
property name="lastLoginIpAddress" column="logins:ipAddress";
Anyway, just some food for thought on how I think Quick could be improved for even greater flexibility.