ente/mobile/lib/db/files_db.dart

1859 lines
59 KiB
Dart
Raw Normal View History

2023-08-24 16:56:24 +00:00
import "dart:io";
2020-03-24 19:59:36 +00:00
import "package:computer/computer.dart";
import 'package:flutter/foundation.dart';
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';
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';
import 'package:photos/models/location/location.dart';
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';
import 'package:sqflite_migration/sqflite_migration.dart';
import 'package:sqlite_async/sqlite_async.dart' as sqlite_async;
2020-03-24 19:59:36 +00:00
2020-07-20 11:03:09 +00:00
class FilesDB {
/*
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");
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';
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
// MMD -> Magic Metadata
2022-07-04 06:02:17 +00:00
static const columnMMdEncodedJson = 'mmd_encoded_json';
static const columnMMdVersion = 'mmd_ver';
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
// 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';
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(),
...addMagicMetadataColumns(),
...addUniqueConstraintOnCollectionFiles(),
...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(),
...addAddedTime(),
2021-07-21 19:55:24 +00:00
];
final dbConfig = MigrationConfig(
2022-06-11 08:23:52 +00:00
initializationScript: initializationScript,
migrationScripts: migrationScripts,
);
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;
static Future<sqlite_async.SqliteDatabase>? _sqliteAsyncDBFuture;
2021-07-21 19:55:24 +00:00
@Deprecated("Use sqliteAsyncDB instead (sqlite_async)")
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
Future<sqlite_async.SqliteDatabase> get sqliteAsyncDB async {
_sqliteAsyncDBFuture ??= _initSqliteAsyncDatabase();
return _sqliteAsyncDBFuture!;
}
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 =
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);
return await openDatabaseWithMigration(path, dbConfig);
2020-03-24 19:59:36 +00:00
}
Future<sqlite_async.SqliteDatabase> _initSqliteAsyncDatabase() async {
final Directory documentsDirectory =
await getApplicationDocumentsDirectory();
final String path = join(documentsDirectory.path, _databaseName);
_logger.info("DB path " + path);
return sqlite_async.SqliteDatabase(path: path);
}
2020-03-24 19:59:36 +00:00
// SQL code to create the database table
static List<String> createTable(String tableName) {
return [
'''
CREATE TABLE $tableName (
2021-01-24 18:59:17 +00:00
$columnGeneratedID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
$columnLocalID TEXT,
$columnUploadedFileID INTEGER DEFAULT -1,
2021-01-24 18:59:17 +00:00
$columnOwnerID INTEGER,
$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,
UNIQUE($columnLocalID, $columnUploadedFileID, $columnCollectionID)
2021-01-24 18:59:17 +00:00
);
''',
];
}
2021-07-21 20:21:31 +00:00
static List<String> addIndices() {
return [
'''
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);
'''
];
}
static List<String> alterDeviceFolderToAllowNULL() {
return [
...createTable(tempTable),
'''
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;
'''
];
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
''',
];
}
static List<String> addMagicMetadataColumns() {
return [
'''
2022-07-23 05:41:43 +00:00
ALTER TABLE $filesTable ADD COLUMN $columnMMdEncodedJson TEXT DEFAULT '{}';
''',
'''
2022-07-23 05:41:43 +00:00
ALTER TABLE $filesTable ADD COLUMN $columnMMdVersion INTEGER DEFAULT 0;
''',
'''
ALTER TABLE $filesTable ADD COLUMN $columnMMdVisibility INTEGER DEFAULT $visibleVisibility;
'''
];
}
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);
''',
'''
2022-07-23 05:41:43 +00:00
CREATE UNIQUE INDEX IF NOT EXISTS cid_uid ON $filesTable ($columnCollectionID, $columnUploadedFileID)
WHERE $columnCollectionID is not NULL AND $columnUploadedFileID is not NULL
AND $columnCollectionID != -1 AND $columnUploadedFileID != -1;
'''
];
}
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
'''
];
}
static List<String> createOnDeviceFilesAndPathCollection() {
return [
'''
2022-08-26 11:47:30 +00:00
CREATE TABLE IF NOT EXISTS device_files (
id TEXT NOT NULL,
path_id TEXT NOT NULL,
UNIQUE(id, path_id)
);
''',
'''
CREATE TABLE IF NOT EXISTS device_collections (
id TEXT PRIMARY KEY NOT NULL,
name TEXT,
modified_at INTEGER NOT NULL DEFAULT 0,
should_backup INTEGER NOT NULL DEFAULT 0,
count INTEGER NOT NULL DEFAULT 0,
collection_id INTEGER DEFAULT -1,
upload_strategy INTEGER DEFAULT 0,
cover_id TEXT
);
''',
'''
CREATE INDEX IF NOT EXISTS df_id_idx ON device_files (id);
''',
'''
CREATE INDEX IF NOT EXISTS df_path_id_idx ON device_files (path_id);
''',
];
}
static List<String> createEntityDataTable() {
return [
'''
2023-04-04 08:48:54 +00:00
CREATE TABLE IF NOT EXISTS entities (
id TEXT PRIMARY KEY NOT NULL,
type TEXT NOT NULL,
2023-04-04 08:48:54 +00:00
ownerID INTEGER NOT NULL,
data TEXT NOT NULL DEFAULT '{}',
2023-04-04 08:48:54 +00:00
updatedAt INTEGER NOT NULL
);
'''
];
}
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);
''',
];
}
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);
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
}
Future<void> deleteDB() async {
if (kDebugMode) {
debugPrint("Deleting files db");
2023-08-24 16:56:24 +00:00
final Directory documentsDirectory =
await getApplicationDocumentsDirectory();
final String path = join(documentsDirectory.path, _databaseName);
2023-08-24 16:56:24 +00:00
File(path).deleteSync(recursive: true);
_dbFuture = null;
}
}
Future<void> insertMultiple(
2023-08-24 16:56:24 +00:00
List<EnteFile> files, {
ConflictAlgorithm conflictAlgorithm = ConflictAlgorithm.replace,
}) async {
2021-04-19 12:46:42 +00:00
final startTime = DateTime.now();
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
}
batch.insert(
2022-07-23 05:41:43 +00:00
filesTable,
_getRowForFile(file),
conflictAlgorithm: conflictAlgorithm,
);
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 {
2024-04-30 10:34:50 +00:00
_logger.info("Inserting $file");
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 {
final db = await instance.sqliteAsyncDB;
final results = await db.getAll(
2024-04-18 10:53:43 +00:00
'SELECT * FROM $filesTable WHERE $columnGeneratedID = ?',
[generatedID],
2022-06-11 08:23:52 +00:00
);
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];
}
2023-08-24 16:56:24 +00:00
Future<EnteFile?> getUploadedFile(int uploadedID, int collectionID) async {
final db = await instance.sqliteAsyncDB;
final results = await db.getAll(
2024-04-18 10:53:43 +00:00
'SELECT * FROM $filesTable WHERE $columnUploadedFileID = ? AND $columnCollectionID = ?',
[
uploadedID,
collectionID,
],
);
if (results.isEmpty) {
return null;
}
2022-07-23 05:41:43 +00:00
return convertToFiles(results)[0];
}
2023-10-03 17:56:51 +00:00
Future<EnteFile?> getAnyUploadedFile(int uploadedID) async {
2024-04-20 10:29:36 +00:00
final db = await instance.sqliteAsyncDB;
final results = await db.getAll(
'SELECT * FROM $filesTable WHERE $columnUploadedFileID = ?',
[uploadedID],
2023-10-03 17:56:51 +00:00
);
if (results.isEmpty) {
return null;
}
return convertToFiles(results)[0];
}
Future<Set<int>> getUploadedFileIDs(int collectionID) async {
final db = await instance.sqliteAsyncDB;
final results = await db.getAll(
2024-04-18 10:53:43 +00:00
'SELECT $columnUploadedFileID FROM $filesTable'
' WHERE $columnCollectionID = ? AND ($columnUploadedFileID IS NOT NULL AND $columnUploadedFileID IS NOT -1)',
[
collectionID,
],
);
2021-07-21 19:55:24 +00:00
final ids = <int>{};
for (final result in results) {
2022-12-29 10:55:49 +00:00
ids.add(result[columnUploadedFileID] as int);
}
return ids;
}
Future<(Set<int>, Map<String, int>)> getUploadAndHash(
int collectionID,
) async {
final db = await instance.database;
final results = await db.query(
2022-07-23 05:41:43 +00:00
filesTable,
columns: [columnUploadedFileID, columnHash],
2022-12-29 10:55:49 +00:00
where:
'$columnCollectionID = ? AND ($columnUploadedFileID IS NOT NULL AND $columnUploadedFileID IS NOT -1)',
whereArgs: [
collectionID,
],
);
2021-07-21 19:55:24 +00:00
final ids = <int>{};
final hash = <String, int>{};
for (final result in results) {
2022-12-29 10:55:49 +00:00
ids.add(result[columnUploadedFileID] as int);
if (result[columnHash] != null) {
hash[result[columnHash] as String] =
result[columnUploadedFileID] as int;
}
}
return (ids, hash);
}
2021-06-28 06:40:19 +00:00
Future<BackedUpFileIDs> getBackedUpIDs() async {
2024-04-18 10:53:43 +00:00
final db = await instance.sqliteAsyncDB;
final results = await db.getAll(
'SELECT $columnLocalID, $columnUploadedFileID, $columnFileSize FROM $filesTable'
' WHERE $columnLocalID IS NOT NULL AND ($columnUploadedFileID IS NOT NULL AND $columnUploadedFileID IS NOT -1)',
2021-06-28 05:30:58 +00:00
);
final Set<String> localIDs = <String>{};
final Set<int> uploadedIDs = <int>{};
int localSize = 0;
2021-06-28 05:30:58 +00:00
for (final result in results) {
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
}
return BackedUpFileIDs(localIDs.toList(), uploadedIDs.toList(), localSize);
2021-06-28 05:30:58 +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,
int visibility = visibleVisibility,
2023-06-20 12:25:49 +00:00
DBFilterOptions? filterOptions,
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();
final order = (asc ?? false ? 'ASC' : 'DESC');
late String query;
late List<Object?>? args;
if (applyOwnerCheck) {
query =
'SELECT * FROM $filesTable WHERE $columnCreationTime >= ? AND $columnCreationTime <= ? '
'AND ($columnOwnerID IS NULL OR $columnOwnerID = ?) '
'AND ($columnCollectionID IS NOT NULL AND $columnCollectionID IS NOT -1)'
' AND $columnMMdVisibility = ? ORDER BY $columnCreationTime $order, $columnModificationTime $order';
args = [startTime, endTime, ownerID, visibility];
} else {
query =
'SELECT * FROM $filesTable WHERE $columnCreationTime >= ? AND $columnCreationTime <= ? '
'AND ($columnCollectionID IS NOT NULL AND $columnCollectionID IS NOT -1)'
' AND $columnMMdVisibility = ? ORDER BY $columnCreationTime $order, $columnModificationTime $order';
args = [startTime, endTime, visibility];
}
2023-03-27 04:36:21 +00:00
if (limit != null) {
query += ' LIMIT ?';
args.add(limit);
}
final db = await instance.sqliteAsyncDB;
final results = await db.getAll(query, args);
_logger.info("message");
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);
stopWatch.log('filteringDone');
2023-03-27 04:36:21 +00:00
stopWatch.stop();
return FileLoadResult(filteredFiles, files.length == limit);
2020-04-12 12:38:49 +00:00
}
Future<FileLoadResult> getAllLocalAndUploadedFiles(
2022-06-11 08:23:52 +00:00
int startTime,
int endTime, {
2022-12-29 10:55:49 +00:00
int? limit,
bool? asc,
required DBFilterOptions filterOptions,
2022-06-11 08:23:52 +00:00
}) async {
final db = await instance.sqliteAsyncDB;
final order = (asc ?? false ? 'ASC' : 'DESC');
final args = [startTime, endTime, visibleVisibility];
String query =
'SELECT * FROM $filesTable WHERE $columnCreationTime >= ? AND $columnCreationTime <= ? AND ($columnMMdVisibility IS NULL OR $columnMMdVisibility = ?)'
' AND ($columnLocalID IS NOT NULL OR ($columnCollectionID IS NOT NULL AND $columnCollectionID IS NOT -1))'
' ORDER BY $columnCreationTime $order, $columnModificationTime $order';
if (limit != null) {
query += ' LIMIT ?';
args.add(limit);
}
final results = await db.getAll(
query,
args,
);
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);
return FileLoadResult(filteredFiles, files.length == limit);
}
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;
}
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,
int visibility = visibleVisibility,
2022-06-11 08:23:52 +00:00
}) async {
final db = await instance.sqliteAsyncDB;
2021-06-09 13:45:42 +00:00
final order = (asc ?? false ? 'ASC' : 'DESC');
String query =
'SELECT * FROM $filesTable WHERE $columnCollectionID = ? AND $columnCreationTime >= ? AND $columnCreationTime <= ? ORDER BY $columnCreationTime $order, $columnModificationTime $order';
final List<Object> args = [collectionID, startTime, endTime];
if (limit != null) {
query += ' LIMIT ?';
args.add(limit);
}
final results = await db.getAll(
query,
args,
2021-04-20 20:11:39 +00:00
);
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 {
2024-04-18 11:44:22 +00:00
final db = await instance.sqliteAsyncDB;
const String whereClause = '$columnCollectionID = ?';
final List<Object> whereArgs = [collectionID];
2024-04-18 11:44:22 +00:00
final results = await db.getAll(
'SELECT * FROM $filesTable WHERE $whereClause',
whereArgs,
);
final files = convertToFiles(results);
return files;
}
2024-05-18 09:52:41 +00:00
Future<List<EnteFile>> getAllFilesFromCollections(
Iterable<int> collectionID,
) async {
final db = await instance.sqliteAsyncDB;
final String sql =
'SELECT * FROM $filesTable WHERE $columnCollectionID IN (${collectionID.join(',')})';
final results = await db.getAll(sql);
final files = convertToFiles(results);
return files;
}
2023-08-24 16:56:24 +00:00
Future<List<EnteFile>> getNewFilesInCollection(
int collectionID,
int addedTime,
) async {
2024-04-18 11:44:22 +00:00
final db = await instance.sqliteAsyncDB;
const String whereClause =
'$columnCollectionID = ? AND $columnAddedTime > ?';
final List<Object> whereArgs = [collectionID, addedTime];
2024-04-18 11:44:22 +00:00
final results = await db.getAll(
'SELECT * FROM $filesTable WHERE $whereClause',
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);
2024-04-18 11:44:22 +00:00
final db = await instance.sqliteAsyncDB;
2022-10-27 07:23:45 +00:00
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];
2024-04-18 11:44:22 +00:00
String query = 'SELECT * FROM $filesTable WHERE $whereClause ORDER BY '
'$columnCreationTime $order, $columnModificationTime $order';
if (limit != null) {
query += ' LIMIT ?';
whereArgs.add(limit);
}
final results = await db.getAll(
query,
whereArgs,
2022-10-27 07:23:45 +00:00
);
final files = convertToFiles(results);
final dedupeResult =
await applyDBFilters(files, DBFilterOptions.dedupeOption);
2022-10-27 07:23:45 +00:00
_logger.info("Fetched " + dedupeResult.length.toString() + " files");
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,
Set<int> ignoredCollectionIDs, {
int? visibility,
String order = 'ASC',
}) async {
if (durations.isEmpty) {
2023-08-24 16:56:24 +00:00
return <EnteFile>[];
}
final db = await instance.sqliteAsyncDB;
2024-01-17 20:12:54 +00:00
String whereClause = "( ";
for (int index = 0; index < durations.length; index++) {
whereClause += "($columnCreationTime >= " +
durations[index][0].toString() +
" AND $columnCreationTime < " +
durations[index][1].toString() +
")";
if (index != durations.length - 1) {
whereClause += " OR ";
} else if (visibility != null) {
whereClause += ' AND $columnMMdVisibility = $visibility';
}
}
whereClause += ")";
final query =
'SELECT * FROM $filesTable WHERE $whereClause ORDER BY $columnCreationTime $order';
final results = await db.getAll(
query,
2024-01-17 20:12:54 +00:00
);
final files = convertToFiles(results);
return applyDBFilters(
files,
DBFilterOptions(ignoredCollectionIDs: ignoredCollectionIDs),
);
}
// 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 {
final db = await instance.database;
final results = await db.query(
2022-07-23 05:41:43 +00:00
filesTable,
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 '
'$columnLocalID IS NOT NULL AND $columnLocalID IS NOT -1',
orderBy: '$columnCreationTime DESC',
groupBy: columnLocalID,
);
final files = convertToFiles(results);
// 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,
);
return files;
}
2023-08-24 16:56:24 +00:00
Future<List<EnteFile>> getUnUploadedLocalFiles() async {
final db = await instance.database;
final results = await db.query(
2022-07-23 05:41:43 +00:00
filesTable,
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
}
Future<List<int>> getUploadedFileIDsToBeUpdated(int ownerID) async {
final db = await instance.database;
final rows = await db.query(
2022-07-23 05:41:43 +00:00
filesTable,
columns: [columnUploadedFileID],
where: '($columnLocalID IS NOT NULL AND $columnOwnerID = ? AND '
'($columnUploadedFileID '
'IS NOT '
'NULL AND $columnUploadedFileID IS NOT -1) AND $columnUpdationTime IS NULL)',
whereArgs: [ownerID],
orderBy: '$columnCreationTime DESC',
distinct: true,
);
2021-07-21 19:55:24 +00:00
final uploadedFileIDs = <int>[];
for (final row in rows) {
2022-12-29 10:55:49 +00:00
uploadedFileIDs.add(row[columnUploadedFileID] as int);
}
return uploadedFileIDs;
}
Future<List<EnteFile>> getFilesInAllCollection(
2023-05-03 12:14:59 +00:00
int uploadedFileID,
int userID,
) async {
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 = ?',
whereArgs: [
2023-05-03 12:14:59 +00:00
userID,
uploadedFileID,
],
);
if (results.isEmpty) {
return <EnteFile>[];
}
return convertToFiles(results);
}
Future<Set<String>> getExistingLocalFileIDs(int ownerID) async {
final db = await instance.database;
final rows = await db.query(
2022-07-23 05:41:43 +00:00
filesTable,
columns: [columnLocalID],
distinct: true,
where: '$columnLocalID IS NOT NULL AND ($columnOwnerID IS NULL OR '
'$columnOwnerID = ?)',
whereArgs: [ownerID],
);
2021-07-21 19:55:24 +00:00
final result = <String>{};
for (final row in rows) {
2022-12-29 10:55:49 +00:00
result.add(row[columnLocalID] as String);
}
return result;
}
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);
}
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;
}
// 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,
String localID,
2022-12-30 09:44:52 +00:00
String? title,
Location? location,
int creationTime,
int modificationTime,
2023-08-22 15:05:29 +00:00
FileType fileType,
) async {
final db = await instance.database;
return await db.update(
2022-07-23 05:41:43 +00:00
filesTable,
{
columnTitle: title,
2022-12-30 09:44:52 +00:00
columnLatitude: location?.latitude,
columnLongitude: location?.longitude,
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),
},
2023-08-22 15:05:29 +00:00
where:
'$columnLocalID = ? AND ($columnOwnerID = ? OR $columnOwnerID IS NULL)',
whereArgs: [localID, ownerID],
);
}
/*
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(
int ownerID,
String localID,
FileType fileType, {
2022-12-29 10:55:49 +00:00
required String title,
required String deviceFolder,
}) 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
($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= ?
''';
whereArgs = [
ownerID,
localID,
getInt(fileType),
title,
deviceFolder,
];
}
final rows = await db.query(
filesTable,
where: whereClause,
whereArgs: whereArgs,
);
return convertToFiles(rows);
}
Future<Map<String, EnteFile>>
getUserOwnedFilesWithSameHashForGivenListOfFiles(
List<EnteFile> files,
int userID,
) async {
final db = await sqliteAsyncDB;
final List<String> hashes = [];
for (final file in files) {
if (file.hash != null && file.hash != '') {
hashes.add(file.hash!);
}
}
if (hashes.isEmpty) {
return {};
}
final inParam = hashes.map((e) => "'$e'").join(',');
final rows = await db.execute('''
SELECT * FROM $filesTable WHERE $columnHash IN ($inParam) AND $columnOwnerID = $userID;
''');
final matchedFiles = convertToFiles(rows);
return Map.fromIterable(matchedFiles, key: (e) => e.hash);
}
2023-08-24 16:56:24 +00:00
Future<List<EnteFile>> getUploadedFilesWithHashes(
2022-08-29 07:58:49 +00:00
FileHashData hashData,
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}'";
}
final db = await instance.database;
2022-08-29 07:58:49 +00:00
final rows = await db.query(
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),
],
);
return convertToFiles(rows);
}
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,
_getRowForFile(file),
2020-08-09 22:34:59 +00:00
where: '$columnGeneratedID = ?',
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 {
final db = await instance.database;
return await db.update(
2022-07-23 05:41:43 +00:00
filesTable,
_getRowForFileWithoutCollection(file),
where: '$columnUploadedFileID = ?',
whereArgs: [file.uploadedFileID],
);
}
Future<int> updateLocalIDForUploaded(int uploadedID, String localID) async {
final db = await instance.database;
return await db.update(
filesTable,
{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
}
Future<int> deleteByGeneratedID(int genID) async {
final db = await instance.database;
return db.delete(
filesTable,
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
);
}
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;
if (file.localID != null) {
// delete all files with same local ID
return db.delete(
2022-07-23 05:41:43 +00:00
filesTable,
where: '$columnLocalID =?',
whereArgs: [file.localID],
);
} else {
return db.delete(
2022-07-23 05:41:43 +00:00
filesTable,
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
}
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,
where:
'($columnUploadedFileID is NULL OR $columnUploadedFileID = -1 ) AND $columnLocalID IN ($inParam)',
);
}
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,
where: '$columnUploadedFileID = ? AND $columnCollectionID = ?',
whereArgs: [uploadedFileID, collectionID],
);
}
Future<int> deleteFilesFromCollection(
2022-06-11 08:23:52 +00:00
int collectionID,
List<int> uploadedFileIDs,
) async {
final db = await instance.database;
return db.delete(
2022-07-23 05:41:43 +00:00
filesTable,
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(
'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
}
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'
' = $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 {
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,
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! + "',";
}
}
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);
}
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;
}
2024-04-20 10:29:36 +00:00
Future<Map<int, int>> getFileIDToCreationTime() async {
final db = await instance.sqliteAsyncDB;
final rows = await db.getAll(
'''
SELECT $columnUploadedFileID, $columnCreationTime
FROM $filesTable
WHERE
($columnUploadedFileID IS NOT NULL AND $columnUploadedFileID IS NOT -1);
''',
);
final result = <int, int>{};
for (final row in rows) {
result[row[columnUploadedFileID] as int] = row[columnCreationTime] as int;
}
return result;
}
// 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(
int collectionID,
bool sortAsc,
) async {
final db = await instance.database;
final order = sortAsc ? 'ASC' : 'DESC';
final rows = await db.query(
filesTable,
where: '$columnCollectionID = ? AND ($columnUploadedFileID IS NOT NULL '
'AND $columnUploadedFileID IS NOT -1)',
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>{};
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(
2022-07-23 05:41:43 +00:00
filesTable,
where: '$columnUploadedFileID IN ($inParam)',
);
2022-07-23 05:41:43 +00:00
final files = convertToFiles(results);
for (final file in files) {
2022-12-29 10:55:49 +00:00
result[file.uploadedFileID!] = file;
}
return result;
}
2023-08-24 16:56:24 +00:00
Future<Map<int, EnteFile>> getFilesFromGeneratedIDs(List<int> ids) async {
final result = <int, EnteFile>{};
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;
}
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;
}
Future<Set<int>> getAllCollectionIDsOfFile(
int uploadedFileID,
) async {
final db = await instance.database;
final results = await db.query(
filesTable,
where: '$columnUploadedFileID = ? AND $columnCollectionID != -1',
columns: [columnCollectionID],
whereArgs: [uploadedFileID],
distinct: true,
);
2022-09-07 01:56:51 +00:00
final collectionIDsOfFile = <int>{};
for (var result in results) {
2022-12-29 10:55:49 +00:00
collectionIDsOfFile.add(result['collection_id'] as int);
}
return collectionIDsOfFile;
}
List<EnteFile> convertToFilesForIsolate(Map args) {
final List<EnteFile> files = [];
for (final result in args["result"]) {
files.add(_getFileFromRow(result));
}
return files;
}
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
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;
}
// 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;
}
// For a given userID, return unique localID for all uploaded live photos
Future<List<String>> getLivePhotosForUser(int userId) async {
final db = await instance.database;
final rows = await db.query(
filesTable,
columns: [columnLocalID],
distinct: true,
where: '$columnOwnerID = ? AND '
'$columnFileType = ? AND $columnLocalID IS NOT NULL',
whereArgs: [userId, getInt(FileType.livePhoto)],
);
final result = <String>[];
for (final row in rows) {
result.add(row[columnLocalID] as String);
}
return result;
}
Future<List<String>> getLocalFilesBackedUpWithoutLocation(int userId) async {
final db = await instance.database;
final rows = await db.query(
filesTable,
columns: [columnLocalID],
distinct: true,
where:
'$columnOwnerID = ? AND $columnLocalID IS NOT NULL AND ($columnUploadedFileID IS NOT NULL AND $columnUploadedFileID IS NOT -1) '
'AND ($columnLatitude IS NULL OR $columnLongitude IS NULL OR $columnLongitude = 0.0 or $columnLongitude = 0.0)',
whereArgs: [userId],
);
final result = <String>[];
for (final row in rows) {
result.add(row[columnLocalID] as String);
}
return result;
}
// 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);
}
Future<List<EnteFile>> getAllFilesFromDB(
Set<int> collectionsToIgnore, {
bool dedupeByUploadId = true,
}) async {
final db = await instance.sqliteAsyncDB;
final result = await db.getAll(
'SELECT * FROM $filesTable ORDER BY $columnCreationTime DESC',
);
final List<EnteFile> files = await Computer.shared()
.compute(convertToFilesForIsolate, param: {"result": result});
2023-08-24 16:56:24 +00:00
final List<EnteFile> deduplicatedFiles = await applyDBFilters(
files,
DBFilterOptions(
ignoredCollectionIDs: collectionsToIgnore,
dedupeUploadID: dedupeByUploadId,
),
);
return deduplicatedFiles;
}
Future<Map<FileType, int>> fetchFilesCountbyType(int userID) async {
final db = await instance.database;
final result = await db.rawQuery(
"SELECT $columnFileType, COUNT(DISTINCT $columnUploadedFileID) FROM $filesTable WHERE $columnUploadedFileID != -1 AND $columnOwnerID == $userID GROUP BY $columnFileType",
);
2022-10-21 05:44:14 +00:00
final filesCount = <FileType, int>{};
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-21 05:44:14 +00:00
return filesCount;
}
Future<FileLoadResult> fetchAllUploadedAndSharedFilesWithLocation(
2023-04-10 04:30:30 +00:00
int startTime,
int endTime, {
int? limit,
bool? asc,
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)'
' 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))',
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);
return FileLoadResult(filteredFiles, files.length == limit);
2023-04-10 04:30:30 +00:00
}
Future<List<int>> getOwnedFileIDs(int ownerID) async {
final db = await instance.sqliteAsyncDB;
final results = await db.getAll(
'''
SELECT DISTINCT $columnUploadedFileID FROM $filesTable
WHERE ($columnOwnerID = ? AND $columnUploadedFileID IS NOT NULL AND
$columnUploadedFileID IS NOT -1)
''',
[ownerID],
2023-09-22 15:39:03 +00:00
);
final ids = <int>[];
for (final result in results) {
ids.add(result[columnUploadedFileID] as int);
2023-11-06 13:30:08 +00:00
}
return ids;
2023-11-06 13:30:08 +00:00
}
Future<List<EnteFile>> getUploadedFiles(List<int> uploadedIDs) async {
final db = await instance.sqliteAsyncDB;
String inParam = "";
for (final id in uploadedIDs) {
inParam += "'" + id.toString() + "',";
}
inParam = inParam.substring(0, inParam.length - 1);
final results = await db.getAll(
'''
SELECT * FROM $filesTable WHERE $columnUploadedFileID IN ($inParam)
GROUP BY $columnUploadedFileID
''',
2023-10-03 19:31:12 +00:00
);
if (results.isEmpty) {
return <EnteFile>[];
}
return convertToFiles(results);
}
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>{};
if (file.generatedID != null) {
row[columnGeneratedID] = file.generatedID;
}
2020-08-09 22:34:59 +00:00
row[columnLocalID] = file.localID;
row[columnUploadedFileID] = file.uploadedFileID ?? -1;
2020-08-09 22:34:59 +00:00
row[columnOwnerID] = file.ownerID;
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
}
row[columnFileType] = getInt(file.fileType);
row[columnCreationTime] = file.creationTime;
row[columnModificationTime] = file.modificationTime;
row[columnUpdationTime] = file.updationTime;
row[columnAddedTime] =
file.addedTime ?? DateTime.now().microsecondsSinceEpoch;
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;
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 ?? '{}';
// 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>{};
row[columnLocalID] = file.localID;
row[columnUploadedFileID] = file.uploadedFileID ?? -1;
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;
}
row[columnFileType] = getInt(file.fileType);
row[columnCreationTime] = file.creationTime;
row[columnModificationTime] = file.modificationTime;
row[columnUpdationTime] = file.updationTime;
row[columnAddedTime] =
file.addedTime ?? DateTime.now().microsecondsSinceEpoch;
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-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;
}
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];
file.uploadedFileID =
row[columnUploadedFileID] == -1 ? null : row[columnUploadedFileID];
file.ownerID = row[columnOwnerID];
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) {
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;
file.addedTime = row[columnAddedTime];
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];
file.mMdVersion = row[columnMMdVersion] ?? 0;
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
}