Skip to content

(WIP) Support for Postgres as an alternative backend to sqlite #136

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ __pycache__
/docs/_build
/docs/_static
/docs/_templates


# Jupyter
*.ipynb
6 changes: 3 additions & 3 deletions ngshare/alembic/versions/aa00db20c10a_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def upgrade():
)
op.create_table(
'assignment_files_assoc_table',
sa.Column('left_id', sa.TEXT(), nullable=False),
sa.Column('left_id', sa.INTEGER(), nullable=False), # changed from TEXT
sa.Column('right_id', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['left_id'], ['assignments._id'],),
sa.ForeignKeyConstraint(['right_id'], ['files._id'],),
Expand All @@ -89,15 +89,15 @@ def upgrade():
)
op.create_table(
'feedback_files_assoc_table',
sa.Column('left_id', sa.TEXT(), nullable=False),
sa.Column('left_id', sa.INTEGER(), nullable=False), # changed from TEXT
sa.Column('right_id', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['left_id'], ['submissions._id'],),
sa.ForeignKeyConstraint(['right_id'], ['files._id'],),
sa.PrimaryKeyConstraint('left_id', 'right_id'),
)
op.create_table(
'submission_files_assoc_table',
sa.Column('left_id', sa.TEXT(), nullable=False),
sa.Column('left_id', sa.INTEGER(), nullable=False), # changed from TEXT
sa.Column('right_id', sa.INTEGER(), nullable=False),
sa.ForeignKeyConstraint(['left_id'], ['submissions._id'],),
sa.ForeignKeyConstraint(['right_id'], ['files._id'],),
Expand Down
6 changes: 3 additions & 3 deletions ngshare/database/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,23 @@
assignment_files_assoc_table = Table(
'assignment_files_assoc_table',
Base.metadata,
Column('left_id', TEXT, ForeignKey('assignments._id'), primary_key=True),
Column('left_id', INTEGER, ForeignKey('assignments._id'), primary_key=True), # changed from TEXT
Column('right_id', INTEGER, ForeignKey('files._id'), primary_key=True),
)

# Submission -> Course (One to Many)
submission_files_assoc_table = Table(
'submission_files_assoc_table',
Base.metadata,
Column('left_id', TEXT, ForeignKey('submissions._id'), primary_key=True),
Column('left_id', INTEGER, ForeignKey('submissions._id'), primary_key=True), # changed from TEXT
Column('right_id', INTEGER, ForeignKey('files._id'), primary_key=True),
)

# Submission (feedback) -> Course (One to Many)
feedback_files_assoc_table = Table(
'feedback_files_assoc_table',
Base.metadata,
Column('left_id', TEXT, ForeignKey('submissions._id'), primary_key=True),
Column('left_id', INTEGER, ForeignKey('submissions._id'), primary_key=True), # changed from TEXT
Column('right_id', INTEGER, ForeignKey('files._id'), primary_key=True),
)

Expand Down
15 changes: 8 additions & 7 deletions ngshare/database/test_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,20 @@

def clear_db(db, storage_path):
'Remove all data from database'
db.query(User).delete()
db.query(Course).delete()
db.query(Assignment).delete()
db.query(Submission).delete()
db.query(File).delete()
db.query(InstructorAssociation).delete()
db.query(StudentAssociation).delete()
for table_name in [
'assignment_files_assoc_table',
'submission_files_assoc_table',
'feedback_files_assoc_table',
]:
db.execute('DELETE FROM %s' % table_name)
db.query(InstructorAssociation).delete()
db.query(StudentAssociation).delete()
db.query(Submission).delete()
db.query(Assignment).delete()
db.query(File).delete()
db.query(Course).delete()
db.query(User).delete()

db.commit()
if storage_path is not None:
shutil.rmtree(storage_path, ignore_errors=True)
Expand Down
3 changes: 3 additions & 0 deletions ngshare/ngshare.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from jupyterhub.services.auth import HubAuthenticated
from sqlalchemy import create_engine, or_
from sqlalchemy.orm import sessionmaker
from sqlalchemy_utils import database_exists, create_database

try:
from . import dbutil
Expand Down Expand Up @@ -944,6 +945,8 @@ def __init__(
)
# Connect Database
engine = create_engine(db_url)
if not database_exists(engine.url):
create_database(engine.url)
Base.metadata.bind = engine
Base.metadata.create_all(engine)
self.db_session = sessionmaker(bind=engine)
Expand Down
43 changes: 31 additions & 12 deletions ngshare/test_ngshare.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,22 +26,38 @@
application, db_name, storage_name = None, None, None
user, hc, bu = None, None, None

BACKEND_POSTGRES = "postgresql"
BACKEND_SQLITE = "sqlite"

db_backend = BACKEND_POSTGRES
#db_backend = BACKEND_SQLITE

@pytest.fixture
def app():
'''Handle alternative backends'''
'Create Tornado application for testing'
global application, db_name, storage_name
# Create temporary location for db and storage
storage_name = tempfile.mktemp('-ngshare-test-dir')
if db_name is None:
db_name = tempfile.mktemp('.db')
storage_name = tempfile.mktemp('-ngshare-test-dir')
application = MyApplication(
'/api/',
'sqlite:///' + db_name,
storage_name,
admin=['root'],
debug=True,
)
if db_backend == BACKEND_SQLITE:
db_name = tempfile.mktemp('.db')
application = MyApplication(
'/api/',
'sqlite:///' + db_name,
storage_name,
admin=['root'],
debug=True,
)
elif db_backend == BACKEND_POSTGRES:
# db_name = tempfile.mktemp('.db')
application = MyApplication(
'/api/',
'postgresql://postgres:omg-a-password@localhost:5432/ngshare_test',
storage_name,
admin=['root'],
debug=True,
)
# Mock authentication using vngshare
MyRequestHandler.__bases__ = (MockAuth, RequestHandler, MyHelpers)
return application
Expand Down Expand Up @@ -1312,7 +1328,10 @@ def test_notimpl():


def test_clean():
'Clean temporary files'
'Clean temporary files - only relevant with an sqlite backend'
global db_name, storage_name
os.remove(db_name)
shutil.rmtree(storage_name)
if db_backend == BACKEND_SQLITE:
os.remove(db_name)
shutil.rmtree(storage_name)
elif db_backend == BACKEND_POSTGRES:
pass