2023-08-24 16:56:24 +00:00
import " dart:io " ;
2020-03-24 19:59:36 +00:00
2022-07-23 10:04:53 +00:00
import ' package:flutter/foundation.dart ' ;
2020-05-27 21:03:30 +00:00
import ' package:logging/logging.dart ' ;
2021-07-12 10:24:30 +00:00
import ' package:path/path.dart ' ;
import ' package:path_provider/path_provider.dart ' ;
2023-06-14 07:23:07 +00:00
import " package:photos/extensions/stop_watch.dart " ;
2021-06-28 06:40:19 +00:00
import ' package:photos/models/backup_status.dart ' ;
2023-08-25 04:39:30 +00:00
import ' package:photos/models/file/file.dart ' ;
import ' package:photos/models/file/file_type.dart ' ;
2023-08-26 05:44:05 +00:00
import ' package:photos/models/file_load_result.dart ' ;
2023-04-02 12:47:18 +00:00
import ' package:photos/models/location/location.dart ' ;
2023-05-25 05:51:56 +00:00
import " package:photos/models/metadata/common_keys.dart " ;
2023-06-20 12:25:49 +00:00
import " package:photos/services/filter/db_filters.dart " ;
2022-08-29 07:58:49 +00:00
import ' package:photos/utils/file_uploader_util.dart ' ;
2020-03-24 19:59:36 +00:00
import ' package:sqflite/sqflite.dart ' ;
2021-01-23 12:43:30 +00:00
import ' package:sqflite_migration/sqflite_migration.dart ' ;
2020-03-24 19:59:36 +00:00
2020-07-20 11:03:09 +00:00
class FilesDB {
2021-05-03 22:48:02 +00:00
/ *
Note: columnUploadedFileID and columnCollectionID have to be compared against
both NULL and - 1 because older clients might have entries where the DEFAULT
was unset , and a migration script to set the DEFAULT would break in case of
duplicate entries for un - uploaded files that were created due to a collision
in background and foreground syncs .
* /
2022-07-04 06:02:17 +00:00
static const _databaseName = " ente.files.db " ;
2020-03-24 19:59:36 +00:00
2020-07-20 11:03:09 +00:00
static final Logger _logger = Logger ( " FilesDB " ) ;
2020-05-27 21:03:30 +00:00
2022-07-23 05:41:43 +00:00
static const filesTable = ' files ' ;
2022-07-04 06:02:17 +00:00
static const tempTable = ' temp_files ' ;
2020-03-26 14:39:31 +00:00
2022-07-04 06:02:17 +00:00
static const columnGeneratedID = ' _id ' ;
static const columnUploadedFileID = ' uploaded_file_id ' ;
static const columnOwnerID = ' owner_id ' ;
static const columnCollectionID = ' collection_id ' ;
static const columnLocalID = ' local_id ' ;
static const columnTitle = ' title ' ;
static const columnDeviceFolder = ' device_folder ' ;
static const columnLatitude = ' latitude ' ;
static const columnLongitude = ' longitude ' ;
static const columnFileType = ' file_type ' ;
static const columnFileSubType = ' file_sub_type ' ;
static const columnDuration = ' duration ' ;
static const columnExif = ' exif ' ;
static const columnHash = ' hash ' ;
static const columnMetadataVersion = ' metadata_version ' ;
static const columnIsDeleted = ' is_deleted ' ;
static const columnCreationTime = ' creation_time ' ;
static const columnModificationTime = ' modification_time ' ;
static const columnUpdationTime = ' updation_time ' ;
2023-06-30 12:47:25 +00:00
static const columnAddedTime = ' added_time ' ;
2022-07-04 06:02:17 +00:00
static const columnEncryptedKey = ' encrypted_key ' ;
static const columnKeyDecryptionNonce = ' key_decryption_nonce ' ;
static const columnFileDecryptionHeader = ' file_decryption_header ' ;
static const columnThumbnailDecryptionHeader = ' thumbnail_decryption_header ' ;
static const columnMetadataDecryptionHeader = ' metadata_decryption_header ' ;
2022-09-24 10:36:05 +00:00
static const columnFileSize = ' file_size ' ;
2020-03-24 19:59:36 +00:00
2021-09-16 13:14:51 +00:00
// MMD -> Magic Metadata
2022-07-04 06:02:17 +00:00
static const columnMMdEncodedJson = ' mmd_encoded_json ' ;
static const columnMMdVersion = ' mmd_ver ' ;
2021-09-16 13:14:51 +00:00
2022-07-04 06:02:17 +00:00
static const columnPubMMdEncodedJson = ' pub_mmd_encoded_json ' ;
static const columnPubMMdVersion = ' pub_mmd_ver ' ;
2021-10-26 05:25:42 +00:00
2021-09-16 13:14:51 +00:00
// part of magic metadata
// Only parse & store selected fields from JSON in separate columns if
// we need to write query based on that field
2022-07-04 06:02:17 +00:00
static const columnMMdVisibility = ' mmd_visibility ' ;
2021-09-16 13:14:51 +00:00
2023-09-23 13:12:35 +00:00
static final initializationScript = [
. . . createTable ( filesTable ) ,
] ;
2021-07-21 19:55:24 +00:00
static final migrationScripts = [
. . . alterDeviceFolderToAllowNULL ( ) ,
. . . alterTimestampColumnTypes ( ) ,
2021-07-21 20:21:31 +00:00
. . . addIndices ( ) ,
2021-08-18 13:23:42 +00:00
. . . addMetadataColumns ( ) ,
2021-09-16 13:14:51 +00:00
. . . addMagicMetadataColumns ( ) ,
2021-09-24 11:19:03 +00:00
. . . addUniqueConstraintOnCollectionFiles ( ) ,
2022-07-21 13:03:33 +00:00
. . . addPubMagicMetadataColumns ( ) ,
. . . createOnDeviceFilesAndPathCollection ( ) ,
2022-09-24 10:36:05 +00:00
. . . addFileSizeColumn ( ) ,
2022-10-03 09:21:20 +00:00
. . . updateIndexes ( ) ,
2023-04-04 08:48:54 +00:00
. . . createEntityDataTable ( ) ,
2023-06-30 12:47:25 +00:00
. . . addAddedTime ( ) ,
2021-07-21 19:55:24 +00:00
] ;
2021-01-23 12:43:30 +00:00
final dbConfig = MigrationConfig (
2022-06-11 08:23:52 +00:00
initializationScript: initializationScript ,
migrationScripts: migrationScripts ,
) ;
2022-08-30 07:41:35 +00:00
2020-03-24 19:59:36 +00:00
// make this a singleton class
2020-07-20 11:03:09 +00:00
FilesDB . _privateConstructor ( ) ;
2021-10-26 14:46:58 +00:00
2020-07-20 11:03:09 +00:00
static final FilesDB instance = FilesDB . _privateConstructor ( ) ;
2020-03-24 19:59:36 +00:00
// only have a single app-wide reference to the database
2022-12-29 10:55:49 +00:00
static Future < Database > ? _dbFuture ;
2021-07-21 19:55:24 +00:00
2020-03-24 19:59:36 +00:00
Future < Database > get database async {
// lazily instantiate the db the first time it is accessed
2021-07-21 19:55:24 +00:00
_dbFuture ? ? = _initDatabase ( ) ;
2022-12-29 10:55:49 +00:00
return _dbFuture ! ;
2020-03-24 19:59:36 +00:00
}
2020-03-26 14:39:31 +00:00
2020-03-24 19:59:36 +00:00
// this opens the database (and creates it if it doesn't exist)
2021-07-21 19:55:24 +00:00
Future < Database > _initDatabase ( ) async {
2023-08-24 16:56:24 +00:00
final Directory documentsDirectory =
2022-08-30 07:33:54 +00:00
await getApplicationDocumentsDirectory ( ) ;
2022-08-29 14:43:31 +00:00
final String path = join ( documentsDirectory . path , _databaseName ) ;
2021-07-21 19:55:24 +00:00
_logger . info ( " DB path " + path ) ;
2021-01-23 12:43:30 +00:00
return await openDatabaseWithMigration ( path , dbConfig ) ;
2020-03-24 19:59:36 +00:00
}
// SQL code to create the database table
2021-01-25 06:15:37 +00:00
static List < String > createTable ( String tableName ) {
2021-01-23 13:49:37 +00:00
return [
'''
2021-01-25 06:15:37 +00:00
CREATE TABLE $tableName (
2021-01-24 18:59:17 +00:00
$columnGeneratedID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL ,
$columnLocalID TEXT ,
2021-05-03 22:48:02 +00:00
$columnUploadedFileID INTEGER DEFAULT - 1 ,
2021-01-24 18:59:17 +00:00
$columnOwnerID INTEGER ,
2021-05-03 22:48:02 +00:00
$columnCollectionID INTEGER DEFAULT - 1 ,
2021-01-24 18:59:17 +00:00
$columnTitle TEXT NOT NULL ,
$columnDeviceFolder TEXT ,
$columnLatitude REAL ,
$columnLongitude REAL ,
$columnFileType INTEGER ,
$columnModificationTime TEXT NOT NULL ,
$columnEncryptedKey TEXT ,
$columnKeyDecryptionNonce TEXT ,
$columnFileDecryptionHeader TEXT ,
$columnThumbnailDecryptionHeader TEXT ,
$columnMetadataDecryptionHeader TEXT ,
$columnIsDeleted INTEGER DEFAULT 0 ,
$columnCreationTime TEXT NOT NULL ,
$columnUpdationTime TEXT ,
2021-03-26 06:14:18 +00:00
UNIQUE ( $columnLocalID , $columnUploadedFileID , $columnCollectionID )
2021-01-24 18:59:17 +00:00
) ;
''' ,
2021-01-24 11:51:53 +00:00
] ;
}
2021-07-21 20:21:31 +00:00
static List < String > addIndices ( ) {
2021-01-24 11:51:53 +00:00
return [
2021-01-23 13:49:37 +00:00
'''
2022-07-23 05:41:43 +00:00
CREATE INDEX IF NOT EXISTS collection_id_index ON $filesTable ( $columnCollectionID ) ;
2021-07-21 19:55:24 +00:00
''' ,
'''
2022-07-23 05:41:43 +00:00
CREATE INDEX IF NOT EXISTS device_folder_index ON $filesTable ( $columnDeviceFolder ) ;
2021-07-21 19:55:24 +00:00
''' ,
'''
2022-07-23 05:41:43 +00:00
CREATE INDEX IF NOT EXISTS creation_time_index ON $filesTable ( $columnCreationTime ) ;
2021-07-21 19:55:24 +00:00
''' ,
'''
2022-07-23 05:41:43 +00:00
CREATE INDEX IF NOT EXISTS updation_time_index ON $filesTable ( $columnUpdationTime ) ;
2021-01-23 13:49:37 +00:00
'''
] ;
2021-01-23 12:43:30 +00:00
}
2021-01-23 13:49:37 +00:00
static List < String > alterDeviceFolderToAllowNULL ( ) {
return [
2021-01-25 06:15:37 +00:00
. . . createTable ( tempTable ) ,
2021-01-23 13:49:37 +00:00
'''
2021-01-25 05:20:57 +00:00
INSERT INTO $tempTable
2021-01-24 07:23:42 +00:00
SELECT *
2022-07-23 05:41:43 +00:00
FROM $filesTable ;
2021-01-24 18:59:17 +00:00
2022-07-23 05:41:43 +00:00
DROP TABLE $filesTable ;
2021-01-24 18:59:17 +00:00
2021-01-25 05:20:57 +00:00
ALTER TABLE $tempTable
2022-07-23 05:41:43 +00:00
RENAME TO $filesTable ;
2021-01-23 13:49:37 +00:00
'''
] ;
2020-03-24 19:59:36 +00:00
}
2020-03-26 14:39:31 +00:00
2021-07-21 19:55:24 +00:00
static List < String > alterTimestampColumnTypes ( ) {
return [
'''
DROP TABLE IF EXISTS $tempTable ;
''' ,
'''
CREATE TABLE $tempTable (
$columnGeneratedID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL ,
$columnLocalID TEXT ,
$columnUploadedFileID INTEGER DEFAULT - 1 ,
$columnOwnerID INTEGER ,
$columnCollectionID INTEGER DEFAULT - 1 ,
$columnTitle TEXT NOT NULL ,
$columnDeviceFolder TEXT ,
$columnLatitude REAL ,
$columnLongitude REAL ,
$columnFileType INTEGER ,
$columnModificationTime INTEGER NOT NULL ,
$columnEncryptedKey TEXT ,
$columnKeyDecryptionNonce TEXT ,
$columnFileDecryptionHeader TEXT ,
$columnThumbnailDecryptionHeader TEXT ,
$columnMetadataDecryptionHeader TEXT ,
$columnCreationTime INTEGER NOT NULL ,
$columnUpdationTime INTEGER ,
UNIQUE ( $columnLocalID , $columnUploadedFileID , $columnCollectionID )
) ;
''' ,
'''
INSERT INTO $tempTable
SELECT
$columnGeneratedID ,
$columnLocalID ,
$columnUploadedFileID ,
$columnOwnerID ,
$columnCollectionID ,
$columnTitle ,
$columnDeviceFolder ,
$columnLatitude ,
$columnLongitude ,
$columnFileType ,
CAST ( $columnModificationTime AS INTEGER ) ,
$columnEncryptedKey ,
$columnKeyDecryptionNonce ,
$columnFileDecryptionHeader ,
$columnThumbnailDecryptionHeader ,
$columnMetadataDecryptionHeader ,
CAST ( $columnCreationTime AS INTEGER ) ,
CAST ( $columnUpdationTime AS INTEGER )
2022-07-23 05:41:43 +00:00
FROM $filesTable ;
2021-07-21 19:55:24 +00:00
''' ,
'''
2022-07-23 05:41:43 +00:00
DROP TABLE $filesTable ;
2021-07-21 19:55:24 +00:00
''' ,
'''
ALTER TABLE $tempTable
2022-07-23 05:41:43 +00:00
RENAME TO $filesTable ;
2021-07-21 19:55:24 +00:00
''' ,
] ;
}
2021-08-18 13:23:42 +00:00
static List < String > addMetadataColumns ( ) {
return [
'''
2022-07-23 05:41:43 +00:00
ALTER TABLE $filesTable ADD COLUMN $columnFileSubType INTEGER ;
2021-08-18 13:23:42 +00:00
''' ,
'''
2022-07-23 05:41:43 +00:00
ALTER TABLE $filesTable ADD COLUMN $columnDuration INTEGER ;
2021-08-18 13:23:42 +00:00
''' ,
'''
2022-07-23 05:41:43 +00:00
ALTER TABLE $filesTable ADD COLUMN $columnExif TEXT ;
2021-08-18 13:23:42 +00:00
''' ,
'''
2022-07-23 05:41:43 +00:00
ALTER TABLE $filesTable ADD COLUMN $columnHash TEXT ;
2021-08-18 13:23:42 +00:00
''' ,
'''
2022-07-23 05:41:43 +00:00
ALTER TABLE $filesTable ADD COLUMN $columnMetadataVersion INTEGER ;
2021-08-18 13:23:42 +00:00
''' ,
] ;
}
2021-09-16 13:14:51 +00:00
static List < String > addMagicMetadataColumns ( ) {
return [
'''
2022-07-23 05:41:43 +00:00
ALTER TABLE $filesTable ADD COLUMN $columnMMdEncodedJson TEXT DEFAULT ' {} ' ;
2021-09-16 13:14:51 +00:00
''' ,
'''
2022-07-23 05:41:43 +00:00
ALTER TABLE $filesTable ADD COLUMN $columnMMdVersion INTEGER DEFAULT 0 ;
2021-09-16 13:14:51 +00:00
''' ,
'''
2023-05-25 05:51:56 +00:00
ALTER TABLE $filesTable ADD COLUMN $columnMMdVisibility INTEGER DEFAULT $visibleVisibility ;
2021-09-16 13:14:51 +00:00
'''
] ;
}
2021-09-24 11:19:03 +00:00
static List < String > addUniqueConstraintOnCollectionFiles ( ) {
return [
'''
2022-07-23 05:41:43 +00:00
DELETE from $filesTable where $columnCollectionID | | ' - ' | | $columnUploadedFileID IN
( SELECT $columnCollectionID | | ' - ' | | $columnUploadedFileID from $filesTable WHERE
2021-10-01 18:47:15 +00:00
$columnCollectionID is not NULL AND $columnUploadedFileID is NOT NULL
AND $columnCollectionID ! = - 1 AND $columnUploadedFileID ! = - 1
GROUP BY ( $columnCollectionID | | ' - ' | | $columnUploadedFileID ) HAVING count ( * ) > 1 )
AND ( $columnCollectionID | | ' - ' | | $columnUploadedFileID | | ' - ' | | $columnGeneratedID ) NOT IN
( SELECT $columnCollectionID | | ' - ' | | $columnUploadedFileID | | ' - ' | | max ( $columnGeneratedID )
2022-07-23 05:41:43 +00:00
from $filesTable WHERE
2021-10-01 18:47:15 +00:00
$columnCollectionID is not NULL AND $columnUploadedFileID is NOT NULL
AND $columnCollectionID ! = - 1 AND $columnUploadedFileID ! = - 1 GROUP BY
( $columnCollectionID | | ' - ' | | $columnUploadedFileID ) HAVING count ( * ) > 1 ) ;
2021-09-24 11:19:03 +00:00
''' ,
'''
2022-07-23 05:41:43 +00:00
CREATE UNIQUE INDEX IF NOT EXISTS cid_uid ON $filesTable ( $columnCollectionID , $columnUploadedFileID )
2021-09-24 11:43:35 +00:00
WHERE $columnCollectionID is not NULL AND $columnUploadedFileID is not NULL
AND $columnCollectionID ! = - 1 AND $columnUploadedFileID ! = - 1 ;
2021-09-24 11:19:03 +00:00
'''
] ;
}
2021-10-26 05:25:42 +00:00
static List < String > addPubMagicMetadataColumns ( ) {
return [
'''
2022-07-23 05:41:43 +00:00
ALTER TABLE $filesTable ADD COLUMN $columnPubMMdEncodedJson TEXT DEFAULT ' {} ' ;
2021-10-26 05:25:42 +00:00
''' ,
'''
2022-07-23 05:41:43 +00:00
ALTER TABLE $filesTable ADD COLUMN $columnPubMMdVersion INTEGER DEFAULT 0 ;
2021-10-26 05:25:42 +00:00
'''
] ;
}
2022-07-21 13:03:33 +00:00
static List < String > createOnDeviceFilesAndPathCollection ( ) {
return [
'''
2022-08-26 11:47:30 +00:00
CREATE TABLE IF NOT EXISTS device_files (
2022-07-21 13:03:33 +00:00
id TEXT NOT NULL ,
path_id TEXT NOT NULL ,
UNIQUE ( id , path_id )
2022-07-23 11:33:59 +00:00
) ;
''' ,
'''
2022-08-31 18:39:39 +00:00
CREATE TABLE IF NOT EXISTS device_collections (
2022-07-23 11:33:59 +00:00
id TEXT PRIMARY KEY NOT NULL ,
name TEXT ,
modified_at INTEGER NOT NULL DEFAULT 0 ,
2022-09-01 04:15:17 +00:00
should_backup INTEGER NOT NULL DEFAULT 0 ,
2022-07-23 11:33:59 +00:00
count INTEGER NOT NULL DEFAULT 0 ,
collection_id INTEGER DEFAULT - 1 ,
2022-09-07 06:03:48 +00:00
upload_strategy INTEGER DEFAULT 0 ,
2022-07-23 11:33:59 +00:00
cover_id TEXT
) ;
''' ,
'''
2022-07-26 05:32:04 +00:00
CREATE INDEX IF NOT EXISTS df_id_idx ON device_files ( id ) ;
2022-07-23 11:33:59 +00:00
''' ,
'''
2022-07-26 05:32:04 +00:00
CREATE INDEX IF NOT EXISTS df_path_id_idx ON device_files ( path_id ) ;
2022-07-21 13:03:33 +00:00
''' ,
] ;
}
2023-04-04 07:20:23 +00:00
static List < String > createEntityDataTable ( ) {
return [
'''
2023-04-04 08:48:54 +00:00
CREATE TABLE IF NOT EXISTS entities (
2023-04-04 07:20:23 +00:00
id TEXT PRIMARY KEY NOT NULL ,
type TEXT NOT NULL ,
2023-04-04 08:48:54 +00:00
ownerID INTEGER NOT NULL ,
2023-04-04 07:20:23 +00:00
data TEXT NOT NULL DEFAULT ' {} ' ,
2023-04-04 08:48:54 +00:00
updatedAt INTEGER NOT NULL
2023-04-04 07:20:23 +00:00
) ;
'''
] ;
}
2022-09-24 10:36:05 +00:00
static List < String > addFileSizeColumn ( ) {
return [
'''
ALTER TABLE $filesTable ADD COLUMN $columnFileSize INTEGER ;
''' ,
] ;
}
2022-10-03 09:21:20 +00:00
static List < String > updateIndexes ( ) {
return [
'''
DROP INDEX IF EXISTS device_folder_index ;
''' ,
'''
CREATE INDEX IF NOT EXISTS file_hash_index ON $filesTable ( $columnHash ) ;
''' ,
] ;
}
2023-06-30 12:47:25 +00:00
static List < String > addAddedTime ( ) {
return [
'''
ALTER TABLE $filesTable ADD COLUMN $columnAddedTime INTEGER NOT NULL DEFAULT - 1 ;
''' ,
'''
CREATE INDEX IF NOT EXISTS added_time_index ON $filesTable ( $columnAddedTime ) ;
'''
] ;
}
2021-03-17 21:07:17 +00:00
Future < void > clearTable ( ) async {
final db = await instance . database ;
2022-07-23 05:41:43 +00:00
await db . delete ( filesTable ) ;
2022-09-29 09:19:14 +00:00
await db . delete ( " device_files " ) ;
await db . delete ( " device_collections " ) ;
2023-04-18 09:33:01 +00:00
await db . delete ( " entities " ) ;
2021-03-17 21:07:17 +00:00
}
2022-07-23 10:04:53 +00:00
Future < void > deleteDB ( ) async {
if ( kDebugMode ) {
debugPrint ( " Deleting files db " ) ;
2023-08-24 16:56:24 +00:00
final Directory documentsDirectory =
2022-07-23 10:04:53 +00:00
await getApplicationDocumentsDirectory ( ) ;
2022-08-30 07:33:54 +00:00
final String path = join ( documentsDirectory . path , _databaseName ) ;
2023-08-24 16:56:24 +00:00
File ( path ) . deleteSync ( recursive: true ) ;
2022-07-23 11:33:59 +00:00
_dbFuture = null ;
2022-07-23 10:04:53 +00:00
}
}
2022-08-24 10:32:03 +00:00
Future < void > insertMultiple (
2023-08-24 16:56:24 +00:00
List < EnteFile > files , {
2022-08-24 10:32:03 +00:00
ConflictAlgorithm conflictAlgorithm = ConflictAlgorithm . replace ,
} ) async {
2021-04-19 12:46:42 +00:00
final startTime = DateTime . now ( ) ;
2023-06-19 05:09:03 +00:00
final db = await database ;
2020-03-30 14:28:46 +00:00
var batch = db . batch ( ) ;
int batchCounter = 0 ;
2023-08-24 16:56:24 +00:00
for ( EnteFile file in files ) {
2020-03-30 14:28:46 +00:00
if ( batchCounter = = 400 ) {
2021-05-06 20:31:21 +00:00
await batch . commit ( noResult: true ) ;
2020-03-30 14:28:46 +00:00
batch = db . batch ( ) ;
2021-04-19 14:14:34 +00:00
batchCounter = 0 ;
2020-03-30 14:28:46 +00:00
}
2020-10-24 10:32:45 +00:00
batch . insert (
2022-07-23 05:41:43 +00:00
filesTable ,
2020-10-24 10:32:45 +00:00
_getRowForFile ( file ) ,
2022-08-24 10:32:03 +00:00
conflictAlgorithm: conflictAlgorithm ,
2020-10-24 10:32:45 +00:00
) ;
2020-03-30 14:28:46 +00:00
batchCounter + + ;
}
2020-11-20 11:05:17 +00:00
await batch . commit ( noResult: true ) ;
2021-04-19 12:46:42 +00:00
final endTime = DateTime . now ( ) ;
final duration = Duration (
2022-06-11 08:23:52 +00:00
microseconds:
endTime . microsecondsSinceEpoch - startTime . microsecondsSinceEpoch ,
) ;
_logger . info (
" Batch insert of " +
files . length . toString ( ) +
" took " +
duration . inMilliseconds . toString ( ) +
" ms. " ,
) ;
2020-03-26 14:39:31 +00:00
}
2023-08-24 16:56:24 +00:00
Future < int > insert ( EnteFile file ) async {
2021-06-09 15:32:30 +00:00
final db = await instance . database ;
return db . insert (
2022-07-23 05:41:43 +00:00
filesTable ,
2021-06-09 15:32:30 +00:00
_getRowForFile ( file ) ,
conflictAlgorithm: ConflictAlgorithm . replace ,
) ;
}
2023-08-24 16:56:24 +00:00
Future < EnteFile ? > getFile ( int generatedID ) async {
2020-10-24 20:05:50 +00:00
final db = await instance . database ;
2022-06-11 08:23:52 +00:00
final results = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2022-06-11 08:23:52 +00:00
where: ' $ columnGeneratedID = ? ' ,
whereArgs: [ generatedID ] ,
) ;
2020-11-01 07:37:23 +00:00
if ( results . isEmpty ) {
return null ;
}
2022-07-23 05:41:43 +00:00
return convertToFiles ( results ) [ 0 ] ;
2020-10-24 20:05:50 +00:00
}
2023-08-24 16:56:24 +00:00
Future < EnteFile ? > getUploadedFile ( int uploadedID , int collectionID ) async {
2020-11-30 06:28:37 +00:00
final db = await instance . database ;
final results = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2020-11-30 06:28:37 +00:00
where: ' $ columnUploadedFileID = ? AND $ columnCollectionID = ? ' ,
whereArgs: [
uploadedID ,
collectionID ,
] ,
) ;
if ( results . isEmpty ) {
return null ;
}
2022-07-23 05:41:43 +00:00
return convertToFiles ( results ) [ 0 ] ;
2020-11-30 06:28:37 +00:00
}
2023-10-03 17:56:51 +00:00
Future < EnteFile ? > getAnyUploadedFile ( int uploadedID ) async {
final db = await instance . database ;
final results = await db . query (
filesTable ,
where: ' $ columnUploadedFileID = ? ' ,
whereArgs: [
uploadedID ,
] ,
) ;
if ( results . isEmpty ) {
return null ;
}
return convertToFiles ( results ) [ 0 ] ;
}
2021-04-19 11:27:52 +00:00
Future < Set < int > > getUploadedFileIDs ( int collectionID ) async {
final db = await instance . database ;
final results = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2021-04-19 11:27:52 +00:00
columns: [ columnUploadedFileID ] ,
2022-12-29 10:55:49 +00:00
where:
' $ columnCollectionID = ? AND ( $ columnUploadedFileID IS NOT NULL AND $ columnUploadedFileID IS NOT -1) ' ,
2021-04-19 11:27:52 +00:00
whereArgs: [
collectionID ,
] ,
) ;
2021-07-21 19:55:24 +00:00
final ids = < int > { } ;
2021-04-19 11:27:52 +00:00
for ( final result in results ) {
2022-12-29 10:55:49 +00:00
ids . add ( result [ columnUploadedFileID ] as int ) ;
2021-04-19 11:27:52 +00:00
}
return ids ;
}
2021-06-28 06:40:19 +00:00
Future < BackedUpFileIDs > getBackedUpIDs ( ) async {
2021-06-28 05:30:58 +00:00
final db = await instance . database ;
final results = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2023-05-31 04:40:59 +00:00
columns: [ columnLocalID , columnUploadedFileID , columnFileSize ] ,
2021-06-28 05:30:58 +00:00
where:
' $ columnLocalID IS NOT NULL AND ( $ columnUploadedFileID IS NOT NULL AND $ columnUploadedFileID IS NOT -1) ' ,
) ;
2023-05-31 02:54:12 +00:00
final Set < String > localIDs = < String > { } ;
final Set < int > uploadedIDs = < int > { } ;
2023-05-31 04:40:59 +00:00
int localSize = 0 ;
2021-06-28 05:30:58 +00:00
for ( final result in results ) {
2023-05-31 04:40:59 +00:00
final String localID = result [ columnLocalID ] as String ;
final int ? fileSize = result [ columnFileSize ] as int ? ;
if ( ! localIDs . contains ( localID ) & & fileSize ! = null ) {
localSize + = fileSize ;
}
2022-12-29 10:55:49 +00:00
localIDs . add ( result [ columnLocalID ] as String ) ;
uploadedIDs . add ( result [ columnUploadedFileID ] as int ) ;
2021-06-28 05:30:58 +00:00
}
2023-05-31 04:40:59 +00:00
return BackedUpFileIDs ( localIDs . toList ( ) , uploadedIDs . toList ( ) , localSize ) ;
2021-06-28 05:30:58 +00:00
}
2022-09-09 10:34:42 +00:00
Future < FileLoadResult > getAllPendingOrUploadedFiles (
2022-06-11 08:23:52 +00:00
int startTime ,
int endTime ,
int ownerID , {
2022-12-29 10:55:49 +00:00
int ? limit ,
bool ? asc ,
2023-05-25 05:51:56 +00:00
int visibility = visibleVisibility ,
2023-06-20 12:25:49 +00:00
DBFilterOptions ? filterOptions ,
2023-05-30 09:00:19 +00:00
bool applyOwnerCheck = false ,
2022-06-11 08:23:52 +00:00
} ) async {
2023-06-19 09:46:19 +00:00
final stopWatch = EnteWatch ( ' getAllPendingOrUploadedFiles ' ) . . start ( ) ;
2023-05-30 09:00:19 +00:00
late String whereQuery ;
late List < Object ? > ? whereArgs ;
if ( applyOwnerCheck ) {
whereQuery = ' $ columnCreationTime >= ? AND $ columnCreationTime <= ? '
' AND ( $ columnOwnerID IS NULL OR $ columnOwnerID = ?) '
' AND ( $ columnCollectionID IS NOT NULL AND $ columnCollectionID IS NOT -1) '
' AND $ columnMMdVisibility = ? ' ;
whereArgs = [ startTime , endTime , ownerID , visibility ] ;
} else {
whereQuery =
' $ columnCreationTime >= ? AND $ columnCreationTime <= ? AND ( $ columnCollectionID IS NOT NULL AND $ columnCollectionID IS NOT -1) '
' AND $ columnMMdVisibility = ? ' ;
whereArgs = [ startTime , endTime , visibility ] ;
}
2023-03-27 04:36:21 +00:00
2020-05-06 18:13:24 +00:00
final db = await instance . database ;
2021-06-09 13:45:42 +00:00
final order = ( asc ? ? false ? ' ASC ' : ' DESC ' ) ;
2020-05-06 18:13:24 +00:00
final results = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2023-06-14 07:31:40 +00:00
where: whereQuery ,
whereArgs: whereArgs ,
2021-06-09 13:45:42 +00:00
orderBy:
' $ columnCreationTime ' + order + ' , $ columnModificationTime ' + order ,
2021-04-20 20:11:39 +00:00
limit: limit ,
2020-05-06 18:13:24 +00:00
) ;
2023-06-19 09:46:19 +00:00
stopWatch . log ( ' queryDone ' ) ;
2022-07-23 05:41:43 +00:00
final files = convertToFiles ( results ) ;
2023-06-19 09:46:19 +00:00
stopWatch . log ( ' convertDone ' ) ;
2023-06-20 12:25:49 +00:00
final filteredFiles = await applyDBFilters ( files , filterOptions ) ;
2023-06-20 12:04:12 +00:00
stopWatch . log ( ' filteringDone ' ) ;
2023-03-27 04:36:21 +00:00
stopWatch . stop ( ) ;
2023-06-20 12:04:12 +00:00
return FileLoadResult ( filteredFiles , files . length = = limit ) ;
2020-04-12 12:38:49 +00:00
}
2021-09-30 09:28:29 +00:00
Future < FileLoadResult > getAllLocalAndUploadedFiles (
2022-06-11 08:23:52 +00:00
int startTime ,
int endTime ,
int ownerID , {
2022-12-29 10:55:49 +00:00
int ? limit ,
bool ? asc ,
2023-06-20 12:49:45 +00:00
required DBFilterOptions filterOptions ,
2022-06-11 08:23:52 +00:00
} ) async {
2021-07-01 11:26:47 +00:00
final db = await instance . database ;
final order = ( asc ? ? false ? ' ASC ' : ' DESC ' ) ;
final results = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2023-04-13 10:17:55 +00:00
where:
2023-05-29 13:47:35 +00:00
' $ columnCreationTime >= ? AND $ columnCreationTime <= ? AND ( $ columnMMdVisibility IS NULL OR $ columnMMdVisibility = ?) '
2023-04-13 10:17:55 +00:00
' AND ( $ columnLocalID IS NOT NULL OR ( $ columnCollectionID IS NOT NULL AND $ columnCollectionID IS NOT -1)) ' ,
2023-05-29 13:47:35 +00:00
whereArgs: [ startTime , endTime , visibleVisibility ] ,
2021-07-01 11:26:47 +00:00
orderBy:
' $ columnCreationTime ' + order + ' , $ columnModificationTime ' + order ,
limit: limit ,
) ;
2022-07-23 05:41:43 +00:00
final files = convertToFiles ( results ) ;
2023-08-26 05:44:05 +00:00
final List < EnteFile > filteredFiles =
await applyDBFilters ( files , filterOptions ) ;
2023-06-20 12:49:45 +00:00
return FileLoadResult ( filteredFiles , files . length = = limit ) ;
2021-07-01 11:26:47 +00:00
}
2023-08-24 16:56:24 +00:00
List < EnteFile > deduplicateByLocalID ( List < EnteFile > files ) {
2022-07-11 04:04:12 +00:00
final localIDs = < String > { } ;
2023-08-24 16:56:24 +00:00
final List < EnteFile > deduplicatedFiles = [ ] ;
2022-07-11 04:04:12 +00:00
for ( final file in files ) {
final id = file . localID ;
2022-12-29 10:55:49 +00:00
if ( id = = null ) {
continue ;
}
if ( localIDs . contains ( id ) ) {
2022-07-11 04:04:12 +00:00
continue ;
}
localIDs . add ( id ) ;
deduplicatedFiles . add ( file ) ;
}
return deduplicatedFiles ;
}
2021-06-29 05:13:16 +00:00
Future < FileLoadResult > getFilesInCollection (
2022-06-11 08:23:52 +00:00
int collectionID ,
int startTime ,
int endTime , {
2022-12-29 10:55:49 +00:00
int ? limit ,
bool ? asc ,
2023-05-25 05:51:56 +00:00
int visibility = visibleVisibility ,
2022-06-11 08:23:52 +00:00
} ) async {
2021-04-20 20:11:39 +00:00
final db = await instance . database ;
2021-06-09 13:45:42 +00:00
final order = ( asc ? ? false ? ' ASC ' : ' DESC ' ) ;
2022-10-26 16:51:42 +00:00
const String whereClause =
' $ columnCollectionID = ? AND $ columnCreationTime >= ? AND $ columnCreationTime <= ? ' ;
final List < Object > whereArgs = [ collectionID , startTime , endTime ] ;
2022-08-27 09:54:06 +00:00
2021-04-20 20:11:39 +00:00
final results = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2022-08-27 09:54:06 +00:00
where: whereClause ,
whereArgs: whereArgs ,
2021-06-09 13:45:42 +00:00
orderBy:
' $ columnCreationTime ' + order + ' , $ columnModificationTime ' + order ,
2021-04-20 20:11:39 +00:00
limit: limit ,
) ;
2022-07-23 05:41:43 +00:00
final files = convertToFiles ( results ) ;
2022-10-27 07:23:45 +00:00
return FileLoadResult ( files , files . length = = limit ) ;
}
2023-08-24 16:56:24 +00:00
Future < List < EnteFile > > getAllFilesCollection ( int collectionID ) async {
2023-01-12 08:27:06 +00:00
final db = await instance . database ;
const String whereClause = ' $ columnCollectionID = ? ' ;
final List < Object > whereArgs = [ collectionID ] ;
final results = await db . query (
filesTable ,
where: whereClause ,
whereArgs: whereArgs ,
) ;
final files = convertToFiles ( results ) ;
return files ;
}
2023-08-24 16:56:24 +00:00
Future < List < EnteFile > > getNewFilesInCollection (
2023-06-25 13:45:34 +00:00
int collectionID ,
2023-06-30 12:47:25 +00:00
int addedTime ,
2023-06-25 13:45:34 +00:00
) async {
final db = await instance . database ;
const String whereClause =
2023-06-30 12:47:25 +00:00
' $ columnCollectionID = ? AND $ columnAddedTime > ? ' ;
final List < Object > whereArgs = [ collectionID , addedTime ] ;
2023-06-25 13:45:34 +00:00
final results = await db . query (
filesTable ,
where: whereClause ,
whereArgs: whereArgs ,
) ;
final files = convertToFiles ( results ) ;
return files ;
}
2022-10-27 07:23:45 +00:00
Future < FileLoadResult > getFilesInCollections (
List < int > collectionIDs ,
int startTime ,
int endTime ,
int userID , {
2022-12-29 10:55:49 +00:00
int ? limit ,
bool ? asc ,
2022-10-27 07:23:45 +00:00
} ) async {
if ( collectionIDs . isEmpty ) {
2023-08-24 16:56:24 +00:00
return FileLoadResult ( < EnteFile > [ ] , false ) ;
2022-10-27 07:23:45 +00:00
}
String inParam = " " ;
for ( final id in collectionIDs ) {
inParam + = " ' " + id . toString ( ) + " ', " ;
}
inParam = inParam . substring ( 0 , inParam . length - 1 ) ;
final db = await instance . database ;
final order = ( asc ? ? false ? ' ASC ' : ' DESC ' ) ;
2022-11-06 08:34:06 +00:00
final String whereClause =
2022-10-27 07:23:45 +00:00
' $ columnCollectionID IN ( $ inParam ) AND $ columnCreationTime >= ? AND '
' $ columnCreationTime <= ? AND $ columnOwnerID = ? ' ;
final List < Object > whereArgs = [ startTime , endTime , userID ] ;
final results = await db . query (
filesTable ,
where: whereClause ,
whereArgs: whereArgs ,
orderBy:
' $ columnCreationTime ' + order + ' , $ columnModificationTime ' + order ,
limit: limit ,
) ;
final files = convertToFiles ( results ) ;
2023-06-20 12:49:45 +00:00
final dedupeResult =
await applyDBFilters ( files , DBFilterOptions . dedupeOption ) ;
2022-10-27 07:23:45 +00:00
_logger . info ( " Fetched " + dedupeResult . length . toString ( ) + " files " ) ;
2021-06-29 05:13:16 +00:00
return FileLoadResult ( files , files . length = = limit ) ;
2021-04-20 20:11:39 +00:00
}
2023-08-24 16:56:24 +00:00
Future < List < EnteFile > > getFilesCreatedWithinDurations (
2022-06-11 08:23:52 +00:00
List < List < int > > durations ,
2022-08-13 13:10:01 +00:00
Set < int > ignoredCollectionIDs , {
2023-11-20 08:57:01 +00:00
int ? visibility ,
2022-08-13 13:10:01 +00:00
String order = ' ASC ' ,
} ) async {
2022-09-16 12:11:16 +00:00
if ( durations . isEmpty ) {
2023-08-24 16:56:24 +00:00
return < EnteFile > [ ] ;
2022-09-16 12:11:16 +00:00
}
2020-07-20 11:53:42 +00:00
final db = await instance . database ;
2022-06-21 13:13:16 +00:00
String whereClause = " ( " ;
2021-04-27 16:02:33 +00:00
for ( int index = 0 ; index < durations . length ; index + + ) {
2022-09-16 15:50:00 +00:00
whereClause + = " ( $ columnCreationTime >= " +
2021-04-27 16:02:33 +00:00
durations [ index ] [ 0 ] . toString ( ) +
" AND $ columnCreationTime < " +
durations [ index ] [ 1 ] . toString ( ) +
" ) " ;
if ( index ! = durations . length - 1 ) {
whereClause + = " OR " ;
2023-11-20 08:57:01 +00:00
} else if ( visibility ! = null ) {
whereClause + = ' AND $ columnMMdVisibility = $ visibility ' ;
2021-04-27 16:02:33 +00:00
}
}
2023-05-30 09:01:56 +00:00
whereClause + = " ) " ;
2020-07-20 11:53:42 +00:00
final results = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2021-07-21 19:55:24 +00:00
where: whereClause ,
2022-08-13 13:10:01 +00:00
orderBy: ' $ columnCreationTime ' + order ,
2020-07-20 11:53:42 +00:00
) ;
2022-07-23 05:41:43 +00:00
final files = convertToFiles ( results ) ;
2023-06-20 12:49:45 +00:00
return applyDBFilters (
files ,
DBFilterOptions ( ignoredCollectionIDs: ignoredCollectionIDs ) ,
) ;
2020-07-20 11:53:42 +00:00
}
2022-09-10 04:36:41 +00:00
// Files which user added to a collection manually but they are not
// uploaded yet or files belonging to a collection which is marked for backup
2023-08-24 16:56:24 +00:00
Future < List < EnteFile > > getFilesPendingForUpload ( ) async {
2022-02-13 09:12:05 +00:00
final db = await instance . database ;
final results = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2022-02-13 09:12:05 +00:00
where:
' ( $ columnUploadedFileID IS NULL OR $ columnUploadedFileID IS -1) AND '
2022-02-13 09:23:10 +00:00
' $ columnCollectionID IS NOT NULL AND $ columnCollectionID IS NOT -1 AND '
2022-02-13 09:12:05 +00:00
' $ columnLocalID IS NOT NULL AND $ columnLocalID IS NOT -1 ' ,
orderBy: ' $ columnCreationTime DESC ' ,
groupBy: columnLocalID ,
) ;
2022-08-30 07:33:54 +00:00
final files = convertToFiles ( results ) ;
2022-02-13 11:05:11 +00:00
// future-safe filter just to ensure that the query doesn't end up returning files
// which should not be backed up
2022-06-11 08:23:52 +00:00
files . removeWhere (
( e ) = >
e . collectionID = = null | |
e . localID = = null | |
e . uploadedFileID ! = null ,
) ;
2022-02-13 11:05:11 +00:00
return files ;
2022-02-13 09:12:05 +00:00
}
2023-08-24 16:56:24 +00:00
Future < List < EnteFile > > getUnUploadedLocalFiles ( ) async {
2021-07-01 11:06:20 +00:00
final db = await instance . database ;
final results = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2021-07-01 11:06:20 +00:00
where:
' ( $ columnUploadedFileID IS NULL OR $ columnUploadedFileID IS -1) AND $ columnLocalID IS NOT NULL ' ,
orderBy: ' $ columnCreationTime DESC ' ,
2021-07-21 19:55:24 +00:00
groupBy: columnLocalID ,
2021-06-04 19:11:39 +00:00
) ;
2022-07-23 05:41:43 +00:00
return convertToFiles ( results ) ;
2021-06-04 19:11:39 +00:00
}
2022-08-26 07:04:41 +00:00
Future < List < int > > getUploadedFileIDsToBeUpdated ( int ownerID ) async {
2020-11-30 18:42:11 +00:00
final db = await instance . database ;
final rows = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2020-11-30 18:42:11 +00:00
columns: [ columnUploadedFileID ] ,
2022-08-26 07:04:41 +00:00
where: ' ( $ columnLocalID IS NOT NULL AND $ columnOwnerID = ? AND '
' ( $ columnUploadedFileID '
' IS NOT '
' NULL AND $ columnUploadedFileID IS NOT -1) AND $ columnUpdationTime IS NULL) ' ,
whereArgs: [ ownerID ] ,
2020-11-30 18:42:11 +00:00
orderBy: ' $ columnCreationTime DESC ' ,
distinct: true ,
) ;
2021-07-21 19:55:24 +00:00
final uploadedFileIDs = < int > [ ] ;
2020-11-30 18:42:11 +00:00
for ( final row in rows ) {
2022-12-29 10:55:49 +00:00
uploadedFileIDs . add ( row [ columnUploadedFileID ] as int ) ;
2020-11-30 18:42:11 +00:00
}
return uploadedFileIDs ;
}
2023-12-01 11:51:16 +00:00
Future < List < EnteFile > > getFilesInAllCollection (
2023-05-03 12:14:59 +00:00
int uploadedFileID ,
int userID ,
) async {
2020-11-30 18:42:11 +00:00
final db = await instance . database ;
final results = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2023-05-03 12:14:59 +00:00
where: ' $ columnLocalID IS NOT NULL AND $ columnOwnerID = ? AND '
' $ columnUploadedFileID = ? ' ,
2020-11-30 18:42:11 +00:00
whereArgs: [
2023-05-03 12:14:59 +00:00
userID ,
2020-11-30 18:42:11 +00:00
uploadedFileID ,
] ,
) ;
if ( results . isEmpty ) {
2023-12-01 11:51:16 +00:00
return < EnteFile > [ ] ;
2020-11-30 18:42:11 +00:00
}
2023-12-01 11:51:16 +00:00
return convertToFiles ( results ) ;
2020-11-30 18:42:11 +00:00
}
2023-01-30 06:19:58 +00:00
Future < Set < String > > getExistingLocalFileIDs ( int ownerID ) async {
2020-11-30 18:42:11 +00:00
final db = await instance . database ;
final rows = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2020-11-30 18:42:11 +00:00
columns: [ columnLocalID ] ,
distinct: true ,
2023-01-30 06:19:58 +00:00
where: ' $ columnLocalID IS NOT NULL AND ( $ columnOwnerID IS NULL OR '
' $ columnOwnerID = ?) ' ,
whereArgs: [ ownerID ] ,
2020-11-30 18:42:11 +00:00
) ;
2021-07-21 19:55:24 +00:00
final result = < String > { } ;
2020-11-30 18:42:11 +00:00
for ( final row in rows ) {
2022-12-29 10:55:49 +00:00
result . add ( row [ columnLocalID ] as String ) ;
2020-11-30 18:42:11 +00:00
}
return result ;
}
2022-09-07 05:28:50 +00:00
Future < Set < String > > getLocalIDsMarkedForOrAlreadyUploaded ( int ownerID ) async {
final db = await instance . database ;
final rows = await db . query (
filesTable ,
columns: [ columnLocalID ] ,
distinct: true ,
where: ' $ columnLocalID IS NOT NULL AND ( $ columnCollectionID IS NOT NULL '
' AND '
' $ columnCollectionID != -1) AND ( $ columnOwnerID = ? OR '
' $ columnOwnerID IS NULL) ' ,
whereArgs: [ ownerID ] ,
) ;
final result = < String > { } ;
for ( final row in rows ) {
2022-12-29 10:55:49 +00:00
result . add ( row [ columnLocalID ] as String ) ;
2022-09-07 05:28:50 +00:00
}
return result ;
}
2022-08-26 09:21:44 +00:00
Future < Set < String > > getLocalFileIDsForCollection ( int collectionID ) async {
final db = await instance . database ;
final rows = await db . query (
filesTable ,
columns: [ columnLocalID ] ,
where: ' $ columnLocalID IS NOT NULL AND $ columnCollectionID = ? ' ,
whereArgs: [ collectionID ] ,
) ;
final result = < String > { } ;
for ( final row in rows ) {
2022-12-29 10:55:49 +00:00
result . add ( row [ columnLocalID ] as String ) ;
2022-08-26 09:21:44 +00:00
}
return result ;
}
2022-08-26 11:00:22 +00:00
// Sets the collectionID for the files with given LocalIDs if the
// corresponding file entries are not already mapped to some other collection
Future < int > setCollectionIDForUnMappedLocalFiles (
int collectionID ,
Set < String > localIDs ,
) async {
final db = await instance . database ;
String inParam = " " ;
for ( final localID in localIDs ) {
inParam + = " ' " + localID + " ', " ;
}
inParam = inParam . substring ( 0 , inParam . length - 1 ) ;
return await db . rawUpdate (
'''
UPDATE $filesTable
SET $columnCollectionID = $collectionID
WHERE $columnLocalID IN ( $inParam ) AND ( $columnCollectionID IS NULL OR
$columnCollectionID = - 1 ) ;
''' ,
) ;
}
2023-08-22 15:05:29 +00:00
Future < int > markFilesForReUpload (
int ownerID ,
2020-11-30 18:42:11 +00:00
String localID ,
2022-12-30 09:44:52 +00:00
String ? title ,
Location ? location ,
2020-11-30 18:42:11 +00:00
int creationTime ,
int modificationTime ,
2023-08-22 15:05:29 +00:00
FileType fileType ,
2020-11-30 18:42:11 +00:00
) async {
final db = await instance . database ;
return await db . update (
2022-07-23 05:41:43 +00:00
filesTable ,
2020-11-30 18:42:11 +00:00
{
columnTitle: title ,
2022-12-30 09:44:52 +00:00
columnLatitude: location ? . latitude ,
columnLongitude: location ? . longitude ,
2020-11-30 18:42:11 +00:00
columnCreationTime: creationTime ,
columnModificationTime: modificationTime ,
2023-08-22 15:05:29 +00:00
// #hack reset updation time to null for re-upload
columnUpdationTime: null ,
columnFileType: getInt ( fileType ) ,
2020-11-30 18:42:11 +00:00
} ,
2023-08-22 15:05:29 +00:00
where:
' $ columnLocalID = ? AND ( $ columnOwnerID = ? OR $ columnOwnerID IS NULL) ' ,
whereArgs: [ localID , ownerID ] ,
2020-11-30 18:42:11 +00:00
) ;
}
2022-09-04 11:42:22 +00:00
/ *
This method should only return localIDs which are not uploaded yet
and can be mapped to incoming remote entry
* /
2023-08-24 16:56:24 +00:00
Future < List < EnteFile > > getUnlinkedLocalMatchesForRemoteFile (
2022-09-04 11:42:22 +00:00
int ownerID ,
String localID ,
FileType fileType , {
2022-12-29 10:55:49 +00:00
required String title ,
required String deviceFolder ,
2022-09-04 11:42:22 +00:00
} ) async {
final db = await instance . database ;
// on iOS, match using localID and fileType. title can either match or
// might be null based on how the file was imported
String whereClause = ''' ( $ columnOwnerID = ? OR $ columnOwnerID IS NULL) AND
2022-09-09 11:51:11 +00:00
$columnLocalID = ? AND $columnFileType = ? AND
2022-09-04 11:42:22 +00:00
( $columnTitle = ? OR $columnTitle IS NULL ) ''' ;
List < Object > whereArgs = [
ownerID ,
localID ,
getInt ( fileType ) ,
title ,
] ;
2023-08-24 16:56:24 +00:00
if ( Platform . isAndroid ) {
2022-09-04 12:15:08 +00:00
whereClause = ''' ( $ columnOwnerID = ? OR $ columnOwnerID IS NULL) AND
$columnLocalID = ? AND $columnFileType = ? AND $columnTitle = ? AND $columnDeviceFolder = ?
2022-09-04 11:42:22 +00:00
''' ;
whereArgs = [
ownerID ,
localID ,
getInt ( fileType ) ,
title ,
deviceFolder ,
] ;
}
final rows = await db . query (
2022-09-06 16:44:25 +00:00
filesTable ,
2022-09-04 11:42:22 +00:00
where: whereClause ,
whereArgs: whereArgs ,
) ;
2022-09-06 16:44:25 +00:00
return convertToFiles ( rows ) ;
2022-09-04 11:42:22 +00:00
}
2023-08-24 16:56:24 +00:00
Future < List < EnteFile > > getUploadedFilesWithHashes (
2022-08-29 07:58:49 +00:00
FileHashData hashData ,
2022-08-05 09:50:03 +00:00
FileType fileType ,
int ownerID ,
) async {
2022-08-29 07:58:49 +00:00
String inParam = " ' ${ hashData . fileHash } ' " ;
if ( fileType = = FileType . livePhoto & & hashData . zipHash ! = null ) {
inParam + = " ,' ${ hashData . zipHash } ' " ;
2022-08-05 09:50:03 +00:00
}
final db = await instance . database ;
2022-08-29 07:58:49 +00:00
final rows = await db . query (
2022-08-29 18:02:00 +00:00
filesTable ,
2022-08-29 07:58:49 +00:00
where: ' ( $ columnUploadedFileID != NULL OR $ columnUploadedFileID != -1) '
' AND $ columnOwnerID = ? AND $ columnFileType = '
' ? '
' AND $ columnHash IN ( $ inParam ) ' ,
whereArgs: [
ownerID ,
getInt ( fileType ) ,
] ,
) ;
2022-08-29 18:02:00 +00:00
return convertToFiles ( rows ) ;
2022-08-05 09:50:03 +00:00
}
2023-08-24 16:56:24 +00:00
Future < int > update ( EnteFile file ) async {
2020-05-06 18:13:24 +00:00
final db = await instance . database ;
return await db . update (
2022-07-23 05:41:43 +00:00
filesTable ,
2020-10-24 23:39:46 +00:00
_getRowForFile ( file ) ,
2020-08-09 22:34:59 +00:00
where: ' $ columnGeneratedID = ? ' ,
2020-10-24 23:39:46 +00:00
whereArgs: [ file . generatedID ] ,
2020-05-06 18:13:24 +00:00
) ;
2020-03-24 19:59:36 +00:00
}
2023-08-24 16:56:24 +00:00
Future < int > updateUploadedFileAcrossCollections ( EnteFile file ) async {
2020-11-30 18:42:11 +00:00
final db = await instance . database ;
return await db . update (
2022-07-23 05:41:43 +00:00
filesTable ,
2020-11-30 18:42:11 +00:00
_getRowForFileWithoutCollection ( file ) ,
where: ' $ columnUploadedFileID = ? ' ,
whereArgs: [ file . uploadedFileID ] ,
) ;
}
2022-09-02 07:42:46 +00:00
Future < int > updateLocalIDForUploaded ( int uploadedID , String localID ) async {
final db = await instance . database ;
return await db . update (
2022-09-06 16:44:25 +00:00
filesTable ,
2022-09-02 07:42:46 +00:00
{ columnLocalID: localID } ,
where: ' $ columnUploadedFileID = ? AND $ columnLocalID IS NULL ' ,
whereArgs: [ uploadedID ] ,
) ;
}
2021-04-27 20:49:00 +00:00
Future < int > delete ( int uploadedFileID ) async {
2020-05-06 18:13:24 +00:00
final db = await instance . database ;
2021-04-27 20:49:00 +00:00
return db . delete (
2022-07-23 05:41:43 +00:00
filesTable ,
2020-10-30 23:25:28 +00:00
where: ' $ columnUploadedFileID =? ' ,
whereArgs: [ uploadedFileID ] ,
2020-05-06 18:13:24 +00:00
) ;
2020-04-12 12:38:49 +00:00
}
2022-08-05 09:50:03 +00:00
Future < int > deleteByGeneratedID ( int genID ) async {
final db = await instance . database ;
return db . delete (
2022-08-05 11:54:23 +00:00
filesTable ,
2022-08-05 09:50:03 +00:00
where: ' $ columnGeneratedID =? ' ,
whereArgs: [ genID ] ,
) ;
}
2021-04-27 20:49:00 +00:00
Future < int > deleteMultipleUploadedFiles ( List < int > uploadedFileIDs ) async {
2020-05-06 18:13:24 +00:00
final db = await instance . database ;
2021-04-27 22:17:19 +00:00
return await db . delete (
2022-07-23 05:41:43 +00:00
filesTable ,
2021-04-27 22:17:19 +00:00
where: ' $ columnUploadedFileID IN ( ${ uploadedFileIDs . join ( ' , ' ) } ) ' ,
2020-05-06 18:13:24 +00:00
) ;
}
2022-09-09 09:34:09 +00:00
Future < int > deleteMultipleByGeneratedIDs ( List < int > generatedIDs ) async {
if ( generatedIDs . isEmpty ) {
return 0 ;
}
final db = await instance . database ;
return await db . delete (
filesTable ,
where: ' $ columnGeneratedID IN ( ${ generatedIDs . join ( ' , ' ) } ) ' ,
) ;
}
2023-08-24 16:56:24 +00:00
Future < int > deleteLocalFile ( EnteFile file ) async {
2020-11-01 07:37:23 +00:00
final db = await instance . database ;
2021-07-24 17:22:46 +00:00
if ( file . localID ! = null ) {
// delete all files with same local ID
return db . delete (
2022-07-23 05:41:43 +00:00
filesTable ,
2021-07-24 17:22:46 +00:00
where: ' $ columnLocalID =? ' ,
whereArgs: [ file . localID ] ,
) ;
} else {
return db . delete (
2022-07-23 05:41:43 +00:00
filesTable ,
2021-07-24 17:22:46 +00:00
where: ' $ columnGeneratedID =? ' ,
whereArgs: [ file . generatedID ] ,
) ;
}
2020-11-01 07:37:23 +00:00
}
2021-06-28 10:12:12 +00:00
Future < void > deleteLocalFiles ( List < String > localIDs ) async {
String inParam = " " ;
for ( final localID in localIDs ) {
inParam + = " ' " + localID + " ', " ;
}
inParam = inParam . substring ( 0 , inParam . length - 1 ) ;
final db = await instance . database ;
2022-06-11 08:23:52 +00:00
await db . rawQuery (
'''
2022-07-23 05:41:43 +00:00
UPDATE $filesTable
2021-06-28 10:12:12 +00:00
SET $columnLocalID = NULL
WHERE $columnLocalID IN ( $inParam ) ;
2022-06-11 08:23:52 +00:00
''' ,
) ;
2021-06-28 10:12:12 +00:00
}
2023-08-24 16:56:24 +00:00
Future < List < EnteFile > > getLocalFiles ( List < String > localIDs ) async {
2021-06-28 10:12:12 +00:00
String inParam = " " ;
for ( final localID in localIDs ) {
inParam + = " ' " + localID + " ', " ;
}
inParam = inParam . substring ( 0 , inParam . length - 1 ) ;
final db = await instance . database ;
final results = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2021-06-28 10:12:12 +00:00
where: ' $ columnLocalID IN ( $ inParam ) ' ,
) ;
2022-07-23 05:41:43 +00:00
return convertToFiles ( results ) ;
2021-06-28 10:12:12 +00:00
}
2021-10-20 10:58:11 +00:00
Future < int > deleteUnSyncedLocalFiles ( List < String > localIDs ) async {
String inParam = " " ;
for ( final localID in localIDs ) {
inParam + = " ' " + localID + " ', " ;
}
inParam = inParam . substring ( 0 , inParam . length - 1 ) ;
final db = await instance . database ;
return db . delete (
2022-07-23 05:41:43 +00:00
filesTable ,
2021-10-20 10:58:11 +00:00
where:
' ( $ columnUploadedFileID is NULL OR $ columnUploadedFileID = -1 ) AND $ columnLocalID IN ( $ inParam ) ' ,
) ;
}
2020-10-23 14:59:51 +00:00
Future < int > deleteFromCollection ( int uploadedFileID , int collectionID ) async {
final db = await instance . database ;
return db . delete (
2022-07-23 05:41:43 +00:00
filesTable ,
2020-10-23 14:59:51 +00:00
where: ' $ columnUploadedFileID = ? AND $ columnCollectionID = ? ' ,
whereArgs: [ uploadedFileID , collectionID ] ,
) ;
}
2021-09-30 09:28:29 +00:00
Future < int > deleteFilesFromCollection (
2022-06-11 08:23:52 +00:00
int collectionID ,
List < int > uploadedFileIDs ,
) async {
2021-09-30 09:28:29 +00:00
final db = await instance . database ;
return db . delete (
2022-07-23 05:41:43 +00:00
filesTable ,
2021-09-30 09:28:29 +00:00
where:
' $ columnCollectionID = ? AND $ columnUploadedFileID IN ( ${ uploadedFileIDs . join ( ' , ' ) } ) ' ,
whereArgs: [ collectionID ] ,
) ;
}
2022-05-05 06:46:31 +00:00
Future < int > collectionFileCount ( int collectionID ) async {
final db = await instance . database ;
2022-08-29 14:43:31 +00:00
final count = Sqflite . firstIntValue (
2022-06-11 08:23:52 +00:00
await db . rawQuery (
2022-11-17 12:00:31 +00:00
' SELECT COUNT(*) FROM $ filesTable where $ columnCollectionID = '
' $ collectionID AND $ columnUploadedFileID IS NOT -1 ' ,
2022-06-11 08:23:52 +00:00
) ,
) ;
2022-12-29 10:55:49 +00:00
return count ? ? 0 ;
2022-05-05 06:46:31 +00:00
}
2023-02-23 07:53:41 +00:00
Future < int > archivedFilesCount (
int visibility ,
int ownerID ,
Set < int > hiddenCollections ,
) async {
2022-05-05 06:46:31 +00:00
final db = await instance . database ;
2022-08-29 14:43:31 +00:00
final count = Sqflite . firstIntValue (
2022-06-11 08:23:52 +00:00
await db . rawQuery (
2022-10-26 16:51:42 +00:00
' SELECT COUNT(distinct( $ columnUploadedFileID )) FROM $ filesTable where '
' $ columnMMdVisibility '
2023-02-23 07:53:41 +00:00
' = $ visibility AND $ columnOwnerID = $ ownerID AND $ columnCollectionID NOT IN ( ${ hiddenCollections . join ( ' , ' ) } ) ' ,
2022-06-11 08:23:52 +00:00
) ,
) ;
2022-12-29 10:55:49 +00:00
return count ? ? 0 ;
2022-05-05 06:46:31 +00:00
}
2020-10-31 12:48:41 +00:00
Future < int > deleteCollection ( int collectionID ) async {
final db = await instance . database ;
return db . delete (
2022-07-23 05:41:43 +00:00
filesTable ,
2020-10-31 12:48:41 +00:00
where: ' $ columnCollectionID = ? ' ,
whereArgs: [ collectionID ] ,
) ;
}
2020-10-28 14:07:32 +00:00
Future < int > removeFromCollection ( int collectionID , List < int > fileIDs ) async {
2020-05-22 18:22:55 +00:00
final db = await instance . database ;
return db . delete (
2022-07-23 05:41:43 +00:00
filesTable ,
2020-10-28 15:25:32 +00:00
where:
' $ columnCollectionID =? AND $ columnUploadedFileID IN ( ${ fileIDs . join ( ' , ' ) } ) ' ,
2020-10-28 14:07:32 +00:00
whereArgs: [ collectionID ] ,
2020-05-22 18:22:55 +00:00
) ;
}
2023-08-24 16:56:24 +00:00
Future < List < EnteFile > > getPendingUploadForCollection ( int collectionID ) async {
2022-09-09 09:34:09 +00:00
final db = await instance . database ;
final results = await db . query (
filesTable ,
where: ' $ columnCollectionID = ? AND ( $ columnUploadedFileID IS NULL OR '
' $ columnUploadedFileID = -1) ' ,
whereArgs: [ collectionID ] ,
) ;
return convertToFiles ( results ) ;
}
Future < Set < String > > getLocalIDsPresentInEntries (
2023-08-24 16:56:24 +00:00
List < EnteFile > existingFiles ,
2022-09-09 09:34:09 +00:00
int collectionID ,
) async {
String inParam = " " ;
for ( final existingFile in existingFiles ) {
2022-12-29 10:55:49 +00:00
if ( existingFile . localID ! = null ) {
inParam + = " ' " + existingFile . localID ! + " ', " ;
}
2022-09-09 09:34:09 +00:00
}
inParam = inParam . substring ( 0 , inParam . length - 1 ) ;
final db = await instance . database ;
final rows = await db . rawQuery (
'''
SELECT $columnLocalID
FROM $filesTable
WHERE $columnLocalID IN ( $inParam ) AND $columnCollectionID ! =
$collectionID AND $columnLocalID IS NOT NULL ;
''' ,
) ;
final result = < String > { } ;
for ( final row in rows ) {
2022-12-29 10:55:49 +00:00
result . add ( row [ columnLocalID ] as String ) ;
2022-09-09 09:34:09 +00:00
}
return result ;
}
2023-06-19 10:28:15 +00:00
// getCollectionLatestFileTime returns map of collectionID to the max
// creationTime of the files in the collection.
Future < Map < int , int > > getCollectionIDToMaxCreationTime ( ) async {
2023-06-22 07:32:26 +00:00
final enteWatch = EnteWatch ( " getCollectionIDToMaxCreationTime " ) . . start ( ) ;
2023-06-19 10:28:15 +00:00
final db = await instance . database ;
final rows = await db . rawQuery (
'''
SELECT $columnCollectionID , MAX ( $columnCreationTime ) AS max_creation_time
FROM $filesTable
WHERE
( $columnCollectionID IS NOT NULL AND $columnCollectionID IS NOT - 1
AND $columnUploadedFileID IS NOT NULL AND $columnUploadedFileID IS
NOT - 1 )
GROUP BY $columnCollectionID ;
''' ,
) ;
final result = < int , int > { } ;
for ( final row in rows ) {
result [ row [ columnCollectionID ] as int ] = row [ ' max_creation_time ' ] as int ;
}
2023-06-22 07:32:26 +00:00
enteWatch . log ( " query done " ) ;
2023-06-19 10:28:15 +00:00
return result ;
}
2023-06-19 05:09:03 +00:00
// getCollectionFileFirstOrLast returns the first or last uploaded file in
// the collection based on the given collectionID and the order.
2023-08-24 16:56:24 +00:00
Future < EnteFile ? > getCollectionFileFirstOrLast (
2023-06-19 05:09:03 +00:00
int collectionID ,
bool sortAsc ,
) async {
final db = await instance . database ;
final order = sortAsc ? ' ASC ' : ' DESC ' ;
final rows = await db . query (
filesTable ,
2023-08-21 06:37:49 +00:00
where: ' $ columnCollectionID = ? AND ( $ columnUploadedFileID IS NOT NULL '
' AND $ columnUploadedFileID IS NOT -1) ' ,
2023-06-19 05:09:03 +00:00
whereArgs: [ collectionID ] ,
orderBy:
' $ columnCreationTime ' + order + ' , $ columnModificationTime ' + order ,
limit: 1 ,
) ;
if ( rows . isEmpty ) {
return null ;
}
return convertToFiles ( rows ) . first ;
}
2022-06-08 08:49:23 +00:00
Future < void > markForReUploadIfLocationMissing ( List < String > localIDs ) async {
if ( localIDs . isEmpty ) {
return ;
}
String inParam = " " ;
for ( final localID in localIDs ) {
inParam + = " ' " + localID + " ', " ;
}
inParam = inParam . substring ( 0 , inParam . length - 1 ) ;
final db = await instance . database ;
2022-06-11 08:23:52 +00:00
await db . rawUpdate (
'''
2022-07-23 05:41:43 +00:00
UPDATE $filesTable
2022-06-08 08:49:23 +00:00
SET $columnUpdationTime = NULL
WHERE $columnLocalID IN ( $inParam )
2022-06-08 10:29:29 +00:00
AND ( $columnLatitude IS NULL OR $columnLongitude IS NULL OR $columnLongitude = 0.0 or $columnLongitude = 0.0 ) ;
2022-06-11 08:23:52 +00:00
''' ,
) ;
2022-06-08 08:49:23 +00:00
}
2020-10-30 20:17:06 +00:00
Future < bool > doesFileExistInCollection (
2022-06-11 08:23:52 +00:00
int uploadedFileID ,
int collectionID ,
) async {
2020-10-30 20:17:06 +00:00
final db = await instance . database ;
final rows = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2020-10-30 20:17:06 +00:00
where: ' $ columnUploadedFileID = ? AND $ columnCollectionID = ? ' ,
whereArgs: [ uploadedFileID , collectionID ] ,
limit: 1 ,
) ;
return rows . isNotEmpty ;
}
2023-08-24 16:56:24 +00:00
Future < Map < int , EnteFile > > getFilesFromIDs ( List < int > ids ) async {
final result = < int , EnteFile > { } ;
2021-09-24 13:39:51 +00:00
if ( ids . isEmpty ) {
return result ;
}
2021-09-14 18:28:14 +00:00
String inParam = " " ;
for ( final id in ids ) {
inParam + = " ' " + id . toString ( ) + " ', " ;
}
inParam = inParam . substring ( 0 , inParam . length - 1 ) ;
final db = await instance . database ;
final results = await db . query (
2022-07-23 05:41:43 +00:00
filesTable ,
2021-09-14 18:28:14 +00:00
where: ' $ columnUploadedFileID IN ( $ inParam ) ' ,
) ;
2022-07-23 05:41:43 +00:00
final files = convertToFiles ( results ) ;
2021-09-14 18:28:14 +00:00
for ( final file in files ) {
2022-12-29 10:55:49 +00:00
result [ file . uploadedFileID ! ] = file ;
2021-09-14 18:28:14 +00:00
}
return result ;
}
2023-08-24 16:56:24 +00:00
Future < Map < int , EnteFile > > getFilesFromGeneratedIDs ( List < int > ids ) async {
final result = < int , EnteFile > { } ;
2022-11-14 09:33:16 +00:00
if ( ids . isEmpty ) {
return result ;
}
String inParam = " " ;
for ( final id in ids ) {
inParam + = " ' " + id . toString ( ) + " ', " ;
}
inParam = inParam . substring ( 0 , inParam . length - 1 ) ;
final db = await instance . database ;
final results = await db . query (
filesTable ,
where: ' $ columnGeneratedID IN ( $ inParam ) ' ,
) ;
final files = convertToFiles ( results ) ;
for ( final file in files ) {
2022-12-29 10:55:49 +00:00
result [ file . generatedID as int ] = file ;
2022-11-14 09:33:16 +00:00
}
return result ;
}
2023-08-24 16:56:24 +00:00
Future < Map < int , List < EnteFile > > > getAllFilesGroupByCollectionID (
2022-11-06 08:22:54 +00:00
List < int > ids ,
) async {
2023-08-24 16:56:24 +00:00
final result = < int , List < EnteFile > > { } ;
2022-10-27 06:05:39 +00:00
if ( ids . isEmpty ) {
return result ;
}
String inParam = " " ;
for ( final id in ids ) {
inParam + = " ' " + id . toString ( ) + " ', " ;
}
inParam = inParam . substring ( 0 , inParam . length - 1 ) ;
final db = await instance . database ;
final results = await db . query (
filesTable ,
where: ' $ columnUploadedFileID IN ( $ inParam ) ' ,
) ;
final files = convertToFiles ( results ) ;
2023-08-24 16:56:24 +00:00
for ( EnteFile eachFile in files ) {
2022-10-27 06:05:39 +00:00
if ( ! result . containsKey ( eachFile . collectionID ) ) {
2023-08-24 16:56:24 +00:00
result [ eachFile . collectionID as int ] = < EnteFile > [ ] ;
2022-10-27 06:05:39 +00:00
}
2022-12-29 10:55:49 +00:00
result [ eachFile . collectionID ] ! . add ( eachFile ) ;
2022-10-27 06:05:39 +00:00
}
return result ;
}
2022-09-06 11:27:39 +00:00
Future < Set < int > > getAllCollectionIDsOfFile (
int uploadedFileID ,
) async {
final db = await instance . database ;
final results = await db . query (
2022-09-07 08:19:13 +00:00
filesTable ,
2022-09-07 01:15:42 +00:00
where: ' $ columnUploadedFileID = ? AND $ columnCollectionID != -1 ' ,
2022-09-06 11:27:39 +00:00
columns: [ columnCollectionID ] ,
2022-09-07 01:15:42 +00:00
whereArgs: [ uploadedFileID ] ,
2022-09-06 11:27:39 +00:00
distinct: true ,
) ;
2022-09-07 01:56:51 +00:00
final collectionIDsOfFile = < int > { } ;
2022-09-06 11:27:39 +00:00
for ( var result in results ) {
2022-12-29 10:55:49 +00:00
collectionIDsOfFile . add ( result [ ' collection_id ' ] as int ) ;
2022-09-06 11:27:39 +00:00
}
return collectionIDsOfFile ;
}
2023-08-24 16:56:24 +00:00
List < EnteFile > convertToFiles ( List < Map < String , dynamic > > results ) {
final List < EnteFile > files = [ ] ;
2020-07-20 11:49:00 +00:00
for ( final result in results ) {
2020-06-19 23:03:26 +00:00
files . add ( _getFileFromRow ( result ) ) ;
2020-03-28 13:56:06 +00:00
}
2020-06-19 23:03:26 +00:00
return files ;
2020-03-28 13:56:06 +00:00
}
2020-03-30 14:28:46 +00:00
2022-11-14 09:33:16 +00:00
Future < List < String > > getGeneratedIDForFilesOlderThan (
int cutOffTime ,
int ownerID ,
) async {
final db = await instance . database ;
final rows = await db . query (
filesTable ,
columns: [ columnGeneratedID ] ,
distinct: true ,
where:
' $ columnCreationTime <= ? AND ( $ columnOwnerID IS NULL OR $ columnOwnerID = ?) ' ,
whereArgs: [ cutOffTime , ownerID ] ,
) ;
final result = < String > [ ] ;
for ( final row in rows ) {
result . add ( row [ columnGeneratedID ] . toString ( ) ) ;
}
return result ;
}
2023-04-18 15:28:46 +00:00
// For givenUserID, get List of unique LocalIDs for files which are
// uploaded by the given user and location is missing
Future < List < String > > getLocalIDsForFilesWithoutLocation ( int ownerID ) async {
final db = await instance . database ;
final rows = await db . query (
filesTable ,
columns: [ columnLocalID ] ,
distinct: true ,
where: ' $ columnOwnerID = ? AND $ columnLocalID IS NOT NULL AND '
' ( $ columnLatitude IS NULL OR '
' $ columnLongitude IS NULL OR $ columnLongitude = 0.0 or $ columnLongitude = 0.0) ' ,
whereArgs: [ ownerID ] ,
) ;
final result = < String > [ ] ;
for ( final row in rows ) {
result . add ( row [ columnLocalID ] . toString ( ) ) ;
}
return result ;
}
2023-05-31 02:54:12 +00:00
// For a given userID, return unique uploadedFileId for the given userID
Future < List < int > > getUploadIDsWithMissingSize ( int userId ) async {
final db = await instance . database ;
final rows = await db . query (
filesTable ,
columns: [ columnUploadedFileID ] ,
distinct: true ,
where: ' $ columnOwnerID = ? AND $ columnFileSize IS NULL ' ,
whereArgs: [ userId ] ,
) ;
final result = < int > [ ] ;
for ( final row in rows ) {
result . add ( row [ columnUploadedFileID ] as int ) ;
}
return result ;
}
2023-05-31 04:40:59 +00:00
// updateSizeForUploadIDs takes a map of upploadedFileID and fileSize and
// update the fileSize for the given uploadedFileID
Future < void > updateSizeForUploadIDs (
Map < int , int > uploadedFileIDToSize ,
) async {
if ( uploadedFileIDToSize . isEmpty ) {
return ;
}
final db = await instance . database ;
final batch = db . batch ( ) ;
for ( final uploadedFileID in uploadedFileIDToSize . keys ) {
batch . update (
filesTable ,
{ columnFileSize: uploadedFileIDToSize [ uploadedFileID ] } ,
where: ' $ columnUploadedFileID = ? ' ,
whereArgs: [ uploadedFileID ] ,
) ;
}
await batch . commit ( noResult: true ) ;
}
2023-08-24 16:56:24 +00:00
Future < List < EnteFile > > getAllFilesFromDB ( Set < int > collectionsToIgnore ) async {
2022-08-01 15:36:24 +00:00
final db = await instance . database ;
2023-04-18 07:21:27 +00:00
final List < Map < String , dynamic > > result =
await db . query ( filesTable , orderBy: ' $ columnCreationTime DESC ' ) ;
2023-08-24 16:56:24 +00:00
final List < EnteFile > files = convertToFiles ( result ) ;
final List < EnteFile > deduplicatedFiles = await applyDBFilters (
2023-06-20 12:49:45 +00:00
files ,
DBFilterOptions ( ignoredCollectionIDs: collectionsToIgnore ) ,
) ;
2022-08-04 05:59:15 +00:00
return deduplicatedFiles ;
2022-08-01 15:36:24 +00:00
}
2022-10-26 04:08:26 +00:00
Future < Map < FileType , int > > fetchFilesCountbyType ( int userID ) async {
2022-10-18 08:31:58 +00:00
final db = await instance . database ;
final result = await db . rawQuery (
2022-10-20 10:11:57 +00:00
" SELECT $ columnFileType , COUNT(DISTINCT $ columnUploadedFileID ) FROM $ filesTable WHERE $ columnUploadedFileID != -1 AND $ columnOwnerID == $ userID GROUP BY $ columnFileType " ,
2022-10-18 08:31:58 +00:00
) ;
2022-10-21 05:44:14 +00:00
2022-10-26 04:08:26 +00:00
final filesCount = < FileType , int > { } ;
2022-10-18 08:31:58 +00:00
for ( var e in result ) {
2022-12-29 10:55:49 +00:00
filesCount . addAll (
{ getFileType ( e [ columnFileType ] as int ) : e . values . last as int } ,
) ;
2022-10-18 08:31:58 +00:00
}
2022-10-21 05:44:14 +00:00
return filesCount ;
2022-10-18 08:31:58 +00:00
}
2023-04-13 10:17:55 +00:00
Future < FileLoadResult > fetchAllUploadedAndSharedFilesWithLocation (
2023-04-10 04:30:30 +00:00
int startTime ,
int endTime , {
int ? limit ,
bool ? asc ,
2023-06-20 12:49:45 +00:00
required DBFilterOptions ? filterOptions ,
2023-04-10 04:30:30 +00:00
} ) async {
final db = await instance . database ;
final order = ( asc ? ? false ? ' ASC ' : ' DESC ' ) ;
final results = await db . query (
filesTable ,
where:
' $ columnLatitude IS NOT NULL AND $ columnLongitude IS NOT NULL AND ( $ columnLatitude IS NOT 0 OR $ columnLongitude IS NOT 0) '
2023-05-30 09:17:20 +00:00
' AND $ columnCreationTime >= ? AND $ columnCreationTime <= ? '
2023-04-10 04:30:30 +00:00
' AND ( $ columnLocalID IS NOT NULL OR ( $ columnCollectionID IS NOT NULL AND $ columnCollectionID IS NOT -1)) ' ,
2023-05-30 09:17:20 +00:00
whereArgs: [ startTime , endTime ] ,
2023-04-10 04:30:30 +00:00
orderBy:
' $ columnCreationTime ' + order + ' , $ columnModificationTime ' + order ,
limit: limit ,
) ;
final files = convertToFiles ( results ) ;
2023-08-26 05:44:05 +00:00
final List < EnteFile > filteredFiles =
await applyDBFilters ( files , filterOptions ) ;
2023-06-20 12:49:45 +00:00
return FileLoadResult ( filteredFiles , files . length = = limit ) ;
2023-04-10 04:30:30 +00:00
}
2023-11-14 07:56:54 +00:00
Future < List < int > > getOwnedFileIDs ( int ownerID ) async {
2023-09-22 15:39:03 +00:00
final db = await instance . database ;
final results = await db . query (
2023-11-14 07:56:54 +00:00
filesTable ,
columns: [ columnUploadedFileID ] ,
where:
' ( $ columnOwnerID = $ ownerID AND $ columnUploadedFileID IS NOT NULL AND $ columnUploadedFileID IS NOT -1) ' ,
distinct: true ,
2023-09-22 15:39:03 +00:00
) ;
2023-11-14 07:56:54 +00:00
final ids = < int > [ ] ;
for ( final result in results ) {
ids . add ( result [ columnUploadedFileID ] as int ) ;
2023-11-06 13:30:08 +00:00
}
2023-11-14 07:56:54 +00:00
return ids ;
2023-11-06 13:30:08 +00:00
}
2023-11-14 07:56:54 +00:00
Future < List < EnteFile > > getUploadedFiles ( List < int > uploadedIDs ) async {
2023-10-03 19:31:12 +00:00
final db = await instance . database ;
2023-11-14 07:56:54 +00:00
String inParam = " " ;
for ( final id in uploadedIDs ) {
inParam + = " ' " + id . toString ( ) + " ', " ;
}
inParam = inParam . substring ( 0 , inParam . length - 1 ) ;
2023-10-03 19:31:12 +00:00
final results = await db . query (
2023-11-14 07:56:54 +00:00
filesTable ,
where: ' $ columnUploadedFileID IN ( $ inParam ) ' ,
groupBy: columnUploadedFileID ,
2023-10-03 19:31:12 +00:00
) ;
2023-11-14 07:56:54 +00:00
if ( results . isEmpty ) {
return < EnteFile > [ ] ;
}
return convertToFiles ( results ) ;
2023-09-22 16:32:00 +00:00
}
2023-08-24 16:56:24 +00:00
Map < String , dynamic > _getRowForFile ( EnteFile file ) {
2021-07-21 19:55:24 +00:00
final row = < String , dynamic > { } ;
2021-05-16 08:40:11 +00:00
if ( file . generatedID ! = null ) {
row [ columnGeneratedID ] = file . generatedID ;
}
2020-08-09 22:34:59 +00:00
row [ columnLocalID ] = file . localID ;
2021-05-03 22:48:02 +00:00
row [ columnUploadedFileID ] = file . uploadedFileID ? ? - 1 ;
2020-08-09 22:34:59 +00:00
row [ columnOwnerID ] = file . ownerID ;
2021-05-03 22:48:02 +00:00
row [ columnCollectionID ] = file . collectionID ? ? - 1 ;
2020-06-19 23:03:26 +00:00
row [ columnTitle ] = file . title ;
row [ columnDeviceFolder ] = file . deviceFolder ;
2023-03-27 05:17:15 +00:00
// if (file.location == null ||
// (file.location!.latitude == null && file.location!.longitude == null)) {
// file.location = Location.randomLocation();
// }
2020-06-19 23:03:26 +00:00
if ( file . location ! = null ) {
2022-12-29 10:55:49 +00:00
row [ columnLatitude ] = file . location ! . latitude ;
row [ columnLongitude ] = file . location ! . longitude ;
2020-06-19 23:03:26 +00:00
}
2021-07-29 20:27:12 +00:00
row [ columnFileType ] = getInt ( file . fileType ) ;
2020-07-06 19:09:47 +00:00
row [ columnCreationTime ] = file . creationTime ;
row [ columnModificationTime ] = file . modificationTime ;
row [ columnUpdationTime ] = file . updationTime ;
2023-06-30 12:47:25 +00:00
row [ columnAddedTime ] =
file . addedTime ? ? DateTime . now ( ) . microsecondsSinceEpoch ;
2020-10-06 22:55:59 +00:00
row [ columnEncryptedKey ] = file . encryptedKey ;
row [ columnKeyDecryptionNonce ] = file . keyDecryptionNonce ;
row [ columnFileDecryptionHeader ] = file . fileDecryptionHeader ;
row [ columnThumbnailDecryptionHeader ] = file . thumbnailDecryptionHeader ;
row [ columnMetadataDecryptionHeader ] = file . metadataDecryptionHeader ;
2021-08-18 13:23:42 +00:00
row [ columnFileSubType ] = file . fileSubType ? ? - 1 ;
row [ columnDuration ] = file . duration ? ? 0 ;
row [ columnExif ] = file . exif ;
row [ columnHash ] = file . hash ;
row [ columnMetadataVersion ] = file . metadataVersion ;
2022-09-24 10:36:05 +00:00
row [ columnFileSize ] = file . fileSize ;
2022-12-29 10:55:49 +00:00
row [ columnMMdVersion ] = file . mMdVersion ;
2021-09-16 13:14:51 +00:00
row [ columnMMdEncodedJson ] = file . mMdEncodedJson ? ? ' {} ' ;
2022-12-29 10:55:49 +00:00
row [ columnMMdVisibility ] = file . magicMetadata . visibility ;
row [ columnPubMMdVersion ] = file . pubMmdVersion ;
2021-10-26 10:37:14 +00:00
row [ columnPubMMdEncodedJson ] = file . pubMmdEncodedJson ? ? ' {} ' ;
2023-04-18 08:15:11 +00:00
// override existing fields to avoid re-writing all queries and logic
if ( file . pubMagicMetadata ! = null ) {
if ( file . pubMagicMetadata ! . editedTime ! = null ) {
row [ columnCreationTime ] = file . pubMagicMetadata ! . editedTime ;
}
if ( file . pubMagicMetadata ! . lat ! = null & &
file . pubMagicMetadata ! . long ! = null ) {
row [ columnLatitude ] = file . pubMagicMetadata ! . lat ;
row [ columnLongitude ] = file . pubMagicMetadata ! . long ;
}
2021-10-26 10:37:14 +00:00
}
2020-03-30 14:28:46 +00:00
return row ;
}
2020-04-12 12:38:49 +00:00
2023-08-24 16:56:24 +00:00
Map < String , dynamic > _getRowForFileWithoutCollection ( EnteFile file ) {
2021-07-21 19:55:24 +00:00
final row = < String , dynamic > { } ;
2020-11-30 18:42:11 +00:00
row [ columnLocalID ] = file . localID ;
2021-05-03 22:48:02 +00:00
row [ columnUploadedFileID ] = file . uploadedFileID ? ? - 1 ;
2020-11-30 18:42:11 +00:00
row [ columnOwnerID ] = file . ownerID ;
row [ columnTitle ] = file . title ;
row [ columnDeviceFolder ] = file . deviceFolder ;
if ( file . location ! = null ) {
2022-12-29 10:55:49 +00:00
row [ columnLatitude ] = file . location ! . latitude ;
row [ columnLongitude ] = file . location ! . longitude ;
2020-11-30 18:42:11 +00:00
}
2021-07-29 20:27:12 +00:00
row [ columnFileType ] = getInt ( file . fileType ) ;
2020-11-30 18:42:11 +00:00
row [ columnCreationTime ] = file . creationTime ;
row [ columnModificationTime ] = file . modificationTime ;
row [ columnUpdationTime ] = file . updationTime ;
2023-06-30 12:47:25 +00:00
row [ columnAddedTime ] =
file . addedTime ? ? DateTime . now ( ) . microsecondsSinceEpoch ;
2020-11-30 18:42:11 +00:00
row [ columnFileDecryptionHeader ] = file . fileDecryptionHeader ;
row [ columnThumbnailDecryptionHeader ] = file . thumbnailDecryptionHeader ;
row [ columnMetadataDecryptionHeader ] = file . metadataDecryptionHeader ;
2021-08-18 13:23:42 +00:00
row [ columnFileSubType ] = file . fileSubType ? ? - 1 ;
row [ columnDuration ] = file . duration ? ? 0 ;
row [ columnExif ] = file . exif ;
row [ columnHash ] = file . hash ;
row [ columnMetadataVersion ] = file . metadataVersion ;
2021-09-16 13:14:51 +00:00
2022-12-29 10:55:49 +00:00
row [ columnMMdVersion ] = file . mMdVersion ;
2021-10-31 14:18:36 +00:00
row [ columnMMdEncodedJson ] = file . mMdEncodedJson ? ? ' {} ' ;
2022-12-29 10:55:49 +00:00
row [ columnMMdVisibility ] = file . magicMetadata . visibility ;
2021-10-26 05:25:42 +00:00
2022-12-29 10:55:49 +00:00
row [ columnPubMMdVersion ] = file . pubMmdVersion ;
2021-10-26 10:37:14 +00:00
row [ columnPubMMdEncodedJson ] = file . pubMmdEncodedJson ? ? ' {} ' ;
2021-10-26 05:25:42 +00:00
if ( file . pubMagicMetadata ! = null & &
2022-12-29 10:55:49 +00:00
file . pubMagicMetadata ! . editedTime ! = null ) {
2021-10-26 05:25:42 +00:00
// override existing creationTime to avoid re-writing all queries related
// to loading the gallery
2022-12-29 10:55:49 +00:00
row [ columnCreationTime ] = file . pubMagicMetadata ! . editedTime ! ;
2021-10-26 05:25:42 +00:00
}
2021-10-27 19:42:30 +00:00
return row ;
2020-11-30 18:42:11 +00:00
}
2023-08-24 16:56:24 +00:00
EnteFile _getFileFromRow ( Map < String , dynamic > row ) {
final file = EnteFile ( ) ;
2020-08-09 22:34:59 +00:00
file . generatedID = row [ columnGeneratedID ] ;
file . localID = row [ columnLocalID ] ;
2021-05-03 22:48:02 +00:00
file . uploadedFileID =
row [ columnUploadedFileID ] = = - 1 ? null : row [ columnUploadedFileID ] ;
2020-10-13 21:40:22 +00:00
file . ownerID = row [ columnOwnerID ] ;
2021-05-03 22:48:02 +00:00
file . collectionID =
row [ columnCollectionID ] = = - 1 ? null : row [ columnCollectionID ] ;
2020-06-19 23:03:26 +00:00
file . title = row [ columnTitle ] ;
file . deviceFolder = row [ columnDeviceFolder ] ;
2020-06-06 21:12:49 +00:00
if ( row [ columnLatitude ] ! = null & & row [ columnLongitude ] ! = null ) {
2023-04-02 12:47:18 +00:00
file . location = Location (
latitude: row [ columnLatitude ] ,
longitude: row [ columnLongitude ] ,
) ;
2020-06-06 21:12:49 +00:00
}
2020-06-19 23:03:26 +00:00
file . fileType = getFileType ( row [ columnFileType ] ) ;
2021-07-21 19:55:24 +00:00
file . creationTime = row [ columnCreationTime ] ;
file . modificationTime = row [ columnModificationTime ] ;
file . updationTime = row [ columnUpdationTime ] ? ? - 1 ;
2023-06-30 12:47:25 +00:00
file . addedTime = row [ columnAddedTime ] ;
2020-10-06 22:55:59 +00:00
file . encryptedKey = row [ columnEncryptedKey ] ;
file . keyDecryptionNonce = row [ columnKeyDecryptionNonce ] ;
file . fileDecryptionHeader = row [ columnFileDecryptionHeader ] ;
file . thumbnailDecryptionHeader = row [ columnThumbnailDecryptionHeader ] ;
file . metadataDecryptionHeader = row [ columnMetadataDecryptionHeader ] ;
2021-08-18 13:23:42 +00:00
file . fileSubType = row [ columnFileSubType ] ? ? - 1 ;
file . duration = row [ columnDuration ] ? ? 0 ;
file . exif = row [ columnExif ] ;
file . hash = row [ columnHash ] ;
file . metadataVersion = row [ columnMetadataVersion ] ? ? 0 ;
2022-09-24 10:36:05 +00:00
file . fileSize = row [ columnFileSize ] ;
2021-09-16 13:14:51 +00:00
2021-09-30 09:28:29 +00:00
file . mMdVersion = row [ columnMMdVersion ] ? ? 0 ;
2021-09-16 13:14:51 +00:00
file . mMdEncodedJson = row [ columnMMdEncodedJson ] ? ? ' {} ' ;
2021-10-26 05:25:42 +00:00
file . pubMmdVersion = row [ columnPubMMdVersion ] ? ? 0 ;
file . pubMmdEncodedJson = row [ columnPubMMdEncodedJson ] ? ? ' {} ' ;
2020-06-19 23:03:26 +00:00
return file ;
2020-04-12 12:38:49 +00:00
}
2020-03-26 14:39:31 +00:00
}