Bez popisu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

sqlutils.py 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. # -*- coding: utf-8 -*-
  2. import os
  3. import logging as logger
  4. import sqlalchemy as sqla
  5. from django.conf import settings
  6. import EditorialModel
  7. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Lodel.settings")
  8. ENGINES = {
  9. 'mysql': {
  10. 'driver': 'pymysql',
  11. 'encoding': 'utf8'
  12. },
  13. 'postgresql': {
  14. 'driver': 'psycopg2',
  15. 'encoding': 'utf8',
  16. },
  17. 'sqlite': {
  18. 'driver': 'pysqlite',
  19. 'encoding': 'utf8',
  20. },
  21. }
  22. sql_config = settings.LODEL2SQLWRAPPER
  23. ## Returns an engine given dbconf name
  24. #
  25. # @param ename str: name of an item in django.conf.settings.LODEL2SQLWRAPPER['db']
  26. # @param sqlaloggin None|bool: If None leave default value, if true activate sqlalchemy logging
  27. # @return SqlAlchemy engine
  28. def get_engine(ename='default', sqlalogging=None):
  29. # Loading confs
  30. cfg = sql_config['db'][ename]
  31. edata = ENGINES[cfg['ENGINE']] # engine infos
  32. conn_str = ""
  33. if cfg['ENGINE'] == 'sqlite':
  34. #SQLite connection string
  35. conn_str = '%s+%s:///%s' % (cfg['ENGINE'], edata['driver'], cfg['NAME'])
  36. else:
  37. #MySQL and PostgreSQL connection string
  38. user = cfg['USER']
  39. user += (':' + cfg['PASSWORD'] if 'PASSWORD' in cfg else '')
  40. if 'HOST' not in cfg:
  41. logger.info('Not HOST in configuration, using localhost')
  42. host = 'localhost'
  43. else:
  44. host = cfg['HOST']
  45. host += (':' + cfg['PORT'] if 'PORT' in cfg else '')
  46. conn_str = '%s+%s://' % (cfg['ENGINE'], edata['driver'])
  47. conn_str += '%s@%s/%s' % (user, host, cfg['NAME'])
  48. ret = sqla.create_engine(conn_str, encoding=edata['encoding'], echo=sqlalogging)
  49. logger.debug("Getting engine :" + str(ret))
  50. return ret
  51. ## Return a sqlalchemy.MetaData object
  52. # @param engine sqlalchemy.engine : A sqlalchemy engine
  53. # @return an sql alechemy MetaData instance bind to engine
  54. def meta(engine):
  55. res = sqla.MetaData(bind=engine)
  56. res.reflect(bind=engine)
  57. return res
  58. ## Return an sqlalchemy table given an EmComponent child class
  59. # @warning Except a class type not an instance
  60. # @param cls : An EmComponent child class
  61. # @return An sqlalchemy table
  62. # @throw TypeError if em_instance is an EmComponent or not an EmComponent child class (or an instance)
  63. # @todo Move this function as an instance method ?
  64. def get_table(self):
  65. if not issubclass(self.__class__, EditorialModel.components.EmComponent) or self.table is None:
  66. raise TypeError("Excepting an EmComponent child class not an " + str(self.__class__))
  67. engine = self.db_engine
  68. return sqla.Table(self.table, meta(engine))
  69. ## This function is intended to execute ddl defined in sqlalter
  70. # @warning There is a dirty workaround here, DDL should returns only one query, but DropColumn for sqlite has to return 4 queries (rename, create, insert, drop). There is a split on the compiled SQL to extract and execute one query at a time
  71. # @param ddl DDLElement: Can be an Database.sqlalter.DropColumn Database.sqlalter.AddColumn or Database.sqlalter.AlterColumn
  72. # @param db_engine: A database engine
  73. # @return True if success, else False
  74. def ddl_execute(ddl, db_engine):
  75. conn = db_engine.connect()
  76. req = str(ddl.compile(dialect=db_engine.dialect))
  77. queries = req.split(';')
  78. for query in queries:
  79. logger.debug("Executing custom raw SQL query : '" + query + "'")
  80. ret = conn.execute(query)
  81. if not bool(ret):
  82. return False
  83. conn.close()
  84. return True