Skip to content

Commit

Permalink
Merge pull request #1 from nside/1.1.0
Browse files Browse the repository at this point in the history
1.1.0
  • Loading branch information
nside authored Jul 24, 2023
2 parents 46e9409 + f195aff commit c4c2f61
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 31 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Publish Python 🐍 distributions 📦 to PyPI

on:
release:
types: [published]

jobs:
build-n-publish:
name: Build and publish Python 🐍 distributions 📦 to PyPI
runs-on: ubuntu-18.04

steps:
- uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.8

- name: Install pypa/build
run: python -m pip install build

- name: Build a binary wheel and a source tarball
run: python -m build --sdist --wheel --outdir dist/

- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}
24 changes: 24 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Run Tests

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v2

- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
python-version: 3.8

- name: Install package
run: |
python -m pip install --upgrade pip
pip install -e .
- name: Run tests
run: |
python -m unittest discover tests
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

setup(
name='sqlite2rest',
version='1.0.0',
version='1.1.0',
description='A Python library for creating a RESTful API from an SQLite database using Flask.',
author='Denis Laprise',
author_email='git@2ni.net',
Expand Down
15 changes: 14 additions & 1 deletion sqlite2rest/app.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,30 @@
import logging
import sys
from flask import Flask, g
from .database import Database
from .routes import setup_routes

def create_app(database_uri):
# Initialize Flask app
app = Flask(__name__)

setup_routes(app, database_uri)
def get_db():
if 'db' not in g:
g.db = Database(database_uri)
return g.db
tables = Database(database_uri).get_tables()
setup_routes(app, tables, get_db)

# Configure logging
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
app.logger.addHandler(logging.StreamHandler(sys.stderr))
app.logger.setLevel(logging.DEBUG)

@app.teardown_appcontext
def teardown_db(exception):
db = g.pop('db', None)

if db is not None:
db.close()

return app
12 changes: 9 additions & 3 deletions sqlite2rest/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

class Database:
def __init__(self, db_uri):
self.conn = sqlite3.connect(db_uri, check_same_thread=False)
self.conn = sqlite3.connect(db_uri)
self.cursor = self.conn.cursor()

def get_tables(self):
Expand All @@ -19,12 +19,16 @@ def get_primary_key(self, table_name):

def get_records(self, table_name):
self.cursor.execute(f"SELECT * FROM {table_name};")
return self.cursor.fetchall()
col_names = [description[0] for description in self.cursor.description]
records = [dict(zip(col_names, record)) for record in self.cursor.fetchall()]
return records

def get_record(self, table_name, key):
primary_key = self.get_primary_key(table_name)
self.cursor.execute(f"SELECT * FROM {table_name} WHERE {primary_key} = ?;", (key,))
return self.cursor.fetchone()
col_names = [description[0] for description in self.cursor.description]
record = dict(zip(col_names, self.cursor.fetchone()))
return record

def create_record(self, table_name, data):
columns = ', '.join(data.keys())
Expand All @@ -43,3 +47,5 @@ def delete_record(self, table_name, key):
self.cursor.execute(f"DELETE FROM {table_name} WHERE {primary_key} = ?;", (key,))
self.conn.commit()

def close(self):
self.conn.close()
13 changes: 5 additions & 8 deletions sqlite2rest/routes.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
from flask import jsonify, request
from .database import Database
from .openapi import get_openapi_spec

def setup_routes(app, database_uri):
tables = Database(database_uri).get_tables()

def setup_routes(app, tables, get_database):
def create_get_records_fn(table_name):
def get_records():
app.logger.info(f'Getting records for table {table_name}')
records = Database(database_uri).get_records(table_name)
records = get_database().get_records(table_name)
return jsonify(records), 200, {'Content-Type': 'application/json'}
get_records.__name__ = f'get_records_{table_name}'
return get_records
Expand All @@ -17,7 +14,7 @@ def create_create_record_fn(table_name):
def create_record():
data = request.get_json()
app.logger.info(f'Creating record in table {table_name} with data {data}')
Database(database_uri).create_record(table_name, data)
get_database().create_record(table_name, data)
return jsonify({'message': 'Record created.'}), 201, {'Content-Type': 'application/json'}
create_record.__name__ = f'create_record_{table_name}'
return create_record
Expand All @@ -26,15 +23,15 @@ def create_update_record_fn(table_name):
def update_record(id):
data = request.get_json()
app.logger.info(f'Updating record with id {id} in table {table_name} with data {data}')
Database(database_uri).update_record(table_name, id, data)
get_database().update_record(table_name, id, data)
return jsonify({'message': 'Record updated.'}), 200, {'Content-Type': 'application/json'}
update_record.__name__ = f'update_record_{table_name}'
return update_record

def create_delete_record_fn(table_name):
def delete_record(id):
app.logger.info(f'Deleting record with id {id} from table {table_name}')
Database(database_uri).delete_record(table_name, id)
get_database().delete_record(table_name, id)
return jsonify({'message': 'Record deleted.'}), 200, {'Content-Type': 'application/json'}
delete_record.__name__ = f'delete_record_{table_name}'
return delete_record
Expand Down
44 changes: 26 additions & 18 deletions tests/test_routes.py
Original file line number Diff line number Diff line change
@@ -1,53 +1,61 @@
import unittest
import json
import os
import shutil
from sqlite2rest import create_app
from sqlite2rest import Database, create_app
import unittest

class TestRoutes(unittest.TestCase):
@classmethod
def setUpClass(cls):
# Copy the database file before running the tests
shutil.copyfile('data/chinook.db', 'test_chinook.db')
# Use a database file for testing
cls.db_uri = 'test.db'
cls.db = Database(cls.db_uri)

# Create a test table
cls.db.cursor.execute('CREATE TABLE Artist (ArtistId INTEGER PRIMARY KEY, Name TEXT);')
cls.db.conn.commit()

@classmethod
def tearDownClass(cls):
# Delete the copied database file after running the tests
os.remove('test_chinook.db')
# Delete the database file after running the tests
os.remove('test.db')

def setUp(self):
# Use the copied database file for testing
self.app = create_app('test_chinook.db')
# Create the Flask app
self.app = create_app(self.db_uri)
self.client = self.app.test_client()

def test_get(self):
def test_0get(self):
response = self.client.get('/Artist')
self.assertEqual(response.status_code, 200)
artists = json.loads(response.data)
self.assertIsInstance(artists, list)
self.assertEqual(artists, [])

def test_create(self):
response = self.client.post('/Artist', json={'Name': 'Test Artist'})
response = self.client.post('/Artist', json={'ArtistId': 1, 'Name': 'Test Artist'})
self.assertEqual(response.status_code, 201)
self.assertEqual(json.loads(response.data), {'message': 'Record created.'})

# Verify the creation by reading it back
response = self.client.get('/Artist')
self.assertEqual(response.status_code, 200)
artists = json.loads(response.data)
self.assertEqual(artists, [{'ArtistId': 1, 'Name': 'Test Artist'}])

def test_update(self):
# First, create a record to update
self.client.post('/Artist', json={'Name': 'Test Artist'})
self.client.post('/Artist', json={'ArtistId': 2, 'Name': 'Test Artist'})

# Then, update the record
response = self.client.put('/Artist/1', json={'Name': 'Updated Artist'})
response = self.client.put('/Artist/2', json={'Name': 'Updated Artist'})
self.assertEqual(response.status_code, 200)
self.assertEqual(json.loads(response.data), {'message': 'Record updated.'})

def test_delete(self):
# First, create a record to delete
self.client.post('/Artist', json={'Name': 'Test Artist'})
self.client.post('/Artist', json={'ArtistId': 3, 'Name': 'Test Artist'})

# Then, delete the record
response = self.client.delete('/Artist/1')
response = self.client.delete('/Artist/3')
self.assertEqual(response.status_code, 200)
self.assertEqual(json.loads(response.data), {'message': 'Record deleted.'})

if __name__ == '__main__':
unittest.main()

0 comments on commit c4c2f61

Please sign in to comment.