# -*- coding: utf-8 -*- ''' Create the web2py model code needed to access your sqlite legacy db. Usage: python extract_sqlite_models.py Access your tables with: legacy_db(legacy_db.mytable.id>0).select() extract_sqlite_models.py -- Copyright (C) Michele Comitini This code is distributed with web2py. The regexp code and the dictionary type map was extended from extact_mysql_models.py that comes with web2py. extact_mysql_models.py is Copyright (C) Falko Krause. ''' import re import sys import sqlite3 data_type_map = dict( varchar='string', int='integer', integer='integer', tinyint='integer', smallint='integer', mediumint='integer', bigint='integer', float='double', double='double', char='string', decimal='integer', date='date', time='time', timestamp='datetime', datetime='datetime', binary='blob', blob='blob', tinyblob='blob', mediumblob='blob', longblob='blob', text='text', tinytext='text', mediumtext='text', longtext='text', bit='boolean', nvarchar='text', numeric='decimal(30,15)', real='decimal(30,15)', ) def get_foreign_keys(sql_lines): fks = dict() for line in sql_lines[1:-1]: hit = re.search(r'FOREIGN\s+KEY\s+\("(\S+)"\)\s+REFERENCES\s+"(\S+)"\s+\("(\S+)"\)', line) if hit: fks[hit.group(1)] = hit.groups()[1:] return fks def sqlite(database_name): conn = sqlite3.connect(database_name) c = conn.cursor() r = c.execute(r"select name,sql from sqlite_master where type='table' and not name like '\_%' and not lower(name) like 'sqlite_%'") tables = r.fetchall() connection_string = "legacy_db = DAL('sqlite://%s')" % database_name.split('/')[-1] legacy_db_table_web2py_code = [] for table_name, sql_create_stmnt in tables: if table_name.startswith('_'): continue if 'CREATE' in sql_create_stmnt: # check if the table exists #remove garbage lines from sql statement sql_lines = sql_create_stmnt.split('\n') sql_lines = [x for x in sql_lines if not( x.startswith('--') or x.startswith('/*') or x == '')] #generate the web2py code from the create statement web2py_table_code = '' fields = [] fks = get_foreign_keys(sql_lines) for line in sql_lines[1:-1]: if re.search('KEY', line) or re.search('PRIMARY', line) or re.search('"ID"', line) or line.startswith(')'): continue hit = re.search(r'\[(\S+)\]\s+(\w+(\(\S+\))?),?( .*)?', line) if hit is not None: name, d_type = hit.group(1), hit.group(2) d_type = re.sub(r'(\w+)\(.*', r'\1', d_type) name = unicode(re.sub('`', '', name)) if name in fks.keys(): if fks[name][1].lower() == 'id': field_type = 'reference %s' % (fks[name][0]) else: field_type = 'reference %s.%s' % (fks[name][0], fks[name][1]) else: field_type = data_type_map[d_type.lower()] web2py_table_code += "\n Field('%s','%s')," % ( name, field_type) web2py_table_code = "legacy_db.define_table('%s',%s\n migrate=False)" % (table_name, web2py_table_code) legacy_db_table_web2py_code.append(web2py_table_code) #---------------------------------------- #write the legacy db to file legacy_db_web2py_code = connection_string + "\n\n" legacy_db_web2py_code += "\n\n#--------\n".join( legacy_db_table_web2py_code) return legacy_db_web2py_code if len(sys.argv) < 2: print 'USAGE:\n\n extract_mysql_models.py data_basename\n\n' else: print "# -*- coding: utf-8 -*-" print sqlite(sys.argv[1])