Skip to content

Commit 3b1e939

Browse files
Cleanup and Reactivity Support
1 parent 6316080 commit 3b1e939

File tree

10 files changed

+160
-106
lines changed

10 files changed

+160
-106
lines changed

packages/firebase_data_connect/firebase_data_connect/lib/firebase_data_connect.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,6 @@ export 'src/optional.dart'
4040
listSerializer;
4141
export 'src/timestamp.dart' show Timestamp;
4242
export 'src/cache/cache_data_types.dart' show CacheSettings, QueryFetchPolicy;
43-
export 'src/cache/cache_manager.dart' show Cache;
44-
export 'src/cache/cache_provider.dart' show CacheProvider;
45-
export 'src/cache/sqlite_cache_provider.dart' show SQLite3CacheProvider;
43+
//export 'src/cache/cache_manager.dart' show Cache;
44+
//export 'src/cache/cache_provider.dart' show CacheProvider;
45+
//export 'src/cache/sqlite_cache_provider.dart' show SQLite3CacheProvider;

packages/firebase_data_connect/firebase_data_connect/lib/src/cache/cache_data_types.dart

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,22 @@ class EntityDataObject {
115115
Map<String, dynamic> _serverValues = {};
116116

117117
/// A set of identifiers for the `QueryRef`s that reference this EDO.
118-
final Set<String> referencedFrom = {};
118+
Set<String> referencedFrom = {};
119119

120-
void updateServerValue(String prop, dynamic value) {
120+
void updateServerValue(String prop, dynamic value, String? requestor) {
121121
_serverValues[prop] = value;
122+
123+
if (requestor != null) {
124+
referencedFrom.add(requestor);
125+
}
122126
}
123127

124-
void setServerValues(Map<String, dynamic> values) {
128+
void setServerValues(Map<String, dynamic> values, String? requestor) {
125129
_serverValues = values;
130+
131+
if (requestor != null) {
132+
referencedFrom.add(requestor);
133+
}
126134
}
127135

128136
/// Dictionary of prop-values contained in this EDO
@@ -137,16 +145,26 @@ class EntityDataObject {
137145

138146
String toRawJson() => json.encode(toJson());
139147

140-
factory EntityDataObject.fromJson(Map<String, dynamic> json) =>
141-
EntityDataObject(
142-
guid: json[GlobalIDKey] as String,
143-
).._serverValues =
144-
Map<String, dynamic>.from(json['_serverValues'] as Map);
145-
146148
Map<String, dynamic> toJson() => {
147149
GlobalIDKey: guid,
148150
'_serverValues': _serverValues,
151+
'referencedFrom': referencedFrom.toList(),
149152
};
153+
154+
factory EntityDataObject.fromJson(Map<String, dynamic> json) {
155+
EntityDataObject edo = EntityDataObject(
156+
guid: json[GlobalIDKey] as String,
157+
);
158+
edo.setServerValues(
159+
Map<String, dynamic>.from(json['_serverValues'] as Map), null);
160+
161+
List<dynamic>? rf = json['referencedFrom'];
162+
if (rf != null) {
163+
edo.referencedFrom = rf.cast<String>().toSet();
164+
}
165+
166+
return edo;
167+
}
150168
}
151169

152170
/// A tree-like data structure that represents the dehydrated or hydrated query result.
@@ -174,12 +192,12 @@ class EntityNode {
174192

175193
factory EntityNode.fromJson(
176194
Map<String, dynamic> json, CacheProvider cacheProvider) {
177-
EntityDataObject? entity = null;
195+
EntityDataObject? entity;
178196
if (json[GlobalIDKey] != null) {
179197
entity = cacheProvider.getEntityDataObject(json[GlobalIDKey]);
180198
}
181199

182-
Map<String, dynamic>? scalars = null;
200+
Map<String, dynamic>? scalars;
183201
if (json[scalarsKey] != null) {
184202
scalars = json[scalarsKey];
185203
}

packages/firebase_data_connect/firebase_data_connect/lib/src/cache/cache_manager.dart

Lines changed: 17 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,12 @@
1313
// limitations under the License.
1414

1515
import 'dart:async';
16-
import 'dart:convert';
1716
import 'dart:developer' as developer;
1817

1918
import 'package:firebase_auth/firebase_auth.dart';
2019
import 'package:firebase_data_connect/firebase_data_connect.dart';
21-
import 'package:firebase_data_connect/src/cache/in_memory_cache_provider.dart';
22-
import 'package:firebase_data_connect/src/cache/sqlite_cache_provider.dart';
23-
import 'package:flutter/foundation.dart';
20+
import 'cache_provider.dart';
21+
import 'in_memory_cache_provider.dart' if (dart.library.io) 'sqlite_cache_provider.dart';
2422

2523
import '../common/common_library.dart';
2624

@@ -38,10 +36,10 @@ class Cache {
3836

3937
factory Cache(CacheSettings settings, FirebaseDataConnect dataConnect) {
4038
Cache c = Cache._internal(settings, dataConnect);
41-
39+
4240
c._initializeProvider();
4341
c._listenForAuthChanges();
44-
42+
4543
return c;
4644
}
4745

@@ -60,31 +58,20 @@ class Cache {
6058
return;
6159
}
6260

63-
if (kIsWeb) {
64-
// change this once we support persistence for web
65-
_cacheProvider = InMemoryCacheProvider(identifier);
66-
providerInitialization = _cacheProvider?.initialize();
67-
return;
68-
}
61+
bool memory = _settings.storage == CacheStorage.memory;
62+
_cacheProvider = cacheImplementation(identifier, memory);
6963

70-
switch (_settings.storage) {
71-
case CacheStorage.memory:
72-
_cacheProvider = SQLite3CacheProvider(identifier, memory: true);
73-
case CacheStorage.persistent:
74-
_cacheProvider = SQLite3CacheProvider(identifier);
75-
}
7664
providerInitialization = _cacheProvider?.initialize();
7765
}
7866

7967
void _listenForAuthChanges() {
8068
if (dataConnect.auth == null) {
81-
developer.log('Not listening for auth changes since no auth instance in data connect');
69+
developer.log(
70+
'Not listening for auth changes since no auth instance in data connect');
8271
return;
8372
}
8473

85-
dataConnect.auth!
86-
.authStateChanges()
87-
.listen((User? user) {
74+
dataConnect.auth!.authStateChanges().listen((User? user) {
8875
_initializeProvider();
8976
});
9077
}
@@ -107,23 +94,25 @@ class Cache {
10794
queryId, serverResponse.data, _cacheProvider!);
10895

10996
EntityNode rootNode = dehydrationResult.dehydratedTree;
110-
String dehydratedJson =
111-
jsonEncode(rootNode.toJson(mode: EncodingMode.dehydrated));
97+
Map<String, dynamic> dehydratedMap =
98+
rootNode.toJson(mode: EncodingMode.dehydrated);
11299

113100
Duration ttl = serverResponse.ttl != null
114101
? serverResponse.ttl!
115102
: Duration(seconds: 10);
116103
final resultTree = ResultTree(
117-
data: rootNode.toJson(
118-
mode: EncodingMode
119-
.dehydrated), // Storing the original response for now
104+
data: dehydratedMap,
120105
ttl: ttl, // Default TTL
121106
cachedAt: DateTime.now(),
122107
lastAccessed: DateTime.now());
123108

124109
_cacheProvider!.saveResultTree(queryId, resultTree);
125110

126-
_impactedQueryController.add(dehydrationResult.impactedQueryIds);
111+
Set<String> impactedQueryIds = dehydrationResult.impactedQueryIds;
112+
impactedQueryIds.remove(queryId); // remove query being cached
113+
print(
114+
'adding to impactedQueryController ${dehydrationResult.impactedQueryIds}');
115+
_impactedQueryController.add(impactedQueryIds);
127116
}
128117

129118
/// Fetches a cached result.

packages/firebase_data_connect/firebase_data_connect/lib/src/cache/in_memory_cache_provider.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class InMemoryCacheProvider implements CacheProvider {
3232
@override
3333
Future<bool> initialize() async {
3434
// nothing to be intialized
35+
print('Initialize inmemory provider called');
3536
return true;
3637
}
3738

@@ -54,6 +55,7 @@ class InMemoryCacheProvider implements CacheProvider {
5455
EntityDataObject getEntityDataObject(String guid) {
5556
EntityDataObject? edo = _edos[guid];
5657
if (edo != null) {
58+
print('Returning existing edo for $guid');
5759
return edo;
5860
} else {
5961
edo = EntityDataObject(guid: guid);
@@ -73,3 +75,5 @@ class InMemoryCacheProvider implements CacheProvider {
7375
_edos.clear();
7476
}
7577
}
78+
79+
CacheProvider cacheImplementation(String identifier, bool memory) => InMemoryCacheProvider(identifier);

packages/firebase_data_connect/firebase_data_connect/lib/src/cache/result_tree_processor.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ import '../common/common_library.dart';
1616
import 'cache_data_types.dart';
1717
import 'cache_provider.dart';
1818

19-
import 'dart:convert';
20-
2119
class DehydrationResult {
2220
final EntityNode dehydratedTree;
2321
final Set<String> impactedQueryIds;
@@ -47,6 +45,7 @@ class ResultTreeProcessor {
4745
CacheProvider cacheProvider, Set<String> impactedQueryIds) {
4846
if (data is Map<String, dynamic>) {
4947
if (data.containsKey(GlobalIDKey)) {
48+
// data contains a unique entity id. we can normalize
5049
final guid = data[GlobalIDKey] as String;
5150

5251
final serverValues = <String, dynamic>{};
@@ -76,7 +75,7 @@ class ResultTreeProcessor {
7675
final existingEdo = cacheProvider.getEntityDataObject(guid);
7776
existingEdo.referencedFrom.add(queryId);
7877
impactedQueryIds.addAll(existingEdo.referencedFrom);
79-
existingEdo.setServerValues(serverValues);
78+
existingEdo.setServerValues(serverValues, queryId);
8079
cacheProvider.saveEntityDataObject(existingEdo);
8180

8281
return EntityNode(
@@ -85,6 +84,7 @@ class ResultTreeProcessor {
8584
nestedObjectLists: nestedObjectLists);
8685
} else {
8786
// GlobalID check
87+
// no entity id. scalar data must be stored inline.
8888
final scalarValues = <String, dynamic>{};
8989
final nestedObjects = <String, EntityNode>{};
9090
final nestedObjectLists = <String, List<EntityNode>>{};
@@ -107,7 +107,7 @@ class ResultTreeProcessor {
107107
scalarValues[key] = value;
108108
}
109109
}
110-
110+
111111
return EntityNode(
112112
scalarValues: scalarValues,
113113
nestedObjects: nestedObjects,

packages/firebase_data_connect/firebase_data_connect/lib/src/cache/sqlite_cache_provider.dart

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,24 @@ class SQLite3CacheProvider implements CacheProvider {
2424
final String _identifier;
2525
final bool memory;
2626

27+
final String entityDataTable = 'entity_data';
28+
final String resultTreeTable = 'query_results';
29+
final String entityDataRefsTable = 'entity_data_query_refs';
30+
2731
SQLite3CacheProvider(this._identifier, {this.memory = false});
2832

2933
@override
3034
Future<bool> initialize() async {
3135
try {
32-
if (memory) {
33-
_db = sqlite3.open(':memory:');
34-
} else {
35-
final dbPath = await getApplicationDocumentsDirectory();
36-
final path = join(dbPath.path, '{$_identifier}.db');
37-
_db = sqlite3.open(path);
38-
}
39-
_createTables();
40-
return true;
36+
if (memory) {
37+
_db = sqlite3.open(':memory:');
38+
} else {
39+
final dbPath = await getApplicationDocumentsDirectory();
40+
final path = join(dbPath.path, '{$_identifier}.db');
41+
_db = sqlite3.open(path);
42+
}
43+
_createTables();
44+
return true;
4145
} catch (e) {
4246
developer.log('Error initializing SQLiteProvider $e');
4347
return false;
@@ -46,13 +50,13 @@ class SQLite3CacheProvider implements CacheProvider {
4650

4751
void _createTables() {
4852
_db.execute('''
49-
CREATE TABLE IF NOT EXISTS result_trees (
53+
CREATE TABLE IF NOT EXISTS $resultTreeTable (
5054
query_id TEXT PRIMARY KEY,
5155
result_tree TEXT
5256
);
5357
''');
5458
_db.execute('''
55-
CREATE TABLE IF NOT EXISTS entity_data_objects (
59+
CREATE TABLE IF NOT EXISTS $entityDataTable (
5660
guid TEXT PRIMARY KEY,
5761
entity_data_object TEXT
5862
);
@@ -66,14 +70,14 @@ class SQLite3CacheProvider implements CacheProvider {
6670

6771
@override
6872
void clear() {
69-
_db.execute('DELETE FROM result_trees');
70-
_db.execute('DELETE FROM entity_data_objects');
73+
_db.execute('DELETE FROM $resultTreeTable');
74+
_db.execute('DELETE FROM $entityDataTable');
7175
}
7276

7377
@override
7478
EntityDataObject getEntityDataObject(String guid) {
7579
final resultSet = _db.select(
76-
'SELECT entity_data_object FROM entity_data_objects WHERE guid = ?',
80+
'SELECT entity_data_object FROM $entityDataTable WHERE guid = ?',
7781
[guid],
7882
);
7983
if (resultSet.isEmpty) {
@@ -88,7 +92,7 @@ class SQLite3CacheProvider implements CacheProvider {
8892
@override
8993
ResultTree? getResultTree(String queryId) {
9094
final resultSet = _db.select(
91-
'SELECT result_tree FROM result_trees WHERE query_id = ?',
95+
'SELECT result_tree FROM $resultTreeTable WHERE query_id = ?',
9296
[queryId],
9397
);
9498
if (resultSet.isEmpty) {
@@ -104,17 +108,22 @@ class SQLite3CacheProvider implements CacheProvider {
104108

105109
@override
106110
void saveEntityDataObject(EntityDataObject edo) {
111+
String rawJson = edo.toRawJson();
112+
developer.log(
113+
'saveEntityDataObject ${edo.guid} refs ${edo.referencedFrom} $rawJson');
107114
_db.execute(
108-
'INSERT OR REPLACE INTO entity_data_objects (guid, entity_data_object) VALUES (?, ?)',
109-
[edo.guid, edo.toRawJson()],
115+
'INSERT OR REPLACE INTO $entityDataTable (guid, entity_data_object) VALUES (?, ?)',
116+
[edo.guid, rawJson],
110117
);
111118
}
112119

113120
@override
114121
void saveResultTree(String queryId, ResultTree resultTree) {
115122
_db.execute(
116-
'INSERT OR REPLACE INTO result_trees (query_id, result_tree) VALUES (?, ?)',
123+
'INSERT OR REPLACE INTO $resultTreeTable (query_id, result_tree) VALUES (?, ?)',
117124
[queryId, resultTree.toRawJson()],
118125
);
119126
}
120127
}
128+
129+
CacheProvider cacheImplementation(String identifier, bool memory) => SQLite3CacheProvider(identifier, memory: memory);

0 commit comments

Comments
 (0)