Skip to content

Commit

Permalink
feat: add database about sql and operations
Browse files Browse the repository at this point in the history
  • Loading branch information
FriesI23 committed Feb 28, 2025
1 parent 6116355 commit 2bf00df
Show file tree
Hide file tree
Showing 15 changed files with 459 additions and 33 deletions.
11 changes: 11 additions & 0 deletions assets/sql/mh_sync.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CREATE TABLE IF NOT EXISTS mh_sync (
id_ INTEGER PRIMARY KEY AUTOINCREMENT,
create_t INTEGER NOT NULL DEFAULT (cast(strftime('%s','now') as int)),
modify_t INTEGER NOT NULL DEFAULT (cast(strftime('%s','now') as int)),
habit_uuid TEXT UNIQUE REFERENCES mh_habits(uuid),
record_uuid TEXT UNIQUE REFERENCES mh_records(uuid),
dirty INTEGER NOT NULL DEFAULT 1,
last_config_uuid TEXT,
last_session_uuid TEXT,
last_mark TEXT
);
3 changes: 3 additions & 0 deletions assets/sql/mh_sync_indexes.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CREATE UNIQUE INDEX IF NOT EXISTS idx_mh_sync_habit_uuid ON mh_sync (habit_uuid);
CREATE UNIQUE INDEX IF NOT EXISTS idx_mh_sync_record_uuid ON mh_sync (record_uuid);
CREATE INDEX IF NOT EXISTS idx_mh_sync_dirty ON mh_sync (dirty);
9 changes: 8 additions & 1 deletion lib/assets/assets.gen.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion lib/common/consts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ const String debuggerZipFile = "debug.zip";
/// - add record reason column
/// ## version 3
/// - add daily goal extra column
const int appDBVersion = 3;
/// ## version 4
/// - add sync table
const int appDBVersion = 4;
//#endregion

//#region app-theme
Expand Down
2 changes: 1 addition & 1 deletion lib/model/habit_import.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class HabitImport {
type: habitDBCell.type ?? defaultHabitType.dbCode);
final dbid = await helper.insertNewHabit(habitDBCell);
if (withRecords) {
await recordDBHelper.insertMultiRecords(
await recordDBHelper.insertOrUpdateMultiRecords(
habitExportData.getRecordDBCells().map(
(e) => e.copyWith(
parentId: dbid,
Expand Down
7 changes: 4 additions & 3 deletions lib/persistent/db_helper_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,14 +102,14 @@ abstract mixin class DBHelperLoadedMixin {

mixin DBOperationsMixin on DBHelperLoadedMixin {
Future<RecordDBCell> saveHabitRecordToDB(
DBID parendId, HabitUUID parendUUID, HabitSummaryRecord record,
DBID parentId, HabitUUID parentUUID, HabitSummaryRecord record,
{bool isNew = false, String? withReason}) async {
final int dbid;
final RecordDBCell dbCell;
if (isNew) {
dbCell = RecordDBCell.build(
parentId: parendId,
parentUUID: parendUUID,
parentId: parentId,
parentUUID: parentUUID,
uuid: record.uuid,
recordDate: record.date.epochDay,
recordType: record.status.dbCode,
Expand All @@ -120,6 +120,7 @@ mixin DBOperationsMixin on DBHelperLoadedMixin {
} else {
dbCell = RecordDBCell(
uuid: record.uuid,
parentUUID: parentUUID,
recordType: record.status.dbCode,
recordValue: record.value,
reason: withReason,
Expand Down
44 changes: 44 additions & 0 deletions lib/persistent/local/db_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import '../../utils/app_path_provider.dart';
import '../utils.dart';
import 'handler/habit.dart';
import 'handler/record.dart';
import 'handler/sync.dart';
import 'sql.dart';
import 'table.dart';

Expand Down Expand Up @@ -71,9 +72,11 @@ class _DBHelper implements DBHelper {
Future<void> _onCreate(Database db, int version) async {
await db.execute(await getSqlFromFile(Assets.sql.mhHabits));
await db.execute(await getSqlFromFile(Assets.sql.mhRecords));
await db.execute(await getSqlFromFile(Assets.sql.mhSync));
final indexesBatch = db.batch();
await Future.wait([
getSqlFromFile(Assets.sql.indexes),
getSqlFromFile(Assets.sql.mhSyncIndexes)
]).then((dataList) {
for (var data in dataList) {
db.batchLines(data, indexesBatch);
Expand All @@ -82,6 +85,7 @@ class _DBHelper implements DBHelper {
await db.execute(CustomSql.autoUpdateHabitsModifyTimeTrigger);
await db.execute(CustomSql.autoUpdateRecordsModifyTimeTrigger);
await db.execute(CustomSql.autoAddSortPostionWhenAddNewHabit);
await db.execute(CustomSql.autoUpdateSyncModifyTimeTrigger);
}

Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
Expand All @@ -103,6 +107,14 @@ class _DBHelper implements DBHelper {
"ADD COLUMN ${HabitDBCellKey.dailyGoalExtra} REAL");
}
}
if (oldVersion < 4) {
await db.execute(await getSqlFromFile(Assets.sql.mhSync));
await db
.batchLines(await getSqlFromFile(Assets.sql.mhSyncIndexes))
.commit();
await db.execute(CustomSql.autoUpdateSyncModifyTimeTrigger);
await DatabaseToV4MigrateHelper(db).initSyncTable();
}
}

Future<Database> _openDB(String dbPath) async {
Expand Down Expand Up @@ -205,6 +217,38 @@ class _DBHelper implements DBHelper {
}
}

class DatabaseToV4MigrateHelper {
final Database db;

const DatabaseToV4MigrateHelper(this.db);

Future<void> initSyncTable() async {
final batch = db.batch();
await Future.wait([
db
.query(TableName.habits, columns: [HabitDBCellKey.uuid])
.then((result) => result.map((e) => e[HabitDBCellKey.uuid] as String))
.then((uuidList) {
for (var uuid in uuidList) {
batch.insert(TableName.sync, {SyncDbCellKey.habitUUID: uuid},
conflictAlgorithm: ConflictAlgorithm.ignore);
}
}),
db
.query(TableName.records, columns: [RecordDBCellKey.uuid])
.then(
(result) => result.map((e) => e[RecordDBCellKey.uuid] as String))
.then((uuidList) {
for (var uuid in uuidList) {
batch.insert(TableName.sync, {SyncDbCellKey.recordUUID: uuid},
conflictAlgorithm: ConflictAlgorithm.ignore);
}
}),
]);
await batch.commit(continueOnError: true, noResult: true);
}
}

abstract class DBHelperHandler {
final DBHelper helper;

Expand Down
50 changes: 42 additions & 8 deletions lib/persistent/local/handler/habit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ import '../../../common/types.dart';
import '../../../model/habit_form.dart';
import '../db_cell.dart';
import '../db_helper.dart';
import '../sql.dart';
import '../table.dart';
import 'sync.dart';

part 'habit.g.dart';

Expand Down Expand Up @@ -124,10 +126,19 @@ class HabitDBHelper extends DBHelperHandler {
@override
String get table => TableName.habits;

String get syncTable => TableName.sync;

Future<int> insertNewHabit(HabitDBCell habit) {
assert(habit.uuid != null);

return db.insert(table, habit.toJson());
return db.transaction((db) async {
final result = await db.insert(table, habit.toJson());
if (result > 0) {
await db.insert(syncTable, SyncDBCell.genFromHabit(habit).toJson(),
conflictAlgorithm: ConflictAlgorithm.rollback);
}
return result;
});
}

Future<int> updateExistHabit(HabitDBCell habit,
Expand All @@ -140,8 +151,15 @@ class HabitDBHelper extends DBHelperHandler {
if (!dbMap.containsKey(key)) dbMap[key] = null;
}

return db.update(table, dbMap,
where: "${HabitDBCellKey.uuid} = ?", whereArgs: [habitUUID]);
return db.transaction((db) async {
final result = await db.update(table, dbMap,
where: "${HabitDBCellKey.uuid} = ?", whereArgs: [habitUUID]);
await db.rawUpdate(
CustomSql.increaseHabitSyncDirtySql(
conflictAlgorithm: ConflictAlgorithm.rollback),
[habitUUID]);
return result;
});
}

Future<void> updateSelectedHabitsSortPostion(
Expand All @@ -156,16 +174,32 @@ class HabitDBHelper extends DBHelperHandler {
whereArgs: [uuid],
conflictAlgorithm: ConflictAlgorithm.rollback);
});
await batch.commit();
batch.rawUpdate(
CustomSql.increaseMultiHabitsSyncDirtySql(
count: uuidList.length,
conflictAlgorithm: ConflictAlgorithm.rollback),
uuidList);
await batch.commit(exclusive: true);
});
}

Future<int> updateSelectedHabitStatus(
List<HabitUUID> uuidList, HabitStatus newStatus) {
return db.update(table, {HabitDBCellKey.status: newStatus.dbCode},
where: "${HabitDBCellKey.uuid} "
"IN (${uuidList.map((e) => '?').join(', ')})",
whereArgs: uuidList);
return db.transaction((db) async {
final result =
await db.update(table, {HabitDBCellKey.status: newStatus.dbCode},
where: "${HabitDBCellKey.uuid} "
"IN (${uuidList.map((e) => '?').join(', ')})",
whereArgs: uuidList);
if (result > 0) {
await db.rawUpdate(
CustomSql.increaseMultiHabitsSyncDirtySql(
count: uuidList.length,
conflictAlgorithm: ConflictAlgorithm.rollback),
uuidList);
}
return result;
});
}

Future<HabitDBCell?> queryHabitByDBID(DBID dbid) {
Expand Down
62 changes: 46 additions & 16 deletions lib/persistent/local/handler/record.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ import 'package:sqflite/sqflite.dart';
import '../../../common/types.dart';
import '../db_cell.dart';
import '../db_helper.dart';
import '../sql.dart';
import '../table.dart';
import 'habit.dart';
import 'sync.dart';

part 'record.g.dart';

Expand Down Expand Up @@ -100,15 +102,33 @@ class RecordDBHelper extends DBHelperHandler {

String get habitTable => TableName.habits;

String get syncTable => TableName.sync;

Future<int> insertNewRecord(RecordDBCell record) {
assert(record.uuid != null);

return db.insert(table, record.toJson());
return db.transaction((db) => _insertNewRecordTransaction(record, db));
}

Future<int> _insertNewRecordTransaction(
RecordDBCell record, Transaction txn) async {
final result = await txn.insert(table, record.toJson(),
conflictAlgorithm: ConflictAlgorithm.replace);
if (result > 0) {
await Future.wait([
txn.insert(syncTable, SyncDBCell.genFromRecord(record).toJson(),
conflictAlgorithm: ConflictAlgorithm.rollback),
txn.rawUpdate(
CustomSql.increaseHabitSyncDirtySql(
conflictAlgorithm: ConflictAlgorithm.rollback),
[record.parentUUID]),
]);
}
return result;
}

Future<void> insertMultiRecords(Iterable<RecordDBCell> records,
{bool updateIfExist = false}) async {
await db.transaction((db) async {
Future<void> insertOrUpdateMultiRecords(Iterable<RecordDBCell> records) {
return db.transaction((db) async {
final tasks = <Future>[];
for (var record in records) {
tasks.add(
Expand All @@ -117,17 +137,9 @@ class RecordDBHelper extends DBHelperHandler {
where: "${RecordDBCellKey.uuid} = ?",
whereArgs: [record.uuid],
limit: 1)
.then((result) async {
if (result.isEmpty) {
await db.insert(table, record.toJson(),
conflictAlgorithm: ConflictAlgorithm.ignore);
} else {
await db.update(table, record.toJson(),
where: '${RecordDBCellKey.uuid} = ?',
whereArgs: [record.uuid],
conflictAlgorithm: ConflictAlgorithm.ignore);
}
}),
.then((result) => result.isEmpty
? _insertNewRecordTransaction(record, db)
: _updateRecordTransaction(record, db)),
);
}

Expand All @@ -138,8 +150,26 @@ class RecordDBHelper extends DBHelperHandler {
Future<int> updateRecord(RecordDBCell record) {
assert(record.uuid != null);

return db.update(table, record.toJson(),
return db.transaction((db) => _updateRecordTransaction(record, db));
}

Future<int> _updateRecordTransaction(
RecordDBCell record, Transaction txn) async {
final result = await txn.update(table, record.toJson(),
where: '${RecordDBCellKey.uuid} = ?', whereArgs: [record.uuid]);
if (result > 0) {
await Future.wait([
txn.rawUpdate(
CustomSql.increaseRecordSyncDirtySql(
conflictAlgorithm: ConflictAlgorithm.rollback),
[record.uuid]),
txn.rawUpdate(
CustomSql.increaseHabitSyncDirtySql(
conflictAlgorithm: ConflictAlgorithm.rollback),
[record.parentUUID]),
]);
}
return result;
}

static const _loadRecordDataColumns = [
Expand Down
Loading

0 comments on commit 2bf00df

Please sign in to comment.