file_updation_db.dart 4.2 KB

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