@react-native-firebase/firestore 20.1.0 → 20.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/__tests__/firestore.test.ts +14 -2
- package/lib/FirestoreQueryModifiers.js +0 -9
- package/lib/FirestoreStatics.js +2 -2
- package/lib/index.d.ts +1 -1
- package/lib/index.js +7 -0
- package/lib/modular/index.js +1 -0
- package/lib/version.js +1 -1
- package/lib/web/RNFBFirestoreModule.android.js +2 -0
- package/lib/web/RNFBFirestoreModule.ios.js +2 -0
- package/lib/web/RNFBFirestoreModule.js +483 -0
- package/lib/web/convert.js +260 -0
- package/lib/web/query.js +112 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [20.2.0](https://github.com/invertase/react-native-firebase/compare/v20.1.0...v20.2.0) (2024-07-15)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
- **other:** Add Firestore support ([#7882](https://github.com/invertase/react-native-firebase/issues/7882)) ([0ebd1dd](https://github.com/invertase/react-native-firebase/commit/0ebd1ddd221c50dde489bce30ad5ed64037d8439))
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
- **firestore:** expose modular `Filter` and it's proper types ([#7884](https://github.com/invertase/react-native-firebase/issues/7884)) ([272efe5](https://github.com/invertase/react-native-firebase/commit/272efe56acdd46b8c994789f751d2c097cb8d025))
|
|
15
|
+
- **firestore:** remove exception throw on inequality queries on different fields ([da24246](https://github.com/invertase/react-native-firebase/commit/da242466d80609f61420feb56d72ad2ee20b2410))
|
|
16
|
+
|
|
6
17
|
## [20.1.0](https://github.com/invertase/react-native-firebase/compare/v20.0.0...v20.1.0) (2024-06-04)
|
|
7
18
|
|
|
8
19
|
**Note:** Version bump only for package @react-native-firebase/firestore
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { describe, expect, it } from '@jest/globals';
|
|
2
2
|
|
|
3
|
-
import firestore, { firebase } from '../lib';
|
|
3
|
+
import firestore, { firebase, Filter } from '../lib';
|
|
4
4
|
|
|
5
5
|
const COLLECTION = 'firestore';
|
|
6
6
|
|
|
7
|
-
describe('
|
|
7
|
+
describe('Firestore', function () {
|
|
8
8
|
describe('namespace', function () {
|
|
9
9
|
it('accessible from firebase.app()', function () {
|
|
10
10
|
const app = firebase.app();
|
|
@@ -372,5 +372,17 @@ describe('Storage', function () {
|
|
|
372
372
|
return expect(e.message).toContain("'queryName' must be a non-empty string");
|
|
373
373
|
}
|
|
374
374
|
});
|
|
375
|
+
|
|
376
|
+
it('`Filter` is properly exposed to end user', async function () {
|
|
377
|
+
const filter1 = Filter('name', '==', 'Tim');
|
|
378
|
+
const filter2 = Filter('age', '>', 21);
|
|
379
|
+
|
|
380
|
+
// @ts-ignore
|
|
381
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
382
|
+
const query = Filter.and(filter1, filter2);
|
|
383
|
+
// @ts-ignore
|
|
384
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
385
|
+
const query2 = Filter.or(filter1, filter2);
|
|
386
|
+
});
|
|
375
387
|
});
|
|
376
388
|
});
|
|
@@ -269,15 +269,6 @@ export default class FirestoreQueryModifiers {
|
|
|
269
269
|
this.hasInequality = filter;
|
|
270
270
|
continue;
|
|
271
271
|
}
|
|
272
|
-
|
|
273
|
-
// Check the set value is the same as the new one
|
|
274
|
-
if (INEQUALITY[filter.operator] && this.hasInequality) {
|
|
275
|
-
if (this.hasInequality.fieldPath._toPath() !== filter.fieldPath._toPath()) {
|
|
276
|
-
throw new Error(
|
|
277
|
-
`Invalid query. All where filters with an inequality (<, <=, >, != or >=) must be on the same field. But you have inequality filters on '${this.hasInequality.fieldPath._toPath()}' and '${filter.fieldPath._toPath()}'`,
|
|
278
|
-
);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
272
|
}
|
|
282
273
|
|
|
283
274
|
for (let i = 0; i < filters.length; i++) {
|
package/lib/FirestoreStatics.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import {
|
|
18
|
+
import { getReactNativeModule } from '@react-native-firebase/app/lib/internal/nativeModule';
|
|
19
19
|
import FirestoreBlob from './FirestoreBlob';
|
|
20
20
|
import FirestoreFieldPath from './FirestoreFieldPath';
|
|
21
21
|
import FirestoreFieldValue from './FirestoreFieldValue';
|
|
@@ -39,7 +39,7 @@ export default {
|
|
|
39
39
|
);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
const native =
|
|
42
|
+
const native = getReactNativeModule('RNFBFirestoreModule');
|
|
43
43
|
native.setLogLevel(logLevel);
|
|
44
44
|
},
|
|
45
45
|
};
|
package/lib/index.d.ts
CHANGED
|
@@ -2342,7 +2342,7 @@ export const firebase: ReactNativeFirebase.Module & {
|
|
|
2342
2342
|
|
|
2343
2343
|
export * from './modular';
|
|
2344
2344
|
|
|
2345
|
-
export const Filter: FilterFunction;
|
|
2345
|
+
export const Filter: FirebaseFirestoreTypes.FilterFunction;
|
|
2346
2346
|
|
|
2347
2347
|
export default defaultExport;
|
|
2348
2348
|
|
package/lib/index.js
CHANGED
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
isUndefined,
|
|
25
25
|
isAndroid,
|
|
26
26
|
} from '@react-native-firebase/app/lib/common';
|
|
27
|
+
import { setReactNativeModule } from '@react-native-firebase/app/lib/internal/nativeModule';
|
|
27
28
|
import {
|
|
28
29
|
createModuleNamespace,
|
|
29
30
|
FirebaseModule,
|
|
@@ -38,6 +39,7 @@ import FirestoreStatics from './FirestoreStatics';
|
|
|
38
39
|
import FirestoreTransactionHandler from './FirestoreTransactionHandler';
|
|
39
40
|
import FirestoreWriteBatch from './FirestoreWriteBatch';
|
|
40
41
|
import version from './version';
|
|
42
|
+
import fallBackModule from './web/RNFBFirestoreModule';
|
|
41
43
|
|
|
42
44
|
const namespace = 'firestore';
|
|
43
45
|
|
|
@@ -378,3 +380,8 @@ export default createModuleNamespace({
|
|
|
378
380
|
// firestore().X(...);
|
|
379
381
|
// firebase.firestore().X(...);
|
|
380
382
|
export const firebase = getFirebaseRoot();
|
|
383
|
+
|
|
384
|
+
// Register the interop module for non-native platforms.
|
|
385
|
+
for (let i = 0; i < nativeModuleName.length; i++) {
|
|
386
|
+
setReactNativeModule(nativeModuleName[i], fallBackModule);
|
|
387
|
+
}
|
package/lib/modular/index.js
CHANGED
package/lib/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
module.exports = '20.
|
|
2
|
+
module.exports = '20.2.0';
|
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
import {
|
|
2
|
+
setLogLevel,
|
|
3
|
+
connectFirestoreEmulator,
|
|
4
|
+
initializeFirestore,
|
|
5
|
+
runTransaction,
|
|
6
|
+
getApp,
|
|
7
|
+
getFirestore,
|
|
8
|
+
collection,
|
|
9
|
+
collectionGroup,
|
|
10
|
+
doc,
|
|
11
|
+
getDoc,
|
|
12
|
+
getDocs,
|
|
13
|
+
getCount,
|
|
14
|
+
deleteDoc,
|
|
15
|
+
setDoc,
|
|
16
|
+
updateDoc,
|
|
17
|
+
writeBatch,
|
|
18
|
+
terminate,
|
|
19
|
+
} from '@react-native-firebase/app/lib/internal/web/firebaseFirestore';
|
|
20
|
+
import { guard, getWebError, emitEvent } from '@react-native-firebase/app/lib/internal/web/utils';
|
|
21
|
+
import { objectToWriteable, readableToObject, parseDocumentBatches } from './convert';
|
|
22
|
+
import { buildQuery } from './query';
|
|
23
|
+
|
|
24
|
+
function rejectWithCodeAndMessage(code, message) {
|
|
25
|
+
return Promise.reject(
|
|
26
|
+
getWebError({
|
|
27
|
+
code,
|
|
28
|
+
message,
|
|
29
|
+
}),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Converts a Firestore document snapshot to a plain object.
|
|
34
|
+
function documentSnapshotToObject(snapshot) {
|
|
35
|
+
const exists = snapshot.exists();
|
|
36
|
+
|
|
37
|
+
const out = {
|
|
38
|
+
metadata: [false, false], // lite SDK doesn't return metadata
|
|
39
|
+
path: snapshot.ref.path,
|
|
40
|
+
exists,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
if (exists) {
|
|
44
|
+
out.data = objectToWriteable(snapshot.data() || {});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Converts a Firestore query snapshot to a plain object.
|
|
51
|
+
function querySnapshotToObject(snapshot) {
|
|
52
|
+
return {
|
|
53
|
+
source: 'get',
|
|
54
|
+
excludesMetadataChanges: true, // lite SDK doesn't return metadata changes
|
|
55
|
+
changes: [],
|
|
56
|
+
metadata: [false, false], // lite SDK doesn't return metadata
|
|
57
|
+
documents: snapshot.docs.map(documentSnapshotToObject),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const emulatorForApp = {};
|
|
62
|
+
const firestoreInstances = {};
|
|
63
|
+
const appInstances = {};
|
|
64
|
+
const transactionHandler = {};
|
|
65
|
+
const transactionBuffer = {};
|
|
66
|
+
|
|
67
|
+
function getCachedAppInstance(appName) {
|
|
68
|
+
return (appInstances[appName] ??= getApp(appName));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Returns a cached Firestore instance.
|
|
72
|
+
function getCachedFirestoreInstance(appName) {
|
|
73
|
+
let instance = firestoreInstances[appName];
|
|
74
|
+
if (!instance) {
|
|
75
|
+
instance = getFirestore(getCachedAppInstance(appName));
|
|
76
|
+
if (emulatorForApp[appName]) {
|
|
77
|
+
connectFirestoreEmulator(
|
|
78
|
+
instance,
|
|
79
|
+
emulatorForApp[appName].host,
|
|
80
|
+
emulatorForApp[appName].port,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
firestoreInstances[appName] = instance;
|
|
84
|
+
}
|
|
85
|
+
return instance;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default {
|
|
89
|
+
/**
|
|
90
|
+
* Sets the log level for Firestore.
|
|
91
|
+
* @param {string} logLevel - The log level.
|
|
92
|
+
*/
|
|
93
|
+
async setLogLevel(logLevel) {
|
|
94
|
+
if (logLevel === 'debug' || logLevel === 'error') {
|
|
95
|
+
setLogLevel(logLevel);
|
|
96
|
+
} else {
|
|
97
|
+
setLogLevel('silent');
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
loadBundle() {
|
|
102
|
+
return rejectWithCodeAndMessage('unsupported', 'Not supported in the lite SDK.');
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
clearPersistence() {
|
|
106
|
+
return rejectWithCodeAndMessage('unsupported', 'Not supported in the lite SDK.');
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Waits for all pending writes to be acknowledged by the backend.
|
|
111
|
+
* Noop in the lite SDK.
|
|
112
|
+
* @returns {Promise<null>} An empty promise.
|
|
113
|
+
*/
|
|
114
|
+
async waitForPendingWrites() {
|
|
115
|
+
return null;
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
disableNetwork() {
|
|
119
|
+
return rejectWithCodeAndMessage('unsupported', 'Not supported in the lite SDK.');
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
enableNetwork() {
|
|
123
|
+
return rejectWithCodeAndMessage('unsupported', 'Not supported in the lite SDK.');
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Use the Firestore emulator.
|
|
128
|
+
* @param {string} appName - The app name.
|
|
129
|
+
* @param {string} host - The emulator host.
|
|
130
|
+
* @param {number} port - The emulator port.
|
|
131
|
+
* @returns {Promise<null>} An empty promise.
|
|
132
|
+
*/
|
|
133
|
+
useEmulator(appName, host, port) {
|
|
134
|
+
return guard(async () => {
|
|
135
|
+
const firestore = getCachedFirestoreInstance(appName);
|
|
136
|
+
connectFirestoreEmulator(firestore, host, port);
|
|
137
|
+
emulatorForApp[appName] = { host, port };
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Initializes a Firestore instance with settings.
|
|
143
|
+
* @param {string} appName - The app name.
|
|
144
|
+
* @param {object} settings - The Firestore settings.
|
|
145
|
+
* @returns {Promise<null>} An empty promise.
|
|
146
|
+
*/
|
|
147
|
+
settings(appName, settings) {
|
|
148
|
+
return guard(() => {
|
|
149
|
+
const instance = initializeFirestore(getCachedAppInstance(appName), settings);
|
|
150
|
+
firestoreInstances[appName] = instance;
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Terminates a Firestore instance.
|
|
156
|
+
* @param {string} appName - The app name.
|
|
157
|
+
* @returns {Promise<null>} An empty promise.
|
|
158
|
+
*/
|
|
159
|
+
terminate(appName) {
|
|
160
|
+
return guard(async () => {
|
|
161
|
+
const firestore = getCachedFirestoreInstance(appName);
|
|
162
|
+
await terminate(firestore);
|
|
163
|
+
return null;
|
|
164
|
+
});
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
// Collection
|
|
168
|
+
namedQueryOnSnapshot() {
|
|
169
|
+
return rejectWithCodeAndMessage('unsupported', 'Not supported in the lite SDK.');
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
collectionOnSnapshot() {
|
|
173
|
+
return rejectWithCodeAndMessage('unsupported', 'Not supported in the lite SDK.');
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
collectionOffSnapshot() {
|
|
177
|
+
return rejectWithCodeAndMessage('unsupported', 'Not supported in the lite SDK.');
|
|
178
|
+
},
|
|
179
|
+
|
|
180
|
+
namedQueryGet() {
|
|
181
|
+
return rejectWithCodeAndMessage('unsupported', 'Not supported in the lite SDK.');
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Get a collection count from Firestore.
|
|
186
|
+
* @param {string} appName - The app name.
|
|
187
|
+
* @param {string} path - The collection path.
|
|
188
|
+
* @param {string} type - The collection type (e.g. collectionGroup).
|
|
189
|
+
* @param {object[]} filters - The collection filters.
|
|
190
|
+
* @param {object[]} orders - The collection orders.
|
|
191
|
+
* @param {object} options - The collection options.
|
|
192
|
+
* @returns {Promise<object>} The collection count object.
|
|
193
|
+
*/
|
|
194
|
+
collectionCount(appName, path, type, filters, orders, options) {
|
|
195
|
+
return guard(async () => {
|
|
196
|
+
const firestore = getCachedFirestoreInstance(appName);
|
|
197
|
+
const queryRef =
|
|
198
|
+
type === 'collectionGroup' ? collectionGroup(firestore, path) : collection(firestore, path);
|
|
199
|
+
const query = buildQuery(queryRef, filters, orders, options);
|
|
200
|
+
const snapshot = await getCount(query);
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
count: snapshot.data().count,
|
|
204
|
+
};
|
|
205
|
+
});
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Get a collection from Firestore.
|
|
210
|
+
* @param {string} appName - The app name.
|
|
211
|
+
* @param {string} path - The collection path.
|
|
212
|
+
* @param {string} type - The collection type (e.g. collectionGroup).
|
|
213
|
+
* @param {object[]} filters - The collection filters.
|
|
214
|
+
* @param {object[]} orders - The collection orders.
|
|
215
|
+
* @param {object} options - The collection options.
|
|
216
|
+
* @param {object} getOptions - The get options.
|
|
217
|
+
* @returns {Promise<object>} The collection object.
|
|
218
|
+
*/
|
|
219
|
+
collectionGet(appName, path, type, filters, orders, options, getOptions) {
|
|
220
|
+
if (getOptions && getOptions.source === 'cache') {
|
|
221
|
+
return rejectWithCodeAndMessage(
|
|
222
|
+
'unsupported',
|
|
223
|
+
'The source cache is not supported in the lite SDK.',
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return guard(async () => {
|
|
228
|
+
const firestore = getCachedFirestoreInstance(appName);
|
|
229
|
+
const queryRef =
|
|
230
|
+
type === 'collectionGroup' ? collectionGroup(firestore, path) : collection(firestore, path);
|
|
231
|
+
const query = buildQuery(queryRef, filters, orders, options);
|
|
232
|
+
const snapshot = await getDocs(query);
|
|
233
|
+
return querySnapshotToObject(snapshot);
|
|
234
|
+
});
|
|
235
|
+
},
|
|
236
|
+
|
|
237
|
+
// Document
|
|
238
|
+
documentOnSnapshot() {
|
|
239
|
+
return rejectWithCodeAndMessage('unsupported', 'Not supported in the lite SDK.');
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
documentOffSnapshot() {
|
|
243
|
+
return rejectWithCodeAndMessage('unsupported', 'Not supported in the lite SDK.');
|
|
244
|
+
},
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Get a document from Firestore.
|
|
248
|
+
* @param {string} appName - The app name.
|
|
249
|
+
* @param {string} path - The document path.
|
|
250
|
+
* @param {object} getOptions - The get options.
|
|
251
|
+
* @returns {Promise<object>} The document object.
|
|
252
|
+
*/
|
|
253
|
+
documentGet(appName, path, getOptions) {
|
|
254
|
+
return guard(async () => {
|
|
255
|
+
if (getOptions && getOptions.source === 'cache') {
|
|
256
|
+
return rejectWithCodeAndMessage(
|
|
257
|
+
'unsupported',
|
|
258
|
+
'The source cache is not supported in the lite SDK.',
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const firestore = getCachedFirestoreInstance(appName);
|
|
263
|
+
const ref = doc(firestore, path);
|
|
264
|
+
const snapshot = await getDoc(ref);
|
|
265
|
+
return documentSnapshotToObject(snapshot);
|
|
266
|
+
});
|
|
267
|
+
},
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Delete a document from Firestore.
|
|
271
|
+
* @param {string} appName - The app name.
|
|
272
|
+
* @param {string} path - The document path.
|
|
273
|
+
* @returns {Promise<null>} An empty promise.
|
|
274
|
+
*/
|
|
275
|
+
documentDelete(appName, path) {
|
|
276
|
+
return guard(async () => {
|
|
277
|
+
const firestore = getCachedFirestoreInstance(appName);
|
|
278
|
+
const ref = doc(firestore, path);
|
|
279
|
+
await deleteDoc(ref);
|
|
280
|
+
return null;
|
|
281
|
+
});
|
|
282
|
+
},
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Set a document in Firestore.
|
|
286
|
+
* @param {string} appName - The app name.
|
|
287
|
+
* @param {string} path - The document path.
|
|
288
|
+
* @param {object} data - The document data.
|
|
289
|
+
* @param {object} options - The set options.
|
|
290
|
+
* @returns {Promise<null>} An empty promise.
|
|
291
|
+
*/
|
|
292
|
+
documentSet(appName, path, data, options) {
|
|
293
|
+
return guard(async () => {
|
|
294
|
+
const firestore = getCachedFirestoreInstance(appName);
|
|
295
|
+
const ref = doc(firestore, path);
|
|
296
|
+
const setOptions = {};
|
|
297
|
+
if ('merge' in options) {
|
|
298
|
+
setOptions.merge = options.merge;
|
|
299
|
+
} else if ('mergeFields' in options) {
|
|
300
|
+
setOptions.mergeFields = options.mergeFields;
|
|
301
|
+
}
|
|
302
|
+
await setDoc(ref, readableToObject(firestore, data), setOptions);
|
|
303
|
+
});
|
|
304
|
+
},
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Update a document in Firestore.
|
|
308
|
+
* @param {string} appName - The app name.
|
|
309
|
+
* @param {string} path - The document path.
|
|
310
|
+
* @param {object} data - The document data.
|
|
311
|
+
* @returns {Promise<null>} An empty promise.
|
|
312
|
+
*/
|
|
313
|
+
documentUpdate(appName, path, data) {
|
|
314
|
+
return guard(async () => {
|
|
315
|
+
const firestore = getCachedFirestoreInstance(appName);
|
|
316
|
+
const ref = doc(firestore, path);
|
|
317
|
+
await updateDoc(ref, readableToObject(firestore, data));
|
|
318
|
+
});
|
|
319
|
+
},
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Batch write documents in Firestore.
|
|
323
|
+
* @param {string} appName - The app name.
|
|
324
|
+
* @param {object[]} writes - The document writes in write batches format.
|
|
325
|
+
*/
|
|
326
|
+
documentBatch(appName, writes) {
|
|
327
|
+
return guard(async () => {
|
|
328
|
+
const firestore = getCachedFirestoreInstance(appName);
|
|
329
|
+
const batch = writeBatch(firestore);
|
|
330
|
+
const writesArray = parseDocumentBatches(firestore, writes);
|
|
331
|
+
|
|
332
|
+
for (const parsed of writesArray) {
|
|
333
|
+
const { type, path } = parsed;
|
|
334
|
+
const ref = doc(firestore, path);
|
|
335
|
+
|
|
336
|
+
switch (type) {
|
|
337
|
+
case 'DELETE':
|
|
338
|
+
batch.delete(ref);
|
|
339
|
+
break;
|
|
340
|
+
case 'UPDATE':
|
|
341
|
+
batch.update(ref, parsed.data);
|
|
342
|
+
break;
|
|
343
|
+
case 'SET':
|
|
344
|
+
const options = parsed.options;
|
|
345
|
+
const setOptions = {};
|
|
346
|
+
if ('merge' in options) {
|
|
347
|
+
setOptions.merge = options.merge;
|
|
348
|
+
} else if ('mergeFields' in options) {
|
|
349
|
+
setOptions.mergeFields = options.mergeFields;
|
|
350
|
+
}
|
|
351
|
+
batch.set(ref, parsed.data, setOptions);
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
await batch.commit();
|
|
357
|
+
});
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Get a document from a Firestore transaction.
|
|
362
|
+
* @param {string} appName - The app name.
|
|
363
|
+
* @param {string} transactionId - The transaction id.
|
|
364
|
+
* @param {string} path - The document path.
|
|
365
|
+
* @returns {Promise<object>} The document object.
|
|
366
|
+
*/
|
|
367
|
+
transactionGetDocument(appName, transactionId, path) {
|
|
368
|
+
if (!transactionHandler[transactionId]) {
|
|
369
|
+
return rejectWithCodeAndMessage(
|
|
370
|
+
'internal-error',
|
|
371
|
+
'An internal error occurred whilst attempting to find a native transaction by id.',
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
return guard(async () => {
|
|
376
|
+
const firestore = getCachedFirestoreInstance(appName);
|
|
377
|
+
const docRef = doc(firestore, path);
|
|
378
|
+
const tsx = transactionHandler[transactionId];
|
|
379
|
+
const snapshot = await tsx.get(docRef);
|
|
380
|
+
return documentSnapshotToObject(snapshot);
|
|
381
|
+
});
|
|
382
|
+
},
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Dispose a transaction instance.
|
|
386
|
+
* @param {string} appName - The app name.
|
|
387
|
+
* @param {string} transactionId - The transaction id.
|
|
388
|
+
*/
|
|
389
|
+
transactionDispose(appName, transactionId) {
|
|
390
|
+
// There's no abort method in the JS SDK, so we just remove the transaction handler.
|
|
391
|
+
delete transactionHandler[transactionId];
|
|
392
|
+
},
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Applies a buffer of commands to a Firestore transaction.
|
|
396
|
+
* @param {string} appName - The app name.
|
|
397
|
+
* @param {string} transactionId - The transaction id.
|
|
398
|
+
* @param {object[]} commandBuffer - The readable array of buffer commands.
|
|
399
|
+
*/
|
|
400
|
+
transactionApplyBuffer(appName, transactionId, commandBuffer) {
|
|
401
|
+
if (transactionHandler[transactionId]) {
|
|
402
|
+
transactionBuffer[transactionId] = commandBuffer;
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Begins a Firestore transaction.
|
|
408
|
+
* @param {string} appName - The app name.
|
|
409
|
+
* @param {string} transactionId - The transaction id.
|
|
410
|
+
* @returns {Promise<null>} An empty promise.
|
|
411
|
+
*/
|
|
412
|
+
transactionBegin(appName, transactionId) {
|
|
413
|
+
return guard(async () => {
|
|
414
|
+
const firestore = getCachedFirestoreInstance(appName);
|
|
415
|
+
|
|
416
|
+
try {
|
|
417
|
+
await runTransaction(firestore, async tsx => {
|
|
418
|
+
transactionHandler[transactionId] = tsx;
|
|
419
|
+
|
|
420
|
+
emitEvent('firestore_transaction_event', {
|
|
421
|
+
eventName: 'firestore_transaction_event',
|
|
422
|
+
body: { type: 'update' },
|
|
423
|
+
appName,
|
|
424
|
+
listenerId: transactionId,
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
function getBuffer() {
|
|
428
|
+
return transactionBuffer[transactionId];
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Wait for and get the stored buffer array for the transaction.
|
|
432
|
+
const buffer = await new Promise(resolve => {
|
|
433
|
+
const interval = setInterval(() => {
|
|
434
|
+
const buffer = getBuffer();
|
|
435
|
+
if (buffer) {
|
|
436
|
+
clearInterval(interval);
|
|
437
|
+
resolve(buffer);
|
|
438
|
+
}
|
|
439
|
+
}, 100);
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
for (const serialized of buffer) {
|
|
443
|
+
const { path, type, data } = serialized;
|
|
444
|
+
const docRef = doc(firestore, path);
|
|
445
|
+
|
|
446
|
+
switch (type) {
|
|
447
|
+
case 'DELETE':
|
|
448
|
+
tsx.delete(docRef);
|
|
449
|
+
break;
|
|
450
|
+
case 'UPDATE':
|
|
451
|
+
tsx.update(docRef, readableToObject(firestore, data));
|
|
452
|
+
break;
|
|
453
|
+
case 'SET':
|
|
454
|
+
const options = serialized.options;
|
|
455
|
+
const setOptions = {};
|
|
456
|
+
if ('merge' in options) {
|
|
457
|
+
setOptions.merge = options.merge;
|
|
458
|
+
} else if ('mergeFields' in options) {
|
|
459
|
+
setOptions.mergeFields = options.mergeFields;
|
|
460
|
+
}
|
|
461
|
+
tsx.set(docRef, readableToObject(firestore, data), setOptions);
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
emitEvent('firestore_transaction_event', {
|
|
468
|
+
eventName: 'firestore_transaction_event',
|
|
469
|
+
body: { type: 'complete' },
|
|
470
|
+
appName,
|
|
471
|
+
listenerId: transactionId,
|
|
472
|
+
});
|
|
473
|
+
} catch (e) {
|
|
474
|
+
emitEvent('firestore_transaction_event', {
|
|
475
|
+
eventName: 'firestore_transaction_event',
|
|
476
|
+
body: { type: 'error', error: getWebError(e) },
|
|
477
|
+
appName,
|
|
478
|
+
listenerId: transactionId,
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
},
|
|
483
|
+
};
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DocumentReference,
|
|
3
|
+
Timestamp,
|
|
4
|
+
GeoPoint,
|
|
5
|
+
Bytes,
|
|
6
|
+
doc,
|
|
7
|
+
documentId,
|
|
8
|
+
serverTimestamp,
|
|
9
|
+
increment,
|
|
10
|
+
deleteField,
|
|
11
|
+
arrayUnion,
|
|
12
|
+
arrayRemove,
|
|
13
|
+
} from '@react-native-firebase/app/lib/internal/web/firebaseFirestore';
|
|
14
|
+
|
|
15
|
+
const INT_NAN = 0;
|
|
16
|
+
const INT_NEGATIVE_INFINITY = 1;
|
|
17
|
+
const INT_POSITIVE_INFINITY = 2;
|
|
18
|
+
const INT_NULL = 3;
|
|
19
|
+
const INT_DOCUMENTID = 4;
|
|
20
|
+
const INT_BOOLEAN_TRUE = 5;
|
|
21
|
+
const INT_BOOLEAN_FALSE = 6;
|
|
22
|
+
const INT_DOUBLE = 7;
|
|
23
|
+
const INT_STRING = 8;
|
|
24
|
+
const INT_STRING_EMPTY = 9;
|
|
25
|
+
const INT_ARRAY = 10;
|
|
26
|
+
const INT_REFERENCE = 11;
|
|
27
|
+
const INT_GEOPOINT = 12;
|
|
28
|
+
const INT_TIMESTAMP = 13;
|
|
29
|
+
const INT_BLOB = 14;
|
|
30
|
+
const INT_FIELDVALUE = 15;
|
|
31
|
+
const INT_OBJECT = 16;
|
|
32
|
+
const INT_INTEGER = 17;
|
|
33
|
+
const INT_NEGATIVE_ZERO = 18;
|
|
34
|
+
const INT_UNKNOWN = -999;
|
|
35
|
+
|
|
36
|
+
const TYPE = 'type';
|
|
37
|
+
const KEY_PATH = 'path';
|
|
38
|
+
const KEY_DATA = 'data';
|
|
39
|
+
const KEY_OPTIONS = 'options';
|
|
40
|
+
|
|
41
|
+
// Converts an object to a writeable object.
|
|
42
|
+
export function objectToWriteable(object) {
|
|
43
|
+
const out = {};
|
|
44
|
+
for (const [key, value] of Object.entries(object)) {
|
|
45
|
+
out[key] = buildTypeMap(value);
|
|
46
|
+
}
|
|
47
|
+
return out;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Converts an array of values to a writeable array.
|
|
51
|
+
export function arrayToWriteable(array) {
|
|
52
|
+
return array.map(buildTypeMap);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Converts a readable object into a plain js object.
|
|
56
|
+
export function readableToObject(firestore, readableMap) {
|
|
57
|
+
const out = {};
|
|
58
|
+
|
|
59
|
+
for (const [key, value] of Object.entries(readableMap)) {
|
|
60
|
+
out[key] = parseTypeMap(firestore, value);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Converts a readable array into a plain js array.
|
|
67
|
+
export function readableToArray(firestore, readableArray) {
|
|
68
|
+
return readableArray.map(value => parseTypeMap(firestore, value));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Converts a readable array of document batch data into a plain js array.
|
|
72
|
+
export function parseDocumentBatches(firestore, readableArray) {
|
|
73
|
+
const out = [];
|
|
74
|
+
|
|
75
|
+
for (const map of readableArray) {
|
|
76
|
+
const write = {
|
|
77
|
+
[TYPE]: map[TYPE],
|
|
78
|
+
[KEY_PATH]: map[KEY_PATH],
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
if (KEY_DATA in map) {
|
|
82
|
+
write[KEY_DATA] = readableToObject(firestore, map[KEY_DATA]);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (KEY_OPTIONS in map) {
|
|
86
|
+
write[KEY_OPTIONS] = map[KEY_OPTIONS];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
out.push(write);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Returns a typed array of a value.
|
|
96
|
+
export function buildTypeMap(value) {
|
|
97
|
+
const out = [];
|
|
98
|
+
if (value === null) {
|
|
99
|
+
out.push(INT_NULL);
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (typeof value === 'boolean') {
|
|
104
|
+
if (value) out.push(INT_BOOLEAN_TRUE);
|
|
105
|
+
else out.push(INT_BOOLEAN_FALSE);
|
|
106
|
+
return out;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Double
|
|
110
|
+
if (typeof value === 'number' && !Number.isInteger(value)) {
|
|
111
|
+
out.push(INT_DOUBLE);
|
|
112
|
+
out.push(value);
|
|
113
|
+
return out;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Integer
|
|
117
|
+
if (typeof value === 'number' && Number.isInteger(value)) {
|
|
118
|
+
if (value == Number.NEGATIVE_INFINITY) {
|
|
119
|
+
out.push(INT_NEGATIVE_INFINITY);
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (value == Number.POSITIVE_INFINITY) {
|
|
124
|
+
out.push(INT_POSITIVE_INFINITY);
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (isNaN(value)) {
|
|
129
|
+
out.push(INT_NAN);
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
out.push(INT_DOUBLE);
|
|
134
|
+
out.push(value);
|
|
135
|
+
return out;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (typeof value === 'string') {
|
|
139
|
+
if (value === '') {
|
|
140
|
+
out.push(INT_STRING_EMPTY);
|
|
141
|
+
} else {
|
|
142
|
+
out.push(INT_STRING);
|
|
143
|
+
out.push(value);
|
|
144
|
+
}
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (Array.isArray(value)) {
|
|
149
|
+
out.push(INT_ARRAY);
|
|
150
|
+
out.push(arrayToWriteable(value));
|
|
151
|
+
return out;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (value instanceof DocumentReference) {
|
|
155
|
+
out.push(INT_REFERENCE);
|
|
156
|
+
out.push(value.path);
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (value instanceof Timestamp) {
|
|
161
|
+
out.push(INT_TIMESTAMP);
|
|
162
|
+
out.push([value.seconds, value.nanoseconds]);
|
|
163
|
+
return out;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (value instanceof GeoPoint) {
|
|
167
|
+
out.push(INT_GEOPOINT);
|
|
168
|
+
out.push([value.latitude, value.longitude]);
|
|
169
|
+
return out;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (value instanceof Bytes) {
|
|
173
|
+
out.push(INT_BLOB);
|
|
174
|
+
out.push(value.toBase64());
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (typeof value === 'object') {
|
|
179
|
+
out.push(INT_OBJECT);
|
|
180
|
+
out.push(objectToWriteable(value));
|
|
181
|
+
return out;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
out.push(INT_UNKNOWN);
|
|
185
|
+
return out;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Parses a typed array into a value.
|
|
189
|
+
export function parseTypeMap(firestore, typedArray) {
|
|
190
|
+
const value = typedArray[0];
|
|
191
|
+
|
|
192
|
+
switch (value) {
|
|
193
|
+
case INT_NAN:
|
|
194
|
+
return NaN;
|
|
195
|
+
case INT_NEGATIVE_INFINITY:
|
|
196
|
+
return Number.NEGATIVE_INFINITY;
|
|
197
|
+
case INT_POSITIVE_INFINITY:
|
|
198
|
+
return Number.POSITIVE_INFINITY;
|
|
199
|
+
case INT_NULL:
|
|
200
|
+
return null;
|
|
201
|
+
case INT_DOCUMENTID:
|
|
202
|
+
return documentId();
|
|
203
|
+
case INT_BOOLEAN_TRUE:
|
|
204
|
+
return true;
|
|
205
|
+
case INT_BOOLEAN_FALSE:
|
|
206
|
+
return false;
|
|
207
|
+
case INT_NEGATIVE_ZERO:
|
|
208
|
+
return -0;
|
|
209
|
+
case INT_INTEGER:
|
|
210
|
+
return Number(typedArray[1]);
|
|
211
|
+
case INT_DOUBLE:
|
|
212
|
+
return Number(typedArray[1]);
|
|
213
|
+
case INT_STRING:
|
|
214
|
+
return String(typedArray[1]);
|
|
215
|
+
case INT_STRING_EMPTY:
|
|
216
|
+
return '';
|
|
217
|
+
case INT_ARRAY:
|
|
218
|
+
return readableToArray(firestore, typedArray[1]);
|
|
219
|
+
case INT_REFERENCE:
|
|
220
|
+
return doc(firestore, typedArray[1]);
|
|
221
|
+
case INT_GEOPOINT:
|
|
222
|
+
const [latitude, longitude] = typedArray[1];
|
|
223
|
+
return new GeoPoint(latitude, longitude);
|
|
224
|
+
case INT_TIMESTAMP:
|
|
225
|
+
const [seconds, nanoseconds] = typedArray[1];
|
|
226
|
+
return new Timestamp(seconds, nanoseconds);
|
|
227
|
+
case INT_BLOB:
|
|
228
|
+
return Bytes.fromBase64String(typedArray[1]);
|
|
229
|
+
case INT_FIELDVALUE:
|
|
230
|
+
const fieldValueArray = typedArray[1];
|
|
231
|
+
const fieldValueType = fieldValueArray[0];
|
|
232
|
+
|
|
233
|
+
if (fieldValueType === 'timestamp') {
|
|
234
|
+
return serverTimestamp();
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (fieldValueType === 'increment') {
|
|
238
|
+
return increment(fieldValueArray[1]);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (fieldValueType === 'delete') {
|
|
242
|
+
return deleteField();
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (fieldValueType === 'array_union') {
|
|
246
|
+
const elements = readableToArray(firestore, fieldValueArray[1]);
|
|
247
|
+
return arrayUnion(...elements);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (fieldValueType === 'array_remove') {
|
|
251
|
+
const elements = readableToArray(firestore, fieldValueArray[1]);
|
|
252
|
+
return arrayRemove(...elements);
|
|
253
|
+
}
|
|
254
|
+
case INT_OBJECT:
|
|
255
|
+
return readableToObject(firestore, typedArray[1]);
|
|
256
|
+
case INT_UNKNOWN:
|
|
257
|
+
default:
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
package/lib/web/query.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FieldPath,
|
|
3
|
+
query,
|
|
4
|
+
where,
|
|
5
|
+
orderBy,
|
|
6
|
+
limit,
|
|
7
|
+
limitToLast,
|
|
8
|
+
startAt,
|
|
9
|
+
startAfter,
|
|
10
|
+
endAt,
|
|
11
|
+
endBefore,
|
|
12
|
+
and,
|
|
13
|
+
or,
|
|
14
|
+
} from '@react-native-firebase/app/lib/internal/web/firebaseFirestore';
|
|
15
|
+
import { parseTypeMap, readableToArray } from './convert';
|
|
16
|
+
|
|
17
|
+
export function buildQuery(queryInstance, filters, orders, options) {
|
|
18
|
+
// Apply filters
|
|
19
|
+
for (const filter of filters) {
|
|
20
|
+
queryInstance = query(queryInstance, getFilterConstraint(filter));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Apply orders
|
|
24
|
+
for (const order of orders) {
|
|
25
|
+
const fieldPath =
|
|
26
|
+
typeof order.fieldPath === 'string' ? order.fieldPath : new FieldPath(...order.fieldPath);
|
|
27
|
+
const direction = order.direction === 'ASCENDING' ? 'asc' : 'desc';
|
|
28
|
+
queryInstance = query(queryInstance, orderBy(fieldPath, direction));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Apply options
|
|
32
|
+
if ('limit' in options) {
|
|
33
|
+
queryInstance = query(queryInstance, limit(options.limit));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if ('limitToLast' in options) {
|
|
37
|
+
queryInstance = query(queryInstance, limitToLast(options.limitToLast));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if ('startAt' in options) {
|
|
41
|
+
const fieldList = readableToArray(queryInstance.firestore, options.startAt);
|
|
42
|
+
queryInstance = query(queryInstance, startAt(...fieldList));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if ('startAfter' in options) {
|
|
46
|
+
const fieldList = readableToArray(queryInstance.firestore, options.startAfter);
|
|
47
|
+
queryInstance = query(queryInstance, startAfter(...fieldList));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if ('endAt' in options) {
|
|
51
|
+
const fieldList = readableToArray(queryInstance.firestore, options.endAt);
|
|
52
|
+
queryInstance = query(queryInstance, endAt(...fieldList));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if ('endBefore' in options) {
|
|
56
|
+
const fieldList = readableToArray(queryInstance.firestore, options.endBefore);
|
|
57
|
+
queryInstance = query(queryInstance, endBefore(...fieldList));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return queryInstance;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getFilterConstraint(filter) {
|
|
64
|
+
if ('fieldPath' in filter && filter.fieldPath) {
|
|
65
|
+
const fieldPath = Array.isArray(filter.fieldPath)
|
|
66
|
+
? new FieldPath(...filter.fieldPath)
|
|
67
|
+
: new FieldPath(...filter.fieldPath._segments);
|
|
68
|
+
const operator = filter.operator;
|
|
69
|
+
const value = parseTypeMap(query.firestore, filter.value);
|
|
70
|
+
|
|
71
|
+
switch (operator) {
|
|
72
|
+
case 'EQUAL':
|
|
73
|
+
return where(fieldPath, '==', value);
|
|
74
|
+
case 'NOT_EQUAL':
|
|
75
|
+
return where(fieldPath, '!=', value);
|
|
76
|
+
case 'GREATER_THAN':
|
|
77
|
+
return where(fieldPath, '>', value);
|
|
78
|
+
case 'GREATER_THAN_OR_EQUAL':
|
|
79
|
+
return where(fieldPath, '>=', value);
|
|
80
|
+
case 'LESS_THAN':
|
|
81
|
+
return where(fieldPath, '<', value);
|
|
82
|
+
case 'LESS_THAN_OR_EQUAL':
|
|
83
|
+
return where(fieldPath, '<=', value);
|
|
84
|
+
case 'ARRAY_CONTAINS':
|
|
85
|
+
return where(fieldPath, 'array-contains', value);
|
|
86
|
+
case 'ARRAY_CONTAINS_ANY':
|
|
87
|
+
return where(fieldPath, 'array-contains-any', value);
|
|
88
|
+
case 'IN':
|
|
89
|
+
return where(fieldPath, 'in', value);
|
|
90
|
+
case 'NOT_IN':
|
|
91
|
+
return where(fieldPath, 'not-in', value);
|
|
92
|
+
}
|
|
93
|
+
} else if ('operator' in filter && 'queries' in filter) {
|
|
94
|
+
const constraints = [];
|
|
95
|
+
|
|
96
|
+
for (const constraint of filter.queries) {
|
|
97
|
+
constraints.push(getFilterConstraint(constraint));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (filter.operator === 'AND') {
|
|
101
|
+
return and(...constraints);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (filter.operator === 'OR') {
|
|
105
|
+
return or(...constraints);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
throw new Error('Invalid filter operator');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
throw new Error('Invaldi filter.');
|
|
112
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-native-firebase/firestore",
|
|
3
|
-
"version": "20.
|
|
3
|
+
"version": "20.2.0",
|
|
4
4
|
"author": "Invertase <oss@invertase.io> (http://invertase.io)",
|
|
5
5
|
"description": "React Native Firebase - Cloud Firestore is a NoSQL cloud database to store and sync data between your React Native application and Firebase's database. The API matches the Firebase Web SDK whilst taking advantage of the native SDKs performance and offline capabilities.",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
"firestore"
|
|
28
28
|
],
|
|
29
29
|
"peerDependencies": {
|
|
30
|
-
"@react-native-firebase/app": "20.
|
|
30
|
+
"@react-native-firebase/app": "20.2.0"
|
|
31
31
|
},
|
|
32
32
|
"publishConfig": {
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "82c50138d07e673213cd8dee5ce9a2f9b5656649"
|
|
36
36
|
}
|