Coverage for nexusLIMS/tui/common/db_utils.py: 100%
25 statements
« prev ^ index » next coverage.py v7.11.3, created at 2026-03-24 05:23 +0000
« prev ^ index » next coverage.py v7.11.3, created at 2026-03-24 05:23 +0000
1"""
2Database utilities for NexusLIMS TUI applications.
4Provides common database query patterns.
5"""
7from typing import Any
9from sqlmodel import Session, select
11from nexusLIMS.db.models import Instrument, SessionLog
14def check_uniqueness(
15 session: Session,
16 model: type,
17 field_name: str,
18 value: Any,
19 exclude_pk: Any | None = None,
20) -> bool:
21 """
22 Check if a value is unique for a given field.
24 Parameters
25 ----------
26 session : Session
27 Active database session
28 model : type
29 SQLModel model class (e.g., Instrument)
30 field_name : str
31 Field name to check (e.g., "api_url")
32 value : Any
33 Value to check for uniqueness
34 exclude_pk : Any | None
35 Primary key value to exclude (for edit operations)
37 Returns
38 -------
39 bool
40 True if unique, False if duplicate exists
42 Examples
43 --------
44 >>> from nexusLIMS.db.models import Instrument
45 >>> with get_db_session() as session:
46 ... is_unique = check_uniqueness(
47 ... session, Instrument, "api_url",
48 ... "https://example.com/api/tools/?id=42"
49 ... )
50 """
51 # Skip check if value is None (for optional fields)
52 if value is None:
53 return True
55 # Build query
56 field = getattr(model, field_name)
57 statement = select(model).where(field == value)
59 # Exclude current record if editing
60 if exclude_pk is not None:
61 pk_field = getattr(model, model.__table__.primary_key.columns.keys()[0])
62 statement = statement.where(pk_field != exclude_pk)
64 # Check if any records exist
65 existing = session.exec(statement).first()
66 return existing is None
69def get_session_log_count(session: Session, instrument_pid: str) -> int:
70 """
71 Get count of session_log entries for an instrument.
73 Useful for warning users before deleting an instrument with associated data.
75 Parameters
76 ----------
77 session : Session
78 Active database session
79 instrument_pid : str
80 Instrument primary key
82 Returns
83 -------
84 int
85 Number of session_log entries
87 Examples
88 --------
89 >>> with get_db_session() as session:
90 ... count = get_session_log_count(session, "FEI-Titan-TEM")
91 ... if count > 0:
92 ... print(f"Warning: {count} session logs will be orphaned")
93 """
94 statement = select(SessionLog).where(SessionLog.instrument == instrument_pid)
95 results = session.exec(statement).all()
96 return len(results)
99def find_conflicting_instrument(
100 session: Session,
101 field_name: str,
102 value: Any,
103 exclude_pid: str | None = None,
104) -> Instrument | None:
105 """
106 Find an instrument that conflicts with a unique field value.
108 Parameters
109 ----------
110 session : Session
111 Active database session
112 field_name : str
113 Unique field name (e.g., api_url)
114 value : Any
115 Value to search for
116 exclude_pid : str | None
117 Instrument PID to exclude (for edit operations)
119 Returns
120 -------
121 Instrument | None
122 Conflicting instrument, or None if no conflict
124 Examples
125 --------
126 >>> with get_db_session() as session:
127 ... conflict = find_conflicting_instrument(
128 ... session, "api_url", "https://example.com/api"
129 ... )
130 ... if conflict:
131 ... print(f"Already used by {conflict.instrument_pid}")
132 """
133 if value is None:
134 return None
136 field = getattr(Instrument, field_name)
137 statement = select(Instrument).where(field == value)
139 if exclude_pid is not None:
140 statement = statement.where(Instrument.instrument_pid != exclude_pid)
142 return session.exec(statement).first()