project-init
This commit is contained in:
commit
65691a0aee
7 files changed
+897
No files matched your search
@@ -0,0 +1,205 @@
|
||||
"""
|
||||
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),
|
||||
)
|
||||
Reference in new issue
Block a user