FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

ORM in D

 
Post new topic   Reply to topic     Forum Index -> DDBI
View previous topic :: View next topic  
Author Message
KirkMcDonald



Joined: 22 Jun 2006
Posts: 23

PostPosted: Thu Jan 18, 2007 5:10 am    Post subject: ORM in D Reply with quote

I have recently begun assembling a proof-of-concept for an ORM in D.

The basic idea behind an object-relational mapping is that database tables correspond to classes, columns correspond to members, and rows correspond to instances. This is a concept that is quite popular in scripting languages, most notably Python, which has at least three very high-quality ORMs. (SQLObject, SQLAlchemy, and another which is part of the Django web framework.)

The reason scripting languages love ORMs is that they are aided by any reflection mechanisms the language supports. (SQLAlchemy, for instance, has the ability to return a class based on an existing database table at runtime. Python's metaclasses are a helluva thing.) There are ORM-like solutions in C++, but they all seem to require code-generation or various burdens on the end-user that I find unacceptable (having used ORMs in Python).

At the moment, my little prototype works like this:

The user defines a class as a subclass of Model. They give the class a number of members whose types are various predefined subclasses of Field.

The essential problem is somehow informing the base Model class about the extra fields defined by the user in their subclass. It turns out that D makes this suprisingly easy. The basic mechanism is this:

Code:
class Model {
    Field[] fields;
    void init(T)(T self) {
        foreach(f; self.tupleof) {
            // check if subclass of Field, add to this.fields
        }
    }
}

class MyModel : Model {
    this() {
        init(this);
    }
}


An alternate solution would be to inherit MyModel from a class template parameterized with MyModel itself, and to place this code in its constructor.

Anyway, my prototype knows how to emit simple CREATE TABLE, INSERT, and UPDATE commands. Once I've figured out how to query the database (and I have a scheme in mind which uses D's typesafe variadics), I'll put this proof-of-concept up somewhere.
Back to top
View user's profile Send private message
pragma



Joined: 28 May 2004
Posts: 607
Location: Washington, DC

PostPosted: Thu Jan 18, 2007 2:06 pm    Post subject: Reply with quote

Fantastic idea Kirk. You're probably the guy with the most practical templating and reflection experience next to Don, so I'm excited that you're doing this.

A few things donned on me when I saw your snippet above. Would this be of any help to your project?

Code:

interface IField {
}

interface IModel{
}

class Field(T) : IField{
}

class Model(T) : T,IModel {
    alias typeof(T.tupleof) FieldTuple;
    static IField[] fields; // look ma, static field data! :)
    static this(){
       foreach(FieldType; FieldTuple){
          fields ~= new Field!(FieldType);
       }
    }
}

class MyModel{
   int x;
   int y;
   int z;
   
   IModel getORM(){
      return new Model!(typeof(this));
   }
}


(Note that "class MyModel: Model!(MyModel){}" won't work. DMD fails to acquire a FieldTuple in that case for some reason.)

Also, how do you plan on handling more complex cases like multi-line recordsets and arrays?
_________________
-- !Eric.t.Anderton at gmail
Back to top
View user's profile Send private message Yahoo Messenger
KirkMcDonald



Joined: 22 Jun 2006
Posts: 23

PostPosted: Thu Jan 18, 2007 4:23 pm    Post subject: Reply with quote

My prototype is doing something closer to this:

Code:
import std.stdio : writefln;
import std.string : toString;

interface IField {
    // ...
}

class IntField : IField {
    int value;
    void opAssign(int v) {
        this.value = v;
    }
    int opCall() {
        return this.value;
    }
    char[] toString() {
        return .toString(this.value);
    }
}

interface IModel {
}

class Model(T) : IModel {
    IField[] fields;
    this() {
        T self = cast(T)this;
        foreach (i, f; self.tupleof) {
            static if (is(typeof(f) : IField)) {
                self.tupleof[i] = new typeof(f);
                this.fields ~= self.tupleof[i];
            }
        }
    }
}

class MyModel : Model!(MyModel) {
    IntField x, y, z;
    this() { super(); }
}

void main() {
    auto m = new MyModel;
    m.x = 10;
    m.y = 20;
    m.z = 30;
    writefln("?s ?s ?s", m.x, m.y, m.z);
}
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic     Forum Index -> DDBI All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group