Skip to content

Commit 8aa697a

Browse files
authored
feat(firestore): support string expressions (#16152)
* regex_find() * regex_find_all() * split() * string_repeat() * string_replace_all() * string_replace_one() * string_index_of()
1 parent 73139f7 commit 8aa697a

File tree

3 files changed

+926
-0
lines changed

3 files changed

+926
-0
lines changed

packages/google-cloud-firestore/google/cloud/firestore_v1/pipeline_expressions.py

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,6 +1327,224 @@ def map_merge(
13271327
[self] + [self._cast_to_expr_or_convert_to_constant(m) for m in other_maps],
13281328
)
13291329

1330+
@expose_as_static
1331+
def regex_find(self, pattern: str | Constant[str] | Expression) -> "Expression":
1332+
"""Creates an expression that returns the first substring of a string expression that
1333+
matches a specified regular expression.
1334+
1335+
This expression uses the RE2 regular expression syntax. See https://github.com/google/re2/wiki/Syntax.
1336+
1337+
Example:
1338+
>>> Field.of("email").regex_find("@[A-Za-z0-9.-]+")
1339+
>>> Field.of("email").regex_find(Field.of("pattern"))
1340+
1341+
Args:
1342+
pattern: The regular expression to search for.
1343+
1344+
Returns:
1345+
A new `Expression` representing the regular expression find function.
1346+
"""
1347+
return FunctionExpression(
1348+
"regex_find", [self, self._cast_to_expr_or_convert_to_constant(pattern)]
1349+
)
1350+
1351+
@expose_as_static
1352+
def regex_find_all(self, pattern: str | Constant[str] | Expression) -> "Expression":
1353+
"""Creates an expression that evaluates to an array of all substrings in a string expression
1354+
that match a specified regular expression.
1355+
1356+
This expression uses the RE2 regular expression syntax. See https://github.com/google/re2/wiki/Syntax.
1357+
1358+
Example:
1359+
>>> Field.of("comment").regex_find_all("@[A-Za-z0-9_]+")
1360+
>>> Field.of("comment").regex_find_all(Field.of("pattern"))
1361+
1362+
Args:
1363+
pattern: The regular expression to search for.
1364+
1365+
Returns:
1366+
A new `Expression` representing the regular expression find function.
1367+
"""
1368+
return FunctionExpression(
1369+
"regex_find_all", [self, self._cast_to_expr_or_convert_to_constant(pattern)]
1370+
)
1371+
1372+
@expose_as_static
1373+
def split(self, delimiter: str | Constant[str] | Expression) -> "Expression":
1374+
"""Creates an expression that splits the value of a field on the provided delimiter.
1375+
1376+
Example:
1377+
>>> Field.of("date").split("date", "-")
1378+
1379+
Args:
1380+
field_name: Split the value in this field.
1381+
delimiter: The delimiter string to split on.
1382+
1383+
Returns:
1384+
A new `Expression` representing the split function.
1385+
"""
1386+
return FunctionExpression(
1387+
"split", [self, self._cast_to_expr_or_convert_to_constant(delimiter)]
1388+
)
1389+
1390+
@expose_as_static
1391+
def string_repeat(self, repetitions: int | Expression) -> "Expression":
1392+
"""Creates an expression that repeats a string or byte array a specified number
1393+
of times.
1394+
1395+
Example:
1396+
>>> # Called on an existing field expression:
1397+
>>> Field.of("name").string_repeat(3)
1398+
>>> # Called statically using the field name:
1399+
>>> Expression.string_repeat("name", 3)
1400+
1401+
Args:
1402+
repetitions: The number of times to repeat the string or byte array.
1403+
1404+
Returns:
1405+
A new `Expression` representing the repeated string or byte array.
1406+
"""
1407+
return FunctionExpression(
1408+
"string_repeat",
1409+
[self, self._cast_to_expr_or_convert_to_constant(repetitions)],
1410+
)
1411+
1412+
@expose_as_static
1413+
def string_replace_all(
1414+
self,
1415+
find: str | bytes | Constant[str] | Constant[bytes] | Expression,
1416+
replacement: str | bytes | Constant[str] | Constant[bytes] | Expression,
1417+
) -> "Expression":
1418+
"""Creates an expression that replaces all occurrences of a substring or byte
1419+
sequence with a replacement.
1420+
1421+
Example:
1422+
>>> # Called on an existing field expression:
1423+
>>> Field.of("text").string_replace_all("foo", "bar")
1424+
1425+
Args:
1426+
find: The substring or byte sequence to search for.
1427+
replacement: The replacement string or byte sequence.
1428+
1429+
Returns:
1430+
A new `Expression` representing the string or byte array with replacements.
1431+
"""
1432+
return FunctionExpression(
1433+
"string_replace_all",
1434+
[
1435+
self,
1436+
self._cast_to_expr_or_convert_to_constant(find),
1437+
self._cast_to_expr_or_convert_to_constant(replacement),
1438+
],
1439+
)
1440+
1441+
@expose_as_static
1442+
def string_replace_one(
1443+
self,
1444+
find: str | bytes | Constant[str] | Constant[bytes] | Expression,
1445+
replacement: str | bytes | Constant[str] | Constant[bytes] | Expression,
1446+
) -> "Expression":
1447+
"""Creates an expression that replaces the first occurrence of a substring or byte
1448+
sequence with a replacement.
1449+
1450+
Example:
1451+
>>> # Called on an existing field expression:
1452+
>>> Field.of("text").string_replace_one("foo", "bar")
1453+
1454+
Args:
1455+
find: The substring or byte sequence to search for.
1456+
replacement: The replacement string or byte sequence.
1457+
1458+
Returns:
1459+
A new `Expression` representing the string or byte array with the replacement.
1460+
"""
1461+
return FunctionExpression(
1462+
"string_replace_one",
1463+
[
1464+
self,
1465+
self._cast_to_expr_or_convert_to_constant(find),
1466+
self._cast_to_expr_or_convert_to_constant(replacement),
1467+
],
1468+
)
1469+
1470+
@expose_as_static
1471+
def string_index_of(
1472+
self,
1473+
search: str | bytes | Constant[str] | Constant[bytes] | Expression,
1474+
) -> "Expression":
1475+
"""Creates an expression that finds the index of the first occurrence of a substring or
1476+
byte sequence.
1477+
1478+
Example:
1479+
>>> # Called on an existing field expression:
1480+
>>> Field.of("text").string_index_of("foo")
1481+
1482+
Args:
1483+
search: The substring or byte sequence to search for.
1484+
1485+
Returns:
1486+
A new `Expression` representing the index of the first occurrence.
1487+
"""
1488+
return FunctionExpression(
1489+
"string_index_of",
1490+
[
1491+
self,
1492+
self._cast_to_expr_or_convert_to_constant(search),
1493+
],
1494+
)
1495+
1496+
@expose_as_static
1497+
def ltrim(
1498+
self,
1499+
chars: str | bytes | Constant[str] | Constant[bytes] | Expression | None = None,
1500+
) -> "Expression":
1501+
"""Creates an expression that trims leading whitespace or a specified sequence
1502+
of characters/bytes from a string or byte sequence.
1503+
1504+
Example:
1505+
>>> # Called on an existing field expression:
1506+
>>> Field.of("text").ltrim()
1507+
>>> Field.of("text").ltrim(" ")
1508+
1509+
Args:
1510+
chars: The substring or byte sequence to trim. If not provided,
1511+
whitespace will be trimmed.
1512+
1513+
Returns:
1514+
A new `Expression` representing the trimmed value.
1515+
"""
1516+
args = [self]
1517+
if chars is not None:
1518+
args.append(self._cast_to_expr_or_convert_to_constant(chars))
1519+
1520+
return FunctionExpression("ltrim", args)
1521+
1522+
@expose_as_static
1523+
def rtrim(
1524+
self,
1525+
chars: str | bytes | Constant[str] | Constant[bytes] | Expression | None = None,
1526+
) -> "Expression":
1527+
"""Creates an expression that trims trailing whitespace or a specified sequence
1528+
of characters/bytes from a string or byte sequence.
1529+
1530+
Example:
1531+
>>> # Called on an existing field expression:
1532+
>>> Field.of("text").rtrim()
1533+
>>> Field.of("text").rtrim(" ")
1534+
1535+
Args:
1536+
chars: The substring or byte sequence to trim. If not provided,
1537+
whitespace will be trimmed.
1538+
1539+
Returns:
1540+
A new `Expression` representing the trimmed value.
1541+
"""
1542+
args = [self]
1543+
if chars is not None:
1544+
args.append(self._cast_to_expr_or_convert_to_constant(chars))
1545+
1546+
return FunctionExpression("rtrim", args)
1547+
13301548
@expose_as_static
13311549
def cosine_distance(self, other: Expression | list[float] | Vector) -> "Expression":
13321550
"""Calculates the cosine distance between two vectors.

0 commit comments

Comments
 (0)