|
| 1 | +/*! |
| 2 | + * Copyright 2023 Google LLC. All Rights Reserved. |
| 3 | + * |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + * you may not use this file except in compliance with the License. |
| 6 | + * You may obtain a copy of the License at |
| 7 | + * |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + * |
| 10 | + * Unless required by applicable law or agreed to in writing, software |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + * See the License for the specific language governing permissions and |
| 14 | + * limitations under the License. |
| 15 | + */ |
| 16 | + |
| 17 | +import * as firestore from '@google-cloud/firestore'; |
| 18 | + |
| 19 | +/** |
| 20 | + * A `Filter` represents a restriction on one or more field values and can |
| 21 | + * be used to refine the results of a {@link Query}. |
| 22 | + * `Filters`s are created by invoking {@link Filter#where}, {@link Filter#or}, |
| 23 | + * or {@link Filter#and} and can then be passed to {@link Query#where} |
| 24 | + * to create a new {@link Query} instance that also contains this `Filter`. |
| 25 | + */ |
| 26 | +export abstract class Filter { |
| 27 | + /** |
| 28 | + * Creates and returns a new [Filter]{@link Filter}, which can be |
| 29 | + * applied to [Query.where()]{@link Query#where}, [Filter.or()]{@link Filter#or}, |
| 30 | + * or [Filter.and()]{@link Filter#and}. When applied to a [Query]{@link Query} |
| 31 | + * it requires that documents must contain the specified field and that its value should |
| 32 | + * satisfy the relation constraint provided. |
| 33 | + * |
| 34 | + * @param {string|FieldPath} fieldPath The name of a property value to compare. |
| 35 | + * @param {string} opStr A comparison operation in the form of a string. |
| 36 | + * Acceptable operator strings are "<", "<=", "==", "!=", ">=", ">", "array-contains", |
| 37 | + * "in", "not-in", and "array-contains-any". |
| 38 | + * @param {*} value The value to which to compare the field for inclusion in |
| 39 | + * a query. |
| 40 | + * @returns {Filter} The created Filter. |
| 41 | + * |
| 42 | + * @example |
| 43 | + * ``` |
| 44 | + * let collectionRef = firestore.collection('col'); |
| 45 | + * |
| 46 | + * collectionRef.where(Filter.where('foo', '==', 'bar')).get().then(querySnapshot => { |
| 47 | + * querySnapshot.forEach(documentSnapshot => { |
| 48 | + * console.log(`Found document at ${documentSnapshot.ref.path}`); |
| 49 | + * }); |
| 50 | + * }); |
| 51 | + * ``` |
| 52 | + */ |
| 53 | + public static where( |
| 54 | + fieldPath: string | firestore.FieldPath, |
| 55 | + opStr: firestore.WhereFilterOp, |
| 56 | + value: unknown |
| 57 | + ): Filter { |
| 58 | + return new UnaryFilter(fieldPath, opStr, value); |
| 59 | + } |
| 60 | + |
| 61 | + /** |
| 62 | + * Creates and returns a new [Filter]{@link Filter} that is a |
| 63 | + * disjunction of the given {@link Filter}s. A disjunction filter includes |
| 64 | + * a document if it satisfies any of the given {@link Filter}s. |
| 65 | + * |
| 66 | + * The returned Filter can be applied to [Query.where()]{@link Query#where}, |
| 67 | + * [Filter.or()]{@link Filter#or}, or [Filter.and()]{@link Filter#and}. When |
| 68 | + * applied to a [Query]{@link Query} it requires that documents must satisfy |
| 69 | + * one of the provided {@link Filter}s. |
| 70 | + * |
| 71 | + * @param {...Filter} filters Optional. The {@link Filter}s |
| 72 | + * for OR operation. These must be created with calls to {@link Filter#where}, |
| 73 | + * {@link Filter#or}, or {@link Filter#and}. |
| 74 | + * @returns {Filter} The created {@link Filter}. |
| 75 | + * |
| 76 | + * @example |
| 77 | + * ``` |
| 78 | + * let collectionRef = firestore.collection('col'); |
| 79 | + * |
| 80 | + * // doc.foo == 'bar' || doc.baz > 0 |
| 81 | + * let orFilter = Filter.or(Filter.where('foo', '==', 'bar'), Filter.where('baz', '>', 0)); |
| 82 | + * |
| 83 | + * collectionRef.where(orFilter).get().then(querySnapshot => { |
| 84 | + * querySnapshot.forEach(documentSnapshot => { |
| 85 | + * console.log(`Found document at ${documentSnapshot.ref.path}`); |
| 86 | + * }); |
| 87 | + * }); |
| 88 | + * ``` |
| 89 | + */ |
| 90 | + public static or(...filters: Filter[]): Filter { |
| 91 | + return new CompositeFilter(filters, 'OR'); |
| 92 | + } |
| 93 | + |
| 94 | + /** |
| 95 | + * Creates and returns a new [Filter]{@link Filter} that is a |
| 96 | + * conjunction of the given {@link Filter}s. A conjunction filter includes |
| 97 | + * a document if it satisfies any of the given {@link Filter}s. |
| 98 | + * |
| 99 | + * The returned Filter can be applied to [Query.where()]{@link Query#where}, |
| 100 | + * [Filter.or()]{@link Filter#or}, or [Filter.and()]{@link Filter#and}. When |
| 101 | + * applied to a [Query]{@link Query} it requires that documents must satisfy |
| 102 | + * one of the provided {@link Filter}s. |
| 103 | + * |
| 104 | + * @param {...Filter} filters Optional. The {@link Filter}s |
| 105 | + * for AND operation. These must be created with calls to {@link Filter#where}, |
| 106 | + * {@link Filter#or}, or {@link Filter#and}. |
| 107 | + * @returns {Filter} The created {@link Filter}. |
| 108 | + * |
| 109 | + * @example |
| 110 | + * ``` |
| 111 | + * let collectionRef = firestore.collection('col'); |
| 112 | + * |
| 113 | + * // doc.foo == 'bar' && doc.baz > 0 |
| 114 | + * let andFilter = Filter.and(Filter.where('foo', '==', 'bar'), Filter.where('baz', '>', 0)); |
| 115 | + * |
| 116 | + * collectionRef.where(andFilter).get().then(querySnapshot => { |
| 117 | + * querySnapshot.forEach(documentSnapshot => { |
| 118 | + * console.log(`Found document at ${documentSnapshot.ref.path}`); |
| 119 | + * }); |
| 120 | + * }); |
| 121 | + * ``` |
| 122 | + */ |
| 123 | + public static and(...filters: Filter[]): Filter { |
| 124 | + return new CompositeFilter(filters, 'AND'); |
| 125 | + } |
| 126 | +} |
| 127 | + |
| 128 | +/** |
| 129 | + * A `UnaryFilter` represents a restriction on one field value and can |
| 130 | + * be used to refine the results of a {@link Query}. |
| 131 | + * `UnaryFilter`s are created by invoking {@link Filter#where} and can then |
| 132 | + * be passed to {@link Query#where} to create a new {@link Query} instance |
| 133 | + * that also contains this `UnaryFilter`. |
| 134 | + * |
| 135 | + * @private |
| 136 | + * @internal |
| 137 | + */ |
| 138 | +export class UnaryFilter extends Filter { |
| 139 | + /** |
| 140 | + @private |
| 141 | + @internal |
| 142 | + */ |
| 143 | + public constructor( |
| 144 | + private field: string | firestore.FieldPath, |
| 145 | + private operator: firestore.WhereFilterOp, |
| 146 | + private value: unknown |
| 147 | + ) { |
| 148 | + super(); |
| 149 | + } |
| 150 | + |
| 151 | + /** |
| 152 | + @private |
| 153 | + @internal |
| 154 | + */ |
| 155 | + public _getField(): string | firestore.FieldPath { |
| 156 | + return this.field; |
| 157 | + } |
| 158 | + |
| 159 | + /** |
| 160 | + @private |
| 161 | + @internal |
| 162 | + */ |
| 163 | + public _getOperator(): firestore.WhereFilterOp { |
| 164 | + return this.operator; |
| 165 | + } |
| 166 | + |
| 167 | + /** |
| 168 | + @private |
| 169 | + @internal |
| 170 | + */ |
| 171 | + public _getValue(): unknown { |
| 172 | + return this.value; |
| 173 | + } |
| 174 | +} |
| 175 | + |
| 176 | +/** |
| 177 | + * A `CompositeFilter` is used to narrow the set of documents returned |
| 178 | + * by a Firestore query by performing the logical OR or AND of multiple |
| 179 | + * {@link Filters}s. `CompositeFilters`s are created by invoking {@link Filter#or} |
| 180 | + * or {@link Filter#and} and can then be passed to {@link Query#where} |
| 181 | + * to create a new query instance that also contains the `CompositeFilter`. |
| 182 | + * |
| 183 | + * @private |
| 184 | + * @internal |
| 185 | + */ |
| 186 | +export class CompositeFilter extends Filter { |
| 187 | + /** |
| 188 | + @private |
| 189 | + @internal |
| 190 | + */ |
| 191 | + public constructor( |
| 192 | + private filters: Filter[], |
| 193 | + private operator: CompositeOperator |
| 194 | + ) { |
| 195 | + super(); |
| 196 | + } |
| 197 | + |
| 198 | + /** |
| 199 | + @private |
| 200 | + @internal |
| 201 | + */ |
| 202 | + public _getFilters(): Filter[] { |
| 203 | + return this.filters; |
| 204 | + } |
| 205 | + |
| 206 | + /** |
| 207 | + @private |
| 208 | + @internal |
| 209 | + */ |
| 210 | + public _getOperator(): CompositeOperator { |
| 211 | + return this.operator; |
| 212 | + } |
| 213 | +} |
| 214 | + |
| 215 | +/** |
| 216 | + * Composition operator of a `CompositeFilter`. This operator specifies the |
| 217 | + * behavior of the `CompositeFilter`. |
| 218 | + * |
| 219 | + * @private |
| 220 | + * @internal |
| 221 | + */ |
| 222 | +export type CompositeOperator = 'AND' | 'OR'; |
0 commit comments