mirror of
https://github.com/zhigang1992/react-native-firebase.git
synced 2026-01-12 22:50:20 +08:00
feat(firestore): support limitToLast query filter (#3702)
Co-authored-by: Mike Diarmid <mike.diarmid@gmail.com>
This commit is contained in:
3132
docs/typedoc.json
vendored
3132
docs/typedoc.json
vendored
File diff suppressed because it is too large
Load Diff
2
docs/typedoc.min.json
vendored
2
docs/typedoc.min.json
vendored
File diff suppressed because one or more lines are too long
@@ -118,6 +118,11 @@ public class ReactNativeFirebaseFirestoreQuery {
|
||||
query = query.limit(limit);
|
||||
}
|
||||
|
||||
if (options.hasKey("limitToLast")) {
|
||||
int limitToLast = options.getInt("limitToLast");
|
||||
query = query.limitToLast(limitToLast);
|
||||
}
|
||||
|
||||
if (options.hasKey("startAt")) {
|
||||
List<Object> fieldList = parseReadableArray(query.getFirestore(), options.getArray("startAt"));
|
||||
query = query.startAt(Objects.requireNonNull(fieldList.toArray()));
|
||||
|
||||
106
packages/firestore/e2e/Query/limitToLast.e2e.js
Normal file
106
packages/firestore/e2e/Query/limitToLast.e2e.js
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2016-present Invertase Limited & Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this library except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
const { wipe } = require('../helpers');
|
||||
|
||||
describe('firestore().collection().limitToLast()', () => {
|
||||
before(() => wipe());
|
||||
|
||||
it('throws if limitToLast is invalid', () => {
|
||||
try {
|
||||
firebase
|
||||
.firestore()
|
||||
.collection('v6')
|
||||
.limitToLast(-1);
|
||||
return Promise.reject(new Error('Did not throw an Error.'));
|
||||
} catch (error) {
|
||||
error.message.should.containEql("'limitToLast' must be a positive integer value");
|
||||
return Promise.resolve();
|
||||
}
|
||||
});
|
||||
|
||||
it('sets limitToLast on internals', async () => {
|
||||
const colRef = firebase
|
||||
.firestore()
|
||||
.collection('v6')
|
||||
.limitToLast(123);
|
||||
|
||||
should(colRef._modifiers.options.limitToLast).equal(123);
|
||||
});
|
||||
|
||||
it('removes limit query if limitToLast is set afterwards', () => {
|
||||
const colRef = firebase
|
||||
.firestore()
|
||||
.collection('v6')
|
||||
.limit(2)
|
||||
.limitToLast(123);
|
||||
|
||||
should(colRef._modifiers.options.limit).equal(undefined);
|
||||
});
|
||||
|
||||
it('removes limitToLast query if limit is set afterwards', () => {
|
||||
const colRef = firebase
|
||||
.firestore()
|
||||
.collection('v6')
|
||||
.limitToLast(123)
|
||||
.limit(2);
|
||||
|
||||
should(colRef._modifiers.options.limitToLast).equal(undefined);
|
||||
});
|
||||
|
||||
it('limitToLast the number of documents', async () => {
|
||||
const colRef = firebase.firestore().collection('v6');
|
||||
|
||||
// Add 3
|
||||
await colRef.add({ count: 1 });
|
||||
await colRef.add({ count: 2 });
|
||||
await colRef.add({ count: 3 });
|
||||
|
||||
const docs = await firebase
|
||||
.firestore()
|
||||
.collection('v6')
|
||||
.limitToLast(2)
|
||||
.orderBy('count', 'desc')
|
||||
.get();
|
||||
|
||||
const results = [];
|
||||
docs.forEach(doc => {
|
||||
results.push(doc.data());
|
||||
});
|
||||
|
||||
should(results.length).equal(2);
|
||||
|
||||
should(results[0].count).equal(2);
|
||||
should(results[1].count).equal(1);
|
||||
});
|
||||
|
||||
it("throws error if no 'orderBy' is set on the query", () => {
|
||||
try {
|
||||
firebase
|
||||
.firestore()
|
||||
.collection('v6')
|
||||
.limitToLast(3)
|
||||
.get();
|
||||
return Promise.reject(new Error('Did not throw an Error.'));
|
||||
} catch (error) {
|
||||
error.message.should.containEql(
|
||||
'limitToLast() queries require specifying at least one firebase.firestore().collection().orderBy() clause',
|
||||
);
|
||||
return Promise.resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -90,6 +90,10 @@
|
||||
if (_options[@"limit"]) {
|
||||
_query = [_query queryLimitedTo:[_options[@"limit"] intValue]];
|
||||
}
|
||||
|
||||
if (_options[@"limitToLast"]) {
|
||||
_query = [_query queryLimitedToLast:[_options[@"limitToLast"] intValue]];
|
||||
}
|
||||
|
||||
if (_options[@"startAt"]) {
|
||||
NSArray *fieldList = [RNFBFirestoreSerialize parseNSArray:_firestore array:_options[@"startAt"]];
|
||||
|
||||
@@ -164,6 +164,8 @@ export default class FirestoreQuery {
|
||||
);
|
||||
}
|
||||
|
||||
this._modifiers.validatelimitToLast();
|
||||
|
||||
return this._firestore.native
|
||||
.collectionGet(
|
||||
this._collectionPath.relativeName,
|
||||
@@ -220,12 +222,26 @@ export default class FirestoreQuery {
|
||||
return new FirestoreQuery(this._firestore, this._collectionPath, modifiers);
|
||||
}
|
||||
|
||||
limitToLast(limitToLast) {
|
||||
if (this._modifiers.isValidLimitToLast(limitToLast)) {
|
||||
throw new Error(
|
||||
"firebase.firestore().collection().limitToLast(*) 'limitToLast' must be a positive integer value.",
|
||||
);
|
||||
}
|
||||
|
||||
const modifiers = this._modifiers._copy().limitToLast(limitToLast);
|
||||
|
||||
return new FirestoreQuery(this._firestore, this._collectionPath, modifiers);
|
||||
}
|
||||
|
||||
onSnapshot(...args) {
|
||||
let snapshotListenOptions;
|
||||
let callback;
|
||||
let onNext;
|
||||
let onError;
|
||||
|
||||
this._modifiers.validatelimitToLast();
|
||||
|
||||
try {
|
||||
const options = parseSnapshotArgs(args);
|
||||
snapshotListenOptions = options.snapshotListenOptions;
|
||||
@@ -405,8 +421,6 @@ export default class FirestoreQuery {
|
||||
throw new Error(`firebase.firestore().collection().where() ${e.message}`);
|
||||
}
|
||||
|
||||
modifiers.validateWhere();
|
||||
|
||||
return new FirestoreQuery(this._firestore, this._collectionPath, modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ const DIRECTIONS = {
|
||||
export default class FirestoreQueryModifiers {
|
||||
constructor() {
|
||||
this._limit = undefined;
|
||||
this._limitToLast = undefined;
|
||||
this._filters = [];
|
||||
this._orders = [];
|
||||
this._type = 'collection';
|
||||
@@ -58,6 +59,7 @@ export default class FirestoreQueryModifiers {
|
||||
_copy() {
|
||||
const newInstance = new FirestoreQueryModifiers();
|
||||
newInstance._limit = this._limit;
|
||||
newInstance._limitToLast = this._limitToLast;
|
||||
newInstance._filters = [...this._filters];
|
||||
newInstance._orders = [...this._orders];
|
||||
newInstance._type = this._type;
|
||||
@@ -82,6 +84,11 @@ export default class FirestoreQueryModifiers {
|
||||
if (this._limit) {
|
||||
options.limit = this._limit;
|
||||
}
|
||||
|
||||
if (this._limitToLast) {
|
||||
options.limitToLast = this._limitToLast;
|
||||
}
|
||||
|
||||
if (this._startAt) {
|
||||
options.startAt = this._startAt;
|
||||
}
|
||||
@@ -141,10 +148,35 @@ export default class FirestoreQueryModifiers {
|
||||
}
|
||||
|
||||
limit(limit) {
|
||||
this._limitToLast = undefined;
|
||||
this._limit = limit;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* limitToLast
|
||||
*/
|
||||
|
||||
isValidLimitToLast(limit) {
|
||||
return !isNumber(limit) || Math.floor(limit) !== limit || limit <= 0;
|
||||
}
|
||||
|
||||
validatelimitToLast() {
|
||||
if (this._limitToLast) {
|
||||
if (!this._orders.length) {
|
||||
throw new Error(
|
||||
'firebase.firestore().collection().limitToLast() queries require specifying at least one firebase.firestore().collection().orderBy() clause',
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
limitToLast(limitToLast) {
|
||||
this._limit = undefined;
|
||||
this._limitToLast = limitToLast;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters
|
||||
*/
|
||||
|
||||
19
packages/firestore/lib/index.d.ts
vendored
19
packages/firestore/lib/index.d.ts
vendored
@@ -971,6 +971,25 @@ export namespace FirebaseFirestoreTypes {
|
||||
* @param limit The maximum number of items to return.
|
||||
*/
|
||||
limit(limit: number): Query;
|
||||
/**
|
||||
* Creates and returns a new Query where the results are limited to the specified number of documents
|
||||
* starting from the last document. The order is dependent on the second parameter for the `orderBy`
|
||||
* method. If `desc` is used, the order is reversed. `orderBy` method call is required when calling `limitToLast`.
|
||||
*
|
||||
* #### Example
|
||||
*
|
||||
* ```js
|
||||
* // Get the last 10 users in reverse order of age
|
||||
* const querySnapshot = firebase.firestore()
|
||||
* .collection('users')
|
||||
* .orderBy('age', 'desc')
|
||||
* .limitToLast(10)
|
||||
* .get();
|
||||
* ```
|
||||
*
|
||||
* @param limitToLast The maximum number of items to return.
|
||||
*/
|
||||
limitToLast(limitToLast: number): Query;
|
||||
|
||||
/**
|
||||
* Attaches a listener for `QuerySnapshot` events.
|
||||
|
||||
Reference in New Issue
Block a user