@@ -1428,87 +1428,35 @@ export class Query implements firestore.Query {
1428
1428
validateStringEnum ( 'Query.where' , whereFilterOpEnums , 2 , opStr ) ;
1429
1429
}
1430
1430
1431
- let fieldValue ;
1431
+ let fieldValue : FieldValue ;
1432
1432
const fieldPath = fieldPathFromArgument ( 'Query.where' , field ) ;
1433
1433
const operator = Operator . fromString ( opStr ) ;
1434
1434
if ( fieldPath . isKeyField ( ) ) {
1435
1435
if (
1436
1436
operator === Operator . ARRAY_CONTAINS ||
1437
- operator === Operator . ARRAY_CONTAINS_ANY ||
1438
- operator === Operator . IN
1437
+ operator === Operator . ARRAY_CONTAINS_ANY
1439
1438
) {
1440
1439
throw new FirestoreError (
1441
1440
Code . INVALID_ARGUMENT ,
1442
1441
`Invalid Query. You can't perform '${ operator . toString ( ) } ' ` +
1443
1442
'queries on FieldPath.documentId().'
1444
1443
) ;
1445
- }
1446
- if ( typeof value === 'string' ) {
1447
- if ( value === '' ) {
1448
- throw new FirestoreError (
1449
- Code . INVALID_ARGUMENT ,
1450
- 'Function Query.where() requires its third parameter to be a ' +
1451
- 'valid document ID if the first parameter is ' +
1452
- 'FieldPath.documentId(), but it was an empty string.'
1453
- ) ;
1444
+ } else if ( operator === Operator . IN ) {
1445
+ this . validateDisjunctiveFilterElements ( value , operator ) ;
1446
+ const referenceList : FieldValue [ ] = [ ] ;
1447
+ for ( const arrayValue of value as FieldValue [ ] ) {
1448
+ referenceList . push ( this . parseDocumentIdValue ( arrayValue ) ) ;
1454
1449
}
1455
- if (
1456
- ! this . _query . isCollectionGroupQuery ( ) &&
1457
- value . indexOf ( '/' ) !== - 1
1458
- ) {
1459
- throw new FirestoreError (
1460
- Code . INVALID_ARGUMENT ,
1461
- `Invalid third parameter to Query.where(). When querying a collection by ` +
1462
- `FieldPath.documentId(), the value provided must be a plain document ID, but ` +
1463
- `'${ value } ' contains a slash.`
1464
- ) ;
1465
- }
1466
- const path = this . _query . path . child ( ResourcePath . fromString ( value ) ) ;
1467
- if ( ! DocumentKey . isDocumentKey ( path ) ) {
1468
- throw new FirestoreError (
1469
- Code . INVALID_ARGUMENT ,
1470
- `Invalid third parameter to Query.where(). When querying a collection group by ` +
1471
- `FieldPath.documentId(), the value provided must result in a valid document path, ` +
1472
- `but '${ path } ' is not because it has an odd number of segments (${
1473
- path . length
1474
- } ).`
1475
- ) ;
1476
- }
1477
- fieldValue = new RefValue (
1478
- this . firestore . _databaseId ,
1479
- new DocumentKey ( path )
1480
- ) ;
1481
- } else if ( value instanceof DocumentReference ) {
1482
- const ref = value as DocumentReference ;
1483
- fieldValue = new RefValue ( this . firestore . _databaseId , ref . _key ) ;
1450
+ fieldValue = new ArrayValue ( referenceList ) ;
1484
1451
} else {
1485
- throw new FirestoreError (
1486
- Code . INVALID_ARGUMENT ,
1487
- `Function Query.where() requires its third parameter to be a ` +
1488
- `string or a DocumentReference if the first parameter is ` +
1489
- `FieldPath.documentId(), but it was: ` +
1490
- `${ valueDescription ( value ) } .`
1491
- ) ;
1452
+ fieldValue = this . parseDocumentIdValue ( value ) ;
1492
1453
}
1493
1454
} else {
1494
1455
if (
1495
1456
operator === Operator . IN ||
1496
1457
operator === Operator . ARRAY_CONTAINS_ANY
1497
1458
) {
1498
- if ( ! Array . isArray ( value ) || value . length === 0 ) {
1499
- throw new FirestoreError (
1500
- Code . INVALID_ARGUMENT ,
1501
- 'Invalid Query. A non-empty array is required for ' +
1502
- `'${ operator . toString ( ) } ' filters.`
1503
- ) ;
1504
- }
1505
- if ( value . length > 10 ) {
1506
- throw new FirestoreError (
1507
- Code . INVALID_ARGUMENT ,
1508
- `Invalid Query. '${ operator . toString ( ) } ' filters support a ` +
1509
- 'maximum of 10 elements in the value array.'
1510
- ) ;
1511
- }
1459
+ this . validateDisjunctiveFilterElements ( value , operator ) ;
1512
1460
}
1513
1461
fieldValue = this . firestore . _dataConverter . parseQueryValue (
1514
1462
'Query.where' ,
@@ -1946,6 +1894,98 @@ export class Query implements firestore.Query {
1946
1894
) ;
1947
1895
}
1948
1896
1897
+ /**
1898
+ * Parses the given documentIdValue into a ReferenceValue, throwing
1899
+ * appropriate errors if the value is anything other than a DocumentReference
1900
+ * or String, or if the string is malformed.
1901
+ */
1902
+ private parseDocumentIdValue ( documentIdValue : unknown ) : RefValue {
1903
+ if ( typeof documentIdValue === 'string' ) {
1904
+ if ( documentIdValue === '' ) {
1905
+ throw new FirestoreError (
1906
+ Code . INVALID_ARGUMENT ,
1907
+ 'Function Query.where() requires its third parameter to be a ' +
1908
+ 'valid document ID if the first parameter is ' +
1909
+ 'FieldPath.documentId(), but it was an empty string.'
1910
+ ) ;
1911
+ }
1912
+ if (
1913
+ ! this . _query . isCollectionGroupQuery ( ) &&
1914
+ documentIdValue . indexOf ( '/' ) !== - 1
1915
+ ) {
1916
+ throw new FirestoreError (
1917
+ Code . INVALID_ARGUMENT ,
1918
+ `Invalid third parameter to Query.where(). When querying a collection by ` +
1919
+ `FieldPath.documentId(), the value provided must be a plain document ID, but ` +
1920
+ `'${ documentIdValue } ' contains a slash.`
1921
+ ) ;
1922
+ }
1923
+ const path = this . _query . path . child (
1924
+ ResourcePath . fromString ( documentIdValue )
1925
+ ) ;
1926
+ if ( ! DocumentKey . isDocumentKey ( path ) ) {
1927
+ throw new FirestoreError (
1928
+ Code . INVALID_ARGUMENT ,
1929
+ `Invalid third parameter to Query.where(). When querying a collection group by ` +
1930
+ `FieldPath.documentId(), the value provided must result in a valid document path, ` +
1931
+ `but '${ path } ' is not because it has an odd number of segments (${
1932
+ path . length
1933
+ } ).`
1934
+ ) ;
1935
+ }
1936
+ return new RefValue ( this . firestore . _databaseId , new DocumentKey ( path ) ) ;
1937
+ } else if ( documentIdValue instanceof DocumentReference ) {
1938
+ const ref = documentIdValue as DocumentReference ;
1939
+ return new RefValue ( this . firestore . _databaseId , ref . _key ) ;
1940
+ } else {
1941
+ throw new FirestoreError (
1942
+ Code . INVALID_ARGUMENT ,
1943
+ `Function Query.where() requires its third parameter to be a ` +
1944
+ `string or a DocumentReference if the first parameter is ` +
1945
+ `FieldPath.documentId(), but it was: ` +
1946
+ `${ valueDescription ( documentIdValue ) } .`
1947
+ ) ;
1948
+ }
1949
+ }
1950
+
1951
+ /**
1952
+ * Validates that the value passed into a disjunctrive filter satisfies all
1953
+ * array requirements.
1954
+ */
1955
+ private validateDisjunctiveFilterElements (
1956
+ value : unknown ,
1957
+ operator : Operator
1958
+ ) : void {
1959
+ if ( ! Array . isArray ( value ) || value . length === 0 ) {
1960
+ throw new FirestoreError (
1961
+ Code . INVALID_ARGUMENT ,
1962
+ 'Invalid Query. A non-empty array is required for ' +
1963
+ `'${ operator . toString ( ) } ' filters.`
1964
+ ) ;
1965
+ }
1966
+ if ( value . length > 10 ) {
1967
+ throw new FirestoreError (
1968
+ Code . INVALID_ARGUMENT ,
1969
+ `Invalid Query. '${ operator . toString ( ) } ' filters support a ` +
1970
+ 'maximum of 10 elements in the value array.'
1971
+ ) ;
1972
+ }
1973
+ if ( value . indexOf ( null ) >= 0 ) {
1974
+ throw new FirestoreError (
1975
+ Code . INVALID_ARGUMENT ,
1976
+ `Invalid Query. '${ operator . toString ( ) } ' filters cannot contain 'null' ` +
1977
+ 'in the value array.'
1978
+ ) ;
1979
+ }
1980
+ if ( value . filter ( element => Number . isNaN ( element ) ) . length > 0 ) {
1981
+ throw new FirestoreError (
1982
+ Code . INVALID_ARGUMENT ,
1983
+ `Invalid Query. '${ operator . toString ( ) } ' filters cannot contain 'NaN' ` +
1984
+ 'in the value array.'
1985
+ ) ;
1986
+ }
1987
+ }
1988
+
1949
1989
private validateNewFilter ( filter : Filter ) : void {
1950
1990
if ( filter instanceof FieldFilter ) {
1951
1991
const arrayOps = [ Operator . ARRAY_CONTAINS , Operator . ARRAY_CONTAINS_ANY ] ;
0 commit comments