Skip to content

Commit aeec17a

Browse files
committed
Fix IndexDbIndexManager encoding of Uint8Array in Safari
1 parent 538f470 commit aeec17a

File tree

6 files changed

+205
-130
lines changed

6 files changed

+205
-130
lines changed

common/api-review/util.api.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,11 @@ export function isReactNative(): boolean;
317317
// @public
318318
export function isSafari(): boolean;
319319

320+
// Warning: (ae-missing-release-tag) "isSafariOrWebkit" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
321+
//
322+
// @public
323+
export function isSafariOrWebkit(): boolean;
324+
320325
// Warning: (ae-missing-release-tag) "issuedAtTime" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
321326
//
322327
// @public

packages/firestore/src/index/index_entry.ts

Lines changed: 69 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,68 +15,107 @@
1515
* limitations under the License.
1616
*/
1717

18+
import { isSafariOrWebkit } from '@firebase/util';
19+
20+
import { DbIndexEntry } from '../local/indexeddb_schema';
21+
import { DbIndexEntryKey } from '../local/indexeddb_sentinels';
1822
import { DocumentKey } from '../model/document_key';
1923

2024
/** Represents an index entry saved by the SDK in persisted storage. */
2125
export class IndexEntry {
2226
constructor(
23-
readonly indexId: number,
24-
readonly documentKey: DocumentKey,
25-
readonly arrayValue: Uint8Array,
26-
readonly directionalValue: Uint8Array
27+
readonly _indexId: number,
28+
readonly _documentKey: DocumentKey,
29+
readonly _arrayValue: Uint8Array | number[],
30+
readonly _directionalValue: Uint8Array | number[]
2731
) {}
2832

2933
/**
3034
* Returns an IndexEntry entry that sorts immediately after the current
3135
* directional value.
3236
*/
3337
successor(): IndexEntry {
34-
const currentLength = this.directionalValue.length;
38+
const currentLength = this._directionalValue.length;
3539
const newLength =
36-
currentLength === 0 || this.directionalValue[currentLength - 1] === 255
40+
currentLength === 0 || this._directionalValue[currentLength - 1] === 255
3741
? currentLength + 1
3842
: currentLength;
3943

4044
const successor = new Uint8Array(newLength);
41-
successor.set(this.directionalValue, 0);
45+
successor.set(this._directionalValue, 0);
4246
if (newLength !== currentLength) {
43-
successor.set([0], this.directionalValue.length);
47+
successor.set([0], this._directionalValue.length);
4448
} else {
4549
++successor[successor.length - 1];
4650
}
4751

4852
return new IndexEntry(
49-
this.indexId,
50-
this.documentKey,
51-
this.arrayValue,
53+
this._indexId,
54+
this._documentKey,
55+
this._arrayValue,
5256
successor
5357
);
5458
}
59+
60+
// Create a representation of the Index Entry as a DbIndexEntry
61+
dbIndexEntry(
62+
uid: string,
63+
orderedDocumentKey: Uint8Array,
64+
documentKey: DocumentKey
65+
): DbIndexEntry {
66+
return {
67+
indexId: this._indexId,
68+
uid, // this.uid,
69+
arrayValue: indexSafeUint8Array(this._arrayValue),
70+
directionalValue: indexSafeUint8Array(this._directionalValue),
71+
orderedDocumentKey: indexSafeUint8Array(orderedDocumentKey), // this.encodeDirectionalKey(fieldIndex, document.key),
72+
documentKey: documentKey.path.toArray()
73+
};
74+
}
75+
76+
// Create a representation of the Index Entry as a DbIndexEntryKey
77+
dbIndexEntryKey(
78+
uid: string,
79+
orderedDocumentKey: Uint8Array,
80+
documentKey: DocumentKey
81+
): DbIndexEntryKey {
82+
return [
83+
this._indexId,
84+
uid,
85+
indexSafeUint8Array(this._arrayValue),
86+
indexSafeUint8Array(this._directionalValue),
87+
indexSafeUint8Array(orderedDocumentKey),
88+
documentKey.path.toArray()
89+
];
90+
}
5591
}
5692

5793
export function indexEntryComparator(
5894
left: IndexEntry,
5995
right: IndexEntry
6096
): number {
61-
let cmp = left.indexId - right.indexId;
97+
let cmp = left._indexId - right._indexId;
6298
if (cmp !== 0) {
6399
return cmp;
64100
}
65101

66-
cmp = compareByteArrays(left.arrayValue, right.arrayValue);
102+
cmp = compareByteArrays(left._arrayValue, right._arrayValue);
67103
if (cmp !== 0) {
68104
return cmp;
69105
}
70106

71-
cmp = compareByteArrays(left.directionalValue, right.directionalValue);
107+
cmp = compareByteArrays(left._directionalValue, right._directionalValue);
72108
if (cmp !== 0) {
73109
return cmp;
74110
}
75111

76-
return DocumentKey.comparator(left.documentKey, right.documentKey);
112+
return DocumentKey.comparator(left._documentKey, right._documentKey);
77113
}
78114

79-
export function compareByteArrays(left: Uint8Array, right: Uint8Array): number {
115+
export function compareByteArrays(
116+
left: Uint8Array | number[],
117+
right: Uint8Array | number[]
118+
): number {
80119
for (let i = 0; i < left.length && i < right.length; ++i) {
81120
const compare = left[i] - right[i];
82121
if (compare !== 0) {
@@ -85,3 +124,17 @@ export function compareByteArrays(left: Uint8Array, right: Uint8Array): number {
85124
}
86125
return left.length - right.length;
87126
}
127+
128+
// Create an safe representation of Uint8Array values
129+
// If the browser is detected as Safari or WebKit, then
130+
// the input array will be converted to `number[]`.
131+
// Otherwise, the input array will be returned in its
132+
// original type.
133+
export function indexSafeUint8Array(
134+
array: Uint8Array | number[]
135+
): Uint8Array | number[] {
136+
if (isSafariOrWebkit() && !Array.isArray(array)) {
137+
return Array.from(array);
138+
}
139+
return array;
140+
}

0 commit comments

Comments
 (0)