From d21171901383ab1219f150a579a1a67f31ade350 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Thu, 26 Feb 2026 14:20:41 -0500 Subject: [PATCH 1/6] wip --- .../pipeline/expressions/Expression.java | 510 ++++++++++++++++++ .../cloud/firestore/it/ITPipelineTest.java | 173 ++++++ 2 files changed, 683 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 363046c39..d94ca0140 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 @@ -1692,6 +1692,360 @@ public static Expression trimValue(String fieldName, Expression characters) { return trimValue(field(fieldName), characters); } + /** + * Creates an expression that removes whitespace from the beginning of a string or byte array. + * + * @param value The expression representing the string or blob to trim. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public static Expression ltrim(Expression value) { + return new FunctionExpression("ltrim", ImmutableList.of(value)); + } + + /** + * Creates an expression that removes leading and trailing whitespace from a string field. + * + * @param fieldName The name of the field containing the string to trim. + * @return A new {@link Expression} representing the trimmed string. + */ + @BetaApi + public static Expression ltrim(String fieldName) { + return ltrim(field(fieldName)); + } + + /** + * Creates an expression that removes specified characters from the beginning of a string + * or blob. + * + * @param value The expression representing the string or blob to trim. + * @param characters The characters to remove. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public static Expression ltrimValue(Expression value, String characters) { + return new FunctionExpression("ltrim", ImmutableList.of(value, constant(characters))); + } + + /** + * Creates an expression that removes specified characters from the beginning of a string + * or blob. + * + * @param fieldName The name of the field containing the string or blob to trim. + * @param characters The characters to remove. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public static Expression ltrimValue(String fieldName, String characters) { + return ltrimValue(field(fieldName), characters); + } + + /** + * Creates an expression that removes specified characters from the beginning of a string + * or blob. + * + * @param value The expression representing the string or blob to trim. + * @param characters The expression representing the characters to remove. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public static Expression ltrimValue(Expression value, Expression characters) { + return new FunctionExpression("ltrim", ImmutableList.of(value, characters)); + } + + /** + * Creates an expression that removes specified characters from the beginning of a string + * or blob. + * + * @param fieldName The name of the field containing the string or blob to trim. + * @param characters The expression representing the characters to remove. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public static Expression ltrimValue(String fieldName, Expression characters) { + return ltrimValue(field(fieldName), characters); + } + + /** + * Creates an expression that removes whitespace from the end of a string or byte array. + * + * @param value The expression representing the string or blob to trim. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public static Expression rtrim(Expression value) { + return new FunctionExpression("rtrim", ImmutableList.of(value)); + } + + /** + * Creates an expression that removes trailing whitespace from a string or byte field. + * + * @param fieldName The name of the field containing the string to trim. + * @return A new {@link Expression} representing the trimmed string. + */ + @BetaApi + public static Expression rtrim(String fieldName) { + return rtrim(field(fieldName)); + } + + /** + * Creates an expression that removes specified characters from the end of a string + * or blob. + * + * @param value The expression representing the string or blob to trim. + * @param characters The characters to remove. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public static Expression rtrimValue(Expression value, String characters) { + return new FunctionExpression("rtrim", ImmutableList.of(value, constant(characters))); + } + + /** + * Creates an expression that removes specified characters from the end of a string + * or blob. + * + * @param fieldName The name of the field containing the string or blob to trim. + * @param characters The characters to remove. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public static Expression rtrimValue(String fieldName, String characters) { + return rtrimValue(field(fieldName), characters); + } + + /** + * Creates an expression that removes specified characters from the end of a string + * or blob. + * + * @param value The expression representing the string or blob to trim. + * @param characters The expression representing the characters to remove. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public static Expression rtrimValue(Expression value, Expression characters) { + return new FunctionExpression("rtrim", ImmutableList.of(value, characters)); + } + + /** + * Creates an expression that removes specified characters from the end of a string + * or blob. + * + * @param fieldName The name of the field containing the string or blob to trim. + * @param characters The expression representing the characters to remove. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public static Expression rtrimValue(String fieldName, Expression characters) { + return trimValue(field(fieldName), characters); + } + + /** + * Creates an expression that repeats a string or byte array a specified number of times. + * + * @param value The expression representing the string or byte array to repeat. + * @param repetitions The number of times to repeat the string or byte array. + * @return A new {@link Expression} representing the repeated string or byte array. + */ + @BetaApi + public static Expression stringRepeat(Expression value, Number repetitions) { + return new FunctionExpression("string_repeat", ImmutableList.of(value, constant(repetitions))); + } + + /** + * Creates an expression that repeats a string or byte array a specified number of times. + * + * @param fieldName The name of the field containing the string or byte array to repeat. + * @param repetitions The number of times to repeat the string or byte array. + * @return A new {@link Expression} representing the repeated string or byte array. + */ + @BetaApi + public static Expression stringRepeat(String fieldName, Number repetitions) { + return stringRepeat(field(fieldName), repetitions); + } + + /** + * Creates an expression that repeats a string or byte array a specified number of times. + * + * @param value The expression representing the string or byte array to repeat. + * @param repetitions The expression representing the number of times to repeat. + * @return A new {@link Expression} representing the repeated string or byte array. + */ + @BetaApi + public static Expression stringRepeat(Expression value, Expression repetitions) { + return new FunctionExpression("string_repeat", ImmutableList.of(value, repetitions)); + } + + /** + * Creates an expression that repeats a string or byte array a specified number of times. + * + * @param fieldName The name of the field containing the string or byte array to repeat. + * @param repetitions The expression representing the number of times to repeat. + * @return A new {@link Expression} representing the repeated string or byte array. + */ + @BetaApi + public static Expression stringRepeat(String fieldName, Expression repetitions) { + return stringRepeat(field(fieldName), repetitions); + } + + /** + * Creates an expression that replaces all occurrences of a substring or byte sequence. + * + * @param value The expression representing the input string or byte array. + * @param find The match pattern. + * @param replacement The replacement string/bytes. + * @return A new {@link Expression} representing the replaced value. + */ + @BetaApi + public static Expression stringReplaceAll(Expression value, String find, String replacement) { + return new FunctionExpression( + "string_replace_all", ImmutableList.of(value, constant(find), constant(replacement))); + } + + /** + * Creates an expression that replaces all occurrences of a substring or byte sequence. + * + * @param fieldName The name of the field containing the input string or byte array. + * @param find The match pattern. + * @param replacement The replacement string/bytes. + * @return A new {@link Expression} representing the replaced value. + */ + @BetaApi + public static Expression stringReplaceAll(String fieldName, String find, String replacement) { + return stringReplaceAll(field(fieldName), find, replacement); + } + + /** + * Creates an expression that replaces all occurrences of a substring or byte sequence. + * + * @param value The expression representing the input string or byte array. + * @param find The expression representing the match pattern. + * @param replacement The expression representing the replacement value. + * @return A new {@link Expression} representing the replaced value. + */ + @BetaApi + public static Expression stringReplaceAll( + Expression value, Expression find, Expression replacement) { + return new FunctionExpression("string_replace_all", ImmutableList.of(value, find, replacement)); + } + + /** + * Creates an expression that replaces all occurrences of a substring or byte sequence. + * + * @param fieldName The name of the field containing the input string or byte array. + * @param find The expression representing the match pattern. + * @param replacement The expression representing the replacement value. + * @return A new {@link Expression} representing the replaced value. + */ + @BetaApi + public static Expression stringReplaceAll( + String fieldName, Expression find, Expression replacement) { + return stringReplaceAll(field(fieldName), find, replacement); + } + + /** + * Creates an expression that replaces the first occurrence of a substring or byte sequence. + * + * @param value The expression representing the input string or byte array. + * @param find The match pattern. + * @param replacement The replacement string/bytes. + * @return A new {@link Expression} representing the replaced value. + */ + @BetaApi + public static Expression stringReplaceOne(Expression value, String find, String replacement) { + return new FunctionExpression( + "string_replace_one", ImmutableList.of(value, constant(find), constant(replacement))); + } + + /** + * Creates an expression that replaces the first occurrence of a substring or byte sequence. + * + * @param fieldName The name of the field containing the input string or byte array. + * @param find The match pattern. + * @param replacement The replacement string/bytes. + * @return A new {@link Expression} representing the replaced value. + */ + @BetaApi + public static Expression stringReplaceOne(String fieldName, String find, String replacement) { + return stringReplaceOne(field(fieldName), find, replacement); + } + + /** + * Creates an expression that replaces the first occurrence of a substring or byte sequence. + * + * @param value The expression representing the input string or byte array. + * @param find The expression representing the match pattern. + * @param replacement The expression representing the replacement value. + * @return A new {@link Expression} representing the replaced value. + */ + @BetaApi + public static Expression stringReplaceOne( + Expression value, Expression find, Expression replacement) { + return new FunctionExpression("string_replace_one", ImmutableList.of(value, find, replacement)); + } + + /** + * Creates an expression that replaces the first occurrence of a substring or byte sequence. + * + * @param fieldName The name of the field containing the input string or byte array. + * @param find The expression representing the match pattern. + * @param replacement The expression representing the replacement value. + * @return A new {@link Expression} representing the replaced value. + */ + @BetaApi + public static Expression stringReplaceOne( + String fieldName, Expression find, Expression replacement) { + return stringReplaceOne(field(fieldName), find, replacement); + } + + /** + * Creates an expression that returns the index of the first occurrence of a substring or bytes. + * + * @param value The expression representing the input string or byte array. + * @param search The search pattern. + * @return A new {@link Expression} representing the index. + */ + @BetaApi + public static Expression stringIndexOf(Expression value, String search) { + return new FunctionExpression("string_index_of", ImmutableList.of(value, constant(search))); + } + + /** + * Creates an expression that returns the index of the first occurrence of a substring or bytes. + * + * @param fieldName The name of the field containing the input string or byte array. + * @param search The search pattern. + * @return A new {@link Expression} representing the index. + */ + @BetaApi + public static Expression stringIndexOf(String fieldName, String search) { + return stringIndexOf(field(fieldName), search); + } + + /** + * Creates an expression that returns the index of the first occurrence of a substring or bytes. + * + * @param value The expression representing the input string or byte array. + * @param search The expression representing the search pattern. + * @return A new {@link Expression} representing the index. + */ + @BetaApi + public static Expression stringIndexOf(Expression value, Expression search) { + return new FunctionExpression("string_index_of", ImmutableList.of(value, search)); + } + + /** + * Creates an expression that returns the index of the first occurrence of a substring or bytes. + * + * @param fieldName The name of the field containing the input string or byte array. + * @param search The expression representing the search pattern. + * @return A new {@link Expression} representing the index. + */ + @BetaApi + public static Expression stringIndexOf(String fieldName, Expression search) { + return stringIndexOf(field(fieldName), search); + } + /** * Creates an expression that splits a string or blob by a delimiter. * @@ -4141,6 +4495,162 @@ public Expression trimValue(Expression characters) { return trimValue(this, characters); } + /** + * Creates an expression that removes whitespace from the beginning of this string or blob expression. + * + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public Expression ltrim() { + return ltrimValue(this); + } + + /** + * Creates an expression that removes the specified set of characters from the beginning of this string or blob expression. + * + * @param characters The characters to remove. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public Expression ltrimValue(String characters) { + return ltrimValue(this, characters); + } + + /** + * Creates an expression that removes the specified characters or bytes from the beginning of this string or blob expression. + * + * @param characters The expression representing the characters or bytes to remove. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public Expression ltrimValue(Expression characters) { + return ltrimValue(this, characters); + } + + /** + * Creates an expression that removes whitespace from the end of this string or blob expression. + * + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public Expression rtrim() { + return rtrim(this); + } + + /** + * Creates an expression that removes the specified set of characters from the end of this string or blob expression. + * + * @param characters The characters to remove. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public Expression rtrimValue(String characters) { + return rtrimValue(this, characters); + } + + /** + * Creates an expression that removes the specified characters or bytes from the end of this string or blob expression. + * + * @param characters The expression representing the characters or bytes to remove. + * @return A new {@link Expression} representing the trimmed string or blob. + */ + @BetaApi + public Expression rtrimValue(Expression characters) { + return rtrimValue(this, characters); + } + + /** + * Creates an expression that repeats a string or byte array a specified number of times. + * + * @param repetitions The number of times to repeat the string or byte array. + * @return A new {@link Expression} representing the repeated string or byte array. + */ + @BetaApi + public Expression stringRepeat(Number repetitions) { + return stringRepeat(this, repetitions); + } + + /** + * Creates an expression that repeats a string or byte array a specified number of times. + * + * @param repetitions The expression representing the number of times to repeat. + * @return A new {@link Expression} representing the repeated string or byte array. + */ + @BetaApi + public Expression stringRepeat(Expression repetitions) { + return stringRepeat(this, repetitions); + } + + /** + * Creates an expression that replaces all occurrences of a substring or byte sequence. + * + * @param find The match pattern. + * @param replacement The replacement string/bytes. + * @return A new {@link Expression} representing the replaced value. + */ + @BetaApi + public Expression stringReplaceAll(String find, String replacement) { + return stringReplaceAll(this, find, replacement); + } + + /** + * Creates an expression that replaces all occurrences of a substring or byte sequence. + * + * @param find The expression representing the match pattern. + * @param replacement The expression representing the replacement value. + * @return A new {@link Expression} representing the replaced value. + */ + @BetaApi + public Expression stringReplaceAll(Expression find, Expression replacement) { + return stringReplaceAll(this, find, replacement); + } + + /** + * Creates an expression that replaces the first occurrence of a substring or byte sequence. + * + * @param find The match pattern. + * @param replacement The replacement string/bytes. + * @return A new {@link Expression} representing the replaced value. + */ + @BetaApi + public Expression stringReplaceOne(String find, String replacement) { + return stringReplaceOne(this, find, replacement); + } + + /** + * Creates an expression that replaces the first occurrence of a substring or byte sequence. + * + * @param find The expression representing the match pattern. + * @param replacement The expression representing the replacement value. + * @return A new {@link Expression} representing the replaced value. + */ + @BetaApi + public Expression stringReplaceOne(Expression find, Expression replacement) { + return stringReplaceOne(this, find, replacement); + } + + /** + * Creates an expression that returns the index of the first occurrence of a substring or bytes. + * + * @param search The search pattern. + * @return A new {@link Expression} representing the index. + */ + @BetaApi + public Expression stringIndexOf(String search) { + return stringIndexOf(this, search); + } + + /** + * Creates an expression that returns the index of the first occurrence of a substring or bytes. + * + * @param search The expression representing the search pattern. + * @return A new {@link Expression} representing the index. + */ + @BetaApi + public Expression stringIndexOf(Expression search) { + return stringIndexOf(this, search); + } + /** * Creates an expression that splits this string or blob expression by a delimiter. * 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 5f810332f..3f0b148f3 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 @@ -48,6 +48,7 @@ import static com.google.cloud.firestore.pipeline.expressions.Expression.lessThan; import static com.google.cloud.firestore.pipeline.expressions.Expression.ln; import static com.google.cloud.firestore.pipeline.expressions.Expression.log; +import static com.google.cloud.firestore.pipeline.expressions.Expression.ltrim; import static com.google.cloud.firestore.pipeline.expressions.Expression.logicalMaximum; import static com.google.cloud.firestore.pipeline.expressions.Expression.logicalMinimum; import static com.google.cloud.firestore.pipeline.expressions.Expression.mapMerge; @@ -58,6 +59,7 @@ import static com.google.cloud.firestore.pipeline.expressions.Expression.pow; import static com.google.cloud.firestore.pipeline.expressions.Expression.regexMatch; import static com.google.cloud.firestore.pipeline.expressions.Expression.round; +import static com.google.cloud.firestore.pipeline.expressions.Expression.rtrim; import static com.google.cloud.firestore.pipeline.expressions.Expression.sqrt; import static com.google.cloud.firestore.pipeline.expressions.Expression.startsWith; import static com.google.cloud.firestore.pipeline.expressions.Expression.stringConcat; @@ -1008,6 +1010,177 @@ public void testTrimWithCharacters() throws Exception { "The Hitchhiker's Guide to the Galaxy"))); } + @Test + public void testLTrim() throws Exception { + List results = + firestore + .pipeline() + .createFrom(collection) + .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) + .addFields(constant(" The Hitchhiker's Guide to the Galaxy ").as("spacedTitle")) + .addFields(constant("\"alice\"").as("userNameWithQuotes")) + .addFields(constant(Blob.fromBytes(new byte[] {0x00, 0x01, 0x02, 0x00, 0x00})).as("bytes")) + .select( + ltrim("spacedTitle").as("ltrimmedTitle"), + field("userNameWithQuotes").ltrim("\"").as("userName"), + field("bytes") + .ltrim(constant(Blob.fromBytes(new byte[] {0x00}))) + .as("bytes")) + .limit(1) + .execute() + .get() + .getResults(); + + assertThat(data(results)) + .isEqualTo( + Lists.newArrayList( + map( + "ltrimmedTitle", "The Hitchhiker's Guide to the Galaxy ", + "userName", "alice\"", + "bytes", Blob.fromBytes(new byte[] {0x01, 0x02, 0x00, 0x00})))); + } + + @Test + public void testRTrim() throws Exception { + List results = + firestore + .pipeline() + .createFrom(collection) + .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) + .addFields(constant(" The Hitchhiker's Guide to the Galaxy ").as("spacedTitle")) + .addFields(constant("\"alice\"").as("userNameWithQuotes")) + .addFields(constant(Blob.fromBytes(new byte[] {0x00, 0x01, 0x02, 0x00, 0x00})).as("bytes")) + .select( + rtrim("spacedTitle").as("rtrimmedTitle"), + field("userNameWithQuotes").rtrim("\"").as("userName"), + field("bytes") + .rtrim(constant(Blob.fromBytes(new byte[] {0x00}))) + .as("bytes")) + .limit(1) + .execute() + .get() + .getResults(); + + assertThat(data(results)) + .isEqualTo( + Lists.newArrayList( + map( + "rtrimmedTitle", " The Hitchhiker's Guide to the Galaxy", + "userName", "\"alice", + "bytes", Blob.fromBytes(new byte[] {0x00, 0x01, 0x02})))); + } + + @Test + public void testStringRepeat() throws Exception { + List results = + firestore + .pipeline() + .createFrom(collection) + .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) + .addFields(constant(Blob.fromBytes(new byte[] {0x01, 0x02, 0x03})).as("bytes")) + .select( + field("title").stringRepeat(2).as("repeatedTitle"), + Expression.stringRepeat(field("title"), 2).as("repeatedTitleStatic"), + field("bytes").stringRepeat(2).as("repeatedBytes")) + .limit(1) + .execute() + .get() + .getResults(); + + assertThat(data(results)) + .isEqualTo( + Lists.newArrayList( + map( + "repeatedTitle", + "The Hitchhiker's Guide to the GalaxyThe Hitchhiker's Guide to the Galaxy", + "repeatedTitleStatic", + "The Hitchhiker's Guide to the GalaxyThe Hitchhiker's Guide to the Galaxy", + "repeatedBytes", + Blob.fromBytes(new byte[] {0x01, 0x02, 0x03, 0x01, 0x02, 0x03})))); + } + + @Test + public void testStringReplaceAll() throws Exception { + List results = + firestore + .pipeline() + .createFrom(collection) + .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) + .addFields(constant(Blob.fromBytes(new byte[] {0x01, 0x02, 0x02})).as("bytes")) + .select( + field("title").stringReplaceAll("e", "X").as("replacedAll"), + Expression.stringReplaceAll(field("title"), "e", "X").as("replacedAllStatic"), + field("bytes").stringReplaceAll(constant(Blob.fromBytes(new byte[] {0x02})), constant(Blob.fromBytes(new byte[] {0x03}))).as("replacedMultipleBytes") + ) + .limit(1) + .execute() + .get() + .getResults(); + + assertThat(data(results)) + .isEqualTo( + Lists.newArrayList( + map( + "replacedAll", "ThX HitchhikXr's GuidX to thX Galaxy", + "replacedAllStatic", "ThX HitchhikXr's GuidX to thX Galaxy", + "replacedMultipleBytes", Blob.fromBytes(new byte[] {0x01, 0x03, 0x03}) + ) + ) + ); + } + + @Test + public void testStringReplaceOne() throws Exception { + List results = + firestore + .pipeline() + .createFrom(collection) + .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) + .addFields(constant(Blob.fromBytes(new byte[] {0x01, 0x02, 0x02})).as("bytes")) + .select( + field("title").stringReplaceOne("e", "X").as("replacedOne"), + Expression.stringReplaceOne("title", "e", "X").as("replacedOneStatic"), + field("bytes").stringReplaceOne(constant(Blob.fromBytes(new byte[] {0x02})), constant(Blob.fromBytes(new byte[] {0x03}))).as("replacedOneByte") + ) + .limit(1) + .execute() + .get() + .getResults(); + + assertThat(data(results)) + .isEqualTo( + Lists.newArrayList( + map("replacedOne", "ThX Hitchhiker's Guide to the Galaxy", + "replacedOneStatic", "ThX Hitchhiker's Guide to the Galaxy", + "replacedOneByte", Blob.fromBytes(new byte[] {0x01, 0x03, 0x02})) + ) + ); + } + + @Test + public void testStringIndexOf() throws Exception { + List results = + firestore + .pipeline() + .createFrom(collection) + .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) + .addFields(constant(Blob.fromBytes(new byte[] {0x01, 0x02, 0x03})).as("bytes")) + .select( + field("title").stringIndexOf("Guide").as("indexOfGuide"), + Expression.stringIndexOf(field("title"), "Guide").as("indexOfGuideStatic"), + field("bytes") + .stringIndexOf(constant(Blob.fromBytes(new byte[] {0x02}))) + .as("indexOfByte")) + .limit(1) + .execute() + .get() + .getResults(); + + assertThat(data(results)) + .isEqualTo( + Lists.newArrayList(map("indexOfGuide", 17L, "indexOfGuideStatic", 17L, "indexOfByte", 1L))); + } + @Test public void testLike() throws Exception { assumeFalse( From 351f8f66e48179ec8738724ebeb781b30b1d067d Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Thu, 26 Feb 2026 16:25:04 -0500 Subject: [PATCH 2/6] snippets --- .../cloud/firestore/it/ITPipelineTest.java | 24 +++--- .../example/firestore/PipelineSnippets.java | 78 +++++++++++++++++++ 2 files changed, 91 insertions(+), 11 deletions(-) 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 3f0b148f3..05d93b65b 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 @@ -1121,12 +1121,12 @@ public void testStringReplaceAll() throws Exception { .isEqualTo( Lists.newArrayList( map( - "replacedAll", "ThX HitchhikXr's GuidX to thX Galaxy", - "replacedAllStatic", "ThX HitchhikXr's GuidX to thX Galaxy", - "replacedMultipleBytes", Blob.fromBytes(new byte[] {0x01, 0x03, 0x03}) - ) - ) - ); + "replacedAll", + "ThX HitchhikXr's GuidX to thX Galaxy", + "replacedAllStatic", + "ThX HitchhikXr's GuidX to thX Galaxy", + "replacedMultipleBytes", + Blob.fromBytes(new byte[] {0x01, 0x03, 0x03})))); } @Test @@ -1150,11 +1150,13 @@ public void testStringReplaceOne() throws Exception { assertThat(data(results)) .isEqualTo( Lists.newArrayList( - map("replacedOne", "ThX Hitchhiker's Guide to the Galaxy", - "replacedOneStatic", "ThX Hitchhiker's Guide to the Galaxy", - "replacedOneByte", Blob.fromBytes(new byte[] {0x01, 0x03, 0x02})) - ) - ); + map( + "replacedOne", + "ThX Hitchhiker's Guide to the Galaxy", + "replacedOneStatic", + "ThX Hitchhiker's Guide to the Galaxy", + "replacedOneByte", + Blob.fromBytes(new byte[] {0x01, 0x03, 0x02})))); } @Test 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 cf6efe72d..328a65cfb 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 @@ -1392,6 +1392,84 @@ void strTrimFunction() throws ExecutionException, InterruptedException { System.out.println(result.getResults()); } + void strLTrimFunction() throws ExecutionException, InterruptedException { + // [START ltrim_function] + Pipeline.Snapshot result = + firestore + .pipeline() + .collection("books") + .select(ltrim(field("name")).as("ltrimmedName")) + .execute() + .get(); + // [END ltrim_function] + System.out.println(result.getResults()); + } + + void strRTrimFunction() throws ExecutionException, InterruptedException { + // [START rtrim_function] + Pipeline.Snapshot result = + firestore + .pipeline() + .collection("books") + .select(rtrim(field("name")).as("rtrimmedName")) + .execute() + .get(); + // [END rtrim_function] + System.out.println(result.getResults()); + } + + void strRepeatFunction() throws ExecutionException, InterruptedException { + // [START string_repeat_function] + Pipeline.Snapshot result = + firestore + .pipeline() + .collection("books") + .select(stringRepeat(field("title"), 2).as("repeatedTitle")) + .execute() + .get(); + // [END string_repeat_function] + System.out.println(result.getResults()); + } + + void strReplaceAllFunction() throws ExecutionException, InterruptedException { + // [START string_replace_all_function] + Pipeline.Snapshot result = + firestore + .pipeline() + .collection("books") + .select(stringReplaceAll(field("title"), "The", "A").as("replacedTitle")) + .execute() + .get(); + // [END string_replace_all_function] + System.out.println(result.getResults()); + } + + void strReplaceOneFunction() throws ExecutionException, InterruptedException { + // [START string_replace_one_function] + Pipeline.Snapshot result = + firestore + .pipeline() + .collection("books") + .select(stringReplaceOne(field("title"), "The", "A").as("replacedTitle")) + .execute() + .get(); + // [END string_replace_one_function] + System.out.println(result.getResults()); + } + + void strIndexOfFunction() throws ExecutionException, InterruptedException { + // [START string_index_of_function] + Pipeline.Snapshot result = + firestore + .pipeline() + .collection("books") + .select(stringIndexOf(field("title"), "The").as("indexOfThe")) + .execute() + .get(); + // [END string_index_of_function] + System.out.println(result.getResults()); + } + void unixMicrosToTimestampFunction() throws ExecutionException, InterruptedException { // [START unix_micros_timestamp] Pipeline.Snapshot result = From eba774872920516f68612ed51390c00b822635c1 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Thu, 26 Feb 2026 16:25:51 -0500 Subject: [PATCH 3/6] ltrimvalue! --- .../com/google/cloud/firestore/it/ITPipelineTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 05d93b65b..d003e8fa7 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 @@ -1022,9 +1022,9 @@ public void testLTrim() throws Exception { .addFields(constant(Blob.fromBytes(new byte[] {0x00, 0x01, 0x02, 0x00, 0x00})).as("bytes")) .select( ltrim("spacedTitle").as("ltrimmedTitle"), - field("userNameWithQuotes").ltrim("\"").as("userName"), + field("userNameWithQuotes").ltrimValue("\"").as("userName"), field("bytes") - .ltrim(constant(Blob.fromBytes(new byte[] {0x00}))) + .ltrimValue(constant(Blob.fromBytes(new byte[] {0x00}))) .as("bytes")) .limit(1) .execute() @@ -1052,9 +1052,9 @@ public void testRTrim() throws Exception { .addFields(constant(Blob.fromBytes(new byte[] {0x00, 0x01, 0x02, 0x00, 0x00})).as("bytes")) .select( rtrim("spacedTitle").as("rtrimmedTitle"), - field("userNameWithQuotes").rtrim("\"").as("userName"), + field("userNameWithQuotes").rtrimValue("\"").as("userName"), field("bytes") - .rtrim(constant(Blob.fromBytes(new byte[] {0x00}))) + .rtrimValue(constant(Blob.fromBytes(new byte[] {0x00}))) .as("bytes")) .limit(1) .execute() From 0bfe8c81f809c29ff92d9e40a609e4d738aee183 Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Thu, 26 Feb 2026 21:29:43 +0000 Subject: [PATCH 4/6] chore: generate libraries at Thu Feb 26 21:26:53 UTC 2026 --- .../pipeline/expressions/Expression.java | 53 +++++++++---------- .../cloud/firestore/it/ITPipelineTest.java | 33 +++++++----- 2 files changed, 44 insertions(+), 42 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 d94ca0140..852e3ed50 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 @@ -1715,8 +1715,7 @@ public static Expression ltrim(String fieldName) { } /** - * Creates an expression that removes specified characters from the beginning of a string - * or blob. + * Creates an expression that removes specified characters from the beginning of a string or blob. * * @param value The expression representing the string or blob to trim. * @param characters The characters to remove. @@ -1728,8 +1727,7 @@ public static Expression ltrimValue(Expression value, String characters) { } /** - * Creates an expression that removes specified characters from the beginning of a string - * or blob. + * Creates an expression that removes specified characters from the beginning of a string or blob. * * @param fieldName The name of the field containing the string or blob to trim. * @param characters The characters to remove. @@ -1741,8 +1739,7 @@ public static Expression ltrimValue(String fieldName, String characters) { } /** - * Creates an expression that removes specified characters from the beginning of a string - * or blob. + * Creates an expression that removes specified characters from the beginning of a string or blob. * * @param value The expression representing the string or blob to trim. * @param characters The expression representing the characters to remove. @@ -1754,8 +1751,7 @@ public static Expression ltrimValue(Expression value, Expression characters) { } /** - * Creates an expression that removes specified characters from the beginning of a string - * or blob. + * Creates an expression that removes specified characters from the beginning of a string or blob. * * @param fieldName The name of the field containing the string or blob to trim. * @param characters The expression representing the characters to remove. @@ -1789,8 +1785,7 @@ public static Expression rtrim(String fieldName) { } /** - * Creates an expression that removes specified characters from the end of a string - * or blob. + * Creates an expression that removes specified characters from the end of a string or blob. * * @param value The expression representing the string or blob to trim. * @param characters The characters to remove. @@ -1802,8 +1797,7 @@ public static Expression rtrimValue(Expression value, String characters) { } /** - * Creates an expression that removes specified characters from the end of a string - * or blob. + * Creates an expression that removes specified characters from the end of a string or blob. * * @param fieldName The name of the field containing the string or blob to trim. * @param characters The characters to remove. @@ -1815,8 +1809,7 @@ public static Expression rtrimValue(String fieldName, String characters) { } /** - * Creates an expression that removes specified characters from the end of a string - * or blob. + * Creates an expression that removes specified characters from the end of a string or blob. * * @param value The expression representing the string or blob to trim. * @param characters The expression representing the characters to remove. @@ -1828,8 +1821,7 @@ public static Expression rtrimValue(Expression value, Expression characters) { } /** - * Creates an expression that removes specified characters from the end of a string - * or blob. + * Creates an expression that removes specified characters from the end of a string or blob. * * @param fieldName The name of the field containing the string or blob to trim. * @param characters The expression representing the characters to remove. @@ -4496,8 +4488,9 @@ public Expression trimValue(Expression characters) { } /** - * Creates an expression that removes whitespace from the beginning of this string or blob expression. - * + * Creates an expression that removes whitespace from the beginning of this string or blob + * expression. + * * @return A new {@link Expression} representing the trimmed string or blob. */ @BetaApi @@ -4506,8 +4499,9 @@ public Expression ltrim() { } /** - * Creates an expression that removes the specified set of characters from the beginning of this string or blob expression. - * + * Creates an expression that removes the specified set of characters from the beginning of this + * string or blob expression. + * * @param characters The characters to remove. * @return A new {@link Expression} representing the trimmed string or blob. */ @@ -4517,8 +4511,9 @@ public Expression ltrimValue(String characters) { } /** - * Creates an expression that removes the specified characters or bytes from the beginning of this string or blob expression. - * + * Creates an expression that removes the specified characters or bytes from the beginning of this + * string or blob expression. + * * @param characters The expression representing the characters or bytes to remove. * @return A new {@link Expression} representing the trimmed string or blob. */ @@ -4527,9 +4522,9 @@ public Expression ltrimValue(Expression characters) { return ltrimValue(this, characters); } - /** + /** * Creates an expression that removes whitespace from the end of this string or blob expression. - * + * * @return A new {@link Expression} representing the trimmed string or blob. */ @BetaApi @@ -4538,8 +4533,9 @@ public Expression rtrim() { } /** - * Creates an expression that removes the specified set of characters from the end of this string or blob expression. - * + * Creates an expression that removes the specified set of characters from the end of this string + * or blob expression. + * * @param characters The characters to remove. * @return A new {@link Expression} representing the trimmed string or blob. */ @@ -4549,8 +4545,9 @@ public Expression rtrimValue(String characters) { } /** - * Creates an expression that removes the specified characters or bytes from the end of this string or blob expression. - * + * Creates an expression that removes the specified characters or bytes from the end of this + * string or blob expression. + * * @param characters The expression representing the characters or bytes to remove. * @return A new {@link Expression} representing the trimmed string or blob. */ 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 d003e8fa7..5de0a74c4 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 @@ -48,9 +48,9 @@ import static com.google.cloud.firestore.pipeline.expressions.Expression.lessThan; import static com.google.cloud.firestore.pipeline.expressions.Expression.ln; import static com.google.cloud.firestore.pipeline.expressions.Expression.log; -import static com.google.cloud.firestore.pipeline.expressions.Expression.ltrim; import static com.google.cloud.firestore.pipeline.expressions.Expression.logicalMaximum; import static com.google.cloud.firestore.pipeline.expressions.Expression.logicalMinimum; +import static com.google.cloud.firestore.pipeline.expressions.Expression.ltrim; import static com.google.cloud.firestore.pipeline.expressions.Expression.mapMerge; import static com.google.cloud.firestore.pipeline.expressions.Expression.mapRemove; import static com.google.cloud.firestore.pipeline.expressions.Expression.notEqual; @@ -1019,13 +1019,12 @@ public void testLTrim() throws Exception { .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) .addFields(constant(" The Hitchhiker's Guide to the Galaxy ").as("spacedTitle")) .addFields(constant("\"alice\"").as("userNameWithQuotes")) - .addFields(constant(Blob.fromBytes(new byte[] {0x00, 0x01, 0x02, 0x00, 0x00})).as("bytes")) + .addFields( + constant(Blob.fromBytes(new byte[] {0x00, 0x01, 0x02, 0x00, 0x00})).as("bytes")) .select( ltrim("spacedTitle").as("ltrimmedTitle"), field("userNameWithQuotes").ltrimValue("\"").as("userName"), - field("bytes") - .ltrimValue(constant(Blob.fromBytes(new byte[] {0x00}))) - .as("bytes")) + field("bytes").ltrimValue(constant(Blob.fromBytes(new byte[] {0x00}))).as("bytes")) .limit(1) .execute() .get() @@ -1049,13 +1048,12 @@ public void testRTrim() throws Exception { .where(equal("title", "The Hitchhiker's Guide to the Galaxy")) .addFields(constant(" The Hitchhiker's Guide to the Galaxy ").as("spacedTitle")) .addFields(constant("\"alice\"").as("userNameWithQuotes")) - .addFields(constant(Blob.fromBytes(new byte[] {0x00, 0x01, 0x02, 0x00, 0x00})).as("bytes")) + .addFields( + constant(Blob.fromBytes(new byte[] {0x00, 0x01, 0x02, 0x00, 0x00})).as("bytes")) .select( rtrim("spacedTitle").as("rtrimmedTitle"), field("userNameWithQuotes").rtrimValue("\"").as("userName"), - field("bytes") - .rtrimValue(constant(Blob.fromBytes(new byte[] {0x00}))) - .as("bytes")) + field("bytes").rtrimValue(constant(Blob.fromBytes(new byte[] {0x00}))).as("bytes")) .limit(1) .execute() .get() @@ -1110,8 +1108,11 @@ public void testStringReplaceAll() throws Exception { .select( field("title").stringReplaceAll("e", "X").as("replacedAll"), Expression.stringReplaceAll(field("title"), "e", "X").as("replacedAllStatic"), - field("bytes").stringReplaceAll(constant(Blob.fromBytes(new byte[] {0x02})), constant(Blob.fromBytes(new byte[] {0x03}))).as("replacedMultipleBytes") - ) + field("bytes") + .stringReplaceAll( + constant(Blob.fromBytes(new byte[] {0x02})), + constant(Blob.fromBytes(new byte[] {0x03}))) + .as("replacedMultipleBytes")) .limit(1) .execute() .get() @@ -1140,8 +1141,11 @@ public void testStringReplaceOne() throws Exception { .select( field("title").stringReplaceOne("e", "X").as("replacedOne"), Expression.stringReplaceOne("title", "e", "X").as("replacedOneStatic"), - field("bytes").stringReplaceOne(constant(Blob.fromBytes(new byte[] {0x02})), constant(Blob.fromBytes(new byte[] {0x03}))).as("replacedOneByte") - ) + field("bytes") + .stringReplaceOne( + constant(Blob.fromBytes(new byte[] {0x02})), + constant(Blob.fromBytes(new byte[] {0x03}))) + .as("replacedOneByte")) .limit(1) .execute() .get() @@ -1180,7 +1184,8 @@ public void testStringIndexOf() throws Exception { assertThat(data(results)) .isEqualTo( - Lists.newArrayList(map("indexOfGuide", 17L, "indexOfGuideStatic", 17L, "indexOfByte", 1L))); + Lists.newArrayList( + map("indexOfGuide", 17L, "indexOfGuideStatic", 17L, "indexOfByte", 1L))); } @Test From bef60c9bad32cc17b5b780707c643951c35ad614 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Fri, 27 Feb 2026 09:54:19 -0500 Subject: [PATCH 5/6] small fixes --- .../firestore/pipeline/expressions/Expression.java | 12 +++++++----- 1 file changed, 7 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 852e3ed50..488dbfe70 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 @@ -1693,7 +1693,8 @@ public static Expression trimValue(String fieldName, Expression characters) { } /** - * Creates an expression that removes whitespace from the beginning of a string or byte array. + * Creates an expression that removes whitespace from the beginning of a string + * or blob. * * @param value The expression representing the string or blob to trim. * @return A new {@link Expression} representing the trimmed string or blob. @@ -1704,9 +1705,10 @@ public static Expression ltrim(Expression value) { } /** - * Creates an expression that removes leading and trailing whitespace from a string field. + * Creates an expression that removes whitespace from the beginning of a string + * or blob. * - * @param fieldName The name of the field containing the string to trim. + * @param fieldName The name of the field containing the string or blob to trim. * @return A new {@link Expression} representing the trimmed string. */ @BetaApi @@ -1829,7 +1831,7 @@ public static Expression rtrimValue(Expression value, Expression characters) { */ @BetaApi public static Expression rtrimValue(String fieldName, Expression characters) { - return trimValue(field(fieldName), characters); + return rtrimValue(field(fieldName), characters); } /** @@ -4495,7 +4497,7 @@ public Expression trimValue(Expression characters) { */ @BetaApi public Expression ltrim() { - return ltrimValue(this); + return ltrim(this); } /** From 1fb1d9a11e1c827888c0ead6658ce9055d92f91e Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Fri, 27 Feb 2026 14:57:48 +0000 Subject: [PATCH 6/6] chore: generate libraries at Fri Feb 27 14:55:29 UTC 2026 --- .../cloud/firestore/pipeline/expressions/Expression.java | 6 ++---- 1 file changed, 2 insertions(+), 4 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 488dbfe70..6297e14e5 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 @@ -1693,8 +1693,7 @@ public static Expression trimValue(String fieldName, Expression characters) { } /** - * Creates an expression that removes whitespace from the beginning of a string - * or blob. + * Creates an expression that removes whitespace from the beginning of a string or blob. * * @param value The expression representing the string or blob to trim. * @return A new {@link Expression} representing the trimmed string or blob. @@ -1705,8 +1704,7 @@ public static Expression ltrim(Expression value) { } /** - * Creates an expression that removes whitespace from the beginning of a string - * or blob. + * Creates an expression that removes whitespace from the beginning of a string or blob. * * @param fieldName The name of the field containing the string or blob to trim. * @return A new {@link Expression} representing the trimmed string.