Skip to content

Commit 2a07791

Browse files
committed
Bytes
1 parent 2d01a6d commit 2a07791

File tree

4 files changed

+65
-0
lines changed

4 files changed

+65
-0
lines changed

common/api-review/firestore-lite.api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@ export function average(field: string | FieldPath): AggregateField<number | null
6868
// @public
6969
export class Bytes {
7070
static fromBase64String(base64: string): Bytes;
71+
static fromJSON(json: object): Bytes;
7172
static fromUint8Array(array: Uint8Array): Bytes;
7273
isEqual(other: Bytes): boolean;
7374
toBase64(): string;
75+
toJSON(): object;
7476
toString(): string;
7577
toUint8Array(): Uint8Array;
7678
}

common/api-review/firestore.api.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@ export function average(field: string | FieldPath): AggregateField<number | null
6868
// @public
6969
export class Bytes {
7070
static fromBase64String(base64: string): Bytes;
71+
static fromJSON(json: object): Bytes;
7172
static fromUint8Array(array: Uint8Array): Bytes;
7273
isEqual(other: Bytes): boolean;
7374
toBase64(): string;
75+
toJSON(): object;
7476
toString(): string;
7577
toUint8Array(): Uint8Array;
7678
}

packages/firestore/src/lite-api/bytes.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,38 @@ export class Bytes {
9191
isEqual(other: Bytes): boolean {
9292
return this._byteString.isEqual(other._byteString);
9393
}
94+
95+
/** Returns a JSON-serializable representation of this `Bytes` instance. */
96+
toJSON(): object {
97+
return {
98+
type: 'firestore/bytes/1.0',
99+
data: this.toBase64()
100+
};
101+
}
102+
/** Builds a `Bytes` instance from a JSON serialized version of `Bytes`. */
103+
static fromJSON(json: object): Bytes {
104+
const requiredFields = ['type', 'data'];
105+
let error: string | undefined = undefined;
106+
let data: string = '';
107+
for (const key of requiredFields) {
108+
if (!(key in json)) {
109+
error = `json missing required field: ${key}`;
110+
}
111+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
112+
const value = (json as any)[key];
113+
if (typeof value !== 'string') {
114+
error = `json field '${key}' must be a string.`;
115+
break;
116+
} else if (key === 'type' && value !== 'firestore/bytes/1.0') {
117+
error = "Expected 'type' field to equal 'firestore/bytes/1.0'";
118+
break;
119+
} else if (key === 'data') {
120+
data = value;
121+
}
122+
}
123+
if (error) {
124+
throw new FirestoreError(Code.INVALID_ARGUMENT, error);
125+
}
126+
return Bytes.fromBase64String(data);
127+
}
94128
}

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,31 @@ describe('Bytes', () => {
5555
expectEqual(blob(1, 2, 3), blob(1, 2, 3));
5656
expectNotEqual(blob(1, 2, 3), blob(4, 5, 6));
5757
});
58+
59+
it('fromJSON reconstructs the value from toJSON', () => {
60+
const bytes = Bytes.fromUint8Array(new Uint8Array([0, 1, 2, 3, 4, 5]));
61+
expect(() => { Bytes.fromJSON(bytes.toJSON())} ).to.not.throw;
62+
expect(Bytes.fromJSON(bytes.toJSON()).isEqual(bytes)).to.be.true;
63+
});
64+
65+
it('toJSON -> fromJSON bytes comparison', () => {
66+
Object.keys(base64Mappings).forEach(base64Str => {
67+
const bytesToSerialize = Bytes.fromBase64String(base64Str);
68+
const deserializedBytes = Bytes.fromJSON(bytesToSerialize.toJSON());
69+
expectEqual(bytesToSerialize, deserializedBytes);
70+
const expectedUint8Array = base64Mappings[base64Str];
71+
const actualUint8Array = deserializedBytes.toUint8Array();
72+
expect(actualUint8Array.length).to.equal(expectedUint8Array.length);
73+
for (let i = 0; i < actualUint8Array.length; i++) {
74+
expect(actualUint8Array[i]).to.equal(expectedUint8Array[i]);
75+
}
76+
});
77+
})
78+
79+
it('fromJSON misisng fields throws', () => {
80+
expect(() => {Bytes.fromJSON({type: 'firestore/bytes/1.0' /* missing data */})}).to.throw;
81+
expect(() => {Bytes.fromJSON({data: 'AA==' /* missing type */})}).to.throw;
82+
expect(() => {Bytes.fromJSON({type: 1, data: 'AA==' })}).to.throw;
83+
expect(() => {Bytes.fromJSON({type: 'firestore/bytes/1.0', data: 1 })}).to.throw;
84+
});
5885
});

0 commit comments

Comments
 (0)