View mode: basic / threaded / horizontal-split · Log in · Help
October 28, 2012
Abstract Database Interface
I've recently been working with Ruby's ActiveRecord as part of my 
job, and I realized that D was powerful enough to make a similar 
abstraction layer. I've been playing with the idea for a little 
while, and I've put up some code at 
https://github.com/blm768/adbi. It isn't nearly as comprehensive 
as ActiveRecord, but it captures the basic idea of representing 
database structures as objects/structs.

Using it is something like this:

module main;

import std.stdio;

import adbi.model;
import adbi.sqlite3.database;

struct Test {
	mixin Model!"test";
	
	const(char)[] name;
	double num;
	mixin reference!("test2", "test2", Test2);
}

struct Test2 {
	mixin Model!"test2";
	int value;
}

int main(string[] args) {
	auto db = new Sqlite3Database("test.db");
	auto q = db.query("SELECT * FROM test;");
	
	Test.updateSchema(db);
	Test2.updateSchema(db);
	
	auto range = ModelRange!Test(q);
	
	foreach(value; range) {
		writeln(value);
	}
	
	auto q2 = db.query("SELECT * FROM test, test2 WHERE test2_id = 
test2.id");
	
	auto r2 = ModelRange!(Join!(Test, Test2))(q2);
	
	foreach(j; r2) {
		writeln(j);
	}
	
	return 0;
}

This code prints out every entry in the "test" table, then prints 
the results of a join on the "test" and "test2" tables. The calls 
to updateSchema() set up some static members of Test and Test2; 
after these calls, the library does not perform any operations 
with the column names, which should make retrieving a record 
noticeably faster than in a system like ActiveRecord. The 
downside is that these functions must be called every time the 
database schema changes in a way that affects column order, but 
that should happen very rarely, if ever, in a typical application.

The code is far from complete, but it's an interesting toy and 
might actually be useful for simple applications once some of the 
issues are ironed out.
October 28, 2012
Re: Abstract Database Interface
On 2012-10-28 02:31, BLM768 wrote:
> I've recently been working with Ruby's ActiveRecord as part of my job,
> and I realized that D was powerful enough to make a similar abstraction
> layer. I've been playing with the idea for a little while, and I've put
> up some code at https://github.com/blm768/adbi. It isn't nearly as
> comprehensive as ActiveRecord, but it captures the basic idea of
> representing database structures as objects/structs.
>
> Using it is something like this:
>
> module main;
>
> import std.stdio;
>
> import adbi.model;
> import adbi.sqlite3.database;
>
> struct Test {
>      mixin Model!"test";
>
>      const(char)[] name;
>      double num;
>      mixin reference!("test2", "test2", Test2);
> }
>
> struct Test2 {
>      mixin Model!"test2";
>      int value;
> }
>
> int main(string[] args) {
>      auto db = new Sqlite3Database("test.db");
>      auto q = db.query("SELECT * FROM test;");
>
>      Test.updateSchema(db);
>      Test2.updateSchema(db);
>
>      auto range = ModelRange!Test(q);
>
>      foreach(value; range) {
>          writeln(value);
>      }
>
>      auto q2 = db.query("SELECT * FROM test, test2 WHERE test2_id =
> test2.id");
>
>      auto r2 = ModelRange!(Join!(Test, Test2))(q2);
>
>      foreach(j; r2) {
>          writeln(j);
>      }
>
>      return 0;
> }
>
> This code prints out every entry in the "test" table, then prints the
> results of a join on the "test" and "test2" tables. The calls to
> updateSchema() set up some static members of Test and Test2; after these
> calls, the library does not perform any operations with the column
> names, which should make retrieving a record noticeably faster than in a
> system like ActiveRecord. The downside is that these functions must be
> called every time the database schema changes in a way that affects
> column order, but that should happen very rarely, if ever, in a typical
> application.
>
> The code is far from complete, but it's an interesting toy and might
> actually be useful for simple applications once some of the issues are
> ironed out.

Looking at the API used in this example it would say that it's not very 
interesting and not very ActiveRecrod like. I think this looks more 
interesting and more like ActiveRecrod:

class Person : Model
{
}

void main ()
{
    auto p = new Person;
    p.name = "John Doe";
    p.save();

    p = Person.where!(x => x.name == "John Doe");
}

But when you start to use associative it won't be as nice looking as 
ActiveRecord due to the not so nice mixin syntax. What we need is AST 
macros and user defined attributes/annotations. With that, associations 
could potentially look like this:

class Foo : Model {}

class Person : Model
{
    @hasMany Foo;
}

-- 
/Jacob Carlborg
October 28, 2012
Re: Abstract Database Interface
I like, nice work.
On 28 Oct 2012 02:35, "BLM768" <blm768@gmail.com> wrote:

> I've recently been working with Ruby's ActiveRecord as part of my job, and
> I realized that D was powerful enough to make a similar abstraction layer.
> I've been playing with the idea for a little while, and I've put up some
> code at https://github.com/blm768/adbi**. It isn't nearly as
> comprehensive as ActiveRecord, but it captures the basic idea of
> representing database structures as objects/structs.
>
> Using it is something like this:
>
> module main;
>
> import std.stdio;
>
> import adbi.model;
> import adbi.sqlite3.database;
>
> struct Test {
>         mixin Model!"test";
>
>         const(char)[] name;
>         double num;
>         mixin reference!("test2", "test2", Test2);
> }
>
> struct Test2 {
>         mixin Model!"test2";
>         int value;
> }
>
> int main(string[] args) {
>         auto db = new Sqlite3Database("test.db");
>         auto q = db.query("SELECT * FROM test;");
>
>         Test.updateSchema(db);
>         Test2.updateSchema(db);
>
>         auto range = ModelRange!Test(q);
>
>         foreach(value; range) {
>                 writeln(value);
>         }
>
>         auto q2 = db.query("SELECT * FROM test, test2 WHERE test2_id =
> test2.id");
>
>         auto r2 = ModelRange!(Join!(Test, Test2))(q2);
>
>         foreach(j; r2) {
>                 writeln(j);
>         }
>
>         return 0;
> }
>
> This code prints out every entry in the "test" table, then prints the
> results of a join on the "test" and "test2" tables. The calls to
> updateSchema() set up some static members of Test and Test2; after these
> calls, the library does not perform any operations with the column names,
> which should make retrieving a record noticeably faster than in a system
> like ActiveRecord. The downside is that these functions must be called
> every time the database schema changes in a way that affects column order,
> but that should happen very rarely, if ever, in a typical application.
>
> The code is far from complete, but it's an interesting toy and might
> actually be useful for simple applications once some of the issues are
> ironed out.
>
>
October 28, 2012
Re: Abstract Database Interface
On Sunday, 28 October 2012 at 00:31:49 UTC, BLM768 wrote:
> I've recently been working with Ruby's ActiveRecord as part of 
> my job, and I realized that D was powerful enough to make a 
> similar abstraction layer. I've been playing with the idea for 
> a little while, and I've put up some code at 
> https://github.com/blm768/adbi. It isn't nearly as 
> comprehensive as ActiveRecord, but it captures the basic idea 
> of representing database structures as objects/structs.
>
> Using it is something like this:
>
> module main;
>
> import std.stdio;
>
> import adbi.model;
> import adbi.sqlite3.database;
>
> struct Test {
> 	mixin Model!"test";
> 	
> 	const(char)[] name;
> 	double num;
> 	mixin reference!("test2", "test2", Test2);
> }
>
> struct Test2 {
> 	mixin Model!"test2";
> 	int value;
> }
>
> int main(string[] args) {
> 	auto db = new Sqlite3Database("test.db");
> 	auto q = db.query("SELECT * FROM test;");
> 	
> 	Test.updateSchema(db);
> 	Test2.updateSchema(db);
> 	
> 	auto range = ModelRange!Test(q);
> 	
> 	foreach(value; range) {
> 		writeln(value);
> 	}
> 	
> 	auto q2 = db.query("SELECT * FROM test, test2 WHERE test2_id = 
> test2.id");
> 	
> 	auto r2 = ModelRange!(Join!(Test, Test2))(q2);
> 	
> 	foreach(j; r2) {
> 		writeln(j);
> 	}
> 	
> 	return 0;
> }
>
> This code prints out every entry in the "test" table, then 
> prints the results of a join on the "test" and "test2" tables. 
> The calls to updateSchema() set up some static members of Test 
> and Test2; after these calls, the library does not perform any 
> operations with the column names, which should make retrieving 
> a record noticeably faster than in a system like ActiveRecord. 
> The downside is that these functions must be called every time 
> the database schema changes in a way that affects column order, 
> but that should happen very rarely, if ever, in a typical 
> application.
>
> The code is far from complete, but it's an interesting toy and 
> might actually be useful for simple applications once some of 
> the issues are ironed out.

I am working on similar project, named SQLd[1]. If you are 
interested, we can join forces and work togheder :)

IRC Nick: Robik
[1]: http://github.com/robik/SQLd
October 29, 2012
Re: Abstract Database Interface
> I am working on similar project, named SQLd[1]. If you are 
> interested, we can join forces and work togheder :)
>
> IRC Nick: Robik
> [1]: http://github.com/robik/SQLd

That might be a good idea. I haven't done much for supporting 
different databases, so getting more backend support would be 
quite nice. What might work well is for me to just refactor my 
code to sit on top of your existing database classes. So far, 
I've really just been playing around, but if people show enough 
interest, I'd like to play with the idea a while longer. :)
October 29, 2012
Re: Abstract Database Interface
>
> Looking at the API used in this example it would say that it's 
> not very interesting and not very ActiveRecrod like. I think 
> this looks more interesting and more like ActiveRecrod:
>
> class Person : Model
> {
> }
>
> void main ()
> {
>     auto p = new Person;
>     p.name = "John Doe";
>     p.save();
>
>     p = Person.where!(x => x.name == "John Doe");
> }
>
> But when you start to use associative it won't be as nice 
> looking as ActiveRecord due to the not so nice mixin syntax. 
> What we need is AST macros and user defined 
> attributes/annotations. With that, associations could 
> potentially look like this:
>
> class Foo : Model {}
>
> class Person : Model
> {
>     @hasMany Foo;
> }

It's definitely not ActiveRecord, but my goal is just to take 
some inspiration from it, not to duplicate it. I'm very concerned 
about efficiency, which is why I'm using structs, and I like 
hard-coding the fields into the structure so there's some 
documentation of what the record is supposed to hold and so the 
compiler can optimize it more heavily. It will probably be a 
little less pretty, but it'll work, and that's what really 
matters. At some point, I might implement an interface to 
generate SQL queries with function calls, but for now, just 
manually writing the queries really isn't hard, and it provides a 
significant speed boost for systems like Sqlite that compile 
queries down to bytecode because it's easier to reuse the query 
object.
October 29, 2012
Re: Abstract Database Interface
> It's definitely not ActiveRecord, but my goal is just to take some
> inspiration from it, not to duplicate it. I'm very concerned about
> efficiency, which is why I'm using structs, and I like hard-coding the
> fields into the structure so there's some documentation of what the
> record is supposed to hold and so the compiler can optimize it more
> heavily. It will probably be a little less pretty, but it'll work, and
> that's what really matters. At some point, I might implement an
> interface to generate SQL queries with function calls, but for now, just
> manually writing the queries really isn't hard, and it provides a
> significant speed boost for systems like Sqlite that compile queries
> down to bytecode because it's easier to reuse the query object.

My point was just that you removed the key features and soul of 
ActiveRecord. Without these features it's just like any other ORM library.

-- 
/Jacob Carlborg
October 29, 2012
Re: Abstract Database Interface
> My point was just that you removed the key features and soul of 
> ActiveRecord. Without these features it's just like any other 
> ORM library.

That's a good point. I haven't had any experience with other ORM 
libraries, so ActiveRecord was the closest thing that came to 
mind.

I definitely do want to eventually capture some of ActiveRecord's 
features, but probably not all of them. I feel like the solution 
should be implemented in a way that fits well with a statically 
typed language, so I'll definitely have to drop some of the 
features. It won't be quite as nice to use, but it will be 
simpler in dome ways, which is one of my primary goals as a 
developer. Tools like ActiveRecord are more fun to use, but 
thinking of all the hash table lookups makes me cringe. :)

If and when the library matures, though, I might think about 
adding some more ActiveRecord-like features if enough people miss 
them.
October 29, 2012
Re: Abstract Database Interface
On 2012-10-29 15:42, BLM768 wrote:

> That's a good point. I haven't had any experience with other ORM
> libraries, so ActiveRecord was the closest thing that came to mind.
>
> I definitely do want to eventually capture some of ActiveRecord's
> features, but probably not all of them. I feel like the solution should
> be implemented in a way that fits well with a statically typed language,
> so I'll definitely have to drop some of the features. It won't be quite
> as nice to use, but it will be simpler in dome ways, which is one of my
> primary goals as a developer. Tools like ActiveRecord are more fun to
> use, but thinking of all the hash table lookups makes me cringe. :)
>
> If and when the library matures, though, I might think about adding some
> more ActiveRecord-like features if enough people miss them.

You can have a look at DataMapper. That's also for Ruby but it's not 
specific for SQL, if I recall correctly. Have a look at some ORM library 
written in Scala, I would guess they can be quite innovative and it's 
statically typed.

http://squeryl.org/index.html
http://datamapper.org/

-- 
/Jacob Carlborg
October 29, 2012
Re: Abstract Database Interface
>
> You can have a look at DataMapper. That's also for Ruby but 
> it's not specific for SQL, if I recall correctly. Have a look 
> at some ORM library written in Scala, I would guess they can be 
> quite innovative and it's statically typed.
>
> http://squeryl.org/index.html
> http://datamapper.org/

Those libraries definitely look interesting. I should probably 
consider some type of NoSQL database support...

Thanks for the links!
« First   ‹ Prev
1 2 3
Top | Discussion index | About this forum | D home