2021-07-14 20:42:19 +00:00
import collections
import sqlite3
import typing
from hydrus . core import HydrusConstants as HC
from hydrus . core import HydrusData
from hydrus . core import HydrusDB
from hydrus . core import HydrusDBModule
2021-08-25 21:59:05 +00:00
from hydrus . client import ClientConstants as CC
from hydrus . client import ClientSearch
2021-07-14 20:42:19 +00:00
from hydrus . client . db import ClientDBMaster
from hydrus . client . db import ClientDBServices
def GenerateFilesTableNames ( service_id : int ) - > typing . Tuple [ str , str , str , str ] :
suffix = str ( service_id )
current_files_table_name = ' current_files_ {} ' . format ( suffix )
deleted_files_table_name = ' deleted_files_ {} ' . format ( suffix )
pending_files_table_name = ' pending_files_ {} ' . format ( suffix )
petitioned_files_table_name = ' petitioned_files_ {} ' . format ( suffix )
return ( current_files_table_name , deleted_files_table_name , pending_files_table_name , petitioned_files_table_name )
def GenerateFilesTableName ( service_id : int , status : int ) - > str :
( current_files_table_name , deleted_files_table_name , pending_files_table_name , petitioned_files_table_name ) = GenerateFilesTableNames ( service_id )
if status == HC . CONTENT_STATUS_CURRENT :
return current_files_table_name
elif status == HC . CONTENT_STATUS_DELETED :
return deleted_files_table_name
elif status == HC . CONTENT_STATUS_PENDING :
return pending_files_table_name
else :
return petitioned_files_table_name
2021-08-25 21:59:05 +00:00
class DBLocationSearchContext ( object ) :
def __init__ ( self , location_search_context : ClientSearch . LocationSearchContext ) :
self . location_search_context = location_search_context
self . files_table_name = None
def GetLocationSearchContext ( self ) - > ClientSearch . LocationSearchContext :
return self . location_search_context
2021-09-01 21:09:01 +00:00
def GetTableJoinIteratedByFileDomain ( self , table_phrase : str ) :
2021-08-25 21:59:05 +00:00
if self . location_search_context . IsAllKnownFiles ( ) :
return table_phrase
else :
return ' {} CROSS JOIN {} USING ( hash_id ) ' . format ( self . files_table_name , table_phrase )
def GetTableJoinLimitedByFileDomain ( self , table_phrase : str ) :
if self . location_search_context . IsAllKnownFiles ( ) :
return table_phrase
else :
return ' {} CROSS JOIN {} USING ( hash_id ) ' . format ( table_phrase , self . files_table_name )
2021-07-14 20:42:19 +00:00
class ClientDBFilesStorage ( HydrusDBModule . HydrusDBModule ) :
def __init__ ( self , cursor : sqlite3 . Cursor , modules_services : ClientDBServices . ClientDBMasterServices , modules_texts : ClientDBMaster . ClientDBMasterTexts ) :
self . modules_services = modules_services
self . modules_texts = modules_texts
HydrusDBModule . HydrusDBModule . __init__ ( self , ' client files storage ' , cursor )
2021-08-25 21:59:05 +00:00
self . temp_file_storage_table_name = None
2021-07-14 20:42:19 +00:00
def _GetInitialIndexGenerationTuples ( self ) :
index_generation_tuples = [ ]
return index_generation_tuples
def AddFiles ( self , service_id , insert_rows ) :
( current_files_table_name , deleted_files_table_name , pending_files_table_name , petitioned_files_table_name ) = GenerateFilesTableNames ( service_id )
2021-08-11 21:14:12 +00:00
self . _ExecuteMany ( ' INSERT OR IGNORE INTO {} VALUES ( ?, ? ); ' . format ( current_files_table_name ) , ( ( hash_id , timestamp ) for ( hash_id , timestamp ) in insert_rows ) )
2021-07-14 20:42:19 +00:00
2021-08-11 21:14:12 +00:00
self . _ExecuteMany ( ' DELETE FROM {} WHERE hash_id = ?; ' . format ( pending_files_table_name ) , ( ( hash_id , ) for ( hash_id , timestamp ) in insert_rows ) )
2021-07-14 20:42:19 +00:00
2021-08-11 21:14:12 +00:00
pending_changed = self . _GetRowCount ( ) > 0
2021-07-14 20:42:19 +00:00
return pending_changed
def ClearDeleteRecord ( self , service_id , hash_ids ) :
deleted_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_DELETED )
2021-08-11 21:14:12 +00:00
self . _ExecuteMany ( ' DELETE FROM {} WHERE hash_id = ?; ' . format ( deleted_files_table_name ) , ( ( hash_id , ) for hash_id in hash_ids ) )
2021-07-14 20:42:19 +00:00
2021-08-11 21:14:12 +00:00
num_deleted = self . _GetRowCount ( )
2021-07-14 20:42:19 +00:00
return num_deleted
2021-08-11 21:14:12 +00:00
def ClearFilesTables ( self , service_id : int , keep_pending = False ) :
2021-08-04 21:59:55 +00:00
( current_files_table_name , deleted_files_table_name , pending_files_table_name , petitioned_files_table_name ) = GenerateFilesTableNames ( service_id )
2021-08-11 21:14:12 +00:00
self . _Execute ( ' DELETE FROM {} ; ' . format ( current_files_table_name ) )
self . _Execute ( ' DELETE FROM {} ; ' . format ( deleted_files_table_name ) )
if not keep_pending :
self . _Execute ( ' DELETE FROM {} ; ' . format ( pending_files_table_name ) )
self . _Execute ( ' DELETE FROM {} ; ' . format ( petitioned_files_table_name ) )
2021-08-04 21:59:55 +00:00
2021-07-14 20:42:19 +00:00
def ClearLocalDeleteRecord ( self , hash_ids = None ) :
# we delete from everywhere, but not for files currently in the trash
service_ids_to_nums_cleared = { }
local_non_trash_service_ids = self . modules_services . GetServiceIds ( ( HC . COMBINED_LOCAL_FILE , HC . LOCAL_FILE_DOMAIN ) )
if hash_ids is None :
trash_current_files_table_name = GenerateFilesTableName ( self . modules_services . trash_service_id , HC . CONTENT_STATUS_CURRENT )
for service_id in local_non_trash_service_ids :
deleted_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_DELETED )
2021-08-11 21:14:12 +00:00
self . _Execute ( ' DELETE FROM {} WHERE hash_id NOT IN ( SELECT hash_id FROM {} ); ' . format ( deleted_files_table_name , trash_current_files_table_name ) )
2021-07-14 20:42:19 +00:00
2021-08-11 21:14:12 +00:00
num_cleared = self . _GetRowCount ( )
2021-07-14 20:42:19 +00:00
service_ids_to_nums_cleared [ service_id ] = num_cleared
2021-08-11 21:14:12 +00:00
self . _Execute ( ' DELETE FROM local_file_deletion_reasons WHERE hash_id NOT IN ( SELECT hash_id FROM {} ); ' . format ( trash_current_files_table_name ) )
2021-07-14 20:42:19 +00:00
else :
trashed_hash_ids = self . FilterCurrentHashIds ( self . modules_services . trash_service_id , hash_ids )
ok_to_clear_hash_ids = set ( hash_ids ) . difference ( trashed_hash_ids )
if len ( ok_to_clear_hash_ids ) > 0 :
for service_id in local_non_trash_service_ids :
deleted_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_DELETED )
2021-08-11 21:14:12 +00:00
self . _ExecuteMany ( ' DELETE FROM {} WHERE hash_id = ?; ' . format ( deleted_files_table_name ) , ( ( hash_id , ) for hash_id in ok_to_clear_hash_ids ) )
2021-07-14 20:42:19 +00:00
2021-08-11 21:14:12 +00:00
num_cleared = self . _GetRowCount ( )
2021-07-14 20:42:19 +00:00
service_ids_to_nums_cleared [ service_id ] = num_cleared
2021-08-11 21:14:12 +00:00
self . _ExecuteMany ( ' DELETE FROM local_file_deletion_reasons WHERE hash_id = ?; ' , ( ( hash_id , ) for hash_id in ok_to_clear_hash_ids ) )
2021-07-14 20:42:19 +00:00
return service_ids_to_nums_cleared
def CreateInitialTables ( self ) :
2021-08-11 21:14:12 +00:00
self . _Execute ( ' CREATE TABLE local_file_deletion_reasons ( hash_id INTEGER PRIMARY KEY, reason_id INTEGER ); ' )
2021-07-14 20:42:19 +00:00
2021-08-04 21:59:55 +00:00
def DeletePending ( self , service_id : int ) :
( current_files_table_name , deleted_files_table_name , pending_files_table_name , petitioned_files_table_name ) = GenerateFilesTableNames ( service_id )
2021-08-11 21:14:12 +00:00
self . _Execute ( ' DELETE FROM {} ; ' . format ( pending_files_table_name ) )
self . _Execute ( ' DELETE FROM {} ; ' . format ( petitioned_files_table_name ) )
2021-08-04 21:59:55 +00:00
def DropFilesTables ( self , service_id : int ) :
( current_files_table_name , deleted_files_table_name , pending_files_table_name , petitioned_files_table_name ) = GenerateFilesTableNames ( service_id )
2021-08-11 21:14:12 +00:00
self . _Execute ( ' DROP TABLE IF EXISTS {} ; ' . format ( current_files_table_name ) )
self . _Execute ( ' DROP TABLE IF EXISTS {} ; ' . format ( deleted_files_table_name ) )
self . _Execute ( ' DROP TABLE IF EXISTS {} ; ' . format ( pending_files_table_name ) )
self . _Execute ( ' DROP TABLE IF EXISTS {} ; ' . format ( petitioned_files_table_name ) )
2021-08-04 21:59:55 +00:00
2021-07-14 20:42:19 +00:00
def FilterAllCurrentHashIds ( self , hash_ids , just_these_service_ids = None ) :
if just_these_service_ids is None :
service_ids = self . modules_services . GetServiceIds ( HC . SPECIFIC_FILE_SERVICES )
else :
service_ids = just_these_service_ids
current_hash_ids = set ( )
2021-08-11 21:14:12 +00:00
with self . _MakeTemporaryIntegerTable ( hash_ids , ' hash_id ' ) as temp_hash_ids_table_name :
2021-07-14 20:42:19 +00:00
for service_id in service_ids :
current_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_CURRENT )
2021-08-11 21:14:12 +00:00
hash_id_iterator = self . _STI ( self . _Execute ( ' SELECT hash_id FROM {} CROSS JOIN {} USING ( hash_id ); ' . format ( temp_hash_ids_table_name , current_files_table_name ) ) )
2021-07-14 20:42:19 +00:00
current_hash_ids . update ( hash_id_iterator )
return current_hash_ids
def FilterAllPendingHashIds ( self , hash_ids , just_these_service_ids = None ) :
if just_these_service_ids is None :
service_ids = self . modules_services . GetServiceIds ( HC . SPECIFIC_FILE_SERVICES )
else :
service_ids = just_these_service_ids
pending_hash_ids = set ( )
2021-08-11 21:14:12 +00:00
with self . _MakeTemporaryIntegerTable ( hash_ids , ' hash_id ' ) as temp_hash_ids_table_name :
2021-07-14 20:42:19 +00:00
for service_id in service_ids :
pending_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_PENDING )
2021-08-11 21:14:12 +00:00
hash_id_iterator = self . _STI ( self . _Execute ( ' SELECT hash_id FROM {} CROSS JOIN {} USING ( hash_id ); ' . format ( temp_hash_ids_table_name , pending_files_table_name ) ) )
2021-07-14 20:42:19 +00:00
pending_hash_ids . update ( hash_id_iterator )
return pending_hash_ids
def FilterCurrentHashIds ( self , service_id , hash_ids ) :
if service_id == self . modules_services . combined_file_service_id :
return set ( hash_ids )
2021-08-11 21:14:12 +00:00
with self . _MakeTemporaryIntegerTable ( hash_ids , ' hash_id ' ) as temp_hash_ids_table_name :
2021-07-14 20:42:19 +00:00
current_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_CURRENT )
2021-08-11 21:14:12 +00:00
current_hash_ids = self . _STS ( self . _Execute ( ' SELECT hash_id FROM {} CROSS JOIN {} USING ( hash_id ); ' . format ( temp_hash_ids_table_name , current_files_table_name ) ) )
2021-07-14 20:42:19 +00:00
return current_hash_ids
def FilterPendingHashIds ( self , service_id , hash_ids ) :
if service_id == self . modules_services . combined_file_service_id :
return set ( hash_ids )
2021-08-11 21:14:12 +00:00
with self . _MakeTemporaryIntegerTable ( hash_ids , ' hash_id ' ) as temp_hash_ids_table_name :
2021-07-14 20:42:19 +00:00
pending_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_PENDING )
2021-08-11 21:14:12 +00:00
pending_hash_ids = self . _STS ( self . _Execute ( ' SELECT hash_id FROM {} CROSS JOIN {} USING ( hash_id ); ' . format ( temp_hash_ids_table_name , pending_files_table_name ) ) )
2021-07-14 20:42:19 +00:00
return pending_hash_ids
def GenerateFilesTables ( self , service_id : int ) :
( current_files_table_name , deleted_files_table_name , pending_files_table_name , petitioned_files_table_name ) = GenerateFilesTableNames ( service_id )
2021-08-11 21:14:12 +00:00
self . _Execute ( ' CREATE TABLE IF NOT EXISTS {} ( hash_id INTEGER PRIMARY KEY, timestamp INTEGER ); ' . format ( current_files_table_name ) )
2021-07-14 20:42:19 +00:00
self . _CreateIndex ( current_files_table_name , [ ' timestamp ' ] )
2021-08-11 21:14:12 +00:00
self . _Execute ( ' CREATE TABLE IF NOT EXISTS {} ( hash_id INTEGER PRIMARY KEY, timestamp INTEGER, original_timestamp INTEGER ); ' . format ( deleted_files_table_name ) )
2021-07-14 20:42:19 +00:00
self . _CreateIndex ( deleted_files_table_name , [ ' timestamp ' ] )
self . _CreateIndex ( deleted_files_table_name , [ ' original_timestamp ' ] )
2021-08-11 21:14:12 +00:00
self . _Execute ( ' CREATE TABLE IF NOT EXISTS {} ( hash_id INTEGER PRIMARY KEY ); ' . format ( pending_files_table_name ) )
2021-07-14 20:42:19 +00:00
2021-08-11 21:14:12 +00:00
self . _Execute ( ' CREATE TABLE IF NOT EXISTS {} ( hash_id INTEGER PRIMARY KEY, reason_id INTEGER ); ' . format ( petitioned_files_table_name ) )
2021-07-14 20:42:19 +00:00
self . _CreateIndex ( petitioned_files_table_name , [ ' reason_id ' ] )
def GetAPendingHashId ( self , service_id ) :
pending_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_PENDING )
2021-08-11 21:14:12 +00:00
result = self . _Execute ( ' SELECT hash_id FROM {} ; ' . format ( pending_files_table_name ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
if result is None :
return None
else :
( hash_id , ) = result
return hash_id
def GetAPetitionedHashId ( self , service_id ) :
petitioned_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_PETITIONED )
2021-08-11 21:14:12 +00:00
result = self . _Execute ( ' SELECT hash_id FROM {} ; ' . format ( petitioned_files_table_name ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
if result is None :
return None
else :
( hash_id , ) = result
return hash_id
def GetCurrentFilesCount ( self , service_id , only_viewable = False ) :
current_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_CURRENT )
if only_viewable :
# hashes to mimes
2021-08-11 21:14:12 +00:00
result = self . _Execute ( ' SELECT COUNT( * ) FROM {} CROSS JOIN files_info USING ( hash_id ) WHERE mime IN {} ; ' . format ( current_files_table_name , HydrusData . SplayListForDB ( HC . SEARCHABLE_MIMES ) ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
else :
2021-08-11 21:14:12 +00:00
result = self . _Execute ( ' SELECT COUNT( * ) FROM {} ; ' . format ( current_files_table_name ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
( count , ) = result
return count
def GetCurrentFilesInboxCount ( self , service_id ) :
current_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_CURRENT )
2021-08-11 21:14:12 +00:00
result = self . _Execute ( ' SELECT COUNT( * ) FROM {} CROSS JOIN file_inbox USING ( hash_id ); ' . format ( current_files_table_name ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
( count , ) = result
return count
def GetCurrentHashIdsList ( self , service_id ) :
current_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_CURRENT )
2021-08-11 21:14:12 +00:00
hash_ids = self . _STL ( self . _Execute ( ' SELECT hash_id FROM {} ; ' . format ( current_files_table_name ) ) )
2021-07-14 20:42:19 +00:00
return hash_ids
def GetCurrentFilesTotalSize ( self , service_id ) :
current_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_CURRENT )
# hashes to size
2021-08-11 21:14:12 +00:00
result = self . _Execute ( ' SELECT SUM( size ) FROM {} CROSS JOIN files_info USING ( hash_id ); ' . format ( current_files_table_name ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
( count , ) = result
return count
def GetCurrentHashIdsToTimestamps ( self , service_id , hash_ids ) :
current_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_CURRENT )
2021-08-11 21:14:12 +00:00
with self . _MakeTemporaryIntegerTable ( hash_ids , ' hash_id ' ) as temp_hash_ids_table_name :
2021-07-14 20:42:19 +00:00
2021-08-11 21:14:12 +00:00
rows = dict ( self . _Execute ( ' SELECT hash_id, timestamp FROM {} CROSS JOIN {} USING ( hash_id ); ' . format ( temp_hash_ids_table_name , current_files_table_name ) ) )
2021-07-14 20:42:19 +00:00
return rows
def GetCurrentTimestamp ( self , service_id : int , hash_id : int ) :
current_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_CURRENT )
2021-08-11 21:14:12 +00:00
result = self . _Execute ( ' SELECT timestamp FROM {} WHERE hash_id = ?; ' . format ( current_files_table_name ) , ( hash_id , ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
if result is None :
return None
else :
( timestamp , ) = result
return timestamp
def GetDeletedFilesCount ( self , service_id : int ) - > int :
deleted_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_DELETED )
2021-08-11 21:14:12 +00:00
result = self . _Execute ( ' SELECT COUNT( * ) FROM {} ; ' . format ( deleted_files_table_name ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
( count , ) = result
return count
def GetDeletionStatus ( self , service_id , hash_id ) :
# can have a value here and just be in trash, so we fetch it whatever the end result
2021-08-11 21:14:12 +00:00
result = self . _Execute ( ' SELECT reason_id FROM local_file_deletion_reasons WHERE hash_id = ?; ' , ( hash_id , ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
if result is None :
file_deletion_reason = ' Unknown deletion reason. '
else :
( reason_id , ) = result
file_deletion_reason = self . modules_texts . GetText ( reason_id )
deleted_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_DELETED )
is_deleted = False
timestamp = None
2021-08-11 21:14:12 +00:00
result = self . _Execute ( ' SELECT timestamp FROM {} WHERE hash_id = ?; ' . format ( deleted_files_table_name ) , ( hash_id , ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
if result is not None :
is_deleted = True
( timestamp , ) = result
return ( is_deleted , timestamp , file_deletion_reason )
2021-08-25 21:59:05 +00:00
def GetDBLocationSearchContext ( self , location_search_context : ClientSearch . LocationSearchContext ) :
if not location_search_context . SearchesAnything ( ) :
location_search_context = ClientSearch . LocationSearchContext ( current_service_keys = [ CC . COMBINED_FILE_SERVICE_KEY ] )
db_location_search_context = DBLocationSearchContext ( location_search_context )
if location_search_context . IsAllKnownFiles ( ) :
# no table set, obviously
return db_location_search_context
table_names = [ ]
for current_service_key in location_search_context . current_service_keys :
service_id = self . modules_services . GetServiceId ( current_service_key )
table_names . append ( GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_CURRENT ) )
for deleted_service_key in location_search_context . deleted_service_keys :
service_id = self . modules_services . GetServiceId ( deleted_service_key )
table_names . append ( GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_DELETED ) )
if len ( table_names ) == 1 :
table_name = table_names [ 0 ]
db_location_search_context . files_table_name = table_name
else :
# while I could make a VIEW of the UNION SELECT, we'll populate an indexed single column table to help query planner later on
# we're hardcoding the name to this class for now, so a limit of one db_location_search_context at a time _for now_
# we make change this in future to use wrapper temp int tables, we'll see
# maybe I should stick this guy in 'temp' to live through db connection resets, but we'll see I guess. it is generally ephemeral, not going to linger through weird vacuum maintenance or anything right?
if self . temp_file_storage_table_name is None :
self . temp_file_storage_table_name = ' mem.temp_file_storage_hash_id '
self . _Execute ( ' CREATE TABLE IF NOT EXISTS {} ( hash_id INTEGER PRIMARY KEY ); ' . format ( self . temp_file_storage_table_name ) )
else :
self . _Execute ( ' DELETE FROM {} ; ' . format ( self . temp_file_storage_table_name ) )
select_query = ' UNION ' . join ( ( ' SELECT hash_id FROM {} ' . format ( table_name ) for table_name in table_names ) )
self . _Execute ( ' INSERT OR IGNORE INTO {} ( hash_id ) SELECT hash_id FROM {} ; ' . format ( self . temp_file_storage_table_name , select_query ) )
db_location_search_context . files_table_name = self . temp_file_storage_table_name
return db_location_search_context
2021-07-14 20:42:19 +00:00
def GetExpectedTableNames ( self ) - > typing . Collection [ str ] :
expected_table_names = [
' local_file_deletion_reasons ' ,
]
return expected_table_names
def GetHashIdsToCurrentServiceIds ( self , temp_hash_ids_table_name ) :
hash_ids_to_current_file_service_ids = collections . defaultdict ( list )
for service_id in self . modules_services . GetServiceIds ( HC . SPECIFIC_FILE_SERVICES ) :
current_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_CURRENT )
2021-08-11 21:14:12 +00:00
for hash_id in self . _STI ( self . _Execute ( ' SELECT hash_id FROM {} CROSS JOIN {} USING ( hash_id ); ' . format ( temp_hash_ids_table_name , current_files_table_name ) ) ) :
2021-07-14 20:42:19 +00:00
hash_ids_to_current_file_service_ids [ hash_id ] . append ( service_id )
return hash_ids_to_current_file_service_ids
def GetHashIdsToServiceInfoDicts ( self , temp_hash_ids_table_name ) :
hash_ids_to_current_file_service_ids_and_timestamps = collections . defaultdict ( list )
hash_ids_to_deleted_file_service_ids_and_timestamps = collections . defaultdict ( list )
hash_ids_to_pending_file_service_ids = collections . defaultdict ( list )
hash_ids_to_petitioned_file_service_ids = collections . defaultdict ( list )
for service_id in self . modules_services . GetServiceIds ( HC . SPECIFIC_FILE_SERVICES ) :
( current_files_table_name , deleted_files_table_name , pending_files_table_name , petitioned_files_table_name ) = GenerateFilesTableNames ( service_id )
2021-08-11 21:14:12 +00:00
for ( hash_id , timestamp ) in self . _Execute ( ' SELECT hash_id, timestamp FROM {} CROSS JOIN {} USING ( hash_id ); ' . format ( temp_hash_ids_table_name , current_files_table_name ) ) :
2021-07-14 20:42:19 +00:00
hash_ids_to_current_file_service_ids_and_timestamps [ hash_id ] . append ( ( service_id , timestamp ) )
2021-08-11 21:14:12 +00:00
for ( hash_id , timestamp , original_timestamp ) in self . _Execute ( ' SELECT hash_id, timestamp, original_timestamp FROM {} CROSS JOIN {} USING ( hash_id ); ' . format ( temp_hash_ids_table_name , deleted_files_table_name ) ) :
2021-07-14 20:42:19 +00:00
hash_ids_to_deleted_file_service_ids_and_timestamps [ hash_id ] . append ( ( service_id , timestamp , original_timestamp ) )
2021-08-11 21:14:12 +00:00
for hash_id in self . _Execute ( ' SELECT hash_id FROM {} CROSS JOIN {} USING ( hash_id ); ' . format ( temp_hash_ids_table_name , pending_files_table_name ) ) :
2021-07-14 20:42:19 +00:00
hash_ids_to_pending_file_service_ids [ hash_id ] . append ( service_id )
2021-08-11 21:14:12 +00:00
for hash_id in self . _Execute ( ' SELECT hash_id FROM {} CROSS JOIN {} USING ( hash_id ); ' . format ( temp_hash_ids_table_name , petitioned_files_table_name ) ) :
2021-07-14 20:42:19 +00:00
hash_ids_to_petitioned_file_service_ids [ hash_id ] . append ( service_id )
return (
hash_ids_to_current_file_service_ids_and_timestamps ,
hash_ids_to_deleted_file_service_ids_and_timestamps ,
hash_ids_to_pending_file_service_ids ,
hash_ids_to_petitioned_file_service_ids
)
def GetNumLocal ( self , service_id : int ) - > int :
current_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_CURRENT )
combined_local_current_files_table_name = GenerateFilesTableName ( self . modules_services . combined_local_file_service_id , HC . CONTENT_STATUS_CURRENT )
2021-08-11 21:14:12 +00:00
( num_local , ) = self . _Execute ( ' SELECT COUNT( * ) FROM {} CROSS JOIN {} USING ( hash_id ); ' . format ( current_files_table_name , combined_local_current_files_table_name ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
return num_local
def GetPendingFilesCount ( self , service_id : int ) - > int :
pending_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_PENDING )
2021-08-11 21:14:12 +00:00
result = self . _Execute ( ' SELECT COUNT( * ) FROM {} ; ' . format ( pending_files_table_name ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
( count , ) = result
return count
def GetPetitionedFilesCount ( self , service_id : int ) - > int :
petitioned_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_PETITIONED )
2021-08-11 21:14:12 +00:00
result = self . _Execute ( ' SELECT COUNT( * ) FROM {} ; ' . format ( petitioned_files_table_name ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
( count , ) = result
return count
def GetServiceIdCounts ( self , hash_ids ) - > typing . Dict [ int , int ] :
2021-08-11 21:14:12 +00:00
with self . _MakeTemporaryIntegerTable ( hash_ids , ' hash_id ' ) as temp_hash_ids_table_name :
2021-07-14 20:42:19 +00:00
service_ids_to_counts = { }
for service_id in self . modules_services . GetServiceIds ( HC . SPECIFIC_FILE_SERVICES ) :
current_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_CURRENT )
# temp hashes to files
2021-08-11 21:14:12 +00:00
( count , ) = self . _Execute ( ' SELECT COUNT( * ) FROM {} CROSS JOIN {} USING ( hash_id ); ' . format ( temp_hash_ids_table_name , current_files_table_name ) ) . fetchone ( )
2021-07-14 20:42:19 +00:00
service_ids_to_counts [ service_id ] = count
return service_ids_to_counts
def GetSomePetitionedRows ( self , service_id : int ) :
petitioned_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_PETITIONED )
2021-08-11 21:14:12 +00:00
petitioned_rows = list ( HydrusData . BuildKeyToListDict ( self . _Execute ( ' SELECT reason_id, hash_id FROM {} ORDER BY reason_id LIMIT 100; ' . format ( petitioned_files_table_name ) ) ) . items ( ) )
2021-07-14 20:42:19 +00:00
return petitioned_rows
2021-09-01 21:09:01 +00:00
def GetTableJoinIteratedByFileDomain ( self , service_id , table_name , status ) :
files_table_name = GenerateFilesTableName ( service_id , status )
return ' {} CROSS JOIN {} USING ( hash_id ) ' . format ( files_table_name , table_name )
def GetTableJoinLimitedByFileDomain ( self , service_id , table_name , status ) :
files_table_name = GenerateFilesTableName ( service_id , status )
return ' {} CROSS JOIN {} USING ( hash_id ) ' . format ( table_name , files_table_name )
2021-07-14 20:42:19 +00:00
def GetTablesAndColumnsThatUseDefinitions ( self , content_type : int ) - > typing . List [ typing . Tuple [ str , str ] ] :
2021-07-28 21:12:00 +00:00
tables_and_columns = [ ]
2021-07-14 20:42:19 +00:00
if HC . CONTENT_TYPE_HASH :
for service_id in self . modules_services . GetServiceIds ( HC . SPECIFIC_FILE_SERVICES ) :
( current_files_table_name , deleted_files_table_name , pending_files_table_name , petitioned_files_table_name ) = GenerateFilesTableNames ( service_id )
tables_and_columns . extend ( [
( current_files_table_name , ' hash_id ' ) ,
( deleted_files_table_name , ' hash_id ' ) ,
( pending_files_table_name , ' hash_id ' ) ,
( petitioned_files_table_name , ' hash_id ' )
] )
2021-07-28 21:12:00 +00:00
return tables_and_columns
2021-07-14 20:42:19 +00:00
def GetUndeleteRows ( self , service_id , hash_ids ) :
deleted_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_DELETED )
2021-08-11 21:14:12 +00:00
with self . _MakeTemporaryIntegerTable ( hash_ids , ' hash_id ' ) as temp_hash_ids_table_name :
2021-07-14 20:42:19 +00:00
2021-08-11 21:14:12 +00:00
rows = self . _Execute ( ' SELECT hash_id, original_timestamp FROM {} CROSS JOIN {} USING ( hash_id ); ' . format ( temp_hash_ids_table_name , deleted_files_table_name ) ) . fetchall ( )
2021-07-14 20:42:19 +00:00
return rows
def PendFiles ( self , service_id , hash_ids ) :
pending_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_PENDING )
2021-08-11 21:14:12 +00:00
self . _ExecuteMany ( ' INSERT OR IGNORE INTO {} ( hash_id ) VALUES ( ? ); ' . format ( pending_files_table_name ) , ( ( hash_id , ) for hash_id in hash_ids ) )
2021-07-14 20:42:19 +00:00
def PetitionFiles ( self , service_id , reason_id , hash_ids ) :
petitioned_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_PETITIONED )
2021-08-11 21:14:12 +00:00
self . _ExecuteMany ( ' DELETE FROM {} WHERE hash_id = ?; ' . format ( petitioned_files_table_name ) , ( ( hash_id , ) for hash_id in hash_ids ) )
2021-07-14 20:42:19 +00:00
2021-08-11 21:14:12 +00:00
self . _ExecuteMany ( ' INSERT OR IGNORE INTO {} ( hash_id, reason_id ) VALUES ( ?, ? ); ' . format ( petitioned_files_table_name ) , ( ( hash_id , reason_id ) for hash_id in hash_ids ) )
2021-07-14 20:42:19 +00:00
def RecordDeleteFiles ( self , service_id , insert_rows ) :
deleted_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_DELETED )
now = HydrusData . GetNow ( )
2021-08-11 21:14:12 +00:00
self . _ExecuteMany (
2021-07-14 20:42:19 +00:00
' INSERT OR IGNORE INTO {} ( hash_id, timestamp, original_timestamp ) VALUES ( ?, ?, ? ); ' . format ( deleted_files_table_name ) ,
( ( hash_id , now , original_timestamp ) for ( hash_id , original_timestamp ) in insert_rows )
)
2021-08-11 21:14:12 +00:00
num_new_deleted_files = self . _GetRowCount ( )
2021-07-14 20:42:19 +00:00
return num_new_deleted_files
def RescindPendFiles ( self , service_id , hash_ids ) :
pending_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_PENDING )
2021-08-11 21:14:12 +00:00
self . _ExecuteMany ( ' DELETE FROM {} WHERE hash_id = ?; ' . format ( pending_files_table_name ) , ( ( hash_id , ) for hash_id in hash_ids ) )
2021-07-14 20:42:19 +00:00
def RescindPetitionFiles ( self , service_id , hash_ids ) :
petitioned_files_table_name = GenerateFilesTableName ( service_id , HC . CONTENT_STATUS_PETITIONED )
2021-08-11 21:14:12 +00:00
self . _ExecuteMany ( ' DELETE FROM {} WHERE hash_id = ?; ' . format ( petitioned_files_table_name ) , ( ( hash_id , ) for hash_id in hash_ids ) )
2021-07-14 20:42:19 +00:00
def RemoveFiles ( self , service_id , hash_ids ) :
( current_files_table_name , deleted_files_table_name , pending_files_table_name , petitioned_files_table_name ) = GenerateFilesTableNames ( service_id )
2021-08-11 21:14:12 +00:00
self . _ExecuteMany ( ' DELETE FROM {} WHERE hash_id = ?; ' . format ( current_files_table_name ) , ( ( hash_id , ) for hash_id in hash_ids ) )
2021-07-14 20:42:19 +00:00
2021-08-11 21:14:12 +00:00
self . _ExecuteMany ( ' DELETE FROM {} WHERE hash_id = ?; ' . format ( petitioned_files_table_name ) , ( ( hash_id , ) for hash_id in hash_ids ) )
2021-07-14 20:42:19 +00:00
2021-08-11 21:14:12 +00:00
pending_changed = self . _GetRowCount ( ) > 0
2021-07-14 20:42:19 +00:00
return pending_changed
def SetFileDeletionReason ( self , hash_ids , reason ) :
reason_id = self . modules_texts . GetTextId ( reason )
2021-08-11 21:14:12 +00:00
self . _ExecuteMany ( ' REPLACE INTO local_file_deletion_reasons ( hash_id, reason_id ) VALUES ( ?, ? ); ' , ( ( hash_id , reason_id ) for hash_id in hash_ids ) )
2021-07-14 20:42:19 +00:00