Skip to content

Commit 259f742

Browse files
Use ByteString in model types
1 parent dad9a4a commit 259f742

File tree

9 files changed

+44
-77
lines changed

9 files changed

+44
-77
lines changed

packages/firestore/src/api/blob.ts

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,7 @@ import {
2323
validateArgType,
2424
validateExactNumberOfArgs
2525
} from '../util/input_validation';
26-
import { primitiveComparator } from '../util/misc';
27-
import {
28-
binaryStringFromUint8Array,
29-
uint8ArrayFromBinaryString
30-
} from '../util/byte_string';
26+
import { ByteString } from '../util/byte_string';
3127

3228
/** Helper function to assert Uint8Array is available at runtime. */
3329
function assertUint8ArrayAvailable(): void {
@@ -57,24 +53,21 @@ function assertBase64Available(): void {
5753
* using the hack above to make sure no-one outside this module can call it.
5854
*/
5955
export class Blob {
60-
// Prefix with underscore to signal this is a private variable in JS and
61-
// prevent it showing up for autocompletion.
62-
// A binary string is a string with each char as Unicode code point in the
63-
// range of [0, 255], essentially simulating a byte array.
64-
private _binaryString: string;
56+
// Prefix with underscore to signal that we consider this not part of the
57+
// public API and to prevent it from showing up for autocompletion.
58+
_byteString: ByteString;
6559

66-
private constructor(binaryString: string) {
60+
constructor(byteString: ByteString) {
6761
assertBase64Available();
68-
this._binaryString = binaryString;
62+
this._byteString = byteString;
6963
}
7064

7165
static fromBase64String(base64: string): Blob {
7266
validateExactNumberOfArgs('Blob.fromBase64String', arguments, 1);
7367
validateArgType('Blob.fromBase64String', 'string', 1, base64);
7468
assertBase64Available();
7569
try {
76-
const binaryString = PlatformSupport.getPlatform().atob(base64);
77-
return new Blob(binaryString);
70+
return new Blob(ByteString.fromBase64String(base64));
7871
} catch (e) {
7972
throw new FirestoreError(
8073
Code.INVALID_ARGUMENT,
@@ -89,42 +82,27 @@ export class Blob {
8982
if (!(array instanceof Uint8Array)) {
9083
throw invalidClassError('Blob.fromUint8Array', 'Uint8Array', 1, array);
9184
}
92-
const binaryString = binaryStringFromUint8Array(array);
93-
return new Blob(binaryString);
85+
return new Blob(ByteString.fromUint8Array(array));
9486
}
9587

9688
toBase64(): string {
9789
validateExactNumberOfArgs('Blob.toBase64', arguments, 0);
9890
assertBase64Available();
99-
return PlatformSupport.getPlatform().btoa(this._binaryString);
91+
return this._byteString.toBase64();
10092
}
10193

10294
toUint8Array(): Uint8Array {
10395
validateExactNumberOfArgs('Blob.toUint8Array', arguments, 0);
10496
assertUint8ArrayAvailable();
105-
const buffer = uint8ArrayFromBinaryString(this._binaryString);
106-
return buffer;
97+
return this._byteString.toUint8Array();
10798
}
10899

109100
toString(): string {
110101
return 'Blob(base64: ' + this.toBase64() + ')';
111102
}
112103

113104
isEqual(other: Blob): boolean {
114-
return this._binaryString === other._binaryString;
115-
}
116-
117-
_approximateByteSize(): number {
118-
// Assume UTF-16 encoding in memory (see StringValue.approximateByteSize())
119-
return this._binaryString.length * 2;
120-
}
121-
122-
/**
123-
* Actually private to JS consumers of our API, so this function is prefixed
124-
* with an underscore.
125-
*/
126-
_compareTo(other: Blob): number {
127-
return primitiveComparator(this._binaryString, other._binaryString);
105+
return this._byteString.isEqual(other._byteString);
128106
}
129107
}
130108

packages/firestore/src/api/database.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import * as firestore from '@firebase/firestore-types';
1919

2020
import { FirebaseApp } from '@firebase/app-types';
2121
import { FirebaseService, _FirebaseApp } from '@firebase/app-types/private';
22+
import { Blob } from './blob';
2223
import { DatabaseId, DatabaseInfo } from '../core/database_info';
2324
import { ListenOptions } from '../core/event_manager';
2425
import {
@@ -44,6 +45,7 @@ import { Document, MaybeDocument, NoDocument } from '../model/document';
4445
import { DocumentKey } from '../model/document_key';
4546
import {
4647
ArrayValue,
48+
BlobValue,
4749
FieldValue,
4850
FieldValueOptions,
4951
ObjectValue,
@@ -1483,6 +1485,8 @@ export class DocumentSnapshot<T = firestore.DocumentData>
14831485
);
14841486
}
14851487
return new DocumentReference(key, this._firestore, this._converter);
1488+
} else if (value instanceof BlobValue) {
1489+
return new Blob(value.internalValue);
14861490
} else {
14871491
return value.value(options);
14881492
}

packages/firestore/src/api/user_data_converter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ export class UserDataConverter {
721721
} else if (value instanceof GeoPoint) {
722722
return new GeoPointValue(value);
723723
} else if (value instanceof Blob) {
724-
return new BlobValue(value);
724+
return new BlobValue(value._byteString);
725725
} else if (value instanceof DocumentKeyReference) {
726726
return new RefValue(value.databaseId, value.key);
727727
} else {

packages/firestore/src/model/field_value.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { primitiveComparator } from '../util/misc';
2525
import { DocumentKey } from './document_key';
2626
import { FieldMask } from './mutation';
2727
import { FieldPath } from './path';
28+
import { ByteString } from '../util/byte_string';
2829
import { SortedMap } from '../util/sorted_map';
2930
import { SortedSet } from '../util/sorted_set';
3031

@@ -455,11 +456,11 @@ export class ServerTimestampValue extends FieldValue {
455456
export class BlobValue extends FieldValue {
456457
typeOrder = TypeOrder.BlobValue;
457458

458-
constructor(readonly internalValue: Blob) {
459+
constructor(readonly internalValue: ByteString) {
459460
super();
460461
}
461462

462-
value(options?: FieldValueOptions): Blob {
463+
value(options?: FieldValueOptions): ByteString {
463464
return this.internalValue;
464465
}
465466

@@ -472,13 +473,13 @@ export class BlobValue extends FieldValue {
472473

473474
compareTo(other: FieldValue): number {
474475
if (other instanceof BlobValue) {
475-
return this.internalValue._compareTo(other.internalValue);
476+
return this.internalValue.compareTo(other.internalValue);
476477
}
477478
return this.defaultCompareTo(other);
478479
}
479480

480481
approximateByteSize(): number {
481-
return this.internalValue._approximateByteSize();
482+
return this.internalValue.approximateByteSize();
482483
}
483484
}
484485

packages/firestore/src/remote/serializer.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,23 +296,23 @@ export class JsonProtoSerializer {
296296
}
297297

298298
/**
299-
* Parse the blob from the protos into the internal Blob class. Note that the
300-
* typings assume all blobs are strings, but they are actually Uint8Arrays
301-
* on Node.
299+
* Parse the blob from the protos into the internal ByteString class. Note
300+
* that the typings assume all blobs are strings, but they are actually
301+
* Uint8Arrays on Node.
302302
*/
303-
private fromBlob(blob: string | Uint8Array): Blob {
303+
private fromBlob(blob: string | Uint8Array): ByteString {
304304
if (typeof blob === 'string') {
305305
assert(
306306
this.options.useProto3Json,
307307
'Expected bytes to be passed in as Uint8Array, but got a string instead.'
308308
);
309-
return Blob.fromBase64String(blob);
309+
return ByteString.fromBase64String(blob);
310310
} else {
311311
assert(
312312
!this.options.useProto3Json,
313313
'Expected bytes to be passed in as Uint8Array, but got a string instead.'
314314
);
315-
return Blob.fromUint8Array(blob);
315+
return ByteString.fromUint8Array(blob);
316316
}
317317
}
318318

packages/firestore/src/util/byte_string.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717

1818
import { PlatformSupport } from '../platform/platform';
19+
import { primitiveComparator } from './misc';
1920

2021
/**
2122
* Immutable class that represents a "proto" byte string.
@@ -28,11 +29,7 @@ import { PlatformSupport } from '../platform/platform';
2829
export class ByteString {
2930
static readonly EMPTY_BYTE_STRING = new ByteString('');
3031

31-
private readonly _binaryString: string;
32-
33-
private constructor(binaryString: string) {
34-
this._binaryString = binaryString;
35-
}
32+
private constructor(private readonly binaryString: string) {}
3633

3734
static fromBase64String(base64: string): ByteString {
3835
const binaryString = PlatformSupport.getPlatform().atob(base64);
@@ -45,19 +42,23 @@ export class ByteString {
4542
}
4643

4744
toBase64(): string {
48-
return PlatformSupport.getPlatform().btoa(this._binaryString);
45+
return PlatformSupport.getPlatform().btoa(this.binaryString);
4946
}
5047

5148
toUint8Array(): Uint8Array {
52-
return uint8ArrayFromBinaryString(this._binaryString);
49+
return uint8ArrayFromBinaryString(this.binaryString);
5350
}
5451

5552
approximateByteSize(): number {
56-
return this._binaryString.length * 2;
53+
return this.binaryString.length * 2;
54+
}
55+
56+
compareTo(other: ByteString): number {
57+
return primitiveComparator(this.binaryString, other.binaryString);
5758
}
5859

5960
isEqual(other: ByteString): boolean {
60-
return this._binaryString === other._binaryString;
61+
return this.binaryString === other.binaryString;
6162
}
6263
}
6364

packages/firestore/test/unit/api/blob.test.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,26 +70,6 @@ describe('Blob', () => {
7070
expect(Blob.fromBase64String('') instanceof PublicBlob).to.equal(true);
7171
});
7272

73-
it('compares correctly', () => {
74-
const values = [
75-
blob(0),
76-
blob(0, 1),
77-
blob(0, 1, 2),
78-
blob(0, 2),
79-
blob(0, 255),
80-
blob(1),
81-
blob(1, 0),
82-
blob(1, 2),
83-
blob(1, 255),
84-
blob(2),
85-
blob(255)
86-
];
87-
88-
expectCorrectComparisons(values, (left: Blob, right: Blob) => {
89-
return left._compareTo(right);
90-
});
91-
});
92-
9373
it('support equality checking with isEqual()', () => {
9474
expectEqual(blob(1, 2, 3), blob(1, 2, 3));
9575
expectNotEqual(blob(1, 2, 3), blob(4, 5, 6));

packages/firestore/test/unit/model/field_value.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,11 @@ describe('FieldValue', () => {
345345
// Doubles and Integers order the same but are not considered equal.
346346
[new fieldValue.DoubleValue(1)],
347347
[wrap(1.1), new fieldValue.DoubleValue(1.1)],
348-
[wrap(blob(0, 1, 2)), new fieldValue.BlobValue(blob(0, 1, 2))],
349-
[new fieldValue.BlobValue(blob(0, 1))],
348+
[
349+
wrap(blob(0, 1, 2)),
350+
new fieldValue.BlobValue(blob(0, 1, 2)._byteString)
351+
],
352+
[new fieldValue.BlobValue(blob(0, 1)._byteString)],
350353
[wrap('string'), new fieldValue.StringValue('string')],
351354
[new fieldValue.StringValue('strin')],
352355
// latin small letter e + combining acute accent

packages/firestore/test/unit/remote/node/serializer.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ describe('Serializer', () => {
353353

354354
it('converts BlobValue to Uint8Array', () => {
355355
const bytes = [0, 1, 2, 3, 4, 5];
356-
const example = Blob.fromUint8Array(new Uint8Array(bytes));
356+
const example = ByteString.fromUint8Array(new Uint8Array(bytes));
357357
const expected = new Uint8Array(bytes);
358358

359359
verifyFieldValueRoundTrip({
@@ -366,7 +366,7 @@ describe('Serializer', () => {
366366
it('converts BlobValue to Base64 string (useProto3Json=true)', () => {
367367
const base64 = 'AAECAwQF';
368368
verifyFieldValueRoundTrip({
369-
value: new fieldValue.BlobValue(Blob.fromBase64String(base64)),
369+
value: new fieldValue.BlobValue(ByteString.fromBase64String(base64)),
370370
valueType: 'bytesValue',
371371
jsonValue: base64,
372372
useProto3Json: true

0 commit comments

Comments
 (0)