206 lines
5.5 KiB
Python
206 lines
5.5 KiB
Python
"""
|
|
CRUD operations for GUARDIAN, STUDENT and ATTENDANCE.
|
|
|
|
Every function takes an open pymysql connection as its first argument and
|
|
manages its own commit/rollback. All functions return plain data
|
|
(dicts/lists/bool) so this module has no dependency on the UI layer.
|
|
"""
|
|
|
|
import pymysql
|
|
|
|
|
|
class CrudError(Exception):
|
|
"""Raised for expected, user-facing data errors (bad FK, duplicate key, etc)."""
|
|
pass
|
|
|
|
|
|
def _run(conn, sql, params=None, fetch=None):
|
|
"""
|
|
Helper: execute a statement, commit, and optionally fetch results.
|
|
fetch: None (no fetch), 'one', or 'all'
|
|
Translates common MySQL errors into CrudError with a friendly message.
|
|
"""
|
|
try:
|
|
with conn.cursor() as cur:
|
|
cur.execute(sql, params or ())
|
|
result = None
|
|
if fetch == "one":
|
|
result = cur.fetchone()
|
|
elif fetch == "all":
|
|
result = cur.fetchall()
|
|
conn.commit()
|
|
return result if fetch else cur.rowcount
|
|
except pymysql.err.IntegrityError as e:
|
|
conn.rollback()
|
|
code = e.args[0] if e.args else None
|
|
if code == 1062:
|
|
raise CrudError("A record with that primary/unique key already exists.")
|
|
if code in (1451, 1452):
|
|
raise CrudError(
|
|
"That operation violates a foreign key constraint "
|
|
"(referenced record missing, or still referenced by other rows)."
|
|
)
|
|
raise CrudError(f"Database integrity error: {e}")
|
|
except pymysql.err.DataError as e:
|
|
conn.rollback()
|
|
raise CrudError(f"Invalid data for one or more fields: {e}")
|
|
except pymysql.err.MySQLError as e:
|
|
conn.rollback()
|
|
raise CrudError(f"Database error: {e}")
|
|
|
|
|
|
# ---------------------------------------------------------------- GUARDIAN --
|
|
|
|
def create_guardian(conn, guid, gname, gphone, gaddress):
|
|
_run(
|
|
conn,
|
|
"INSERT INTO GUARDIAN (GUID, GName, GPhone, GAddress) VALUES (%s, %s, %s, %s)",
|
|
(guid, gname, gphone, gaddress),
|
|
)
|
|
|
|
|
|
def get_guardian(conn, guid):
|
|
return _run(conn, "SELECT * FROM GUARDIAN WHERE GUID = %s", (guid,), fetch="one")
|
|
|
|
|
|
def list_guardians(conn):
|
|
return _run(conn, "SELECT * FROM GUARDIAN ORDER BY GUID", fetch="all")
|
|
|
|
|
|
def update_guardian(conn, guid, gname=None, gphone=None, gaddress=None):
|
|
fields, params = [], []
|
|
if gname is not None:
|
|
fields.append("GName = %s")
|
|
params.append(gname)
|
|
if gphone is not None:
|
|
fields.append("GPhone = %s")
|
|
params.append(gphone)
|
|
if gaddress is not None:
|
|
fields.append("GAddress = %s")
|
|
params.append(gaddress)
|
|
if not fields:
|
|
return 0
|
|
params.append(guid)
|
|
return _run(conn, f"UPDATE GUARDIAN SET {', '.join(fields)} WHERE GUID = %s", params)
|
|
|
|
|
|
def delete_guardian(conn, guid):
|
|
return _run(conn, "DELETE FROM GUARDIAN WHERE GUID = %s", (guid,))
|
|
|
|
|
|
# ----------------------------------------------------------------- STUDENT --
|
|
|
|
def create_student(conn, roll_number, sname, sdateofbirth, guid):
|
|
_run(
|
|
conn,
|
|
"INSERT INTO STUDENT (RollNumber, SName, SDateofBirth, GUID) VALUES (%s, %s, %s, %s)",
|
|
(roll_number, sname, sdateofbirth, guid),
|
|
)
|
|
|
|
|
|
def get_student(conn, roll_number):
|
|
return _run(conn, "SELECT * FROM STUDENT WHERE RollNumber = %s", (roll_number,), fetch="one")
|
|
|
|
|
|
def list_students(conn):
|
|
return _run(
|
|
conn,
|
|
"""
|
|
SELECT s.RollNumber, s.SName, s.SDateofBirth, s.GUID, g.GName AS GuardianName
|
|
FROM STUDENT s
|
|
LEFT JOIN GUARDIAN g ON s.GUID = g.GUID
|
|
ORDER BY s.RollNumber
|
|
""",
|
|
fetch="all",
|
|
)
|
|
|
|
|
|
def update_student(conn, roll_number, sname=None, sdateofbirth=None, guid=None):
|
|
fields, params = [], []
|
|
if sname is not None:
|
|
fields.append("SName = %s")
|
|
params.append(sname)
|
|
if sdateofbirth is not None:
|
|
fields.append("SDateofBirth = %s")
|
|
params.append(sdateofbirth)
|
|
if guid is not None:
|
|
fields.append("GUID = %s")
|
|
params.append(guid)
|
|
if not fields:
|
|
return 0
|
|
params.append(roll_number)
|
|
return _run(conn, f"UPDATE STUDENT SET {', '.join(fields)} WHERE RollNumber = %s", params)
|
|
|
|
|
|
def delete_student(conn, roll_number):
|
|
return _run(conn, "DELETE FROM STUDENT WHERE RollNumber = %s", (roll_number,))
|
|
|
|
|
|
# --------------------------------------------------------------- ATTENDANCE --
|
|
|
|
def mark_attendance(conn, attendance_date, roll_number, status):
|
|
"""Insert attendance; if a record for that date+student exists, update it instead."""
|
|
existing = _run(
|
|
conn,
|
|
"SELECT 1 FROM ATTENDANCE WHERE AttendanceDate = %s AND RollNumber = %s",
|
|
(attendance_date, roll_number),
|
|
fetch="one",
|
|
)
|
|
if existing:
|
|
_run(
|
|
conn,
|
|
"UPDATE ATTENDANCE SET AttendanceStatus = %s "
|
|
"WHERE AttendanceDate = %s AND RollNumber = %s",
|
|
(status, attendance_date, roll_number),
|
|
)
|
|
return "updated"
|
|
else:
|
|
_run(
|
|
conn,
|
|
"INSERT INTO ATTENDANCE (AttendanceDate, RollNumber, AttendanceStatus) "
|
|
"VALUES (%s, %s, %s)",
|
|
(attendance_date, roll_number, status),
|
|
)
|
|
return "created"
|
|
|
|
|
|
def get_attendance(conn, attendance_date, roll_number):
|
|
return _run(
|
|
conn,
|
|
"SELECT * FROM ATTENDANCE WHERE AttendanceDate = %s AND RollNumber = %s",
|
|
(attendance_date, roll_number),
|
|
fetch="one",
|
|
)
|
|
|
|
|
|
def list_attendance_by_date(conn, attendance_date):
|
|
return _run(
|
|
conn,
|
|
"""
|
|
SELECT a.AttendanceDate, a.RollNumber, s.SName, a.AttendanceStatus
|
|
FROM ATTENDANCE a
|
|
JOIN STUDENT s ON a.RollNumber = s.RollNumber
|
|
WHERE a.AttendanceDate = %s
|
|
ORDER BY a.RollNumber
|
|
""",
|
|
(attendance_date,),
|
|
fetch="all",
|
|
)
|
|
|
|
|
|
def list_attendance_by_student(conn, roll_number):
|
|
return _run(
|
|
conn,
|
|
"SELECT * FROM ATTENDANCE WHERE RollNumber = %s ORDER BY AttendanceDate",
|
|
(roll_number,),
|
|
fetch="all",
|
|
)
|
|
|
|
|
|
def delete_attendance(conn, attendance_date, roll_number):
|
|
return _run(
|
|
conn,
|
|
"DELETE FROM ATTENDANCE WHERE AttendanceDate = %s AND RollNumber = %s",
|
|
(attendance_date, roll_number),
|
|
)
|