Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1fb5e9c
[firestore_platform_interface] Add package scaffolding.
ditman Dec 12, 2019
8b80635
[firestore_platform_interface] Add first pass of split interfaces and
ditman Dec 12, 2019
cd3c1c8
[firestore_platform_interface] Add SetOptions type.
ditman Dec 13, 2019
f91c6fb
[firestore_platform_interface] Tighten types, reshuffle exports.
ditman Dec 13, 2019
cc03bd7
[firestore] [WIP] Use new platform interface, port transactions to ne…
ditman Dec 13, 2019
46f0759
[firestore_platform_interface] Tighten types around Write Batches.
ditman Dec 13, 2019
795b287
[firestore] Migrate Write Batch to the platform interface.
ditman Dec 13, 2019
6421625
[firestore_platform_interface] Some more types, and reshuffling of ex…
ditman Dec 13, 2019
e4424d5
[firestore] Finish porting the plugin to the platform interface, and
ditman Dec 13, 2019
4331bb0
[firestore_platform_interface] Fix signature of callHandler methods.
ditman Dec 13, 2019
2a711a4
[firestore_platform_interface] Add MethodChannel implementation for W…
ditman Dec 13, 2019
6a19d71
[firestore_platform_interface] Make _tokens final, not const.
ditman Dec 13, 2019
27610a3
[firestore_platform_interface] MethodChannel implementations now require
ditman Dec 14, 2019
55fa17a
[firestore] Inject the FirestoreMessageCodec into the
ditman Dec 14, 2019
058ed75
[firestore_platform_interface] Cleanup imports
ditman Dec 14, 2019
732baed
[firestore_platform_interface] Rename `PlatformWriteBatch` to
ditman Dec 14, 2019
daccabc
[firestore] Rename `PlatformWriteBatch` to `PlatformWriteBatchHandle`
ditman Dec 14, 2019
c65a7dd
[firestore_platform_interface] Add MethodChannelTransaction
ditman Dec 14, 2019
5c5f713
[firestore] Remove superfluous cast.
ditman Dec 14, 2019
843a36f
[firestore_platform_interface] Implement Query:getDocuments
ditman Dec 16, 2019
5779f2d
[firestore] Move Source to the platform interface.
ditman Dec 16, 2019
6c568dc
[firestore_platform_interface] Add, and use MultiMethodChannel.
ditman Dec 16, 2019
7967d41
[firestore] Export Source from platform interface.
ditman Dec 16, 2019
831ee19
[firestore_platform_interface] Add implementation for DocumentReference.
ditman Dec 17, 2019
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
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'dart:convert';
import 'dart:typed_data';
import 'dart:ui' show hashValues, hashList;

import 'package:cloud_firestore_platform_interface/cloud_firestore_platform_interface.dart';
import 'package:collection/collection.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer;
Expand All @@ -17,6 +18,9 @@ import 'package:meta/meta.dart';

import 'src/utils/auto_id_generator.dart';

import 'package:cloud_firestore_platform_interface/cloud_firestore_platform_interface.dart'
show Source;

part 'src/blob.dart';
part 'src/collection_reference.dart';
part 'src/document_change.dart';
Expand All @@ -33,4 +37,3 @@ part 'src/snapshot_metadata.dart';
part 'src/timestamp.dart';
part 'src/transaction.dart';
part 'src/write_batch.dart';
part 'src/source.dart';
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,12 @@ class DocumentReference {
/// If [merge] is true, the provided data will be merged into an
/// existing document instead of overwriting.
Future<void> setData(Map<String, dynamic> data, {bool merge = false}) {
return Firestore.channel.invokeMethod<void>(
'DocumentReference#setData',
<String, dynamic>{
'app': firestore.app.name,
'path': path,
'data': data,
'options': <String, bool>{'merge': merge},
},
);
return Firestore.platform.documentReference.set(
firestore.app.name,
path: path,
data: data,
options: PlatformSetOptions(merge: merge),
);
}

/// Updates fields in the document referred to by this [DocumentReference].
Expand All @@ -66,44 +63,38 @@ class DocumentReference {
///
/// If no document exists yet, the update will fail.
Future<void> updateData(Map<String, dynamic> data) {
return Firestore.channel.invokeMethod<void>(
'DocumentReference#updateData',
<String, dynamic>{
'app': firestore.app.name,
'path': path,
'data': data,
},
);
return Firestore.platform.documentReference.update(
firestore.app.name,
path: path,
data: data,
);
}

/// Reads the document referenced by this [DocumentReference].
///
/// If no document exists, the read will return null.
Future<DocumentSnapshot> get({Source source = Source.serverAndCache}) async {
final Map<String, dynamic> data =
await Firestore.channel.invokeMapMethod<String, dynamic>(
'DocumentReference#get',
<String, dynamic>{
'app': firestore.app.name,
'path': path,
'source': _getSourceString(source),
},
);
final PlatformDocumentSnapshot snapshot = await Firestore.platform.documentReference.get(
firestore.app.name,
path: path,
source: source,
);

return DocumentSnapshot._(
data['path'],
_asStringKeyedMap(data['data']),
SnapshotMetadata._(data['metadata']['hasPendingWrites'],
data['metadata']['isFromCache']),
snapshot.path,
_asStringKeyedMap(snapshot.data),
SnapshotMetadata._(snapshot.metadata.hasPendingWrites,
snapshot.metadata.isFromCache),
firestore,
);
}

/// Deletes the document referred to by this [DocumentReference].
Future<void> delete() {
return Firestore.channel.invokeMethod<void>(
'DocumentReference#delete',
<String, dynamic>{'app': firestore.app.name, 'path': path},
);
return Firestore.platform.documentReference.delete(
firestore.app.name,
path: path,
);
}

/// Returns the reference of a collection contained inside of this
Expand All @@ -118,34 +109,19 @@ class DocumentReference {
// TODO(jackson): Reduce code duplication with [Query]
Stream<DocumentSnapshot> snapshots({bool includeMetadataChanges = false}) {
assert(includeMetadataChanges != null);
Future<int> _handle;
// It's fine to let the StreamController be garbage collected once all the
// subscribers have cancelled; this analyzer warning is safe to ignore.
StreamController<DocumentSnapshot> controller; // ignore: close_sinks
controller = StreamController<DocumentSnapshot>.broadcast(
onListen: () {
_handle = Firestore.channel.invokeMethod<int>(
'DocumentReference#addSnapshotListener',
<String, dynamic>{
'app': firestore.app.name,
'path': path,
'includeMetadataChanges': includeMetadataChanges,
},
).then<int>((dynamic result) => result);
_handle.then((int handle) {
Firestore._documentObservers[handle] = controller;
});
},
onCancel: () {
_handle.then((int handle) async {
await Firestore.channel.invokeMethod<void>(
'removeListener',
<String, dynamic>{'handle': handle},
);
Firestore._documentObservers.remove(handle);
});
},
);
return controller.stream;

return Firestore.platform.documentReference.snapshots(
firestore.app.name,
path: path,
includeMetadataChanges: includeMetadataChanges,
).map((PlatformDocumentSnapshot snapshot) {
return DocumentSnapshot._(
snapshot.path,
_asStringKeyedMap(snapshot.data),
SnapshotMetadata._(snapshot.metadata.hasPendingWrites,
snapshot.metadata.isFromCache),
firestore,
);
});
}
}
97 changes: 30 additions & 67 deletions packages/cloud_firestore/cloud_firestore/lib/src/firestore.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,11 @@ part of cloud_firestore;
///
/// You can get an instance by calling [Firestore.instance].
class Firestore {
Firestore({FirebaseApp app}) : app = app ?? FirebaseApp.instance {
if (_initialized) return;
channel.setMethodCallHandler((MethodCall call) async {
if (call.method == 'QuerySnapshot') {
final QuerySnapshot snapshot = QuerySnapshot._(call.arguments, this);
_queryObservers[call.arguments['handle']].add(snapshot);
} else if (call.method == 'DocumentSnapshot') {
final DocumentSnapshot snapshot = DocumentSnapshot._(
call.arguments['path'],
_asStringKeyedMap(call.arguments['data']),
SnapshotMetadata._(call.arguments['metadata']['hasPendingWrites'],
call.arguments['metadata']['isFromCache']),
this,
);
_documentObservers[call.arguments['handle']].add(snapshot);
} else if (call.method == 'DoTransaction') {
final int transactionId = call.arguments['transactionId'];
final Transaction transaction = Transaction(transactionId, this);
final dynamic result =
await _transactionHandlers[transactionId](transaction);
await transaction._finish();
return result;
}
});
_initialized = true;
}
Firestore({FirebaseApp app}) : app = app ?? FirebaseApp.instance;

/// The platform instance that talks to the native side of the plugin.
@visibleForTesting
static final FirestorePlatform platform = FirestorePlatform.instance ?? (FirestorePlatform.instance = MethodChannelFirestore(FirestoreMessageCodec()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems a bit unintuitive to be doing the assignment like this.


/// Gets the instance of Firestore for the default Firebase app.
static final Firestore instance = Firestore();
Expand All @@ -43,24 +22,6 @@ class Firestore {
/// If null, the default [FirebaseApp] is used.
final FirebaseApp app;

static bool _initialized = false;

@visibleForTesting
static const MethodChannel channel = MethodChannel(
'plugins.flutter.io/cloud_firestore',
StandardMethodCodec(FirestoreMessageCodec()),
);

static final Map<int, StreamController<QuerySnapshot>> _queryObservers =
<int, StreamController<QuerySnapshot>>{};

static final Map<int, StreamController<DocumentSnapshot>> _documentObservers =
<int, StreamController<DocumentSnapshot>>{};

static final Map<int, TransactionHandler> _transactionHandlers =
<int, TransactionHandler>{};
static int _transactionHandlerId = 0;

@override
bool operator ==(dynamic o) => o is Firestore && o.app == app;

Expand Down Expand Up @@ -123,39 +84,41 @@ class Firestore {
{Duration timeout = const Duration(seconds: 5)}) async {
assert(timeout.inMilliseconds > 0,
'Transaction timeout must be more than 0 milliseconds');
final int transactionId = _transactionHandlerId++;
_transactionHandlers[transactionId] = transactionHandler;
final Map<String, dynamic> result = await channel
.invokeMapMethod<String, dynamic>(
'Firestore#runTransaction', <String, dynamic>{
'app': app.name,
'transactionId': transactionId,
'transactionTimeout': timeout.inMilliseconds
});

// Wrap the user-supplied [TransactionHandler] into something that can be passed to the Platform implementation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Wrap the user-supplied [TransactionHandler] into something that can be passed to the Platform implementation.
// Wrap the user-supplied [TransactionHandler] into something that can be passed to the platform implementation.

final PlatformTransactionHandler handler = (PlatformTransaction platformTransaction) async {
Transaction transaction = Transaction(platformTransaction.transactionId, this);
final dynamic result = await transactionHandler(transaction);
await transaction._finish();
return result;
};

final Map<String, dynamic> result = await Firestore.platform.transaction.run(
app.name,
updateFunction: handler,
transactionTimeout: timeout.inMilliseconds,
);

return result ?? <String, dynamic>{};
}

@deprecated
Future<void> enablePersistence(bool enable) async {
Future<void> enablePersistence(bool enable) {
assert(enable != null);
await channel
.invokeMethod<void>('Firestore#enablePersistence', <String, dynamic>{
'app': app.name,
'enable': enable,
});
return Firestore.platform.enablePersistence(app.name, enable: enable);
}

Future<void> settings(
{bool persistenceEnabled,
String host,
bool sslEnabled,
int cacheSizeBytes}) async {
await channel.invokeMethod<void>('Firestore#settings', <String, dynamic>{
'app': app.name,
'persistenceEnabled': persistenceEnabled,
'host': host,
'sslEnabled': sslEnabled,
'cacheSizeBytes': cacheSizeBytes,
});
int cacheSizeBytes}) {

return Firestore.platform.settings(app.name,
persistenceEnabled: persistenceEnabled,
host: host,
sslEnabled: sslEnabled,
cacheSizeBytes: cacheSizeBytes,
);
}
}
61 changes: 18 additions & 43 deletions packages/cloud_firestore/cloud_firestore/lib/src/query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,55 +52,30 @@ class Query {
// TODO(jackson): Reduce code duplication with [DocumentReference]
Stream<QuerySnapshot> snapshots({bool includeMetadataChanges = false}) {
assert(includeMetadataChanges != null);
Future<int> _handle;
// It's fine to let the StreamController be garbage collected once all the
// subscribers have cancelled; this analyzer warning is safe to ignore.
StreamController<QuerySnapshot> controller; // ignore: close_sinks
controller = StreamController<QuerySnapshot>.broadcast(
onListen: () {
_handle = Firestore.channel.invokeMethod<int>(
'Query#addSnapshotListener',
<String, dynamic>{
'app': firestore.app.name,
'path': _path,
'isCollectionGroup': _isCollectionGroup,
'parameters': _parameters,
'includeMetadataChanges': includeMetadataChanges,
},
).then<int>((dynamic result) => result);
_handle.then((int handle) {
Firestore._queryObservers[handle] = controller;
});
},
onCancel: () {
_handle.then((int handle) async {
await Firestore.channel.invokeMethod<void>(
'removeListener',
<String, dynamic>{'handle': handle},
);
Firestore._queryObservers.remove(handle);
});
},
);
return controller.stream;

return Firestore.platform.query.snapshots(
firestore.app.name,
path: _path,
isCollectionGroup: _isCollectionGroup,
parameters: _parameters,
includeMetadataChanges: includeMetadataChanges,
).map((PlatformQuerySnapshot snapshot) => QuerySnapshot._(snapshot.asMap(), firestore));
}

/// Fetch the documents for this query
Future<QuerySnapshot> getDocuments(
{Source source = Source.serverAndCache}) async {
assert(source != null);
final Map<dynamic, dynamic> data =
await Firestore.channel.invokeMapMethod<String, dynamic>(
'Query#getDocuments',
<String, dynamic>{
'app': firestore.app.name,
'path': _path,
'isCollectionGroup': _isCollectionGroup,
'parameters': _parameters,
'source': _getSourceString(source),
},
);
return QuerySnapshot._(data, firestore);

final PlatformQuerySnapshot snapshot = await Firestore.platform.query.getDocuments(
firestore.app.name,
path: _path,
isCollectionGroup: _isCollectionGroup,
parameters: _parameters,
source: source,
);

return QuerySnapshot._(snapshot.asMap(), firestore);
}

/// Obtains a CollectionReference corresponding to this query's location.
Expand Down
Loading