> >> Something like:
> >>      (db.mytable.id == 3).ignore_common_filters().select()
>
> > A bit ugly, and gets worse if we add more arguments in the future.
>
> Say in our API that we have a Cat type with some uncommon options for
> users to set. Which is the better approach for setting these options?
>
> A) add optional argument(s) to the constructor. B) add method(s) to
> modify the object state. C) add properties to assign. D) encapsulate
> the options in a wrapper class Feline.
>
D (though the wrapper class might be something more like GroomedCat, not a 
strict synonym)
 

> A), obviously, is the normal solution, but we can't do that with Query
> because we normally produce Query objects from overloaded operators of
> Field. Going with solution D) over B) or C) is a very odd thing to do.
>
Not sure why. It leads to nicer syntax.
 

> If D) served some other purpose, it might begin to make sense, but as
> I've already argued, it doesn't.
>
Why does the chosen solution have to serve more than one purpose?

Maybe it's better to think about it from the perspective of using the API 
rather than worrying about the internal implementation.

We have a connection object that represents a database:

db

db is callable -- calling it with a query plus some optional arguments 
defines a set of records in the database:

db(query, **optional_arguments)

The query involves special DAL syntax, applying various operators to table 
fields (behind the scenes, the DAL converts that to a Query object, but 
that's just an implementation detail). The optional arguments may further 
refine the set of records identified by the query.

Once we have defined a set of records, we can apply various methods to that 
set, such as select, count, delete, etc.

db(query, **optional_arguments).select(...)

That all seems fairly straightforward to me, and the syntax is clean. In 
this story, the query is just the DAL syntax for identifying particular 
records, whereas the set is defined both by the query syntax and the 
optional arguments. From the standpoint of the API, it doesn't really 
matter that the query becomes a Query object internally -- you just need to 
know the query syntax, and you pass your query syntax to the db object to 
define your records. Note, the Query class doesn't have any public methods 
to call, so the user doesn't need to explicitly think about the Query class 
-- all the action happens with the Set object. From the user perspective, 
there's query syntax and a Set object -- no need to worry about the 
internal details of the Query vs. Set classes. Perhaps there's a better 
alternative for the internal implementation, but the public API seems 
reasonable to me.

Anthony

Reply via email to