diff ikweb/tools/lazygen_model.py @ 247:7747bbe5b68e

start to develope Information Exchange Center of Ikariam Game. (prototpye)
author "Hisn Yi, Chen <ossug.hychen@gmail.com>"
date Mon, 01 Dec 2008 00:27:22 +0800
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ikweb/tools/lazygen_model.py	Mon Dec 01 00:27:22 2008 +0800
@@ -0,0 +1,228 @@
+#!/usr/bin/env python
+import re
+import os
+import sys
+
+from sqlalchemy import *
+# dirty import XD
+gaeo_home = os.getenv('GAEO_HOME').replace('~',os.getenv('HOME'))+'/bin'
+try:
+    sys.path.append(gaeo_home)
+    from gaeogen import *
+except ImportError, e:
+    print "can not import gaeogen, the gaeogen path maybe wrong, got path:%s" % gaeo_home
+    sys.exit()
+
+
+def sqlite_column_mapper(model_class, table_obj):
+    """
+    map sqlite columns of the table to GAEO Model
+    
+    >>> metadata = MetaData()
+    >>> users_table = Table('users', metadata,
+    ...     Column('id', Integer, primary_key=True),
+    ...     Column('name', String),
+    ...     Column('fullname', String),
+    ...     Column('password', String)
+    ... )
+    >>> model = sqlite_column_mapper(GenModel, users_table)
+    >>> model.generate_content()
+    """
+    def convertor(col_type):
+        lowertype = col_type.lower()
+
+        if re.match('char', lowertype): col_type = "String"
+        if re.match('(int|integer)', lowertype):    col_type = 'Integer'
+        return col_type
+    
+    model = model_class(table_obj.name)
+    
+    for column in table_obj.columns:        
+        model.add_property( "%s" % GenProperty(column.name, 
+                                               column, 
+                                               convertor))
+    return model
+
+class GenProperty(object):
+    """
+    GAE Property Generator.
+        
+    class Property(verbose_name=None, name=None, default=None, required=False, validator=None, choices=None)
+    """
+    db_prefix = "^(SL|PG|Max|MS|FB|Ac|Info|Oracle)"        
+
+    def __init__(self, name, column=False, convertor=False):
+        """
+        >>> col = Column('summary', String(2000))
+        >>> p = GenProperty('summary', col)
+        >>> "%s" % p
+        "summary:StringProperty(verbose_name='summary',name='summary')"
+        >>> meta = MetaData()
+        >>> meta.bind = create_engine("sqlite:///dummy.sqlite")
+        >>> t = Table('ally', meta, autoload=True)        
+        >>> p = GenProperty('name', t.columns.get('name'))
+        >>> "%s" % p
+        "name:TextProperty(verbose_name='name',name='name')"
+        >>> p = GenProperty('name', t.columns.get('time'))
+        >>> "%s" % p
+        "name:DatetimeProperty(verbose_name='name',name='name')"
+        """
+        self.name = name
+        self.column = column
+        
+        # very dirty ...
+        if column:
+                self.type_name = re.sub( self.db_prefix,'',
+                                         column.type.__class__.__name__)
+                if convertor:
+                    self.type_name = convertor(self.type_name)
+        
+    def __str__(self):
+        return self.gen()
+    
+    def gen(self):
+        """
+        generate gaeo property code.
+        """
+        clause= self.create_clause(self.type_name, self.column) 
+        return gae_property_code(self.name, self.type_name, clause)        
+    
+    def create_clause(self, type, column):
+        """
+        create property cluase.
+                
+        >>> s = Column('summary', String(2000))
+        >>> code = GenProperty(s.name).create_clause('string', s)
+        >>> code
+        {'verbose_name': 'summary', 'name': 'summary'}
+        """
+        clause= self.create_basic_clause(column)
+        
+        try:
+            other_caluse = getattr(self, 'create_%s_clause' % type.lower())(column)
+            clause.update(other_caluse)            
+        except:
+            pass
+        
+        return clause
+    
+    def create_basic_clause(self, column):
+        """
+        create basic property cluase.
+        """
+        clause = {'verbose_name':self.name, 'name':self.name}
+            
+        if column.default:
+            clause.setdefault('default', column.default)
+        elif column.server_default:
+            clause.setdefault('default', column.server_default)
+            
+        return clause
+
+def gae_property_code(name, type, clause):
+    """
+    generate google app engine property code.
+    
+    >>> gae_property_code('name', 'string', {'default':'hychen','name':'hi'})
+    "name:StringProperty(default='hychen',name='hi')"
+    """
+    argv = []
+    
+    def _quote(v):
+        try:
+            return "'"+v+"'"
+        except TypeError:
+            pass
+    
+    for k,v in clause.items():
+        argv.append("%s=%s" % (k, _quote(v) ) )
+
+    return "%s:%sProperty(%s)" % (name, 
+                                  type.capitalize(),
+                                   ','.join(argv))
+
+class ModelMaker:
+
+    is_build = False
+    
+    def __init__(self, **kwds):
+        """
+        to create GAEO Model
+        
+        >>> maker = ModelMaker(schema="sqlite:///dummy.sqlite", autoload=True)
+        >>> maker.build()        
+        """
+        self.models = []
+        self.set_engine(kwds['schema'])
+        
+        try:                        
+            if True == kwds['autoload']:
+                self.table_names = self.db_engine.table_names()
+            else:
+                self.table_names = kwds['include_tables']
+        except KeyError:
+            print "input wrong argv."
+        
+    def set_engine(self, schema):
+        """
+        set db engine
+        """
+        self.db_engine = create_engine(schema)        
+        self.meta = MetaData()        
+        self.meta.bind = self.db_engine
+
+    def build(self):
+        """
+        build models by talbse in database.
+        """
+        mapper_func = '%s_column_mapper' % self.db_engine.name.lower()
+        
+        for table_name in self.table_names:
+            table = Table(table_name, self.meta, autoload=True)            
+            self.models.append( eval(mapper_func)( GenModel, table) )
+            
+        self.is_build = True
+            
+    def save(self):
+        """
+        save model
+        """
+        if self.is_build:
+            application_dir = os.path.join(os.getcwd(), 'application')
+            model_dir = os.path.join(application_dir, 'model')
+                        
+            # check if the model directory had been created
+            if not os.path.exists(os.path.join(model_dir, '__init__.py')):
+                create_file(os.path.join(model_dir, '__init__.py'), [])
+                                        
+            for model in self.models:
+                print 'Creating Model %s ...' % model.name
+                model.save(os.path.join(model_dir, '%s.py' % model.name))
+        else:
+            print "not build yet."
+
+def gen_models_from_db(db_schema, include_tables=False):
+    """
+    generate models form database.
+    
+    gen_models_from_db("sqlite://dumy.sqlite")
+    
+    # spefiy tables
+    gen_models_from_db("sqlite://dumy.sqlite", include_tables=['tb1','tb2'])
+    """
+    if not include_tables:
+        maker = ModelMaker(schema=db_schema, autoload=True)
+    else:
+        maker = ModelMaker(schema=db_schema, include_tables=include_tables)
+        
+    maker.build()
+    maker.save()
+
+if '__main__' == __name__:
+    import sys
+    
+    if 'test' == sys.argv[1]:    
+        import doctest
+        doctest.testmod()
+    else:
+        gen_models_from_db(sys.argv[1])