Skip to content
This repository was archived by the owner on Mar 4, 2026. It is now read-only.

Commit a620ada

Browse files
Accept strings in where(FieldPath.documentId(), ...) (#136)
1 parent 59f738a commit a620ada

3 files changed

Lines changed: 85 additions & 30 deletions

File tree

src/reference.js

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,12 +1126,16 @@ class Query {
11261126
);
11271127
}
11281128

1129-
let newFilter = new FieldFilter(
1130-
FieldPath.fromArgument(fieldPath),
1131-
comparisonOperators[opStr],
1132-
value
1129+
fieldPath = FieldPath.fromArgument(fieldPath);
1130+
1131+
if (fieldPath === FieldPath._DOCUMENT_ID) {
1132+
value = this._convertReference(value);
1133+
}
1134+
1135+
let combinedFilters = this._fieldFilters.concat(
1136+
new FieldFilter(fieldPath, comparisonOperators[opStr], value)
11331137
);
1134-
let combinedFilters = this._fieldFilters.concat(newFilter);
1138+
11351139
return new Query(
11361140
this._firestore,
11371141
this._referencePath,
@@ -1395,31 +1399,7 @@ class Query {
13951399
let fieldValue = fieldValues[i];
13961400

13971401
if (fieldOrders[i].field === FieldPath._DOCUMENT_ID) {
1398-
if (is.string(fieldValue)) {
1399-
fieldValue = new DocumentReference(
1400-
this._firestore,
1401-
this._referencePath.append(fieldValue)
1402-
);
1403-
} else if (is.instance(fieldValue, DocumentReference)) {
1404-
if (!this._referencePath.isPrefixOf(fieldValue.ref)) {
1405-
throw new Error(
1406-
`'${fieldValue.path}' is not part of the query ` +
1407-
'result set and cannot be used as a query boundary.'
1408-
);
1409-
}
1410-
} else {
1411-
throw new Error(
1412-
'The corresponding value for FieldPath.documentId() must be a ' +
1413-
'string or a DocumentReference.'
1414-
);
1415-
}
1416-
1417-
if (fieldValue.ref.parent().compareTo(this._referencePath) !== 0) {
1418-
throw new Error(
1419-
'Only a direct child can be used as a query boundary. ' +
1420-
`Found: '${fieldValue.path}'.`
1421-
);
1422-
}
1402+
fieldValue = this._convertReference(fieldValue);
14231403
}
14241404

14251405
if (DocumentTransform.isTransformSentinel(fieldValue)) {
@@ -1435,6 +1415,47 @@ class Query {
14351415
return options;
14361416
}
14371417

1418+
/**
1419+
* Validates that a value used with FieldValue.documentId() is either a
1420+
* string or a DocumentReference that is part of the query`s result set.
1421+
* Throws a validation error or returns a DocumentReference that can
1422+
* directly be used in the Query.
1423+
*
1424+
* @param {*} reference - The value to validate.
1425+
* @throws If the value cannot be used for this query.
1426+
* @return {DocumentReference} If valid, returns a DocumentReference that
1427+
* can be used with the query.
1428+
* @private
1429+
*/
1430+
_convertReference(reference) {
1431+
if (is.string(reference)) {
1432+
reference = new DocumentReference(
1433+
this._firestore,
1434+
this._referencePath.append(reference)
1435+
);
1436+
} else if (is.instance(reference, DocumentReference)) {
1437+
if (!this._referencePath.isPrefixOf(reference.ref)) {
1438+
throw new Error(
1439+
`'${reference.path}' is not part of the query result set and ` +
1440+
'cannot be used as a query boundary.'
1441+
);
1442+
}
1443+
} else {
1444+
throw new Error(
1445+
'The corresponding value for FieldPath.documentId() must be a ' +
1446+
'string or a DocumentReference.'
1447+
);
1448+
}
1449+
1450+
if (reference.ref.parent().compareTo(this._referencePath) !== 0) {
1451+
throw new Error(
1452+
'Only a direct child can be used as a query boundary. ' +
1453+
`Found: '${reference.path}'.`
1454+
);
1455+
}
1456+
return reference;
1457+
}
1458+
14381459
/**
14391460
* Creates and returns a new [Query]{@link Query} that starts at the provided
14401461
* set of field values relative to the order of the query. The order of the

system-test/firestore.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,21 @@ describe('Query class', function() {
854854
});
855855
});
856856

857+
it('can query by FieldPath.documentId()', function() {
858+
let ref = randomCol.doc('foo');
859+
860+
return ref
861+
.set({})
862+
.then(() => {
863+
return randomCol
864+
.where(Firestore.FieldPath.documentId(), '>=', 'bar')
865+
.get();
866+
})
867+
.then(res => {
868+
assert.equal(res.docs.length, 1);
869+
});
870+
});
871+
857872
it('has orderBy() method', function() {
858873
let ref1 = randomCol.doc('doc1');
859874
let ref2 = randomCol.doc('doc2');

test/query.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,25 @@ describe('where() interface', function() {
591591
return query.get();
592592
});
593593

594+
it('supports strings for FieldPath.documentId()', function() {
595+
firestore.api.Firestore._runQuery = function(request) {
596+
requestEquals(
597+
request,
598+
fieldFilters('__name__', 'EQUAL', {
599+
valueType: 'referenceValue',
600+
referenceValue:
601+
'projects/test-project/databases/(default)/' +
602+
'documents/collectionId/foo',
603+
})
604+
);
605+
return stream();
606+
};
607+
608+
let query = firestore.collection('collectionId');
609+
query = query.where(Firestore.FieldPath.documentId(), '==', 'foo');
610+
return query.get();
611+
});
612+
594613
it('supports unary filters', function() {
595614
firestore.api.Firestore._runQuery = function(request) {
596615
requestEquals(request, unaryFilters('foo', 'IS_NAN', 'bar', 'IS_NULL'));

0 commit comments

Comments
 (0)