Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
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
7 changes: 7 additions & 0 deletions packages/firebase_database/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 0.0.8

* Added missing offline persistence and query functionality on Android
* Fixed startAt query behavior on iOS
* Persistence methods no longer throw errors on failure, return false instead
* Updates to docs and tests

## 0.0.7

* Fixed offline persistence on iOS
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
import com.google.firebase.database.ChildEventListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseException;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
Expand All @@ -31,7 +33,7 @@ public class FirebaseDatabasePlugin implements MethodCallHandler {

// Handles are ints used as indexes into the sparse array of active observers
private int nextHandle = 0;
private final SparseArray<EventObserver> observers = new SparseArray<EventObserver>();
private final SparseArray<EventObserver> observers = new SparseArray<>();

public static void registerWith(PluginRegistry.Registrar registrar) {
final MethodChannel channel =
Expand All @@ -43,14 +45,75 @@ private FirebaseDatabasePlugin(MethodChannel channel) {
this.channel = channel;
}

private static DatabaseReference getReference(Map<String, ?> arguments) {
@SuppressWarnings("unchecked")
private DatabaseReference getReference(Map<String, Object> arguments) {
String path = (String) arguments.get("path");
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
if (path != null) reference = reference.child(path);
return reference;
}

private Query getQuery(Map<String, Object> arguments) {
Query query = getReference(arguments);
@SuppressWarnings("unchecked")
Map<String, Object> parameters = (Map<String, Object>) arguments.get("parameters");
if (parameters == null) return query;
Object orderBy = parameters.get("orderBy");
if ("child".equals(orderBy)) {
query = query.orderByChild((String) parameters.get("orderByChildKey"));
} else if ("key".equals(orderBy)) {
query = query.orderByKey();
} else if ("value".equals(orderBy)) {
query = query.orderByValue();
} else if ("priority".equals(orderBy)) {
query = query.orderByPriority();
}
if (parameters.containsKey("startAt")) {
Object startAt = parameters.get("startAt");
String startAtKey = (String) parameters.get("startAtKey");
if (startAt instanceof Boolean) {
query = query.startAt((Boolean) startAt, startAtKey);
} else if (startAt instanceof String) {
query = query.startAt((String) startAt, startAtKey);
} else if (startAt instanceof Double) {
query = query.endAt((Double) startAt);
} else if (startAt instanceof Integer) {
query = query.startAt((int) startAt);
}
}
if (parameters.containsKey("endAt")) {
Object endAt = parameters.get("endAt");
String endAtKey = (String) parameters.get("endAtKey");
if (endAt instanceof Boolean) {
query = query.endAt((Boolean) endAt, endAtKey);
} else if (endAt instanceof String) {
query = query.endAt((String) endAt, endAtKey);
} else if (endAt instanceof Double) {
query = query.endAt((Double) endAt);
} else if (endAt instanceof Integer) {
query = query.endAt((int) endAt);
}
}
if (parameters.containsKey("equalTo")) {
Object equalTo = parameters.get("equalTo");
if (equalTo instanceof Boolean) {
query = query.equalTo((Boolean) equalTo);
} else if (equalTo instanceof String) {
query = query.equalTo((String) equalTo);
} else if (equalTo instanceof Double) {
query = query.equalTo((Double) equalTo);
} else if (equalTo instanceof Integer) {
query = query.equalTo((int) equalTo);
}
}
if (parameters.containsKey("limitToFirst")) {
query = query.limitToFirst((int) parameters.get("limitToFirst"));
}
if (parameters.containsKey("limitToLast")) {
query = query.limitToLast((int) parameters.get("limitToLast"));
}
return query;
}

private class DefaultCompletionListener implements DatabaseReference.CompletionListener {
private final Result result;

Expand Down Expand Up @@ -79,8 +142,8 @@ private class EventObserver implements ChildEventListener, ValueEventListener {

private void sendEvent(String eventType, DataSnapshot snapshot, String previousChildName) {
if (eventType.equals(requestedEventType)) {
Map<String, Object> arguments = new HashMap<String, Object>();
Map<String, Object> snapshotMap = new HashMap<String, Object>();
Map<String, Object> arguments = new HashMap<>();
Map<String, Object> snapshotMap = new HashMap<>();
snapshotMap.put("key", snapshot.getKey());
snapshotMap.put("value", snapshot.getValue());
arguments.put("handle", handle);
Expand Down Expand Up @@ -119,39 +182,59 @@ public void onDataChange(DataSnapshot snapshot) {
}
}

@SuppressWarnings("unchecked")
@Override
public void onMethodCall(MethodCall call, final Result result) {
Map<String, Object> arguments = (Map<String, Object>) call.arguments;
switch (call.method) {
case "FirebaseDatabase#goOnline":
FirebaseDatabase.getInstance().goOnline();
break;
{
FirebaseDatabase.getInstance().goOnline();
result.success(null);
break;
}

case "FirebaseDatabase#goOffline":
FirebaseDatabase.getInstance().goOffline();
break;
{
FirebaseDatabase.getInstance().goOffline();
result.success(null);
break;
}

case "FirebaseDatabase#purgeOutstandingWrites":
FirebaseDatabase.getInstance().purgeOutstandingWrites();
break;
{
FirebaseDatabase.getInstance().purgeOutstandingWrites();
result.success(null);
break;
}

case "FirebaseDatabase#setPersistenceEnabled":
{
boolean isEnabled = (boolean) arguments.get("enabled");
FirebaseDatabase.getInstance().setPersistenceEnabled(isEnabled);
Boolean isEnabled = (Boolean) call.arguments;
try {
FirebaseDatabase.getInstance().setPersistenceEnabled(isEnabled);
result.success(true);
} catch (DatabaseException e) {
// Database is already in use, e.g. after hot reload/restart.
result.success(false);
}
break;
}

case "FirebaseDatabase#setPersistenceCacheSizeBytes":
{
long cacheSize = (long) arguments.get("cacheSize");
FirebaseDatabase.getInstance().setPersistenceCacheSizeBytes(cacheSize);
long cacheSize = (Integer) call.arguments;
try {
FirebaseDatabase.getInstance().setPersistenceCacheSizeBytes(cacheSize);
result.success(true);
} catch (DatabaseException e) {
// Database is already in use, e.g. after hot reload/restart.
result.success(false);
}
break;
}

case "DatabaseReference#set":
{
Map<String, Object> arguments = call.arguments();
Object value = arguments.get("value");
Object priority = arguments.get("priority");
DatabaseReference reference = getReference(arguments);
Expand All @@ -165,37 +248,48 @@ public void onMethodCall(MethodCall call, final Result result) {

case "DatabaseReference#setPriority":
{
Map<String, Object> arguments = call.arguments();
Object priority = arguments.get("priority");
DatabaseReference reference = getReference(arguments);
reference.setPriority(priority, new DefaultCompletionListener(result));
break;
}

case "Query#keepSynced":
{
Map<String, Object> arguments = call.arguments();
boolean value = (Boolean) arguments.get("value");
getQuery(arguments).keepSynced(value);
break;
}

case "Query#observe":
{
Map<String, Object> arguments = call.arguments();
String eventType = (String) arguments.get("eventType");
int handle = nextHandle++;
EventObserver observer = new EventObserver(eventType, handle);
observers.put(handle, observer);
if (eventType.equals(EVENT_TYPE_VALUE)) {
getReference(arguments).addValueEventListener(observer);
getQuery(arguments).addValueEventListener(observer);
} else {
getReference(arguments).addChildEventListener(observer);
getQuery(arguments).addChildEventListener(observer);
}
result.success(handle);
break;
}

case "Query#removeObserver":
{
DatabaseReference reference = getReference(arguments);
Map<String, Object> arguments = call.arguments();
Query query = getQuery(arguments);
int handle = (Integer) arguments.get("handle");
EventObserver observer = observers.get(handle);
if (observer != null) {
if (observer.requestedEventType.equals(EVENT_TYPE_VALUE)) {
reference.removeEventListener((ValueEventListener) observer);
query.removeEventListener((ValueEventListener) observer);
} else {
reference.removeEventListener((ChildEventListener) observer);
query.removeEventListener((ChildEventListener) observer);
}
observers.delete(handle);
result.success(null);
Expand Down
6 changes: 5 additions & 1 deletion packages/firebase_database/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,16 @@ class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
super.initState();
FirebaseDatabase.instance.setPersistenceEnabled(true);
FirebaseDatabase.instance.setPersistenceCacheSizeBytes(10000000);
_counterRef.keepSynced(true);
_counterSubscription = _counterRef.onValue.listen((Event event) {
setState(() {
_counter = event.snapshot.value ?? 0;
});
});
_messagesSubscription = _messagesRef.onChildAdded.listen((Event event) {
_messagesSubscription =
_messagesRef.limitToLast(10).onChildAdded.listen((Event event) {
print('Child added: ${event.snapshot.value}');
});
}
Expand Down
33 changes: 28 additions & 5 deletions packages/firebase_database/ios/Classes/FirebaseDatabasePlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ - (FlutterError *)flutterError {
}
id startAt = parameters[@"startAt"];
if (startAt) {
query = [query queryStartingAtValue:startAt childKey:parameters[@"endAtKey"]];
query = [query queryStartingAtValue:startAt childKey:parameters[@"startAtKey"]];
}
id endAt = parameters[@"endAt"];
if (endAt) {
Expand Down Expand Up @@ -109,16 +109,39 @@ - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result
};
if ([@"FirebaseDatabase#goOnline" isEqualToString:call.method]) {
[[FIRDatabase database] goOnline];
result(nil);
} else if ([@"FirebaseDatabase#goOffline" isEqualToString:call.method]) {
[[FIRDatabase database] goOffline];
result(nil);
} else if ([@"FirebaseDatabase#purgeOutstandingWrites" isEqualToString:call.method]) {
[[FIRDatabase database] purgeOutstandingWrites];
result(nil);
} else if ([@"FirebaseDatabase#setPersistenceEnabled" isEqualToString:call.method]) {
NSNumber *value = call.arguments[@"enabled"];
[FIRDatabase database].persistenceEnabled = value.boolValue;
NSNumber *value = call.arguments;
@try {
[FIRDatabase database].persistenceEnabled = value.boolValue;
result([NSNumber numberWithBool:YES]);
} @catch (NSException *exception) {
if ([@"FIRDatabaseAlreadyInUse" isEqualToString:exception.name]) {
// Database is already in use, e.g. after hot reload/restart.
result([NSNumber numberWithBool:NO]);
} else {
@throw;
}
}
} else if ([@"FirebaseDatabase#setPersistenceCacheSizeBytes" isEqualToString:call.method]) {
NSNumber *value = call.arguments[@"cacheSize"];
[FIRDatabase database].persistenceCacheSizeBytes = value.unsignedIntegerValue;
NSNumber *value = call.arguments;
@try {
[FIRDatabase database].persistenceCacheSizeBytes = value.unsignedIntegerValue;
result([NSNumber numberWithBool:YES]);
} @catch (NSException *exception) {
if ([@"FIRDatabaseAlreadyInUse" isEqualToString:exception.name]) {
// Database is already in use, e.g. after hot reload/restart.
result([NSNumber numberWithBool:NO]);
} else {
@throw;
}
}
} else if ([@"DatabaseReference#set" isEqualToString:call.method]) {
[getReference(call.arguments) setValue:call.arguments[@"value"]
andPriority:call.arguments[@"priority"]
Expand Down
4 changes: 2 additions & 2 deletions packages/firebase_database/lib/src/database_reference.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,10 @@ class DatabaseReference extends Query {
/// priority (including no priority), they are sorted by key. Numeric keys
/// come first (sorted numerically), followed by the remaining keys (sorted
/// lexicographically).

///
/// Note that priorities are parsed and ordered as IEEE 754 double-precision
/// floating-point numbers. Keys are always stored as strings and are treated
/// as numbers only when they can be parsed as a 32-bit integer
/// as numbers only when they can be parsed as a 32-bit integer.
Future<Null> setPriority(dynamic priority) async {
return _database._channel.invokeMethod(
'DatabaseReference#setPriority',
Expand Down
Loading