Skip to content

Commit

Permalink
Add Blob support to cloud_firestore (flutter#473)
Browse files Browse the repository at this point in the history
  • Loading branch information
kuemit authored and mravn-google committed Apr 12, 2018
1 parent 068a9fb commit 99988d6
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 1 deletion.
4 changes: 4 additions & 0 deletions packages/cloud_firestore/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.6.2

* Support for BLOB data type.

## 0.6.1

* Simplified podspec for Cocoapods 1.5.0, avoiding link issues in app archives.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.google.android.gms.tasks.TaskCompletionSource;
import com.google.android.gms.tasks.Tasks;
import com.google.firebase.FirebaseApp;
import com.google.firebase.firestore.Blob;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.DocumentChange;
import com.google.firebase.firestore.DocumentReference;
Expand Down Expand Up @@ -567,6 +568,7 @@ final class FirestoreMessageCodec extends StandardMessageCodec {
private static final byte DATE_TIME = (byte) 128;
private static final byte GEO_POINT = (byte) 129;
private static final byte DOCUMENT_REFERENCE = (byte) 130;
private static final byte BLOB = (byte) 131;

@Override
protected void writeValue(ByteArrayOutputStream stream, Object value) {
Expand All @@ -583,6 +585,9 @@ protected void writeValue(ByteArrayOutputStream stream, Object value) {
writeBytes(
stream, ((DocumentReference) value).getFirestore().getApp().getName().getBytes(UTF8));
writeBytes(stream, ((DocumentReference) value).getPath().getBytes(UTF8));
} else if (value instanceof Blob) {
stream.write(BLOB);
writeBytes(stream, ((Blob) value).toBytes());
} else {
super.writeValue(stream, value);
}
Expand All @@ -604,6 +609,9 @@ protected Object readValueOfType(byte type, ByteBuffer buffer) {
final byte[] pathBytes = readBytes(buffer);
final String path = new String(pathBytes, UTF8);
return firestore.document(path);
case BLOB:
final byte[] bytes = readBytes(buffer);
return Blob.fromBytes(bytes);
default:
return super.readValueOfType(type, buffer);
}
Expand Down
10 changes: 10 additions & 0 deletions packages/cloud_firestore/ios/Classes/CloudFirestorePlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ - (FlutterError *)flutterError {
const UInt8 DATE_TIME = 128;
const UInt8 GEO_POINT = 129;
const UInt8 DOCUMENT_REFERENCE = 130;
const UInt8 BLOB = 131;

@interface FirestoreWriter : FlutterStandardWriter
- (void)writeValue:(id)value;
Expand Down Expand Up @@ -153,6 +154,11 @@ - (void)writeValue:(id)value {
[self writeByte:DOCUMENT_REFERENCE];
[self writeUTF8:document.firestore.app.name];
[self writeUTF8:documentPath];
} else if ([value isKindOfClass:[NSData class]]) {
NSData *blob = value;
[self writeByte:BLOB];
[self writeSize:blob.length];
[self writeData:blob];
} else {
[super writeValue:value];
}
Expand Down Expand Up @@ -186,6 +192,10 @@ - (id)readValueOfType:(UInt8)type {
NSString *documentPath = [self readUTF8];
return [firestore documentWithPath:documentPath];
}
case BLOB: {
UInt32 elementCount = [self readSize];
return [self readData:elementCount];
}
default:
return [super readValueOfType:type];
}
Expand Down
2 changes: 2 additions & 0 deletions packages/cloud_firestore/lib/cloud_firestore.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ library cloud_firestore;

import 'dart:async';
import 'dart:convert';
import 'dart:typed_data';
import 'dart:ui' show hashValues, hashList;

import 'package:firebase_core/firebase_core.dart';
Expand All @@ -17,6 +18,7 @@ import 'package:collection/collection.dart';
import 'src/utils/push_id_generator.dart';

part 'src/collection_reference.dart';
part 'src/blob.dart';
part 'src/document_change.dart';
part 'src/document_snapshot.dart';
part 'src/document_reference.dart';
Expand Down
18 changes: 18 additions & 0 deletions packages/cloud_firestore/lib/src/blob.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2018, the Chromium project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

part of cloud_firestore;

class Blob {
final Uint8List bytes;
const Blob(this.bytes);

@override
bool operator ==(dynamic other) =>
other is Blob &&
const DeepCollectionEquality().equals(other.bytes, bytes);

@override
int get hashCode => hashList(bytes);
}
9 changes: 9 additions & 0 deletions packages/cloud_firestore/lib/src/firestore_message_codec.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class FirestoreMessageCodec extends StandardMessageCodec {
static const int _kDateTime = 128;
static const int _kGeoPoint = 129;
static const int _kDocumentReference = 130;
static const int _kBlob = 131;

@override
void writeValue(WriteBuffer buffer, dynamic value) {
Expand All @@ -29,6 +30,10 @@ class FirestoreMessageCodec extends StandardMessageCodec {
final List<int> bytes = utf8.encoder.convert(value.path);
writeSize(buffer, bytes.length);
buffer.putUint8List(bytes);
} else if (value is Blob) {
buffer.putUint8(_kBlob);
writeSize(buffer, value.bytes.length);
buffer.putUint8List(value.bytes);
} else {
super.writeValue(buffer, value);
}
Expand All @@ -51,6 +56,10 @@ class FirestoreMessageCodec extends StandardMessageCodec {
final String path =
utf8.decoder.convert(buffer.getUint8List(pathLength));
return firestore.document(path);
case _kBlob:
final int length = readSize(buffer);
final List<int> bytes = buffer.getUint8List(length);
return new Blob(bytes);
default:
return super.readValueOfType(type, buffer);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/cloud_firestore/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for Cloud Firestore, a cloud-hosted, noSQL database
live synchronization and offline support on Android and iOS.
author: Flutter Team <[email protected]>
homepage: https://github.com/flutter/plugins/tree/master/packages/cloud_firestore
version: 0.6.1
version: 0.6.2

flutter:
plugin:
Expand Down
26 changes: 26 additions & 0 deletions packages/cloud_firestore/test/cloud_firestore_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,26 @@ void main() {
});
});

group('Blob', () {
test('hashCode equality', () async {
final Uint8List bytesA = new Uint8List(8);
bytesA.setAll(0, <int>[0, 2, 4, 6, 8, 10, 12, 14]);
final Blob a = new Blob(bytesA);
final Uint8List bytesB = new Uint8List(8);
bytesB.setAll(0, <int>[0, 2, 4, 6, 8, 10, 12, 14]);
final Blob b = new Blob(bytesB);
expect(a.hashCode == b.hashCode, isTrue);
});
test('hashCode not equal', () async {
final Uint8List bytesA = new Uint8List(8);
bytesA.setAll(0, <int>[0, 2, 4, 6, 8, 10, 12, 14]);
final Blob a = new Blob(bytesA);
final Uint8List bytesB = new Uint8List(8);
bytesB.setAll(0, <int>[1, 2, 4, 6, 8, 10, 12, 14]);
final Blob b = new Blob(bytesB);
expect(a.hashCode == b.hashCode, isFalse);
});
});
group('CollectionsReference', () {
test('id', () async {
expect(collectionReference.id, equals('foo'));
Expand Down Expand Up @@ -527,6 +547,12 @@ void main() {
];
_checkEncodeDecode<dynamic>(codec, message);
});
test('encode and decode blob', () {
final Uint8List bytes = new Uint8List(4);
bytes[0] = 128;
final Blob message = new Blob(bytes);
_checkEncodeDecode<dynamic>(codec, message);
});
});

group('WriteBatch', () {
Expand Down

0 comments on commit 99988d6

Please sign in to comment.