@react-native-firebase/firestore 17.4.3 → 18.0.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 +27 -0
- package/android/src/reactnative/java/io/invertase/firebase/firestore/ReactNativeFirebaseFirestoreQuery.java +120 -42
- package/ios/RNFBFirestore/RNFBFirestoreQuery.m +81 -16
- package/lib/FirestoreFilter.js +151 -0
- package/lib/FirestoreQuery.js +58 -40
- package/lib/FirestoreQueryModifiers.js +64 -50
- package/lib/FirestoreStatics.js +2 -1
- package/lib/index.d.ts +66 -0
- package/lib/version.js +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,33 @@
|
|
|
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
|
+
## [18.0.0](https://github.com/invertase/react-native-firebase/compare/v17.5.0...v18.0.0) (2023-06-05)
|
|
7
|
+
|
|
8
|
+
### ⚠ BREAKING CHANGES
|
|
9
|
+
|
|
10
|
+
- **app, sdk:** this version of the underlying firebase-ios-sdk has
|
|
11
|
+
a minimum Xcode requirement of 14.1 which transitively implies a macOS
|
|
12
|
+
minimum version of 12.5
|
|
13
|
+
- **app, sdk:** the "safetyNet" provider for App Check has been removed
|
|
14
|
+
from the underlying firebase-android-sdk and we have removed it here. You
|
|
15
|
+
should upgrade to the "playIntegrity" provider for App Check
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
|
|
19
|
+
- **app, sdk:** android-sdk v32 - app-check safetyNet provider is removed ([a0e76ec](https://github.com/invertase/react-native-firebase/commit/a0e76ecab65c69a19055a84bc19c069482b1bc88))
|
|
20
|
+
- **app, sdk:** ios-sdk 10.10.0, requires Xcode 14.1+ / macOS 12.5+ ([3122918](https://github.com/invertase/react-native-firebase/commit/3122918c19c27696caf51f30caafdcaa76807db8))
|
|
21
|
+
|
|
22
|
+
### Bug Fixes
|
|
23
|
+
|
|
24
|
+
- **firestore, types:** add types for Filter constraints on Queries ([#7124](https://github.com/invertase/react-native-firebase/issues/7124)) ([0785d27](https://github.com/invertase/react-native-firebase/commit/0785d276669b9c875951d4527e8884c9014e48fe))
|
|
25
|
+
- **firestore:** Allow queries with combined in and array-contains-any ([#7142](https://github.com/invertase/react-native-firebase/issues/7142)) ([8da6951](https://github.com/invertase/react-native-firebase/commit/8da69519b3dd516a67976a490434f8f9c12a426e))
|
|
26
|
+
|
|
27
|
+
## [17.5.0](https://github.com/invertase/react-native-firebase/compare/v17.4.3...v17.5.0) (2023-05-11)
|
|
28
|
+
|
|
29
|
+
### Features
|
|
30
|
+
|
|
31
|
+
- **firestore:** Firestore `Filter` instance. Use `Filter`, `Filter.or()` & `Filter.and()` in Firestore queries. ([#7045](https://github.com/invertase/react-native-firebase/issues/7045)) ([f7ec3d1](https://github.com/invertase/react-native-firebase/commit/f7ec3d1970f4fa8cc9752bb3cd8f1550b2a457c5))
|
|
32
|
+
|
|
6
33
|
### [17.4.3](https://github.com/invertase/react-native-firebase/compare/v17.4.2...v17.4.3) (2023-04-26)
|
|
7
34
|
|
|
8
35
|
**Note:** Version bump only for package @react-native-firebase/firestore
|
|
@@ -26,6 +26,7 @@ import com.facebook.react.bridge.WritableMap;
|
|
|
26
26
|
import com.google.android.gms.tasks.Task;
|
|
27
27
|
import com.google.android.gms.tasks.Tasks;
|
|
28
28
|
import com.google.firebase.firestore.FieldPath;
|
|
29
|
+
import com.google.firebase.firestore.Filter;
|
|
29
30
|
import com.google.firebase.firestore.Query;
|
|
30
31
|
import com.google.firebase.firestore.QuerySnapshot;
|
|
31
32
|
import com.google.firebase.firestore.Source;
|
|
@@ -65,62 +66,139 @@ public class ReactNativeFirebaseFirestoreQuery {
|
|
|
65
66
|
for (int i = 0; i < filters.size(); i++) {
|
|
66
67
|
ReadableMap filter = filters.getMap(i);
|
|
67
68
|
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
if (filter.hasKey("fieldPath")) {
|
|
70
|
+
ArrayList<Object> fieldPathArray =
|
|
71
|
+
Objects.requireNonNull(Objects.requireNonNull(filter).getArray("fieldPath"))
|
|
72
|
+
.toArrayList();
|
|
73
|
+
String[] segmentArray = (String[]) fieldPathArray.toArray(new String[0]);
|
|
74
|
+
|
|
75
|
+
FieldPath fieldPath = FieldPath.of(Objects.requireNonNull(segmentArray));
|
|
76
|
+
String operator = filter.getString("operator");
|
|
77
|
+
ReadableArray arrayValue = filter.getArray("value");
|
|
78
|
+
Object value = parseTypeMap(query.getFirestore(), Objects.requireNonNull(arrayValue));
|
|
79
|
+
|
|
80
|
+
switch (Objects.requireNonNull(operator)) {
|
|
81
|
+
case "EQUAL":
|
|
82
|
+
query = query.whereEqualTo(Objects.requireNonNull(fieldPath), value);
|
|
83
|
+
break;
|
|
84
|
+
case "NOT_EQUAL":
|
|
85
|
+
query = query.whereNotEqualTo(Objects.requireNonNull(fieldPath), value);
|
|
86
|
+
break;
|
|
87
|
+
case "GREATER_THAN":
|
|
88
|
+
query =
|
|
89
|
+
query.whereGreaterThan(
|
|
90
|
+
Objects.requireNonNull(fieldPath), Objects.requireNonNull(value));
|
|
91
|
+
break;
|
|
92
|
+
case "GREATER_THAN_OR_EQUAL":
|
|
93
|
+
query =
|
|
94
|
+
query.whereGreaterThanOrEqualTo(
|
|
95
|
+
Objects.requireNonNull(fieldPath), Objects.requireNonNull(value));
|
|
96
|
+
break;
|
|
97
|
+
case "LESS_THAN":
|
|
98
|
+
query =
|
|
99
|
+
query.whereLessThan(
|
|
100
|
+
Objects.requireNonNull(fieldPath), Objects.requireNonNull(value));
|
|
101
|
+
break;
|
|
102
|
+
case "LESS_THAN_OR_EQUAL":
|
|
103
|
+
query =
|
|
104
|
+
query.whereLessThanOrEqualTo(
|
|
105
|
+
Objects.requireNonNull(fieldPath), Objects.requireNonNull(value));
|
|
106
|
+
break;
|
|
107
|
+
case "ARRAY_CONTAINS":
|
|
108
|
+
query =
|
|
109
|
+
query.whereArrayContains(
|
|
110
|
+
Objects.requireNonNull(fieldPath), Objects.requireNonNull(value));
|
|
111
|
+
break;
|
|
112
|
+
case "ARRAY_CONTAINS_ANY":
|
|
113
|
+
query =
|
|
114
|
+
query.whereArrayContainsAny(
|
|
115
|
+
Objects.requireNonNull(fieldPath),
|
|
116
|
+
Objects.requireNonNull((List<Object>) value));
|
|
117
|
+
break;
|
|
118
|
+
case "IN":
|
|
119
|
+
query =
|
|
120
|
+
query.whereIn(
|
|
121
|
+
Objects.requireNonNull(fieldPath),
|
|
122
|
+
Objects.requireNonNull((List<Object>) value));
|
|
123
|
+
break;
|
|
124
|
+
case "NOT_IN":
|
|
125
|
+
query =
|
|
126
|
+
query.whereNotIn(
|
|
127
|
+
Objects.requireNonNull(fieldPath),
|
|
128
|
+
Objects.requireNonNull((List<Object>) value));
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
} else if (filter.hasKey("operator") && filter.hasKey("queries")) {
|
|
132
|
+
query = query.where(applyFilterQueries(filter));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private Filter applyFilterQueries(ReadableMap filter) {
|
|
138
|
+
if (filter.hasKey("fieldPath")) {
|
|
139
|
+
String operator =
|
|
140
|
+
(String) Objects.requireNonNull(Objects.requireNonNull(filter).getString("operator"));
|
|
141
|
+
ReadableMap fieldPathMap = Objects.requireNonNull(filter.getMap("fieldPath"));
|
|
142
|
+
ReadableArray segments = Objects.requireNonNull(fieldPathMap.getArray("_segments"));
|
|
143
|
+
int arraySize = segments.size();
|
|
144
|
+
String[] segmentArray = new String[arraySize];
|
|
70
145
|
|
|
71
|
-
|
|
72
|
-
|
|
146
|
+
for (int i = 0; i < arraySize; i++) {
|
|
147
|
+
segmentArray[i] = segments.getString(i);
|
|
148
|
+
}
|
|
149
|
+
FieldPath fieldPath = FieldPath.of(segmentArray);
|
|
73
150
|
ReadableArray arrayValue = filter.getArray("value");
|
|
151
|
+
|
|
74
152
|
Object value = parseTypeMap(query.getFirestore(), Objects.requireNonNull(arrayValue));
|
|
75
153
|
|
|
76
|
-
switch (
|
|
154
|
+
switch (operator) {
|
|
77
155
|
case "EQUAL":
|
|
78
|
-
|
|
79
|
-
break;
|
|
156
|
+
return Filter.equalTo(fieldPath, value);
|
|
80
157
|
case "NOT_EQUAL":
|
|
81
|
-
|
|
82
|
-
break;
|
|
83
|
-
case "GREATER_THAN":
|
|
84
|
-
query =
|
|
85
|
-
query.whereGreaterThan(
|
|
86
|
-
Objects.requireNonNull(fieldPath), Objects.requireNonNull(value));
|
|
87
|
-
break;
|
|
88
|
-
case "GREATER_THAN_OR_EQUAL":
|
|
89
|
-
query =
|
|
90
|
-
query.whereGreaterThanOrEqualTo(
|
|
91
|
-
Objects.requireNonNull(fieldPath), Objects.requireNonNull(value));
|
|
92
|
-
break;
|
|
158
|
+
return Filter.notEqualTo(fieldPath, value);
|
|
93
159
|
case "LESS_THAN":
|
|
94
|
-
|
|
95
|
-
query.whereLessThan(Objects.requireNonNull(fieldPath), Objects.requireNonNull(value));
|
|
96
|
-
break;
|
|
160
|
+
return Filter.lessThan(fieldPath, value);
|
|
97
161
|
case "LESS_THAN_OR_EQUAL":
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
162
|
+
return Filter.lessThanOrEqualTo(fieldPath, value);
|
|
163
|
+
case "GREATER_THAN":
|
|
164
|
+
return Filter.greaterThan(fieldPath, value);
|
|
165
|
+
case "GREATER_THAN_OR_EQUAL":
|
|
166
|
+
return Filter.greaterThanOrEqualTo(fieldPath, value);
|
|
102
167
|
case "ARRAY_CONTAINS":
|
|
103
|
-
|
|
104
|
-
query.whereArrayContains(
|
|
105
|
-
Objects.requireNonNull(fieldPath), Objects.requireNonNull(value));
|
|
106
|
-
break;
|
|
168
|
+
return Filter.arrayContains(fieldPath, value);
|
|
107
169
|
case "ARRAY_CONTAINS_ANY":
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
Objects.requireNonNull(fieldPath), Objects.requireNonNull((List<Object>) value));
|
|
111
|
-
break;
|
|
170
|
+
assert value != null;
|
|
171
|
+
return Filter.arrayContainsAny(fieldPath, (List<?>) value);
|
|
112
172
|
case "IN":
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
Objects.requireNonNull(fieldPath), Objects.requireNonNull((List<Object>) value));
|
|
116
|
-
break;
|
|
173
|
+
assert value != null;
|
|
174
|
+
return Filter.inArray(fieldPath, (List<?>) value);
|
|
117
175
|
case "NOT_IN":
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
176
|
+
assert value != null;
|
|
177
|
+
return Filter.notInArray(fieldPath, (List<?>) value);
|
|
178
|
+
default:
|
|
179
|
+
throw new Error("Invalid operator");
|
|
122
180
|
}
|
|
123
181
|
}
|
|
182
|
+
|
|
183
|
+
String operator = Objects.requireNonNull(filter).getString("operator");
|
|
184
|
+
ReadableArray queries =
|
|
185
|
+
Objects.requireNonNull(Objects.requireNonNull(filter).getArray("queries"));
|
|
186
|
+
ArrayList<Filter> parsedFilters = new ArrayList<>();
|
|
187
|
+
int arraySize = queries.size();
|
|
188
|
+
for (int i = 0; i < arraySize; i++) {
|
|
189
|
+
ReadableMap map = queries.getMap(i);
|
|
190
|
+
parsedFilters.add(applyFilterQueries(map));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (operator.equals("AND")) {
|
|
194
|
+
return Filter.and(parsedFilters.toArray(new Filter[0]));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (operator.equals("OR")) {
|
|
198
|
+
return Filter.or(parsedFilters.toArray(new Filter[0]));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
throw new Error("Missing 'Filter' instance return");
|
|
124
202
|
}
|
|
125
203
|
|
|
126
204
|
private void applyOrders(ReadableArray orders) {
|
|
@@ -51,33 +51,98 @@
|
|
|
51
51
|
|
|
52
52
|
- (void)applyFilters {
|
|
53
53
|
for (NSDictionary *filter in _filters) {
|
|
54
|
-
|
|
54
|
+
if (filter[@"fieldPath"]) {
|
|
55
|
+
NSArray *fieldPathArray = filter[@"fieldPath"];
|
|
56
|
+
|
|
57
|
+
FIRFieldPath *fieldPath = [[FIRFieldPath alloc] initWithFields:fieldPathArray];
|
|
58
|
+
NSString *operator= filter[@"operator"];
|
|
59
|
+
id value = [RNFBFirestoreSerialize parseTypeMap:_firestore typeMap:filter[@"value"]];
|
|
60
|
+
if ([operator isEqualToString:@"EQUAL"]) {
|
|
61
|
+
_query = [_query queryWhereFieldPath:fieldPath isEqualTo:value];
|
|
62
|
+
} else if ([operator isEqualToString:@"NOT_EQUAL"]) {
|
|
63
|
+
_query = [_query queryWhereFieldPath:fieldPath isNotEqualTo:value];
|
|
64
|
+
} else if ([operator isEqualToString:@"GREATER_THAN"]) {
|
|
65
|
+
_query = [_query queryWhereFieldPath:fieldPath isGreaterThan:value];
|
|
66
|
+
} else if ([operator isEqualToString:@"GREATER_THAN_OR_EQUAL"]) {
|
|
67
|
+
_query = [_query queryWhereFieldPath:fieldPath isGreaterThanOrEqualTo:value];
|
|
68
|
+
} else if ([operator isEqualToString:@"LESS_THAN"]) {
|
|
69
|
+
_query = [_query queryWhereFieldPath:fieldPath isLessThan:value];
|
|
70
|
+
} else if ([operator isEqualToString:@"LESS_THAN_OR_EQUAL"]) {
|
|
71
|
+
_query = [_query queryWhereFieldPath:fieldPath isLessThanOrEqualTo:value];
|
|
72
|
+
} else if ([operator isEqualToString:@"ARRAY_CONTAINS"]) {
|
|
73
|
+
_query = [_query queryWhereFieldPath:fieldPath arrayContains:value];
|
|
74
|
+
} else if ([operator isEqualToString:@"IN"]) {
|
|
75
|
+
_query = [_query queryWhereFieldPath:fieldPath in:value];
|
|
76
|
+
} else if ([operator isEqualToString:@"ARRAY_CONTAINS_ANY"]) {
|
|
77
|
+
_query = [_query queryWhereFieldPath:fieldPath arrayContainsAny:value];
|
|
78
|
+
} else if ([operator isEqualToString:@"NOT_IN"]) {
|
|
79
|
+
_query = [_query queryWhereFieldPath:fieldPath notIn:value];
|
|
80
|
+
}
|
|
81
|
+
} else if (filter[@"operator"] && filter[@"queries"]) {
|
|
82
|
+
// Filter query
|
|
83
|
+
FIRFilter *generatedFilter = [self _applyFilterQueries:filter];
|
|
84
|
+
_query = [_query queryWhereFilter:generatedFilter];
|
|
85
|
+
} else {
|
|
86
|
+
@throw
|
|
87
|
+
[NSException exceptionWithName:@"InvalidOperator"
|
|
88
|
+
reason:@"The correct signature for a filter has not been parsed"
|
|
89
|
+
userInfo:nil];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
- (FIRFilter *)_applyFilterQueries:(NSDictionary<NSString *, id> *)map {
|
|
95
|
+
if ([map objectForKey:@"fieldPath"]) {
|
|
96
|
+
NSString *operator= map[@"operator"];
|
|
97
|
+
NSArray *fieldPathArray = map[@"fieldPath"][@"_segments"];
|
|
98
|
+
|
|
55
99
|
FIRFieldPath *fieldPath = [[FIRFieldPath alloc] initWithFields:fieldPathArray];
|
|
56
|
-
|
|
57
|
-
id value = [RNFBFirestoreSerialize parseTypeMap:_firestore typeMap:filter[@"value"]];
|
|
100
|
+
id value = [RNFBFirestoreSerialize parseTypeMap:_firestore typeMap:map[@"value"]];
|
|
58
101
|
|
|
59
102
|
if ([operator isEqualToString:@"EQUAL"]) {
|
|
60
|
-
|
|
103
|
+
return [FIRFilter filterWhereFieldPath:fieldPath isEqualTo:value];
|
|
61
104
|
} else if ([operator isEqualToString:@"NOT_EQUAL"]) {
|
|
62
|
-
|
|
63
|
-
} else if ([operator isEqualToString:@"GREATER_THAN"]) {
|
|
64
|
-
_query = [_query queryWhereFieldPath:fieldPath isGreaterThan:value];
|
|
65
|
-
} else if ([operator isEqualToString:@"GREATER_THAN_OR_EQUAL"]) {
|
|
66
|
-
_query = [_query queryWhereFieldPath:fieldPath isGreaterThanOrEqualTo:value];
|
|
105
|
+
return [FIRFilter filterWhereFieldPath:fieldPath isNotEqualTo:value];
|
|
67
106
|
} else if ([operator isEqualToString:@"LESS_THAN"]) {
|
|
68
|
-
|
|
107
|
+
return [FIRFilter filterWhereFieldPath:fieldPath isLessThan:value];
|
|
69
108
|
} else if ([operator isEqualToString:@"LESS_THAN_OR_EQUAL"]) {
|
|
70
|
-
|
|
109
|
+
return [FIRFilter filterWhereFieldPath:fieldPath isLessThanOrEqualTo:value];
|
|
110
|
+
} else if ([operator isEqualToString:@"GREATER_THAN"]) {
|
|
111
|
+
return [FIRFilter filterWhereFieldPath:fieldPath isGreaterThan:value];
|
|
112
|
+
} else if ([operator isEqualToString:@"GREATER_THAN_OR_EQUAL"]) {
|
|
113
|
+
return [FIRFilter filterWhereFieldPath:fieldPath isGreaterThanOrEqualTo:value];
|
|
71
114
|
} else if ([operator isEqualToString:@"ARRAY_CONTAINS"]) {
|
|
72
|
-
|
|
73
|
-
} else if ([operator isEqualToString:@"IN"]) {
|
|
74
|
-
_query = [_query queryWhereFieldPath:fieldPath in:value];
|
|
115
|
+
return [FIRFilter filterWhereFieldPath:fieldPath arrayContains:value];
|
|
75
116
|
} else if ([operator isEqualToString:@"ARRAY_CONTAINS_ANY"]) {
|
|
76
|
-
|
|
117
|
+
return [FIRFilter filterWhereFieldPath:fieldPath arrayContainsAny:value];
|
|
118
|
+
} else if ([operator isEqualToString:@"IN"]) {
|
|
119
|
+
return [FIRFilter filterWhereFieldPath:fieldPath in:value];
|
|
77
120
|
} else if ([operator isEqualToString:@"NOT_IN"]) {
|
|
78
|
-
|
|
121
|
+
return [FIRFilter filterWhereFieldPath:fieldPath notIn:value];
|
|
122
|
+
} else {
|
|
123
|
+
@throw [NSException exceptionWithName:@"InvalidOperator"
|
|
124
|
+
reason:@"Invalid operator"
|
|
125
|
+
userInfo:nil];
|
|
79
126
|
}
|
|
80
127
|
}
|
|
128
|
+
|
|
129
|
+
NSString *op = map[@"operator"];
|
|
130
|
+
NSArray<NSDictionary<NSString *, id> *> *queries = map[@"queries"];
|
|
131
|
+
NSMutableArray<FIRFilter *> *parsedFilters = [NSMutableArray array];
|
|
132
|
+
|
|
133
|
+
for (NSDictionary *query in queries) {
|
|
134
|
+
[parsedFilters addObject:[self _applyFilterQueries:query]];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if ([op isEqual:@"AND"]) {
|
|
138
|
+
return [FIRFilter andFilterWithFilters:parsedFilters];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if ([op isEqualToString:@"OR"]) {
|
|
142
|
+
return [FIRFilter orFilterWithFilters:parsedFilters];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
@throw [NSException exceptionWithName:@"InvalidOperator" reason:@"Invalid operator" userInfo:nil];
|
|
81
146
|
}
|
|
82
147
|
|
|
83
148
|
- (void)applyOrders {
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { isString, isNull, isUndefined, isArray } from '@react-native-firebase/app/lib/common';
|
|
2
|
+
import { fromDotSeparatedString } from './FirestoreFieldPath';
|
|
3
|
+
import { generateNativeData } from './utils/serialize';
|
|
4
|
+
import { OPERATORS } from './FirestoreQueryModifiers';
|
|
5
|
+
const AND_QUERY = 'AND';
|
|
6
|
+
const OR_QUERY = 'OR';
|
|
7
|
+
|
|
8
|
+
export function Filter(fieldPath, operator, value) {
|
|
9
|
+
return new _Filter(fieldPath, operator, value);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function _Filter(fieldPath, operator, value, filterOperator, queries) {
|
|
13
|
+
if ([AND_QUERY, OR_QUERY].includes(filterOperator)) {
|
|
14
|
+
// AND or OR Filter (list of Filters)
|
|
15
|
+
this.operator = filterOperator;
|
|
16
|
+
this.queries = queries;
|
|
17
|
+
|
|
18
|
+
this._toMap = function _toMap() {
|
|
19
|
+
return {
|
|
20
|
+
operator: this.operator,
|
|
21
|
+
queries: this.queries.map(query => query._toMap()),
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
return this;
|
|
26
|
+
} else {
|
|
27
|
+
// Filter
|
|
28
|
+
this.fieldPath = fieldPath;
|
|
29
|
+
this.operator = operator;
|
|
30
|
+
this.value = value;
|
|
31
|
+
|
|
32
|
+
this._toMap = function _toMap() {
|
|
33
|
+
return {
|
|
34
|
+
fieldPath: this.fieldPath,
|
|
35
|
+
operator: this.operator,
|
|
36
|
+
value: this.value,
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
Filter.and = function and(...queries) {
|
|
45
|
+
if (queries.length > 10 || queries.length < 2) {
|
|
46
|
+
throw new Error(`Expected 2-10 instances of Filter, but got ${queries.length} Filters`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const validateFilters = queries.every(filter => filter instanceof _Filter);
|
|
50
|
+
|
|
51
|
+
if (!validateFilters) {
|
|
52
|
+
throw new Error('Expected every argument to be an instance of Filter');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return new _Filter(null, null, null, AND_QUERY, queries);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
function hasOrOperator(obj) {
|
|
59
|
+
return obj.operator === 'OR' || (Array.isArray(obj.queries) && obj.queries.some(hasOrOperator));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
Filter.or = function or(...queries) {
|
|
63
|
+
if (queries.length > 10 || queries.length < 2) {
|
|
64
|
+
throw new Error(`Expected 2-10 instances of Filter, but got ${queries.length} Filters`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const validateFilters = queries.every(filter => filter instanceof _Filter);
|
|
68
|
+
|
|
69
|
+
if (!validateFilters) {
|
|
70
|
+
throw new Error('Expected every argument to be an instance of Filter');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const hasOr = queries.some(hasOrOperator);
|
|
74
|
+
|
|
75
|
+
if (hasOr) {
|
|
76
|
+
throw new Error('OR Filters with nested OR Filters are not supported');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return new _Filter(null, null, null, OR_QUERY, queries);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
function mapFieldQuery({ fieldPath, operator, value, queries }, modifiers) {
|
|
83
|
+
if (operator === AND_QUERY || operator === OR_QUERY) {
|
|
84
|
+
return {
|
|
85
|
+
operator,
|
|
86
|
+
queries: queries.map(filter => mapFieldQuery(filter, modifiers)),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
let path;
|
|
91
|
+
if (isString(fieldPath)) {
|
|
92
|
+
try {
|
|
93
|
+
path = fromDotSeparatedString(fieldPath);
|
|
94
|
+
} catch (e) {
|
|
95
|
+
throw new Error(`first argument of Filter(*,_ , _) 'fieldPath' ${e.message}.`);
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
path = fieldPath;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (!modifiers.isValidOperator(operator)) {
|
|
102
|
+
throw new Error(
|
|
103
|
+
"second argument of Filter(*,_ , _) 'opStr' is invalid. Expected one of '==', '>', '>=', '<', '<=', '!=', 'array-contains', 'not-in', 'array-contains-any' or 'in'.",
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (isUndefined(value)) {
|
|
108
|
+
throw new Error("third argument of Filter(*,_ , _) 'value' argument expected.");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (
|
|
112
|
+
isNull(value) &&
|
|
113
|
+
!modifiers.isEqualOperator(operator) &&
|
|
114
|
+
!modifiers.isNotEqualOperator(operator)
|
|
115
|
+
) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
"third argument of Filter(*,_ , _) 'value' is invalid. You can only perform equals comparisons on null",
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (modifiers.isInOperator(operator)) {
|
|
122
|
+
if (!isArray(value) || !value.length) {
|
|
123
|
+
throw new Error(
|
|
124
|
+
`third argument of Filter(*,_ , _) 'value' is invalid. A non-empty array is required for '${operator}' filters.`,
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (value.length > 10) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
`third argument of Filter(*,_ , _) 'value' is invalid. '${operator}' filters support a maximum of 10 elements in the value array.`,
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
fieldPath: path,
|
|
137
|
+
operator: OPERATORS[operator],
|
|
138
|
+
value: generateNativeData(value, true),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function generateFilters(filter, modifiers) {
|
|
143
|
+
const filterMap = filter._toMap();
|
|
144
|
+
|
|
145
|
+
const queriesMaps = filterMap.queries.map(filter => mapFieldQuery(filter, modifiers));
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
operator: filterMap.operator,
|
|
149
|
+
queries: queriesMaps,
|
|
150
|
+
};
|
|
151
|
+
}
|
package/lib/FirestoreQuery.js
CHANGED
|
@@ -28,6 +28,7 @@ import FirestoreDocumentSnapshot from './FirestoreDocumentSnapshot';
|
|
|
28
28
|
import FirestoreFieldPath, { fromDotSeparatedString } from './FirestoreFieldPath';
|
|
29
29
|
import FirestoreQuerySnapshot from './FirestoreQuerySnapshot';
|
|
30
30
|
import { parseSnapshotArgs } from './utils';
|
|
31
|
+
import { _Filter, generateFilters } from './FirestoreFilter';
|
|
31
32
|
|
|
32
33
|
let _id = 0;
|
|
33
34
|
|
|
@@ -406,62 +407,79 @@ export default class FirestoreQuery {
|
|
|
406
407
|
);
|
|
407
408
|
}
|
|
408
409
|
|
|
409
|
-
where(
|
|
410
|
-
if (
|
|
410
|
+
where(fieldPathOrFilter, opStr, value) {
|
|
411
|
+
if (
|
|
412
|
+
!isString(fieldPathOrFilter) &&
|
|
413
|
+
!(fieldPathOrFilter instanceof FirestoreFieldPath) &&
|
|
414
|
+
!(fieldPathOrFilter instanceof _Filter)
|
|
415
|
+
) {
|
|
411
416
|
throw new Error(
|
|
412
|
-
"firebase.firestore().collection().where(*) 'fieldPath' must be a string or instance of
|
|
417
|
+
"firebase.firestore().collection().where(*) 'fieldPath' must be a string, instance of FieldPath or instance of Filter.",
|
|
413
418
|
);
|
|
414
419
|
}
|
|
415
420
|
|
|
416
|
-
let
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
} catch (e) {
|
|
422
|
-
throw new Error(`firebase.firestore().collection().where(*) 'fieldPath' ${e.message}.`);
|
|
423
|
-
}
|
|
421
|
+
let modifiers;
|
|
422
|
+
if (fieldPathOrFilter instanceof _Filter && fieldPathOrFilter.queries) {
|
|
423
|
+
//AND or OR filter
|
|
424
|
+
const filters = generateFilters(fieldPathOrFilter, this._modifiers);
|
|
425
|
+
modifiers = this._modifiers._copy().filterWhere(filters);
|
|
424
426
|
} else {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
}
|
|
427
|
+
if (fieldPathOrFilter instanceof _Filter) {
|
|
428
|
+
// Standard Filter. Usual path.
|
|
429
|
+
opStr = fieldPathOrFilter.operator;
|
|
430
|
+
value = fieldPathOrFilter.value;
|
|
431
|
+
fieldPathOrFilter = fieldPathOrFilter.fieldPath;
|
|
432
|
+
}
|
|
433
|
+
let path;
|
|
433
434
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
435
|
+
if (isString(fieldPathOrFilter)) {
|
|
436
|
+
try {
|
|
437
|
+
path = fromDotSeparatedString(fieldPathOrFilter);
|
|
438
|
+
} catch (e) {
|
|
439
|
+
throw new Error(`firebase.firestore().collection().where(*) 'fieldPath' ${e.message}.`);
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
path = fieldPathOrFilter;
|
|
443
|
+
}
|
|
439
444
|
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
throw new Error(
|
|
446
|
-
"firebase.firestore().collection().where(_, _, *) 'value' is invalid. You can only perform equals comparisons on null",
|
|
447
|
-
);
|
|
448
|
-
}
|
|
445
|
+
if (!this._modifiers.isValidOperator(opStr)) {
|
|
446
|
+
throw new Error(
|
|
447
|
+
"firebase.firestore().collection().where(_, *) 'opStr' is invalid. Expected one of '==', '>', '>=', '<', '<=', '!=', 'array-contains', 'not-in', 'array-contains-any' or 'in'.",
|
|
448
|
+
);
|
|
449
|
+
}
|
|
449
450
|
|
|
450
|
-
|
|
451
|
-
if (!isArray(value) || !value.length) {
|
|
451
|
+
if (isUndefined(value)) {
|
|
452
452
|
throw new Error(
|
|
453
|
-
|
|
453
|
+
"firebase.firestore().collection().where(_, _, *) 'value' argument expected.",
|
|
454
454
|
);
|
|
455
455
|
}
|
|
456
456
|
|
|
457
|
-
if (
|
|
457
|
+
if (
|
|
458
|
+
isNull(value) &&
|
|
459
|
+
!this._modifiers.isEqualOperator(opStr) &&
|
|
460
|
+
!this._modifiers.isNotEqualOperator(opStr)
|
|
461
|
+
) {
|
|
458
462
|
throw new Error(
|
|
459
|
-
|
|
463
|
+
"firebase.firestore().collection().where(_, _, *) 'value' is invalid. You can only perform equals comparisons on null",
|
|
460
464
|
);
|
|
461
465
|
}
|
|
462
|
-
}
|
|
463
466
|
|
|
464
|
-
|
|
467
|
+
if (this._modifiers.isInOperator(opStr)) {
|
|
468
|
+
if (!isArray(value) || !value.length) {
|
|
469
|
+
throw new Error(
|
|
470
|
+
`firebase.firestore().collection().where(_, _, *) 'value' is invalid. A non-empty array is required for '${opStr}' filters.`,
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
if (value.length > 10) {
|
|
475
|
+
throw new Error(
|
|
476
|
+
`firebase.firestore().collection().where(_, _, *) 'value' is invalid. '${opStr}' filters support a maximum of 10 elements in the value array.`,
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
modifiers = this._modifiers._copy().where(path, opStr, value);
|
|
482
|
+
}
|
|
465
483
|
|
|
466
484
|
try {
|
|
467
485
|
modifiers.validateWhere();
|
|
@@ -19,7 +19,7 @@ import { isNumber } from '@react-native-firebase/app/lib/common';
|
|
|
19
19
|
import FirestoreFieldPath, { DOCUMENT_ID } from './FirestoreFieldPath';
|
|
20
20
|
import { buildNativeArray, generateNativeData } from './utils/serialize';
|
|
21
21
|
|
|
22
|
-
const OPERATORS = {
|
|
22
|
+
export const OPERATORS = {
|
|
23
23
|
'==': 'EQUAL',
|
|
24
24
|
'>': 'GREATER_THAN',
|
|
25
25
|
'>=': 'GREATER_THAN_OR_EQUAL',
|
|
@@ -57,6 +57,14 @@ export default class FirestoreQueryModifiers {
|
|
|
57
57
|
this._startAfter = undefined;
|
|
58
58
|
this._endAt = undefined;
|
|
59
59
|
this._endBefore = undefined;
|
|
60
|
+
|
|
61
|
+
// Pulled out of function to preserve their state
|
|
62
|
+
this.hasInequality = false;
|
|
63
|
+
this.hasNotEqual = false;
|
|
64
|
+
this.hasArrayContains = false;
|
|
65
|
+
this.hasArrayContainsAny = false;
|
|
66
|
+
this.hasIn = false;
|
|
67
|
+
this.hasNotIn = false;
|
|
60
68
|
}
|
|
61
69
|
|
|
62
70
|
_copy() {
|
|
@@ -221,118 +229,113 @@ export default class FirestoreQueryModifiers {
|
|
|
221
229
|
return this;
|
|
222
230
|
}
|
|
223
231
|
|
|
232
|
+
filterWhere(filter) {
|
|
233
|
+
this._filters = this._filters.concat(filter);
|
|
234
|
+
return this;
|
|
235
|
+
}
|
|
236
|
+
|
|
224
237
|
validateWhere() {
|
|
225
|
-
|
|
226
|
-
|
|
238
|
+
if (this._filters.length > 0) {
|
|
239
|
+
this._filterCheck(this._filters);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
_filterCheck(filters) {
|
|
244
|
+
for (let i = 0; i < filters.length; i++) {
|
|
245
|
+
const filter = filters[i];
|
|
246
|
+
|
|
247
|
+
if (filter.queries) {
|
|
248
|
+
// Recursively check sub-queries for Filters
|
|
249
|
+
this._filterCheck(filter.queries);
|
|
250
|
+
// If it is a Filter query, skip the rest of the loop
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
227
253
|
|
|
228
|
-
for (let i = 0; i < this._filters.length; i++) {
|
|
229
|
-
const filter = this._filters[i];
|
|
230
254
|
// Skip if no inequality
|
|
231
255
|
if (!INEQUALITY[filter.operator]) {
|
|
232
256
|
continue;
|
|
233
257
|
}
|
|
234
258
|
|
|
235
259
|
if (filter.operator === OPERATORS['!=']) {
|
|
236
|
-
if (hasNotEqual) {
|
|
260
|
+
if (this.hasNotEqual) {
|
|
237
261
|
throw new Error("Invalid query. You cannot use more than one '!=' inequality filter.");
|
|
238
262
|
}
|
|
239
263
|
//needs to set hasNotEqual = true before setting first hasInequality = filter. It is used in a condition check later
|
|
240
|
-
hasNotEqual = true;
|
|
264
|
+
this.hasNotEqual = true;
|
|
241
265
|
}
|
|
242
266
|
|
|
243
267
|
// Set the first inequality
|
|
244
|
-
if (!hasInequality) {
|
|
245
|
-
hasInequality = filter;
|
|
268
|
+
if (!this.hasInequality) {
|
|
269
|
+
this.hasInequality = filter;
|
|
246
270
|
continue;
|
|
247
271
|
}
|
|
248
272
|
|
|
249
273
|
// Check the set value is the same as the new one
|
|
250
|
-
if (INEQUALITY[filter.operator] && hasInequality) {
|
|
251
|
-
if (hasInequality.fieldPath._toPath() !== filter.fieldPath._toPath()) {
|
|
274
|
+
if (INEQUALITY[filter.operator] && this.hasInequality) {
|
|
275
|
+
if (this.hasInequality.fieldPath._toPath() !== filter.fieldPath._toPath()) {
|
|
252
276
|
throw new Error(
|
|
253
|
-
`Invalid query. All where filters with an inequality (<, <=, >, != or >=) must be on the same field. But you have inequality filters on '${hasInequality.fieldPath._toPath()}' and '${filter.fieldPath._toPath()}'`,
|
|
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()}'`,
|
|
254
278
|
);
|
|
255
279
|
}
|
|
256
280
|
}
|
|
257
281
|
}
|
|
258
282
|
|
|
259
|
-
let
|
|
260
|
-
|
|
261
|
-
let hasIn;
|
|
262
|
-
let hasNotIn;
|
|
263
|
-
|
|
264
|
-
for (let i = 0; i < this._filters.length; i++) {
|
|
265
|
-
const filter = this._filters[i];
|
|
283
|
+
for (let i = 0; i < filters.length; i++) {
|
|
284
|
+
const filter = filters[i];
|
|
266
285
|
|
|
267
286
|
if (filter.operator === OPERATORS['array-contains']) {
|
|
268
|
-
if (hasArrayContains) {
|
|
287
|
+
if (this.hasArrayContains) {
|
|
269
288
|
throw new Error('Invalid query. Queries only support a single array-contains filter.');
|
|
270
289
|
}
|
|
271
|
-
hasArrayContains = true;
|
|
290
|
+
this.hasArrayContains = true;
|
|
272
291
|
}
|
|
273
292
|
|
|
274
293
|
if (filter.operator === OPERATORS['array-contains-any']) {
|
|
275
|
-
if (hasArrayContainsAny) {
|
|
294
|
+
if (this.hasArrayContainsAny) {
|
|
276
295
|
throw new Error(
|
|
277
296
|
"Invalid query. You cannot use more than one 'array-contains-any' filter.",
|
|
278
297
|
);
|
|
279
298
|
}
|
|
280
299
|
|
|
281
|
-
if (
|
|
282
|
-
throw new Error(
|
|
283
|
-
"Invalid query. You cannot use 'array-contains-any' filters with 'in' filters.",
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
if (hasNotIn) {
|
|
300
|
+
if (this.hasNotIn) {
|
|
288
301
|
throw new Error(
|
|
289
302
|
"Invalid query. You cannot use 'array-contains-any' filters with 'not-in' filters.",
|
|
290
303
|
);
|
|
291
304
|
}
|
|
292
305
|
|
|
293
|
-
hasArrayContainsAny = true;
|
|
306
|
+
this.hasArrayContainsAny = true;
|
|
294
307
|
}
|
|
295
308
|
|
|
296
309
|
if (filter.operator === OPERATORS.in) {
|
|
297
|
-
if (
|
|
298
|
-
throw new Error("Invalid query. You cannot use more than one 'in' filter.");
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
if (hasArrayContainsAny) {
|
|
302
|
-
throw new Error(
|
|
303
|
-
"Invalid query. You cannot use 'in' filters with 'array-contains-any' filters.",
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if (hasNotIn) {
|
|
310
|
+
if (this.hasNotIn) {
|
|
308
311
|
throw new Error("Invalid query. You cannot use 'in' filters with 'not-in' filters.");
|
|
309
312
|
}
|
|
310
313
|
|
|
311
|
-
hasIn = true;
|
|
314
|
+
this.hasIn = true;
|
|
312
315
|
}
|
|
313
316
|
|
|
314
317
|
if (filter.operator === OPERATORS['not-in']) {
|
|
315
|
-
if (hasNotIn) {
|
|
318
|
+
if (this.hasNotIn) {
|
|
316
319
|
throw new Error("Invalid query. You cannot use more than one 'not-in' filter.");
|
|
317
320
|
}
|
|
318
321
|
|
|
319
|
-
if (hasNotEqual) {
|
|
322
|
+
if (this.hasNotEqual) {
|
|
320
323
|
throw new Error(
|
|
321
324
|
"Invalid query. You cannot use 'not-in' filters with '!=' inequality filters",
|
|
322
325
|
);
|
|
323
326
|
}
|
|
324
327
|
|
|
325
|
-
if (hasIn) {
|
|
328
|
+
if (this.hasIn) {
|
|
326
329
|
throw new Error("Invalid query. You cannot use 'not-in' filters with 'in' filters.");
|
|
327
330
|
}
|
|
328
331
|
|
|
329
|
-
if (hasArrayContainsAny) {
|
|
332
|
+
if (this.hasArrayContainsAny) {
|
|
330
333
|
throw new Error(
|
|
331
334
|
"Invalid query. You cannot use 'not-in' filters with 'array-contains-any' filters.",
|
|
332
335
|
);
|
|
333
336
|
}
|
|
334
337
|
|
|
335
|
-
hasNotIn = true;
|
|
338
|
+
this.hasNotIn = true;
|
|
336
339
|
}
|
|
337
340
|
}
|
|
338
341
|
}
|
|
@@ -356,6 +359,10 @@ export default class FirestoreQueryModifiers {
|
|
|
356
359
|
}
|
|
357
360
|
|
|
358
361
|
validateOrderBy() {
|
|
362
|
+
this._validateOrderByCheck(this._filters);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
_validateOrderByCheck(filters) {
|
|
359
366
|
// Ensure order hasn't been called on the same field
|
|
360
367
|
if (this._orders.length > 1) {
|
|
361
368
|
const orders = this._orders.map($ => $.fieldPath._toPath());
|
|
@@ -367,13 +374,20 @@ export default class FirestoreQueryModifiers {
|
|
|
367
374
|
}
|
|
368
375
|
|
|
369
376
|
// Skip if no where filters
|
|
370
|
-
if (
|
|
377
|
+
if (filters.length === 0) {
|
|
371
378
|
return;
|
|
372
379
|
}
|
|
373
380
|
|
|
374
381
|
// Ensure the first order field path is equal to the inequality filter field path
|
|
375
|
-
for (let i = 0; i <
|
|
376
|
-
const filter =
|
|
382
|
+
for (let i = 0; i < filters.length; i++) {
|
|
383
|
+
const filter = filters[i];
|
|
384
|
+
|
|
385
|
+
if (filter.queries) {
|
|
386
|
+
// Recursively check sub-queries for Filters
|
|
387
|
+
this._validateOrderByCheck(filter.queries);
|
|
388
|
+
// If it is a Filter query, skip the rest of the loop
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
377
391
|
const filterFieldPath = filter.fieldPath._toPath();
|
|
378
392
|
|
|
379
393
|
for (let k = 0; k < this._orders.length; k++) {
|
package/lib/FirestoreStatics.js
CHANGED
|
@@ -21,13 +21,14 @@ import FirestoreFieldPath from './FirestoreFieldPath';
|
|
|
21
21
|
import FirestoreFieldValue from './FirestoreFieldValue';
|
|
22
22
|
import FirestoreGeoPoint from './FirestoreGeoPoint';
|
|
23
23
|
import FirestoreTimestamp from './FirestoreTimestamp';
|
|
24
|
-
|
|
24
|
+
import { Filter } from './FirestoreFilter';
|
|
25
25
|
export default {
|
|
26
26
|
Blob: FirestoreBlob,
|
|
27
27
|
FieldPath: FirestoreFieldPath,
|
|
28
28
|
FieldValue: FirestoreFieldValue,
|
|
29
29
|
GeoPoint: FirestoreGeoPoint,
|
|
30
30
|
Timestamp: FirestoreTimestamp,
|
|
31
|
+
Filter: Filter,
|
|
31
32
|
|
|
32
33
|
CACHE_SIZE_UNLIMITED: -1,
|
|
33
34
|
|
package/lib/index.d.ts
CHANGED
|
@@ -49,6 +49,47 @@ import { ReactNativeFirebase } from '@react-native-firebase/app';
|
|
|
49
49
|
*/
|
|
50
50
|
export namespace FirebaseFirestoreTypes {
|
|
51
51
|
import FirebaseModule = ReactNativeFirebase.FirebaseModule;
|
|
52
|
+
/**
|
|
53
|
+
* An instance of Filter used to generate Firestore Filter queries.
|
|
54
|
+
*/
|
|
55
|
+
|
|
56
|
+
export type QueryFilterType = 'OR' | 'AND';
|
|
57
|
+
|
|
58
|
+
export interface QueryFilterConstraint {
|
|
59
|
+
fieldPath: keyof T | FieldPath;
|
|
60
|
+
operator: WhereFilterOp;
|
|
61
|
+
value: any;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface QueryCompositeFilterConstraint {
|
|
65
|
+
operator: QueryFilterType;
|
|
66
|
+
queries: QueryFilterConstraint[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The Filter functions used to generate an instance of Filter.
|
|
70
|
+
*/
|
|
71
|
+
export interface FilterFunction {
|
|
72
|
+
/**
|
|
73
|
+
* The Filter function used to generate an instance of Filter.
|
|
74
|
+
* e.g. Filter('name', '==', 'Ada')
|
|
75
|
+
*/
|
|
76
|
+
(fieldPath: keyof T | FieldPath, operator: WhereFilterOp, value: any): QueryFilterConstraint;
|
|
77
|
+
/**
|
|
78
|
+
* The Filter.or() static function used to generate a logical OR query using multiple Filter instances.
|
|
79
|
+
* e.g. Filter.or(Filter('name', '==', 'Ada'), Filter('name', '==', 'Bob'))
|
|
80
|
+
*/
|
|
81
|
+
or(...queries: QueryFilterConstraint[]): QueryCompositeFilterConstraint;
|
|
82
|
+
/**
|
|
83
|
+
* The Filter.and() static function used to generate a logical AND query using multiple Filter instances.
|
|
84
|
+
* e.g. Filter.and(Filter('name', '==', 'Ada'), Filter('name', '==', 'Bob'))
|
|
85
|
+
*/
|
|
86
|
+
and(...queries: QueryFilterConstraint[]): QueryCompositeFilterConstraint;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* The Filter function used to generate an instance of Filter.
|
|
90
|
+
* e.g. Filter('name', '==', 'Ada')
|
|
91
|
+
*/
|
|
92
|
+
export const Filter: FilterFunction;
|
|
52
93
|
|
|
53
94
|
/**
|
|
54
95
|
* An immutable object representing an array of bytes.
|
|
@@ -1354,6 +1395,24 @@ export namespace FirebaseFirestoreTypes {
|
|
|
1354
1395
|
* @param value The comparison value.
|
|
1355
1396
|
*/
|
|
1356
1397
|
where(fieldPath: keyof T | FieldPath, opStr: WhereFilterOp, value: any): Query<T>;
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* Creates and returns a new Query with the additional filter that documents must contain the specified field and
|
|
1401
|
+
* the value should satisfy the relation constraint provided.
|
|
1402
|
+
*
|
|
1403
|
+
* #### Example
|
|
1404
|
+
*
|
|
1405
|
+
* ```js
|
|
1406
|
+
* // Get all users who's age is 30 or above
|
|
1407
|
+
* const querySnapshot = await firebase.firestore()
|
|
1408
|
+
* .collection('users')
|
|
1409
|
+
* .where(Filter('age', '>=', 30));
|
|
1410
|
+
* .get();
|
|
1411
|
+
* ```
|
|
1412
|
+
*
|
|
1413
|
+
* @param filter The filter to apply to the query.
|
|
1414
|
+
*/
|
|
1415
|
+
where(filter: QueryFilterConstraint | QueryCompositeFilterConstraint): Query<T>;
|
|
1357
1416
|
}
|
|
1358
1417
|
|
|
1359
1418
|
/**
|
|
@@ -2006,6 +2065,11 @@ export namespace FirebaseFirestoreTypes {
|
|
|
2006
2065
|
*/
|
|
2007
2066
|
Timestamp: typeof Timestamp;
|
|
2008
2067
|
|
|
2068
|
+
/**
|
|
2069
|
+
* Returns the `Filter` function.
|
|
2070
|
+
*/
|
|
2071
|
+
Filter: typeof Filter;
|
|
2072
|
+
|
|
2009
2073
|
/**
|
|
2010
2074
|
* Used to set the cache size to unlimited when passing to `cacheSizeBytes` in
|
|
2011
2075
|
* `firebase.firestore().settings()`.
|
|
@@ -2276,6 +2340,8 @@ export const firebase: ReactNativeFirebase.Module & {
|
|
|
2276
2340
|
): ReactNativeFirebase.FirebaseApp & { firestore(): FirebaseFirestoreTypes.Module };
|
|
2277
2341
|
};
|
|
2278
2342
|
|
|
2343
|
+
export const Filter: FilterFunction;
|
|
2344
|
+
|
|
2279
2345
|
export default defaultExport;
|
|
2280
2346
|
|
|
2281
2347
|
/**
|
package/lib/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Generated by genversion.
|
|
2
|
-
module.exports = '
|
|
2
|
+
module.exports = '18.0.0';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-native-firebase/firestore",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "18.0.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": "
|
|
30
|
+
"@react-native-firebase/app": "18.0.0"
|
|
31
31
|
},
|
|
32
32
|
"publishConfig": {
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "db49dfeab62fa0c52530ccf2bfdfe9e27947bdbd"
|
|
36
36
|
}
|