From d111e3f1eb265ee9e00ab4bb83340de92e505c25 Mon Sep 17 00:00:00 2001 From: Matthew Strickland Date: Sun, 6 Mar 2016 21:44:21 -0800 Subject: [PATCH] added tests for basic functionality --- docs/conf.py | 6 ++++ docs/modules.rst | 7 +++++ docs/rcquerybuilder.rst | 30 +++++++++++++++++++ rcquerybuilder/builder.py | 62 +++++++++++++++++++++++++++++++++++++++ tests/test_builder.py | 44 +++++++++++++++++++++++++++ 5 files changed, 149 insertions(+) create mode 100644 docs/modules.rst create mode 100644 docs/rcquerybuilder.rst diff --git a/docs/conf.py b/docs/conf.py index f7f397c..34bced1 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -31,6 +31,7 @@ extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', + 'sphinx.ext.napoleon' ] # Add any paths that contain templates here, relative to this directory. @@ -290,3 +291,8 @@ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False + +# -- Options for Napoleon extension --------------------------------------- +napoleon_google_docstring = True +napoleon_include_private_with_doc = True +napoleon_include_special_with_doc = True diff --git a/docs/modules.rst b/docs/modules.rst new file mode 100644 index 0000000..b1f0c98 --- /dev/null +++ b/docs/modules.rst @@ -0,0 +1,7 @@ +rcquerybuilder +============== + +.. toctree:: + :maxdepth: 4 + + rcquerybuilder diff --git a/docs/rcquerybuilder.rst b/docs/rcquerybuilder.rst new file mode 100644 index 0000000..8843089 --- /dev/null +++ b/docs/rcquerybuilder.rst @@ -0,0 +1,30 @@ +rcquerybuilder package +====================== + +Submodules +---------- + +rcquerybuilder.builder module +----------------------------- + +.. automodule:: rcquerybuilder.builder + :members: + :undoc-members: + :show-inheritance: + +rcquerybuilder.pipeline module +------------------------------ + +.. automodule:: rcquerybuilder.pipeline + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: rcquerybuilder + :members: + :undoc-members: + :show-inheritance: diff --git a/rcquerybuilder/builder.py b/rcquerybuilder/builder.py index 6b1358f..f6772cf 100644 --- a/rcquerybuilder/builder.py +++ b/rcquerybuilder/builder.py @@ -1,3 +1,65 @@ +"""redCrown MongoDB QueryBuilder + +This module contains the builder and query classes for usage with ``pymongo``. + +Example: + + Basic Usage (select/find queries):: + + import pymongo + + mongo = pymongo.MongoClient() + db = mongo['db_foobar'] + + qb = Builder(collection=db['collection_foobar']) + qb.field('name').is_not_in(['Matthew', 'Boris']) \\ + .field('age').gte(21) \\ + .field('attributes').is_type('object') + + # The query object forwards it's query to the collection + # on on the ``execute()`` call. + query = qb.get_query() + + # cursor is a ``pymongo.cursor.Cursor`` instance. + cursor = qb.get_query().execute() + + # Which is equivalent to: + collection.find({'name': {'$nin': ['Matthew', 'Boris']}, + 'age': {'$gte': 21}, + 'attributes': {'$type': 3}}) + + Update Queries:: + + qb.update(multi=True) \\ + .field('foo').equals('bar').set('buzz') \\ + .field('totals').gt(10) \\ + .field('counter').inc(1) \\ + .field('some_list').push({'name': 'testing', 'value': 'cool'}) + + update_result = qb.get_query().execute() + + # Which is equivalent to: + collection.update_many( + {'foo': 'bar', 'totals': {'$gt': 10}}, + { + '$set': {'foo': 'buzz'}, + '$inc': {'counter': 1}, + '$push': {'some_list': {'name': 'testing', 'value': 'cool'}} + } + ) + +""" + + +def expr(): + """Get a new ``Expr`` instance. + + Returns: + Expr: The ``Expr`` instance. + """ + return Expr() + + class Builder(object): def __init__(self, collection): self.collection = collection diff --git a/tests/test_builder.py b/tests/test_builder.py index 905f91f..f043a4a 100644 --- a/tests/test_builder.py +++ b/tests/test_builder.py @@ -15,6 +15,50 @@ def test_basic_fluent_api(self): assert query_list == {'name': 'foobar', 'fizz': {'$ne': None}} + def test_find_query(self): + qb = Builder(collection=None) + qb.field('name').is_not_in(['Matthew', 'Boris']) \ + .field('age').gte(21) \ + .field('attributes').is_type('object') + + query_list = qb.get_query_list() + + assert {'name': {'$nin': ['Matthew', 'Boris']}, + 'age': {'$gte': 21}, + 'attributes': {'$type': 3}} == query_list + + def test_update_query(self): + qb = Builder(collection=None) + + qb.update(multi=True) \ + .field('foo').equals('bar').set('buzz') \ + .field('totals').gt(10) \ + .field('counter').inc(1) \ + .field('some_list').push({'name': 'testing', 'value': 'cool'}) + + query_parts = qb.get_query().query + + assert {'foo': 'bar', + 'totals': {'$gt': 10}} == query_parts['query'] + + assert {'$set': {'foo': 'buzz'}, + '$inc': {'counter': 1}, + '$push': {'some_list': {'name': 'testing', 'value': 'cool'}}} == query_parts['newObj'] + + def test_insert_query(self): + qb = Builder(collection=None) + + qb.insert() \ + .field('name').set('awesome') \ + .field('age').set(21) \ + .field('attributes').set([0, 1, 2, 3]) + + insert_query = qb.get_query().query['newObj'] + + assert {'name': 'awesome', + 'age': 21, + 'attributes': [0, 1, 2, 3]} == insert_query + if __name__ == '__main__': unittest.main()