From c55e185fe30009aeadade1d66abd4558c627af75 Mon Sep 17 00:00:00 2001
From: davebshow <davebshow@gmail.com>
Date: Sun, 3 Jul 2016 19:22:25 -0400
Subject: [PATCH] added readme

---
 README.md            | 104 +++++++++++++++++++++++++++++++++++++++++++
 goblin/api.py        |   4 +-
 goblin/properties.py |   4 +-
 setup.py             |   4 +-
 4 files changed, 111 insertions(+), 5 deletions(-)
 create mode 100644 README.md

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..5a1683f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,104 @@
+## Why davebshow/goblin???
+
+Let's face it, ZEROFAIL/goblin has problems. It's not really anyone's fault, it is just a fact of life. The mogwai codebase is monumental and it makes heavy use of metaprogramming, instrumentation, class inheritance, global variables and configuration, and third-party libraries. This results in opaque code that is hard to read and maintain, resulting in less community interest and more work for developers looking to make improvements. My port to TinkerPop3 just made things worse, as it introduced a level of callback hell only know to the most hardcore JavaScript developers. At this point, while ZEROFAIL/goblin basically works, implementing new functionality is a daunting task, and simple debugging and reasoning have become serious work. I was trying to think how to remedy these problems and rescue goblin from an ugly, bloated fate as we move forward adding new functionality. Then, it dawned on me: all I need to do is drag that whole folder to the virtual trash bin on my desktop and start from scratch.
+
+But, wait, a whole new OGM from scratch...? Well, yes and no. Borrowing a few concepts from SQLAlchemy and using what I've learned from working on previous Python software targeting the Gremlin Server, I was able to piece together a fully functioning system in just a few hours of work and less than 1/10 the code. So, here is my *community prototype* OGM contribution to the Python TinkerPop3 ecosystem.
+
+## Features
+
+1. *Transparent* Python 3.5 codebase using PEP 492 await/async syntax that leverages asynchronous iterators and asynchronous context managers
+2. SQLAlchemy style element creation and queries
+3. Full integration with the official GLV gremlin-python
+4. Transparent mapping between OGM and database values
+5. Support for session/transaction management
+6. Graph database vendor agnostic/configurable
+7. Fully extensible data type system
+8. Descriptor based property assignment
+9. And more...!
+
+### Install
+```
+$ pip install git+https://github.com/davebshow/goblin.git
+```
+### Create/update elements
+
+```python
+
+import asyncio
+
+from goblin.api import create_engine, Vertex, Edge
+from goblin.properties import Property, String
+
+
+class TestVertex(Vertex):
+    __label__ = 'test_vertex'
+    name = Property(String)
+    notes = Property(String, initval='N/A')
+
+
+class TestEdge(Edge):
+    __label__ = 'test_edge'
+    notes = Property(String, initval='N/A')
+
+
+loop = asyncio.get_event_loop()
+engine = loop.run_until_complete(
+    create_engine("http://localhost:8182/", loop))
+
+
+async def create():
+    session = engine.session()
+    leif = TestVertex()
+    leif.name = 'leifur'
+    jon = TestVertex()
+    jon.name = 'jonathan'
+    works_for = TestEdge()
+    works_for.source = jon
+    works_for.target = leif
+    assert works_for.notes == 'N/A'
+    works_for.notes = 'zerofail'
+    session.add(leif, jon, works_for)
+    await session.flush()
+    print(leif.name, leif.id, jon.name, jon.id,
+          works_for.notes, works_for.id)
+    leif.name = 'leif'
+    session.add(leif)
+    await session.flush()
+    print(leif.name, leif.id)
+
+
+loop.run_until_complete(create())
+# leifur 0 jonathan 3 zerofail 6
+# leif 0
+```
+
+### Query the db:
+
+```python
+async def query():
+    session = engine.session()
+    stream = await session.query(TestVertex).all()
+    async for msg in stream:
+        print(msg)
+
+
+loop.run_until_complete(query())
+# [<__main__.TestVertex object at 0x7f46d833e588>, <__main__.TestVertex object at 0x7f46d833e780>]
+
+```
+
+### See how objects map to the db:
+
+```python
+TestVertex.__mapping__
+# <Mapping(type=vertex, label=test_vertex, properties=[
+  # {'db_name': 'test_vertex__name', 'ogm_name': 'name', 'data_type': <class 'goblin.properties.String'>},
+  # {'db_name': 'test_vertex__notes', 'ogm_name': 'notes', 'data_type': <class 'goblin.properties.String'>}])
+
+```
+
+### Close the engine
+
+```python
+loop.run_until_complete(engine.close())
+```
diff --git a/goblin/api.py b/goblin/api.py
index 340442c..3b02105 100644
--- a/goblin/api.py
+++ b/goblin/api.py
@@ -44,7 +44,7 @@ async def create_engine(url, loop):
 class Engine:
     """Class used to encapsulate database connection configuration and generate
        database connections. Used as a factory to create :py:class:`Session`
-       objects."""
+       objects. More config coming soon."""
 
     def __init__(self, url, loop, *, force_close=True, **features):
         self._url = url
@@ -196,7 +196,7 @@ class Session:
         result = await stream.fetch_data()
         if result.data:
             edge = mapper.map_edge_to_ogm(result.data[0], element,
-                                              element.__mapping__)
+                                          element.__mapping__)
             return edge
 
     def _get_edge_by_id(self, eid):
diff --git a/goblin/properties.py b/goblin/properties.py
index d664b08..96d3768 100644
--- a/goblin/properties.py
+++ b/goblin/properties.py
@@ -14,7 +14,8 @@ class Property:
 
 
 class PropertyDescriptor:
-    """Descriptor that validates user property input."""
+    """Descriptor that validates user property input and gets/sets properties
+       as instance attributes."""
 
     def __init__(self, name, data_type, *, initval=None):
         self._name = '_' + name
@@ -22,7 +23,6 @@ class PropertyDescriptor:
         self._initval = initval
 
     def __get__(self, obj, objtype):
-        print(self._data_type)
         if obj is None:
             return self
         return getattr(obj, self._name, self._initval)
diff --git a/setup.py b/setup.py
index 228fe68..3001d38 100644
--- a/setup.py
+++ b/setup.py
@@ -12,7 +12,9 @@ setup(
     packages=["goblin", "goblin.gremlin_python",
               "goblin.gremlin_python_driver", "tests"],
     install_requires=[
-        "aiohttp==0.21.6"
+        "aenum==1.4.5",
+        "aiohttp==0.21.6",
+        "inflection==0.3.1"
     ],
     test_suite="tests",
     classifiers=[
-- 
GitLab