Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/powersync_core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 1.7.0-dev

- Update PowerSync core extension to 0.4.8.
- `disconnectAndClear()`: Add `soft` parameter to only delete public data, allowing it to be reconstructed quickly.
- Raw tables: Add `clear` parameter to clear raw tables in `disconnectAndClear()`.

## 1.6.1

- Web: Fix decoding sync streams on status.
Expand Down
2 changes: 1 addition & 1 deletion packages/powersync_core/lib/src/database/core_version.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ extension type const PowerSyncCoreVersion((int, int, int) _tuple) {
// - scripts/download_core_binary_demos.dart
// - packages/sqlite3_wasm_build/build.sh
// - Android and Darwin (CocoaPods and SwiftPM) in powersync_flutter_libs
static const minimum = PowerSyncCoreVersion((0, 4, 6));
static const minimum = PowerSyncCoreVersion((0, 4, 8));

/// The first version of the core extensions that this version of the Dart
/// SDK doesn't support.
Expand Down
26 changes: 22 additions & 4 deletions packages/powersync_core/lib/src/database/powersync_db_mixin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -245,17 +245,35 @@ mixin PowerSyncDatabaseMixin implements SqliteConnection {

/// Disconnect and clear the database.
///
/// Use this when logging out.
/// Clearing the database is useful when a user logs out, to ensure another
/// user logging in later would not see previous data.
///
/// The database can still be queried after this is called, but the tables
/// would be empty.
///
/// To preserve data in local-only tables, set [clearLocal] to false.
Future<void> disconnectAndClear({bool clearLocal = true}) async {
/// To preserve data in local-only tables, set [clearLocal] to `false`.
///
/// A [soft] clear deletes publicly visible data, but keeps internal copies of
/// data synced in the database. This usually means that if the same user logs
/// out and back in again, the first sync is very fast because all internal
/// data is still available. WHen a different user logs in, no old data would
/// be visible at any point.
/// Using soft deletes is recommended where it's not a security issue that old
/// data could be reconstructible from the database.
Future<void> disconnectAndClear(
{bool clearLocal = true, bool soft = false}) async {
await disconnect();

await writeTransaction((tx) async {
await tx.execute('select powersync_clear(?)', [clearLocal ? 1 : 0]);
var flags = 0;
if (clearLocal) {
flags |= 1; // MASK_CLEAR_LOCAL
}
if (soft) {
flags |= 2; // MASK_SOFT_CLEAR
}

await tx.execute('select powersync_clear(?)', [flags]);
});
// The data has been deleted - reset these
setStatus(SyncStatus(lastSyncedAt: null, hasSynced: false));
Expand Down
12 changes: 12 additions & 0 deletions packages/powersync_core/lib/src/schema.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/// @docImport 'database/powersync_db_mixin.dart';
library;

import 'crud.dart';
import 'schema_logic.dart';

Expand Down Expand Up @@ -368,16 +371,25 @@ final class RawTable {
/// used here must all be [PendingStatementValue.id].
final PendingStatement delete;

/// An optional SQL statement to run when a PowerSync database is cleared.
///
/// When this value is unset, clearing the database (via
/// [PowerSyncDatabaseMixin.disconnectAndClear]) would not affect the raw
/// table.
final String? clear;

const RawTable({
required this.name,
required this.put,
required this.delete,
this.clear,
});

Map<String, dynamic> toJson() => {
'name': name,
'put': put,
'delete': delete,
'clear': clear,
};
}

Expand Down
56 changes: 56 additions & 0 deletions packages/powersync_core/test/disconnect_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,61 @@ void main() {
final changes = await changesFuture;
expect(changes.first, equals(UpdateNotification({'customers'})));
});

test('soft clear', () async {
final db = await testUtils.setupPowerSync(path: path, schema: testSchema);
addTearDown(db.close);

await db.execute(
'INSERT INTO customers (id, name) VALUES(uuid(), ?)', ['testuser']);
await db.execute(
'INSERT INTO ps_buckets (name, last_applied_op) VALUES (?, ?)',
['bkt', 10],
);

// Doing a soft-clear should delete data but keep the bucket around.
await db.disconnectAndClear(soft: true);
expect(await db.getAll('SELECT * FROM ps_buckets'), hasLength(1));

// Doing a default clear also deletes buckets.
await db.disconnectAndClear();
expect(await db.getAll('SELECT * FROM ps_buckets'), isEmpty);
});

test('clear raw tables', () async {
final db = await testUtils.setupPowerSync(
path: path,
schema: Schema(
rawTables: [
RawTable(
name: 'lists',
put: PendingStatement(
sql: 'INSERT OR REPLACE INTO lists (id, name) VALUES (?, ?)',
params: [
PendingStatementValue.id(),
PendingStatementValue.column('name')
],
),
delete: PendingStatement(
sql: 'DELETE FROM lists WHERE id = ?',
params: [PendingStatementValue.id()],
),
clear: 'DELETE FROM lists',
),
],
[],
),
);
addTearDown(db.close);

await db.execute(
'CREATE TABLE lists (id TEXT NOT NULL PRIMARY KEY, name TEXT)');
await db
.execute('INSERT INTO lists (id, name) VALUES (uuid(), ?)', ['list']);

expect(await db.getAll('SELECT * FROM lists'), hasLength(1));
await db.disconnectAndClear();
expect(await db.getAll('SELECT * FROM lists'), isEmpty);
});
});
}
2 changes: 1 addition & 1 deletion packages/powersync_flutter_libs/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,5 @@ android {
}

dependencies {
implementation 'com.powersync:powersync-sqlite-core:0.4.6'
implementation 'com.powersync:powersync-sqlite-core:0.4.8'
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ A new Flutter FFI plugin project.
s.osx.deployment_target = '10.15'

# NOTE: Always update Package.swift as well when updating this!
s.dependency "powersync-sqlite-core", "~> 0.4.6"
s.dependency "powersync-sqlite-core", "~> 0.4.8"

# Flutter.framework does not contain a i386 slice.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
Expand Down
4 changes: 2 additions & 2 deletions packages/powersync_flutter_libs/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ set(CORE_FILE_NAME "libpowersync.so")

set(POWERSYNC_ARCH ${CMAKE_SYSTEM_PROCESSOR})
if (${POWERSYNC_ARCH} MATCHES "x86_64" OR ${POWERSYNC_ARCH} MATCHES "AMD64")
set(CORE_FILE_NAME "libpowersync_x64.so")
set(CORE_FILE_NAME "libpowersync_x64.linux.so")
elseif (${POWERSYNC_ARCH} MATCHES "^arm64" OR ${POWERSYNC_ARCH} MATCHES "^armv8")
set(CORE_FILE_NAME "libpowersync_aarch64.so")
set(CORE_FILE_NAME "libpowersync_aarch64.linux.so")
endif ()

set(POWERSYNC_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${CORE_FILE_NAME}")
Expand Down
2 changes: 1 addition & 1 deletion packages/sqlite3_wasm_build/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
set -e

SQLITE_VERSION="2.9.0"
POWERSYNC_CORE_VERSION="0.4.6"
POWERSYNC_CORE_VERSION="0.4.8"
SQLITE_PATH="sqlite3.dart"

if [ -d "$SQLITE_PATH" ]; then
Expand Down
6 changes: 3 additions & 3 deletions scripts/download_core_binary_demos.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
import 'dart:io';

final coreUrl =
'https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v0.4.6';
'https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v0.4.8';

void main() async {
final powersyncLibsLinuxPath = "packages/powersync_flutter_libs/linux";
final powersyncLibsWindowsPath = "packages/powersync_flutter_libs/windows";

final linuxArm64FileName = "libpowersync_aarch64.so";
final linuxX64FileName = "libpowersync_x64.so";
final linuxArm64FileName = "libpowersync_aarch64.linux.so";
final linuxX64FileName = "libpowersync_x64.linux.so";
final windowsX64FileName = "powersync_x64.dll";

// Download dynamic library
Expand Down
10 changes: 5 additions & 5 deletions scripts/init_powersync_core_binary.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'dart:io';
import 'package:melos/melos.dart';

final sqliteUrl =
'https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v0.4.6';
'https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v0.4.8';

void main() async {
final sqliteCoreFilename = getLibraryForPlatform();
Expand Down Expand Up @@ -72,13 +72,13 @@ Future<void> downloadFile(String url, String savePath) async {
String getLibraryForPlatform() {
switch (Abi.current()) {
case Abi.macosArm64:
return 'libpowersync_aarch64.dylib';
return 'libpowersync_aarch64.macos.dylib';
case Abi.macosX64:
return 'libpowersync_x64.dylib';
return 'libpowersync_x64.macos.dylib';
case Abi.linuxX64:
return 'libpowersync_x64.so';
return 'libpowersync_x64.linux.so';
case Abi.linuxArm64:
return 'libpowersync_aarch64.so';
return 'libpowersync_aarch64.linux.so';
case Abi.windowsX64:
return 'powersync_x64.dll';
case Abi.windowsArm64:
Expand Down