Skip to content

Commit 538a9f6

Browse files
committed
ESQL: Add url_encode function
- Rename the capability to exclude the decoding portion, since this PR is only concerned with encoding. - Mark url_encode as SNAPSHOT to allow changes in encoding logic. - Add tests that use random strings to test a wide range of characters, that run alongside the ones that use random URLs. - Minor change in the sample csv test string to showcase a fictional URL with path and few query params.
1 parent 561da2e commit 538a9f6

File tree

9 files changed

+71
-36
lines changed

9 files changed

+71
-36
lines changed

docs/changelog/132869.yaml

Lines changed: 0 additions & 5 deletions
This file was deleted.

docs/reference/query-languages/esql/_snippets/functions/examples/url_encode.md

Lines changed: 4 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/query-languages/esql/kibana/definition/functions/url_encode.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/query-languages/esql/kibana/docs/functions/url_encode.md

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/plugin/esql/qa/testFixtures/src/main/resources/string.csv-spec

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2467,34 +2467,33 @@ warning:Line 2:9: java.lang.IllegalArgumentException: single-value function enco
24672467
;
24682468

24692469
url_encode sample for docs
2470-
required_capability: url_decode_encode
2470+
required_capability: url_encode
24712471

24722472
// tag::url_encode[]
2473-
ROW u = "http://elastic.co"
2474-
| EVAL e = URL_ENCODE(u)
2473+
ROW u = "https://www.example.com/papers?q=information+retrieval&year=2024&citations=high" | EVAL u = URL_ENCODE(u)
24752474
// end::url_encode[]
24762475
;
24772476

24782477
// tag::url_encode-result[]
2479-
u:keyword | e:keyword
2480-
http://elastic.co | http%3A%2F%2Felastic.co
2478+
u:keyword
2479+
https%3A%2F%2Fwww.example.com%2Fpapers%3Fq%3Dinformation%2Bretrieval%26year%3D2024%26citations%3Dhigh
24812480
// end::url_encode-result[]
24822481
;
24832482

24842483
url_encode mixed functions tests
24852484
FROM employees
2486-
| WHERE emp_no == 10001
2487-
| EVAL a = TRIM(URL_ENCODE(first_name))
2488-
| EVAL b = URL_ENCODE(TO_LOWER(first_name))
2489-
| KEEP a,b;
2485+
| WHERE emp_no == 10001
2486+
| EVAL a = TRIM(URL_ENCODE(first_name))
2487+
| EVAL b = URL_ENCODE(TO_LOWER(first_name))
2488+
| KEEP a,b;
24902489

24912490
a:keyword | b:keyword
24922491
Georgi | georgi
24932492
;
24942493

24952494
url_encode mixed input tests
2496-
ROW u = ["hello elastic!", "a+b-c%d", "", "!#$&'()+,/:;=?@[]"] | EVAL u = URL_ENCODE(u);
2495+
ROW u = ["hello elastic!", "a+b-c%d", "", "!#$&'()*+,/:;=?@[]"] | EVAL u = URL_ENCODE(u);
24972496

24982497
u:keyword
2499-
["hello+elastic%21", "a%2Bb-c%25d", "", "%21%23%24%26%27%28%29%2B%2C%2F%3A%3B%3D%3F%40%5B%5D"]
2498+
["hello+elastic%21", "a%2Bb-c%25d", "", "%21%23%24%26%27%28%29*%2B%2C%2F%3A%3B%3D%3F%40%5B%5D"]
25002499
;

x-pack/plugin/esql/src/main/generated/org/elasticsearch/xpack/esql/expression/function/scalar/convert/UrlEncodeEvaluator.java

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,12 +1399,12 @@ public enum Cap {
13991399
/**
14001400
* Allow qualifiers in attribute names.
14011401
*/
1402-
NAME_QUALIFIERS(Build.current().isSnapshot());
1402+
NAME_QUALIFIERS(Build.current().isSnapshot()),
14031403

14041404
/**
14051405
* URL encoding function.
14061406
*/
1407-
URL_ENCODE;
1407+
URL_ENCODE(Build.current().isSnapshot());
14081408

14091409
private final boolean enabled;
14101410

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/UrlEncode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ public EvalOperator.ExpressionEvaluator.Factory toEvaluator(ToEvaluator toEvalua
7979

8080
@ConvertEvaluator()
8181
static BytesRef process(final BytesRef val) {
82-
String s = val.utf8ToString();
83-
String encoded = URLEncoder.encode(s, StandardCharsets.UTF_8);
82+
String input = val.utf8ToString();
83+
String encoded = URLEncoder.encode(input, StandardCharsets.UTF_8);
8484
return new BytesRef(encoded);
8585
}
8686

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/scalar/convert/UrlEncodeTests.java

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
1212

1313
import org.apache.lucene.util.BytesRef;
14+
import org.elasticsearch.common.lucene.BytesRefs;
1415
import org.elasticsearch.xpack.esql.core.expression.Expression;
1516
import org.elasticsearch.xpack.esql.core.tree.Source;
1617
import org.elasticsearch.xpack.esql.core.type.DataType;
@@ -28,6 +29,9 @@
2829

2930
@FunctionName("url_encode")
3031
public class UrlEncodeTests extends AbstractScalarFunctionTestCase {
32+
33+
private record RandomUrl(String plain, String encoded) {}
34+
3135
public UrlEncodeTests(@Name("TestCase") Supplier<TestCaseSupplier.TestCase> testCaseSupplier) {
3236
this.testCase = testCaseSupplier.get();
3337
}
@@ -37,8 +41,16 @@ public static Iterable<Object[]> parameters() {
3741
List<TestCaseSupplier> suppliers = new ArrayList<>();
3842

3943
for (DataType dataType : DataType.stringTypes()) {
40-
TestCaseSupplier supplier = new TestCaseSupplier(List.of(dataType), () -> createTestCase(dataType));
41-
suppliers.add(supplier);
44+
suppliers.add(new TestCaseSupplier(List.of(dataType), () -> createTestCaseWithRandomUrl(dataType)));
45+
46+
for (TestCaseSupplier.TypedDataSupplier supplier : TestCaseSupplier.stringCases(dataType)) {
47+
TestCaseSupplier testCaseSupplier = new TestCaseSupplier(
48+
supplier.name(),
49+
List.of(supplier.type()),
50+
() -> createTestCaseWithRandomString(dataType, supplier)
51+
);
52+
suppliers.add(testCaseSupplier);
53+
}
4254
}
4355

4456
return parameterSuppliersFromTypedDataWithDefaultChecksNoErrors(false, suppliers);
@@ -49,24 +61,45 @@ protected Expression build(Source source, List<Expression> args) {
4961
return new UrlEncode(source, args.get(0));
5062
}
5163

52-
private static TestCaseSupplier.TestCase createTestCase(DataType dataType) {
53-
String url = generateRandomUrl();
54-
BytesRef input = new BytesRef(url);
64+
private static TestCaseSupplier.TestCase createTestCaseWithRandomUrl(DataType dataType) {
65+
RandomUrl url = generateRandomUrl();
66+
BytesRef input = new BytesRef(url.plain());
67+
BytesRef output = new BytesRef(url.encoded());
68+
TestCaseSupplier.TypedData fieldTypedData = new TestCaseSupplier.TypedData(input, dataType, "string");
69+
70+
return new TestCaseSupplier.TestCase(
71+
List.of(fieldTypedData),
72+
"UrlEncodeEvaluator[val=Attribute[channel=0]]",
73+
dataType,
74+
equalTo(output)
75+
);
76+
}
77+
78+
private static TestCaseSupplier.TestCase createTestCaseWithRandomString(
79+
DataType dataType,
80+
TestCaseSupplier.TypedDataSupplier supplier
81+
) {
82+
TestCaseSupplier.TypedData fieldTypedData = supplier.get();
83+
BytesRef input = BytesRefs.toBytesRef(fieldTypedData.data());
5584
BytesRef output = new BytesRef(URLEncoder.encode(input.utf8ToString(), StandardCharsets.UTF_8));
5685

5786
return new TestCaseSupplier.TestCase(
58-
List.of(new TestCaseSupplier.TypedData(input, dataType, "string")),
87+
List.of(fieldTypedData),
5988
"UrlEncodeEvaluator[val=Attribute[channel=0]]",
6089
dataType,
6190
equalTo(output)
6291
);
6392
}
6493

65-
private static String generateRandomUrl() {
94+
private static RandomUrl generateRandomUrl() {
6695
String protocol = randomFrom("http://", "https://", "");
6796
String domain = String.format("%s.com", randomAlphaOfLengthBetween(3, 10));
6897
String path = randomFrom("", "/" + randomAlphanumericOfLength(5) + "/");
6998
String query = randomFrom("", "?" + randomAlphaOfLength(5) + "=" + randomAlphanumericOfLength(5));
70-
return String.format("%s%s%s%s", protocol, domain, path, query);
99+
100+
String plain = String.format("%s%s%s%s", protocol, domain, path, query);
101+
String encoded = URLEncoder.encode(plain, StandardCharsets.UTF_8);
102+
103+
return new RandomUrl(plain, encoded);
71104
}
72105
}

0 commit comments

Comments
 (0)