Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds lazy loading of cs50.SQL #5

Merged
merged 5 commits into from
Feb 25, 2017
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion src/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,24 @@
import imp
import sys

from .cs50 import *
from .sql import *

class CustomImporter(object):
"""
Import cs50.SQL lazily so that rest of library can be used without SQLAlchemy installed.
https://docs.python.org/3/library/imp.html
http://xion.org.pl/2012/05/06/hacking-python-imports/
http://dangerontheranger.blogspot.com/2012/07/how-to-use-sysmetapath-with-python.html
"""
def find_module(self, fullname, path=None):
if fullname == "cs50.SQL":
return self
return None
def load_module(self, name):
if name in sys.modules:
return sys.modules[name]
from .sql import SQL
sys.modules[name] = SQL
return SQL
sys.meta_path.append(CustomImporter())
25 changes: 17 additions & 8 deletions src/sql.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,52 @@
import sqlalchemy

class SQL(object):
"""TODO"""
"""Wrap SQLAlchemy to provide a simple SQL API."""

def __init__(self, url):
"""TODO"""
"""
Create instance of sqlalchemy.engine.Engine.
URL should be a string that indicates database dialect and connection arguments.
http://docs.sqlalchemy.org/en/latest/core/engines.html#sqlalchemy.create_engine
"""
try:
self.engine = sqlalchemy.create_engine(url)
except Exception as e:
raise RuntimeError(e)

def execute(self, text, *multiparams, **params):
"""TODO"""
"""
Execute a SQL statement.
"""
try:

# bind parameters before statement reaches database, so that bound parameters appear in exceptions
# http://docs.sqlalchemy.org/en/latest/core/sqlelement.html#sqlalchemy.sql.expression.text
# https://groups.google.com/forum/#!topic/sqlalchemy/FfLwKT1yQlg
# http://docs.sqlalchemy.org/en/latest/core/connections.html#sqlalchemy.engine.Engine.execute
# http://docs.sqlalchemy.org/en/latest/faq/sqlexpressions.html#how-do-i-render-sql-expressions-as-strings-possibly-with-bound-parameters-inlined
statement = sqlalchemy.text(text).bindparams(*multiparams, **params)
result = self.engine.execute(str(statement.compile(compile_kwargs={"literal_binds": True})))

# SELECT
# if SELECT (or INSERT with RETURNING), return result set as list of dict objects
if result.returns_rows:
rows = result.fetchall()
return [dict(row) for row in rows]

# INSERT
# if INSERT, return primary key value for a newly inserted row
elif result.lastrowid is not None:
return result.lastrowid

# DELETE, UPDATE
# if DELETE or UPDATE, return number of rows matched
else:
return result.rowcount

# if constraint violated, return None
except sqlalchemy.exc.IntegrityError:
return None

# else raise error
except Exception as e:
raise RuntimeError(e)