Welcome, guest | Sign In | My Account | Store | Cart
# this is storm.py
import string, new, MySQLdb
from types import *
from MySQLdb.cursors import DictCursor

bag_belongs_to, bag_has_many = [],[]
def belongs_to(what): bag_belongs_to.append(what)
def has_many(what): bag_has_many.append(what)

class Mysqlwrapper:
        def __init__(self,**kwds):
                self.conn = MySQLdb.connect(cursorclass=DictCursor,**kwds)
                self.cursor = self.conn.cursor()
                self.escape = self.conn.escape_string
                self.insert_id = self.conn.insert_id
                self.commit = self.conn.commit
                self.q = self.cursor.execute

        def qone(self,query):
                self.q(query)
                return self.cursor.fetchone()

        def qall(self,query):
                self.q(query)
                return self.cursor.fetchall()

class MetaRecord(type):
        def __new__(cls, name, bases, dct):
                global bag_belongs_to, bag_has_many
                if name in globals(): return globals()[name]
                else:
                        Record = type.__new__(cls, name, bases, dct)
                        for i in bag_belongs_to: Record.belongs_to(i)
                        for i in bag_has_many: Record.has_many(i)
                        bag_belongs_to = []
                        hag_has_many = []
                        return Record

class Storm(dict):
        __metaclass__ = MetaRecord
        __CONN = None

        @classmethod
        def belongs_to(cls, what):
                def dah(self):
                        belong_cls = globals().get(what,None)
                        if not belong_cls:
                                belong_cls = type(what,(Storm,),{})
                        return belong_cls.selectone(self[what+'_id'])
                setattr(cls,what,new.instancemethod(dah,None,cls))

        @classmethod
        def has_many(cls, what):
                def dah(self):
                        hasmany_cls = globals().get(what,None)
                        if not hasmany_cls:
                                hasmany_cls = type(what,(Storm,),{})
                        dct={}
                        dct[string.lower(cls.__name__)+'_id']=self['id']
                        return hasmany_cls.select(**dct)
                setattr(cls,what,new.instancemethod(dah,None,cls))

        @classmethod
        def conn(cls, **kwds):
                if not cls.__CONN: cls.__CONN = Mysqlwrapper(**kwds)

        @classmethod
        def exe(cls,s):
                if not cls.__CONN: raise "Database not connected"
                return cls.__CONN.qall(s)

        @classmethod
        def insert(cls,**kwds):
                vs = [[k,cls.__CONN.escape(str(kwds[k]))] for k in kwds]
                if vs:
                        s = "insert into %s (%s) values ('%s')" % (
                          string.lower(cls.__name__), ','.join([v[0] for v in vs]),
                          "','".join([v[1] for v in vs]))

                        cls.__CONN.q(s)
                        cls.__CONN.commit()
                        return cls.__CONN.insert_id()
                else: raise "nothing to insert"

        @classmethod
        def select(cls,*args, **kwds):
                if len(args)==1 and (type(args[0])==IntType or type(args[0])==LongType):
                        q = "select * from %s where id='%s'"%(string.lower(cls.__name__),args[0])
                        where = "where id='%s'"%args[0]
                else:
                        if args: s = ",".join(args)
                        else: s = "*"

                        if kwds:
                                c,limit,orderby = [],'',''
                                for k in kwds:
                                        if k == 'limit': limit = "limit "+str(kwds[k])
                                        elif k == 'order': orderby = "order by "+str(kwds[k])
                                        else: c.append(k+"='"+str(kwds[k])+"'")
                                where = " and ".join(c)
                                if where: where = "where %s"%where
                                where = "%s %s %s"%(where,orderby,limit)
                        else: where = ""

                        q = " ".join(['select',s,'from',string.lower(cls.__name__),where])

                r = cls.__CONN.qall(q)
                list = []
                for i in r:
                        list.append(cls(i))
                        list[-1].__dict__['where'] = where
                return list

        @classmethod
        def selectone(cls,*args, **kwds):
                r = cls.select(*args,**kwds)
                if r: return r[0]
                else: return {}

        @classmethod
        def update(cls,cond,**kwds):
                if not cond or not kwds: raise "Update What?!"
                if type(cond) == IntType: w = "id='%d'" % cond
                else: w = cond
                vs = [[k,cls.__CONN.escape(str(kwds[k]))] for k in kwds]
                if vs:
                        s = "UPDATE %s SET %s WHERE %s" % ( string.lower(cls.__name__),
                          ','.join(["%s='%s'"%(v[0],v[1]) for v  in vs]), w)
                        cls.__CONN.q(s)
                        cls.__CONN.commit()

        @classmethod
        def delete(cls,id):
                if type(id) == IntType:
                        cls.__CONN.q("delete from %s where id='%d'"%
                          (string.lower(cls.__name__),id))
                        cls.__CONN.commit()
                else: raise "Only accept integer argument"

        def __init__(self,dct={}):
                if not self.__class__.__CONN: raise "Database not connected"
                dict.__init__(self,dct)
                self.__dict__['cur_table']= string.lower(self.__class__.__name__)
                self.__dict__['where']= ''
                self.__dict__['sql_buff']={}

        def sql(self,sql): self.__class__.__CONN.q(sql)

        def save(self):
                s = ""
                if self.where:
                        f = []
                        for v in self.sql_buff:
                                f.append("%s='%s'"%(v,self.sql_buff[v]))
                        s = "UPDATE %s SET %s %s" % (
                          self.cur_table, ','.join(f), self.where)
                else:
                        f,i=[],[]
                        for v in self.sql_buff:
                                f.append(v)
                                i.append(self.sql_buff[v])
                        if f and i:
                                s = "INSERT INTO %s (%s) VALUES ('%s')" % (
                                  self.cur_table, ','.join(f), "','".join(i))

                if s:
                        self.__class__.__CONN.q(s)
                        self.__class__.__CONN.commit()
                else: raise "nothing to insert"


        def __setattr__(self,attr,value):
                if attr in self.__dict__: self.__dict__[attr]=value
                else:
                        v = self.__class__.__CONN.escape(str(value))
                        self.__dict__['sql_buff'][attr] = v
                        self[attr] = v

        def __getattr__(self,attr):
                if attr in self.__dict__: return self.__dict__[attr]
                try: return self[attr]
                except KeyError: pass
                raise AttributeError

__all__ = ['Storm', 'belongs_to', 'has_many']
#----------------- end of storm.py ----------------


Below is a session screenshot of using this ORM(Storm):
-------------------------------------------------------------
wang@dapper-03:~/spark/lib$ mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 46 to server version: 5.0.22-Debian_0ubuntu6.06-log
Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> create database teststorm;
Query OK, 1 row affected (0.00 sec)
mysql> use teststorm;
Database changed
mysql> create table author(id int auto_increment primary key,name varchar(50));
Query OK, 0 rows affected (0.06 sec)
mysql> create table book(id int auto_increment primary key,author_id int,title varchar(100));
Query OK, 0 rows affected (0.01 sec)
mysql> describe author;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(50) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> describe book;
+-----------+--------------+------+-----+---------+----------------+
| Field     | Type         | Null | Key | Default | Extra          |
+-----------+--------------+------+-----+---------+----------------+
| id        | int(11)      | NO   | PRI | NULL    | auto_increment |
| author_id | int(11)      | YES  |     | NULL    |                |
| title     | varchar(100) | YES  |     | NULL    |                |
+-----------+--------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
mysql> Bye
wang@dapper-03:~/spark/lib$ python
Python 2.4.3 (#2, Apr 27 2006, 14:43:58)
[GCC 4.0.3 (Ubuntu 4.0.3-1ubuntu5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from storm import *
>>> class Author(Storm):
...     has_many('book')
...
>>> class Book(Storm):
...     belongs_to('author')
...
>>> Storm.conn(user='root',db='teststorm')
>>> a = Author()
>>> a.name = 'Tolstoy'
>>> a.save()
>>> Author.insert(name='Charles Dickens')
0L
>>> a.name, a['name']
('Tolstoy', 'Tolstoy')
>>> o = Author.selectone(2)
>>> o
{'id': 2L, 'name': 'Charles Dickens'}
>>> o.id, o.name, o['id'], o['name']
(2L, 'Charles Dickens', 2L, 'Charles Dickens')
>>> b = Book()
>>> b.author_id = 1
>>> b.title = 'Anna Karenina'
>>> b.save()
>>> b.title = 'War and Peace'
>>> b.save()
>>> b.author_id = 2
>>> b.title = 'Great Expectations'
>>> b.save()
>>> Book.insert(author_id=2,title='A Tale of Two Cities')
0L
>>> Book.insert(author_id=2,title='David Copperfield')
0L
>>> all = Book.select()
>>> all
[{'author_id': 1L, 'id': 1L, 'title': 'Anna Karenina'}, {'author_id': 1L, 'id': 2L, 'title': 'War and Peace'}, 
{'author_id': 2L, 'id': 3L, 'title': 'Great Expectations'}, {'author_id': 2L, 'id': 4L, 'title': 
'A Tale of Two Cities'}, {'author_id': 2L, 'id': 5L, 'title': 'David Copperfield'}]
>>> o = Book.selectone(4)
>>> a = o.author()
>>> a
{'id': 2L, 'name': 'Charles Dickens'}
>>> a = Author.selectone(name='Tolstoy')
>>> a
{'id': 1L, 'name': 'Tolstoy'}
>>> b = a.book()
>>> b
[{'author_id': 1L, 'id': 1L, 'title': 'Anna Karenina'}, {'author_id': 1L, 'id': 2L, 'title': 'War and Peace'}]
>>> b[0].title, b[1].title
('Anna Karenina', 'War and Peace')
>>>
wang@dapper-03:~/spark/lib$

History

  • revision 2 (17 years ago)
  • previous revisions are not available