Skip to content

Commit 02afa7d

Browse files
authored
Merge pull request #19 from olmps/architecture-updates
Architecture updates
2 parents 470730d + 0f34dea commit 02afa7d

29 files changed

+444
-414
lines changed

.resources/00arch_overview.png

-106 KB
Binary file not shown.

.resources/00arch_overview_simple.png

107 KB
Loading
102 KB
Loading

ARCHITECTURE.md

Lines changed: 150 additions & 69 deletions
Large diffs are not rendered by default.

CHANGELOG.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
Releases here should only be made whenever there is a build available for them in the respective stores (even if it's
99
a beta or production release, they must be documented here).
1010

11-
## Unreleased
11+
## [Unreleased]
1212

1313
> Android build: ?
14-
> iOS build: ?
14+
> iOS build: ?
15+
16+
## [0.1.0-dev.1] - 2021-04-01
17+
18+
Initial release, defines core architecture.
19+
The application is unusable on this version.

lib/application/view-models/app_vm.dart

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import 'package:flutter/foundation.dart';
22
import 'package:flutter_riverpod/flutter_riverpod.dart';
3-
import 'package:memo/data/database_repository.dart';
4-
import 'package:memo/data/sembast_database.dart' as sembast_db;
3+
import 'package:memo/data/repositories/deck_repository.dart';
4+
import 'package:memo/domain/services/deck_services.dart';
5+
import 'package:memo/data/gateways/document_database_gateway.dart';
6+
import 'package:memo/data/gateways/sembast_database.dart' as sembast_db;
57
import 'package:sembast/sembast.dart';
68

79
/// Manages all app asynchronous dependencies
@@ -41,14 +43,16 @@ class AppVMImpl extends AppVM {
4143
//
4244
// All of these needs a late initialization due to runtime dependencies, which we will only know after some async
4345
// initialization.
44-
final dbRepo = DatabaseRepositoryImpl(dependencies[0] as Database);
45-
// final exampleServices = HabitsServicesImpl(dbRepo: dbRepo);
46-
// return AppState(exampleServices: exampleServices);
47-
value = AsyncValue.data(AppState());
46+
47+
final dbRepo = SembastGateway(dependencies[0] as Database);
48+
final decksRepo = DeckRepositoryImpl(dbRepo);
49+
final deckServices = DeckServicesImpl(decksRepo);
50+
51+
value = AsyncValue.data(AppState(deckServices: deckServices));
4852
}
4953
}
5054

5155
class AppState {
52-
// const AppState({required this.exampleServices});
53-
// final ExampleServices exampleServices;
56+
const AppState({required this.deckServices});
57+
final DeckServices deckServices;
5458
}

lib/data/database_repository.dart

Lines changed: 0 additions & 157 deletions
This file was deleted.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import 'dart:async';
2+
import 'package:sembast/sembast.dart';
3+
4+
/// Handles the local persistence to the database
5+
abstract class DocumentDatabaseGateway {
6+
/// Adds an [object] to the [store], using a [id]
7+
///
8+
/// If there is already an object with the same [id], the default behavior is to merge all of its fields.
9+
/// [shouldMerge] should be `false` if pre-existing fields should not be merged.
10+
Future<void> put({
11+
required String id,
12+
required Map<String, dynamic> object,
13+
required String store,
14+
bool shouldMerge = true,
15+
});
16+
17+
/// Deletes the value with [id] from the [store]
18+
Future<void> remove({required String id, required String store});
19+
20+
/// Retrieves an object with [id] from the [store]
21+
///
22+
/// Returns `null` if the key doesn't exist
23+
Future<Map<String, dynamic>?> get({required String id, required String store});
24+
25+
/// Retrieves all objects within [store]
26+
Future<List<Map<String, dynamic>>> getAll({required String store});
27+
28+
/// Retrieves a stream of all the [store] objects, triggered whenever any update occurs to this [store]
29+
Future<Stream<List<Map<String, dynamic>>>> listenAll({required String store});
30+
}
31+
32+
//
33+
// DocumentDatabaseGateway implementation using `sembast`
34+
//
35+
class SembastGateway implements DocumentDatabaseGateway {
36+
SembastGateway(this._db);
37+
38+
// `sembast` database instance
39+
final Database _db;
40+
41+
@override
42+
Future<void> put({
43+
required String id,
44+
required Map<String, dynamic> object,
45+
required String store,
46+
bool shouldMerge = true,
47+
}) async {
48+
final storeMap = stringMapStoreFactory.store(store);
49+
50+
await storeMap.record(id).put(_db, object, merge: shouldMerge);
51+
}
52+
53+
@override
54+
Future<void> remove({required String id, required String store}) async {
55+
final storeMap = stringMapStoreFactory.store(store);
56+
await storeMap.record(id).delete(_db);
57+
}
58+
59+
@override
60+
Future<Map<String, dynamic>?> get({required String id, required String store}) async {
61+
final storeMap = stringMapStoreFactory.store(store);
62+
return storeMap.record(id).get(_db);
63+
}
64+
65+
@override
66+
Future<List<Map<String, dynamic>>> getAll({
67+
required String store,
68+
}) async {
69+
final storeMap = stringMapStoreFactory.store(store);
70+
71+
final allRecords = await storeMap.find(_db);
72+
return allRecords.map((record) => record.value).toList();
73+
}
74+
75+
@override
76+
Future<Stream<List<Map<String, dynamic>>>> listenAll({required String store}) async {
77+
final storeMap = stringMapStoreFactory.store(store);
78+
79+
return storeMap.query().onSnapshots(_db).transform(snapshotTransformer);
80+
}
81+
82+
/// Transforms a list of `sembast` snapshot records into a list of objects
83+
final snapshotTransformer =
84+
StreamTransformer<List<RecordSnapshot<String, Map<String, Object?>>>, List<Map<String, Object?>>>.fromHandlers(
85+
handleData: (snapshots, sink) {
86+
final transformedRecords = snapshots.map((record) => record.value).toList();
87+
sink.add(transformedRecords);
88+
},
89+
);
90+
}

lib/data/sembast_database.dart renamed to lib/data/gateways/sembast_database.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'dart:async';
22

3-
import 'package:flutter/foundation.dart';
3+
import 'package:meta/meta.dart';
44
import 'package:path/path.dart' as path;
55
import 'package:path_provider/path_provider.dart';
66
import 'package:sembast/sembast.dart';
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import 'package:memo/domain/models/deck.dart';
2+
import 'package:memo/data/serializers/deck_serializer.dart';
3+
import 'package:memo/data/gateways/document_database_gateway.dart';
4+
5+
abstract class DeckRepository {
6+
Future<List<Deck>> getAllDecks();
7+
}
8+
9+
class DeckRepositoryImpl implements DeckRepository {
10+
DeckRepositoryImpl(this._db);
11+
12+
final DocumentDatabaseGateway _db;
13+
final _deckSerializer = DeckSerializer();
14+
final _deckStore = 'decks';
15+
16+
@override
17+
Future<List<Deck>> getAllDecks() async {
18+
final rawDecks = await _db.getAll(store: _deckStore);
19+
return rawDecks.map(_deckSerializer.from).toList();
20+
}
21+
}

0 commit comments

Comments
 (0)