Skip to content

Commit f47f734

Browse files
committed
store: Throw exception when account already logged in
When account is already logged in, throw AccountAlreadyExists to allow caller to catch and handle exception.
1 parent 8e75c3c commit f47f734

File tree

4 files changed

+77
-3
lines changed

4 files changed

+77
-3
lines changed

lib/model/database.dart

+18-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import 'dart:io';
22

33
import 'package:drift/drift.dart';
44
import 'package:drift/native.dart';
5+
import 'package:drift/remote.dart';
56
import 'package:path/path.dart' as path;
67
import 'package:path_provider/path_provider.dart';
8+
import 'package:sqlite3/common.dart';
79

810
part 'database.g.dart';
911

@@ -103,7 +105,21 @@ class AppDatabase extends _$AppDatabase {
103105
);
104106
}
105107

106-
Future<int> createAccount(AccountsCompanion values) {
107-
return into(accounts).insert(values);
108+
Future<int> createAccount(AccountsCompanion values) async {
109+
try {
110+
return await into(accounts).insert(values);
111+
} catch (e) {
112+
// Unwrap cause if it's a remote Drift call. On the app, it's running
113+
// via a remote, but on local tests, it's running natively so
114+
// unwrapping is not required.
115+
final cause = (e is DriftRemoteException) ? e.remoteCause : e;
116+
if (cause case SqliteException(
117+
extendedResultCode: SqlExtendedError.SQLITE_CONSTRAINT_UNIQUE)) {
118+
throw AccountAlreadyExistsException();
119+
}
120+
rethrow;
121+
}
108122
}
109123
}
124+
125+
class AccountAlreadyExistsException implements Exception {}

lib/model/store.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import 'stream.dart';
2525
import 'unreads.dart';
2626

2727
export 'package:drift/drift.dart' show Value;
28-
export 'database.dart' show Account, AccountsCompanion;
28+
export 'database.dart' show Account, AccountsCompanion, AccountAlreadyExistsException;
2929

3030
/// Store for all the user's data.
3131
///

test/model/database_test.dart

+48
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,54 @@ void main() {
4141
'acked_push_token': null,
4242
});
4343
});
44+
45+
test('create account with same realm and userId ', () async {
46+
final accountData = AccountsCompanion.insert(
47+
realmUrl: Uri.parse('https://chat.example/'),
48+
userId: 1,
49+
50+
apiKey: '1234',
51+
zulipVersion: '6.0',
52+
zulipMergeBase: const Value('6.0'),
53+
zulipFeatureLevel: 42,
54+
);
55+
final accountDataWithSameUserId = AccountsCompanion.insert(
56+
realmUrl: Uri.parse('https://chat.example/'),
57+
userId: 1,
58+
59+
apiKey: '12345',
60+
zulipVersion: '6.0',
61+
zulipMergeBase: const Value('6.0'),
62+
zulipFeatureLevel: 42,
63+
);
64+
await database.createAccount(accountData);
65+
await check(database.createAccount(accountDataWithSameUserId))
66+
.throws<AccountAlreadyExistsException>();
67+
});
68+
69+
test('create account with same realm and email', () async {
70+
final accountData = AccountsCompanion.insert(
71+
realmUrl: Uri.parse('https://chat.example/'),
72+
userId: 1,
73+
74+
apiKey: '1234',
75+
zulipVersion: '6.0',
76+
zulipMergeBase: const Value('6.0'),
77+
zulipFeatureLevel: 42,
78+
);
79+
final accountDataWithSameEmail = AccountsCompanion.insert(
80+
realmUrl: Uri.parse('https://chat.example/'),
81+
userId: 2,
82+
83+
apiKey: '12345',
84+
zulipVersion: '6.0',
85+
zulipMergeBase: const Value('6.0'),
86+
zulipFeatureLevel: 42,
87+
);
88+
await database.createAccount(accountData);
89+
await check(database.createAccount(accountDataWithSameEmail))
90+
.throws<AccountAlreadyExistsException>();
91+
});
4492
});
4593

4694
group('migrations', () {

test/model/test_store.dart

+10
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,16 @@ class TestGlobalStore extends GlobalStore {
7676

7777
@override
7878
Future<Account> doInsertAccount(AccountsCompanion data) async {
79+
// Check for duplication is typically handled by the database but since
80+
// we're not using a real database, this needs to be handled here.
81+
// See [AppDatabase.createAccount].
82+
if (accounts.any((account) =>
83+
data.realmUrl.value == account.realmUrl
84+
&& (data.userId.value == account.userId
85+
|| data.email.value == account.email))) {
86+
throw AccountAlreadyExistsException();
87+
}
88+
7989
final accountId = data.id.present ? data.id.value : _nextAccountId++;
8090
return Account(
8191
id: accountId,

0 commit comments

Comments
 (0)