from contextlib import closing import os from json import dumps from typing import List from typing import Optional from pycs.database.Result import Result class File: """ database class for files """ def __init__(self, database, row): self.database = database self.identifier = row[0] self.uuid = row[1] self.project_id = row[2] self.collection_id = row[3] self.type = row[4] self.name = row[5] self.extension = row[6] self.size = row[7] self.created = row[8] self.path = row[9] self.frames = row[10] self.fps = row[11] @property def absolute_path(self): if os.path.isabs(self.path): return self.path return os.path.join(os.getcwd(), self.path) def project(self): """ get the project associated with this file :return: project """ return self.database.project(self.project_id) def collection(self): """ get the collection associated with this file :return: collection """ if self.collection_id is None: return None return self.database.collection(self.collection_id) def set_collection(self, collection_id: Optional[int]): """ set this file's collection :param collection_id: new collection :return: """ with closing(self.database.con.cursor()) as cursor: cursor.execute('UPDATE files SET collection = ? WHERE id = ?', (collection_id, self.identifier)) self.collection_id = collection_id def set_collection_by_reference(self, collection_reference: Optional[str]): """ set this file's collection :param collection_reference: collection reference :return: """ if collection_reference is None: self.set_collection(None) return with closing(self.database.con.cursor()) as cursor: cursor.execute('SELECT id FROM collections WHERE reference = ?', [collection_reference]) row = cursor.fetchone() self.set_collection(row[0] if row is not None else None) def remove(self) -> None: """ remove this file from the database :return: """ with closing(self.database.con.cursor()) as cursor: cursor.execute('DELETE FROM files WHERE id = ?', [self.identifier]) def previous(self): """ get the predecessor of this file :return: another file """ with closing(self.database.con.cursor()) as cursor: cursor.execute(''' SELECT * FROM files WHERE id < ? AND project = ? ORDER BY id DESC LIMIT 1 ''', (self.identifier, self.project_id)) row = cursor.fetchone() if row is not None: return File(self.database, row) return None def next(self): """ get the successor of this file :return: another file """ with closing(self.database.con.cursor()) as cursor: cursor.execute(''' SELECT * FROM files WHERE id > ? AND project = ? ORDER BY id ASC LIMIT 1 ''', (self.identifier, self.project_id)) row = cursor.fetchone() if row is not None: return File(self.database, row) return None def previous_in_collection(self): """ get the predecessor of this file :return: another file """ with closing(self.database.con.cursor()) as cursor: if self.collection_id is None: cursor.execute(''' SELECT * FROM files WHERE id < ? AND project = ? AND collection IS NULL ORDER BY id DESC LIMIT 1 ''', (self.identifier, self.project_id)) else: cursor.execute(''' SELECT * FROM files WHERE id < ? AND project = ? AND collection = ? ORDER BY id DESC LIMIT 1 ''', (self.identifier, self.project_id, self.collection_id)) row = cursor.fetchone() if row is not None: return File(self.database, row) return None def next_in_collection(self): """ get the successor of this file :return: another file """ with closing(self.database.con.cursor()) as cursor: if self.collection_id is None: cursor.execute(''' SELECT * FROM files WHERE id > ? AND project = ? AND collection IS NULL ORDER BY id ASC LIMIT 1 ''', (self.identifier, self.project_id)) else: cursor.execute(''' SELECT * FROM files WHERE id > ? AND project = ? AND collection = ? ORDER BY id ASC LIMIT 1 ''', (self.identifier, self.project_id, self.collection_id)) row = cursor.fetchone() if row is not None: return File(self.database, row) return None def results(self) -> List[Result]: """ get a list of all results associated with this file :return: list of results """ with closing(self.database.con.cursor()) as cursor: cursor.execute('SELECT * FROM results WHERE file = ?', [self.identifier]) return list(map( lambda row: Result(self.database, row), cursor.fetchall() )) def result(self, identifier) -> Optional[Result]: """ get a specific result using its unique identifier :param identifier: unique identifier :return: result """ with closing(self.database.con.cursor()) as cursor: cursor.execute(''' SELECT * FROM results WHERE id = ? AND file = ? ''', (identifier, self.identifier)) row = cursor.fetchone() if row is not None: return Result(self.database, row) return None def create_result(self, origin, result_type, label, data=None): """ create a result :param origin: :param result_type: :param label: :param data: :return: """ if data is not None: data = dumps(data) with closing(self.database.con.cursor()) as cursor: cursor.execute(''' INSERT INTO results (file, origin, type, label, data) VALUES ( ?, ?, ?, ?, ?) ''', (self.identifier, origin, result_type, label, data)) return self.result(cursor.lastrowid) def remove_results(self, origin='pipeline') -> List[Result]: """ remove all results with the specified origin :param origin: either 'pipeline' or 'user' :return: list of removed results """ with closing(self.database.con.cursor()) as cursor: cursor.execute(''' SELECT * FROM results WHERE file = ? AND origin = ? ''', (self.identifier, origin)) results = list(map(lambda row: Result(self.database, row), cursor.fetchall())) cursor.execute(''' DELETE FROM results WHERE file = ? AND origin = ? ''', (self.identifier, origin)) return results