mirror of
https://github.com/yweber/lodel2.git
synced 2025-11-22 05:36:54 +01:00
Merge branch 'newlodel' of git.labocleo.org:lodel2 into newlodel
This commit is contained in:
commit
462d09d876
5 changed files with 131 additions and 12 deletions
|
|
@ -1,3 +1 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
|
||||
from .utils.starter import init_lodel
|
||||
|
|
|
|||
46
lodel/datasource/generic/migrationhandler.py
Normal file
46
lodel/datasource/generic/migrationhandler.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
## @package lodel.datasource.migrationhandler.generic
|
||||
# @brief A generic migration handler
|
||||
#
|
||||
# According to it, every moditification is possible
|
||||
#
|
||||
|
||||
|
||||
## Manage model changes
|
||||
class GenericMigrationHandler(object):
|
||||
|
||||
def __init__(self, debug=False):
|
||||
self.debug = debug
|
||||
|
||||
## @brief Records a change in the EditorialModel and indicates whether or not it is possible to make it
|
||||
# @note The states (initial_state and new_state) contains only fields that changes
|
||||
def register_change(self, em, uid, initial_state, new_state):
|
||||
if self.debug:
|
||||
print("\n##############")
|
||||
print("GenericMigrationHandler debug. Changes for component with uid %s :" % uid)
|
||||
if initial_state is None:
|
||||
print("Component creation (uid = %s): \n\t" % uid, new_state)
|
||||
elif new_state is None:
|
||||
print("Component deletion (uid = %s): \n\t" % uid, initial_state)
|
||||
else:
|
||||
field_list = set(initial_state.keys()).union(set(new_state.keys()))
|
||||
for field_name in field_list:
|
||||
str_chg = "\t%s " % field_name
|
||||
if field_name in initial_state:
|
||||
str_chg += "'" + str(initial_state[field_name]) + "'"
|
||||
else:
|
||||
str_chg += " creating "
|
||||
str_chg += " => "
|
||||
if field_name in new_state:
|
||||
str_chg += "'" + str(new_state[field_name]) + "'"
|
||||
else:
|
||||
str_chg += " deletion "
|
||||
print(str_chg)
|
||||
|
||||
print("##############\n")
|
||||
|
||||
## @brief Not usefull for the moment
|
||||
def register_model_state(self, em, state_hash):
|
||||
if self.debug:
|
||||
print("New EditorialModel state registered : '%s'" % state_hash)
|
||||
|
|
@ -1,4 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import bson
|
||||
from bson.son import SON
|
||||
from collections import OrderedDict
|
||||
import pymongo
|
||||
from pymongo import MongoClient
|
||||
from pymongo.errors import BulkWriteError
|
||||
|
|
@ -64,12 +68,11 @@ class MongoDbDataSource(GenericDataSource):
|
|||
# @param filters list : List of filters
|
||||
# @param rel_filters list : List of relational filters
|
||||
# @param order list : List of column to order. ex: order = [('title', 'ASC'),]
|
||||
# @param group list : List of tupple representing the column to group together. ex: group = [('title', 'ASC'),]
|
||||
# @param group list : List of tupple representing the column used as "group by" fields. ex: group = [('title', 'ASC'),]
|
||||
# @param limit int : Number of records to be returned
|
||||
# @param offset int: used with limit to choose the start record
|
||||
# @param instanciate bool : If true, the records are returned as instances, else they are returned as dict
|
||||
# @return list
|
||||
# @todo Implement the grouping
|
||||
# @todo Implement the relations
|
||||
def select(self, target_cls, field_list, filters, rel_filters=None, order=None, group=None, limit=None, offset=0,
|
||||
instanciate=True):
|
||||
|
|
@ -79,13 +82,41 @@ class MongoDbDataSource(GenericDataSource):
|
|||
query_result_ordering = utils.parse_query_order(order) if order is not None else None
|
||||
results_field_list = None if len(field_list) == 0 else field_list
|
||||
limit = limit if limit is not None else 0
|
||||
cursor = collection.find(
|
||||
filter=query_filters,
|
||||
projection=results_field_list,
|
||||
skip=offset,
|
||||
limit=limit,
|
||||
sort=query_result_ordering
|
||||
)
|
||||
|
||||
if group is None:
|
||||
cursor = collection.find(
|
||||
filter=query_filters,
|
||||
projection=results_field_list,
|
||||
skip=offset,
|
||||
limit=limit,
|
||||
sort=query_result_ordering
|
||||
)
|
||||
else:
|
||||
pipeline = list()
|
||||
unwinding_list = list()
|
||||
grouping_dict = OrderedDict()
|
||||
sorting_list = list()
|
||||
for group_param in group:
|
||||
field_name = group_param[0]
|
||||
field_sort_option = group_param[1]
|
||||
sort_option = utils.MONGODB_SORT_OPERATORS_MAP[field_sort_option]
|
||||
unwinding_list.append({'$unwind': '$%s' % field_name})
|
||||
grouping_dict[field_name] = '$%s' % field_name
|
||||
sorting_list.append((field_name, sort_option))
|
||||
|
||||
sorting_list.extends(query_result_ordering)
|
||||
|
||||
pipeline.append({'$match': query_filters})
|
||||
if results_field_list is not None:
|
||||
pipeline.append({'$project': SON([{field_name: 1} for field_name in field_list])})
|
||||
pipeline.extend(unwinding_list)
|
||||
pipeline.append({'$group': grouping_dict})
|
||||
pipeline.extend({'$sort': SON(sorting_list)})
|
||||
if offset > 0:
|
||||
pipeline.append({'$skip': offset})
|
||||
if limit is not None:
|
||||
pipeline.append({'$limit': limit})
|
||||
|
||||
results = list()
|
||||
for document in cursor:
|
||||
results.append(document)
|
||||
|
|
|
|||
|
|
@ -1 +1,41 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from lodel.datasource.generic.migrationhandler import GenericMigrationHandler
|
||||
from lodel.datasource.mongodb.datasource import MongoDbDataSource
|
||||
from lodel.editorial_model.components import EmClass, EmField
|
||||
class MigrationHandlerChangeError(Exception):
|
||||
pass
|
||||
|
||||
## @brief Modifies a MongoDb database given editorial model changes
|
||||
class MongoDbMigrationHandler(GenericMigrationHandler):
|
||||
|
||||
## @brief constructs a MongoDbMigrationHandler
|
||||
# @param conn_args dict : a dictionary containing connection options
|
||||
# @param **kwargs : extra arguments given to the connection methods
|
||||
def __init__(self, conn_args=None, **kwargs):
|
||||
if conn_args is None:
|
||||
conn_args = {} # TODO : récupérer les options de connexion dans les settings
|
||||
self.connection_name = conn_args['name']
|
||||
# del conn_args['module']
|
||||
|
||||
self.db_conn = MongoDbDataSource(self.connection_name)
|
||||
# TODO Réimplémenter la partie sur les settings
|
||||
mh_settings = {}
|
||||
self.dryrun = kwargs['dryrun'] if 'dryrun' in kwargs else mh_settings['dryrun']
|
||||
self.foreign_keys = kwargs['foreign_keys'] if 'foreign_keys' in kwargs else mh_settings['foreign_keys']
|
||||
self.drop_if_exists = kwargs['drop_if_exists'] if 'drop_if_exists' in kwargs else mh_settings['drop_if_exists']
|
||||
self._create_default_collections(self.drop_if_exists)
|
||||
|
||||
## @brief Modify the database given an EM change
|
||||
#
|
||||
# @param em model : The EditorialModel.model object to provide the global context.
|
||||
# @param uid str : The uid of the changed component.
|
||||
# @param initial_state dict|None : dict with field name as key and field value as value. Represents the original state. None means it's a creation of a new component.
|
||||
# @param new_state dict|None : dict with field name as key and field value as value. Represents the new state. None means it's a component deletion.
|
||||
# @throw MigrationHandlerChangeError if the change was refused
|
||||
def register_change(self, em, uid, initial_state, new_state):
|
||||
pass
|
||||
|
||||
|
||||
def _create_default_collections(self, drop_if_exist=False):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ LODEL_SORT_OPERATORS_MAP = {
|
|||
'DESC': pymongo.DESCENDING
|
||||
}
|
||||
|
||||
MONGODB_SORT_OPERATORS_MAP = {
|
||||
'ASC': 1,
|
||||
'DESC': -1
|
||||
}
|
||||
|
||||
## @brief Returns a collection name given a Emclass name
|
||||
# @param class_name str : The class name
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue