Skip to content

Added refreshSchema() #57

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Aug 20, 2024
Merged
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
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,34 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

## 2024-08-20

### Changes

---

Packages with breaking changes:

- There are no breaking changes in this release.

Packages with other changes:

- [`sqlite_async` - `v0.8.2`](#sqlite_async---v082)
- [`drift_sqlite_async` - `v0.1.0-alpha.5`](#drift_sqlite_async---v010-alpha5)

Packages with dependency updates only:

> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.

- `drift_sqlite_async` - `v0.1.0-alpha.5`

---

#### `sqlite_async` - `v0.8.2`

- **FEAT**: Added `refreshSchema()`, allowing queries and watch calls to work against updated schemas.


## 2024-07-10

### Changes
Expand Down
9 changes: 8 additions & 1 deletion melos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ name: sqlite_async_monorepo
packages:
- packages/**

command:
version:
changelog: false
packageFilters:
noPrivate: true

scripts:
prepare: melos bootstrap && melos prepare:compile:webworker && melos prepare:sqlite:wasm

Expand All @@ -26,9 +32,10 @@ scripts:
description: Analyze Dart code in packages.
run: dart analyze packages --fatal-infos

# TODO: Temporarily setting the exit-code-threshold to 10 until drift_sqlite_async dependencies are updated.
analyze:packages:pana:
description: Analyze Dart packages with Pana
exec: dart pub global run pana --no-warning --exit-code-threshold 0
exec: dart pub global run pana --no-warning --exit-code-threshold 10
packageFilters:
noPrivate: true

Expand Down
4 changes: 4 additions & 0 deletions packages/drift_sqlite_async/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.1.0-alpha.5

- Update a dependency to the latest release.

## 0.1.0-alpha.4

- Import `sqlite3_common` instead of `sqlite3` for web support.
Expand Down
4 changes: 2 additions & 2 deletions packages/drift_sqlite_async/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: drift_sqlite_async
version: 0.1.0-alpha.4
version: 0.1.0-alpha.5
homepage: https://github.com/powersync-ja/sqlite_async.dart
repository: https://github.com/powersync-ja/sqlite_async.dart
description: Use Drift with a sqlite_async database, allowing both to be used in the same application.
Expand All @@ -15,7 +15,7 @@ environment:
sdk: ">=3.0.0 <4.0.0"
dependencies:
drift: ">=2.15.0 <2.19.0"
sqlite_async: ^0.8.1
sqlite_async: ^0.8.2
dev_dependencies:
build_runner: ^2.4.8
drift_dev: ">=2.15.0 <2.19.0"
Expand Down
6 changes: 5 additions & 1 deletion packages/sqlite_async/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
## 0.8.2

- **FEAT**: Added `refreshSchema()`, allowing queries and watch calls to work against updated schemas.

## 0.8.1

- Added Navigator locks for web `Mutex`s.
- Added Navigator locks for web `Mutex`s.

## 0.8.0

Expand Down
11 changes: 11 additions & 0 deletions packages/sqlite_async/lib/src/native/database/connection_pool.dart
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,17 @@ class SqliteConnectionPool with SqliteQueries implements SqliteConnection {
// read-only connections first.
await _writeConnection?.close();
}

@override
Future<void> refreshSchema() async {
final toRefresh = _allReadConnections.toList();

await _writeConnection?.refreshSchema();

for (var connection in toRefresh) {
await connection.refreshSchema();
}
}
}

typedef ReadCallback<T> = Future<T> Function(SqliteReadContext tx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,4 +166,9 @@ class SqliteDatabaseImpl
readOnly: false,
openFactory: openFactory);
}

@override
Future<void> refreshSchema() {
return _pool.refreshSchema();
}
}
4 changes: 4 additions & 0 deletions packages/sqlite_async/lib/src/sqlite_connection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ abstract class SqliteConnection extends SqliteWriteContext {

Future<void> close();

/// Ensures that all connections are aware of the latest schema changes applied (if any).
/// Queries and watch calls can potentially use outdated schema information after a schema update.
Future<void> refreshSchema();

/// Returns true if the connection is closed
@override
bool get closed;
Expand Down
5 changes: 5 additions & 0 deletions packages/sqlite_async/lib/src/sqlite_queries.dart
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,9 @@ mixin SqliteQueries implements SqliteWriteContext, SqliteConnection {
return tx.executeBatch(sql, parameterSets);
});
}

@override
Future<void> refreshSchema() {
return get("PRAGMA table_info('sqlite_master')");
}
}
2 changes: 1 addition & 1 deletion packages/sqlite_async/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: sqlite_async
description: High-performance asynchronous interface for SQLite on Dart and Flutter.
version: 0.8.1
version: 0.8.2
repository: https://github.com/powersync-ja/sqlite_async.dart
environment:
sdk: ">=3.4.0 <4.0.0"
Expand Down
98 changes: 98 additions & 0 deletions packages/sqlite_async/test/native/schema_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
@TestOn('!browser')
import 'dart:async';

import 'package:sqlite_async/sqlite_async.dart';
import 'package:sqlite_async/src/utils/shared_utils.dart';
import 'package:test/test.dart';

import '../utils/test_utils_impl.dart';

final testUtils = TestUtils();

void main() {
group('Schema Tests', () {
late String path;

setUp(() async {
path = testUtils.dbPath();
await testUtils.cleanDb(path: path);
});

tearDown(() async {
await testUtils.cleanDb(path: path);
});

createTables(SqliteDatabase db) async {
await db.writeTransaction((tx) async {
await tx.execute(
'CREATE TABLE _customers(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)');
await tx.execute(
'CREATE TABLE _local_customers(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)');
await tx
.execute('CREATE VIEW customers AS SELECT * FROM _local_customers');
});
}

updateTables(SqliteDatabase db) async {
await db.writeTransaction((tx) async {
await tx.execute('DROP VIEW IF EXISTS customers');
await tx.execute('CREATE VIEW customers AS SELECT * FROM _customers');
});
}

test('should refresh schema views', () async {
final db = await testUtils.setupDatabase(path: path);
await createTables(db);

final customerTables =
await getSourceTables(db, "select * from customers");
expect(customerTables.contains('_local_customers'), true);
await updateTables(db);

// without this, source tables are outdated
await db.refreshSchema();

final updatedCustomerTables =
await getSourceTables(db, "select * from customers");
expect(updatedCustomerTables.contains('_customers'), true);
});

test('should complete refresh schema after transaction', () async {
var completer1 = Completer<void>();
var transactionCompleted = false;

final db = await testUtils.setupDatabase(path: path);
await createTables(db);

// Start a read transaction
db.readTransaction((tx) async {
completer1.complete();
await tx.get('select test_sleep(2000)');

transactionCompleted = true;
});

// Wait for the transaction to start
await completer1.future;

var refreshSchemaFuture = db.refreshSchema();

// Setup check that refreshSchema completes after the transaction has completed
var refreshAfterTransaction = false;
refreshSchemaFuture.then((_) {
if (transactionCompleted) {
refreshAfterTransaction = true;
}
});

await refreshSchemaFuture;

expect(refreshAfterTransaction, isTrue,
reason: 'refreshSchema completed before transaction finished');

// Sanity check
expect(transactionCompleted, isTrue,
reason: 'Transaction did not complete as expected');
});
});
}
Loading