2023-06-17 21:50:52 +00:00
|
|
|
import 'dart:async';
|
2023-10-19 21:45:07 +00:00
|
|
|
import 'dart:io';
|
2023-07-20 20:56:00 +00:00
|
|
|
import 'package:flutter/foundation.dart';
|
2023-06-17 21:50:52 +00:00
|
|
|
import 'package:sqflite/sqflite.dart';
|
|
|
|
import 'package:path_provider/path_provider.dart' show MissingPlatformDirectoryException, getApplicationDocumentsDirectory;
|
|
|
|
import 'package:tetra_stats/services/crud_exceptions.dart';
|
|
|
|
import 'package:tetra_stats/services/tetrio_crud.dart';
|
|
|
|
import 'package:path/path.dart' show join;
|
|
|
|
|
|
|
|
const String dbName = "TetraStats.db";
|
|
|
|
|
2024-01-29 21:13:07 +00:00
|
|
|
/// Base class for CRUD services. Contains basic functions
|
2023-06-17 21:50:52 +00:00
|
|
|
class DB {
|
|
|
|
Database? _db;
|
2024-01-29 21:13:07 +00:00
|
|
|
|
|
|
|
/// Handles opening of DB and creates tables if they not exist
|
2023-06-17 21:50:52 +00:00
|
|
|
Future<void> open() async {
|
|
|
|
if (_db != null) {
|
2024-01-29 21:13:07 +00:00
|
|
|
// in order to not open DB multiple times
|
2023-06-17 21:50:52 +00:00
|
|
|
throw DatabaseAlreadyOpen();
|
|
|
|
}
|
|
|
|
try {
|
2023-07-20 20:56:00 +00:00
|
|
|
String dbPath;
|
2024-01-29 21:13:07 +00:00
|
|
|
if (kIsWeb) { // i hate web
|
2023-07-20 20:56:00 +00:00
|
|
|
dbPath = dbName;
|
|
|
|
} else {
|
|
|
|
final docsPath = await getApplicationDocumentsDirectory();
|
|
|
|
dbPath = join(docsPath.path, dbName);
|
|
|
|
}
|
2023-06-17 21:50:52 +00:00
|
|
|
final db = await openDatabase(dbPath);
|
|
|
|
_db = db;
|
|
|
|
await db.execute(createTetrioUsersTable);
|
|
|
|
await db.execute(createTetrioUsersToTrack);
|
2023-06-23 18:38:15 +00:00
|
|
|
await db.execute(createTetrioTLRecordsTable);
|
2024-01-08 22:42:49 +00:00
|
|
|
await db.execute(createTetrioTLReplayStats);
|
2024-09-01 21:44:19 +00:00
|
|
|
await db.execute(createTetrioLeagueTable);
|
2023-06-17 21:50:52 +00:00
|
|
|
} on MissingPlatformDirectoryException {
|
|
|
|
throw UnableToGetDocuments();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-29 21:13:07 +00:00
|
|
|
/// Handles closing of DB
|
2023-06-17 21:50:52 +00:00
|
|
|
Future<void> close() async {
|
|
|
|
final db = _db;
|
|
|
|
if (db == null) {
|
|
|
|
throw DatabaseIsNotOpen();
|
|
|
|
} else {
|
|
|
|
await db.close();
|
|
|
|
_db = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-29 21:13:07 +00:00
|
|
|
/// if we need instance of our DB, it will return it.
|
2023-06-17 21:50:52 +00:00
|
|
|
Database getDatabaseOrThrow() {
|
|
|
|
final db = _db;
|
|
|
|
if (db == null) {
|
|
|
|
throw DatabaseIsNotOpen();
|
|
|
|
} else {
|
|
|
|
return db;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-29 21:13:07 +00:00
|
|
|
/// You can never be too sure. Although we can be 100% sure, that DB is open after executing that function
|
2023-06-17 21:50:52 +00:00
|
|
|
Future<void> ensureDbIsOpen() async {
|
|
|
|
try {
|
|
|
|
await open();
|
|
|
|
} on DatabaseAlreadyOpen {
|
|
|
|
// empty
|
|
|
|
}
|
|
|
|
}
|
2023-10-19 21:45:07 +00:00
|
|
|
|
2024-01-29 21:13:07 +00:00
|
|
|
/// Executes VACUUM command for our DB and returns number of bytes, that was saved with this operation
|
2023-10-19 21:45:07 +00:00
|
|
|
Future<int> compressDB() async{
|
|
|
|
await ensureDbIsOpen();
|
|
|
|
final db = getDatabaseOrThrow();
|
|
|
|
String dbPath;
|
|
|
|
if (kIsWeb) {
|
|
|
|
dbPath = dbName;
|
|
|
|
} else {
|
|
|
|
final docsPath = await getApplicationDocumentsDirectory();
|
|
|
|
dbPath = join(docsPath.path, dbName);
|
|
|
|
}
|
|
|
|
var dbFile = File(dbPath);
|
|
|
|
var dbStats = await dbFile.stat();
|
|
|
|
await db.execute("VACUUM");
|
|
|
|
var newDBStats = await dbFile.stat();
|
|
|
|
return dbStats.size - newDBStats.size;
|
|
|
|
}
|
2024-11-04 22:20:36 +00:00
|
|
|
|
|
|
|
Future<bool> checkImportingDB(File db) async {
|
|
|
|
final newDB = await openDatabase(db.path);
|
|
|
|
var usersTable = await newDB.rawQuery("PRAGMA table_xinfo(`${tetrioUsersTable}`);");
|
|
|
|
List<String> usersTableRows = [for (Map<String, Object?> row in usersTable) row["name"] as String];
|
|
|
|
if (!listEquals(usersTableRows, tetrioUsersTableRows)) return false;
|
|
|
|
var usersToTrackTable = await newDB.rawQuery("PRAGMA table_xinfo(`${tetrioUsersToTrackTable}`);");
|
|
|
|
List<String> usersToTrackTableRows = [for (Map<String, Object?> row in usersToTrackTable) row["name"] as String];
|
|
|
|
if (!listEquals(usersToTrackTableRows, tetrioUsersToTrackTableRows)) return false;
|
|
|
|
var leagueMatchesTable = await newDB.rawQuery("PRAGMA table_xinfo(`${tetraLeagueMatchesTable}`);");
|
|
|
|
List<String> leagueMatchesTableRows = [for (Map<String, Object?> row in leagueMatchesTable) row["name"] as String];
|
|
|
|
if (!listEquals(leagueMatchesTableRows, tetraLeagueMatchesTableRows)) return false;
|
|
|
|
var tlReplayStatsTable = await newDB.rawQuery("PRAGMA table_xinfo(`${tetrioTLReplayStatsTable}`);");
|
|
|
|
List<String> TLReplayStatsTableRows = [for (Map<String, Object?> row in tlReplayStatsTable) row["name"] as String];
|
|
|
|
if (!listEquals(TLReplayStatsTableRows, tetrioTLReplayStatsTableRows)) return false;
|
|
|
|
var leagueTable = await newDB.rawQuery("PRAGMA table_xinfo(`${tetrioLeagueTable}`);");
|
|
|
|
List<String> leagueTableRows = [for (Map<String, Object?> row in leagueTable) row["name"] as String];
|
|
|
|
if (!listEquals(leagueTableRows, tetrioLeagueTableRows)) return false;
|
|
|
|
return true;
|
|
|
|
}
|
2023-06-17 21:50:52 +00:00
|
|
|
}
|