""" JQL query builder. """ from typing import Optional, List class JQL: """Fluent JQL builder.""" def __init__(self): self._parts: List[str] = [] self._order: Optional[str] = None def _q(self, val: str) -> str: return f'"{val}"' if " " in val else val # Conditions def assigned_to_me(self) -> "JQL": self._parts.append("assignee = currentUser()") return self def project(self, key: str) -> "JQL": self._parts.append(f"project = {self._q(key)}") return self def sprint_open(self) -> "JQL": self._parts.append("sprint in openSprints()") return self def in_backlog(self) -> "JQL": self._parts.append("sprint is EMPTY") return self def not_done(self) -> "JQL": self._parts.append("statusCategory != Done") return self def status(self, name: str) -> "JQL": self._parts.append(f"status = {self._q(name)}") return self def label(self, name: str) -> "JQL": self._parts.append(f"labels = {self._q(name)}") return self def text(self, search: str) -> "JQL": self._parts.append(f'text ~ "{search}"') return self def issue_type(self, name: str) -> "JQL": self._parts.append(f"issuetype = {self._q(name)}") return self def raw(self, jql: str) -> "JQL": self._parts.append(jql) return self # Ordering def order_by(self, field: str, desc: bool = True) -> "JQL": self._order = f"ORDER BY {field} {'DESC' if desc else 'ASC'}" return self def build(self) -> str: jql = " AND ".join(self._parts) if self._order: jql = f"{jql} {self._order}" return jql.strip() # Preset queries for main use cases class Queries: @staticmethod def my_tickets(project: Optional[str] = None) -> JQL: q = JQL().assigned_to_me().not_done().order_by("updated") if project: q.project(project) return q @staticmethod def backlog(project: str) -> JQL: return JQL().project(project).in_backlog().not_done().order_by("priority") @staticmethod def current_sprint(project: str) -> JQL: return JQL().project(project).sprint_open().order_by("priority")