Skip to content

Commit 0623505

Browse files
authored
Added refreshSchema() (#57)
* Added refreshSchema() to SqliteConnection interface. * Simplifying refreshSchema implementation by introducing exlusiveLock and refreshSchema in `sqlite_database`. * Cleanup of function comment. * Updated changelog. * Removed exclusiveLock, simplified implementation of refreshSchema. * squashed * chore(release): publish packages - [email protected] - [email protected] * Increased pana score threshold temporarily. * Added comment to pana threshold alteration.
1 parent 9428ad9 commit 0623505

File tree

11 files changed

+171
-5
lines changed

11 files changed

+171
-5
lines changed

CHANGELOG.md

+28
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,34 @@
33
All notable changes to this project will be documented in this file.
44
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
55

6+
## 2024-08-20
7+
8+
### Changes
9+
10+
---
11+
12+
Packages with breaking changes:
13+
14+
- There are no breaking changes in this release.
15+
16+
Packages with other changes:
17+
18+
- [`sqlite_async` - `v0.8.2`](#sqlite_async---v082)
19+
- [`drift_sqlite_async` - `v0.1.0-alpha.5`](#drift_sqlite_async---v010-alpha5)
20+
21+
Packages with dependency updates only:
22+
23+
> 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.
24+
25+
- `drift_sqlite_async` - `v0.1.0-alpha.5`
26+
27+
---
28+
29+
#### `sqlite_async` - `v0.8.2`
30+
31+
- **FEAT**: Added `refreshSchema()`, allowing queries and watch calls to work against updated schemas.
32+
33+
634
## 2024-07-10
735

836
### Changes

melos.yaml

+8-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ name: sqlite_async_monorepo
33
packages:
44
- packages/**
55

6+
command:
7+
version:
8+
changelog: false
9+
packageFilters:
10+
noPrivate: true
11+
612
scripts:
713
prepare: melos bootstrap && melos prepare:compile:webworker && melos prepare:sqlite:wasm
814

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

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

packages/drift_sqlite_async/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.1.0-alpha.5
2+
3+
- Update a dependency to the latest release.
4+
15
## 0.1.0-alpha.4
26

37
- Import `sqlite3_common` instead of `sqlite3` for web support.

packages/drift_sqlite_async/pubspec.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: drift_sqlite_async
2-
version: 0.1.0-alpha.4
2+
version: 0.1.0-alpha.5
33
homepage: https://github.com/powersync-ja/sqlite_async.dart
44
repository: https://github.com/powersync-ja/sqlite_async.dart
55
description: Use Drift with a sqlite_async database, allowing both to be used in the same application.
@@ -15,7 +15,7 @@ environment:
1515
sdk: ">=3.0.0 <4.0.0"
1616
dependencies:
1717
drift: ">=2.15.0 <2.19.0"
18-
sqlite_async: ^0.8.1
18+
sqlite_async: ^0.8.2
1919
dev_dependencies:
2020
build_runner: ^2.4.8
2121
drift_dev: ">=2.15.0 <2.19.0"

packages/sqlite_async/CHANGELOG.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1+
## 0.8.2
2+
3+
- **FEAT**: Added `refreshSchema()`, allowing queries and watch calls to work against updated schemas.
4+
15
## 0.8.1
26

3-
- Added Navigator locks for web `Mutex`s.
7+
- Added Navigator locks for web `Mutex`s.
48

59
## 0.8.0
610

packages/sqlite_async/lib/src/native/database/connection_pool.dart

+11
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,17 @@ class SqliteConnectionPool with SqliteQueries implements SqliteConnection {
221221
// read-only connections first.
222222
await _writeConnection?.close();
223223
}
224+
225+
@override
226+
Future<void> refreshSchema() async {
227+
final toRefresh = _allReadConnections.toList();
228+
229+
await _writeConnection?.refreshSchema();
230+
231+
for (var connection in toRefresh) {
232+
await connection.refreshSchema();
233+
}
234+
}
224235
}
225236

226237
typedef ReadCallback<T> = Future<T> Function(SqliteReadContext tx);

packages/sqlite_async/lib/src/native/database/native_sqlite_database.dart

+5
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,9 @@ class SqliteDatabaseImpl
166166
readOnly: false,
167167
openFactory: openFactory);
168168
}
169+
170+
@override
171+
Future<void> refreshSchema() {
172+
return _pool.refreshSchema();
173+
}
169174
}

packages/sqlite_async/lib/src/sqlite_connection.dart

+4
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ abstract class SqliteConnection extends SqliteWriteContext {
130130

131131
Future<void> close();
132132

133+
/// Ensures that all connections are aware of the latest schema changes applied (if any).
134+
/// Queries and watch calls can potentially use outdated schema information after a schema update.
135+
Future<void> refreshSchema();
136+
133137
/// Returns true if the connection is closed
134138
@override
135139
bool get closed;

packages/sqlite_async/lib/src/sqlite_queries.dart

+5
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,9 @@ mixin SqliteQueries implements SqliteWriteContext, SqliteConnection {
137137
return tx.executeBatch(sql, parameterSets);
138138
});
139139
}
140+
141+
@override
142+
Future<void> refreshSchema() {
143+
return get("PRAGMA table_info('sqlite_master')");
144+
}
140145
}

packages/sqlite_async/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: sqlite_async
22
description: High-performance asynchronous interface for SQLite on Dart and Flutter.
3-
version: 0.8.1
3+
version: 0.8.2
44
repository: https://github.com/powersync-ja/sqlite_async.dart
55
environment:
66
sdk: ">=3.4.0 <4.0.0"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
@TestOn('!browser')
2+
import 'dart:async';
3+
4+
import 'package:sqlite_async/sqlite_async.dart';
5+
import 'package:sqlite_async/src/utils/shared_utils.dart';
6+
import 'package:test/test.dart';
7+
8+
import '../utils/test_utils_impl.dart';
9+
10+
final testUtils = TestUtils();
11+
12+
void main() {
13+
group('Schema Tests', () {
14+
late String path;
15+
16+
setUp(() async {
17+
path = testUtils.dbPath();
18+
await testUtils.cleanDb(path: path);
19+
});
20+
21+
tearDown(() async {
22+
await testUtils.cleanDb(path: path);
23+
});
24+
25+
createTables(SqliteDatabase db) async {
26+
await db.writeTransaction((tx) async {
27+
await tx.execute(
28+
'CREATE TABLE _customers(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)');
29+
await tx.execute(
30+
'CREATE TABLE _local_customers(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)');
31+
await tx
32+
.execute('CREATE VIEW customers AS SELECT * FROM _local_customers');
33+
});
34+
}
35+
36+
updateTables(SqliteDatabase db) async {
37+
await db.writeTransaction((tx) async {
38+
await tx.execute('DROP VIEW IF EXISTS customers');
39+
await tx.execute('CREATE VIEW customers AS SELECT * FROM _customers');
40+
});
41+
}
42+
43+
test('should refresh schema views', () async {
44+
final db = await testUtils.setupDatabase(path: path);
45+
await createTables(db);
46+
47+
final customerTables =
48+
await getSourceTables(db, "select * from customers");
49+
expect(customerTables.contains('_local_customers'), true);
50+
await updateTables(db);
51+
52+
// without this, source tables are outdated
53+
await db.refreshSchema();
54+
55+
final updatedCustomerTables =
56+
await getSourceTables(db, "select * from customers");
57+
expect(updatedCustomerTables.contains('_customers'), true);
58+
});
59+
60+
test('should complete refresh schema after transaction', () async {
61+
var completer1 = Completer<void>();
62+
var transactionCompleted = false;
63+
64+
final db = await testUtils.setupDatabase(path: path);
65+
await createTables(db);
66+
67+
// Start a read transaction
68+
db.readTransaction((tx) async {
69+
completer1.complete();
70+
await tx.get('select test_sleep(2000)');
71+
72+
transactionCompleted = true;
73+
});
74+
75+
// Wait for the transaction to start
76+
await completer1.future;
77+
78+
var refreshSchemaFuture = db.refreshSchema();
79+
80+
// Setup check that refreshSchema completes after the transaction has completed
81+
var refreshAfterTransaction = false;
82+
refreshSchemaFuture.then((_) {
83+
if (transactionCompleted) {
84+
refreshAfterTransaction = true;
85+
}
86+
});
87+
88+
await refreshSchemaFuture;
89+
90+
expect(refreshAfterTransaction, isTrue,
91+
reason: 'refreshSchema completed before transaction finished');
92+
93+
// Sanity check
94+
expect(transactionCompleted, isTrue,
95+
reason: 'Transaction did not complete as expected');
96+
});
97+
});
98+
}

0 commit comments

Comments
 (0)