This should ease some of the verbosity that is required when working with TQL.
Elliot provided be with several examples of their usage:
---
<!--- This would be /transfer/tags --->
<cfimport taglib="tags" prefix="t">
<!--- Do list operations --->
<cfset transfer = getTransfer()>
<t:query name="result" transfer="#transfer#">
select
u.firstName, u.lastName
from
user.User as u
where
u.email like <t:queryparam value="%foo.com" type="string">
</t:query>
<cfset application.transfer.myDatasource = getTransfer()>
<!--- By default datasources are stored in application scope --->
<t:query name="result" datasource="myDatasource">
select
u.firstName, u.lastName
from
user.User as u
where
u.email like <t:queryparam value="%foo.com" type="string">
</t:query>
<cfset request.transfer.myDatasource = getTransfer()>
<t:query name="result" datasource="myDatasource" scope="request">
select
u.firstName, u.lastName
from
user.User as u
where
u.email like <t:queryparam value="%foo.com" type="string">
</t:query>
<!--- Do read operations --->
<!--- Get a single record as a TransferObject --->
<t:query name="user" action="read" class="user.User" transfer="#getTransfer()#">
select
u.firstName, u.lastName
from
user.User as u
where
u.email like <t:queryparam value="%foo.com" type="string">
</t:query>
---
I think the examples pretty much speak for themselves, and the code
behind the tags is quite easy to understand, but let me know if there
are any questions.
Currently there is a limitation of the 'datasource' attribute only
being searched under application.transfer, or request.transfer, but
Elliot is working on allowing to be more flexible.
Side note: what do people think of the attribute 'datasource'? On one
hand, it makes it like <cfquery>, on the other, it makes it seem like
it should have the datasource bean. I was thinking 'scope' and 'key',
rather than 'scope' and 'datasource', but that has its con's as well.
What do you guys think?
Mark
Currently it looks in application.transfer.xxx, which suggests there's
a struct called application.transfer, in which you store the "real"
Transfer as a key. That's a bit confusing to me. Why not just store
Transfer in application.transfer? What else, in addition to Transfer,
would you store in the application.transfer struct?
I'll definitely play with these tags and see if I can make any
suggestions about what would seem clearer to me.
Cheers,
Bob
--
Bob Silverberg
www.silverwareconsulting.com
Hmm, the overloading idea sounds interesting, but I can see that
ending up being even more confusing. In terms of a name for the
attribute, something like where="", or search="" sounds more
descriptive to me.
> Some applications have more than one transfer instance, like using
> more than one CF datasource. So I figured you'd just name your
> datasources by appending them by name to the {scope}.transfer struct.
Oh yeah. That all makes sense. I never have more than one instance,
so I didn't think of that.
> Going to drop the requirement that they be clustered in a struct named
> transfer though, so like you said, you could have just one transfer
> stored in application.transfer. That probably agrees more with how
> people write code now.
That would certainly make it more straightforward to me.
> Thanks for the feedback Bob!
>
> - Elliott
No problem. Thanks for the tags!
--
Bob Silverberg
www.silverwareconsulting.com
scope="application" key="foo.bar"
The only thing is, if the scope is implicitly 'application', you could
just end up with:
key="foo.bar"
And no real knowledge of knowledge of where it is looking.
It 'feels' like a better fit to me, but I can see issues with it too.
What do people think?
Mark
What exactly is the datasource attribute? Why is it looking in
application.transfer or request.transfer? That makes no sense for the
use cases I'm familiar with. I typically inject the Transfer
Datasource object directly into my data gateway objects if they need
to use SQL and then in my <cfquery> tag I use datasource.getName() /
getUserName() / getPassword() - but I don't see how that relates to
TQL at all. What Transfer variable is being used here? Re-reading the
example, it looks like it is using the Transfer object itself - that
has nothing to do with a datasource. Again, that would be something I
would inject.
If it is just the Transfer object, why not just use
transfer="#whatever#" instead of trying to do some sort of scope
lookup? I would have expected variables.transfer to be the most common
location anyway (certainly for folks who use ColdSpring with
Transfer).
--
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/
"If you're not annoying somebody, you're not really alive."
-- Margaret Atwood
<!--- Do list operations --->
<cfset transfer = getTransfer()>
<t:query name="result" transfer="#transfer#">
select
u.firstName, u.lastName
from
user.User as u
where
u.email like <t:queryparam value="%foo.com" type="string">
</t:query>
Maybe there should be no 'datasource' attribute, and simply must pass
in Transfer?
Mark
Regarding providing a shortcut, I made a mod to my copy of the tag
which does allow me to exclude transfer from the list of attributes.
It relies on a certain convention, which means it's not very flexible,
but I offer it as an example. I changed the "looking for Transfer"
code to this:
<cfif not isObject(attributes.transfer)>
<cfif StructKeyExists(caller.this,"getTransfer")>
<cfset attributes.transfer = caller.this.getTransfer() />
<cfelse>
<cfparam name="attributes.datasource" type="string">
<cfparam name="attributes.scope" type="string" default="application">
<cfset scope = structGet(attributes.scope & ".transfer")>
<cfif not structKeyExists(scope, attributes.datasource)>
<cfthrow
type="transfer.query.DatasourceMissing"
message="No Transfer found at
#attributes.scope#.transfer[#attributes.datasource#]"
>
</cfif>
<cfset attributes.transfer = scope[attributes.datasource]>
</cfif>
</cfif>
I will pretty much always be writing TQL code in a gateway, and I
inject Transfer into my Gateway via CS, so I know that Transfer will
always be available via getTransfer() in the caller. By adding that
line of code I don't have to specify anything about Transfer at all in
my <t:query> tag. This will also work if I want to write TQL in a
decorator, or even, gasp, a service. Obviously this will only work if
you have a getTransfer() method defined in the caller, which I know
not everyone does (many people just use variables.transfer directly).
Because this won't help everyone, it may not be a logical addition to
the shipping version of the tag, but I wanted to point out that it is
helpful to me.
Getting back to the question of how to make this easiest for folks not
familiar with Transfer, I totally agree with just doing away with
scope, and having the user pass in the Transfer object all the time.
Like in your example:
<t:query transfer="#application.transfer#">
In my opinion this actually mimics what many people who don't use
Transfer are already doing. They probably have something like:
<cfquery name="qryTemp" datasource="#application.DSN#">
or
<cfquery name="qryTemp" datasource="#request.DSN#">
So changing that to:
<t:query name="qryTemp" transfer="#application.transfer#">
Is about as similar as you can get.
Cheers,
Bob
--
Bob Silverberg
www.silverwareconsulting.com
I'll commit them shortly.
Mark