guru_sdk/guru_app/packages/guru_utils/lib/database/database.dart

143 lines
4.4 KiB
Dart

import 'dart:io';
import 'package:dartx/dartx_io.dart';
import 'package:guru_utils/file/file_utils.dart';
import 'package:guru_utils/id/id_utils.dart';
import 'package:guru_utils/log/log.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
export 'batch/batch_data.dart';
export 'batch/batch_aware.dart';
export 'package:sqflite/sqflite.dart';
/// Created by Haoyi on 2022/8/24
///
part 'migration.dart';
typedef TableCreator = Future Function(Transaction delegate);
abstract class AppDatabase {
late Database _database;
List<TableCreator> get tableCreators;
List<Migration> get migrations;
int get version;
String get dbName;
Future<String> getTestingPath() async {
return "./mocks_dir/db";
}
Future _createTables(Database db) {
return db.transaction((Transaction delegate) async {
final List<TableCreator> creators = tableCreators;
for (var creator in creators) {
await creator(delegate);
}
});
}
Future _migrate(Database database, int from, int to) async {
Log.d("MIGRATE [$from] => [$to]");
final _migrations = migrations;
return database.transaction((txn) async {
for (int index = from - 1; (index < to - 1) && (index < _migrations.length); ++index) {
var result = MigrateResult.failed;
try {
Log.d("====> BEGIN MIGRATE [${index + 1}] => [${index + 2}]");
result = await _migrations[index].migrate(txn);
} catch (error) {
Log.d(" migrate [${index + 1}] => [${index + 2}] error:[$error]");
rethrow;
}
Log.d("====> END MIGRATE [${index + 1}] => [${index + 2}] result: $result");
}
});
}
Future initDatabase() async {
final isTesting = Platform.environment.containsKey('FLUTTER_TEST');
final dbDir = isTesting ? await getTestingPath() : await getDatabasesPath();
final dbPath = join(dbDir, "$dbName.db");
Log.d("dbPath:$dbPath");
_database = await openDatabase(
dbPath,
version: version,
onCreate: (Database db, int version) async {
// When creating the db, create the table
try {
await _createTables(db);
} catch (error, stacktrace) {
Log.w("createTables error! $error", stackTrace: stacktrace);
}
},
onUpgrade: (Database db, int oldVersion, int newVersion) async {
await _migrate(db, oldVersion, newVersion);
},
);
}
Database getDb() {
return _database;
}
Future<T> runInTransaction<T>(Future<T> Function(Transaction txn) action) {
return getDb().transaction(action);
}
Future backup(String token) async {
final uuid = IdUtils.keyUuid(token);
final isTesting = Platform.environment.containsKey('FLUTTER_TEST');
final dbDir = isTesting ? await getTestingPath() : await getDatabasesPath();
final dbFile = File(join(dbDir, "$dbName.db"));
final backupDbFile = File(join(dbDir, "$dbName.$uuid.db"));
Log.d("backup dbPath:${dbFile.name} to ${backupDbFile.name}");
if (await FileUtils.instance.checkFileExists(backupDbFile)) {
await backupDbFile.delete();
}
await dbFile.copy(backupDbFile.path);
}
Future<bool> restore(String token) async {
final uuid = IdUtils.keyUuid(token);
final isTesting = Platform.environment.containsKey('FLUTTER_TEST');
final dbDir = isTesting ? await getTestingPath() : await getDatabasesPath();
final dbFile = File(join(dbDir, "$dbName.db"));
final restoreDbFile = File(join(dbDir, "$dbName.$uuid.db"));
Log.d("restore dbPath:${restoreDbFile.name} to ${dbFile.name}");
if (await FileUtils.instance.checkFileExists(dbFile)) {
_database.close();
await dbFile.delete();
}
if (await FileUtils.instance.checkFileExists(restoreDbFile) == false) {
Log.w("backupDbFile not exists");
return false;
}
await restoreDbFile.copy(dbFile.path);
return true;
}
Future<bool> switchSession(String oldToken, String newToken) async {
if (oldToken == newToken) {
Log.w("same uid, no need to switch");
return false;
}
await getDb().close();
if (oldToken.isNotEmpty) {
await backup(oldToken);
}
await restore(newToken);
await initDatabase();
return true;
}
}
extension DatabaseExt on AppDatabase {
String joinTextValue(List<String> value, [String separator = ""]) {
return value.map((str) => "'$str'").toList().join(separator);
}
}