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

Commit 1d92887

Browse files
authored
feat: add support for regexFind and regexFindAll Pipeline expressions (#2310)
1 parent 26e4a58 commit 1d92887

3 files changed

Lines changed: 234 additions & 0 deletions

File tree

google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,134 @@ public static BooleanExpression regexContains(String fieldName, String pattern)
12281228
return regexContains(field(fieldName), constant(pattern));
12291229
}
12301230

1231+
/**
1232+
* Creates an expression that returns the first substring of a string expression that matches a
1233+
* specified regular expression.
1234+
*
1235+
* <p>This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression
1236+
* syntax.
1237+
*
1238+
* @param string The expression representing the string to search.
1239+
* @param pattern The regular expression to search for.
1240+
* @return A new {@link Expression} representing the regular expression find function.
1241+
*/
1242+
@BetaApi
1243+
public static Expression regexFind(Expression string, Expression pattern) {
1244+
return new FunctionExpression("regex_find", ImmutableList.of(string, pattern));
1245+
}
1246+
1247+
/**
1248+
* Creates an expression that returns the first substring of a string expression that matches a
1249+
* specified regular expression.
1250+
*
1251+
* <p>This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression
1252+
* syntax.
1253+
*
1254+
* @param string The expression representing the string to search.
1255+
* @param pattern The regular expression to search for.
1256+
* @return A new {@link Expression} representing the regular expression find function.
1257+
*/
1258+
@BetaApi
1259+
public static Expression regexFind(Expression string, String pattern) {
1260+
return regexFind(string, constant(pattern));
1261+
}
1262+
1263+
/**
1264+
* Creates an expression that returns the first substring of a string field that matches a
1265+
* specified regular expression.
1266+
*
1267+
* <p>This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression
1268+
* syntax.
1269+
*
1270+
* @param fieldName The name of the field containing the string to search.
1271+
* @param pattern The regular expression to search for.
1272+
* @return A new {@link Expression} representing the regular expression find function.
1273+
*/
1274+
@BetaApi
1275+
public static Expression regexFind(String fieldName, Expression pattern) {
1276+
return regexFind(field(fieldName), pattern);
1277+
}
1278+
1279+
/**
1280+
* Creates an expression that returns the first substring of a string field that matches a
1281+
* specified regular expression.
1282+
*
1283+
* <p>This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression
1284+
* syntax.
1285+
*
1286+
* @param fieldName The name of the field containing the string to search.
1287+
* @param pattern The regular expression to search for.
1288+
* @return A new {@link Expression} representing the regular expression find function.
1289+
*/
1290+
@BetaApi
1291+
public static Expression regexFind(String fieldName, String pattern) {
1292+
return regexFind(field(fieldName), constant(pattern));
1293+
}
1294+
1295+
/**
1296+
* Creates an expression that evaluates to a list of all substrings in a string expression that
1297+
* match a specified regular expression.
1298+
*
1299+
* <p>This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression
1300+
* syntax.
1301+
*
1302+
* @param string The expression representing the string to search.
1303+
* @param pattern The regular expression to search for.
1304+
* @return A new {@link Expression} that evaluates to a list of matched substrings.
1305+
*/
1306+
@BetaApi
1307+
public static Expression regexFindAll(Expression string, Expression pattern) {
1308+
return new FunctionExpression("regex_find_all", ImmutableList.of(string, pattern));
1309+
}
1310+
1311+
/**
1312+
* Creates an expression that evaluates to a list of all substrings in a string expression that
1313+
* match a specified regular expression.
1314+
*
1315+
* <p>This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression
1316+
* syntax.
1317+
*
1318+
* @param string The expression representing the string to search.
1319+
* @param pattern The regular expression to search for.
1320+
* @return A new {@link Expression} that evaluates to a list of matched substrings.
1321+
*/
1322+
@BetaApi
1323+
public static Expression regexFindAll(Expression string, String pattern) {
1324+
return regexFindAll(string, constant(pattern));
1325+
}
1326+
1327+
/**
1328+
* Creates an expression that evaluates to a list of all substrings in a string field that match a
1329+
* specified regular expression.
1330+
*
1331+
* <p>This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression
1332+
* syntax.
1333+
*
1334+
* @param fieldName The name of the field containing the string to search.
1335+
* @param pattern The regular expression to search for.
1336+
* @return A new {@link Expression} that evaluates to a list of matched substrings.
1337+
*/
1338+
@BetaApi
1339+
public static Expression regexFindAll(String fieldName, Expression pattern) {
1340+
return regexFindAll(field(fieldName), pattern);
1341+
}
1342+
1343+
/**
1344+
* Creates an expression that evaluates to a list of all substrings in a string field that match a
1345+
* specified regular expression.
1346+
*
1347+
* <p>This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression
1348+
* syntax.
1349+
*
1350+
* @param fieldName The name of the field containing the string to search.
1351+
* @param pattern The regular expression to search for.
1352+
* @return A new {@link Expression} that evaluates to a list of matched substrings.
1353+
*/
1354+
@BetaApi
1355+
public static Expression regexFindAll(String fieldName, String pattern) {
1356+
return regexFindAll(field(fieldName), constant(pattern));
1357+
}
1358+
12311359
/**
12321360
* Creates an expression that checks if a string field matches a specified regular expression.
12331361
*
@@ -3872,6 +4000,36 @@ public final BooleanExpression regexContains(Object pattern) {
38724000
return regexContains(this, toExprOrConstant(pattern));
38734001
}
38744002

4003+
/**
4004+
* Creates an expression that returns the first substring of a string expression that matches a
4005+
* specified regular expression.
4006+
*
4007+
* <p>This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression
4008+
* syntax.
4009+
*
4010+
* @param pattern The regular expression to search for.
4011+
* @return A new {@link Expression} representing the regular expression find function.
4012+
*/
4013+
@BetaApi
4014+
public final Expression regexFind(Object pattern) {
4015+
return regexFind(this, toExprOrConstant(pattern));
4016+
}
4017+
4018+
/**
4019+
* Creates an expression that evaluates to a list of all substrings in a string expression that
4020+
* match a specified regular expression.
4021+
*
4022+
* <p>This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression
4023+
* syntax.
4024+
*
4025+
* @param pattern The regular expression to search for.
4026+
* @return A new {@link Expression} that evaluates to a list of matched substrings.
4027+
*/
4028+
@BetaApi
4029+
public final Expression regexFindAll(Object pattern) {
4030+
return regexFindAll(this, toExprOrConstant(pattern));
4031+
}
4032+
38754033
/**
38764034
* Creates an expression that checks if this string expression matches a specified regular
38774035
* expression.

google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,56 @@ public void testRegexContains() throws Exception {
10461046
assertThat(data(results)).hasSize(5);
10471047
}
10481048

1049+
@Test
1050+
public void testRegexFind() throws Exception {
1051+
assumeFalse(
1052+
"Regexes are not supported against the emulator",
1053+
isRunningAgainstFirestoreEmulator(firestore));
1054+
1055+
List<PipelineResult> results =
1056+
firestore
1057+
.pipeline()
1058+
.createFrom(collection)
1059+
.select(field("title").regexFind("^\\w+").as("firstWordInTitle"))
1060+
.sort(field("firstWordInTitle").ascending())
1061+
.limit(3)
1062+
.execute()
1063+
.get()
1064+
.getResults();
1065+
1066+
assertThat(data(results))
1067+
.isEqualTo(
1068+
Lists.newArrayList(
1069+
map("firstWordInTitle", "1984"),
1070+
map("firstWordInTitle", "Crime"),
1071+
map("firstWordInTitle", "Dune")));
1072+
}
1073+
1074+
@Test
1075+
public void testRegexFindAll() throws Exception {
1076+
assumeFalse(
1077+
"Regexes are not supported against the emulator",
1078+
isRunningAgainstFirestoreEmulator(firestore));
1079+
1080+
List<PipelineResult> results =
1081+
firestore
1082+
.pipeline()
1083+
.createFrom(collection)
1084+
.select(field("title").regexFindAll("\\w+").as("wordsInTitle"))
1085+
.sort(field("wordsInTitle").ascending())
1086+
.limit(3)
1087+
.execute()
1088+
.get()
1089+
.getResults();
1090+
1091+
assertThat(data(results))
1092+
.isEqualTo(
1093+
Lists.newArrayList(
1094+
map("wordsInTitle", Lists.newArrayList("1984")),
1095+
map("wordsInTitle", Lists.newArrayList("Crime", "and", "Punishment")),
1096+
map("wordsInTitle", Lists.newArrayList("Dune"))));
1097+
}
1098+
10491099
@Test
10501100
public void testRegexMatches() throws Exception {
10511101
assumeFalse(

samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,6 +1257,32 @@ void regexContainsFunction() throws ExecutionException, InterruptedException {
12571257
System.out.println(result.getResults());
12581258
}
12591259

1260+
void regexFindFunction() throws ExecutionException, InterruptedException {
1261+
// [START regex_find]
1262+
Pipeline.Snapshot result =
1263+
firestore
1264+
.pipeline()
1265+
.collection("documents")
1266+
.select(regexFind(field("email"), "@[A-Za-z0-9.-]+").as("domain"))
1267+
.execute()
1268+
.get();
1269+
// [END regex_find]
1270+
System.out.println(result.getResults());
1271+
}
1272+
1273+
void regexFindAllFunction() throws ExecutionException, InterruptedException {
1274+
// [START regex_find_all]
1275+
Pipeline.Snapshot result =
1276+
firestore
1277+
.pipeline()
1278+
.collection("documents")
1279+
.select(regexFindAll(field("comment"), "@[A-Za-z0-9_]+").as("mentions"))
1280+
.execute()
1281+
.get();
1282+
// [END regex_find_all]
1283+
System.out.println(result.getResults());
1284+
}
1285+
12601286
void regexMatchFunction() throws ExecutionException, InterruptedException {
12611287
// [START regex_match]
12621288
Pipeline.Snapshot result =

0 commit comments

Comments
 (0)