ORMs can be hard to debug and don't perfectly insulate programs from changes to schema
"""Get data from database."""importosimportsqlite3importutilENV_VAR="DATA"classModelException(Exception):"""Problems with queries."""def__init__(self,msg):self._msg=msgdef__str__(self):returnself._msgdefconnect():"""Connect to database."""path=os.getenv(ENV_VAR)ifnotpath:raiseModelException(f"Environment variable {ENV_VAR} not set")connection=sqlite3.connect(path,detect_types=sqlite3.PARSE_DECLTYPES)connection.row_factory=util.dict_factoryreturnconnectiondefall_staff():"""Get all staff."""query=""" select * from staff """try:connection=connect()cursor=connection.execute(query)returncursor.fetchall()exceptsqlite3.DatabaseErrorasexc:raiseModelException(str(exc))defcolumn(name):"""Get a single column of staff."""query=f""" select {name} from staff """try:connection=connect()cursor=connection.execute(query)return[r[name]forrincursor.fetchall()]exceptsqlite3.DatabaseErrorasexc:raiseModelException(str(exc))defrow(staff_id):"""Get a single row of staff."""query=""" select * from staff where staff_id=? """try:connection=connect()cursor=connection.execute(query,(staff_id,))result=cursor.fetchall()iflen(result)==0:raiseModelException(f"no rows match {staff_id}")eliflen(result)>1:raiseModelException(f"multiple rows match {staff_id}")returnresult[0]exceptsqlite3.DatabaseErrorasexc:raiseModelException(str(exc))
Re-create connection each time model is accessed
Creating it once and attaching to the Flask app fails because of multithreading
Catch SQLite exceptions and raise our own so that our server only has to catch one thing
Add some more error handling
Query Builder
Security problem: we're inserting a user-defined name into a query
models_pika.py is shorter and more readable than the SQL version
"""Get data from database."""importosfrompypikaimportQuery,Tableimportsqlite3importutilENV_VAR="DATA"STAFF_COLUMNS=["staff_id","personal","family"]classModelException(Exception):"""Problems with queries."""def__init__(self,msg):self._msg=msgdef__str__(self):returnself._msgdefconnect():"""Connect to database."""path=os.getenv(ENV_VAR)ifnotpath:raiseModelException(f"Environment variable {ENV_VAR} not set")connection=sqlite3.connect(path,detect_types=sqlite3.PARSE_DECLTYPES)connection.row_factory=util.dict_factoryreturnconnectiondefall_staff():"""Get all staff."""staff=Table("staff")query=Query.from_(staff).select(*STAFF_COLUMNS)try:connection=connect()cursor=connection.execute(str(query))returncursor.fetchall()exceptsqlite3.DatabaseErrorasexc:raiseModelException(str(exc))defcolumn(name):"""Get a single column of staff."""ifnamenotinSTAFF_COLUMNS:raiseModelException(f"Column '{name}' does not exist")staff=Table("staff")query=Query.from_(staff).select(name)try:connection=connect()cursor=connection.execute(str(query))return[r[name]forrincursor.fetchall()]exceptsqlite3.DatabaseErrorasexc:raiseModelException(str(exc))defrow(staff_id):"""Get a single row of staff."""staff=Table("staff")query=Query.from_(staff) \
.select(*STAFF_COLUMNS) \
.where(staff.staff_id==staff_id)try:connection=connect()cursor=connection.execute(str(query))result=cursor.fetchall()iflen(result)==0:raiseModelException(f"no rows match {staff_id}")eliflen(result)>1:raiseModelException(f"multiple rows match {staff_id}")returnresult[0]exceptsqlite3.DatabaseErrorasexc:raiseModelException(str(exc))