From 9eba2231de9fef16514fa50e26826a57d48416bd Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Tue, 3 Feb 2026 10:25:10 -0500 Subject: [PATCH 1/4] feat: add support for `regexFind` and `regexFindAll` Pipeline expressions Adds support for `regexFind` and `regexFindAll` pipeline expressions. --- .../pipeline/expressions/Expression.java | 161 ++++++++++++++++++ .../cloud/firestore/it/ITPipelineTest.java | 50 ++++++ .../example/firestore/PipelineSnippets.java | 28 +++ 3 files changed, 239 insertions(+) diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java index 5443b7513f..10dbedf61b 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java @@ -1228,6 +1228,137 @@ public static BooleanExpression regexContains(String fieldName, String pattern) return regexContains(field(fieldName), constant(pattern)); } + /** + * Creates an expression that returns the first substring of a string expression that matches a + * specified regular expression. + * + *

This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression + * syntax. + * + * @param string The expression representing the string to search. + * @param pattern The regular expression to search for. + * @return A new {@link Expression} representing the regular expression find function. + */ + @BetaApi + public static Expression regexFind(Expression string, Expression pattern) { + return new FunctionExpression("regex_find", ImmutableList.of(string, pattern)); + } + + /** + * Creates an expression that returns the first substring of a string expression that matches a + * specified regular expression. + * + *

This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression + * syntax. + * + * @param string The expression representing the string to search. + * @param pattern The regular expression to search for. + * @return A new {@link Expression} representing the regular expression find function. + */ + @BetaApi + public static Expression regexFind(Expression string, String pattern) { + return regexFind(string, constant(pattern)); + } + + /** + * Creates an expression that returns the first substring of a string field that matches a + * specified regular expression. + * + *

This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression + * syntax. + * + * @param fieldName The name of the field containing the string to search. + * @param pattern The regular expression to search for. + * @return A new {@link Expression} representing the regular expression find function. + */ + @BetaApi + public static Expression regexFind(String fieldName, Expression pattern) { + return regexFind(field(fieldName), pattern); + } + + /** + * Creates an expression that returns the first substring of a string field that matches a + * specified regular expression. + * + *

This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression + * syntax. + * + * @param fieldName The name of the field containing the string to search. + * @param pattern The regular expression to search for. + * @return A new {@link Expression} representing the regular expression find function. + */ + @BetaApi + public static Expression regexFind(String fieldName, String pattern) { + return regexFind(field(fieldName), constant(pattern)); + } + + /** + * Creates an expression that evaluates to a list of all substrings in a string expression that + * match a specified regular expression. + * + *

This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression + * syntax. + * + * @param string The expression representing the string to search. + * @param pattern The regular expression to search for. + * @return A new {@link Expression} that evaluates to a list of matched substrings. + */ + @BetaApi + public static Expression regexFindAll(Expression string, Expression pattern) { + return new FunctionExpression("regex_find_all", ImmutableList.of(string, pattern)); + } + + /** + * Creates an expression that evaluates to a list of all substrings in a string expression that + * match a specified regular expression. + * + *

This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression + * syntax. + * + *

```kotlin // Extract all mentions from a lower-cased comment regexFindAll(field("comment"), + * "@[A-Za-z0-9_]+") ``` + * + * @param string The expression representing the string to search. + * @param pattern The regular expression to search for. + * @return A new {@link Expression} that evaluates to a list of matched substrings. + */ + @BetaApi + public static Expression regexFindAll(Expression string, String pattern) { + return regexFindAll(string, constant(pattern)); + } + + /** + * Creates an expression that evaluates to a list of all substrings in a string field that match a + * specified regular expression. + * + *

This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression + * syntax. + * + * @param fieldName The name of the field containing the string to search. + * @param pattern The regular expression to search for. + * @return A new {@link Expression} that evaluates to a list of matched substrings. + */ + @BetaApi + public static Expression regexFindAll(String fieldName, Expression pattern) { + return regexFindAll(field(fieldName), pattern); + } + + /** + * Creates an expression that evaluates to a list of all substrings in a string field that match a + * specified regular expression. + * + *

This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression + * syntax. + * + * @param fieldName The name of the field containing the string to search. + * @param pattern The regular expression to search for. + * @return A new {@link Expression} that evaluates to a list of matched substrings. + */ + @BetaApi + public static Expression regexFindAll(String fieldName, String pattern) { + return regexFindAll(field(fieldName), constant(pattern)); + } + /** * Creates an expression that checks if a string field matches a specified regular expression. * @@ -3872,6 +4003,36 @@ public final BooleanExpression regexContains(Object pattern) { return regexContains(this, toExprOrConstant(pattern)); } + /** + * Creates an expression that evaluates to a list of all substrings in a string expression that + * match a specified regular expression. + * + *

This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression + * syntax. + * + * @param pattern The regular expression to search for. + * @return A new {@link Expression} representing the regular expression find function. + */ + @BetaApi + public final Expression regexFind(Object pattern) { + return regexFind(this, toExprOrConstant(pattern)); + } + + /** + * Creates an expression that evaluates to a list of all substrings in a string expression that + * match a specified regular expression. + * + *

This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression + * syntax. + * + * @param pattern The regular expression to search for. + * @return A new {@link Expression} that evaluates to a list of matched substrings. + */ + @BetaApi + public final Expression regexFindAll(Object pattern) { + return regexFindAll(this, toExprOrConstant(pattern)); + } + /** * Creates an expression that checks if this string expression matches a specified regular * expression. diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java index 6fd9075b71..5f810332f1 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java @@ -1046,6 +1046,56 @@ public void testRegexContains() throws Exception { assertThat(data(results)).hasSize(5); } + @Test + public void testRegexFind() throws Exception { + assumeFalse( + "Regexes are not supported against the emulator", + isRunningAgainstFirestoreEmulator(firestore)); + + List results = + firestore + .pipeline() + .createFrom(collection) + .select(field("title").regexFind("^\\w+").as("firstWordInTitle")) + .sort(field("firstWordInTitle").ascending()) + .limit(3) + .execute() + .get() + .getResults(); + + assertThat(data(results)) + .isEqualTo( + Lists.newArrayList( + map("firstWordInTitle", "1984"), + map("firstWordInTitle", "Crime"), + map("firstWordInTitle", "Dune"))); + } + + @Test + public void testRegexFindAll() throws Exception { + assumeFalse( + "Regexes are not supported against the emulator", + isRunningAgainstFirestoreEmulator(firestore)); + + List results = + firestore + .pipeline() + .createFrom(collection) + .select(field("title").regexFindAll("\\w+").as("wordsInTitle")) + .sort(field("wordsInTitle").ascending()) + .limit(3) + .execute() + .get() + .getResults(); + + assertThat(data(results)) + .isEqualTo( + Lists.newArrayList( + map("wordsInTitle", Lists.newArrayList("1984")), + map("wordsInTitle", Lists.newArrayList("Crime", "and", "Punishment")), + map("wordsInTitle", Lists.newArrayList("Dune")))); + } + @Test public void testRegexMatches() throws Exception { assumeFalse( diff --git a/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java b/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java index aeb373747c..a54e300b38 100644 --- a/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java +++ b/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java @@ -1257,6 +1257,34 @@ void regexContainsFunction() throws ExecutionException, InterruptedException { System.out.println(result.getResults()); } + void regexFindFunction() throws ExecutionException, InterruptedException { + // [START regex_find] + Pipeline.Snapshot result = + firestore + .pipeline() + .collection("documents") + .select( + regexFind(field("email"), "@[A-Za-z0-9.-]+").as("domain") + ) + .execute() + .get(); + // [END regex_find] + } + + void regexFindAllFunction() throws ExecutionException, InterruptedException { + // [START regex_find_all] + Pipeline.Snapshot result = + firestore + .pipeline() + .collection("documents") + .select( + regexFindAll(field("comment"), "@[A-Za-z0-9_]+").as("mentions") + ) + .execute() + .get(); + // [END regex_find_all] + } + void regexMatchFunction() throws ExecutionException, InterruptedException { // [START regex_match] Pipeline.Snapshot result = From 37a2a142b97d881de223fcd45fffda4e31b87fe3 Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Tue, 3 Feb 2026 15:30:13 +0000 Subject: [PATCH 2/4] chore: generate libraries at Tue Feb 3 15:28:03 UTC 2026 --- .../example/firestore/PipelineSnippets.java | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java b/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java index a54e300b38..89f172bbd2 100644 --- a/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java +++ b/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java @@ -1260,28 +1260,24 @@ void regexContainsFunction() throws ExecutionException, InterruptedException { void regexFindFunction() throws ExecutionException, InterruptedException { // [START regex_find] Pipeline.Snapshot result = - firestore - .pipeline() - .collection("documents") - .select( - regexFind(field("email"), "@[A-Za-z0-9.-]+").as("domain") - ) - .execute() - .get(); + firestore + .pipeline() + .collection("documents") + .select(regexFind(field("email"), "@[A-Za-z0-9.-]+").as("domain")) + .execute() + .get(); // [END regex_find] } void regexFindAllFunction() throws ExecutionException, InterruptedException { // [START regex_find_all] Pipeline.Snapshot result = - firestore - .pipeline() - .collection("documents") - .select( - regexFindAll(field("comment"), "@[A-Za-z0-9_]+").as("mentions") - ) - .execute() - .get(); + firestore + .pipeline() + .collection("documents") + .select(regexFindAll(field("comment"), "@[A-Za-z0-9_]+").as("mentions")) + .execute() + .get(); // [END regex_find_all] } From c97d21fa6e15d746cb7b46e8ef5563aacfb72165 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Tue, 17 Feb 2026 12:21:06 -0500 Subject: [PATCH 3/4] review fixes --- .../cloud/firestore/pipeline/expressions/Expression.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java index 10dbedf61b..363046c39c 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/pipeline/expressions/Expression.java @@ -1315,9 +1315,6 @@ public static Expression regexFindAll(Expression string, Expression pattern) { *

This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression * syntax. * - *

```kotlin // Extract all mentions from a lower-cased comment regexFindAll(field("comment"), - * "@[A-Za-z0-9_]+") ``` - * * @param string The expression representing the string to search. * @param pattern The regular expression to search for. * @return A new {@link Expression} that evaluates to a list of matched substrings. @@ -4004,8 +4001,8 @@ public final BooleanExpression regexContains(Object pattern) { } /** - * Creates an expression that evaluates to a list of all substrings in a string expression that - * match a specified regular expression. + * Creates an expression that returns the first substring of a string expression that matches a + * specified regular expression. * *

This expression uses the [RE2](https://github.com/google/re2/wiki/Syntax) regular expression * syntax. From 97592eead82948ca39437d1fb5a08c420321ea68 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Tue, 17 Feb 2026 12:22:28 -0500 Subject: [PATCH 4/4] add print to new snippets --- .../src/main/java/com/example/firestore/PipelineSnippets.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java b/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java index 89f172bbd2..cf6efe72d1 100644 --- a/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java +++ b/samples/preview-snippets/src/main/java/com/example/firestore/PipelineSnippets.java @@ -1267,6 +1267,7 @@ void regexFindFunction() throws ExecutionException, InterruptedException { .execute() .get(); // [END regex_find] + System.out.println(result.getResults()); } void regexFindAllFunction() throws ExecutionException, InterruptedException { @@ -1279,6 +1280,7 @@ void regexFindAllFunction() throws ExecutionException, InterruptedException { .execute() .get(); // [END regex_find_all] + System.out.println(result.getResults()); } void regexMatchFunction() throws ExecutionException, InterruptedException {