RejectedSoftware Forums

Sign up

Gotta love D

I didn't want to write all those "copy from row to object", so I hacked together something with UDAs

    @dbexpr("FROM user ORDER BY username ASC")
    struct UserListItem
    {
        @dbexpr("user_id")
        int user_id;

        @dbexpr("username")
        string username;
    }
    const users = db.queryExpr!UserListItem;

    res.render!("user.list.dt", req, users);

The little queryExpr method just translates this to a standard select.
Every struct/class field is added as a sql field, and the one at the top is added last.
They can be as complex as you'd like, and they can use query parameters (although the parameter values isn't added from the struct).

And of course, everything is build in at compile time, so there is no performance overhead - gotta love D! :)

Re: Gotta love D

On Sat, 21 Sep 2013 00:51:52 GMT, simendsjo wrote:

I didn't want to write all those "copy from row to object", so I hacked together something with UDAs

    @dbexpr("FROM user ORDER BY username ASC")
    struct UserListItem
    {
        @dbexpr("user_id")
        int user_id;

        @dbexpr("username")
        string username;
    }
    const users = db.queryExpr!UserListItem;

    res.render!("user.list.dt", req, users);

The little queryExpr method just translates this to a standard select.
Every struct/class field is added as a sql field, and the one at the top is added last.
They can be as complex as you'd like, and they can use query parameters (although the parameter values isn't added from the struct).

And of course, everything is build in at compile time, so there is no performance overhead - gotta love D! :)

Nice!

I just wish it was possible to concentrate on the nice things, but most time seems to be needed to work around compiler bugs (again, the situation was better for a while)... </rant>

Btw. did you already look at hibernated? It seems to be on hold for a while now, though, and misses a patch to use the latest mysql-native version.

Re: Gotta love D

On Sat, 21 Sep 2013 10:27:16 GMT, Sönke Ludwig wrote:

On Sat, 21 Sep 2013 00:51:52 GMT, simendsjo wrote:

I didn't want to write all those "copy from row to object", so I hacked together something with UDAs

    @dbexpr("FROM user ORDER BY username ASC")
    struct UserListItem
    {
        @dbexpr("user_id")
        int user_id;

        @dbexpr("username")
        string username;
    }
    const users = db.queryExpr!UserListItem;

    res.render!("user.list.dt", req, users);

The little queryExpr method just translates this to a standard select.
Every struct/class field is added as a sql field, and the one at the top is added last.
They can be as complex as you'd like, and they can use query parameters (although the parameter values isn't added from the struct).

And of course, everything is build in at compile time, so there is no performance overhead - gotta love D! :)

Nice!

I just wish it was possible to concentrate on the nice things, but most time seems to be needed to work around compiler bugs (again, the situation was better for a while)... </rant>

Yeah, I've been struggling with a lot of bugs for supporting UDAs like this.

Btw. did you already look at hibernated? It seems to be on hold for a while now, though, and misses a patch to use the latest mysql-native version.

No, haven't looked at it. If it works like hibernate or other ORMs, it will either fetch a lot of stuff when I don't need it, or lazily go to the database whenever I access fields..
I've used NHibernate on several projects in the past, but I would rather just use something very simple so I can control exactly what gets fetched - kind of constrained by resources here :)

Re: Gotta love D

On Sat, 21 Sep 2013 00:51:52 GMT, simendsjo wrote:

I didn't want to write all those "copy from row to object", so I hacked together something with UDAs

    @dbexpr("FROM user ORDER BY username ASC")
    struct UserListItem
    {
        @dbexpr("user_id")
        int user_id;

        @dbexpr("username")
        string username;
    }
    const users = db.queryExpr!UserListItem;

    res.render!("user.list.dt", req, users);

Possible improvement proposal! :) One can simply use __traits(identifier) in absence of @dbexpr on member field to keep interface more DRY when names match.

I absolutely love declarative programming in D though. Working on REST module was no doubt my most awesome D coding experience :)

Re: Gotta love D

On Sat, 21 Sep 2013 11:03:34 GMT, Dicebot wrote:

On Sat, 21 Sep 2013 00:51:52 GMT, simendsjo wrote:

I didn't want to write all those "copy from row to object", so I hacked together something with UDAs

    @dbexpr("FROM user ORDER BY username ASC")
    struct UserListItem
    {
        @dbexpr("user_id")
        int user_id;

        @dbexpr("username")
        string username;
    }
    const users = db.queryExpr!UserListItem;

    res.render!("user.list.dt", req, users);

Possible improvement proposal! :) One can simply use __traits(identifier) in absence of @dbexpr on member field to keep interface more DRY when names match.

Yeah, thought of implementing that. And support for insert, update, delete.

I absolutely love declarative programming in D though. Working on REST module was no doubt my most awesome D coding experience :)

Ditto. Love to see where this is going once people gets more experience using it and compiler bugs gets sorted out.
I'm really hoping someone will implement AutoMapper for D.

Re: Gotta love D

On Sat, 21 Sep 2013 10:57:18 GMT, simendsjo wrote:

On Sat, 21 Sep 2013 10:27:16 GMT, Sönke Ludwig wrote:

Btw. did you already look at hibernated? It seems to be on hold for a while now, though, and misses a patch to use the latest mysql-native version.

No, haven't looked at it. If it works like hibernate or other ORMs, it will either fetch a lot of stuff when I don't need it, or lazily go to the database whenever I access fields..
I've used NHibernate on several projects in the past, but I would rather just use something very simple so I can control exactly what gets fetched - kind of constrained by resources here :)

Hm that sounds like a reasonable objection, indeed. I wanted to try a hibernate like model for some time, but this makes me worry a bit now, at least for some applications. Especially if the API lacks manual intervention for the cases where it really becomes critical.

Re: Gotta love D

On Sun, 22 Sep 2013 12:41:26 GMT, Sönke Ludwig wrote:

On Sat, 21 Sep 2013 10:57:18 GMT, simendsjo wrote:

On Sat, 21 Sep 2013 10:27:16 GMT, Sönke Ludwig wrote:

Btw. did you already look at hibernated? It seems to be on hold for a while now, though, and misses a patch to use the latest mysql-native version.

No, haven't looked at it. If it works like hibernate or other ORMs, it will either fetch a lot of stuff when I don't need it, or lazily go to the database whenever I access fields..
I've used NHibernate on several projects in the past, but I would rather just use something very simple so I can control exactly what gets fetched - kind of constrained by resources here :)

Hm that sounds like a reasonable objection, indeed. I wanted to try a hibernate like model for some time, but this makes me worry a bit now, at least for some applications. Especially if the API lacks manual intervention for the cases where it really becomes critical.

ORMs is really tempting as it removes a lot of potential errors and removed a lot of duplication. I think all larger frameworks have ways of writing SQL manually when you need to, but if you want performance, you'll end up working around the framework at every corner and loosing most of the benefits.

I'll no longer use an ORM for those reasons :/
But I'll experiment a bit with this in D - pretty sure it's possible to get something more minimal while experiencing some of the advantages of ORM.

Re: Gotta love D

On Sat, 21 Sep 2013 11:03:34 GMT, Dicebot wrote:

Possible improvement proposal! :) One can simply use __traits(identifier) in absence of @dbexpr on member field to keep interface more DRY when names match.

How about an explicit UDA for that, something like @dbcolumn.

Re: Gotta love D

On Fri, 11 Oct 2013 15:41:01 GMT, Martin Nowak wrote:

On Sat, 21 Sep 2013 11:03:34 GMT, Dicebot wrote:

Possible improvement proposal! :) One can simply use __traits(identifier) in absence of @dbexpr on member field to keep interface more DRY when names match.

How about an explicit UDA for that, something like @dbcolumn.

?

The very point of proposal is to not have any UDA's when information is already enough - same as it done in various vibe.d modules, configuration by convention.

Re: Gotta love D

On 10/11/2013 06:25 PM, Dicebot wrote:

The very point of proposal is to not have any UDA's when information is already enough - same as it done in various vibe.d modules, configuration by convention.

I thought about extra fields in UserListItem that are not part of the
query result.

But after some more thought, I'm actually actually wondering whether
binding a fixed query to a type is a good idea in the first place,
because the type mainly serves as carrier of the UDA metadata.

     @dbexpr("FROM user ORDER BY username ASC")
     struct UserListItem
     {
         @dbexpr("user_id")
         int user_id;

         @dbexpr("username")
         string username;
     }
     const users = db.queryExpr!UserListItem;

IMHO a throwaway tuple type made more sense for a single query.

db.select!(Tuple!(int, "user_id", string, "username"))("FROM user ORDER 
BY username ASC");

If your targeting to express SQL schemata it should be more declarative,
maybe like so.

/// name of table
struct table { string name; }
/// optional: name of column in table
struct column { string name; }
/// primary key constraint
struct primaryKey {}
/// unique constraint
struct unique {}
/// references a foreign key
struct foreignKey(alias column) { alias key = column; }

@table("user")
struct User
{
     @primaryKey
     int id;

     string name;

     @column("bar") @unique
     string foo;

     @foreignKey!(City.name)
     string city;
}

@table("city")
struct City
{
     @primaryKey
     string name;
}

The declaration should give you enough information to implement the
following SQL statements.

db.select!("id", "name").from!User;
db.select.from!User;
db.select.from!User.orderBy!("name")(Order.ascend);

db.insertInto!User(User(0, "dawg", "code@dawg.eu", "Berlin"));

db.select.from!User.where!("id <=")(20);
db.select.from!User.where!("name LIKE")("foo*");