Skip to content

Commit ed8f391

Browse files
committed
feat: implement deleteAll method and related tests for database cleanup
1 parent 808a553 commit ed8f391

File tree

11 files changed

+705
-4
lines changed

11 files changed

+705
-4
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ A high-performance, type-safe NoSQL database for Dart and Flutter applications.
3636
-**Field Validation**: Built-in validation with custom rules
3737
- 🔐 **Access Control**: Field-level visibility control
3838
- 🔄 **Relationships**: Support for one-to-many and many-to-many relationships
39+
- 🧹 **Data Management**: Methods for complete database cleanup and reset
3940

4041
## Installation
4142

documentation/docs/crud.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,22 @@ Future<void> _demonstrateCRUD(QuantaDB db) async {
118118

119119
The `delete` method removes the key-value pair associated with the given key.
120120

121+
### Delete All
122+
123+
To remove all data from the database, use the `deleteAll` method. This is useful for scenarios like logging out a user, clearing cache, or resetting the application state.
124+
125+
```dart
126+
// Example of deleting all data from the database
127+
Future<void> _demonstrateDeleteAll(QuantaDB db) async {
128+
print('Deleting all data from the database...');
129+
130+
// Call the deleteAll method
131+
await db.deleteAll();
132+
133+
print('All data has been deleted from the database');
134+
}
135+
```
136+
137+
> ⚠️ **Warning**: The `deleteAll` method removes all data from the database. This operation cannot be undone, so use it with caution.
138+
121139
These basic CRUD operations are the foundation for managing data in QuantaDB. In the next sections, we will explore more advanced topics like querying and transactions.

example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
buildConfiguration = "Debug"
2727
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
2828
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
2930
shouldUseLaunchSchemeArgsEnv = "YES">
3031
<MacroExpansion>
3132
<BuildableReference
@@ -54,11 +55,13 @@
5455
buildConfiguration = "Debug"
5556
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
5657
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
58+
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
5759
launchStyle = "0"
5860
useCustomWorkingDirectory = "NO"
5961
ignoresPersistentStateOnLaunch = "NO"
6062
debugDocumentVersioning = "YES"
6163
debugServiceExtension = "internal"
64+
enableGPUValidationMode = "1"
6265
allowLocationSimulation = "YES">
6366
<BuildableProductRunnable
6467
runnableDebuggingMode = "0">

example/ios/Runner/AppDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import Flutter
22
import UIKit
33

4-
@UIApplicationMain
4+
@main
55
@objc class AppDelegate: FlutterAppDelegate {
66
override func application(
77
_ application: UIApplication,

lib/quanta_db_imp.dart

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,41 @@ class QuantaDB {
114114
_isInitialized = false;
115115
}
116116

117+
/// Delete all data from the database
118+
///
119+
/// This method deletes all data from the database, including all SSTables and the memtable.
120+
/// Use with caution as this operation cannot be undone.
121+
Future<void> deleteAll() async {
122+
_checkInitialized();
123+
124+
try {
125+
// Get all keys from the memtable
126+
final allKeys = await storage.keys();
127+
128+
if (allKeys.isEmpty) {
129+
// No data to delete
130+
return;
131+
}
132+
133+
// For small datasets, use transaction for batch deletion
134+
if (allKeys.length < 10000) {
135+
await storage.transaction((txn) async {
136+
for (final key in allKeys) {
137+
await txn.delete(key);
138+
}
139+
});
140+
} else {
141+
// For large datasets, close and reinitialize for better performance
142+
// This effectively clears all data without individual deletions
143+
await storage.close();
144+
await storage.init();
145+
_isInitialized = true; // Ensure database remains initialized
146+
}
147+
} catch (e) {
148+
throw StorageException('Failed to delete all data: $e');
149+
}
150+
}
151+
117152
void _checkInitialized() {
118153
if (!_isInitialized) {
119154
throw StateError(

lib/src/storage/lsm_storage.dart

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// ignore_for_file: avoid_print
2+
13
import 'dart:async';
24
import 'dart:io';
35

@@ -71,7 +73,6 @@ class LSMStorage {
7173
final sstable = await SSTable.load(file.path);
7274
_sstables.add(sstable);
7375
} catch (e) {
74-
// ignore: avoid_print
7576
print('Error loading SSTable ${file.path}: $e');
7677
// Optionally delete corrupted files
7778
await file.delete();
@@ -307,8 +308,21 @@ class Transaction {
307308
/// Commit the transaction
308309
Future<void> commit() async {
309310
// Apply changes to the main storage
310-
for (final entry in _memTable.entries.entries) {
311-
await _storage.put(entry.key, entry.value);
311+
for (final change in _changes) {
312+
if (change.changeType == ChangeType.insert) {
313+
await _storage.put(change.key, change.value);
314+
} else if (change.changeType == ChangeType.delete) {
315+
try {
316+
// Check if key exists before deleting
317+
final exists = await _storage.get(change.key) != null;
318+
if (exists) {
319+
await _storage.delete(change.key);
320+
}
321+
} catch (e) {
322+
// Ignore errors for keys that don't exist
323+
print('Warning: Failed to delete key ${change.key}: $e');
324+
}
325+
}
312326
}
313327
}
314328

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// ignore_for_file: avoid_print
2+
3+
import 'dart:io';
4+
import 'package:quanta_db/quanta_db.dart';
5+
6+
void main() async {
7+
// Create a temporary directory for the test database
8+
final tempDir = await Directory.systemTemp.createTemp('quanta_db_test_');
9+
print('Created temporary directory: ${tempDir.path}');
10+
11+
try {
12+
// Open the database in the temporary directory
13+
print('\nOpening database...');
14+
final db = await QuantaDB.open(tempDir.path);
15+
await db.init();
16+
print('Database initialized');
17+
18+
// Populate the database with test data
19+
print('\nPopulating database with test data...');
20+
await db.put('test:1', {'name': 'Test 1', 'value': 100});
21+
await db.put('test:2', {'name': 'Test 2', 'value': 200});
22+
await db.put('test:3', {'name': 'Test 3', 'value': 300});
23+
print('Added 3 test records');
24+
25+
// Verify data was stored
26+
print('\nVerifying data was stored:');
27+
final value1 = await db.get('test:1');
28+
final value2 = await db.get('test:2');
29+
final value3 = await db.get('test:3');
30+
31+
print('test:1 = $value1');
32+
print('test:2 = $value2');
33+
print('test:3 = $value3');
34+
35+
// Delete all data
36+
print('\nDeleting all data...');
37+
await db.deleteAll();
38+
print('All data deleted');
39+
40+
// Verify all data was deleted
41+
print('\nVerifying all data was deleted:');
42+
final deletedValue1 = await db.get('test:1');
43+
final deletedValue2 = await db.get('test:2');
44+
final deletedValue3 = await db.get('test:3');
45+
46+
print('test:1 = $deletedValue1');
47+
print('test:2 = $deletedValue2');
48+
print('test:3 = $deletedValue3');
49+
50+
// Add new data after deletion
51+
print('\nAdding new data after deletion...');
52+
await db.put('test:new', {'name': 'New Test', 'value': 999});
53+
print('Added new test record');
54+
55+
// Verify new data exists
56+
print('\nVerifying new data exists:');
57+
final newValue = await db.get('test:new');
58+
print('test:new = $newValue');
59+
60+
// Close the database
61+
print('\nClosing database...');
62+
await db.close();
63+
print('Database closed');
64+
65+
print('\nTest completed successfully!');
66+
} catch (e, stackTrace) {
67+
print('Error: $e');
68+
print('Stack trace: $stackTrace');
69+
} finally {
70+
// Clean up the temporary directory
71+
print('\nCleaning up temporary directory...');
72+
if (await tempDir.exists()) {
73+
await tempDir.delete(recursive: true);
74+
print('Temporary directory deleted');
75+
}
76+
}
77+
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import 'dart:async';
2+
import 'package:quanta_db/quanta_db.dart';
3+
4+
// A simple user model for testing
5+
class User {
6+
final String id;
7+
final String name;
8+
final int age;
9+
final bool isActive;
10+
11+
User(this.id, this.name, this.age, this.isActive);
12+
13+
Map<String, dynamic> toMap() {
14+
return {
15+
'id': id,
16+
'name': name,
17+
'age': age,
18+
'isActive': isActive,
19+
};
20+
}
21+
22+
factory User.fromMap(Map<String, dynamic> map) {
23+
return User(
24+
map['id'],
25+
map['name'],
26+
map['age'],
27+
map['isActive'],
28+
);
29+
}
30+
31+
@override
32+
String toString() {
33+
return 'User{id: $id, name: $name, age: $age, isActive: $isActive}';
34+
}
35+
}
36+
37+
Future<void> main() async {
38+
print('Starting performance test for deleteAll method...');
39+
40+
// Open the database
41+
var db = await QuantaDB.open('delete_all_performance_test');
42+
db.init();
43+
44+
// Number of records to insert
45+
const int recordCount = 10000; // Use 10,000 for testing, can be increased
46+
47+
try {
48+
// Insert a large number of records
49+
print('Inserting $recordCount records...');
50+
final Stopwatch insertStopwatch = Stopwatch()..start();
51+
52+
for (int i = 0; i < recordCount; i++) {
53+
final user = User(
54+
'user_$i',
55+
'User $i',
56+
20 + (i % 50), // Ages between 20-69
57+
i % 2 == 0, // Half active, half inactive
58+
);
59+
60+
await db.storage.put(user.id, user.toMap());
61+
62+
// Print progress every 1000 records
63+
if ((i + 1) % 1000 == 0) {
64+
print('Inserted ${i + 1} records...');
65+
}
66+
}
67+
68+
insertStopwatch.stop();
69+
print(
70+
'Inserted $recordCount records in ${insertStopwatch.elapsedMilliseconds}ms');
71+
72+
// Verify record count
73+
final allKeys = await db.storage.keys();
74+
print('Total records in database: ${allKeys.length}');
75+
76+
// Delete all records and measure time
77+
print('\nDeleting all records using deleteAll method...');
78+
final Stopwatch deleteStopwatch = Stopwatch()..start();
79+
80+
try {
81+
await db.deleteAll();
82+
deleteStopwatch.stop();
83+
print('Deleted all records in ${deleteStopwatch.elapsedMilliseconds}ms');
84+
} catch (e) {
85+
deleteStopwatch.stop();
86+
print('Error during deleteAll: $e');
87+
print('Attempting to reopen the database...');
88+
89+
// Reopen the database
90+
db = await QuantaDB.open('delete_all_performance_test');
91+
print('Database reopened successfully.');
92+
}
93+
94+
// Verify deletion
95+
final remainingKeys = await db.storage.keys();
96+
print('Remaining records in database: ${remainingKeys.length}');
97+
98+
if (remainingKeys.isEmpty) {
99+
print('\nSuccess: All records were deleted successfully!');
100+
} else {
101+
print(
102+
'\nWarning: Some records were not deleted. Remaining: ${remainingKeys.length}');
103+
}
104+
} catch (e) {
105+
print('Error during test: $e');
106+
} finally {
107+
// Close the database
108+
await db.close();
109+
print('\nTest completed.');
110+
}
111+
}

0 commit comments

Comments
 (0)