Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/google/cloud/firestore_v1/pipeline_expressions.py: 53%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

470 statements  

1# Copyright 2025 Google LLC 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# http://www.apache.org/licenses/LICENSE-2.0 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14""" 

15.. warning:: 

16 **Preview API**: Firestore Pipelines is currently in preview and is 

17 subject to potential breaking changes in future releases. 

18""" 

19 

20from __future__ import annotations 

21from typing import ( 

22 Any, 

23 Generic, 

24 TypeVar, 

25 Sequence, 

26) 

27from abc import ABC 

28from abc import abstractmethod 

29from enum import Enum 

30import datetime 

31from google.cloud.firestore_v1.types.document import Value 

32from google.cloud.firestore_v1.types.query import StructuredQuery as Query_pb 

33from google.cloud.firestore_v1.vector import Vector 

34from google.cloud.firestore_v1._helpers import GeoPoint 

35from google.cloud.firestore_v1._helpers import encode_value 

36from google.cloud.firestore_v1._helpers import decode_value 

37 

38CONSTANT_TYPE = TypeVar( 

39 "CONSTANT_TYPE", 

40 str, 

41 int, 

42 float, 

43 bool, 

44 datetime.datetime, 

45 bytes, 

46 GeoPoint, 

47 Vector, 

48 None, 

49) 

50 

51 

52class Ordering: 

53 """Represents the direction for sorting results in a pipeline.""" 

54 

55 class Direction(Enum): 

56 ASCENDING = "ascending" 

57 DESCENDING = "descending" 

58 

59 def __init__(self, expr, order_dir: Direction | str = Direction.ASCENDING): 

60 """ 

61 Initializes an Ordering instance 

62 

63 Args: 

64 expr (Expression | str): The expression or field path string to sort by. 

65 If a string is provided, it's treated as a field path. 

66 order_dir (Direction | str): The direction to sort in. 

67 Defaults to ascending 

68 """ 

69 self.expr = expr if isinstance(expr, Expression) else Field.of(expr) 

70 self.order_dir = ( 

71 Ordering.Direction[order_dir.upper()] 

72 if isinstance(order_dir, str) 

73 else order_dir 

74 ) 

75 

76 def __repr__(self): 

77 if self.order_dir is Ordering.Direction.ASCENDING: 

78 order_str = ".ascending()" 

79 else: 

80 order_str = ".descending()" 

81 return f"{self.expr!r}{order_str}" 

82 

83 def _to_pb(self) -> Value: 

84 return Value( 

85 map_value={ 

86 "fields": { 

87 "direction": Value(string_value=self.order_dir.value), 

88 "expression": self.expr._to_pb(), 

89 } 

90 } 

91 ) 

92 

93 

94class Expression(ABC): 

95 """Represents an expression that can be evaluated to a value within the 

96 execution of a pipeline. 

97 

98 Expressionessions are the building blocks for creating complex queries and 

99 transformations in Firestore pipelines. They can represent: 

100 

101 - **Field references:** Access values from document fields. 

102 - **Literals:** Represent constant values (strings, numbers, booleans). 

103 - **FunctionExpression calls:** Apply functions to one or more expressions. 

104 - **Aggregations:** Calculate aggregate values (e.g., sum, average) over a set of documents. 

105 

106 The `Expression` class provides a fluent API for building expressions. You can chain 

107 together method calls to create complex expressions. 

108 """ 

109 

110 def __repr__(self): 

111 return f"{self.__class__.__name__}()" 

112 

113 @abstractmethod 

114 def _to_pb(self) -> Value: 

115 raise NotImplementedError 

116 

117 @staticmethod 

118 def _cast_to_expr_or_convert_to_constant( 

119 o: Any, include_vector=False 

120 ) -> "Expression": 

121 """Convert arbitrary object to an Expression.""" 

122 if isinstance(o, Expression): 

123 return o 

124 if isinstance(o, dict): 

125 return Map(o) 

126 if isinstance(o, list): 

127 if include_vector and all([isinstance(i, (float, int)) for i in o]): 

128 return Constant(Vector(o)) 

129 else: 

130 return Array(o) 

131 return Constant(o) 

132 

133 class expose_as_static: 

134 """ 

135 Decorator to mark instance methods to be exposed as static methods as well as instance 

136 methods. 

137 

138 When called statically, the first argument is converted to a Field expression if needed. 

139 

140 Example: 

141 >>> Field.of("test").add(5) 

142 >>> FunctionExpression.add("test", 5) 

143 """ 

144 

145 def __init__(self, instance_func): 

146 self.instance_func = instance_func 

147 

148 def static_func(self, first_arg, *other_args, **kwargs): 

149 if not isinstance(first_arg, (Expression, str)): 

150 raise TypeError( 

151 f"'{self.instance_func.__name__}' must be called on an Expression or a string representing a field. got {type(first_arg)}." 

152 ) 

153 first_expr = ( 

154 Field.of(first_arg) 

155 if not isinstance(first_arg, Expression) 

156 else first_arg 

157 ) 

158 return self.instance_func(first_expr, *other_args, **kwargs) 

159 

160 def __get__(self, instance, owner): 

161 if instance is None: 

162 return self.static_func 

163 else: 

164 return self.instance_func.__get__(instance, owner) 

165 

166 @expose_as_static 

167 def add(self, other: Expression | float) -> "Expression": 

168 """Creates an expression that adds this expression to another expression or constant. 

169 

170 Example: 

171 >>> # Add the value of the 'quantity' field and the 'reserve' field. 

172 >>> Field.of("quantity").add(Field.of("reserve")) 

173 >>> # Add 5 to the value of the 'age' field 

174 >>> Field.of("age").add(5) 

175 

176 Args: 

177 other: The expression or constant value to add to this expression. 

178 

179 Returns: 

180 A new `Expression` representing the addition operation. 

181 """ 

182 return FunctionExpression( 

183 "add", [self, self._cast_to_expr_or_convert_to_constant(other)] 

184 ) 

185 

186 @expose_as_static 

187 def subtract(self, other: Expression | float) -> "Expression": 

188 """Creates an expression that subtracts another expression or constant from this expression. 

189 

190 Example: 

191 >>> # Subtract the 'discount' field from the 'price' field 

192 >>> Field.of("price").subtract(Field.of("discount")) 

193 >>> # Subtract 20 from the value of the 'total' field 

194 >>> Field.of("total").subtract(20) 

195 

196 Args: 

197 other: The expression or constant value to subtract from this expression. 

198 

199 Returns: 

200 A new `Expression` representing the subtraction operation. 

201 """ 

202 return FunctionExpression( 

203 "subtract", [self, self._cast_to_expr_or_convert_to_constant(other)] 

204 ) 

205 

206 @expose_as_static 

207 def multiply(self, other: Expression | float) -> "Expression": 

208 """Creates an expression that multiplies this expression by another expression or constant. 

209 

210 Example: 

211 >>> # Multiply the 'quantity' field by the 'price' field 

212 >>> Field.of("quantity").multiply(Field.of("price")) 

213 >>> # Multiply the 'value' field by 2 

214 >>> Field.of("value").multiply(2) 

215 

216 Args: 

217 other: The expression or constant value to multiply by. 

218 

219 Returns: 

220 A new `Expression` representing the multiplication operation. 

221 """ 

222 return FunctionExpression( 

223 "multiply", [self, self._cast_to_expr_or_convert_to_constant(other)] 

224 ) 

225 

226 @expose_as_static 

227 def divide(self, other: Expression | float) -> "Expression": 

228 """Creates an expression that divides this expression by another expression or constant. 

229 

230 Example: 

231 >>> # Divide the 'total' field by the 'count' field 

232 >>> Field.of("total").divide(Field.of("count")) 

233 >>> # Divide the 'value' field by 10 

234 >>> Field.of("value").divide(10) 

235 

236 Args: 

237 other: The expression or constant value to divide by. 

238 

239 Returns: 

240 A new `Expression` representing the division operation. 

241 """ 

242 return FunctionExpression( 

243 "divide", [self, self._cast_to_expr_or_convert_to_constant(other)] 

244 ) 

245 

246 @expose_as_static 

247 def mod(self, other: Expression | float) -> "Expression": 

248 """Creates an expression that calculates the modulo (remainder) to another expression or constant. 

249 

250 Example: 

251 >>> # Calculate the remainder of dividing the 'value' field by field 'divisor'. 

252 >>> Field.of("value").mod(Field.of("divisor")) 

253 >>> # Calculate the remainder of dividing the 'value' field by 5. 

254 >>> Field.of("value").mod(5) 

255 

256 Args: 

257 other: The divisor expression or constant. 

258 

259 Returns: 

260 A new `Expression` representing the modulo operation. 

261 """ 

262 return FunctionExpression( 

263 "mod", [self, self._cast_to_expr_or_convert_to_constant(other)] 

264 ) 

265 

266 @expose_as_static 

267 def abs(self) -> "Expression": 

268 """Creates an expression that calculates the absolute value of this expression. 

269 

270 Example: 

271 >>> # Get the absolute value of the 'change' field. 

272 >>> Field.of("change").abs() 

273 

274 Returns: 

275 A new `Expression` representing the absolute value. 

276 """ 

277 return FunctionExpression("abs", [self]) 

278 

279 @expose_as_static 

280 def ceil(self) -> "Expression": 

281 """Creates an expression that calculates the ceiling of this expression. 

282 

283 Example: 

284 >>> # Get the ceiling of the 'value' field. 

285 >>> Field.of("value").ceil() 

286 

287 Returns: 

288 A new `Expression` representing the ceiling value. 

289 """ 

290 return FunctionExpression("ceil", [self]) 

291 

292 @expose_as_static 

293 def exp(self) -> "Expression": 

294 """Creates an expression that computes e to the power of this expression. 

295 

296 Example: 

297 >>> # Compute e to the power of the 'value' field 

298 >>> Field.of("value").exp() 

299 

300 Returns: 

301 A new `Expression` representing the exponential value. 

302 """ 

303 return FunctionExpression("exp", [self]) 

304 

305 @expose_as_static 

306 def floor(self) -> "Expression": 

307 """Creates an expression that calculates the floor of this expression. 

308 

309 Example: 

310 >>> # Get the floor of the 'value' field. 

311 >>> Field.of("value").floor() 

312 

313 Returns: 

314 A new `Expression` representing the floor value. 

315 """ 

316 return FunctionExpression("floor", [self]) 

317 

318 @expose_as_static 

319 def ln(self) -> "Expression": 

320 """Creates an expression that calculates the natural logarithm of this expression. 

321 

322 Example: 

323 >>> # Get the natural logarithm of the 'value' field. 

324 >>> Field.of("value").ln() 

325 

326 Returns: 

327 A new `Expression` representing the natural logarithm. 

328 """ 

329 return FunctionExpression("ln", [self]) 

330 

331 @expose_as_static 

332 def log(self, base: Expression | float) -> "Expression": 

333 """Creates an expression that calculates the logarithm of this expression with a given base. 

334 

335 Example: 

336 >>> # Get the logarithm of 'value' with base 2. 

337 >>> Field.of("value").log(2) 

338 >>> # Get the logarithm of 'value' with base from 'base_field'. 

339 >>> Field.of("value").log(Field.of("base_field")) 

340 

341 Args: 

342 base: The base of the logarithm. 

343 

344 Returns: 

345 A new `Expression` representing the logarithm. 

346 """ 

347 return FunctionExpression( 

348 "log", [self, self._cast_to_expr_or_convert_to_constant(base)] 

349 ) 

350 

351 @expose_as_static 

352 def log10(self) -> "Expression": 

353 """Creates an expression that calculates the base 10 logarithm of this expression. 

354 

355 Example: 

356 >>> Field.of("value").log10() 

357 

358 Returns: 

359 A new `Expression` representing the logarithm. 

360 """ 

361 return FunctionExpression("log10", [self]) 

362 

363 @expose_as_static 

364 def pow(self, exponent: Expression | float) -> "Expression": 

365 """Creates an expression that calculates this expression raised to the power of the exponent. 

366 

367 Example: 

368 >>> # Raise 'base_val' to the power of 2. 

369 >>> Field.of("base_val").pow(2) 

370 >>> # Raise 'base_val' to the power of 'exponent_val'. 

371 >>> Field.of("base_val").pow(Field.of("exponent_val")) 

372 

373 Args: 

374 exponent: The exponent. 

375 

376 Returns: 

377 A new `Expression` representing the power operation. 

378 """ 

379 return FunctionExpression( 

380 "pow", [self, self._cast_to_expr_or_convert_to_constant(exponent)] 

381 ) 

382 

383 @expose_as_static 

384 def round(self) -> "Expression": 

385 """Creates an expression that rounds this expression to the nearest integer. 

386 

387 Example: 

388 >>> # Round the 'value' field. 

389 >>> Field.of("value").round() 

390 

391 Returns: 

392 A new `Expression` representing the rounded value. 

393 """ 

394 return FunctionExpression("round", [self]) 

395 

396 @expose_as_static 

397 def sqrt(self) -> "Expression": 

398 """Creates an expression that calculates the square root of this expression. 

399 

400 Example: 

401 >>> # Get the square root of the 'area' field. 

402 >>> Field.of("area").sqrt() 

403 

404 Returns: 

405 A new `Expression` representing the square root. 

406 """ 

407 return FunctionExpression("sqrt", [self]) 

408 

409 @expose_as_static 

410 def logical_maximum(self, *others: Expression | CONSTANT_TYPE) -> "Expression": 

411 """Creates an expression that returns the larger value between this expression 

412 and another expression or constant, based on Firestore's value type ordering. 

413 

414 Firestore's value type ordering is described here: 

415 https://cloud.google.com/firestore/docs/concepts/data-types#value_type_ordering 

416 

417 Example: 

418 >>> # Returns the larger value between the 'discount' field and the 'cap' field. 

419 >>> Field.of("discount").logical_maximum(Field.of("cap")) 

420 >>> # Returns the larger value between the 'value' field and some ints 

421 >>> Field.of("value").logical_maximum(10, 20, 30) 

422 

423 Args: 

424 others: The other expression or constant values to compare with. 

425 

426 Returns: 

427 A new `Expression` representing the logical maximum operation. 

428 """ 

429 return FunctionExpression( 

430 "maximum", 

431 [self] + [self._cast_to_expr_or_convert_to_constant(o) for o in others], 

432 infix_name_override="logical_maximum", 

433 ) 

434 

435 @expose_as_static 

436 def logical_minimum(self, *others: Expression | CONSTANT_TYPE) -> "Expression": 

437 """Creates an expression that returns the smaller value between this expression 

438 and another expression or constant, based on Firestore's value type ordering. 

439 

440 Firestore's value type ordering is described here: 

441 https://cloud.google.com/firestore/docs/concepts/data-types#value_type_ordering 

442 

443 Example: 

444 >>> # Returns the smaller value between the 'discount' field and the 'floor' field. 

445 >>> Field.of("discount").logical_minimum(Field.of("floor")) 

446 >>> # Returns the smaller value between the 'value' field and some ints 

447 >>> Field.of("value").logical_minimum(10, 20, 30) 

448 

449 Args: 

450 others: The other expression or constant values to compare with. 

451 

452 Returns: 

453 A new `Expression` representing the logical minimum operation. 

454 """ 

455 return FunctionExpression( 

456 "minimum", 

457 [self] + [self._cast_to_expr_or_convert_to_constant(o) for o in others], 

458 infix_name_override="logical_minimum", 

459 ) 

460 

461 @expose_as_static 

462 def equal(self, other: Expression | CONSTANT_TYPE) -> "BooleanExpression": 

463 """Creates an expression that checks if this expression is equal to another 

464 expression or constant value. 

465 

466 Example: 

467 >>> # Check if the 'age' field is equal to 21 

468 >>> Field.of("age").equal(21) 

469 >>> # Check if the 'city' field is equal to "London" 

470 >>> Field.of("city").equal("London") 

471 

472 Args: 

473 other: The expression or constant value to compare for equality. 

474 

475 Returns: 

476 A new `Expression` representing the equality comparison. 

477 """ 

478 return BooleanExpression( 

479 "equal", [self, self._cast_to_expr_or_convert_to_constant(other)] 

480 ) 

481 

482 @expose_as_static 

483 def not_equal(self, other: Expression | CONSTANT_TYPE) -> "BooleanExpression": 

484 """Creates an expression that checks if this expression is not equal to another 

485 expression or constant value. 

486 

487 Example: 

488 >>> # Check if the 'status' field is not equal to "completed" 

489 >>> Field.of("status").not_equal("completed") 

490 >>> # Check if the 'country' field is not equal to "USA" 

491 >>> Field.of("country").not_equal("USA") 

492 

493 Args: 

494 other: The expression or constant value to compare for inequality. 

495 

496 Returns: 

497 A new `Expression` representing the inequality comparison. 

498 """ 

499 return BooleanExpression( 

500 "not_equal", [self, self._cast_to_expr_or_convert_to_constant(other)] 

501 ) 

502 

503 @expose_as_static 

504 def greater_than(self, other: Expression | CONSTANT_TYPE) -> "BooleanExpression": 

505 """Creates an expression that checks if this expression is greater than another 

506 expression or constant value. 

507 

508 Example: 

509 >>> # Check if the 'age' field is greater than the 'limit' field 

510 >>> Field.of("age").greater_than(Field.of("limit")) 

511 >>> # Check if the 'price' field is greater than 100 

512 >>> Field.of("price").greater_than(100) 

513 

514 Args: 

515 other: The expression or constant value to compare for greater than. 

516 

517 Returns: 

518 A new `Expression` representing the greater than comparison. 

519 """ 

520 return BooleanExpression( 

521 "greater_than", [self, self._cast_to_expr_or_convert_to_constant(other)] 

522 ) 

523 

524 @expose_as_static 

525 def greater_than_or_equal( 

526 self, other: Expression | CONSTANT_TYPE 

527 ) -> "BooleanExpression": 

528 """Creates an expression that checks if this expression is greater than or equal 

529 to another expression or constant value. 

530 

531 Example: 

532 >>> # Check if the 'quantity' field is greater than or equal to field 'requirement' plus 1 

533 >>> Field.of("quantity").greater_than_or_equal(Field.of('requirement').add(1)) 

534 >>> # Check if the 'score' field is greater than or equal to 80 

535 >>> Field.of("score").greater_than_or_equal(80) 

536 

537 Args: 

538 other: The expression or constant value to compare for greater than or equal to. 

539 

540 Returns: 

541 A new `Expression` representing the greater than or equal to comparison. 

542 """ 

543 return BooleanExpression( 

544 "greater_than_or_equal", 

545 [self, self._cast_to_expr_or_convert_to_constant(other)], 

546 ) 

547 

548 @expose_as_static 

549 def less_than(self, other: Expression | CONSTANT_TYPE) -> "BooleanExpression": 

550 """Creates an expression that checks if this expression is less than another 

551 expression or constant value. 

552 

553 Example: 

554 >>> # Check if the 'age' field is less than 'limit' 

555 >>> Field.of("age").less_than(Field.of('limit')) 

556 >>> # Check if the 'price' field is less than 50 

557 >>> Field.of("price").less_than(50) 

558 

559 Args: 

560 other: The expression or constant value to compare for less than. 

561 

562 Returns: 

563 A new `Expression` representing the less than comparison. 

564 """ 

565 return BooleanExpression( 

566 "less_than", [self, self._cast_to_expr_or_convert_to_constant(other)] 

567 ) 

568 

569 @expose_as_static 

570 def less_than_or_equal( 

571 self, other: Expression | CONSTANT_TYPE 

572 ) -> "BooleanExpression": 

573 """Creates an expression that checks if this expression is less than or equal to 

574 another expression or constant value. 

575 

576 Example: 

577 >>> # Check if the 'quantity' field is less than or equal to 20 

578 >>> Field.of("quantity").less_than_or_equal(Constant.of(20)) 

579 >>> # Check if the 'score' field is less than or equal to 70 

580 >>> Field.of("score").less_than_or_equal(70) 

581 

582 Args: 

583 other: The expression or constant value to compare for less than or equal to. 

584 

585 Returns: 

586 A new `Expression` representing the less than or equal to comparison. 

587 """ 

588 return BooleanExpression( 

589 "less_than_or_equal", 

590 [self, self._cast_to_expr_or_convert_to_constant(other)], 

591 ) 

592 

593 @expose_as_static 

594 def equal_any( 

595 self, array: Array | Sequence[Expression | CONSTANT_TYPE] | Expression 

596 ) -> "BooleanExpression": 

597 """Creates an expression that checks if this expression is equal to any of the 

598 provided values or expressions. 

599 

600 Example: 

601 >>> # Check if the 'category' field is either "Electronics" or value of field 'primaryType' 

602 >>> Field.of("category").equal_any(["Electronics", Field.of("primaryType")]) 

603 

604 Args: 

605 array: The values or expressions to check against. 

606 

607 Returns: 

608 A new `Expression` representing the 'IN' comparison. 

609 """ 

610 return BooleanExpression( 

611 "equal_any", 

612 [ 

613 self, 

614 self._cast_to_expr_or_convert_to_constant(array), 

615 ], 

616 ) 

617 

618 @expose_as_static 

619 def not_equal_any( 

620 self, array: Array | list[Expression | CONSTANT_TYPE] | Expression 

621 ) -> "BooleanExpression": 

622 """Creates an expression that checks if this expression is not equal to any of the 

623 provided values or expressions. 

624 

625 Example: 

626 >>> # Check if the 'status' field is neither "pending" nor "cancelled" 

627 >>> Field.of("status").not_equal_any(["pending", "cancelled"]) 

628 

629 Args: 

630 array: The values or expressions to check against. 

631 

632 Returns: 

633 A new `Expression` representing the 'NOT IN' comparison. 

634 """ 

635 return BooleanExpression( 

636 "not_equal_any", 

637 [ 

638 self, 

639 self._cast_to_expr_or_convert_to_constant(array), 

640 ], 

641 ) 

642 

643 @expose_as_static 

644 def array_get(self, offset: Expression | int) -> "FunctionExpression": 

645 """ 

646 Creates an expression that indexes into an array from the beginning or end and returns the 

647 element. A negative offset starts from the end. 

648 

649 Example: 

650 >>> Array([1,2,3]).array_get(0) 

651 

652 Args: 

653 offset: the index of the element to return 

654 

655 Returns: 

656 A new `Expression` representing the `array_get` operation. 

657 """ 

658 return FunctionExpression( 

659 "array_get", [self, self._cast_to_expr_or_convert_to_constant(offset)] 

660 ) 

661 

662 @expose_as_static 

663 def array_contains( 

664 self, element: Expression | CONSTANT_TYPE 

665 ) -> "BooleanExpression": 

666 """Creates an expression that checks if an array contains a specific element or value. 

667 

668 Example: 

669 >>> # Check if the 'sizes' array contains the value from the 'selectedSize' field 

670 >>> Field.of("sizes").array_contains(Field.of("selectedSize")) 

671 >>> # Check if the 'colors' array contains "red" 

672 >>> Field.of("colors").array_contains("red") 

673 

674 Args: 

675 element: The element (expression or constant) to search for in the array. 

676 

677 Returns: 

678 A new `Expression` representing the 'array_contains' comparison. 

679 """ 

680 return BooleanExpression( 

681 "array_contains", [self, self._cast_to_expr_or_convert_to_constant(element)] 

682 ) 

683 

684 @expose_as_static 

685 def array_contains_all( 

686 self, 

687 elements: Array | list[Expression | CONSTANT_TYPE] | Expression, 

688 ) -> "BooleanExpression": 

689 """Creates an expression that checks if an array contains all the specified elements. 

690 

691 Example: 

692 >>> # Check if the 'tags' array contains both "news" and "sports" 

693 >>> Field.of("tags").array_contains_all(["news", "sports"]) 

694 >>> # Check if the 'tags' array contains both of the values from field 'tag1' and "tag2" 

695 >>> Field.of("tags").array_contains_all([Field.of("tag1"), "tag2"]) 

696 

697 Args: 

698 elements: The list of elements (expressions or constants) to check for in the array. 

699 

700 Returns: 

701 A new `Expression` representing the 'array_contains_all' comparison. 

702 """ 

703 return BooleanExpression( 

704 "array_contains_all", 

705 [ 

706 self, 

707 self._cast_to_expr_or_convert_to_constant(elements), 

708 ], 

709 ) 

710 

711 @expose_as_static 

712 def array_contains_any( 

713 self, 

714 elements: Array | list[Expression | CONSTANT_TYPE] | Expression, 

715 ) -> "BooleanExpression": 

716 """Creates an expression that checks if an array contains any of the specified elements. 

717 

718 Example: 

719 >>> # Check if the 'categories' array contains either values from field "cate1" or "cate2" 

720 >>> Field.of("categories").array_contains_any([Field.of("cate1"), Field.of("cate2")]) 

721 >>> # Check if the 'groups' array contains either the value from the 'userGroup' field 

722 >>> # or the value "guest" 

723 >>> Field.of("groups").array_contains_any([Field.of("userGroup"), "guest"]) 

724 

725 Args: 

726 elements: The list of elements (expressions or constants) to check for in the array. 

727 

728 Returns: 

729 A new `Expression` representing the 'array_contains_any' comparison. 

730 """ 

731 return BooleanExpression( 

732 "array_contains_any", 

733 [ 

734 self, 

735 self._cast_to_expr_or_convert_to_constant(elements), 

736 ], 

737 ) 

738 

739 @expose_as_static 

740 def array_length(self) -> "Expression": 

741 """Creates an expression that calculates the length of an array. 

742 

743 Example: 

744 >>> # Get the number of items in the 'cart' array 

745 >>> Field.of("cart").array_length() 

746 

747 Returns: 

748 A new `Expression` representing the length of the array. 

749 """ 

750 return FunctionExpression("array_length", [self]) 

751 

752 @expose_as_static 

753 def array_reverse(self) -> "Expression": 

754 """Creates an expression that returns the reversed content of an array. 

755 

756 Example: 

757 >>> # Get the 'preferences' array in reversed order. 

758 >>> Field.of("preferences").array_reverse() 

759 

760 Returns: 

761 A new `Expression` representing the reversed array. 

762 """ 

763 return FunctionExpression("array_reverse", [self]) 

764 

765 @expose_as_static 

766 def array_concat( 

767 self, *other_arrays: Array | list[Expression | CONSTANT_TYPE] | Expression 

768 ) -> "Expression": 

769 """Creates an expression that concatenates an array expression with another array. 

770 

771 Example: 

772 >>> # Combine the 'tags' array with a new array and an array field 

773 >>> Field.of("tags").array_concat(["newTag1", "newTag2", Field.of("otherTag")]) 

774 

775 Args: 

776 array: The list of constants or expressions to concat with. 

777 

778 Returns: 

779 A new `Expression` representing the concatenated array. 

780 """ 

781 return FunctionExpression( 

782 "array_concat", 

783 [self] 

784 + [self._cast_to_expr_or_convert_to_constant(arr) for arr in other_arrays], 

785 ) 

786 

787 @expose_as_static 

788 def concat(self, *others: Expression | CONSTANT_TYPE) -> "Expression": 

789 """Creates an expression that concatenates expressions together 

790 

791 Args: 

792 *others: The expressions to concatenate. 

793 

794 Returns: 

795 A new `Expression` representing the concatenated value. 

796 """ 

797 return FunctionExpression( 

798 "concat", 

799 [self] + [self._cast_to_expr_or_convert_to_constant(o) for o in others], 

800 ) 

801 

802 @expose_as_static 

803 def length(self) -> "Expression": 

804 """ 

805 Creates an expression that calculates the length of the expression if it is a string, array, map, or blob. 

806 

807 Example: 

808 >>> # Get the length of the 'name' field. 

809 >>> Field.of("name").length() 

810 

811 Returns: 

812 A new `Expression` representing the length of the expression. 

813 """ 

814 return FunctionExpression("length", [self]) 

815 

816 @expose_as_static 

817 def is_absent(self) -> "BooleanExpression": 

818 """Creates an expression that returns true if a value is absent. Otherwise, returns false even if 

819 the value is null. 

820 

821 Example: 

822 >>> # Check if the 'email' field is absent. 

823 >>> Field.of("email").is_absent() 

824 

825 Returns: 

826 A new `BooleanExpressionession` representing the isAbsent operation. 

827 """ 

828 return BooleanExpression("is_absent", [self]) 

829 

830 @expose_as_static 

831 def if_absent(self, default_value: Expression | CONSTANT_TYPE) -> "Expression": 

832 """Creates an expression that returns a default value if an expression evaluates to an absent value. 

833 

834 Example: 

835 >>> # Return the value of the 'email' field, or "N/A" if it's absent. 

836 >>> Field.of("email").if_absent("N/A") 

837 

838 Args: 

839 default_value: The expression or constant value to return if this expression is absent. 

840 

841 Returns: 

842 A new `Expression` representing the ifAbsent operation. 

843 """ 

844 return FunctionExpression( 

845 "if_absent", 

846 [self, self._cast_to_expr_or_convert_to_constant(default_value)], 

847 ) 

848 

849 @expose_as_static 

850 def is_error(self): 

851 """Creates an expression that checks if a given expression produces an error 

852 

853 Example: 

854 >>> # Resolves to True if an expression produces an error 

855 >>> Field.of("value").divide("string").is_error() 

856 

857 Returns: 

858 A new `Expression` representing the isError operation. 

859 """ 

860 return FunctionExpression("is_error", [self]) 

861 

862 @expose_as_static 

863 def if_error(self, then_value: Expression | CONSTANT_TYPE) -> "Expression": 

864 """Creates an expression that returns ``then_value`` if this expression evaluates to an error. 

865 Otherwise, returns the value of this expression. 

866 

867 Example: 

868 >>> # Resolves to 0 if an expression produces an error 

869 >>> Field.of("value").divide("string").if_error(0) 

870 

871 Args: 

872 then_value: The value to return if this expression evaluates to an error. 

873 

874 Returns: 

875 A new `Expression` representing the ifError operation. 

876 """ 

877 return FunctionExpression( 

878 "if_error", [self, self._cast_to_expr_or_convert_to_constant(then_value)] 

879 ) 

880 

881 @expose_as_static 

882 def exists(self) -> "BooleanExpression": 

883 """Creates an expression that checks if a field exists in the document. 

884 

885 Example: 

886 >>> # Check if the document has a field named "phoneNumber" 

887 >>> Field.of("phoneNumber").exists() 

888 

889 Returns: 

890 A new `Expression` representing the 'exists' check. 

891 """ 

892 return BooleanExpression("exists", [self]) 

893 

894 @expose_as_static 

895 def sum(self) -> "Expression": 

896 """Creates an aggregation that calculates the sum of a numeric field across multiple stage inputs. 

897 

898 Example: 

899 >>> # Calculate the total revenue from a set of orders 

900 >>> Field.of("orderAmount").sum().as_("totalRevenue") 

901 

902 Returns: 

903 A new `AggregateFunction` representing the 'sum' aggregation. 

904 """ 

905 return AggregateFunction("sum", [self]) 

906 

907 @expose_as_static 

908 def average(self) -> "Expression": 

909 """Creates an aggregation that calculates the average (mean) of a numeric field across multiple 

910 stage inputs. 

911 

912 Example: 

913 >>> # Calculate the average age of users 

914 >>> Field.of("age").average().as_("averageAge") 

915 

916 Returns: 

917 A new `AggregateFunction` representing the 'avg' aggregation. 

918 """ 

919 return AggregateFunction("average", [self]) 

920 

921 @expose_as_static 

922 def count(self) -> "Expression": 

923 """Creates an aggregation that counts the number of stage inputs with valid evaluations of the 

924 expression or field. 

925 

926 Example: 

927 >>> # Count the total number of products 

928 >>> Field.of("productId").count().as_("totalProducts") 

929 

930 Returns: 

931 A new `AggregateFunction` representing the 'count' aggregation. 

932 """ 

933 return AggregateFunction("count", [self]) 

934 

935 @expose_as_static 

936 def count_if(self) -> "Expression": 

937 """Creates an aggregation that counts the number of values of the provided field or expression 

938 that evaluate to True. 

939 

940 Example: 

941 >>> # Count the number of adults 

942 >>> Field.of("age").greater_than(18).count_if().as_("totalAdults") 

943 

944 

945 Returns: 

946 A new `AggregateFunction` representing the 'count_if' aggregation. 

947 """ 

948 return AggregateFunction("count_if", [self]) 

949 

950 @expose_as_static 

951 def count_distinct(self) -> "Expression": 

952 """Creates an aggregation that counts the number of distinct values of the 

953 provided field or expression. 

954 

955 Example: 

956 >>> # Count the total number of countries in the data 

957 >>> Field.of("country").count_distinct().as_("totalCountries") 

958 

959 Returns: 

960 A new `AggregateFunction` representing the 'count_distinct' aggregation. 

961 """ 

962 return AggregateFunction("count_distinct", [self]) 

963 

964 @expose_as_static 

965 def minimum(self) -> "Expression": 

966 """Creates an aggregation that finds the minimum value of a field across multiple stage inputs. 

967 

968 Example: 

969 >>> # Find the lowest price of all products 

970 >>> Field.of("price").minimum().as_("lowestPrice") 

971 

972 Returns: 

973 A new `AggregateFunction` representing the 'minimum' aggregation. 

974 """ 

975 return AggregateFunction("minimum", [self]) 

976 

977 @expose_as_static 

978 def maximum(self) -> "Expression": 

979 """Creates an aggregation that finds the maximum value of a field across multiple stage inputs. 

980 

981 Example: 

982 >>> # Find the highest score in a leaderboard 

983 >>> Field.of("score").maximum().as_("highestScore") 

984 

985 Returns: 

986 A new `AggregateFunction` representing the 'maximum' aggregation. 

987 """ 

988 return AggregateFunction("maximum", [self]) 

989 

990 @expose_as_static 

991 def char_length(self) -> "Expression": 

992 """Creates an expression that calculates the character length of a string. 

993 

994 Example: 

995 >>> # Get the character length of the 'name' field 

996 >>> Field.of("name").char_length() 

997 

998 Returns: 

999 A new `Expression` representing the length of the string. 

1000 """ 

1001 return FunctionExpression("char_length", [self]) 

1002 

1003 @expose_as_static 

1004 def byte_length(self) -> "Expression": 

1005 """Creates an expression that calculates the byte length of a string in its UTF-8 form. 

1006 

1007 Example: 

1008 >>> # Get the byte length of the 'name' field 

1009 >>> Field.of("name").byte_length() 

1010 

1011 Returns: 

1012 A new `Expression` representing the byte length of the string. 

1013 """ 

1014 return FunctionExpression("byte_length", [self]) 

1015 

1016 @expose_as_static 

1017 def like(self, pattern: Expression | str) -> "BooleanExpression": 

1018 """Creates an expression that performs a case-sensitive string comparison. 

1019 

1020 Example: 

1021 >>> # Check if the 'title' field contains the word "guide" (case-sensitive) 

1022 >>> Field.of("title").like("%guide%") 

1023 >>> # Check if the 'title' field matches the pattern specified in field 'pattern'. 

1024 >>> Field.of("title").like(Field.of("pattern")) 

1025 

1026 Args: 

1027 pattern: The pattern (string or expression) to search for. You can use "%" as a wildcard character. 

1028 

1029 Returns: 

1030 A new `Expression` representing the 'like' comparison. 

1031 """ 

1032 return BooleanExpression( 

1033 "like", [self, self._cast_to_expr_or_convert_to_constant(pattern)] 

1034 ) 

1035 

1036 @expose_as_static 

1037 def regex_contains(self, regex: Expression | str) -> "BooleanExpression": 

1038 """Creates an expression that checks if a string contains a specified regular expression as a 

1039 substring. 

1040 

1041 Example: 

1042 >>> # Check if the 'description' field contains "example" (case-insensitive) 

1043 >>> Field.of("description").regex_contains("(?i)example") 

1044 >>> # Check if the 'description' field contains the regular expression stored in field 'regex' 

1045 >>> Field.of("description").regex_contains(Field.of("regex")) 

1046 

1047 Args: 

1048 regex: The regular expression (string or expression) to use for the search. 

1049 

1050 Returns: 

1051 A new `Expression` representing the 'contains' comparison. 

1052 """ 

1053 return BooleanExpression( 

1054 "regex_contains", [self, self._cast_to_expr_or_convert_to_constant(regex)] 

1055 ) 

1056 

1057 @expose_as_static 

1058 def regex_match(self, regex: Expression | str) -> "BooleanExpression": 

1059 """Creates an expression that checks if a string matches a specified regular expression. 

1060 

1061 Example: 

1062 >>> # Check if the 'email' field matches a valid email pattern 

1063 >>> Field.of("email").regex_match("[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}") 

1064 >>> # Check if the 'email' field matches a regular expression stored in field 'regex' 

1065 >>> Field.of("email").regex_match(Field.of("regex")) 

1066 

1067 Args: 

1068 regex: The regular expression (string or expression) to use for the match. 

1069 

1070 Returns: 

1071 A new `Expression` representing the regular expression match. 

1072 """ 

1073 return BooleanExpression( 

1074 "regex_match", [self, self._cast_to_expr_or_convert_to_constant(regex)] 

1075 ) 

1076 

1077 @expose_as_static 

1078 def string_contains(self, substring: Expression | str) -> "BooleanExpression": 

1079 """Creates an expression that checks if this string expression contains a specified substring. 

1080 

1081 Example: 

1082 >>> # Check if the 'description' field contains "example". 

1083 >>> Field.of("description").string_contains("example") 

1084 >>> # Check if the 'description' field contains the value of the 'keyword' field. 

1085 >>> Field.of("description").string_contains(Field.of("keyword")) 

1086 

1087 Args: 

1088 substring: The substring (string or expression) to use for the search. 

1089 

1090 Returns: 

1091 A new `Expression` representing the 'contains' comparison. 

1092 """ 

1093 return BooleanExpression( 

1094 "string_contains", 

1095 [self, self._cast_to_expr_or_convert_to_constant(substring)], 

1096 ) 

1097 

1098 @expose_as_static 

1099 def starts_with(self, prefix: Expression | str) -> "BooleanExpression": 

1100 """Creates an expression that checks if a string starts with a given prefix. 

1101 

1102 Example: 

1103 >>> # Check if the 'name' field starts with "Mr." 

1104 >>> Field.of("name").starts_with("Mr.") 

1105 >>> # Check if the 'fullName' field starts with the value of the 'firstName' field 

1106 >>> Field.of("fullName").starts_with(Field.of("firstName")) 

1107 

1108 Args: 

1109 prefix: The prefix (string or expression) to check for. 

1110 

1111 Returns: 

1112 A new `Expression` representing the 'starts with' comparison. 

1113 """ 

1114 return BooleanExpression( 

1115 "starts_with", [self, self._cast_to_expr_or_convert_to_constant(prefix)] 

1116 ) 

1117 

1118 @expose_as_static 

1119 def ends_with(self, postfix: Expression | str) -> "BooleanExpression": 

1120 """Creates an expression that checks if a string ends with a given postfix. 

1121 

1122 Example: 

1123 >>> # Check if the 'filename' field ends with ".txt" 

1124 >>> Field.of("filename").ends_with(".txt") 

1125 >>> # Check if the 'url' field ends with the value of the 'extension' field 

1126 >>> Field.of("url").ends_with(Field.of("extension")) 

1127 

1128 Args: 

1129 postfix: The postfix (string or expression) to check for. 

1130 

1131 Returns: 

1132 A new `Expression` representing the 'ends with' comparison. 

1133 """ 

1134 return BooleanExpression( 

1135 "ends_with", [self, self._cast_to_expr_or_convert_to_constant(postfix)] 

1136 ) 

1137 

1138 @expose_as_static 

1139 def string_concat(self, *elements: Expression | CONSTANT_TYPE) -> "Expression": 

1140 """Creates an expression that concatenates string expressions, fields or constants together. 

1141 

1142 Example: 

1143 >>> # Combine the 'firstName', " ", and 'lastName' fields into a single string 

1144 >>> Field.of("firstName").string_concat(" ", Field.of("lastName")) 

1145 

1146 Args: 

1147 *elements: The expressions or constants (typically strings) to concatenate. 

1148 

1149 Returns: 

1150 A new `Expression` representing the concatenated string. 

1151 """ 

1152 return FunctionExpression( 

1153 "string_concat", 

1154 [self] + [self._cast_to_expr_or_convert_to_constant(el) for el in elements], 

1155 ) 

1156 

1157 @expose_as_static 

1158 def to_lower(self) -> "Expression": 

1159 """Creates an expression that converts a string to lowercase. 

1160 

1161 Example: 

1162 >>> # Convert the 'name' field to lowercase 

1163 >>> Field.of("name").to_lower() 

1164 

1165 Returns: 

1166 A new `Expression` representing the lowercase string. 

1167 """ 

1168 return FunctionExpression("to_lower", [self]) 

1169 

1170 @expose_as_static 

1171 def to_upper(self) -> "Expression": 

1172 """Creates an expression that converts a string to uppercase. 

1173 

1174 Example: 

1175 >>> # Convert the 'title' field to uppercase 

1176 >>> Field.of("title").to_upper() 

1177 

1178 Returns: 

1179 A new `Expression` representing the uppercase string. 

1180 """ 

1181 return FunctionExpression("to_upper", [self]) 

1182 

1183 @expose_as_static 

1184 def trim(self) -> "Expression": 

1185 """Creates an expression that removes leading and trailing whitespace from a string. 

1186 

1187 Example: 

1188 >>> # Trim whitespace from the 'userInput' field 

1189 >>> Field.of("userInput").trim() 

1190 

1191 Returns: 

1192 A new `Expression` representing the trimmed string. 

1193 """ 

1194 return FunctionExpression("trim", [self]) 

1195 

1196 @expose_as_static 

1197 def string_reverse(self) -> "Expression": 

1198 """Creates an expression that reverses a string. 

1199 

1200 Example: 

1201 >>> # Reverse the 'userInput' field 

1202 >>> Field.of("userInput").reverse() 

1203 

1204 Returns: 

1205 A new `Expression` representing the reversed string. 

1206 """ 

1207 return FunctionExpression("string_reverse", [self]) 

1208 

1209 @expose_as_static 

1210 def substring( 

1211 self, position: Expression | int, length: Expression | int | None = None 

1212 ) -> "Expression": 

1213 """Creates an expression that returns a substring of the results of this expression. 

1214 

1215 

1216 Example: 

1217 >>> Field.of("description").substring(5, 10) 

1218 >>> Field.of("description").substring(5) 

1219 

1220 Args: 

1221 position: the index of the first character of the substring. 

1222 length: the length of the substring. If not provided the substring 

1223 will end at the end of the input. 

1224 

1225 Returns: 

1226 A new `Expression` representing the extracted substring. 

1227 """ 

1228 args = [self, self._cast_to_expr_or_convert_to_constant(position)] 

1229 if length is not None: 

1230 args.append(self._cast_to_expr_or_convert_to_constant(length)) 

1231 return FunctionExpression("substring", args) 

1232 

1233 @expose_as_static 

1234 def join(self, delimeter: Expression | str) -> "Expression": 

1235 """Creates an expression that joins the elements of an array into a string 

1236 

1237 

1238 Example: 

1239 >>> Field.of("tags").join(", ") 

1240 

1241 Args: 

1242 delimiter: The delimiter to add between the elements of the array. 

1243 

1244 Returns: 

1245 A new `Expression` representing the joined string. 

1246 """ 

1247 return FunctionExpression( 

1248 "join", [self, self._cast_to_expr_or_convert_to_constant(delimeter)] 

1249 ) 

1250 

1251 @expose_as_static 

1252 def map_get(self, key: str | Constant[str]) -> "Expression": 

1253 """Accesses a value from the map produced by evaluating this expression. 

1254 

1255 Example: 

1256 >>> Map({"city": "London"}).map_get("city") 

1257 >>> Field.of("address").map_get("city") 

1258 

1259 Args: 

1260 key: The key to access in the map. 

1261 

1262 Returns: 

1263 A new `Expression` representing the value associated with the given key in the map. 

1264 """ 

1265 return FunctionExpression( 

1266 "map_get", [self, self._cast_to_expr_or_convert_to_constant(key)] 

1267 ) 

1268 

1269 @expose_as_static 

1270 def map_remove(self, key: str | Constant[str]) -> "Expression": 

1271 """Remove a key from a the map produced by evaluating this expression. 

1272 

1273 Example: 

1274 >>> Map({"city": "London"}).map_remove("city") 

1275 >>> Field.of("address").map_remove("city") 

1276 

1277 Args: 

1278 key: The key to remove in the map. 

1279 

1280 Returns: 

1281 A new `Expression` representing the map_remove operation. 

1282 """ 

1283 return FunctionExpression( 

1284 "map_remove", [self, self._cast_to_expr_or_convert_to_constant(key)] 

1285 ) 

1286 

1287 @expose_as_static 

1288 def map_merge( 

1289 self, 

1290 *other_maps: Map 

1291 | dict[str | Constant[str], Expression | CONSTANT_TYPE] 

1292 | Expression, 

1293 ) -> "Expression": 

1294 """Creates an expression that merges one or more dicts into a single map. 

1295 

1296 Example: 

1297 >>> Map({"city": "London"}).map_merge({"country": "UK"}, {"isCapital": True}) 

1298 >>> Field.of("settings").map_merge({"enabled":True}, FunctionExpression.conditional(Field.of('isAdmin'), {"admin":True}, {}}) 

1299 

1300 Args: 

1301 *other_maps: Sequence of maps to merge into the resulting map. 

1302 

1303 Returns: 

1304 A new `Expression` representing the value associated with the given key in the map. 

1305 """ 

1306 return FunctionExpression( 

1307 "map_merge", 

1308 [self] + [self._cast_to_expr_or_convert_to_constant(m) for m in other_maps], 

1309 ) 

1310 

1311 @expose_as_static 

1312 def cosine_distance(self, other: Expression | list[float] | Vector) -> "Expression": 

1313 """Calculates the cosine distance between two vectors. 

1314 

1315 Example: 

1316 >>> # Calculate the cosine distance between the 'userVector' field and the 'itemVector' field 

1317 >>> Field.of("userVector").cosine_distance(Field.of("itemVector")) 

1318 >>> # Calculate the Cosine distance between the 'location' field and a target location 

1319 >>> Field.of("location").cosine_distance([37.7749, -122.4194]) 

1320 

1321 Args: 

1322 other: The other vector (represented as an Expression, list of floats, or Vector) to compare against. 

1323 

1324 Returns: 

1325 A new `Expression` representing the cosine distance between the two vectors. 

1326 """ 

1327 return FunctionExpression( 

1328 "cosine_distance", 

1329 [ 

1330 self, 

1331 self._cast_to_expr_or_convert_to_constant(other, include_vector=True), 

1332 ], 

1333 ) 

1334 

1335 @expose_as_static 

1336 def euclidean_distance( 

1337 self, other: Expression | list[float] | Vector 

1338 ) -> "Expression": 

1339 """Calculates the Euclidean distance between two vectors. 

1340 

1341 Example: 

1342 >>> # Calculate the Euclidean distance between the 'location' field and a target location 

1343 >>> Field.of("location").euclidean_distance([37.7749, -122.4194]) 

1344 >>> # Calculate the Euclidean distance between two vector fields: 'pointA' and 'pointB' 

1345 >>> Field.of("pointA").euclidean_distance(Field.of("pointB")) 

1346 

1347 Args: 

1348 other: The other vector (represented as an Expression, list of floats, or Vector) to compare against. 

1349 

1350 Returns: 

1351 A new `Expression` representing the Euclidean distance between the two vectors. 

1352 """ 

1353 return FunctionExpression( 

1354 "euclidean_distance", 

1355 [ 

1356 self, 

1357 self._cast_to_expr_or_convert_to_constant(other, include_vector=True), 

1358 ], 

1359 ) 

1360 

1361 @expose_as_static 

1362 def dot_product(self, other: Expression | list[float] | Vector) -> "Expression": 

1363 """Calculates the dot product between two vectors. 

1364 

1365 Example: 

1366 >>> # Calculate the dot product between a feature vector and a target vector 

1367 >>> Field.of("features").dot_product([0.5, 0.8, 0.2]) 

1368 >>> # Calculate the dot product between two document vectors: 'docVector1' and 'docVector2' 

1369 >>> Field.of("docVector1").dot_product(Field.of("docVector2")) 

1370 

1371 Args: 

1372 other: The other vector (represented as an Expression, list of floats, or Vector) to calculate dot product with. 

1373 

1374 Returns: 

1375 A new `Expression` representing the dot product between the two vectors. 

1376 """ 

1377 return FunctionExpression( 

1378 "dot_product", 

1379 [ 

1380 self, 

1381 self._cast_to_expr_or_convert_to_constant(other, include_vector=True), 

1382 ], 

1383 ) 

1384 

1385 @expose_as_static 

1386 def vector_length(self) -> "Expression": 

1387 """Creates an expression that calculates the length (dimension) of a Firestore Vector. 

1388 

1389 Example: 

1390 >>> # Get the vector length (dimension) of the field 'embedding'. 

1391 >>> Field.of("embedding").vector_length() 

1392 

1393 Returns: 

1394 A new `Expression` representing the length of the vector. 

1395 """ 

1396 return FunctionExpression("vector_length", [self]) 

1397 

1398 @expose_as_static 

1399 def timestamp_to_unix_micros(self) -> "Expression": 

1400 """Creates an expression that converts a timestamp to the number of microseconds since the epoch 

1401 (1970-01-01 00:00:00 UTC). 

1402 

1403 Truncates higher levels of precision by rounding down to the beginning of the microsecond. 

1404 

1405 Example: 

1406 >>> # Convert the 'timestamp' field to microseconds since the epoch. 

1407 >>> Field.of("timestamp").timestamp_to_unix_micros() 

1408 

1409 Returns: 

1410 A new `Expression` representing the number of microseconds since the epoch. 

1411 """ 

1412 return FunctionExpression("timestamp_to_unix_micros", [self]) 

1413 

1414 @expose_as_static 

1415 def unix_micros_to_timestamp(self) -> "Expression": 

1416 """Creates an expression that converts a number of microseconds since the epoch (1970-01-01 

1417 00:00:00 UTC) to a timestamp. 

1418 

1419 Example: 

1420 >>> # Convert the 'microseconds' field to a timestamp. 

1421 >>> Field.of("microseconds").unix_micros_to_timestamp() 

1422 

1423 Returns: 

1424 A new `Expression` representing the timestamp. 

1425 """ 

1426 return FunctionExpression("unix_micros_to_timestamp", [self]) 

1427 

1428 @expose_as_static 

1429 def timestamp_to_unix_millis(self) -> "Expression": 

1430 """Creates an expression that converts a timestamp to the number of milliseconds since the epoch 

1431 (1970-01-01 00:00:00 UTC). 

1432 

1433 Truncates higher levels of precision by rounding down to the beginning of the millisecond. 

1434 

1435 Example: 

1436 >>> # Convert the 'timestamp' field to milliseconds since the epoch. 

1437 >>> Field.of("timestamp").timestamp_to_unix_millis() 

1438 

1439 Returns: 

1440 A new `Expression` representing the number of milliseconds since the epoch. 

1441 """ 

1442 return FunctionExpression("timestamp_to_unix_millis", [self]) 

1443 

1444 @expose_as_static 

1445 def unix_millis_to_timestamp(self) -> "Expression": 

1446 """Creates an expression that converts a number of milliseconds since the epoch (1970-01-01 

1447 00:00:00 UTC) to a timestamp. 

1448 

1449 Example: 

1450 >>> # Convert the 'milliseconds' field to a timestamp. 

1451 >>> Field.of("milliseconds").unix_millis_to_timestamp() 

1452 

1453 Returns: 

1454 A new `Expression` representing the timestamp. 

1455 """ 

1456 return FunctionExpression("unix_millis_to_timestamp", [self]) 

1457 

1458 @expose_as_static 

1459 def timestamp_to_unix_seconds(self) -> "Expression": 

1460 """Creates an expression that converts a timestamp to the number of seconds since the epoch 

1461 (1970-01-01 00:00:00 UTC). 

1462 

1463 Truncates higher levels of precision by rounding down to the beginning of the second. 

1464 

1465 Example: 

1466 >>> # Convert the 'timestamp' field to seconds since the epoch. 

1467 >>> Field.of("timestamp").timestamp_to_unix_seconds() 

1468 

1469 Returns: 

1470 A new `Expression` representing the number of seconds since the epoch. 

1471 """ 

1472 return FunctionExpression("timestamp_to_unix_seconds", [self]) 

1473 

1474 @expose_as_static 

1475 def unix_seconds_to_timestamp(self) -> "Expression": 

1476 """Creates an expression that converts a number of seconds since the epoch (1970-01-01 00:00:00 

1477 UTC) to a timestamp. 

1478 

1479 Example: 

1480 >>> # Convert the 'seconds' field to a timestamp. 

1481 >>> Field.of("seconds").unix_seconds_to_timestamp() 

1482 

1483 Returns: 

1484 A new `Expression` representing the timestamp. 

1485 """ 

1486 return FunctionExpression("unix_seconds_to_timestamp", [self]) 

1487 

1488 @expose_as_static 

1489 def timestamp_add( 

1490 self, unit: Expression | str, amount: Expression | float 

1491 ) -> "Expression": 

1492 """Creates an expression that adds a specified amount of time to this timestamp expression. 

1493 

1494 Example: 

1495 >>> # Add a duration specified by the 'unit' and 'amount' fields to the 'timestamp' field. 

1496 >>> Field.of("timestamp").timestamp_add(Field.of("unit"), Field.of("amount")) 

1497 >>> # Add 1.5 days to the 'timestamp' field. 

1498 >>> Field.of("timestamp").timestamp_add("day", 1.5) 

1499 

1500 Args: 

1501 unit: The expression or string evaluating to the unit of time to add, must be one of 

1502 'microsecond', 'millisecond', 'second', 'minute', 'hour', 'day'. 

1503 amount: The expression or float representing the amount of time to add. 

1504 

1505 Returns: 

1506 A new `Expression` representing the resulting timestamp. 

1507 """ 

1508 return FunctionExpression( 

1509 "timestamp_add", 

1510 [ 

1511 self, 

1512 self._cast_to_expr_or_convert_to_constant(unit), 

1513 self._cast_to_expr_or_convert_to_constant(amount), 

1514 ], 

1515 ) 

1516 

1517 @expose_as_static 

1518 def timestamp_subtract( 

1519 self, unit: Expression | str, amount: Expression | float 

1520 ) -> "Expression": 

1521 """Creates an expression that subtracts a specified amount of time from this timestamp expression. 

1522 

1523 Example: 

1524 >>> # Subtract a duration specified by the 'unit' and 'amount' fields from the 'timestamp' field. 

1525 >>> Field.of("timestamp").timestamp_subtract(Field.of("unit"), Field.of("amount")) 

1526 >>> # Subtract 2.5 hours from the 'timestamp' field. 

1527 >>> Field.of("timestamp").timestamp_subtract("hour", 2.5) 

1528 

1529 Args: 

1530 unit: The expression or string evaluating to the unit of time to subtract, must be one of 

1531 'microsecond', 'millisecond', 'second', 'minute', 'hour', 'day'. 

1532 amount: The expression or float representing the amount of time to subtract. 

1533 

1534 Returns: 

1535 A new `Expression` representing the resulting timestamp. 

1536 """ 

1537 return FunctionExpression( 

1538 "timestamp_subtract", 

1539 [ 

1540 self, 

1541 self._cast_to_expr_or_convert_to_constant(unit), 

1542 self._cast_to_expr_or_convert_to_constant(amount), 

1543 ], 

1544 ) 

1545 

1546 @expose_as_static 

1547 def collection_id(self): 

1548 """Creates an expression that returns the collection ID from a path. 

1549 

1550 Example: 

1551 >>> # Get the collection ID from a path. 

1552 >>> Field.of("__name__").collection_id() 

1553 

1554 Returns: 

1555 A new `Expression` representing the collection ID. 

1556 """ 

1557 return FunctionExpression("collection_id", [self]) 

1558 

1559 @expose_as_static 

1560 def document_id(self): 

1561 """Creates an expression that returns the document ID from a path. 

1562 

1563 Example: 

1564 >>> # Get the document ID from a path. 

1565 >>> Field.of("__name__").document_id() 

1566 

1567 Returns: 

1568 A new `Expression` representing the document ID. 

1569 """ 

1570 return FunctionExpression("document_id", [self]) 

1571 

1572 def ascending(self) -> Ordering: 

1573 """Creates an `Ordering` that sorts documents in ascending order based on this expression. 

1574 

1575 Example: 

1576 >>> # Sort documents by the 'name' field in ascending order 

1577 >>> client.pipeline().collection("users").sort(Field.of("name").ascending()) 

1578 

1579 Returns: 

1580 A new `Ordering` for ascending sorting. 

1581 """ 

1582 return Ordering(self, Ordering.Direction.ASCENDING) 

1583 

1584 def descending(self) -> Ordering: 

1585 """Creates an `Ordering` that sorts documents in descending order based on this expression. 

1586 

1587 Example: 

1588 >>> # Sort documents by the 'createdAt' field in descending order 

1589 >>> client.pipeline().collection("users").sort(Field.of("createdAt").descending()) 

1590 

1591 Returns: 

1592 A new `Ordering` for descending sorting. 

1593 """ 

1594 return Ordering(self, Ordering.Direction.DESCENDING) 

1595 

1596 def as_(self, alias: str) -> "AliasedExpression": 

1597 """Assigns an alias to this expression. 

1598 

1599 Aliases are useful for renaming fields in the output of a stage or for giving meaningful 

1600 names to calculated values. 

1601 

1602 Example: 

1603 >>> # Calculate the total price and assign it the alias "totalPrice" and add it to the output. 

1604 >>> client.pipeline().collection("items").add_fields( 

1605 ... Field.of("price").multiply(Field.of("quantity")).as_("totalPrice") 

1606 ... ) 

1607 

1608 Args: 

1609 alias: The alias to assign to this expression. 

1610 

1611 Returns: 

1612 A new `Selectable` (typically an `AliasedExpression`) that wraps this 

1613 expression and associates it with the provided alias. 

1614 """ 

1615 return AliasedExpression(self, alias) 

1616 

1617 

1618class Constant(Expression, Generic[CONSTANT_TYPE]): 

1619 """Represents a constant literal value in an expression.""" 

1620 

1621 def __init__(self, value: CONSTANT_TYPE): 

1622 self.value: CONSTANT_TYPE = value 

1623 

1624 def __eq__(self, other): 

1625 if not isinstance(other, Constant): 

1626 return other == self.value 

1627 else: 

1628 return other.value == self.value 

1629 

1630 @staticmethod 

1631 def of(value: CONSTANT_TYPE) -> Constant[CONSTANT_TYPE]: 

1632 """Creates a constant expression from a Python value.""" 

1633 return Constant(value) 

1634 

1635 def __repr__(self): 

1636 value_str = repr(self.value) 

1637 if isinstance(self.value, float) and value_str == "nan": 

1638 value_str = "math.nan" 

1639 return f"Constant.of({value_str})" 

1640 

1641 def __hash__(self): 

1642 return hash(self.value) 

1643 

1644 def _to_pb(self) -> Value: 

1645 return encode_value(self.value) 

1646 

1647 

1648class FunctionExpression(Expression): 

1649 """A base class for expressions that represent function calls.""" 

1650 

1651 def __init__( 

1652 self, 

1653 name: str, 

1654 params: Sequence[Expression], 

1655 *, 

1656 use_infix_repr: bool = True, 

1657 infix_name_override: str | None = None, 

1658 ): 

1659 self.name = name 

1660 self.params = list(params) 

1661 self._use_infix_repr = use_infix_repr 

1662 self._infix_name_override = infix_name_override 

1663 

1664 def __repr__(self): 

1665 """ 

1666 Most FunctionExpressions can be triggered infix. Eg: Field.of('age').greater_than(18). 

1667 

1668 Display them this way in the repr string where possible 

1669 """ 

1670 if self._use_infix_repr: 

1671 infix_name = self._infix_name_override or self.name 

1672 if len(self.params) == 1: 

1673 return f"{self.params[0]!r}.{infix_name}()" 

1674 elif len(self.params) == 2: 

1675 return f"{self.params[0]!r}.{infix_name}({self.params[1]!r})" 

1676 else: 

1677 return f"{self.params[0]!r}.{infix_name}({', '.join([repr(p) for p in self.params[1:]])})" 

1678 return f"{self.__class__.__name__}({', '.join([repr(p) for p in self.params])})" 

1679 

1680 def __eq__(self, other): 

1681 if not isinstance(other, FunctionExpression): 

1682 return False 

1683 else: 

1684 return other.name == self.name and other.params == self.params 

1685 

1686 def _to_pb(self): 

1687 return Value( 

1688 function_value={ 

1689 "name": self.name, 

1690 "args": [p._to_pb() for p in self.params], 

1691 } 

1692 ) 

1693 

1694 

1695class AggregateFunction(FunctionExpression): 

1696 """A base class for aggregation functions that operate across multiple inputs.""" 

1697 

1698 

1699class Selectable(Expression): 

1700 """Base class for expressions that can be selected or aliased in projection stages.""" 

1701 

1702 def __eq__(self, other): 

1703 if not isinstance(other, type(self)): 

1704 return False 

1705 else: 

1706 return other._to_map() == self._to_map() 

1707 

1708 @abstractmethod 

1709 def _to_map(self) -> tuple[str, Value]: 

1710 """ 

1711 Returns a str: Value representation of the Selectable 

1712 """ 

1713 raise NotImplementedError 

1714 

1715 @classmethod 

1716 def _value_from_selectables(cls, *selectables: Selectable) -> Value: 

1717 """ 

1718 Returns a Value representing a map of Selectables 

1719 """ 

1720 return Value( 

1721 map_value={ 

1722 "fields": {m[0]: m[1] for m in [s._to_map() for s in selectables]} 

1723 } 

1724 ) 

1725 

1726 @staticmethod 

1727 def _to_value(field_list: Sequence[Selectable]) -> Value: 

1728 return Value( 

1729 map_value={ 

1730 "fields": {m[0]: m[1] for m in [f._to_map() for f in field_list]} 

1731 } 

1732 ) 

1733 

1734 

1735T = TypeVar("T", bound=Expression) 

1736 

1737 

1738class AliasedExpression(Selectable, Generic[T]): 

1739 """Wraps an expression with an alias.""" 

1740 

1741 def __init__(self, expr: T, alias: str): 

1742 self.expr = expr 

1743 self.alias = alias 

1744 

1745 def _to_map(self): 

1746 return self.alias, self.expr._to_pb() 

1747 

1748 def __repr__(self): 

1749 return f"{self.expr}.as_('{self.alias}')" 

1750 

1751 def _to_pb(self): 

1752 return Value(map_value={"fields": {self.alias: self.expr._to_pb()}}) 

1753 

1754 

1755class Field(Selectable): 

1756 """Represents a reference to a field within a document.""" 

1757 

1758 DOCUMENT_ID = "__name__" 

1759 

1760 def __init__(self, path: str): 

1761 """Initializes a Field reference. 

1762 

1763 Args: 

1764 path: The dot-separated path to the field (e.g., "address.city"). 

1765 Use Field.DOCUMENT_ID for the document ID. 

1766 """ 

1767 self.path = path 

1768 

1769 @staticmethod 

1770 def of(path: str): 

1771 """Creates a Field reference. 

1772 

1773 Args: 

1774 path: The dot-separated path to the field (e.g., "address.city"). 

1775 Use Field.DOCUMENT_ID for the document ID. 

1776 

1777 Returns: 

1778 A new Field instance. 

1779 """ 

1780 return Field(path) 

1781 

1782 def _to_map(self): 

1783 return self.path, self._to_pb() 

1784 

1785 def __repr__(self): 

1786 return f"Field.of({self.path!r})" 

1787 

1788 def _to_pb(self): 

1789 return Value(field_reference_value=self.path) 

1790 

1791 

1792class BooleanExpression(FunctionExpression): 

1793 """Filters the given data in some way.""" 

1794 

1795 @staticmethod 

1796 def _from_query_filter_pb(filter_pb, client): 

1797 if isinstance(filter_pb, Query_pb.CompositeFilter): 

1798 sub_filters = [ 

1799 BooleanExpression._from_query_filter_pb(f, client) 

1800 for f in filter_pb.filters 

1801 ] 

1802 if filter_pb.op == Query_pb.CompositeFilter.Operator.OR: 

1803 return Or(*sub_filters) 

1804 elif filter_pb.op == Query_pb.CompositeFilter.Operator.AND: 

1805 return And(*sub_filters) 

1806 else: 

1807 raise TypeError( 

1808 f"Unexpected CompositeFilter operator type: {filter_pb.op}" 

1809 ) 

1810 elif isinstance(filter_pb, Query_pb.UnaryFilter): 

1811 field = Field.of(filter_pb.field.field_path) 

1812 if filter_pb.op == Query_pb.UnaryFilter.Operator.IS_NAN: 

1813 return And(field.exists(), field.equal(float("nan"))) 

1814 elif filter_pb.op == Query_pb.UnaryFilter.Operator.IS_NOT_NAN: 

1815 return And(field.exists(), Not(field.equal(float("nan")))) 

1816 elif filter_pb.op == Query_pb.UnaryFilter.Operator.IS_NULL: 

1817 return And(field.exists(), field.equal(None)) 

1818 elif filter_pb.op == Query_pb.UnaryFilter.Operator.IS_NOT_NULL: 

1819 return And(field.exists(), Not(field.equal(None))) 

1820 else: 

1821 raise TypeError(f"Unexpected UnaryFilter operator type: {filter_pb.op}") 

1822 elif isinstance(filter_pb, Query_pb.FieldFilter): 

1823 field = Field.of(filter_pb.field.field_path) 

1824 value = decode_value(filter_pb.value, client) 

1825 if filter_pb.op == Query_pb.FieldFilter.Operator.LESS_THAN: 

1826 return And(field.exists(), field.less_than(value)) 

1827 elif filter_pb.op == Query_pb.FieldFilter.Operator.LESS_THAN_OR_EQUAL: 

1828 return And(field.exists(), field.less_than_or_equal(value)) 

1829 elif filter_pb.op == Query_pb.FieldFilter.Operator.GREATER_THAN: 

1830 return And(field.exists(), field.greater_than(value)) 

1831 elif filter_pb.op == Query_pb.FieldFilter.Operator.GREATER_THAN_OR_EQUAL: 

1832 return And(field.exists(), field.greater_than_or_equal(value)) 

1833 elif filter_pb.op == Query_pb.FieldFilter.Operator.EQUAL: 

1834 return And(field.exists(), field.equal(value)) 

1835 elif filter_pb.op == Query_pb.FieldFilter.Operator.NOT_EQUAL: 

1836 # In Enterprise DBs NOT_EQUAL will match a field that does not exist, 

1837 # therefore we do not want an existence filter for the NOT_EQUAL conversion 

1838 # so the Query and Pipeline behavior are consistent in Enterprise. 

1839 return field.not_equal(value) 

1840 if filter_pb.op == Query_pb.FieldFilter.Operator.ARRAY_CONTAINS: 

1841 return And(field.exists(), field.array_contains(value)) 

1842 elif filter_pb.op == Query_pb.FieldFilter.Operator.ARRAY_CONTAINS_ANY: 

1843 return And(field.exists(), field.array_contains_any(value)) 

1844 elif filter_pb.op == Query_pb.FieldFilter.Operator.IN: 

1845 return And(field.exists(), field.equal_any(value)) 

1846 elif filter_pb.op == Query_pb.FieldFilter.Operator.NOT_IN: 

1847 # In Enterprise DBs NOT_IN will match a field that does not exist, 

1848 # therefore we do not want an existence filter for the NOT_IN conversion 

1849 # so the Query and Pipeline behavior are consistent in Enterprise. 

1850 return field.not_equal_any(value) 

1851 else: 

1852 raise TypeError(f"Unexpected FieldFilter operator type: {filter_pb.op}") 

1853 elif isinstance(filter_pb, Query_pb.Filter): 

1854 # unwrap oneof 

1855 f = ( 

1856 filter_pb.composite_filter 

1857 or filter_pb.field_filter 

1858 or filter_pb.unary_filter 

1859 ) 

1860 return BooleanExpression._from_query_filter_pb(f, client) 

1861 else: 

1862 raise TypeError(f"Unexpected filter type: {type(filter_pb)}") 

1863 

1864 

1865class Array(FunctionExpression): 

1866 """ 

1867 Creates an expression that creates a Firestore array value from an input list. 

1868 

1869 Example: 

1870 >>> Array(["bar", Field.of("baz")]) 

1871 

1872 Args: 

1873 elements: The input list to evaluate in the expression 

1874 """ 

1875 

1876 def __init__(self, elements: list[Expression | CONSTANT_TYPE]): 

1877 if not isinstance(elements, list): 

1878 raise TypeError("Array must be constructed with a list") 

1879 converted_elements = [ 

1880 self._cast_to_expr_or_convert_to_constant(el) for el in elements 

1881 ] 

1882 super().__init__("array", converted_elements) 

1883 

1884 def __repr__(self): 

1885 return f"Array({self.params})" 

1886 

1887 

1888class Map(FunctionExpression): 

1889 """ 

1890 Creates an expression that creates a Firestore map value from an input dict. 

1891 

1892 Example: 

1893 >>> Expression.map({"foo": "bar", "baz": Field.of("baz")}) 

1894 

1895 Args: 

1896 elements: The input dict to evaluate in the expression 

1897 """ 

1898 

1899 def __init__(self, elements: dict[str | Constant[str], Expression | CONSTANT_TYPE]): 

1900 element_list = [] 

1901 for k, v in elements.items(): 

1902 element_list.append(self._cast_to_expr_or_convert_to_constant(k)) 

1903 element_list.append(self._cast_to_expr_or_convert_to_constant(v)) 

1904 super().__init__("map", element_list) 

1905 

1906 def __repr__(self): 

1907 formatted_params = [ 

1908 a.value if isinstance(a, Constant) else a for a in self.params 

1909 ] 

1910 d = {a: b for a, b in zip(formatted_params[::2], formatted_params[1::2])} 

1911 return f"Map({d})" 

1912 

1913 

1914class And(BooleanExpression): 

1915 """ 

1916 Represents an expression that performs a logical 'AND' operation on multiple filter conditions. 

1917 

1918 Example: 

1919 >>> # Check if the 'age' field is greater than 18 AND the 'city' field is "London" AND 

1920 >>> # the 'status' field is "active" 

1921 >>> And(Field.of("age").greater_than(18), Field.of("city").equal("London"), Field.of("status").equal("active")) 

1922 

1923 Args: 

1924 *conditions: The filter conditions to 'AND' together. 

1925 """ 

1926 

1927 def __init__(self, *conditions: "BooleanExpression"): 

1928 super().__init__("and", conditions, use_infix_repr=False) 

1929 

1930 

1931class Not(BooleanExpression): 

1932 """ 

1933 Represents an expression that negates a filter condition. 

1934 

1935 Example: 

1936 >>> # Find documents where the 'completed' field is NOT true 

1937 >>> Not(Field.of("completed").equal(True)) 

1938 

1939 Args: 

1940 condition: The filter condition to negate. 

1941 """ 

1942 

1943 def __init__(self, condition: BooleanExpression): 

1944 super().__init__("not", [condition], use_infix_repr=False) 

1945 

1946 

1947class Or(BooleanExpression): 

1948 """ 

1949 Represents expression that performs a logical 'OR' operation on multiple filter conditions. 

1950 

1951 Example: 

1952 >>> # Check if the 'age' field is greater than 18 OR the 'city' field is "London" OR 

1953 >>> # the 'status' field is "active" 

1954 >>> Or(Field.of("age").greater_than(18), Field.of("city").equal("London"), Field.of("status").equal("active")) 

1955 

1956 Args: 

1957 *conditions: The filter conditions to 'OR' together. 

1958 """ 

1959 

1960 def __init__(self, *conditions: "BooleanExpression"): 

1961 super().__init__("or", conditions, use_infix_repr=False) 

1962 

1963 

1964class Xor(BooleanExpression): 

1965 """ 

1966 Represents an expression that performs a logical 'XOR' (exclusive OR) operation on multiple filter conditions. 

1967 

1968 Example: 

1969 >>> # Check if only one of the conditions is true: 'age' greater than 18, 'city' is "London", 

1970 >>> # or 'status' is "active". 

1971 >>> Xor(Field.of("age").greater_than(18), Field.of("city").equal("London"), Field.of("status").equal("active")) 

1972 

1973 Args: 

1974 *conditions: The filter conditions to 'XOR' together. 

1975 """ 

1976 

1977 def __init__(self, conditions: Sequence["BooleanExpression"]): 

1978 super().__init__("xor", conditions, use_infix_repr=False) 

1979 

1980 

1981class Conditional(BooleanExpression): 

1982 """ 

1983 Represents a conditional expression that evaluates to a 'then' expression if a condition is true 

1984 and an 'else' expression if the condition is false. 

1985 

1986 Example: 

1987 >>> # If 'age' is greater than 18, return "Adult"; otherwise, return "Minor". 

1988 >>> Conditional(Field.of("age").greater_than(18), Constant.of("Adult"), Constant.of("Minor")); 

1989 

1990 Args: 

1991 condition: The condition to evaluate. 

1992 then_expr: The expression to return if the condition is true. 

1993 else_expr: The expression to return if the condition is false 

1994 """ 

1995 

1996 def __init__( 

1997 self, condition: BooleanExpression, then_expr: Expression, else_expr: Expression 

1998 ): 

1999 super().__init__( 

2000 "conditional", [condition, then_expr, else_expr], use_infix_repr=False 

2001 ) 

2002 

2003 

2004class Count(AggregateFunction): 

2005 """ 

2006 Represents an aggregation that counts the number of stage inputs with valid evaluations of the 

2007 expression or field. 

2008 

2009 Example: 

2010 >>> # Count the total number of products 

2011 >>> Field.of("productId").count().as_("totalProducts") 

2012 >>> Count(Field.of("productId")) 

2013 >>> Count().as_("count") 

2014 

2015 Args: 

2016 expression: The expression or field to count. If None, counts all stage inputs. 

2017 """ 

2018 

2019 def __init__(self, expression: Expression | None = None): 

2020 expression_list = [expression] if expression else [] 

2021 super().__init__("count", expression_list, use_infix_repr=bool(expression_list)) 

2022 

2023 

2024class CurrentTimestamp(FunctionExpression): 

2025 """Creates an expression that returns the current timestamp 

2026 

2027 Returns: 

2028 A new `Expression` representing the current timestamp. 

2029 """ 

2030 

2031 def __init__(self): 

2032 super().__init__("current_timestamp", [], use_infix_repr=False)