|
7 | 7 | # pyright: reportDeprecated=false |
8 | 8 |
|
9 | 9 |
|
| 10 | +import platform |
10 | 11 | import re |
11 | 12 | import shutil |
12 | 13 | import sys |
|
93 | 94 | TextFieldTemplate, |
94 | 95 | ) |
95 | 96 | from tagstudio.core.library.alchemy.joins import TagEntry, TagParent |
| 97 | +from tagstudio.core.library.alchemy.metadata import FileMetadata |
96 | 98 | from tagstudio.core.library.alchemy.models import ( |
97 | 99 | Entry, |
98 | 100 | Folder, |
|
105 | 107 | from tagstudio.core.library.alchemy.visitors import SQLBoolExpressionBuilder |
106 | 108 | from tagstudio.core.library.ignore import migrate_ext_list |
107 | 109 | from tagstudio.core.library.json.library import Library as JsonLibrary |
| 110 | +from tagstudio.core.utils.stat import get_date_created, get_date_modified |
108 | 111 | from tagstudio.core.utils.types import unwrap |
109 | 112 | from tagstudio.qt.translations import Translations |
110 | 113 |
|
@@ -924,7 +927,11 @@ def get_entry(self, entry_id: int) -> Entry | None: |
924 | 927 | return entry |
925 | 928 |
|
926 | 929 | def get_entry_full( |
927 | | - self, entry_id: int, with_fields: bool = True, with_tags: bool = True |
| 930 | + self, |
| 931 | + entry_id: int, |
| 932 | + with_fields: bool = True, |
| 933 | + with_tags: bool = True, |
| 934 | + with_metadata: bool = True, |
928 | 935 | ) -> Entry | None: |
929 | 936 | """Load entry and join with all joins and all tags.""" |
930 | 937 | # NOTE: TODO: Currently this method makes multiple separate queries to the db and combines |
@@ -954,6 +961,11 @@ def get_entry_full( |
954 | 961 | ) |
955 | 962 | ) |
956 | 963 |
|
| 964 | + if with_metadata: |
| 965 | + entry_stmt = entry_stmt.outerjoin(Entry.file_metadata).options( |
| 966 | + selectinload(Entry.file_metadata), |
| 967 | + ) |
| 968 | + |
957 | 969 | start_time = time.time() |
958 | 970 | entry = session.scalar(entry_stmt) |
959 | 971 | if with_tags: |
@@ -1147,10 +1159,79 @@ def remove_entries(self, entry_ids: list[int]) -> None: |
1147 | 1159 | session.query(Entry).where(Entry.id.in_(sub_list)).delete() |
1148 | 1160 | session.commit() |
1149 | 1161 |
|
1150 | | - def has_entry_with_path(self, path: Path) -> bool: |
1151 | | - """Check if an entry with this path is in the library.""" |
| 1162 | + def get_entry_id_from_path(self, path: Path) -> int: |
| 1163 | + """Attempt to return an Entry ID given a filepath, else return -1.""" |
1152 | 1164 | with Session(self.engine) as session: |
1153 | | - return session.query(exists().where(Entry.path == path)).scalar() |
| 1165 | + return session.scalar(select(Entry.id).where(Entry.path == path).limit(1)) or -1 |
| 1166 | + |
| 1167 | + # def update_entry_file_metadata( |
| 1168 | + # self, entry_id: int, date_created: datetime | None, date_modified: datetime | None |
| 1169 | + # ): |
| 1170 | + # with Session(self.engine) as session: |
| 1171 | + # stmt = update(FileMetadata).where( |
| 1172 | + # and_( |
| 1173 | + # FileMetadata.entry_id == entry_id, |
| 1174 | + # ) |
| 1175 | + # ) |
| 1176 | + # if date_created: |
| 1177 | + # stmt = stmt.values(date_created=date_created) |
| 1178 | + # if date_modified: |
| 1179 | + # stmt = stmt.values(date_modified=date_modified) |
| 1180 | + |
| 1181 | + # session.execute(stmt) |
| 1182 | + # session.commit() |
| 1183 | + |
| 1184 | + def refresh_file_entry_stats(self, entry_id: int, path: Path | None): |
| 1185 | + """Updates a file entry's associated stat() data.""" |
| 1186 | + needs_update = False |
| 1187 | + |
| 1188 | + entry = self.get_entry_full( |
| 1189 | + entry_id, with_fields=False, with_tags=False, with_metadata=True |
| 1190 | + ) |
| 1191 | + if not entry: |
| 1192 | + return |
| 1193 | + |
| 1194 | + if not path: |
| 1195 | + full_path = unwrap(self.library_dir) / entry.path |
| 1196 | + else: |
| 1197 | + full_path = unwrap(self.library_dir) / path |
| 1198 | + |
| 1199 | + logger.info(full_path) |
| 1200 | + |
| 1201 | + file_date_created = get_date_created(full_path) |
| 1202 | + file_date_modified = get_date_modified(full_path) |
| 1203 | + |
| 1204 | + # Log info |
| 1205 | + if entry.date_created != file_date_created: |
| 1206 | + logger.info(f"Difference in date_created!: {entry.date_created}/{file_date_created}") |
| 1207 | + needs_update = True |
| 1208 | + else: |
| 1209 | + logger.info("No difference in date_created.") |
| 1210 | + |
| 1211 | + if entry.date_modified != file_date_modified: |
| 1212 | + logger.info(f"Difference in date_modified!: {entry.date_modified}/{file_date_modified}") |
| 1213 | + needs_update = True |
| 1214 | + else: |
| 1215 | + logger.info("No difference in date_modified") |
| 1216 | + |
| 1217 | + if needs_update: |
| 1218 | + return |
| 1219 | + else: |
| 1220 | + logger.info(f"Updating entry file_metadata for {full_path}") |
| 1221 | + |
| 1222 | + with Session(self.engine) as session: |
| 1223 | + stmt = update(FileMetadata).where( |
| 1224 | + and_( |
| 1225 | + FileMetadata.entry_id == entry_id, |
| 1226 | + ) |
| 1227 | + ) |
| 1228 | + if file_date_created: |
| 1229 | + stmt = stmt.values(date_created=file_date_created) |
| 1230 | + if file_date_modified: |
| 1231 | + stmt = stmt.values(date_modified=file_date_modified) |
| 1232 | + |
| 1233 | + session.execute(stmt) |
| 1234 | + session.commit() |
1154 | 1235 |
|
1155 | 1236 | def get_paths(self, limit: int = -1) -> list[str]: |
1156 | 1237 | path_strings: list[str] = [] |
@@ -1468,7 +1549,7 @@ def update_entry_path(self, entry_id: int | Entry, path: Path) -> bool: |
1468 | 1549 |
|
1469 | 1550 | Returns True if the action succeeded and False if the path already exists. |
1470 | 1551 | """ |
1471 | | - if self.has_entry_with_path(path): |
| 1552 | + if self.get_entry_id_from_path(path) >= 0: |
1472 | 1553 | return False |
1473 | 1554 | if isinstance(entry_id, Entry): |
1474 | 1555 | entry_id = entry_id.id |
|
0 commit comments