mirror of
https://github.com/yweber/lodel2.git
synced 2025-12-03 17:26:54 +01:00
Write an instance creation script and replace the SQLMigrationHandler by the MysqlMigrationHandler
see README.md for more informations about instance creation
This commit is contained in:
parent
d5169cf9a1
commit
4383606fbb
11 changed files with 1588 additions and 137 deletions
|
|
@ -1,156 +1,547 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
## @package EditorialModel.migrationhandler.sql
|
||||
# @brief A dummy migration handler
|
||||
#
|
||||
# According to it every modifications are possible
|
||||
#
|
||||
import copy
|
||||
import pymysql
|
||||
|
||||
import EditorialModel
|
||||
from DataSource.MySQL.common_utils import MySQL
|
||||
from DataSource.dummy.migrationhandler import DummyMigrationHandler
|
||||
from EditorialModel.fieldtypes.generic import GenericFieldType
|
||||
from EditorialModel.model import Model
|
||||
from mosql.db import Database
|
||||
from Lodel.utils.mosql import create, alter_add
|
||||
|
||||
# The global MH algorithm is as follow :
|
||||
# A create_table(table_name, pk_name, pk_opt) method that create a table
|
||||
# with one pk field
|
||||
# An add_column(table_name, field_name, field_opt) method that add a column to a table
|
||||
#
|
||||
# The create_default_table method will call both methods to create the object and relation tables
|
||||
#
|
||||
# Supported operations :
|
||||
# - EmClass creation
|
||||
# - EmClass deletion (untested)
|
||||
# - EmField creation
|
||||
# - EmField deletion (untested)
|
||||
# - rel2type attribute creation
|
||||
# - rel2type attribute deletion (unstested)
|
||||
#
|
||||
# Unsupported operations :
|
||||
# - EmClass rename
|
||||
# - EmField rename
|
||||
# - rel2type field rename
|
||||
# - rel2type attribute rename
|
||||
# - EmFieldType changes
|
||||
#
|
||||
# @todo Unified datasources and migration handlers via utils functions
|
||||
|
||||
|
||||
## Manage Model changes
|
||||
class SQLMigrationHandler(DummyMigrationHandler):
|
||||
## @brief Modify a MySQL database given editorial model changes
|
||||
class MysqlMigrationHandler(DummyMigrationHandler):
|
||||
|
||||
fieldtype_to_sql = {
|
||||
'char': "CHAR(255)",
|
||||
'integer': 'INT'
|
||||
}
|
||||
## @brief Construct a MysqlMigrationHandler
|
||||
# @param host str : The db host
|
||||
# @param user str : The db user
|
||||
# @param password str : The db password
|
||||
# @param db str : The db name
|
||||
def __init__(self, host, user, passwd, db, module=pymysql, db_engine='InnoDB', foreign_keys=True, debug=False, dryrun=False, drop_if_exists=False):
|
||||
self.datasource = MySQL
|
||||
self._dbmodule = module
|
||||
#Connect to MySQL
|
||||
self.db = self._dbmodule.connect(host=host, user=user, passwd=passwd, db=db)
|
||||
self.debug = debug
|
||||
self.dryrun = dryrun
|
||||
self.db_engine = db_engine
|
||||
self.foreign_keys = foreign_keys if db_engine == 'InnoDB' else False
|
||||
self.drop_if_exists = drop_if_exists
|
||||
#Create default tables
|
||||
self._create_default_tables(self.drop_if_exists)
|
||||
|
||||
def __init__(self, module=None, *conn_args, **conn_kargs):
|
||||
super(SQLMigrationHandler, self).__init__(False)
|
||||
## @brief Delete all table created by the MH
|
||||
# @param model Model : the Editorial model
|
||||
def __purge_db(self, model):
|
||||
for uid in [c.uid for c in model.components('EmClass')]:
|
||||
try:
|
||||
self.delete_emclass_table(model, uid)
|
||||
except self._dbmodule.err.InternalError as e:
|
||||
print(e)
|
||||
|
||||
self.db = Database(module, *conn_args, **conn_kargs)
|
||||
self._pk_column = (EditorialModel.classtypes.pk_name(), 'INTEGER PRIMARY KEY AUTOINCREMENT')
|
||||
self._main_table_name = 'object'
|
||||
self._relation_table_name = 'relation'
|
||||
for tname in [MySQL.get_r2t2table_name(f.em_class.name, model.component(f.rel_to_type_id).name) for f in model.components('EmField') if f.fieldtype == 'rel2type']:
|
||||
try:
|
||||
self._query("DROP TABLE %s;" % tname)
|
||||
except self._dbmodule.err.InternalError as e:
|
||||
print(e)
|
||||
|
||||
self._install_tables()
|
||||
for tname in [MySQL.relations_table_name, MySQL.objects_table_name]:
|
||||
try:
|
||||
self._query("DROP TABLE %s;" % tname)
|
||||
except self._dbmodule.err.InternalError as e:
|
||||
print(e)
|
||||
|
||||
## @brief Record a change in the EditorialModel and indicate wether or not it is possible to make it
|
||||
# @note The states ( initial_state and new_state ) contains only fields that changes
|
||||
# @param model model : The EditorialModel.model object to provide the global context
|
||||
## @brief Modify the db given an EM change
|
||||
# @param em model : The EditorialModel.model object to provide the global context
|
||||
# @param uid int : The uid of the change EmComponent
|
||||
# @param initial_state dict | None : dict with field name as key and field value as value. Representing the original state. None mean creation of a new component.
|
||||
# @param new_state dict | None : dict with field name as key and field value as value. Representing the new state. None mean component deletion
|
||||
# @throw EditorialModel.exceptions.MigrationHandlerChangeError if the change was refused
|
||||
def register_change(self, model, uid, initial_state, new_state):
|
||||
# find type of component change
|
||||
if initial_state is None:
|
||||
state_change = 'new'
|
||||
elif new_state is None:
|
||||
state_change = 'del'
|
||||
else:
|
||||
state_change = 'upgrade'
|
||||
def register_change(self, em, uid, initial_state, new_state, engine=None):
|
||||
if engine is None:
|
||||
engine = self.db_engine
|
||||
if isinstance(em.component(uid), EditorialModel.classes.EmClass):
|
||||
if initial_state is None:
|
||||
#EmClass creation
|
||||
self.create_emclass_table(em, uid, engine)
|
||||
elif new_state is None:
|
||||
#EmClass deletion
|
||||
self.delete_emclass_table(em, uid)
|
||||
elif isinstance(em.component(uid), EditorialModel.fields.EmField):
|
||||
emfield = em.component(uid)
|
||||
if emfield.rel_field_id is None:
|
||||
#non relationnal field
|
||||
if initial_state is None:
|
||||
#non relationnal EmField creation
|
||||
if emfield.name not in EditorialModel.classtypes.common_fields.keys():
|
||||
self.add_col_from_emfield(em, uid)
|
||||
elif new_state is None:
|
||||
#non relationnal EmField deletion
|
||||
if emfield.name not in EditorialModel.classtypes.common_fields.keys():
|
||||
self.del_col_from_emfield(em, uid)
|
||||
else:
|
||||
#relationnal field
|
||||
if initial_state is None:
|
||||
#Rel2type attr creation
|
||||
self.add_relationnal_field(em, uid)
|
||||
elif new_state is None:
|
||||
#Rel2type attr deletion
|
||||
self.del_relationnal_field(em, uid)
|
||||
|
||||
# call method to handle the database change
|
||||
component_name = Model.name_from_emclass(type(model.component(uid)))
|
||||
handler_func = component_name.lower() + '_' + state_change
|
||||
if hasattr(self, handler_func):
|
||||
getattr(self, handler_func)(model, uid, initial_state, new_state)
|
||||
## @brief dumdumdummy
|
||||
# @note implemented to avoid the log message of EditorialModel.migrationhandler.dummy.DummyMigrationHandler
|
||||
def register_model_state(self, em, state_hash):
|
||||
pass
|
||||
|
||||
# New Class, a table must be created
|
||||
def emclass_new(self, model, uid, initial_state, new_state):
|
||||
class_table_name = self._class_table_name(new_state['name'])
|
||||
self._query_bd(
|
||||
create(table=class_table_name, column=[self._pk_column])
|
||||
)
|
||||
|
||||
# New Field, must create a column in Class table or in Class_Type relational attribute table
|
||||
# @todo common fields creation does not allow to add new common fields. It should
|
||||
def emfield_new(self, model, uid, initial_state, new_state):
|
||||
|
||||
# field is of type rel2type, create the relational class_type table and return
|
||||
if new_state['fieldtype'] == 'rel2type':
|
||||
# find relational_type name, and class name of the field
|
||||
class_name = self._class_table_name_from_field(model, new_state)
|
||||
type_name = model.component(new_state['rel_to_type_id']).name
|
||||
table_name = self._relational_table_name(class_name, type_name)
|
||||
self._query_bd(
|
||||
create(table=table_name, column=[self._pk_column]),
|
||||
)
|
||||
return
|
||||
|
||||
# Column creation
|
||||
#
|
||||
# field is internal, create a column in the objects table
|
||||
if new_state['internal']:
|
||||
if new_state['fieldtype'] == 'pk': # this column has already beeen created by self._install_tables()
|
||||
return
|
||||
if new_state['name'] in EditorialModel.classtypes.common_fields: # this column has already beeen created by self._install_tables()
|
||||
return
|
||||
|
||||
# field is relational (rel_field_id), create a column in the class_type table
|
||||
elif new_state['rel_field_id']:
|
||||
class_name = self._class_table_name_from_field(model, new_state)
|
||||
rel_type_id = model.component(new_state['rel_field_id']).rel_to_type_id
|
||||
type_name = model.component(rel_type_id).name
|
||||
table_name = self._relational_table_name(class_name, type_name)
|
||||
|
||||
# else create a column in the class table
|
||||
else:
|
||||
table_name = self._class_table_name_from_field(model, new_state)
|
||||
|
||||
field_definition = self._fieldtype_definition(new_state['fieldtype'], new_state)
|
||||
self._query_bd(
|
||||
alter_add(table=table_name, column=[(new_state['name'],field_definition)])
|
||||
)
|
||||
|
||||
## convert fieldtype name to SQL definition
|
||||
def _fieldtype_definition(self, fieldtype, options):
|
||||
basic_type = GenericFieldType.from_name(fieldtype).ftype
|
||||
if basic_type == 'int':
|
||||
return 'INT'
|
||||
elif basic_type == 'char':
|
||||
max_length = options['max_length'] if 'max_length' in options else 255
|
||||
return 'CHAR(%s)' % max_length
|
||||
elif basic_type == 'text':
|
||||
return 'TEXT'
|
||||
elif basic_type == 'bool':
|
||||
return 'BOOLEAN'
|
||||
elif basic_type == 'datetime':
|
||||
definition = 'DATETIME'
|
||||
if 'now_on_create' in options and options['now_on_create']:
|
||||
definition += ' DEFAULT CURRENT_TIMESTAMP'
|
||||
#if 'now_on_update' in options and options['now_on_update']:
|
||||
#definition += ' ON UPDATE CURRENT_TIMESTAMP'
|
||||
return definition
|
||||
|
||||
raise EditorialModel.exceptions.MigrationHandlerChangeError("Basic type '%s' of fieldtype '%s' is not compatible with SQL migration Handler" % basic_type, fieldtype)
|
||||
|
||||
## Test if internal tables must be created, create it if it must
|
||||
def _install_tables(self):
|
||||
# create common fields definition
|
||||
common_fields = [self._pk_column]
|
||||
for name, options in EditorialModel.classtypes.common_fields.items():
|
||||
if options['fieldtype'] != 'pk':
|
||||
common_fields.append((name, self._fieldtype_definition(options['fieldtype'], options)))
|
||||
|
||||
# create common tables
|
||||
self._query_bd(
|
||||
create(table=self._main_table_name, column=common_fields),
|
||||
create(table=self._relation_table_name, column=[('relation_id','INTEGER PRIMARY KEY AUTOINCREMENT'), ('superior_id','INT'), ('subdordinate_id','INT'), ('nature','CHAR(255)'), ('depth','INT'), ('rank','INT')])
|
||||
)
|
||||
|
||||
def _query_bd(self, *queries):
|
||||
with self.db as cur:
|
||||
for query in queries:
|
||||
print(query)
|
||||
## @brief Exec a query
|
||||
# @param query str : SQL query
|
||||
def _query(self, query):
|
||||
if self.debug:
|
||||
print(query + "\n")
|
||||
if not self.dryrun:
|
||||
with self.db.cursor() as cur:
|
||||
cur.execute(query)
|
||||
self.db.commit() # autocommit
|
||||
|
||||
def _class_table_name(self, class_name):
|
||||
return 'class_' + class_name
|
||||
## @brief Add a relationnal field
|
||||
# Add a rel2type attribute
|
||||
# @note this function handles the table creation
|
||||
# @param em Model : EditorialModel.model.Model instance
|
||||
# @param rfuid int : Relationnal field uid
|
||||
def add_relationnal_field(self, em, rfuid):
|
||||
emfield = em.component(rfuid)
|
||||
if not isinstance(emfield, EditorialModel.fields.EmField):
|
||||
raise ValueError("The given uid is not an EmField uid")
|
||||
|
||||
def _relational_table_name(self, class_name, type_name):
|
||||
return 'r2t_' + class_name + '_' + type_name
|
||||
r2tf = em.component(emfield.rel_field_id)
|
||||
tname = self._r2t2table_name(em, r2tf)
|
||||
pkname, pkftype = self._relation_pk
|
||||
|
||||
def _class_table_name_from_field(self, model, field):
|
||||
class_id = field['class_id']
|
||||
class_name = model.component(class_id).name
|
||||
class_table_name = self._class_table_name(class_name)
|
||||
return class_table_name
|
||||
#If not exists create a relational table
|
||||
self._create_table(tname, pkname, pkftype, self.db_engine, if_exists='nothing')
|
||||
#Add a foreign key if wanted
|
||||
if self.foreign_keys:
|
||||
self._add_fk(tname, self.datasource.relations_table_name, pkname, pkname)
|
||||
#Add the column
|
||||
self._add_column(tname, emfield.name, emfield.fieldtype_instance())
|
||||
#Update table triggers
|
||||
self._generate_triggers(tname, self._r2type2cols(em, r2tf))
|
||||
|
||||
## @brief Delete a rel2type attribute
|
||||
#
|
||||
# Delete a rel2type attribute
|
||||
# @note this method handles the table deletion
|
||||
# @param em Model : EditorialModel.model.Model instance
|
||||
# @param rfuid int : Relationnal field uid
|
||||
def del_relationnal_field(self, em, rfuid):
|
||||
emfield = em.component(rfuid)
|
||||
if not isinstance(emfield, EditorialModel.fields.EmField):
|
||||
raise ValueError("The given uid is not an EmField uid")
|
||||
|
||||
r2tf = em.component(emfield.rel_field_id)
|
||||
tname = self._r2t2table_name(em, r2tf)
|
||||
|
||||
if len(self._r2type2cols(em, r2tf)) == 1:
|
||||
#The table can be deleted (no more attribute for this rel2type)
|
||||
self._query("""DROP TABLE {table_name}""".format(table_name=tname))
|
||||
else:
|
||||
self._del_column(tname, emfield.name)
|
||||
#Update table triggers
|
||||
self._generate_triggers(tname, self._r2type2cols(em, r2tf))
|
||||
|
||||
## @brief Given an EmField uid add a column to the corresponding table
|
||||
# @param em Model : A Model instance
|
||||
# @param uid int : An EmField uid
|
||||
def add_col_from_emfield(self, em, uid):
|
||||
emfield = em.component(uid)
|
||||
if not isinstance(emfield, EditorialModel.fields.EmField):
|
||||
raise ValueError("The given uid is not an EmField uid")
|
||||
|
||||
emclass = emfield.em_class
|
||||
tname = self._emclass2table_name(emclass)
|
||||
self._add_column(tname, emfield.name, emfield.fieldtype_instance())
|
||||
# Refresh the table triggers
|
||||
cols_l = self._class2cols(emclass)
|
||||
self._generate_triggers(tname, cols_l)
|
||||
|
||||
## @brief Given a class uid create the coressponding table
|
||||
# @param em Model : A Model instance
|
||||
# @param uid int : An EmField uid
|
||||
def create_emclass_table(self, em, uid, engine):
|
||||
emclass = em.component(uid)
|
||||
if not isinstance(emclass, EditorialModel.classes.EmClass):
|
||||
raise ValueError("The given uid is not an EmClass uid")
|
||||
pkname, pktype = self._common_field_pk
|
||||
table_name = self._emclass2table_name(emclass)
|
||||
self._create_table(table_name, pkname, pktype, engine=engine)
|
||||
|
||||
if self.foreign_keys:
|
||||
self._add_fk(table_name, self.datasource.objects_table_name, pkname, pkname)
|
||||
|
||||
## @brief Given an EmClass uid delete the corresponding table
|
||||
# @param em Model : A Model instance
|
||||
# @param uid int : An EmField uid
|
||||
def delete_emclass_table(self, em, uid):
|
||||
emclass = em.component(uid)
|
||||
if not isinstance(emclass, EditorialModel.classes.EmClass):
|
||||
raise ValueError("The give uid is not an EmClass uid")
|
||||
tname = self._emclass2table_name(emclass)
|
||||
# Delete the table triggers to prevent errors
|
||||
self._generate_triggers(tname, dict())
|
||||
|
||||
tname = self.datasource.escape_idname(tname)
|
||||
|
||||
self._query("""DROP TABLE {table_name};""".format(table_name=tname))
|
||||
|
||||
## @brief Given an EmField delete the corresponding column
|
||||
# @param em Model : an @ref EditorialModel.model.Model instance
|
||||
# @param uid int : an EmField uid
|
||||
def delete_col_from_emfield(self, em, uid):
|
||||
emfield = em.component(uid)
|
||||
if not isinstance(emfield, EditorialModel.fields.EmField):
|
||||
raise ValueError("The given uid is not an EmField uid")
|
||||
|
||||
emclass = emfield.em_class
|
||||
tname = self._emclass2table_name(emclass)
|
||||
# Delete the table triggers to prevent errors
|
||||
self._generate_triggers(tname, dict())
|
||||
|
||||
self._del_column(tname, emfield.name)
|
||||
# Refresh the table triggers
|
||||
cols_ls = self._class2cols(emclass)
|
||||
self._generate_triggers(tname, cols_l)
|
||||
|
||||
## @brief Delete a column from a table
|
||||
# @param tname str : The table name
|
||||
# @param fname str : The column name
|
||||
def _del_column(self, tname, fname):
|
||||
tname = self.datasource.escape_idname(tname)
|
||||
fname = self.datasource.escape_idname(fname)
|
||||
|
||||
self._query("""ALTER TABLE {table_name} DROP COLUMN {col_name};""".format(table_name=tname, col_name=fname))
|
||||
|
||||
## @brief Construct a table name given an EmClass instance
|
||||
# @param emclass EmClass : An EmClass instance
|
||||
# @return a table name
|
||||
def _emclass2table_name(self, emclass):
|
||||
return self.datasource.get_table_name_from_class(emclass.name)
|
||||
#return "class_%s"%emclass.name
|
||||
|
||||
## @brief Construct a table name given a rela2type EmField instance
|
||||
# @param em Model : A Model instance
|
||||
# @param emfield EmField : An EmField instance
|
||||
# @return a table name
|
||||
def _r2t2table_name(self, em, emfield):
|
||||
emclass = emfield.em_class
|
||||
emtype = em.component(emfield.rel_to_type_id)
|
||||
return self.datasource.get_r2t2table_name(emclass.name, emtype.name)
|
||||
#return "%s_%s_%s"%(emclass.name, emtype.name, emfield.name)
|
||||
|
||||
## @brief Generate a columns_fieldtype dict given a rel2type EmField
|
||||
# @param em Model : an @ref EditorialModel.model.Model instance
|
||||
# @param emfield EmField : and @ref EditorialModel.fields.EmField instance
|
||||
def _r2type2cols(self, em, emfield):
|
||||
return {f.name: f.fieldtype_instance() for f in em.components('EmField') if f.rel_field_id == emfield.uid}
|
||||
|
||||
## @brief Generate a columns_fieldtype dict given an EmClass
|
||||
# @param emclass EmClass : An EmClass instance
|
||||
# @return A dict with column name as key and EmFieldType instance as value
|
||||
def _class2cols(self, emclass):
|
||||
if not isinstance(emclass, EditorialModel.classes.EmClass):
|
||||
raise ValueError("The given uid is not an EmClass uid")
|
||||
return {f.name: f.fieldtype_instance() for f in emclass.fields() if f.name not in EditorialModel.classtypes.common_fields.keys()}
|
||||
|
||||
## @brief Create object and relations tables
|
||||
# @param drop_if_exist bool : If true drop tables if exists
|
||||
def _create_default_tables(self, drop_if_exist=False):
|
||||
if_exists = 'drop' if drop_if_exist else 'nothing'
|
||||
#Object tablea
|
||||
tname = self.datasource.objects_table_name
|
||||
pk_name, pk_ftype = self._common_field_pk
|
||||
self._create_table(tname, pk_name, pk_ftype, engine=self.db_engine, if_exists=if_exists)
|
||||
#Adding columns
|
||||
cols = {fname: self._common_field_to_ftype(fname) for fname in EditorialModel.classtypes.common_fields}
|
||||
for fname, ftype in cols.items():
|
||||
if fname != pk_name:
|
||||
self._add_column(tname, fname, ftype)
|
||||
#Creating triggers
|
||||
self._generate_triggers(tname, cols)
|
||||
|
||||
#Relation table
|
||||
tname = self.datasource.relations_table_name
|
||||
pk_name, pk_ftype = self._relation_pk
|
||||
self._create_table(tname, pk_name, pk_ftype, engine=self.db_engine, if_exists=if_exists)
|
||||
#Adding columns
|
||||
for fname, ftype in self._relation_cols.items():
|
||||
self._add_column(tname, fname, ftype)
|
||||
#Creating triggers
|
||||
self._generate_triggers(tname, self._relation_cols)
|
||||
|
||||
## @return true if the name changes
|
||||
def _name_change(self, initial_state, new_state):
|
||||
return 'name' in initial_state and initial_state['name'] != new_state['name']
|
||||
|
||||
## @brief Create a table with primary key
|
||||
# @param table_name str : table name
|
||||
# @param pk_name str : pk column name
|
||||
# @param pk_specs str : see @ref _field_to_sql()
|
||||
# @param engine str : The engine to use with this table
|
||||
# @param charset str : The charset of this table
|
||||
# @param if_exist str : takes values in ['nothing', 'drop']
|
||||
def _create_table(self, table_name, pk_name, pk_ftype, engine, charset='utf8', if_exists='nothing'):
|
||||
#Escaped table name
|
||||
etname = self.datasource.escape_idname(table_name)
|
||||
pk_type = self._field_to_type(pk_ftype)
|
||||
pk_specs = self._field_to_specs(pk_ftype)
|
||||
|
||||
if if_exists == 'drop':
|
||||
self._query("""DROP TABLE IF EXISTS {table_name};""".format(table_name=etname))
|
||||
qres = """
|
||||
CREATE TABLE {table_name} (
|
||||
{pk_name} {pk_type} {pk_specs},
|
||||
PRIMARY KEY({pk_name})
|
||||
) ENGINE={engine} DEFAULT CHARSET={charset};"""
|
||||
elif if_exists == 'nothing':
|
||||
qres = """CREATE TABLE IF NOT EXISTS {table_name} (
|
||||
{pk_name} {pk_type} {pk_specs},
|
||||
PRIMARY KEY({pk_name})
|
||||
) ENGINE={engine} DEFAULT CHARSET={charset};"""
|
||||
else:
|
||||
raise ValueError("Unexpected value for argument if_exists '%s'." % if_exists)
|
||||
|
||||
self._query(qres.format(
|
||||
table_name=self.datasource.escape_idname(table_name),
|
||||
pk_name=self.datasource.escape_idname(pk_name),
|
||||
pk_type=pk_type,
|
||||
pk_specs=pk_specs,
|
||||
engine=engine,
|
||||
charset=charset
|
||||
))
|
||||
|
||||
## @brief Add a column to a table
|
||||
# @param table_name str : The table name
|
||||
# @param col_name str : The columns name
|
||||
# @param col_fieldtype EmFieldype the fieldtype
|
||||
def _add_column(self, table_name, col_name, col_fieldtype, drop_if_exists=False):
|
||||
add_col = """ALTER TABLE {table_name}
|
||||
ADD COLUMN {col_name} {col_type} {col_specs};"""
|
||||
|
||||
etname = self.datasource.escape_idname(table_name)
|
||||
ecname = self.datasource.escape_idname(col_name)
|
||||
|
||||
add_col = add_col.format(
|
||||
table_name=etname,
|
||||
col_name=ecname,
|
||||
col_type=self._field_to_type(col_fieldtype),
|
||||
col_specs=self._field_to_specs(col_fieldtype),
|
||||
)
|
||||
try:
|
||||
self._query(add_col)
|
||||
except self._dbmodule.err.InternalError as e:
|
||||
if drop_if_exists:
|
||||
self._del_column(table_name, col_name)
|
||||
self._add_column(table_name, col_name, col_fieldtype, drop_if_exists)
|
||||
else:
|
||||
#LOG
|
||||
print("Aborded, column `%s` exists" % col_name)
|
||||
|
||||
## @brief Add a foreign key
|
||||
# @param src_table_name str : The name of the table where we will add the FK
|
||||
# @param dst_table_name str : The name of the table the FK will point on
|
||||
# @param src_col_name str : The name of the concerned column in the src_table
|
||||
# @param dst_col_name str : The name of the concerned column in the dst_table
|
||||
def _add_fk(self, src_table_name, dst_table_name, src_col_name, dst_col_name):
|
||||
stname = self.datasource.escape_idname(src_table_name)
|
||||
dtname = self.datasource.escape_idname(dst_table_name)
|
||||
scname = self.datasource.escape_idname(src_col_name)
|
||||
dcname = self.datasource.escape_idname(dst_col_name)
|
||||
|
||||
fk_name = self.datasource.get_fk_name(src_table_name, dst_table_name)
|
||||
|
||||
self._del_fk(src_table_name, dst_table_name)
|
||||
|
||||
self._query("""ALTER TABLE {src_table}
|
||||
ADD CONSTRAINT {fk_name}
|
||||
FOREIGN KEY ({src_col}) references {dst_table}({dst_col});""".format(
|
||||
fk_name=self.datasource.escape_idname(fk_name),
|
||||
src_table=stname,
|
||||
src_col=scname,
|
||||
dst_table=dtname,
|
||||
dst_col=dcname
|
||||
))
|
||||
|
||||
## @brief Given a source and a destination table, delete the corresponding FK
|
||||
# @param src_table_name str : The name of the table where the FK is
|
||||
# @param dst_table_name str : The name of the table the FK point on
|
||||
# @warning fails silently
|
||||
def _del_fk(self, src_table_name, dst_table_name):
|
||||
try:
|
||||
self._query("""ALTER TABLE {src_table}
|
||||
DROP FOREIGN KEY {fk_name}""".format(
|
||||
src_table=self.datasource.escape_idname(src_table_name),
|
||||
fk_name=self.datasource.escape_idname(self.datasource.get_fk_name(src_table_name, dst_table_name))
|
||||
))
|
||||
except self._dbmodule.err.InternalError:
|
||||
# If the FK don't exists we do not care
|
||||
pass
|
||||
|
||||
## @brief Generate triggers given a table_name and its columns fieldtypes
|
||||
# @param table_name str : Table name
|
||||
# @param cols_ftype dict : with col name as key and column fieldtype as value
|
||||
def _generate_triggers(self, table_name, cols_ftype):
|
||||
colval_l_upd = dict() # param for update trigger
|
||||
colval_l_ins = dict() # param for insert trigger
|
||||
|
||||
for cname, cftype in cols_ftype.items():
|
||||
if cftype.ftype == 'datetime':
|
||||
if cftype.now_on_update:
|
||||
colval_l_upd[cname] = 'NOW()'
|
||||
if cftype.now_on_create:
|
||||
colval_l_ins[cname] = 'NOW()'
|
||||
|
||||
self._table_trigger(table_name, 'UPDATE', colval_l_upd)
|
||||
self._table_trigger(table_name, 'INSERT', colval_l_ins)
|
||||
|
||||
## @brief Create trigger for a table
|
||||
#
|
||||
# Primarly designed to create trigger for DATETIME types
|
||||
# The method generates triggers of the form
|
||||
#
|
||||
# CREATE TRIGGER BEFORE <moment> ON <table_name>
|
||||
# FOR EACH ROW SET <for colname, colval in cols_val>
|
||||
# NEW.<colname> = <colval>,
|
||||
# <endfor>;
|
||||
# @param table_name str : The table name
|
||||
# @param moment str : can be 'update' or 'insert'
|
||||
# @param cols_val dict : Dict with column name as key and column value as value
|
||||
def _table_trigger(self, table_name, moment, cols_val):
|
||||
trigger_name = self.datasource.escape_idname("%s_%s_trig" % (table_name, moment))
|
||||
#Try to delete the trigger
|
||||
drop_trig = """DROP TRIGGER IF EXISTS {trigger_name};""".format(trigger_name=trigger_name)
|
||||
self._query(drop_trig)
|
||||
|
||||
col_val_l = ', '.join(["NEW.%s = %s" % (self.datasource.escape_idname(cname), cval)for cname, cval in cols_val.items()])
|
||||
#Create a trigger if needed
|
||||
if len(col_val_l) > 0:
|
||||
trig_q = """CREATE TRIGGER {trigger_name} BEFORE {moment} ON {table_name}
|
||||
FOR EACH ROW SET {col_val_list};""".format(
|
||||
trigger_name=trigger_name,
|
||||
table_name=self.datasource.escape_idname(table_name),
|
||||
moment=moment, col_val_list=col_val_l
|
||||
)
|
||||
self._query(trig_q)
|
||||
|
||||
## @brief Identifier escaping
|
||||
# @param idname str : An SQL identifier
|
||||
#def _idname_escape(self, idname):
|
||||
# if '`' in idname:
|
||||
# raise ValueError("Invalid name : '%s'"%idname)
|
||||
# return '`%s`'%idname
|
||||
|
||||
## @brief Returns column specs from fieldtype
|
||||
# @param emfieldtype EmFieldType : An EmFieldType insance
|
||||
# @todo escape default value
|
||||
def _field_to_specs(self, emfieldtype):
|
||||
colspec = ''
|
||||
if not emfieldtype.nullable:
|
||||
colspec = 'NOT NULL'
|
||||
if hasattr(emfieldtype, 'default'):
|
||||
colspec += ' DEFAULT '
|
||||
if emfieldtype.default is None:
|
||||
colspec += 'NULL '
|
||||
else:
|
||||
colspec += emfieldtype.default # ESCAPE VALUE HERE !!!!
|
||||
|
||||
if emfieldtype.name == 'pk':
|
||||
colspec += ' AUTO_INCREMENT'
|
||||
|
||||
return colspec
|
||||
|
||||
## @brief Given a fieldtype return a MySQL type specifier
|
||||
# @param emfieldtype EmFieldType : A fieldtype
|
||||
# @return the corresponding MySQL type
|
||||
def _field_to_type(self, emfieldtype):
|
||||
ftype = emfieldtype.ftype
|
||||
|
||||
if ftype == 'char' or ftype == 'str':
|
||||
res = "VARCHAR(%d)" % emfieldtype.max_length
|
||||
elif ftype == 'text':
|
||||
res = "TEXT"
|
||||
elif ftype == 'datetime':
|
||||
res = "DATETIME"
|
||||
# client side workaround for only one column with CURRENT_TIMESTAMP : giving NULL to timestamp that don't allows NULL
|
||||
# cf. https://dev.mysql.com/doc/refman/5.0/en/timestamp-initialization.html#idm139961275230400
|
||||
# The solution for the migration handler is to create triggers :
|
||||
# CREATE TRIGGER trigger_name BEFORE INSERT ON `my_super_table`
|
||||
# FOR EACH ROW SET NEW.my_date_column = NOW();
|
||||
# and
|
||||
# CREATE TRIGGER trigger_name BEFORE UPDATE ON
|
||||
|
||||
elif ftype == 'bool':
|
||||
res = "BOOL"
|
||||
elif ftype == 'int':
|
||||
res = "INT"
|
||||
elif ftype == 'rel2type':
|
||||
res = "INT"
|
||||
else:
|
||||
raise ValueError("Unsuported fieldtype ftype : %s" % ftype)
|
||||
|
||||
return res
|
||||
|
||||
## @brief Returns a tuple (pkname, pk_ftype)
|
||||
@property
|
||||
def _common_field_pk(self):
|
||||
for fname, fta in EditorialModel.classtypes.common_fields.items():
|
||||
if fta['fieldtype'] == 'pk':
|
||||
return (fname, self._common_field_to_ftype(fname))
|
||||
return (None, None)
|
||||
|
||||
## @brief Returns a tuple (rel_pkname, rel_ftype)
|
||||
# @todo do it
|
||||
@property
|
||||
def _relation_pk(self):
|
||||
return (MySQL.relations_pkname, EditorialModel.fieldtypes.pk.EmFieldType())
|
||||
|
||||
## @brief Returns a dict { colname:fieldtype } of relation table columns
|
||||
@property
|
||||
def _relation_cols(self):
|
||||
from_name = EditorialModel.fieldtypes.generic.GenericFieldType.from_name
|
||||
return {
|
||||
'id_sup': from_name('integer')(),
|
||||
'id_sub': from_name('integer')(),
|
||||
'rank': from_name('integer')(nullable=True),
|
||||
'depth': from_name('integer')(nullable=True),
|
||||
'nature': from_name('char')(max_lenght=10, nullable=True),
|
||||
}
|
||||
|
||||
## @brief Given a common field name return an EmFieldType instance
|
||||
# @param cname str : Common field name
|
||||
# @return An EmFieldType instance
|
||||
def _common_field_to_ftype(self, cname):
|
||||
fta = copy.copy(EditorialModel.classtypes.common_fields[cname])
|
||||
fto = EditorialModel.fieldtypes.generic.GenericFieldType.from_name(fta['fieldtype'])
|
||||
del fta['fieldtype']
|
||||
return fto(**fta)
|
||||
|
|
|
|||
156
DataSource/MySQL/migrationhandler__future__.py
Normal file
156
DataSource/MySQL/migrationhandler__future__.py
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
## @package EditorialModel.migrationhandler.sql
|
||||
# @brief A dummy migration handler
|
||||
#
|
||||
# According to it every modifications are possible
|
||||
#
|
||||
|
||||
import EditorialModel
|
||||
from DataSource.dummy.migrationhandler import DummyMigrationHandler
|
||||
from EditorialModel.fieldtypes.generic import GenericFieldType
|
||||
from EditorialModel.model import Model
|
||||
from mosql.db import Database
|
||||
from Lodel.utils.mosql import create, alter_add
|
||||
|
||||
|
||||
## Manage Model changes
|
||||
class SQLMigrationHandler(DummyMigrationHandler):
|
||||
|
||||
fieldtype_to_sql = {
|
||||
'char': "CHAR(255)",
|
||||
'integer': 'INT'
|
||||
}
|
||||
|
||||
def __init__(self, module=None, *conn_args, **conn_kargs):
|
||||
super(SQLMigrationHandler, self).__init__(False)
|
||||
|
||||
self.db = Database(module, *conn_args, **conn_kargs)
|
||||
self._pk_column = (EditorialModel.classtypes.pk_name(), 'INTEGER PRIMARY KEY AUTO_INCREMENT')
|
||||
self._main_table_name = 'object'
|
||||
self._relation_table_name = 'relation'
|
||||
|
||||
self._install_tables()
|
||||
|
||||
## @brief Record a change in the EditorialModel and indicate wether or not it is possible to make it
|
||||
# @note The states ( initial_state and new_state ) contains only fields that changes
|
||||
# @param model model : The EditorialModel.model object to provide the global context
|
||||
# @param uid int : The uid of the change EmComponent
|
||||
# @param initial_state dict | None : dict with field name as key and field value as value. Representing the original state. None mean creation of a new component.
|
||||
# @param new_state dict | None : dict with field name as key and field value as value. Representing the new state. None mean component deletion
|
||||
# @throw EditorialModel.exceptions.MigrationHandlerChangeError if the change was refused
|
||||
def register_change(self, model, uid, initial_state, new_state):
|
||||
# find type of component change
|
||||
if initial_state is None:
|
||||
state_change = 'new'
|
||||
elif new_state is None:
|
||||
state_change = 'del'
|
||||
else:
|
||||
state_change = 'upgrade'
|
||||
|
||||
# call method to handle the database change
|
||||
component_name = Model.name_from_emclass(type(model.component(uid)))
|
||||
handler_func = component_name.lower() + '_' + state_change
|
||||
if hasattr(self, handler_func):
|
||||
getattr(self, handler_func)(model, uid, initial_state, new_state)
|
||||
|
||||
# New Class, a table must be created
|
||||
def emclass_new(self, model, uid, initial_state, new_state):
|
||||
class_table_name = self._class_table_name(new_state['name'])
|
||||
self._query_bd(
|
||||
create(table=class_table_name, column=[self._pk_column])
|
||||
)
|
||||
|
||||
# New Field, must create a column in Class table or in Class_Type relational attribute table
|
||||
# @todo common fields creation does not allow to add new common fields. It should
|
||||
def emfield_new(self, model, uid, initial_state, new_state):
|
||||
|
||||
# field is of type rel2type, create the relational class_type table and return
|
||||
if new_state['fieldtype'] == 'rel2type':
|
||||
# find relational_type name, and class name of the field
|
||||
class_name = self._class_table_name_from_field(model, new_state)
|
||||
type_name = model.component(new_state['rel_to_type_id']).name
|
||||
table_name = self._relational_table_name(class_name, type_name)
|
||||
self._query_bd(
|
||||
create(table=table_name, column=[self._pk_column]),
|
||||
)
|
||||
return
|
||||
|
||||
# Column creation
|
||||
#
|
||||
# field is internal, create a column in the objects table
|
||||
if new_state['internal']:
|
||||
if new_state['fieldtype'] == 'pk': # this column has already beeen created by self._install_tables()
|
||||
return
|
||||
if new_state['name'] in EditorialModel.classtypes.common_fields: # this column has already beeen created by self._install_tables()
|
||||
return
|
||||
|
||||
# field is relational (rel_field_id), create a column in the class_type table
|
||||
elif new_state['rel_field_id']:
|
||||
class_name = self._class_table_name_from_field(model, new_state)
|
||||
rel_type_id = model.component(new_state['rel_field_id']).rel_to_type_id
|
||||
type_name = model.component(rel_type_id).name
|
||||
table_name = self._relational_table_name(class_name, type_name)
|
||||
|
||||
# else create a column in the class table
|
||||
else:
|
||||
table_name = self._class_table_name_from_field(model, new_state)
|
||||
|
||||
field_definition = self._fieldtype_definition(new_state['fieldtype'], new_state)
|
||||
self._query_bd(
|
||||
alter_add(table=table_name, column=[(new_state['name'],field_definition)])
|
||||
)
|
||||
|
||||
## convert fieldtype name to SQL definition
|
||||
def _fieldtype_definition(self, fieldtype, options):
|
||||
basic_type = GenericFieldType.from_name(fieldtype).ftype
|
||||
if basic_type == 'int':
|
||||
return 'INT'
|
||||
elif basic_type == 'char':
|
||||
max_length = options['max_length'] if 'max_length' in options else 255
|
||||
return 'CHAR(%s)' % max_length
|
||||
elif basic_type == 'text':
|
||||
return 'TEXT'
|
||||
elif basic_type == 'bool':
|
||||
return 'BOOLEAN'
|
||||
elif basic_type == 'datetime':
|
||||
definition = 'DATETIME'
|
||||
if 'now_on_create' in options and options['now_on_create']:
|
||||
definition += ' DEFAULT CURRENT_TIMESTAMP'
|
||||
#if 'now_on_update' in options and options['now_on_update']:
|
||||
#definition += ' ON UPDATE CURRENT_TIMESTAMP'
|
||||
return definition
|
||||
|
||||
raise EditorialModel.exceptions.MigrationHandlerChangeError("Basic type '%s' of fieldtype '%s' is not compatible with SQL migration Handler" % basic_type, fieldtype)
|
||||
|
||||
## Test if internal tables must be created, create it if it must
|
||||
def _install_tables(self):
|
||||
# create common fields definition
|
||||
common_fields = [self._pk_column]
|
||||
for name, options in EditorialModel.classtypes.common_fields.items():
|
||||
if options['fieldtype'] != 'pk':
|
||||
common_fields.append((name, self._fieldtype_definition(options['fieldtype'], options)))
|
||||
|
||||
# create common tables
|
||||
self._query_bd(
|
||||
create(table=self._main_table_name, column=common_fields),
|
||||
create(table=self._relation_table_name, column=[('relation_id','INTEGER PRIMARY KEY AUTOINCREMENT'), ('superior_id','INT'), ('subdordinate_id','INT'), ('nature','CHAR(255)'), ('depth','INT'), ('rank','INT')])
|
||||
)
|
||||
|
||||
def _query_bd(self, *queries):
|
||||
with self.db as cur:
|
||||
for query in queries:
|
||||
print(query)
|
||||
cur.execute(query)
|
||||
|
||||
def _class_table_name(self, class_name):
|
||||
return 'class_' + class_name
|
||||
|
||||
def _relational_table_name(self, class_name, type_name):
|
||||
return 'r2t_' + class_name + '_' + type_name
|
||||
|
||||
def _class_table_name_from_field(self, model, field):
|
||||
class_id = field['class_id']
|
||||
class_name = model.component(class_id).name
|
||||
class_table_name = self._class_table_name(class_name)
|
||||
return class_table_name
|
||||
10
README.md
10
README.md
|
|
@ -1,3 +1,13 @@
|
|||
Creating a Lodel "instance":
|
||||
|
||||
use the lodel_init.sh script :
|
||||
lodel_init.sh INSTANCE_NAME INSTANCE_WANTED_PATH [LODEL2_LIB_PATH]
|
||||
|
||||
Once the instance is created you can run an interactive python interpreter using :
|
||||
cd INSTANCE_PATH; python loader.py
|
||||
|
||||
If you want to write a script that run is the instance env you have to from loader import *
|
||||
|
||||
First test installation :
|
||||
|
||||
- use python 3.4
|
||||
|
|
|
|||
17
install/Makefile
Normal file
17
install/Makefile
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
all:
|
||||
|
||||
refreshdyn:
|
||||
python -c "import utils; utils.refreshdyn()"
|
||||
|
||||
dbinit:
|
||||
python -c "import utils; utils.db_init()"
|
||||
|
||||
.PHONY: clean cleanpycache cleanpyc refreshdyn
|
||||
|
||||
clean: cleanpycache
|
||||
|
||||
cleanpyc:
|
||||
-@rm -v *.pyc
|
||||
|
||||
cleanpycache: cleanpyc
|
||||
-@rm -vR __pycache__
|
||||
171
install/dynleapi.py
Normal file
171
install/dynleapi.py
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
## @author LeFactory
|
||||
|
||||
import EditorialModel
|
||||
from EditorialModel import fieldtypes
|
||||
from EditorialModel.fieldtypes import naturerelation, char, integer, datetime, pk
|
||||
|
||||
import leapi
|
||||
import leapi.lecrud
|
||||
import leapi.leobject
|
||||
import leapi.lerelation
|
||||
from leapi.leclass import _LeClass
|
||||
from leapi.letype import _LeType
|
||||
|
||||
import DataSource.MySQL.leapidatasource
|
||||
|
||||
|
||||
## @brief _LeCrud concret class
|
||||
# @see leapi.lecrud._LeCrud
|
||||
class LeCrud(leapi.lecrud._LeCrud):
|
||||
_datasource = DataSource.MySQL.leapidatasource.LeDataSourceSQL(**{})
|
||||
_uid_fieldtype = None
|
||||
|
||||
## @brief _LeObject concret class
|
||||
# @see leapi.leobject._LeObject
|
||||
class LeObject(LeCrud, leapi.leobject._LeObject):
|
||||
_me_uid = {1: 'Textes', 2: 'Personnes', 19: 'Numero', 5: 'Article', 6: 'Personne', 13: 'Publication', 14: 'Rubrique'}
|
||||
_uid_fieldtype = { 'lodel_id': EditorialModel.fieldtypes.pk.EmFieldType(**{'internal': 'automatic'}) }
|
||||
_leo_fieldtypes = {
|
||||
'creation_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'now_on_create': True, 'internal': 'automatic'}),
|
||||
'string': EditorialModel.fieldtypes.char.EmFieldType(**{'max_length': 128, 'internal': 'automatic'}),
|
||||
'modification_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'now_on_update': True, 'now_on_create': True, 'internal': 'automatic'}),
|
||||
'type_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'internal': 'automatic'}),
|
||||
'class_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'internal': 'automatic'})
|
||||
}
|
||||
|
||||
## @brief _LeRelation concret class
|
||||
# @see leapi.lerelation._LeRelation
|
||||
class LeRelation(LeCrud, leapi.lerelation._LeRelation):
|
||||
_uid_fieldtype = { 'id_relation': EditorialModel.fieldtypes.pk.EmFieldType(**{'internal': 'automatic'}) }
|
||||
_rel_fieldtypes = {
|
||||
'rank': EditorialModel.fieldtypes.integer.EmFieldType(**{'internal': 'automatic'}),
|
||||
'nature': EditorialModel.fieldtypes.naturerelation.EmFieldType(**{}),
|
||||
'depth': EditorialModel.fieldtypes.integer.EmFieldType(**{'internal': 'automatic'})
|
||||
}
|
||||
_rel_attr_fieldtypes = dict()
|
||||
|
||||
class LeHierarch(LeRelation, leapi.lerelation._LeHierarch):
|
||||
_rel_attr_fieldtypes = dict()
|
||||
|
||||
class LeRel2Type(LeRelation, leapi.lerelation._LeRel2Type):
|
||||
pass
|
||||
|
||||
class LeClass(LeObject, _LeClass):
|
||||
pass
|
||||
|
||||
class LeType(LeClass, _LeType):
|
||||
pass
|
||||
|
||||
## @brief EmClass Textes LeClass child class
|
||||
# @see leapi.leclass.LeClass
|
||||
class Textes(LeClass, LeObject):
|
||||
_class_id = 1
|
||||
|
||||
|
||||
## @brief EmClass Personnes LeClass child class
|
||||
# @see leapi.leclass.LeClass
|
||||
class Personnes(LeClass, LeObject):
|
||||
_class_id = 2
|
||||
|
||||
|
||||
## @brief EmClass Publication LeClass child class
|
||||
# @see leapi.leclass.LeClass
|
||||
class Publication(LeClass, LeObject):
|
||||
_class_id = 13
|
||||
|
||||
|
||||
## @brief EmType Article LeType child class
|
||||
# @see leobject::letype::LeType
|
||||
class Article(LeType, Textes):
|
||||
_type_id = 5
|
||||
|
||||
|
||||
## @brief EmType Personne LeType child class
|
||||
# @see leobject::letype::LeType
|
||||
class Personne(LeType, Personnes):
|
||||
_type_id = 6
|
||||
|
||||
|
||||
## @brief EmType Rubrique LeType child class
|
||||
# @see leobject::letype::LeType
|
||||
class Rubrique(LeType, Publication):
|
||||
_type_id = 14
|
||||
|
||||
|
||||
## @brief EmType Numero LeType child class
|
||||
# @see leobject::letype::LeType
|
||||
class Numero(LeType, Publication):
|
||||
_type_id = 19
|
||||
|
||||
|
||||
class Rel_textes2personne(LeRel2Type):
|
||||
_rel_attr_fieldtypes = {
|
||||
'adresse': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False})
|
||||
}
|
||||
|
||||
|
||||
#Initialisation of Textes class attributes
|
||||
Textes._fieldtypes = {
|
||||
'modification_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'nullable': False, 'uniq': False, 'now_on_update': True, 'now_on_create': True, 'internal': 'automatic'}),
|
||||
'soustitre': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
|
||||
'string': EditorialModel.fieldtypes.char.EmFieldType(**{'nullable': True, 'uniq': False, 'max_length': 128, 'internal': 'automatic'}),
|
||||
'titre': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
|
||||
'bleu': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
|
||||
'lodel_id': EditorialModel.fieldtypes.pk.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
|
||||
'type_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
|
||||
'class_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
|
||||
'creation_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'uniq': False, 'nullable': False, 'now_on_create': True, 'internal': 'automatic'})
|
||||
}
|
||||
Textes._linked_types = [Personne]
|
||||
Textes._classtype = 'entity'
|
||||
|
||||
#Initialisation of Personnes class attributes
|
||||
Personnes._fieldtypes = {
|
||||
'nom': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
|
||||
'age': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
|
||||
'prenom': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
|
||||
'string': EditorialModel.fieldtypes.char.EmFieldType(**{'nullable': True, 'uniq': False, 'max_length': 128, 'internal': 'automatic'}),
|
||||
'lodel_id': EditorialModel.fieldtypes.pk.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
|
||||
'modification_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'nullable': False, 'uniq': False, 'now_on_update': True, 'now_on_create': True, 'internal': 'automatic'}),
|
||||
'type_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
|
||||
'class_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
|
||||
'creation_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'uniq': False, 'nullable': False, 'now_on_create': True, 'internal': 'automatic'})
|
||||
}
|
||||
Personnes._linked_types = []
|
||||
Personnes._classtype = 'person'
|
||||
|
||||
#Initialisation of Publication class attributes
|
||||
Publication._fieldtypes = {
|
||||
'modification_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'nullable': False, 'uniq': False, 'now_on_update': True, 'now_on_create': True, 'internal': 'automatic'}),
|
||||
'creation_date': EditorialModel.fieldtypes.datetime.EmFieldType(**{'uniq': False, 'nullable': False, 'now_on_create': True, 'internal': 'automatic'}),
|
||||
'string': EditorialModel.fieldtypes.char.EmFieldType(**{'nullable': True, 'uniq': False, 'max_length': 128, 'internal': 'automatic'}),
|
||||
'lodel_id': EditorialModel.fieldtypes.pk.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
|
||||
'titre': EditorialModel.fieldtypes.char.EmFieldType(**{'uniq': False, 'nullable': True, 'internal': False}),
|
||||
'type_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'}),
|
||||
'class_id': EditorialModel.fieldtypes.integer.EmFieldType(**{'uniq': False, 'nullable': False, 'internal': 'automatic'})
|
||||
}
|
||||
Publication._linked_types = []
|
||||
Publication._classtype = 'entity'
|
||||
|
||||
#Initialisation of Article class attributes
|
||||
Article._fields = ['titre', 'class_id', 'soustitre', 'string', 'type_id', 'lodel_id', 'modification_date', 'creation_date']
|
||||
Article._superiors = {'parent': [Rubrique]}
|
||||
Article._leclass = Textes
|
||||
|
||||
#Initialisation of Personne class attributes
|
||||
Personne._fields = ['nom', 'class_id', 'prenom', 'string', 'type_id', 'lodel_id', 'modification_date', 'creation_date']
|
||||
Personne._superiors = {}
|
||||
Personne._leclass = Personnes
|
||||
|
||||
#Initialisation of Rubrique class attributes
|
||||
Rubrique._fields = ['titre', 'class_id', 'string', 'type_id', 'lodel_id', 'modification_date', 'creation_date']
|
||||
Rubrique._superiors = {'parent': [Rubrique, Numero]}
|
||||
Rubrique._leclass = Publication
|
||||
|
||||
#Initialisation of Numero class attributes
|
||||
Numero._fields = ['titre', 'class_id', 'string', 'type_id', 'lodel_id', 'modification_date', 'creation_date']
|
||||
Numero._superiors = {}
|
||||
Numero._leclass = Publication
|
||||
|
||||
## @brief Dict for getting LeClass and LeType child classes given an EM uid
|
||||
LeObject._me_uid = {1: Textes, 2: Personnes, 19: Numero, 5: Article, 6: Personne, 13: Publication, 14: Rubrique}
|
||||
579
install/em.json
Normal file
579
install/em.json
Normal file
|
|
@ -0,0 +1,579 @@
|
|||
{
|
||||
"1": {
|
||||
"component": "EmClass",
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"sortcolumn": "rank",
|
||||
"classtype": "entity",
|
||||
"icon": "0",
|
||||
"rank": 1,
|
||||
"name": "textes",
|
||||
"help_text": "",
|
||||
"string": "{\"fre\": \"Texte\"}"
|
||||
},
|
||||
"2": {
|
||||
"component": "EmClass",
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"sortcolumn": "rank",
|
||||
"classtype": "person",
|
||||
"icon": "0",
|
||||
"rank": 1,
|
||||
"name": "personnes",
|
||||
"help_text": "",
|
||||
"string": "{\"fre\": \"Personnes\"}"
|
||||
},
|
||||
"4": {
|
||||
"nullable": true,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "{\"fre\": \"Titre\"}",
|
||||
"class_id": 1,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 1,
|
||||
"fieldtype": "char",
|
||||
"help_text": "",
|
||||
"internal": false,
|
||||
"rel_field_id": null,
|
||||
"name": "titre"
|
||||
},
|
||||
"5": {
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"class_id": 1,
|
||||
"icon": "0",
|
||||
"name": "article",
|
||||
"superiors_list": {
|
||||
"parent": [
|
||||
14
|
||||
]
|
||||
},
|
||||
"fields_list": [
|
||||
7
|
||||
],
|
||||
"string": "{\"fre\": \"Article\"}",
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"component": "EmType",
|
||||
"rank": 1,
|
||||
"help_text": "",
|
||||
"sortcolumn": "rank"
|
||||
},
|
||||
"6": {
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"class_id": 2,
|
||||
"icon": "0",
|
||||
"name": "personne",
|
||||
"superiors_list": {},
|
||||
"fields_list": [
|
||||
10
|
||||
],
|
||||
"string": "{\"fre\": \"Personne\"}",
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"component": "EmType",
|
||||
"rank": 1,
|
||||
"help_text": "",
|
||||
"sortcolumn": "rank"
|
||||
},
|
||||
"7": {
|
||||
"nullable": true,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": true,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "{\"fre\": \"Sous-titre\"}",
|
||||
"class_id": 1,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 2,
|
||||
"fieldtype": "char",
|
||||
"help_text": "",
|
||||
"internal": false,
|
||||
"rel_field_id": null,
|
||||
"name": "soustitre"
|
||||
},
|
||||
"9": {
|
||||
"nullable": true,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "{\"fre\": \"Nom\"}",
|
||||
"class_id": 2,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 1,
|
||||
"fieldtype": "char",
|
||||
"help_text": "",
|
||||
"internal": false,
|
||||
"rel_field_id": null,
|
||||
"name": "nom"
|
||||
},
|
||||
"10": {
|
||||
"nullable": true,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": true,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "{\"fre\": \"Pr\\u00e9nom\"}",
|
||||
"class_id": 2,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 2,
|
||||
"fieldtype": "char",
|
||||
"help_text": "",
|
||||
"internal": false,
|
||||
"rel_field_id": null,
|
||||
"name": "prenom"
|
||||
},
|
||||
"11": {
|
||||
"nullable": true,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "{\"fre\": \"Auteur\"}",
|
||||
"class_id": 1,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rel_to_type_id": 6,
|
||||
"rank": 1,
|
||||
"fieldtype": "rel2type",
|
||||
"help_text": "",
|
||||
"internal": false,
|
||||
"rel_field_id": null,
|
||||
"name": "auteur"
|
||||
},
|
||||
"12": {
|
||||
"nullable": true,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "{\"fre\": \"Adresse\"}",
|
||||
"class_id": 1,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 2,
|
||||
"fieldtype": "char",
|
||||
"help_text": "",
|
||||
"internal": false,
|
||||
"rel_field_id": 11,
|
||||
"name": "adresse"
|
||||
},
|
||||
"13": {
|
||||
"component": "EmClass",
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"sortcolumn": "rank",
|
||||
"classtype": "entity",
|
||||
"icon": "0",
|
||||
"rank": 2,
|
||||
"name": "publication",
|
||||
"help_text": "",
|
||||
"string": "{\"fre\": \"Publication\"}"
|
||||
},
|
||||
"14": {
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"class_id": 13,
|
||||
"icon": "0",
|
||||
"name": "rubrique",
|
||||
"superiors_list": {
|
||||
"parent": [
|
||||
14,
|
||||
19
|
||||
]
|
||||
},
|
||||
"fields_list": [],
|
||||
"string": "{\"fre\": \"Rubrique\"}",
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"component": "EmType",
|
||||
"rank": 1,
|
||||
"help_text": "",
|
||||
"sortcolumn": "rank"
|
||||
},
|
||||
"16": {
|
||||
"nullable": true,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "{\"fre\": \"Titre\"}",
|
||||
"class_id": 13,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 1,
|
||||
"fieldtype": "char",
|
||||
"help_text": "",
|
||||
"internal": false,
|
||||
"rel_field_id": null,
|
||||
"name": "titre"
|
||||
},
|
||||
"18": {
|
||||
"nullable": true,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": true,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "{\"fre\": \"Age\"}",
|
||||
"class_id": 2,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 3,
|
||||
"fieldtype": "char",
|
||||
"help_text": "",
|
||||
"internal": false,
|
||||
"rel_field_id": null,
|
||||
"name": "age"
|
||||
},
|
||||
"19": {
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"class_id": 13,
|
||||
"icon": "0",
|
||||
"name": "numero",
|
||||
"superiors_list": {},
|
||||
"fields_list": [],
|
||||
"string": "{\"fre\": \"Num\\u00e9ro\"}",
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"component": "EmType",
|
||||
"rank": 2,
|
||||
"help_text": "",
|
||||
"sortcolumn": "rank"
|
||||
},
|
||||
"21": {
|
||||
"nullable": true,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": true,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "{\"fre\": \"Bleu\"}",
|
||||
"class_id": 1,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 1,
|
||||
"fieldtype": "char",
|
||||
"help_text": "",
|
||||
"internal": false,
|
||||
"rel_field_id": null,
|
||||
"name": "bleu"
|
||||
},
|
||||
"23": {
|
||||
"nullable": false,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "",
|
||||
"class_id": 1,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 1,
|
||||
"fieldtype": "integer",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"rel_field_id": null,
|
||||
"name": "class_id"
|
||||
},
|
||||
"24": {
|
||||
"nullable": true,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"max_length": 128,
|
||||
"icon": "0",
|
||||
"optional": false,
|
||||
"component": "EmField",
|
||||
"string": "",
|
||||
"class_id": 1,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"name": "string",
|
||||
"rank": 2,
|
||||
"fieldtype": "char",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"rel_field_id": null,
|
||||
"uniq": false
|
||||
},
|
||||
"25": {
|
||||
"nullable": false,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "",
|
||||
"class_id": 1,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 3,
|
||||
"fieldtype": "integer",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"rel_field_id": null,
|
||||
"name": "type_id"
|
||||
},
|
||||
"26": {
|
||||
"nullable": false,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "",
|
||||
"class_id": 1,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 4,
|
||||
"fieldtype": "pk",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"rel_field_id": null,
|
||||
"name": "lodel_id"
|
||||
},
|
||||
"28": {
|
||||
"nullable": false,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "",
|
||||
"class_id": 2,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 1,
|
||||
"fieldtype": "integer",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"rel_field_id": null,
|
||||
"name": "class_id"
|
||||
},
|
||||
"29": {
|
||||
"nullable": true,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"max_length": 128,
|
||||
"icon": "0",
|
||||
"optional": false,
|
||||
"component": "EmField",
|
||||
"string": "",
|
||||
"class_id": 2,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"name": "string",
|
||||
"rank": 2,
|
||||
"fieldtype": "char",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"rel_field_id": null,
|
||||
"uniq": false
|
||||
},
|
||||
"30": {
|
||||
"nullable": false,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "",
|
||||
"class_id": 2,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 3,
|
||||
"fieldtype": "integer",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"rel_field_id": null,
|
||||
"name": "type_id"
|
||||
},
|
||||
"31": {
|
||||
"nullable": false,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "",
|
||||
"class_id": 2,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 4,
|
||||
"fieldtype": "pk",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"rel_field_id": null,
|
||||
"name": "lodel_id"
|
||||
},
|
||||
"33": {
|
||||
"nullable": false,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "",
|
||||
"class_id": 13,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 1,
|
||||
"fieldtype": "integer",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"rel_field_id": null,
|
||||
"name": "class_id"
|
||||
},
|
||||
"34": {
|
||||
"nullable": true,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"max_length": 128,
|
||||
"icon": "0",
|
||||
"optional": false,
|
||||
"component": "EmField",
|
||||
"string": "",
|
||||
"class_id": 13,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"name": "string",
|
||||
"rank": 2,
|
||||
"fieldtype": "char",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"rel_field_id": null,
|
||||
"uniq": false
|
||||
},
|
||||
"35": {
|
||||
"nullable": false,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "",
|
||||
"class_id": 13,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 3,
|
||||
"fieldtype": "integer",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"rel_field_id": null,
|
||||
"name": "type_id"
|
||||
},
|
||||
"36": {
|
||||
"nullable": false,
|
||||
"date_update": "Fri Oct 16 11:05:04 2015",
|
||||
"optional": false,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"string": "",
|
||||
"class_id": 13,
|
||||
"date_create": "Fri Oct 16 11:05:04 2015",
|
||||
"rank": 4,
|
||||
"fieldtype": "pk",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"rel_field_id": null,
|
||||
"name": "lodel_id"
|
||||
},
|
||||
"37": {
|
||||
"nullable": false,
|
||||
"date_update": "Wed Nov 4 10:52:13 2015",
|
||||
"optional": false,
|
||||
"rank": 5,
|
||||
"icon": "0",
|
||||
"name": "modification_date",
|
||||
"component": "EmField",
|
||||
"string": "",
|
||||
"class_id": 1,
|
||||
"date_create": "Wed Nov 4 10:52:13 2015",
|
||||
"now_on_create": true,
|
||||
"internal": "automatic",
|
||||
"fieldtype": "datetime",
|
||||
"now_on_update": true,
|
||||
"help_text": "",
|
||||
"rel_field_id": null,
|
||||
"uniq": false
|
||||
},
|
||||
"38": {
|
||||
"nullable": false,
|
||||
"date_update": "Wed Nov 4 10:52:13 2015",
|
||||
"rel_field_id": null,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"now_on_create": true,
|
||||
"class_id": 1,
|
||||
"date_create": "Wed Nov 4 10:52:13 2015",
|
||||
"rank": 6,
|
||||
"string": "",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"optional": false,
|
||||
"name": "creation_date",
|
||||
"fieldtype": "datetime"
|
||||
},
|
||||
"39": {
|
||||
"nullable": false,
|
||||
"date_update": "Wed Nov 4 10:52:13 2015",
|
||||
"rel_field_id": null,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"now_on_create": true,
|
||||
"class_id": 2,
|
||||
"date_create": "Wed Nov 4 10:52:13 2015",
|
||||
"rank": 5,
|
||||
"string": "",
|
||||
"now_on_update": true,
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"optional": false,
|
||||
"name": "modification_date",
|
||||
"fieldtype": "datetime"
|
||||
},
|
||||
"40": {
|
||||
"nullable": false,
|
||||
"date_update": "Wed Nov 4 10:52:13 2015",
|
||||
"rel_field_id": null,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"now_on_create": true,
|
||||
"class_id": 2,
|
||||
"date_create": "Wed Nov 4 10:52:13 2015",
|
||||
"rank": 6,
|
||||
"string": "",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"optional": false,
|
||||
"name": "creation_date",
|
||||
"fieldtype": "datetime"
|
||||
},
|
||||
"41": {
|
||||
"nullable": false,
|
||||
"date_update": "Wed Nov 4 10:52:13 2015",
|
||||
"rel_field_id": null,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"now_on_create": true,
|
||||
"class_id": 13,
|
||||
"date_create": "Wed Nov 4 10:52:13 2015",
|
||||
"rank": 5,
|
||||
"string": "",
|
||||
"now_on_update": true,
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"optional": false,
|
||||
"name": "modification_date",
|
||||
"fieldtype": "datetime"
|
||||
},
|
||||
"42": {
|
||||
"nullable": false,
|
||||
"date_update": "Wed Nov 4 10:52:13 2015",
|
||||
"rel_field_id": null,
|
||||
"icon": "0",
|
||||
"uniq": false,
|
||||
"component": "EmField",
|
||||
"now_on_create": true,
|
||||
"class_id": 13,
|
||||
"date_create": "Wed Nov 4 10:52:13 2015",
|
||||
"rank": 6,
|
||||
"string": "",
|
||||
"help_text": "",
|
||||
"internal": "automatic",
|
||||
"optional": false,
|
||||
"name": "creation_date",
|
||||
"fieldtype": "datetime"
|
||||
}
|
||||
}
|
||||
28
install/loader.py
Normal file
28
install/loader.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import settings
|
||||
import importlib
|
||||
import sys
|
||||
import os
|
||||
|
||||
sys.path.append(settings.lodel2_lib_path)
|
||||
|
||||
# Import dynamic code
|
||||
if os.path.isfile(settings.dynamic_code):
|
||||
from dynleapi import *
|
||||
|
||||
# Import wanted datasource objects
|
||||
for db_modname in ['leapidatasource', 'migrationhandler']:
|
||||
mod = importlib.import_module("DataSource.{pkg_name}.{mod_name}".format(
|
||||
pkg_name=settings.ds_package,
|
||||
mod_name=db_modname,
|
||||
)
|
||||
)
|
||||
# Expose the module in globals
|
||||
globals()[db_modname] = mod
|
||||
|
||||
if __name__ == '__main__':
|
||||
import code
|
||||
print("""
|
||||
Running interactive python in Lodel2 %s instance environment
|
||||
|
||||
"""%settings.name)
|
||||
code.interact(local=locals())
|
||||
21
install/settings.py
Normal file
21
install/settings.py
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#-*- coding:utf8 -*-
|
||||
|
||||
import pymysql
|
||||
|
||||
name = 'LODEL2_INSTANCE_NAME'
|
||||
lodel2_lib_path = 'LODEL2_LIB_ABS_PATH'
|
||||
|
||||
emfile = 'em.json'
|
||||
dynamic_code = 'dynleapi.py'
|
||||
|
||||
ds_package = 'MySQL'
|
||||
mh_classname = 'MysqlMigrationHandler'
|
||||
datasource = {
|
||||
'default': {
|
||||
'module': pymysql,
|
||||
'host': '127.0.0.1',
|
||||
'user': 'DBUSER',
|
||||
'passwd': 'DBPASSWORD',
|
||||
'db': 'DBNAME'
|
||||
}
|
||||
}
|
||||
29
install/utils.py
Executable file
29
install/utils.py
Executable file
|
|
@ -0,0 +1,29 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import settings
|
||||
from settings import *
|
||||
from loader import *
|
||||
|
||||
def refreshdyn():
|
||||
import sys
|
||||
from EditorialModel.model import Model
|
||||
from leapi.lefactory import LeFactory
|
||||
from EditorialModel.backend.json_backend import EmBackendJson
|
||||
from DataSource.MySQL.leapidatasource import LeDataSourceSQL
|
||||
OUTPUT = dynamic_code
|
||||
EMJSON = emfile
|
||||
# Load editorial model
|
||||
em = Model(EmBackendJson(EMJSON))
|
||||
# Generate dynamic code
|
||||
fact = LeFactory(OUTPUT)
|
||||
# Create the python file
|
||||
fact.create_pyfile(em, LeDataSourceSQL, {})
|
||||
|
||||
def db_init():
|
||||
from EditorialModel.backend.json_backend import EmBackendJson
|
||||
from EditorialModel.model import Model
|
||||
mh = getattr(migrationhandler,settings.mh_classname)(**(settings.datasource['default']))
|
||||
em = Model(EmBackendJson(settings.emfile))
|
||||
em.migrate_handler(mh)
|
||||
|
||||
|
||||
47
lodel_init.sh
Executable file
47
lodel_init.sh
Executable file
|
|
@ -0,0 +1,47 @@
|
|||
#!/bin/bash
|
||||
|
||||
usage() {
|
||||
echo "Usage : $0 instance_name instance_dir [lodel_libdir]" 1>&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ $# -lt 2 ]
|
||||
then
|
||||
echo "Not enough arguments" 1>&2
|
||||
usage
|
||||
fi
|
||||
|
||||
|
||||
name="$1"
|
||||
instdir="$2"
|
||||
libdir="$3"
|
||||
libdir="${libdir:=$(realpath $(dirname $0))}"
|
||||
|
||||
emfilename="em.json"
|
||||
settings="$instdir/settings.py"
|
||||
em="$instdir/em.json"
|
||||
dyncode="$instdir/${name}.py"
|
||||
|
||||
if [ -e "$instdir" ]
|
||||
then
|
||||
echo "Abording... "$instdir" exists" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Creating lodel instance directory '$instdir'"
|
||||
mkdir -pv "$instdir"
|
||||
|
||||
cp -v $libdir/install/* $instdir
|
||||
|
||||
sed -i -e "s#LODEL2_LIB_ABS_PATH#$libdir#" "$settings"
|
||||
sed -i -e "s#LODEL2_INSTANCE_NAME#$name#" "$settings"
|
||||
|
||||
echo "Generating dynamic code"
|
||||
cd "$instdir"
|
||||
make refreshdyn
|
||||
echo "Cleaning instance directory"
|
||||
make clean
|
||||
|
||||
echo -e "\nInstance successfully created in $instdir"
|
||||
echo -e "============================\n"
|
||||
echo "Now you should edit '$settings' and then run : cd $instdir && make dbinit"
|
||||
|
|
@ -1,15 +1,17 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import sys
|
||||
from EditorialModel.model import Model
|
||||
from leapi.lefactory import LeFactory
|
||||
from EditorialModel.backend.json_backend import EmBackendJson
|
||||
from leapi.datasources.ledatasourcesql import LeDataSourceSQL
|
||||
|
||||
OUTPUT = 'leapi/dyn.py'
|
||||
OUTPUT = 'leapi/dyn.py' if len(sys.argv) == 1 else sys.argv[1]
|
||||
EMJSON = 'EditorialModel/test/me.json' if len(sys.argv) < 3 else sys.argv[2]
|
||||
|
||||
em = Model(EmBackendJson('EditorialModel/test/me.json'))
|
||||
em = Model(EmBackendJson(EMJSON))
|
||||
|
||||
fact = LeFactory('leapi/dyn.py')
|
||||
fact = LeFactory(OUTPUT)
|
||||
fact.create_pyfile(em, LeDataSourceSQL, {})
|
||||
print(fact.generate_python(em, LeDataSourceSQL, {}))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue