Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Renamed services to repositories to better reflect their purpose
- Loading branch information
1 parent
30d3487
commit bd3115d
Showing
8 changed files
with
220 additions
and
216 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# -*- coding: utf-8 -*- | ||
from pytest import raises | ||
from tests.watson.db import support | ||
|
||
|
||
class TestBaseRepository(object): | ||
|
||
def setup(self): | ||
self.session = support.session | ||
|
||
def test_create(self): | ||
with raises(Exception): | ||
support.TestRepository() | ||
assert support.TestRepository(self.session) | ||
|
||
def test_new_obj(self): | ||
repo = support.TestRepository(self.session) | ||
obj = repo.new(value=2) | ||
assert obj.value == 2 | ||
|
||
def test_query_all(self): | ||
repo = support.TestRepository(self.session) | ||
assert len(repo.all()) == 6 | ||
|
||
def test_get(self): | ||
repo = support.TestRepository(self.session) | ||
repo.get(1).value == 1 | ||
with raises(Exception): | ||
repo.get(10, error_on_not_found=True) | ||
|
||
def test_first(self): | ||
repo = support.TestRepository(self.session) | ||
assert repo.first(id=1).value == '1' | ||
|
||
def test_save_delete(self): | ||
repo = support.TestRepository(self.session) | ||
obj = repo.new(value='test') | ||
repo.save(obj) | ||
assert repo.count() == 7 | ||
repo.delete(obj) | ||
assert repo.count() == 6 | ||
assert not repo.first(value='test') | ||
|
||
def test_save_delete_all(self): | ||
repo = support.TestRepository(self.session) | ||
obj = repo.new(value='test') | ||
obj2 = repo.new(value='test2') | ||
repo.save_all(obj, obj2) | ||
assert repo.first(value='test2') | ||
repo.delete_all(obj, obj2) | ||
assert not repo.first(value='test2') | ||
|
||
def test_update(self): | ||
with raises(NotImplementedError): | ||
support.TestRepository(self.session).update() |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
# -*- coding: utf-8 -*- | ||
__version__ = '2.0.3' | ||
__version__ = '2.1.0' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
# -*- coding: utf-8 -*- | ||
import abc | ||
from watson.db.contextmanagers import transaction_scope | ||
|
||
|
||
class Base(metaclass=abc.ABCMeta): | ||
"""Provides common interactions with the SQLAlchemy session. | ||
Example: | ||
.. code-block:: python | ||
class MyRepository(Base): | ||
__model__ = models.MyModel | ||
# sqlalchemy_session is a reference to a Session object | ||
repo = MyRepository(sqlalchemy_session) | ||
mymodel = repo.new(attr='Value') | ||
print(mymodel.attr) # 'Value' | ||
repo.save(mymodel) | ||
Attributes: | ||
session (Session): The SqlAlchemy session | ||
__model__ (mixed): The model object the server interacts with | ||
""" | ||
session = None | ||
__model__ = None | ||
|
||
def __init__(self, session): | ||
""" | ||
Args: | ||
session (Session): The SqlAlchemy session | ||
""" | ||
self.session = session | ||
|
||
@property | ||
def query(self): | ||
return self.session.query(self.__model__) | ||
|
||
def all(self): | ||
""" | ||
Returns: | ||
list: A list of all model objects | ||
""" | ||
return self.query.all() | ||
|
||
def get(self, id, error_on_not_found=False): | ||
"""Retrieve a single object based on it's ID. | ||
Args: | ||
id (int): The primary key of the record | ||
error_on_not_found (bool): Raise an exception if not found | ||
Returns: | ||
mixed: The matching model object | ||
Raises: | ||
Exception when no matching results are found. | ||
""" | ||
obj = self.query.get(id) | ||
if not obj and error_on_not_found: | ||
raise Exception('No matching result found.') | ||
return obj | ||
|
||
# Convenience methods | ||
|
||
def find(self, **kwargs): | ||
"""Shorthand for the filter_by method. | ||
Should be used when performing query specific operations (such as | ||
bulk deletion) | ||
Args: | ||
kwargs: The fields to search for | ||
""" | ||
return self.query.filter_by(**kwargs) | ||
|
||
def first(self, **kwargs): | ||
"""Return the first matching result for the query. | ||
Args: | ||
kwargs: The fields to search for | ||
Returns: | ||
mixed: The object found, or None if nothing was returned | ||
""" | ||
return self.find(**kwargs).first() | ||
|
||
def delete(self, model): | ||
"""Deletes a model from the database. | ||
Args: | ||
model (mixed): The model to delete | ||
""" | ||
with transaction_scope(self.session) as session: | ||
session.delete(model) | ||
|
||
def delete_all(self, *models): | ||
"""Delete a list of models. | ||
If deleting more than a single model of the same type, then | ||
a Repository.find(**kwargs).delete() should be called (and wrapped in a | ||
transaction_scope) instead. | ||
Args: | ||
models (list): The models to delete | ||
""" | ||
with transaction_scope(self.session) as session: | ||
for model in models: | ||
session.delete(model) | ||
|
||
def new(self, **kwargs): | ||
"""Creates a new instance of the model object | ||
Args: | ||
kwargs (mixed): The initial values for the model | ||
Returns: | ||
mixed: The newly created model | ||
""" | ||
return self.__model__(**kwargs) | ||
|
||
def save(self, model): | ||
"""Add the model to the session and save it to the database. | ||
Args: | ||
model (mixed): The object to save | ||
Returns: | ||
mixed: The saved model | ||
""" | ||
with transaction_scope(self.session) as session: | ||
session.add(model) | ||
return model | ||
|
||
def save_all(self, *models): | ||
"""Save a list of models. | ||
Args: | ||
models (list, tuple): The models to save | ||
""" | ||
with transaction_scope(self.session) as session: | ||
for model in models: | ||
session.add(model) | ||
return True | ||
|
||
def count(self): | ||
"""Returns the total number of model objects | ||
Return: | ||
int | ||
""" | ||
return self.query.count() | ||
|
||
def update(self, **kwargs): | ||
raise NotImplementedError() |
Oops, something went wrong.