import types
from oldman.resource.resource import ClientResource, StoreResource
[docs]class ModelConversionManager(object):
"""TODO: describe and find a better name."""
def __init__(self):
# { (client_model, data_store): store_model }
self._client_to_store_models = {}
# { store_model: client_model
self._store_to_client_models = {}
# { (client_model, store_model): converter}
self._converters = {}
[docs] def register_model_converter(self, client_model, store_model, data_store, model_converter):
self._client_to_store_models[(client_model, data_store)] = store_model
self._store_to_client_models[store_model] = client_model
self._converters[(client_model, store_model)] = model_converter
[docs] def convert_store_to_client_resources(self, store_resources, client_resource_manager):
"""TODO: describe """
if isinstance(store_resources, types.GeneratorType):
return (self.convert_store_to_client_resource(r)
for r in store_resources)
# Otherwise, returns a list
return [self.convert_store_to_client_resource(r, client_resource_manager)
for r in store_resources]
[docs] def convert_store_to_client_resource(self, store_resource, client_resource_manager):
client_former_types, client_new_types = self._extract_types_from_store_resource(store_resource)
client_model_manager = client_resource_manager.model_manager
# Mutable
client_resource = ClientResource(client_resource_manager, client_model_manager, store_resource.store,
id=store_resource.id, types=client_new_types, is_new=store_resource.is_new,
former_types=client_former_types)
store = store_resource.store
# Client models from the most general to the more specific
client_models = list(client_resource.models)
client_models.reverse()
for client_model in client_models:
# Corresponding store model
store_model = self._client_to_store_models.get((client_model, store))
if store_model is None:
#TODO: find a better exception
raise Exception("No store model associate to %s" % client_model.name)
converter = self._converters[(client_model, store_model)]
# Update the client resource according to the model properties
converter.from_store_to_client(store_resource, client_resource)
return client_resource
[docs] def convert_client_to_store_resource(self, client_resource):
# Same store between the client_resource and the store_resource
store = client_resource.store
store_former_types, store_new_types = self._extract_types_from_client_resource(client_resource)
#TODO: should we consider late IRI attributions?
store_resource = StoreResource(store.model_manager, store, id=client_resource.id,
types=store_new_types, is_new=client_resource.is_new,
former_types=store_former_types)
# From the most general to the more specific
store_models = list(store_resource.models)
store_models.reverse()
for store_model in store_models:
client_model = self._store_to_client_models.get(store_model)
if client_model is None:
#TODO: find a better exception
raise Exception("No client model associate to %s" % store_model.name)
converter = self._converters[(client_model, store_model)]
# Update the client resource according to the model properties
converter.from_client_to_store(client_resource, store_resource)
return store_resource
def _extract_types_from_store_resource(self, store_resource):
# Non model types
new_types = set(store_resource.non_model_types)
former_types = set(store_resource.former_non_model_types)
for store_model in store_resource.models:
client_model = self._store_to_client_models.get(store_model)
if client_model is None:
#TODO: See if relevant and find a better name
raise Exception("No client model corresponding to %s" % store_model.name)
client_model_type = client_model.class_iri
if store_model.class_iri in store_resource.former_types:
former_types.add(client_model_type)
if client_model_type is not None:
new_types.add(client_model_type)
return former_types, new_types
def _extract_types_from_client_resource(self, client_resource):
# Non model types
new_types = set(client_resource.non_model_types)
former_types = set(client_resource.former_non_model_types)
# Types corresponding to models
store = client_resource.store
for client_model in client_resource.models:
store_model = self._client_to_store_models.get((client_model, store))
if store_model is None:
#TODO: See if relevant and find a better name
raise Exception("No store model corresponding to %s" % client_model.name)
store_model_type = store_model.class_iri
if client_model.class_iri in client_resource.former_types:
former_types.add(store_model_type)
new_types.add(store_model_type)
return former_types, new_types
[docs]class ModelConverter(object):
"""TODO: find a better name and explain """
[docs] def from_client_to_store(self, client_resource, store_resource):
raise NotImplementedError("Should be implemented by a sub-class")
[docs] def from_store_to_client(self, store_resource, client_resource):
raise NotImplementedError("Should be implemented by a sub-class")
[docs]class DirectMappingModelConverter(ModelConverter):
def __init__(self, client_to_store_mappings):
"""
:param client_to_store_mappings: Attribute mapping
:return:
"""
self._client_to_store_mappings = client_to_store_mappings
self._store_to_client_mappings = {v: k for k, v in client_to_store_mappings.items()}
[docs] def from_client_to_store(self, client_resource, store_resource):
self._transfer_values(client_resource, store_resource, self._client_to_store_mappings)
[docs] def from_store_to_client(self, store_resource, client_resource):
self._transfer_values(store_resource, client_resource, self._store_to_client_mappings)
@staticmethod
def _transfer_values(source_resource, target_resource, mappings):
for source_attr_name, target_attr_name in mappings.items():
# Attributes
source_attr = source_resource.get_attribute(source_attr_name)
target_attr = target_resource.get_attribute(target_attr_name)
# Transfers a clone of the source entry
source_entry = source_attr.get_entry(source_resource)
if source_entry is not None:
target_attr.set_entry(target_resource, source_entry.clone())
[docs]class EquivalentModelConverter(DirectMappingModelConverter):
"""TODO: describe """
def __init__(self, client_model, store_model):
mappings = {attr_name: attr_name for attr_name in client_model.om_attributes}
DirectMappingModelConverter.__init__(self, mappings)
#TODO: check that the models are equivalent