file_updation_db.dart 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. import 'dart:io';
  2. import 'package:flutter/foundation.dart';
  3. import 'package:logging/logging.dart';
  4. import 'package:path/path.dart';
  5. import 'package:path_provider/path_provider.dart';
  6. import 'package:sqflite/sqflite.dart';
  7. import 'package:sqflite_migration/sqflite_migration.dart';
  8. class FileUpdationDB {
  9. static const _databaseName = "ente.files_migration.db";
  10. static final Logger _logger = Logger((FileUpdationDB).toString());
  11. static const tableName = 're_upload_tracker';
  12. static const columnLocalID = 'local_id';
  13. static const columnReason = 'reason';
  14. static const missingLocation = 'missing_location';
  15. static const modificationTimeUpdated = 'modificationTimeUpdated';
  16. static const badCreationTime = 'badCreationTime';
  17. // SQL code to create the database table
  18. static List<String> _createTable() {
  19. return [
  20. '''
  21. CREATE TABLE $tableName (
  22. $columnLocalID TEXT NOT NULL,
  23. UNIQUE($columnLocalID)
  24. );
  25. ''',
  26. ];
  27. }
  28. static List<String> addReasonColumn() {
  29. return [
  30. '''
  31. ALTER TABLE $tableName ADD COLUMN $columnReason TEXT;
  32. ''',
  33. '''
  34. UPDATE $tableName SET $columnReason = '$missingLocation';
  35. ''',
  36. ];
  37. }
  38. static final initializationScript = [..._createTable()];
  39. static final migrationScripts = [
  40. ...addReasonColumn(),
  41. ];
  42. final dbConfig = MigrationConfig(
  43. initializationScript: initializationScript,
  44. migrationScripts: migrationScripts,
  45. );
  46. FileUpdationDB._privateConstructor();
  47. static final FileUpdationDB instance = FileUpdationDB._privateConstructor();
  48. // only have a single app-wide reference to the database
  49. static Future<Database>? _dbFuture;
  50. Future<Database> get database async {
  51. // lazily instantiate the db the first time it is accessed
  52. _dbFuture ??= _initDatabase();
  53. return _dbFuture!;
  54. }
  55. // this opens the database (and creates it if it doesn't exist)
  56. Future<Database> _initDatabase() async {
  57. final Directory documentsDirectory =
  58. await getApplicationDocumentsDirectory();
  59. final String path = join(documentsDirectory.path, _databaseName);
  60. debugPrint("DB path " + path);
  61. return await openDatabaseWithMigration(path, dbConfig);
  62. }
  63. Future<void> clearTable() async {
  64. final db = await instance.database;
  65. await db.delete(tableName);
  66. }
  67. Future<void> insertMultiple(
  68. List<String> fileLocalIDs,
  69. String reason,
  70. ) async {
  71. final startTime = DateTime.now();
  72. final db = await instance.database;
  73. var batch = db.batch();
  74. int batchCounter = 0;
  75. for (String localID in fileLocalIDs) {
  76. if (batchCounter == 400) {
  77. await batch.commit(noResult: true);
  78. batch = db.batch();
  79. batchCounter = 0;
  80. }
  81. batch.insert(
  82. tableName,
  83. _getRowForReUploadTable(localID, reason),
  84. conflictAlgorithm: ConflictAlgorithm.replace,
  85. );
  86. batchCounter++;
  87. }
  88. await batch.commit(noResult: true);
  89. final endTime = DateTime.now();
  90. final duration = Duration(
  91. microseconds:
  92. endTime.microsecondsSinceEpoch - startTime.microsecondsSinceEpoch,
  93. );
  94. _logger.info(
  95. "Batch insert of ${fileLocalIDs.length} "
  96. "took ${duration.inMilliseconds} ms.",
  97. );
  98. }
  99. Future<void> deleteByLocalIDs(List<String> localIDs, String reason) async {
  100. if (localIDs.isEmpty) {
  101. return;
  102. }
  103. String inParam = "";
  104. for (final localID in localIDs) {
  105. inParam += "'" + localID + "',";
  106. }
  107. inParam = inParam.substring(0, inParam.length - 1);
  108. final db = await instance.database;
  109. await db.rawQuery(
  110. '''
  111. DELETE FROM $tableName
  112. WHERE $columnLocalID IN ($inParam) AND $columnReason = '$reason';
  113. ''',
  114. );
  115. }
  116. Future<List<String>> getLocalIDsForPotentialReUpload(
  117. int limit,
  118. String reason,
  119. ) async {
  120. final db = await instance.database;
  121. final String whereClause = '$columnReason = "$reason"';
  122. final rows = await db.query(
  123. tableName,
  124. limit: limit,
  125. where: whereClause,
  126. );
  127. final result = <String>[];
  128. for (final row in rows) {
  129. result.add(row[columnLocalID] as String);
  130. }
  131. return result;
  132. }
  133. Map<String, dynamic> _getRowForReUploadTable(String localID, String reason) {
  134. final row = <String, dynamic>{};
  135. row[columnLocalID] = localID;
  136. row[columnReason] = reason;
  137. return row;
  138. }
  139. }