1
0
Fork 0
mirror of https://github.com/yweber/lodel2.git synced 2026-06-07 03:20:48 +02:00

Merge branch 'component_db_instance_attr'

Conflicts:
	EditorialModel/classes.py
	EditorialModel/types.py
This commit is contained in:
Yann 2015-07-09 17:37:43 +02:00
commit 9cec5af1fa
9 changed files with 84 additions and 64 deletions

View file

@ -5,6 +5,7 @@ import logging as logger
import sqlalchemy as sqla
from django.conf import settings
import EditorialModel
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Lodel.settings")
@ -76,17 +77,12 @@ def meta(engine):
# @param cls : An EmComponent child class
# @return An sqlalchemy table
# @throw TypeError if em_instance is an EmComponent or not an EmComponent child class (or an instance)
def get_table(cls):
from EditorialModel.components import EmComponent # dirty circula inclusion hack
if not issubclass(cls, EmComponent) or cls.table is None:
raise TypeError("Excepting an EmComponent child class not an " + str(cls))
engine = cls.db_engine()
return sqla.Table(cls.table, meta(engine))
def getTable(cls):
return get_table(cls)
# @todo Move this function as an instance method ?
def get_table(self):
if not issubclass(self.__class__, EditorialModel.components.EmComponent) or self.table is None:
raise TypeError("Excepting an EmComponent child class not an " + str(self.__class__))
engine = self.db_engine
return sqla.Table(self.table, meta(engine))
## This function is intended to execute ddl defined in sqlalter
# @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

View file

@ -44,7 +44,7 @@ class EmClass(EmComponent):
#Create a new entry in the em_class table
result = super(EmClass, cls).create(name=name, classtype=classtype, icon=icon, sortcolumn=sortcolumn, **em_component_args)
dbe = result.db_engine()
dbe = result.db_engine
conn = dbe.connect()
#Create a new table storing LodelObjects of this EmClass
@ -69,7 +69,7 @@ class EmClass(EmComponent):
if len(fieldgroups) > 0:
return False
dbe = self.__class__.db_engine()
dbe = self.db_engine
meta = sqlutils.meta(dbe)
#Here we have to give a connection
class_table = sql.Table(self.name, meta)
@ -88,7 +88,7 @@ class EmClass(EmComponent):
## Isolate SQL for EmClass::fieldgroups
# @return An array of dict (sqlalchemy fetchall)
def _fieldgroups_db(self):
dbe = self.__class__.db_engine()
dbe = self.db_engine
emfg = sql.Table(EditorialModel.fieldgroups.EmFieldGroup.table, sqlutils.meta(dbe))
req = emfg.select().where(emfg.c.class_id == self.uid)
@ -116,7 +116,7 @@ class EmClass(EmComponent):
## Isolate SQL for EmCLass::types
# @return An array of dict (sqlalchemy fetchall)
def _types_db(self):
dbe = self.__class__.db_engine()
dbe = self.db_engine
emtype = sql.Table(EditorialModel.types.EmType.table, sqlutils.meta(dbe))
req = emtype.select().where(emtype.c.class_id == self.uid)
conn = dbe.connect()
@ -134,7 +134,7 @@ class EmClass(EmComponent):
def _link_type_db(self, table_name):
# Create a new table storing additionnal fields for the relation between the linked type and this EmClass
conn = self.__class__.db_engine().connect()
conn = self.db_engine.connect()
meta = sql.MetaData()
emlinketable = sql.Table(table_name, meta, sql.Column('uid', sql.VARCHAR(50), primary_key=True))
emlinketable.create(conn)
@ -146,7 +146,7 @@ class EmClass(EmComponent):
return self._linked_types_db()
def _linked_types_db(self):
dbe = self.__class__.db_engine()
dbe = self.db_engine
meta = sql.MetaData()
meta.reflect(dbe)

View file

@ -53,7 +53,14 @@ class EmComponent(object):
# @param id_or_name int|str: name or id of the object
# @throw TypeError if id_or_name is not an integer nor a string
# @throw NotImplementedError if called with EmComponent
def __init__(self, id_or_name):
def __init__(self, id_or_name, dbconf = 'default'):
self.dbconf = dbconf
if self.dbconf:
self.db_engine = sqlutils.get_engine(dbconf)
else:
self.db_engine = False
if type(self) == EmComponent:
raise NotImplementedError('Abstract class')
@ -129,15 +136,15 @@ class EmComponent(object):
super(EmComponent, self).__setattr__('deleted', False)
@classmethod
#@classmethod
## Shortcut that return the sqlAlchemy engine
def db_engine(cls):
return sqlutils.get_engine(cls.dbconf)
#def db_engine(cls):
# return sqlutils.get_engine(cls.dbconf)
## Do the query on the database for EmComponent::populate()
# @throw EmComponentNotExistError if the instance is not anymore stored in database
def _populate_db(self):
dbe = self.__class__.db_engine()
dbe = self.db_engine
component = sql.Table(self.table, sqlutils.meta(dbe))
req = sql.sql.select([component])
@ -159,7 +166,7 @@ class EmComponent(object):
## Insert a new component in the database
#
# This function create and assign a new UID and handle the date_create and date_update values
#
# @warning There is a mandatory argument dbconf that indicate wich database configuration to use
# @param **kwargs : Names arguments representing object properties
# @return An instance of the created component
# @throw TypeError if an element of kwargs isn't a valid object propertie or if a mandatory argument is missing
@ -194,21 +201,27 @@ class EmComponent(object):
# if cls._fields[name].notNull and cls._fields[name].default == None:
# raise TypeError("Missing argument : "+name)
if 'dbconf' in kwargs:
if not kwargs['db_engine']:
raise NotImplementedError("Its a nonsense to call create with no database")
dbconf = kwargs['dbconf']
else:
dbconf = 'default'
dbe = sqlutils.get_engine(dbconf)
kwargs['uid'] = cls.new_uid()
kwargs['uid'] = cls.new_uid(dbe)
kwargs['date_update'] = kwargs['date_create'] = datetime.datetime.utcnow()
dbe = cls.db_engine()
conn = dbe.connect()
kwargs['rank'] = cls.get_max_rank( kwargs[cls.ranked_in] )+1
kwargs['rank'] = cls._get_max_rank( kwargs[cls.ranked_in], dbe )+1
table = sql.Table(cls.table, sqlutils.meta(dbe))
req = table.insert(kwargs)
if not conn.execute(req):
raise RuntimeError("Unable to create the "+cls.__class__.__name__+" EmComponent ")
conn.close()
return cls(kwargs['name'])
return cls(kwargs['name'], dbconf)
## Write the representation of the component in the database
# @return bool
@ -232,7 +245,7 @@ class EmComponent(object):
# @throw RunTimeError if it was unable to do the Db update
def _save_db(self, values):
""" Do the query on the db """
dbe = self.__class__.db_engine()
dbe = self.db_engine
component = sql.Table(self.table, sqlutils.meta(dbe))
req = sql.update(component, values=values).where(component.c.uid == self.uid)
@ -247,7 +260,7 @@ class EmComponent(object):
# @throw RunTimeError if it was unable to do the deletion
def delete(self):
#<SQL>
dbe = self.__class__.db_engine()
dbe = self.db_engine
component = sql.Table(self.table, sqlutils.meta(dbe))
req = component.delete().where(component.c.uid == self.uid)
conn = dbe.connect()
@ -260,13 +273,11 @@ class EmComponent(object):
super(EmComponent, self).__setattr__('deleted', True)
return True
## get_max_rank
# Retourne le rank le plus élevé pour le groupe de component au quel apartient l'objet actuelle
## @brief Get the maximum rank given an EmComponent child class and a ranked_in filter
# @param ranked_in_value mixed: The rank "family"
# @param return -1 if no EmComponent found else return an integer >= 0
# @return -1 if no EmComponent found else return an integer >= 0
@classmethod
def get_max_rank(cls, ranked_in_value):
dbe = cls.db_engine()
def _get_max_rank(cls, ranked_in_value, dbe):
component = sql.Table(cls.table, sqlutils.meta(dbe))
req = sql.sql.select([component.c.rank]).where(getattr(component.c, cls.ranked_in) == ranked_in_value).order_by(component.c.rank.desc())
c = dbe.connect()
@ -278,6 +289,12 @@ class EmComponent(object):
else:
return -1
## Only make a call to the class method
# @return A positive integer or -1 if no components
# @see EmComponent::_get_max_rank()
def get_max_rank(self, ranked_in_value):
return self.__class__._get_max_rank(ranked_in_value, self.db_engine)
## Set a new rank for this component
# @note This function assume that ranks are properly set from 1 to x with no gap
# @param new_rank int: The new rank
@ -298,9 +315,9 @@ class EmComponent(object):
limits = [ self.rank + ( 1 if mod > 0 else -1), new_rank ] #The range of modified ranks
limits.sort()
dbe = self.db_engine()
dbe = self.db_engine
conn = dbe.connect()
table = sqlutils.get_table(self.__class__)
table = sqlutils.get_table(self)
#Selecting the components that will be modified
req = table.select().where( getattr(table.c, self.ranked_in) == getattr(self, self.ranked_in)).where(table.c.rank >= limits[0]).where(table.c.rank <= limits[1])
@ -358,11 +375,11 @@ class EmComponent(object):
#
# Use the class property table
# @return A new uid (an integer)
def new_uid(cls):
def new_uid(cls, db_engine):
if cls.table is None:
raise NotImplementedError("Abstract method")
dbe = cls.db_engine()
dbe = db_engine
uidtable = sql.Table('uids', sqlutils.meta(dbe))
conn = dbe.connect()

View file

@ -5,6 +5,7 @@ from EditorialModel.classes import EmClass
import EditorialModel.fieldtypes as ftypes
from Database import sqlutils
import sqlalchemy as sql
import EditorialModel
@ -43,9 +44,10 @@ class EmFieldGroup(EmComponent):
## Get the list of associated fields
# @return A list of EmField instance
def fields(self):
field_table = sqlutils.getTable(EditorialModel.fields.EmField)
meta = sqlutils.meta(self.db_engine)
field_table = sql.Table(EditorialModel.fields.EmField.table, meta)
req = field_table.select(field_table.c.uid).where(field_table.c.fieldgroup_id == self.uid)
conn = self.__class__.db_engine().connect()
conn = self.db_engine.connect()
res = conn.execute(req)
rows = res.fetchall()
conn.close()

View file

@ -71,11 +71,11 @@ class EmField(EmComponent):
# @return bool : True if deleted False if deletion aborded
# @todo Check if unconditionnal deletion is correct
def delete(self):
dbe = self.__class__.db_engine()
dbe = self.db_engine
class_table = sql.Table(self.get_class_table(), sqlutils.meta(dbe))
field_col = sql.Column(self.name)
ddl = DropColumn(class_table, field_col)
sqlutils.ddl_execute(ddl, self.__class__.db_engine())
sqlutils.ddl_execute(ddl, self.db_engine)
return super(EmField, self).delete()
## add_field_column_to_class_table (Function)
@ -84,7 +84,7 @@ class EmField(EmComponent):
#
# @return True in case of success, False if not
def add_field_column_to_class_table(self):
dbe = self.db_engine()
dbe = self.db_engine
fieldtype = get_field_type(self.fieldtype)
new_column = sql.Column(name=self.name, **(fieldtype.sqlalchemy_args()))
class_table = sql.Table(self.get_class_table(), sqlutils.meta(dbe))
@ -103,9 +103,10 @@ class EmField(EmComponent):
# @return An EmClass instance
def get_class(self):
#<SQL>
dbe = self.db_engine()
dbe = self.db_engine
meta = sqlutils.meta(dbe)
conn = dbe.connect()
fieldgroup_table = sqlutils.getTable(EmFieldGroup)
fieldgroup_table = sql.Table(EmFieldGroup.table, meta)
req = fieldgroup_table.select().where(fieldgroup_table.c.uid == self.fieldgroup_id)
res = conn.execute(req)
row = res.fetchone()

View file

@ -240,7 +240,7 @@ class TestUid(ComponentTestCase):
def test_newuid(self):
""" Test valid calls for new_uid method """
for _ in range(10):
nuid = EmTestComp.new_uid()
nuid = EmTestComp.new_uid(self.dber)
conn = self.dber.connect()
tuid = sqla.Table('uids', sqlutils.meta(self.dber))
@ -257,7 +257,7 @@ class TestUid(ComponentTestCase):
def test_newuid_abstract(self):
""" Test not valit call for new_uid method """
with self.assertRaises(NotImplementedError):
EmComponent.new_uid()
EmComponent.new_uid(self.dber)
pass
#=======================#
@ -432,11 +432,11 @@ class TestCreate(ComponentTestCase):
pass
def testGetMaxRank(self):
old = EmTestComp.get_max_rank('f')
old = EmTestComp._get_max_rank('f', self.dber)
EmTestComp.create(name="foobartest", rank_fam = 'f')
n = EmTestComp.get_max_rank('f')
n = EmTestComp._get_max_rank('f', self.dber)
self.assertEqual(old+1, n, "Excepted value was "+str(old+1)+" but got "+str(n))
self.assertEqual(EmTestComp.get_max_rank('z'), -1)
self.assertEqual(EmTestComp._get_max_rank('z', self.dber), -1)
pass
#====================#

View file

@ -79,7 +79,7 @@ class FieldTestCase(TestCase):
# @param field EmField: EmField object
# @return Number of found records
def _get_field_records_Db(self,field):
dbe = EmComponent.db_engine()
dbe = field.db_engine
fieldtable = sqla.Table(EmField.table, sqlutils.meta(dbe))
conn = dbe.connect()
req = fieldtable.select().where(fieldtable.c.uid==field.uid).where(fieldtable.c.name==field.name)
@ -103,7 +103,8 @@ class FieldTestCase(TestCase):
# @param table_name str: Name of the table
# @return list of columns
def _get_table_columns_Db(self, table_name):
table = sqla.Table(table_name, sqlutils.meta(EmComponent.db_engine()))
dbe = self.testClass.db_engine
table = sqla.Table(table_name, sqlutils.meta(dbe))
return table.c
## TestField (Class)

View file

@ -67,6 +67,7 @@ class TestInit(FieldGroupTestCase):
def setUp(self):
super(TestInit, self).setUp()
dbe = sqlutils.get_engine()
conn = sqlutils.get_engine().connect()
ent1 = EmClass('entity1')
@ -76,9 +77,9 @@ class TestInit(FieldGroupTestCase):
self.creadate = datetime.datetime.utcnow()
#Test fieldgroup
self.tfg = [
{ 'uid': EmFieldGroup.new_uid(), 'name': 'fg1', 'string': '{"fr":"Super Fieldgroup"}', 'help': '{"en":"help"}', 'rank': 0 , 'class_id': ent1.uid, 'date_create' : self.creadate, 'date_update': self.creadate},
{ 'uid': EmFieldGroup.new_uid(), 'name': 'fg2', 'string': '{"fr":"Super Fieldgroup"}', 'help': '{"en":"help"}', 'rank': 1 , 'class_id': ent1.uid, 'date_create': self.creadate, 'date_update': self.creadate},
{ 'uid': EmFieldGroup.new_uid(), 'name': 'fg3', 'string': '{"fr":"Super Fieldgroup"}', 'help': '{"en":"help"}', 'rank': 2 , 'class_id': idx1.uid, 'date_create': self.creadate, 'date_update': self.creadate},
{ 'uid': EmFieldGroup.new_uid(dbe), 'name': 'fg1', 'string': '{"fr":"Super Fieldgroup"}', 'help': '{"en":"help"}', 'rank': 0 , 'class_id': ent1.uid, 'date_create' : self.creadate, 'date_update': self.creadate},
{ 'uid': EmFieldGroup.new_uid(dbe), 'name': 'fg2', 'string': '{"fr":"Super Fieldgroup"}', 'help': '{"en":"help"}', 'rank': 1 , 'class_id': ent1.uid, 'date_create': self.creadate, 'date_update': self.creadate},
{ 'uid': EmFieldGroup.new_uid(dbe), 'name': 'fg3', 'string': '{"fr":"Super Fieldgroup"}', 'help': '{"en":"help"}', 'rank': 2 , 'class_id': idx1.uid, 'date_create': self.creadate, 'date_update': self.creadate},
]
req = sqla.Table('em_fieldgroup', sqlutils.meta(sqlutils.get_engine())).insert(self.tfg)

View file

@ -49,7 +49,7 @@ class EmType(EmComponent):
# @return sqlalchemy em_type_hierarchy table object
# @todo Don't hardcode table name
def _table_hierarchy(self):
return sql.Table(self.__class__.table_hierarchy, sqlutils.meta(self.db_engine()))
return sql.Table(self.__class__.table_hierarchy, sqlutils.meta(self.db_engine))
@property
## Return the EmClassType of the type
@ -76,9 +76,10 @@ class EmType(EmComponent):
## Get the list of associated fieldgroups
# @return A list of EmFieldGroup instance
def field_groups(self):
fg_table = sqlutils.getTable(EmFieldGroup)
meta = sqlutils.meta(self.db_engine)
fg_table = sql.Table(EmFieldGroup.table, meta)
req = fg_table.select(fg_table.c.uid).where(fg_table.c.class_id == self.class_id)
conn = self.__class__.db_engine().connect()
conn = self.db_engine.connect()
res = conn.execute(req)
rows = res.fetchall()
conn.close()
@ -96,7 +97,7 @@ class EmType(EmComponent):
## Return selected optional field
# @return A list of EmField instance
def selected_fields(self):
dbe = self.db_engine()
dbe = self.db_engine
meta = sqlutils.meta(dbe)
conn = dbe.connect()
@ -155,7 +156,7 @@ class EmType(EmComponent):
if not field.optional:
raise ValueError("This field is not optional")
dbe = self.db_engine()
dbe = self.db_engine
meta = sqlutils.meta(dbe)
conn = dbe.connect()
@ -216,8 +217,9 @@ class EmType(EmComponent):
# @throw RunTimeError if a nature fetched from db is not valid
# @see EmType::subordinates(), EmType::superiors()
def _sub_or_sup(self, sup=True):
conn = self.db_engine().connect()
conn = self.db_engine.connect()
htable = self._table_hierarchy
type_table = sqlutils.get_table(self)
req = htable.select()
if sup:
@ -265,7 +267,7 @@ class EmType(EmComponent):
elif self.name != em_type.name:
raise ValueError("Not allowed to put a different em_type as superior in a relation of nature '" + relation_nature + "'")
conn = self.db_engine().connect()
conn = self.db_engine.connect()
htable = self._table_hierarchy
values = {'subordinate_id': self.uid, 'superior_id': em_type.uid, 'nature': relation_nature}
req = htable.insert(values=values)
@ -290,7 +292,7 @@ class EmType(EmComponent):
if relation_nature not in EmClassType.natures(self.classtype['name']):
raise ValueError("Invalid nature for add_superior : '" + relation_nature + "'. Allowed relations for this type are " + str(EmClassType.natures(self.classtype['name'])))
conn = self.db_engine().connect()
conn = self.db_engine.connect()
htable = self._table_hierarchy
req = htable.delete(htable.c.superior_id == em_type.uid and htable.c.nature == relation_nature)
conn.execute(req)
@ -306,7 +308,7 @@ class EmType(EmComponent):
## @brief Return the list of all the types linked to this type, should they be superiors or subordinates
# @return A list of EmType objects
def _linked_types_db(self):
conn = self.db_engine().connect()
conn = self.db_engine.connect()
htable = self._table_hierarchy
req = htable.select(htable.c.superior_id, htable.c.subordinate_id)
req = req.where(sql.or_(htable.c.subordinate_id == self.uid, htable.c.superior_id == self.uid))