[std.database]
Kapps
Kapps at NotValidEmail.com
Thu Oct 13 00:51:48 PDT 2011
On 12/10/2011 12:57 AM, Jacob Carlborg wrote:
> On 2011-10-11 23:31, Andrei Alexandrescu wrote:
>> On 10/11/11 3:05 PM, Jacob Carlborg wrote:
>>> If we're talking use cases and high level interfaces I would go with
>>> something like:
>> [snip]
>>> I recommend that everyone take a good look at ActiveRecord in Ruby on
>>> Rails:
>>>
>>> http://guides.rubyonrails.org/active_record_querying.html
>>> http://guides.rubyonrails.org/association_basics.html
>>> http://guides.rubyonrails.org/active_record_validations_callbacks.html
>>
>> I confess the example you gave looks very foreign to me. From consulting
>> http://guides.rubyonrails.org/active_record_querying.html, I see Ruby's
>> active records esentially recode relational algebra in Ruby (as for the
>> constructs the equivalent SQL is shown).
>
> Yes, exactly. The point is to have as much as possible in functions
> instead of string literals and have a more Ruby like API than an SQL
> looking API.
>
> connection.select("*").from("users");
>
> instead of
>
> connection.execute("select * from users")
>
> Then they wrap everything in an object oriented API.
>
>> For a variety of reasons, this would be tenuous in D. One simple reason
>> is that e.g. lambdas don't offer access to textual representation, which
>> would be necessary to translate lambda-based conditions into SQL text.
>
> ActiveRecord doesn't support these lambda-based conditions out of the
> box. It is possible with the help of plugins, which uses a Ruby parser
> to get things done.
>
> I though that it might be possible to do in D, without the use of a
> parser. Take this for example:
>
> Post.where(p => p.title == "asd")
>
> "p" would be some kind of object/struct that overloads opDispatch. The
> opDispatch method would return an object/struct that overloads opCmp and
> opEquals. opCmp/opEquals would then return an object/struct that have
> recorded the comparison. The "where" method can then translate it in to
> raw SQL.
>
> To this to work opCmp/opEquals need to be able to return a struct or an
> object, I don't know if this is possible.
>
>> I might be narrow-minded, but I thought we're still looking at writing
>> and executing good old SQL code.
>>
>>
>> Andrei
>
> That would of course still be needed. I would consider that interface
> sit in the middle layer, above the lower driver level and below a higher
> ORM like level.
>
> Everyone is of course free to choose at which layer they want to
> interface with the database.
>
Agreed, I don't think it's unreasonable to have an API for easier
interoperability between databases that use slightly different syntax.
The implementation isn't exactly difficult, and it makes for a very nice
benefit and alternative to writing raw SQL (plus, prevents you from
doing things like making a typo on a WHERE clause or missing a comma or
semi-colon).
My approach to this was to just have a Query structure, and internally
each database parses it as is. The query structure basically just has an
array of where clauses, selects, etc, all of which are strings, with
methods such as where or select that simply append to the appropriate
clause and return the same query for chaining. The db then generates SQL
for it, and returns a prepared statement. I rather like this approach,
as (in my opinion) it looks cleaner, is more verifiable and, for my
projects, I use it instead of actually writing my sql queries when possible.
Example:
query q = query("Customers").select("LastName","MiddleName")
.where("FirstName = ?")
.limit(10)
.select("CustomerID")
.order("LastName", Ascending)
The above would be passed in to a prepared statement, and for MySql
would generate the statement "SELECT LastName, MiddleName, CustomerID
FROM Customers WHERE FirstName = ? LIMIT 0, 10;". For something like SQL
Server though, it could use TOP 10 instead of LIMIT 0, 10.
One of the other nice things is that it makes it simpler to make even
higher level APIs for it. For example, you could generate a statement
that populates a struct by just using
'query("Customers").select!(MyCustomerStruct)().where("Name=?")',
which would just call Select on all the fields without having to worry
about how to generate the SQL for it.
More information about the Digitalmars-d
mailing list