Repository: proteanhq/protean

Issue:
Move Entity LifeCycle methods from `Adapter` to `Entity`
So far, we have been registering **Models** into the Repository Factory, and retrieving them when we need to interact with the database. This mechanism works fine, but requires the repository factory to be initialized at a particular stage and passed on into the use cases. Also, the use cases are written to take cognizance of these repository objects, so the code is not as "Application Logic" as it could be.

Instead of `repo_factory.get('DogSchema').create(...)`, we would simply want `Dog.create(...)` which not only represents the business logic better but opens the code to more streamlined workflows with the database (like when to initialize connections and when to let them go, when to initialize child objects etc.)

So I suggest moving the lifecycle methods of `get,` `create,` `update,` `delete` etc. into the `Entity,` and hook onto the adapter directly from within the `Entity` code.

Discussion:

Patch:
diff --git a/src/protean/__init__.py b/src/protean/__init__.py
index c84d132c..fbc1cd24 100644
--- a/src/protean/__init__.py
+++ b/src/protean/__init__.py
@@ -1,6 +1,3 @@
 """Primary Module to define version and expose packages"""
 
 __version__ = '0.0.6'
-
-
-from .core.entity import Entity
diff --git a/src/protean/core/entity.py b/src/protean/core/entity.py
index 2172d7bf..fa65c67c 100644
--- a/src/protean/core/entity.py
+++ b/src/protean/core/entity.py
@@ -1,8 +1,14 @@
 """Entity Functionality and Classes"""
+import logging
+
 from collections import OrderedDict
 
+from typing import Any
+
 from protean.core.field import Field, Auto
-from protean.core.exceptions import ValidationError
+from protean.core.exceptions import ValidationError, ObjectNotFoundError
+
+logger = logging.getLogger('protean.core.entity')
 
 
 class EntityBase(type):
@@ -155,7 +161,7 @@ class Entity(metaclass=EntityBase):
         except ValidationError as err:
             self.errors[field_name] = err.messages
 
-    def update(self, data):
+    def update_data(self, data):
         """
         Update the entity with the given set of values
 
@@ -177,3 +183,184 @@ class Entity(metaclass=EntityBase):
         """ Return entity data as a dictionary """
         return {field_name: getattr(self, field_name, None)
                 for field_name in self.meta_.declared_fields}
+
+    @classmethod
+    def get(cls, identifier: Any) -> 'Entity':
+        """Get a specific Record from the Repository
+
+        :param identifier: id of the record to be fetched from the repository.
+        """
+        logger.debug(f'Lookup `{cls.__name__}` object with identifier {identifier}')
+        # Get the ID field for the entity
+        filters = {
+            cls.meta_.id_field.field_name: identifier
+        }
+
+        # Find this item in the repository or raise Error
+        results = cls.filter(page=1, per_page=1, **filters)
+        if not results:
+            raise ObjectNotFoundError(
+                f'`{cls.__name__}` object with identifier {identifier} '
+                f'does not exist.')
+
+        # Return the first result
+        return results.first
+
+    @classmethod
+    def _retrieve_model(cls):
+        """Retrieve model details associated with this Entity"""
+        from protean.core.repository import repo_factory  # FIXME Move to a better placement
+
+        # Fetch Model class and connected-adapter from Repository Factory
+        model_cls = repo_factory.get_model(cls.__name__)
+        adapter = getattr(repo_factory, cls.__name__)
+
+        return (model_cls, adapter)
+
+    @classmethod
+    def filter(cls, page: int = 1, per_page: int = 10, order_by: list = (),
+               excludes_: dict = None, **filters) -> 'Pagination':
+        """
+        Read Record(s) from the repository. Method must return a `Pagination`
+        object
+
+        :param page: The current page number of the records to be pulled
+        :param per_page: The size of each page of the records to be pulled
+        :param order_by: The list of parameters to be used for ordering the
+        results. Use a `-` before the parameter name to sort in descending
+        order and if not ascending order.
+        :param excludes_: Objects with these properties will be excluded
+        from the results
+
+        :return Returns a `Pagination` object that holds the filtered results
+        """
+        logger.debug(
+            f'Query `{cls.__name__}` objects with filters {filters} and '
+            f'order results by {order_by}')
+
+        # Fetch Model class and connected-adapter from Repository Factory
+        model_cls, adapter = cls._retrieve_model()
+
+        # order_by clause must be list of keys
+        order_by = model_cls.opts_.order_by if not order_by else order_by
+        if not isinstance(order_by, (list, tuple)):
+            order_by = [order_by]
+
+        # default excludes to a dictionary
+        excludes_ = excludes_ or {}
+
+        # Call the read method of the repository
+        results = adapter._filter_objects(page, per_page, order_by, excludes_, **filters)
+
+        # Convert the returned results to entity and return it
+        entity_items = []
+        for item in results.items:
+            entity_items.append(model_cls.to_entity(item))
+        results.items = entity_items
+
+        return results
+
+    @classmethod
+    def exists(cls, excludes_, **filters):
+        """ Return `True` if objects matching the provided filters and excludes
+        exist if not return false.
+
+        Call the filter query by default. Can be overridden for better and
+        quicker implementations.
+
+        :param excludes_: entities without this combination of field name and
+        values will be returned
+        """
+        results = cls.filter(page=1, per_page=1, excludes_=excludes_, **filters)
+        return bool(results)
+
+    @classmethod
+    def create(cls, *args, **kwargs) -> 'Entity':
+        """Create a new record in the repository"""
+        logger.debug(
+            f'Creating new `{cls.__name__}` object using data {kwargs}')
+
+        model_cls, adapter = cls._retrieve_model()
+
+        # Build the entity from the input arguments
+        entity = cls(*args, **kwargs)
+
+        # Do unique checks, create this object and return it
+        entity.validate_unique()
+
+        # Build the model object and create it
+        model_obj = adapter._create_object(model_cls.from_entity(entity))
+
+        # Update the auto fields of the entity
+        for field_name, field_obj in entity.meta_.declared_fields.items():
+            if isinstance(field_obj, Auto):
+                if isinstance(model_obj, dict):
+                    field_val = model_obj[field_name]
+                else:
+                    field_val = getattr(model_obj, field_name)
+                setattr(entity, field_name, field_val)
+
+        return entity
+
+    def update(self, data: dict) -> 'Entity':
+        """Update a Record in the repository
+
+        :param identifier: The id of the record to be updated
+        :param data: A dictionary of record properties to be updated
+        """
+        logger.debug(
+            f'Updating existing `{self.__class__.__name__}` object with id '
+            f'{self.id} using data {data}')
+
+        # Fetch Model class and connected-adapter from Repository Factory
+        model_cls, adapter = self.__class__._retrieve_model()
+
+        # Update entity's data attributes
+        self.update_data(data)
+
+        # Do unique checks, update the record and return the Entity
+        self.validate_unique(create=False)
+        adapter._update_object(model_cls.from_entity(self))
+
+        return self
+
+    def validate_unique(self, create=True):
+        """ Validate the unique constraints for the entity """
+        # Fetch Model class and connected-adapter from Repository Factory
+        model_cls, _ = self.__class__._retrieve_model()
+
+        # Build the filters from the unique constraints
+        filters, excludes = {}, {}
+
+        for field_name, field_obj in self.meta_.unique_fields:
+            lookup_value = getattr(self, field_name, None)
+            # Ignore empty lookup values
+            if lookup_value in Field.empty_values:
+                continue
+            # Ignore identifiers on updates
+            if not create and field_obj.identifier:
+                excludes[field_name] = lookup_value
+                continue
+            filters[field_name] = lookup_value
+
+        # Lookup the objects by the filters and raise error on results
+        for filter_key, lookup_value in filters.items():
+            if self.exists(excludes, **{filter_key: lookup_value}):
+                field_obj = self.meta_.declared_fields[filter_key]
+                field_obj.fail('unique',
+                               model_name=model_cls.opts_.model_name,
+                               field_name=filter_key)
+
+    def delete(self):
+        """Delete a Record from the Repository
+        
+        FIXME: Return True or False to indicate an object was deleted, 
+               rather than the count of records deleted
+        """
+        # Fetch Model class and connected-adapter from Repository Factory
+        _, adapter = self.__class__._retrieve_model()
+
+        filters = {
+            self.__class__.meta_.id_field.field_name: self.id
+        }
+        return adapter._delete_objects(**filters)
diff --git a/src/protean/core/field/base.py b/src/protean/core/field/base.py
index 8a670b5b..1371fb7e 100644
--- a/src/protean/core/field/base.py
+++ b/src/protean/core/field/base.py
@@ -32,7 +32,7 @@ class Field(metaclass=ABCMeta):
     # Default error messages for various kinds of errors.
     default_error_messages = {
         'invalid': 'Value is not a valid type for this field.',
-        'unique': '`{schema_name:s}` with this `{field_name:s}` already exists.',
+        'unique': '`{model_name:s}` with this `{field_name:s}` already exists.',
         'required': 'This field is required.',
         'invalid_choice': 'Value `{value!r}` is not a valid choice. '
                           'Must be one of {choices!r}',
diff --git a/src/protean/core/repository/__init__.py b/src/protean/core/repository/__init__.py
index 2c7de434..7d1db248 100644
--- a/src/protean/core/repository/__init__.py
+++ b/src/protean/core/repository/__init__.py
@@ -1,10 +1,10 @@
 """Package for defining interfaces for Repository Implementations"""
 
-from .base import BaseRepository, BaseSchema, SchemaOptions, \
+from .base import BaseAdapter, BaseModel, ModelOptions, \
     BaseConnectionHandler
-from .factory import RepositoryFactory, repo
+from .factory import RepositoryFactory, repo_factory
 from .pagination import Pagination
 
-__all__ = ('BaseRepository', 'BaseSchema', 'SchemaOptions',
-           'BaseConnectionHandler', 'RepositoryFactory', 'repo',
+__all__ = ('BaseAdapter', 'BaseModel', 'ModelOptions',
+           'BaseConnectionHandler', 'RepositoryFactory', 'repo_factory',
            'Pagination')
diff --git a/src/protean/core/repository/base.py b/src/protean/core/repository/base.py
index a4db272e..8d41fb4b 100644
--- a/src/protean/core/repository/base.py
+++ b/src/protean/core/repository/base.py
@@ -7,9 +7,8 @@ from abc import abstractmethod
 from typing import Any
 
 from protean.core.entity import Entity
-from protean.core.field import Field, Auto
-from protean.core.exceptions import ValidationError, ConfigurationError, \
-    ObjectNotFoundError
+from protean.core.field import Auto
+from protean.core.exceptions import ConfigurationError
 from protean.utils.meta import OptionsMeta
 from protean.utils import inflection
 
@@ -18,18 +17,18 @@ from .pagination import Pagination
 logger = logging.getLogger('protean.repository')
 
 
-class BaseRepository(metaclass=ABCMeta):
-    """Repository interface to interact with databases
+class BaseAdapter(metaclass=ABCMeta):
+    """Adapter interface to interact with databases
 
-    :param conn: A connection/session to the data source of the schema
-    :param schema_cls: The schema class registered with this repository
+    :param conn: A connection/session to the data source of the model
+    :param model_cls: The model class registered with this repository
     """
 
-    def __init__(self, conn, schema_cls):
+    def __init__(self, conn, model_cls):
         self.conn = conn
-        self.schema_cls = schema_cls
-        self.entity_cls = schema_cls.opts_.entity_cls
-        self.schema_name = schema_cls.opts_.schema_name
+        self.model_cls = model_cls
+        self.entity_cls = model_cls.opts_.entity_cls
+        self.model_name = model_cls.opts_.model_name
 
     @abstractmethod
     def _filter_objects(self, page: int = 1, per_page: int = 10,
@@ -40,222 +39,70 @@ class BaseRepository(metaclass=ABCMeta):
         object
         """
 
-    def get(self, identifier: Any) -> Entity:
-        """Get a specific Record from the Repository
-
-        :param identifier: id of the record to be fetched from the repository.
-
-        """
-        logger.debug(
-            f'Lookup `{self.schema_name}` object with identifier {identifier}')
-        # Get the ID field for the entity
-        filters = {
-            self.entity_cls.meta_.id_field.field_name: identifier
-        }
-
-        # Find this item in the repository or raise Error
-        results = self.filter(page=1, per_page=1, **filters)
-        if not results:
-            raise ObjectNotFoundError(
-                f'`{self.schema_name}` object with identifier {identifier} '
-                f'does not exist.')
-
-        # Return the first result
-        return results.first
-
-    def filter(self, page: int = 1, per_page: int = 10, order_by: list = (),
-               excludes_: dict = None, **filters) -> Pagination:
-        """
-        Read Record(s) from the repository. Method must return a `Pagination`
-        object
-
-        :param page: The current page number of the records to be pulled
-        :param per_page: The size of each page of the records to be pulled
-        :param order_by: The list of parameters to be used for ordering the
-        results. Use a `-` before the parameter name to sort in descending
-        order and if not ascending order.
-        :param excludes_: Objects with these properties will be excluded
-        from the results
-
-        :return Returns a `Pagination` object that holds the filtered results
-        """
-        logger.debug(
-            f'Query `{self.schema_name}` objects with filters {filters} and '
-            f'order results by {order_by}')
-
-        # order_by clause must be list of keys
-        order_by = self.schema_cls.opts_.order_by if not order_by else order_by
-        if not isinstance(order_by, (list, tuple)):
-            order_by = [order_by]
-
-        # default excludes to a dictionary
-        excludes_ = excludes_ or {}
-
-        # Call the read method of the repository
-        results = self._filter_objects(page, per_page, order_by, excludes_,
-                                       **filters)
-
-        # Convert the returned results to entity and return it
-        entity_items = []
-        for item in results.items:
-            entity_items.append(self.schema_cls.to_entity(item))
-        results.items = entity_items
-
-        return results
-
-    def exists(self, excludes_, **filters):
-        """ Return `True` if objects matching the provided filters and excludes
-        exist if not return false.
-
-        Call the filter query by default. Can be overridden for better and
-        quicker implementations.
-
-        :param excludes_: entities without this combination of field name and
-        values will be returned
-        """
-        results = self.filter(page=1, per_page=1, excludes_=excludes_, **filters)
-        return bool(results)
-
     @abstractmethod
-    def _create_object(self, schema_obj: Any):
-        """Create a new schema object from the entity"""
-
-    def create(self, *args, **kwargs) -> Entity:
-        """Create a new record in the repository"""
-        logger.debug(
-            f'Creating new `{self.schema_name}` object using data {kwargs}')
-
-        # Build the entity from the input arguments
-        entity = self.entity_cls(*args, **kwargs)
-
-        # Do unique checks, create this object and return it
-        self.validate_unique(entity)
-
-        # Build the schema object and create it
-        schema_obj = self._create_object(
-            self.schema_cls.from_entity(entity))
-
-        # Update the auto fields of the entity
-        for field_name, field_obj in entity.meta_.declared_fields.items():
-            if isinstance(field_obj, Auto):
-                if isinstance(schema_obj, dict):
-                    field_val = schema_obj[field_name]
-                else:
-                    field_val = getattr(schema_obj, field_name)
-                setattr(entity, field_name, field_val)
-
-        return entity
+    def _create_object(self, model_obj: Any):
+        """Create a new model object from the entity"""
 
     @abstractmethod
-    def _update_object(self, schema_obj: Any):
-        """Update a schema object in the repository and return it"""
-
-    def update(self, identifier: Any, data: dict) -> Entity:
-        """Update a Record in the repository
-
-        :param identifier: The id of the record to be updated
-        :param data: A dictionary of record properties to be updated
-        """
-        logger.debug(
-            f'Updating existing `{self.schema_name}` object with id '
-            f'{identifier} using data {data}')
-
-        # Get the entity and update it
-        entity = self.get(identifier)
-        entity.update(data)
-
-        # Do unique checks, update the record and return the Entity
-        self.validate_unique(entity, create=False)
-        self._update_object(
-            self.schema_cls.from_entity(entity))
-        return entity
-
-    def validate_unique(self, entity, create=True):
-        """ Validate the unique constraints for the entity """
-        # Build the filters from the unique constraints
-        filters, excludes = {}, {}
-        for field_name, field_obj in entity.meta_.unique_fields:
-            lookup_value = getattr(entity, field_name, None)
-            # Ignore empty lookup values
-            if lookup_value in Field.empty_values:
-                continue
-            # Ignore identifiers on updates
-            if not create and field_obj.identifier:
-                excludes[field_name] = lookup_value
-                continue
-            filters[field_name] = lookup_value
-
-        # Lookup the objects by the filters and raise error on results
-        for filter_key, lookup_value in filters.items():
-            if self.exists(excludes, **{filter_key: lookup_value}):
-                field_obj = entity.meta_.declared_fields[filter_key]
-                field_obj.fail('unique',
-                               schema_name=self.schema_name,
-                               field_name=filter_key)
+    def _update_object(self, model_obj: Any):
+        """Update a model object in the repository and return it"""
 
     @abstractmethod
     def _delete_objects(self, **filters):
         """Delete a Record from the Repository"""
 
-    def delete(self, identifier: Any):
-        """Delete a Record from the Repository"""
-        filters = {
-            self.entity_cls.meta_.id_field.field_name: identifier
-        }
-        return self._delete_objects(**filters)
-
 
-class SchemaOptions(object):
-    """class Meta options for the :class:`RepositorySchema`."""
+class ModelOptions(object):
+    """class Meta options for the :class:`BaseModel`."""
 
-    def __init__(self, meta, schema_cls):
+    def __init__(self, meta, model_cls):
         self.entity_cls = getattr(meta, 'entity', None)
         if not self.entity_cls or not issubclass(self.entity_cls, Entity):
             raise ConfigurationError(
                 '`entity` option must be set and be a subclass of `Entity`.')
 
-        # Get the schema name to be used, if not provided default it
-        self.schema_name = getattr(meta, 'schema_name', None)
-        if not self.schema_name:
-            self.schema_name = inflection.underscore(schema_cls.__name__)
+        # Get the model name to be used, if not provided default it
+        self.model_name = getattr(meta, 'model_name', None)
+        if not self.model_name:
+            self.model_name = inflection.underscore(model_cls.__name__)
 
-        # Get the database bound to this schema
+        # Get the database bound to this model
         self.bind = getattr(meta, 'bind', 'default')
 
         # Default ordering of the filter response
         self.order_by = getattr(meta, 'order_by', ())
 
 
-class BaseSchema(metaclass=OptionsMeta):
-    """ Repository Schema defines an index/table in the repository"""
-    options_cls = SchemaOptions
+class BaseModel(metaclass=OptionsMeta):
+    """Model that defines an index/table in the repository"""
+    options_cls = ModelOptions
     opts_ = None
 
     class Meta(object):
-        """Options object for a Schema.
+        """Options object for a Model.
         Example usage: ::
             class Meta:
                 entity = Dog
         Available options:
-        - ``base``: Indicates that this is a base schema so ignore the meta
-        - ``entity``: the entity associated with this schema.
-        - ``schema_name``: name of this schema that will be used as table/index
+        - ``base``: Indicates that this is a base model so ignore the meta
+        - ``entity``: the entity associated with this model.
+        - ``model_name``: name of this model that will be used as table/index
         names, defaults to underscore version of the class name.
         - ``bind``: the name of the repository connection associated with this
-        schema, default value is `default`.
+        model, default value is `default`.
         - ``order_by``: default ordering of objects returned by filter queries.
         """
         base = True
 
     @classmethod
     def from_entity(cls, entity):
-        """Initialize Repository Schema object from Entity object"""
-        raise NotImplemented()
+        """Initialize Repository Model object from Entity object"""
+        raise NotImplementedError()
 
     @classmethod
     def to_entity(cls, *args, **kwargs):
-        """Convert Repository Schema Object to Entity Object"""
-        raise NotImplemented()
+        """Convert Repository Model Object to Entity Object"""
+        raise NotImplementedError()
 
 
 class BaseConnectionHandler(metaclass=ABCMeta):
diff --git a/src/protean/core/repository/factory.py b/src/protean/core/repository/factory.py
index 8542f5a9..b5ff1ef5 100644
--- a/src/protean/core/repository/factory.py
+++ b/src/protean/core/repository/factory.py
@@ -7,17 +7,23 @@ from threading import local
 from protean.core.exceptions import ConfigurationError
 from protean.conf import active_config
 
-from .base import BaseSchema, BaseRepository
+from .base import BaseModel, BaseAdapter
 
 logger = logging.getLogger('protean.repository')
 
 
 class RepositoryFactory:
-    """Repository Factory interface to retrieve resource repositories"""
+    """Repository Factory interface to retrieve Resource Objects from Repositories
+
+    FIXME RepositoryFactory should prepare adapter objects JIT, so that connections
+        are kept open only for the necessary duration. Once the request is handled, it should
+        be let go.
+    """
 
     def __init__(self):
         """"Initialize repository factory"""
         self._registry = {}
+        self._model_registry = {}
         self._connections = local()
         self._repositories = None
 
@@ -47,54 +53,63 @@ class RepositoryFactory:
             self._connections.connections = {}
             return self._connections.connections
 
-    def register(self, schema_cls, repo_cls=None):
-        """ Register the given schema with the factory
-        :param schema_cls: class of the schema to be registered
+    def register(self, model_cls, repo_cls=None):
+        """ Register the given model with the factory
+        :param model_cls: class of the model to be registered
         :param repo_cls: Optional repository class to use if not the
         `Repository` defined by the provider is userd
         """
-        if not issubclass(schema_cls, BaseSchema):
+        if not issubclass(model_cls, BaseModel):
             raise AssertionError(
-                f'Schema {schema_cls} must be subclass of `BaseSchema`')
+                f'Model {model_cls} must be subclass of `BaseModel`')
 
-        if repo_cls and not issubclass(repo_cls, BaseRepository):
+        if repo_cls and not issubclass(repo_cls, BaseAdapter):
             raise AssertionError(
-                f'Repository {repo_cls} must be subclass of `BaseRepository`')
+                f'Repository {repo_cls} must be subclass of `BaseAdapter`')
 
-        # Register the schema if it does not exist
-        schema_name = schema_cls.__name__
-        if not self._registry.get(schema_name):
-            # Lookup the connection details for the schema
+        # Register the model if it does not exist
+        model_name = model_cls.__name__
+        entity_name = model_cls.Meta.entity.__name__
+        if not self._registry.get(entity_name):
+            # Lookup the connection details for the model
             try:
-                conn_info = self.repositories[schema_cls.opts_.bind]
+                conn_info = self.repositories[model_cls.opts_.bind]
             except KeyError:
                 raise ConfigurationError(
-                    f"'{schema_cls.opts_.bind}' repository not found in "
+                    f"'{model_cls.opts_.bind}' repository not found in "
                     f"'REPOSITORIES'")
 
             # Load the repository provider
             provider = importlib.import_module(conn_info['PROVIDER'])
 
             # If no connection exists then build it
-            if schema_cls.opts_.bind not in self.connections:
+            if model_cls.opts_.bind not in self.connections:
                 conn_handler = provider.ConnectionHandler(
-                    schema_cls.opts_.bind, conn_info)
-                self._connections.connections[schema_cls.opts_.bind] = \
+                    model_cls.opts_.bind, conn_info)
+                self._connections.connections[model_cls.opts_.bind] = \
                     conn_handler.get_connection()
 
-            # Finally register the schema against the provider repository
-            repo_cls = repo_cls or provider.Repository
-            self._registry[schema_name] = \
-                repo_cls(self.connections[schema_cls.opts_.bind], schema_cls)
+            # Finally register the model against the provider repository
+            repo_cls = repo_cls or provider.Adapter
+            self._registry[entity_name] = \
+                repo_cls(self.connections[model_cls.opts_.bind], model_cls)
+            self._model_registry[entity_name] = model_cls
             logger.debug(
-                f'Registered schema {schema_name} with repository provider '
+                f'Registered model {model_name} for entity {entity_name} with repository provider '
                 f'{conn_info["PROVIDER"]}.')
 
-    def __getattr__(self, schema):
+    def get_model(self, entity_name):
+        """Retrieve Model class connected to Entity"""
+        try:
+            return self._model_registry[entity_name]
+        except KeyError:
+            raise AssertionError('No Model registered for {entity_name}')
+
+    def __getattr__(self, entity_name):
         try:
-            return self._registry[schema]
+            return self._registry[entity_name]
         except KeyError:
-            raise AssertionError('Unregistered Schema')
+            raise AssertionError('No Model registered for {entity_name}')
 
     def close_connections(self):
         """ Close all connections registered with the repository """
@@ -105,4 +120,4 @@ class RepositoryFactory:
             conn_handler.close_connection(conn_obj)
 
 
-repo = RepositoryFactory()
+repo_factory = RepositoryFactory()
diff --git a/src/protean/core/tasklet.py b/src/protean/core/tasklet.py
index 38c08eea..a40fa1be 100644
--- a/src/protean/core/tasklet.py
+++ b/src/protean/core/tasklet.py
@@ -7,14 +7,12 @@ class Tasklet:
     """Utility class to execute UseCases"""
 
     @classmethod
-    def perform(cls, repo_factory, schema_cls, usecase_cls, request_object_cls,
+    def perform(cls, entity_cls, usecase_cls, request_object_cls,
                 payload: dict, raise_error=False):
         """
         This method bundles all essential artifacts and initiates usecase
         execution.
-        :param repo_factory: The repository factory class for fetching the
-        repository
-        :param schema_cls: The schema class to be used for running the usecase
+        :param entity_cls: The entity class to be used for running the usecase
         :param usecase_cls: The usecase class that will be executed by
         the tasklet.
         :param request_object_cls: The request object to be used as input to the
@@ -26,13 +24,9 @@ class Tasklet:
         :type raise_error: bool
         """
 
-        # Get the Repository for the Current Schema
-        repo = getattr(repo_factory, schema_cls.__name__)
-
         # Initialize the use case and request objects
-        use_case = usecase_cls(repo)
-        request_object = request_object_cls.\
-            from_dict(schema_cls.opts_.entity_cls, payload)
+        use_case = usecase_cls()
+        request_object = request_object_cls.from_dict(entity_cls, payload)
 
         # Run the use case and return the response
         resp = use_case.execute(request_object)
diff --git a/src/protean/core/usecase/base.py b/src/protean/core/usecase/base.py
index 977eabc2..eb307377 100644
--- a/src/protean/core/usecase/base.py
+++ b/src/protean/core/usecase/base.py
@@ -5,7 +5,6 @@ import logging
 from abc import ABCMeta
 from abc import abstractmethod
 
-from protean.core.repository import BaseRepository
 from protean.core.exceptions import ObjectNotFoundError, ValidationError
 from protean.core.transport import ResponseFailure
 
@@ -15,13 +14,6 @@ logger = logging.getLogger('protean.usecase')
 class UseCase(metaclass=ABCMeta):
     """This is the base class for all UseCases"""
 
-    def __init__(self, repo: BaseRepository):
-        """Initialize UseCase with repository factory object
-
-        :param repo: The repository associated with the use case
-        """
-        self.repo = repo
-
     def execute(self, request_object):
         """Generic executor method of all UseCases"""
 
diff --git a/src/protean/core/usecase/generic.py b/src/protean/core/usecase/generic.py
index d883655b..e596683f 100644
--- a/src/protean/core/usecase/generic.py
+++ b/src/protean/core/usecase/generic.py
@@ -46,7 +46,7 @@ class ShowUseCase(UseCase):
         identifier = request_object.identifier
 
         # Look for the object by its ID and return it
-        resource = self.repo.get(identifier)
+        resource = request_object.entity_cls.get(identifier)
         return ResponseSuccess(Status.SUCCESS, resource)
 
 
@@ -98,10 +98,10 @@ class ListUseCase(UseCase):
 
     def process_request(self, request_object):
         """Return a list of resources"""
-        resources = self.repo.filter(request_object.page,
-                                     request_object.per_page,
-                                     request_object.order_by,
-                                     **request_object.filters)
+        resources = request_object.entity_cls.filter(request_object.page,
+                                                     request_object.per_page,
+                                                     request_object.order_by,
+                                                     **request_object.filters)
         return ResponseSuccess(Status.SUCCESS, resources)
 
 
@@ -129,7 +129,7 @@ class CreateUseCase(UseCase):
     def process_request(self, request_object):
         """Process Create Resource Request"""
 
-        resource = self.repo.create(**request_object.data)
+        resource = request_object.entity_cls.create(**request_object.data)
         return ResponseSuccessCreated(resource)
 
 
@@ -169,10 +169,11 @@ class UpdateUseCase(UseCase):
     def process_request(self, request_object):
         """Process Update Resource Request"""
 
-        identifier = request_object.identifier
-
+        # Retrieve the object by its identifier
+        entity = request_object.entity_cls.get(request_object.identifier)
+    
         # Update the object and return the updated data
-        resource = self.repo.update(identifier, request_object.data)
+        resource = entity.update(data=request_object.data)
         return ResponseSuccess(Status.SUCCESS, resource)
 
 
@@ -209,8 +210,10 @@ class DeleteUseCase(UseCase):
         """Process the Delete Resource Request"""
 
         # Delete the object by its identifier
-        identifier = request_object.identifier
-        self.repo.delete(identifier)
+        entity = request_object.entity_cls.get(request_object.identifier)
+        entity.delete()
+
+        # FIXME Check for return value of `delete()`
 
         # We have successfully deleted the object.
         # Sending a 204 Response code.
diff --git a/src/protean/impl/repository/dict_repo.py b/src/protean/impl/repository/dict_repo.py
index e3985ffb..65fd8150 100644
--- a/src/protean/impl/repository/dict_repo.py
+++ b/src/protean/impl/repository/dict_repo.py
@@ -8,8 +8,9 @@ from threading import Lock
 from operator import itemgetter
 
 from protean.core.field import Auto
-from protean.core.repository import BaseRepository, BaseSchema, \
+from protean.core.repository import BaseAdapter, BaseModel, \
     Pagination, BaseConnectionHandler
+from protean.core.exceptions import ObjectNotFoundError
 
 
 # Global in-memory store of dict data. Keyed by name, to provide
@@ -18,34 +19,35 @@ _databases = {}
 _locks = {}
 
 
-class Repository(BaseRepository):
+class Adapter(BaseAdapter):
     """ A repository for storing data in a dictionary """
 
-    def _set_auto_fields(self, schema_obj):
+    def _set_auto_fields(self, model_obj):
         """ Set the values of the auto field using counter"""
         for field_name, field_obj in \
                 self.entity_cls.meta_.declared_fields.items():
-            counter_key = f'{self.schema_name}_{field_name}'
-            if isinstance(field_obj, Auto) and \
-                    not getattr(schema_obj, field_name, None):
-
+            counter_key = f'{self.model_name}_{field_name}'
+            if isinstance(field_obj, Auto) and not (field_name in model_obj
+                                                    and model_obj[field_name] is not None):
                 # Increment the counter and it should start from 1
                 counter = next(self.conn['counters'][counter_key])
                 if not counter:
                     counter = next(self.conn['counters'][counter_key])
-                schema_obj[field_name] = counter
-        return schema_obj
 
-    def _create_object(self, schema_obj):
+                model_obj[field_name] = counter
+        return model_obj
+
+    def _create_object(self, model_obj):
         """ Write a record to the dict repository"""
         # Update the value of the counters
-        schema_obj = self._set_auto_fields(schema_obj)
+        model_obj = self._set_auto_fields(model_obj)
 
         # Add the entity to the repository
-        identifier = schema_obj[self.entity_cls.meta_.id_field.field_name]
+        identifier = model_obj[self.entity_cls.meta_.id_field.field_name]
         with self.conn['lock']:
-            self.conn['data'][self.schema_name][identifier] = schema_obj
-        return schema_obj
+            self.conn['data'][self.model_name][identifier] = model_obj
+
+        return model_obj
 
     def _filter_objects(self, page: int = 1, per_page: int = 10,
                         order_by: list = (), _excludes=None, **filters):
@@ -54,7 +56,7 @@ class Repository(BaseRepository):
         # Filter the dictionary objects based on the filters
         items = []
         excludes = _excludes if _excludes else {}
-        for item in self.conn['data'][self.schema_name].values():
+        for item in self.conn['data'][self.model_name].values():
             match = True
 
             # Add objects that match the given filters
@@ -91,19 +93,25 @@ class Repository(BaseRepository):
             items=items[cur_offset: cur_limit])
         return result
 
-    def _update_object(self, schema_obj):
+    def _update_object(self, model_obj):
         """ Update the entity record in the dictionary """
-        identifier = schema_obj[self.entity_cls.meta_.id_field.field_name]
+        identifier = model_obj[self.entity_cls.meta_.id_field.field_name]
         with self.conn['lock']:
-            self.conn['data'][self.schema_name][identifier] = schema_obj
-        return schema_obj
+            # Check if object is present
+            if not identifier in self.conn['data'][self.model_name]:
+                raise ObjectNotFoundError(
+                    f'`{self.__class__.__name__}` object with identifier {identifier} '
+                    f'does not exist.')
+
+            self.conn['data'][self.model_name][identifier] = model_obj
+        return model_obj
 
     def _delete_objects(self, **filters):
         """ Delete the dictionary object by its id"""
 
         # Delete the object from the dictionary and return the deletion count
         delete_ids = []
-        for identifier, item in self.conn['data'][self.schema_name].items():
+        for identifier, item in self.conn['data'][self.model_name].items():
             match = True
 
             # Add objects that match the given filters
@@ -115,18 +123,19 @@ class Repository(BaseRepository):
 
         # Delete all the matching identifiers
         for identifier in delete_ids:
-            del self.conn['data'][self.schema_name][identifier]
+            del self.conn['data'][self.model_name][identifier]
 
         return len(delete_ids)
 
     def delete_all(self):
         """ Delete all objects in this schema """
         with self.conn['lock']:
-            del self.conn['data'][self.schema_name]
+            if self.model_name in self.conn['data']:
+                del self.conn['data'][self.model_name]
 
 
-class DictSchema(BaseSchema):
-    """ A schema for the dictionary repository"""
+class DictModel(BaseModel):
+    """ A model for the dictionary repository"""
 
     @classmethod
     def from_entity(cls, entity):


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index ae6a5d41..ed57e421 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,4 +1,19 @@
 """Module to setup Factories and other required artifacts for tests"""
 import os
+import pytest
 
 os.environ['PROTEAN_CONFIG'] = 'tests.support.sample_config'
+
+
+@pytest.fixture(autouse=True)
+def run_around_tests():
+    """Initialize DogModel with Dict Repo"""
+    from protean.core.repository import repo_factory
+    from tests.support.dog import DogModel
+
+    repo_factory.register(DogModel)
+
+    # A test function will be run at this point
+    yield
+
+    repo_factory.Dog.delete_all()
diff --git a/tests/core/test_cache.py b/tests/core/test_cache.py
index 99245613..e9068d56 100644
--- a/tests/core/test_cache.py
+++ b/tests/core/test_cache.py
@@ -2,16 +2,14 @@
 import time
 
 from protean.core.cache import cache
-from protean.core.repository import repo
+from protean.core.repository import repo_factory
+
+from tests.support.dog import Dog
 
 
 class TestCache:
     """This class holds tests for Cache class"""
 
-    @classmethod
-    def teardown_class(cls):
-        repo.DogSchema.delete_all()
-
     def test_init(self):
         """Test successful access to the Cache Wrapper"""
         assert cache.provider is not None
@@ -19,7 +17,7 @@ class TestCache:
     def test_add(self):
         """ Test adding and retrieving an entry to the cache """
         # Add an entity to the cache
-        dog = repo.DogSchema.create(id=1, name='Johnny', owner='John')
+        dog = Dog.create(id=1, name='Johnny', owner='John')
         cache.provider.add(f'dog:{dog.id}', dog.to_dict())
 
         # Retrieve the entity
@@ -28,23 +26,27 @@ class TestCache:
 
     def test_set(self):
         """ Test setting an existing key and expiry of keys """
+        dog = Dog.create(id=1, name='Johnny', owner='John')
+
         # Set an entity to the cache
-        dog = repo.DogSchema.get(1)
-        cache.provider.set(f'dog:{dog.id}', dog.to_dict(), expiry=5)
+        dog = Dog.get(1)
+        cache.provider.set(f'dog:{dog.id}', dog.to_dict(), expiry=1)
 
         # Retrieve the entity
         dog_d = cache.provider.get(f'dog:{dog.id}')
         assert dog_d == {'age': 5, 'id': 1, 'name': 'Johnny', 'owner': 'John'}
 
         # Sleep and wait for expiry
-        time.sleep(5)
+        time.sleep(2)
         dog_d = cache.provider.get(f'dog:{dog.id}')
         assert dog_d is None
 
     def test_touch(self):
         """ Test updating the expiry of key using touch """
+        dog = Dog.create(id=1, name='Johnny', owner='John')
+
         # Set an entity to the cache
-        dog = repo.DogSchema.get(1)
+        dog = Dog.get(1)
         cache.provider.set(f'dog:{dog.id}', dog.to_dict(), expiry=1)
 
         # Retrieve the entity
@@ -53,14 +55,16 @@ class TestCache:
 
         # Touch and retrieve the entity again
         cache.provider.touch(f'dog:{dog.id}', expiry=10)
-        time.sleep(2)
+        time.sleep(1)
         dog_d = cache.provider.get(f'dog:{dog.id}')
         assert dog_d is not None
 
     def test_delete(self):
         """ Test deleting a key from the cache """
+        dog = Dog.create(id=1, name='Johnny', owner='John')
+
         # Set an entity to the cache
-        dog = repo.DogSchema.get(1)
+        dog = Dog.get(1)
         cache.provider.set(f'dog:{dog.id}', dog.to_dict())
 
         # Retrieve the entity
@@ -95,4 +99,3 @@ class TestCache:
         cache.provider.delete_many(['k1', 'k2', 'k3'])
         values = cache.provider.get_many(['k1', 'k2', 'k3'])
         assert values == {}
-
diff --git a/tests/core/test_entity.py b/tests/core/test_entity.py
index 9135b1eb..7f28c2d3 100644
--- a/tests/core/test_entity.py
+++ b/tests/core/test_entity.py
@@ -2,19 +2,13 @@
 
 import pytest
 
+from tests.support.dog import Dog
+
 from protean.core.entity import Entity
-from protean.core.exceptions import ValidationError
+from protean.core.exceptions import ValidationError, ObjectNotFoundError
 from protean.core import field
 
 
-class Dog(Entity):
-    """This is a dummy Dog Entity class"""
-    id = field.Integer(identifier=True)
-    name = field.String(required=True, max_length=50, min_length=5)
-    age = field.Integer(default=5)
-    owner = field.String(required=True, max_length=15)
-
-
 class TestEntity:
     """This class holds tests for Base Entity Abstract class"""
 
@@ -68,14 +62,14 @@ class TestEntity:
 
         # Test single error message
         try:
-            Dog(id=1, name='John Doe')
+            Dog(id=1, name='John Doe', owner='Jimmy')
         except ValidationError as err:
             assert err.normalized_messages == {
                 'owner': [Dog.owner.error_messages['required']]}
 
         # Test multiple error messages
         try:
-            Dog(id=1, name='Joh')
+            Dog(id=1, name='Joh', owner='Jimmy')
         except ValidationError as err:
             assert err.normalized_messages == {
                 'name': ['Ensure value has at least 5 characters.'],
@@ -119,3 +113,104 @@ class TestEntity:
         assert dog is not None
         assert dog.to_dict() == {
             'age': 10, 'id': 1, 'name': 'John Doe', 'owner': 'Jimmy'}
+
+    def test_create_error(self):
+        """ Add an entity to the repository missing a required attribute"""
+        with pytest.raises(ValidationError):
+            Dog.create(owner='John')
+
+    def test_create(self):
+        """ Add an entity to the repository"""
+        dog = Dog.create(id=11344234, name='Johnny', owner='John')
+        assert dog is not None
+        assert dog.id == 11344234
+        assert dog.name == 'Johnny'
+        assert dog.age == 5
+        assert dog.owner == 'John'
+
+        dog = Dog.get(11344234)
+        assert dog is not None
+
+    def test_update_with_invalid_id(self):
+        """Try to update a non-existing entry"""
+
+        dog = Dog.create(id=11344234, name='Johnny', owner='John')
+        dog.delete()
+        with pytest.raises(ObjectNotFoundError):
+            dog.update(data=dict(age=10))
+
+    def test_update(self):
+        """ Update an existing entity in the repository"""
+        dog = Dog.create(id=2, name='Johnny', owner='Carey', age=2)
+
+        dog.update(data=dict(age=10))
+        u_dog = Dog.get(2)
+        assert u_dog is not None
+        assert u_dog.age == 10
+
+    def test_that_update_runs_validations(self):
+        """Try updating with invalid values"""
+        dog = Dog.create(id=1, name='Johnny', owner='Carey', age=2)
+
+        with pytest.raises(ValidationError):
+            dog.update(data=dict(age='x'))
+
+    def test_unique(self):
+        """ Test the unique constraints for the entity """
+        Dog.create(id=2, name='Johnny', owner='Carey')
+
+        with pytest.raises(ValidationError) as err:
+            Dog.create(
+                id=2, name='Johnny', owner='Carey')
+        assert err.value.normalized_messages == {
+            'name': ['`dogs` with this `name` already exists.']}
+
+    def test_filter(self):
+        """ Query the repository using filters """
+        # Add multiple entries to the DB
+        Dog.create(id=2, name='Murdock', age=7, owner='John')
+        Dog.create(id=3, name='Jean', age=3, owner='John')
+        Dog.create(id=4, name='Bart', age=6, owner='Carrie')
+
+        # Filter by the Owner
+        dogs = Dog.filter(owner='John')
+        assert dogs is not None
+        assert dogs.total == 2
+        assert len(dogs.items) == 2
+
+        # Order the results by age
+        dogs = Dog.filter(owner='John', order_by=['-age'])
+        assert dogs is not None
+        assert dogs.first.age == 7
+        assert dogs.first.name == 'Murdock'
+
+    def test_pagination(self):
+        """ Test the pagination of the filter results"""
+        for counter in range(1, 5):
+            Dog.create(id=counter, name=counter, owner='Owner Name')
+
+        dogs = Dog.filter(per_page=2, order_by=['id'])
+        assert dogs is not None
+        assert dogs.total == 4
+        assert len(dogs.items) == 2
+        assert dogs.first.id == 1
+        assert dogs.has_next
+        assert not dogs.has_prev
+
+        dogs = Dog.filter(page=2, per_page=2, order_by=['id'])
+        assert len(dogs.items) == 2
+        assert dogs.first.id == 3
+        assert not dogs.has_next
+        assert dogs.has_prev
+
+    def test_delete(self):
+        """ Delete an object in the reposoitory by ID"""
+        dog = Dog.create(id=3, name='Johnny', owner='Carey')
+        del_count = dog.delete()
+        assert del_count == 1
+
+        del_count = dog.delete()
+        assert del_count == 0
+
+        with pytest.raises(ObjectNotFoundError):
+            Dog.get(3)
diff --git a/tests/core/test_repository.py b/tests/core/test_repository.py
index e80cd099..aef8d0d5 100644
--- a/tests/core/test_repository.py
+++ b/tests/core/test_repository.py
@@ -2,83 +2,62 @@
 
 import pytest
 
-from protean.core.entity import Entity
-from protean.core.repository import repo
+from protean.impl.repository.dict_repo import _databases
+from protean.core.repository import repo_factory
 from protean.core.exceptions import ValidationError, ObjectNotFoundError
-from protean.core import field
-from protean.impl.repository.dict_repo import DictSchema, _databases
 
-
-class Dog(Entity):
-    """This is a dummy Dog Entity class"""
-    id = field.Integer(identifier=True)
-    name = field.String(required=True, unique=True, max_length=50)
-    age = field.Integer(default=5)
-    owner = field.String(required=True, max_length=15)
-
-
-class DogSchema(DictSchema):
-    """ Schema for the Dog Entity"""
-
-    class Meta:
-        """ Meta class for schema options"""
-        entity = Dog
-        schema_name = 'dogs'
-
-
-repo.register(DogSchema)
+from tests.support.dog import Dog
 
 
 class TestRepository:
     """This class holds tests for Repository class"""
 
-    @classmethod
-    def teardown_class(cls):
-        repo.DogSchema.delete_all()
-
     def test_init(self):
         """Test successful access to the Dog repository"""
 
-        repo.DogSchema.filter()
-        current_db = dict(repo.DogSchema.conn)
+        Dog.filter()
+        current_db = dict(repo_factory.Dog.conn)
         assert current_db['data'] == {'dogs': {}}
 
-    def test_create(self):
-        """ Add an entity to the repository"""
+    def test_create_error(self):
+        """ Add an entity to the repository missing a required attribute"""
         with pytest.raises(ValidationError):
-            repo.DogSchema.create(name='Johnny', owner='John')
+            Dog.create(owner='John')
 
-        dog = repo.DogSchema.create(id=1, name='Johnny', owner='John')
+    def test_create(self):
+        """ Add an entity to the repository"""
+        dog = Dog.create(id=11344234, name='Johnny', owner='John')
         assert dog is not None
-        assert dog.id == 1
+        assert dog.id == 11344234
         assert dog.name == 'Johnny'
         assert dog.age == 5
         assert dog.owner == 'John'
 
-        dog = repo.DogSchema.get(1)
+        dog = Dog.get(11344234)
         assert dog is not None
 
     def test_update(self):
         """ Update an existing entity in the repository"""
+        dog = Dog.create(id=2, name='Johnny', owner='Carey', age=2)
 
-        # Using an invalid id should fail
-        with pytest.raises(ObjectNotFoundError):
-            repo.DogSchema.update(identifier=2, data=dict(age=10))
-
-        # Updates should run the validations
-        with pytest.raises(ValidationError):
-            repo.DogSchema.update(identifier=1, data=dict(age='x'))
-
-        repo.DogSchema.update(identifier=1, data=dict(age=10))
-        u_dog = repo.DogSchema.get(1)
+        dog.update(data=dict(age=10))
+        u_dog = Dog.get(2)
         assert u_dog is not None
         assert u_dog.age == 10
 
+    def test_that_update_runs_validations(self):
+        """Try updating with invalid values"""
+        dog = Dog.create(id=1, name='Johnny', owner='Carey', age=2)
+
+        with pytest.raises(ValidationError):
+            dog.update(data=dict(age='x'))
+
     def test_unique(self):
         """ Test the unique constraints for the entity """
+        Dog.create(id=2, name='Johnny', owner='Carey')
 
         with pytest.raises(ValidationError) as err:
-            repo.DogSchema.create(
+            Dog.create(
                 id=2, name='Johnny', owner='Carey')
         assert err.value.normalized_messages == {
             'name': ['`dogs` with this `name` already exists.']}
@@ -86,25 +65,28 @@ class TestRepository:
     def test_filter(self):
         """ Query the repository using filters """
         # Add multiple entries to the DB
-        repo.DogSchema.create(id=2, name='Murdock', age=7, owner='John')
-        repo.DogSchema.create(id=3, name='Jean', age=3, owner='John')
-        repo.DogSchema.create(id=4, name='Bart', age=6, owner='Carrie')
+        Dog.create(id=2, name='Murdock', age=7, owner='John')
+        Dog.create(id=3, name='Jean', age=3, owner='John')
+        Dog.create(id=4, name='Bart', age=6, owner='Carrie')
 
         # Filter by the Owner
-        dogs = repo.DogSchema.filter(owner='John')
+        dogs = Dog.filter(owner='John')
         assert dogs is not None
-        assert dogs.total == 3
-        assert len(dogs.items) == 3
+        assert dogs.total == 2
+        assert len(dogs.items) == 2
 
         # Order the results by age
-        dogs = repo.DogSchema.filter(owner='John', order_by=['-age'])
+        dogs = Dog.filter(owner='John', order_by=['-age'])
         assert dogs is not None
-        assert dogs.first.age == 10
-        assert dogs.first.name == 'Johnny'
+        assert dogs.first.age == 7
+        assert dogs.first.name == 'Murdock'
 
     def test_pagination(self):
         """ Test the pagination of the filter results"""
-        dogs = repo.DogSchema.filter(per_page=2, order_by=['id'])
+        for counter in range(1, 5):
+            Dog.create(id=counter, name=counter, owner='Owner Name')
+
+        dogs = Dog.filter(per_page=2, order_by=['id'])
         assert dogs is not None
         assert dogs.total == 4
         assert len(dogs.items) == 2
@@ -112,7 +94,7 @@ class TestRepository:
         assert dogs.has_next
         assert not dogs.has_prev
 
-        dogs = repo.DogSchema.filter(page=2, per_page=2, order_by=['id'])
+        dogs = Dog.filter(page=2, per_page=2, order_by=['id'])
         assert len(dogs.items) == 2
         assert dogs.first.id == 3
         assert not dogs.has_next
@@ -120,16 +102,17 @@ class TestRepository:
 
     def test_delete(self):
         """ Delete an object in the reposoitory by ID"""
-        del_count = repo.DogSchema.delete(1)
+        dog = Dog.create(id=3, name='Johnny', owner='Carey')
+        del_count = dog.delete()
         assert del_count == 1
 
-        del_count = repo.DogSchema.delete(1)
+        del_count = dog.delete()
         assert del_count == 0
 
         with pytest.raises(ObjectNotFoundError):
-            repo.DogSchema.get(1)
+            Dog.get(3)
 
     def test_close_connections(self):
         """ Test closing all connections to the repository"""
         assert 'default' in _databases
-        repo.close_connections()
+        repo_factory.close_connections()
diff --git a/tests/core/test_tasklet.py b/tests/core/test_tasklet.py
index d34ec31b..05ef227b 100644
--- a/tests/core/test_tasklet.py
+++ b/tests/core/test_tasklet.py
@@ -3,28 +3,22 @@ import pytest
 
 from protean.core.tasklet import Tasklet
 from protean.core.usecase import ShowRequestObject, ShowUseCase
-from protean.core.repository import repo
 from protean.core.exceptions import UsecaseExecutionError
 from protean.core.transport import Status
 
-from .test_repository import DogSchema
+from tests.support.dog import Dog
 
 
 class TestTasklet:
     """Tests for Tasklet Utility Methods"""
 
-    @classmethod
-    def teardown_class(cls):
-        repo.DogSchema.delete_all()
-
     def test_perform(self):
         """Test call to Tasklet's perform method"""
-        repo.DogSchema.create(id=1, name='Murdock', owner='John')
+        Dog.create(id=1, name='Murdock', owner='John')
 
         # Perform a Show Usecase using Tasklet
         payload = {'identifier': 1}
-        response = Tasklet.perform(
-            repo, DogSchema, ShowUseCase, ShowRequestObject, payload)
+        response = Tasklet.perform(Dog, ShowUseCase, ShowRequestObject, payload)
 
         # Validate the response received
         assert response is not None
@@ -35,9 +29,7 @@ class TestTasklet:
     def test_raise_error(self):
         """ Test raise error function of the Tasklet """
         with pytest.raises(UsecaseExecutionError) as exc_info:
-            Tasklet.perform(
-                repo, DogSchema, ShowUseCase, ShowRequestObject, {},
-                raise_error=True)
+            Tasklet.perform(Dog, ShowUseCase, ShowRequestObject, {}, raise_error=True)
         assert exc_info.value.value[0] == Status.UNPROCESSABLE_ENTITY
         assert exc_info.value.value[1] ==  \
                {'code': 422, 'message': {'identifier': 'is required'}}
diff --git a/tests/core/test_usecase.py b/tests/core/test_usecase.py
index dceb1650..bce8d434 100644
--- a/tests/core/test_usecase.py
+++ b/tests/core/test_usecase.py
@@ -2,34 +2,12 @@
 
 import pytest
 
-from protean.core.entity import Entity
-from protean.core import field
 from protean.core.usecase import (
     UseCase, ShowUseCase, ShowRequestObject, ListRequestObject, ListUseCase,
     CreateRequestObject, CreateUseCase, UpdateRequestObject, UpdateUseCase,
     DeleteRequestObject, DeleteUseCase)
-from protean.core.repository import repo
-from protean.impl.repository.dict_repo import DictSchema
 
-
-class Dog(Entity):
-    """This is a dummy Dog Entity class"""
-    name = field.String(required=True, max_length=50, unique=True)
-    age = field.Integer(default=5)
-    owner = field.String(required=True, max_length=15)
-
-
-class DogAutoSchema(DictSchema):
-    """ Schema for the Dog Entity"""
-
-    class Meta:
-        """ Meta class for schema options"""
-        entity = Dog
-        schema_name = 'dogs-auto'
-
-
-repo.register(DogAutoSchema)
-dog_repo = repo.DogAutoSchema
+from tests.support.dog import Dog
 
 
 class TestUseCase:
@@ -38,7 +16,7 @@ class TestUseCase:
     def test_init(self):
         """Test Initialization of the generic UseCase class"""
         with pytest.raises(TypeError):
-            UseCase(dog_repo)
+            UseCase()
 
 
 class TestShowRequestObject:
@@ -119,11 +97,11 @@ class TestShowUseCase:
         """Test Show UseCase's `process_request` method"""
 
         # Add an object to the repository
-        dog_repo.create(name='Johnny', owner='John')
+        Dog.create(id=1, name='Johnny', owner='John')
 
         # Build the request object and run the usecase
         request_obj = ShowRequestObject.from_dict(Dog, {'identifier': 1})
-        use_case = ShowUseCase(dog_repo)
+        use_case = ShowUseCase()
         response = use_case.execute(request_obj)
         assert response is not None
         assert response.success
@@ -136,7 +114,7 @@ class TestShowUseCase:
 
         # Build the request object and run the usecase
         request_obj = ShowRequestObject.from_dict(Dog, {})
-        use_case = ShowUseCase(dog_repo)
+        use_case = ShowUseCase()
         response = use_case.execute(request_obj)
         assert response is not None
         assert not response.success
@@ -146,7 +124,7 @@ class TestShowUseCase:
 
         # Build the request object and run the usecase
         request_obj = ShowRequestObject.from_dict(Dog, {'identifier': 12})
-        use_case = ShowUseCase(dog_repo)
+        use_case = ShowUseCase()
         response = use_case.execute(request_obj)
         assert response is not None
         assert not response.success
@@ -158,29 +136,23 @@ class TestListUseCase:
     @classmethod
     def setup_class(cls):
         """ Setup instructions for this case """
-        dog_repo.create(name='Murdock', owner='John', age=7)
-        dog_repo.create(name='Jean', owner='John', age=3)
-        dog_repo.create(name='Bart', owner='Carrie', age=6)
-
-    @classmethod
-    def teardown_class(cls):
-        """ Teardown instructions for this case """
-        dog_repo.delete_all()
+        Dog.create(name='Murdock', owner='John', age=7)
+        Dog.create(name='Jean', owner='John', age=3)
+        Dog.create(name='Bart', owner='Carrie', age=6)
 
     def test_process_request(self):
         """Test List UseCase's `process_request` method"""
         # Build the request object and run the usecase
         request_obj = ListRequestObject.from_dict(
             Dog, dict(order_by=['age'], owner='John'))
-        use_case = ListUseCase(dog_repo)
+        use_case = ListUseCase()
         response = use_case.execute(request_obj)
 
         # Validate the response received
         assert response is not None
         assert response.success
         assert response.value.page == 1
-        assert response.value.total == 3
-        assert response.value.first.id == 3
+        assert response.value.total == 2
         assert response.value.first.age == 3
 
 
@@ -193,21 +165,25 @@ class TestCreateUseCase:
         # Fix and rerun the usecase
         request_data = dict(name='Barry', age=10, owner='Jimmy')
         request_obj = CreateRequestObject.from_dict(Dog, request_data)
-        use_case = CreateUseCase(dog_repo)
+        use_case = CreateUseCase()
         response = use_case.execute(request_obj)
 
         assert response is not None
         assert response.success
-        assert response.value.id == 5
         assert response.value.name == 'Barry'
 
     def test_unique_validation(self):
         """Test unique validation for create usecase"""
 
+        request_data = dict(name='Drew', age=10, owner='Jimmy')
+        request_obj = CreateRequestObject.from_dict(Dog, request_data)
+        use_case = CreateUseCase()
+        response = use_case.execute(request_obj)
+
         # Build the request object and run the usecase
-        request_data = dict(id=5, name='Jerry', age=10, owner='Jimmy')
+        request_data = dict(id=response.value.id, name='Jerry', age=10, owner='Jimmy')
         request_obj = CreateRequestObject.from_dict(Dog, request_data)
-        use_case = CreateUseCase(dog_repo)
+        use_case = CreateUseCase()
         response = use_case.execute(request_obj)
 
         # Validate the response received
@@ -215,38 +191,39 @@ class TestCreateUseCase:
         assert not response.success
         assert response.value == {
             'code': 422,
-            'message': {'id': ['`dogs-auto` with this `id` already exists.']}}
+            'message': {'id': ['`dogs` with this `id` already exists.']}}
 
 
 class TestUpdateUseCase:
     """Tests for the generic UpdateUseCase Class"""
 
-    @classmethod
-    def setup_class(cls):
+    @pytest.fixture(scope="function")
+    def dog_to_update(self):
         """ Setup instructions for this case """
-        cls.dog = dog_repo.create(name='Johnny', owner='John')
+        dog = Dog.create(id=1, name='Johnny', owner='John')
+        yield dog
 
-    def test_process_request(self):
+    def test_process_request(self, dog_to_update):
         """Test Update UseCase's `process_request` method"""
 
         # Build the request object and run the usecase
         request_obj = UpdateRequestObject.from_dict(
-            Dog, {'identifier': self.dog.id, 'data': {'age': 13}})
-        use_case = UpdateUseCase(dog_repo)
+            Dog, {'identifier': dog_to_update.id, 'data': {'age': 13}})
+        use_case = UpdateUseCase()
         response = use_case.execute(request_obj)
 
         # Validate the response received
         assert response is not None
         assert response.success
-        assert response.value.id == self.dog.id
+        assert response.value.id == dog_to_update.id
         assert response.value.age == 13
 
-    def test_validation_errors(self):
+    def test_validation_errors(self, dog_to_update):
         """Test Update Usecase for validation errors"""
         # Build the request object and run the usecase
         request_obj = UpdateRequestObject.from_dict(
-            Dog, {'identifier': self.dog.id, 'data': {'age': 'x'}})
-        use_case = UpdateUseCase(dog_repo)
+            Dog, {'identifier': dog_to_update.id, 'data': {'age': 'x'}})
+        use_case = UpdateUseCase()
         response = use_case.execute(request_obj)
 
         # Validate the response received
@@ -255,12 +232,15 @@ class TestUpdateUseCase:
         assert response.value == {
             'code': 422, 'message': {'age': ['"x" value must be an integer.']}}
 
-    def test_unique_validation(self):
+    def test_unique_validation(self, dog_to_update):
         """Test Update Usecase for unique validation"""
+        # Create a dog with the same name
+        Dog.create(id=2, name='Barry', owner='John')
+
         # Build the request object and run the usecase
         request_obj = UpdateRequestObject.from_dict(
-            Dog, {'identifier': self.dog.id, 'data': {'name': 'Barry'}})
-        use_case = UpdateUseCase(dog_repo)
+            Dog, {'identifier': dog_to_update.id, 'data': {'name': 'Barry'}})
+        use_case = UpdateUseCase()
         response = use_case.execute(request_obj)
 
         # Validate the response received
@@ -269,7 +249,7 @@ class TestUpdateUseCase:
         assert response.value == {
             'code': 422,
             'message': {
-                'name': ['`dogs-auto` with this `name` already exists.']}}
+                'name': ['`dogs` with this `name` already exists.']}}
 
 
 class TestDeleteUseCase:
@@ -278,7 +258,7 @@ class TestDeleteUseCase:
     @classmethod
     def setup_class(cls):
         """ Setup instructions for this case """
-        cls.dog = dog_repo.create(name='Jimmy', owner='John')
+        cls.dog = Dog.create(name='Jimmy', owner='John')
 
     def test_process_request(self):
         """Test Delete UseCase's `process_request` method"""
@@ -286,7 +266,7 @@ class TestDeleteUseCase:
         # Build the request object and run the usecase
         request_obj = DeleteRequestObject.from_dict(
             Dog, {'identifier': self.dog.id})
-        use_case = DeleteUseCase(dog_repo)
+        use_case = DeleteUseCase()
         response = use_case.execute(request_obj)
 
         # Validate the response received
@@ -297,7 +277,7 @@ class TestDeleteUseCase:
         # Try to lookup the object again
         request_obj = ShowRequestObject.from_dict(
             Dog, {'identifier': self.dog.id})
-        use_case = ShowUseCase(dog_repo)
+        use_case = ShowUseCase()
         response = use_case.execute(request_obj)
         assert response is not None
         assert not response.success
diff --git a/tests/support/dog.py b/tests/support/dog.py
new file mode 100644
index 00000000..ed02a5ed
--- /dev/null
+++ b/tests/support/dog.py
@@ -0,0 +1,21 @@
+"""Support Classes for Test Cases"""
+
+from protean.core.entity import Entity
+from protean.core import field
+from protean.impl.repository.dict_repo import DictModel
+
+
+class Dog(Entity):
+    """This is a dummy Dog Entity class"""
+    name = field.String(required=True, unique=True, max_length=50)
+    age = field.Integer(default=5)
+    owner = field.String(required=True, max_length=15)
+
+
+class DogModel(DictModel):
+    """ Model for the Dog Entity"""
+
+    class Meta:
+        """ Meta class for model options"""
+        entity = Dog
+        model_name = 'dogs'
diff --git a/tests/test_context.py b/tests/test_context.py
index f11bbc74..dec44706 100644
--- a/tests/test_context.py
+++ b/tests/test_context.py
@@ -4,12 +4,12 @@ import threading
 import time
 
 from protean.core.usecase import CreateUseCase, CreateRequestObject
-from protean.core.repository import repo
+from protean.core.repository import repo_factory
 from protean.core.entity import Entity
 from protean.core.tasklet import Tasklet
 from protean.context import context
 from protean.core import field
-from protean.impl.repository.dict_repo import DictSchema
+from protean.impl.repository.dict_repo import DictModel
 
 
 class CreateUseCase2(CreateUseCase):
@@ -28,16 +28,16 @@ class ThreadedDog(Entity):
     created_by = field.String(required=True, max_length=15)
 
 
-class ThreadedDogSchema(DictSchema):
-    """ Schema for the ThreadedDog Entity"""
+class ThreadedDogModel(DictModel):
+    """ Model for the ThreadedDog Entity"""
 
     class Meta:
         """ Meta class for schema options"""
         entity = ThreadedDog
-        schema_name = 'threaded_dogs'
+        model_name = 'threaded_dogs'
 
 
-repo.register(ThreadedDogSchema)
+repo_factory.register(ThreadedDogModel)
 
 
 def test_context_with_threads():
@@ -50,9 +50,8 @@ def test_context_with_threads():
         # Sleep for some determinate time to allow other threads to
         # move forward
         time.sleep(sleep)
-        Tasklet.perform(
-            repo, ThreadedDogSchema, CreateUseCase2, CreateRequestObject,
-            {'name': name})
+
+        Tasklet.perform(ThreadedDog, CreateUseCase2, CreateRequestObject, {'name': name})
 
     # Run 5 threads and create multiple objects
     threads = [
@@ -76,7 +75,7 @@ def test_context_with_threads():
         t.join()
 
     # Get the list of dogs and validate the results
-    dogs = repo.ThreadedDogSchema.filter(per_page=-1)
+    dogs = ThreadedDog.filter(per_page=10)
     assert dogs.total == 5
     for dog in dogs.items:
         if dog.name == 'Johnny':
@@ -91,4 +90,4 @@ def test_context_with_threads():
             assert dog.created_by == 'thread_5'
 
     # Cleanup the database
-    repo.ThreadedDogSchema.delete_all()
+    repo_factory.ThreadedDog.delete_all()