浏览代码

ESQL: Generate docs for ceil (#106616)

This replaces the hand maintained docs for `CEIL` and with the docs
generated by the tests. There shouldn't be any diff in the generated
docs.
Nik Everett 1 年之前
父节点
当前提交
7c46c735e4

+ 0 - 35
docs/reference/esql/functions/ceil.asciidoc

@@ -1,35 +0,0 @@
-[discrete]
-[[esql-ceil]]
-=== `CEIL`
-
-*Syntax*
-
-[.text-center]
-image::esql/functions/signature/ceil.svg[Embedded,opts=inline]
-
-*Parameters*
-
-`n`::
-Numeric expression. If `null`, the function returns `null`.
-
-*Description*
-
-Round a number up to the nearest integer.
-
-NOTE: This is a noop for `long` (including unsigned) and `integer`.
-      For `double` this picks the closest `double` value to the integer
-      similar to {javadoc}/java.base/java/lang/Math.html#ceil(double)[Math.ceil].
-
-include::types/ceil.asciidoc[]
-
-
-*Example*
-
-[source.merge.styled,esql]
-----
-include::{esql-specs}/math.csv-spec[tag=ceil]
-----
-[%header.monospaced.styled,format=dsv,separator=|]
-|===
-include::{esql-specs}/math.csv-spec[tag=ceil-result]
-|===

+ 2 - 0
docs/reference/esql/functions/description/ceil.asciidoc

@@ -3,3 +3,5 @@
 *Description*
 
 Round a number up to the nearest integer.
+
+NOTE: This is a noop for `long` (including unsigned) and `integer`. For `double` this picks the closest `double` value to the integer similar to {javadoc}/java.base/java/lang/Math.html#ceil(double)[Math.ceil].

+ 13 - 0
docs/reference/esql/functions/examples/ceil.asciidoc

@@ -0,0 +1,13 @@
+// This is generated by ESQL's AbstractFunctionTestCase. Do no edit it. See ../README.md for how to regenerate it.
+
+*Example*
+
+[source.merge.styled,esql]
+----
+include::{esql-specs}/math.csv-spec[tag=ceil]
+----
+[%header.monospaced.styled,format=dsv,separator=|]
+|===
+include::{esql-specs}/math.csv-spec[tag=ceil-result]
+|===
+

+ 1 - 0
docs/reference/esql/functions/layout/ceil.asciidoc

@@ -12,3 +12,4 @@ image::esql/functions/signature/ceil.svg[Embedded,opts=inline]
 include::../parameters/ceil.asciidoc[]
 include::../description/ceil.asciidoc[]
 include::../types/ceil.asciidoc[]
+include::../examples/ceil.asciidoc[]

+ 1 - 1
docs/reference/esql/functions/math-functions.asciidoc

@@ -36,7 +36,7 @@ include::layout/acos.asciidoc[]
 include::layout/asin.asciidoc[]
 include::layout/atan.asciidoc[]
 include::layout/atan2.asciidoc[]
-include::ceil.asciidoc[]
+include::layout/ceil.asciidoc[]
 include::cos.asciidoc[]
 include::cosh.asciidoc[]
 include::e.asciidoc[]

+ 1 - 1
docs/reference/esql/functions/parameters/ceil.asciidoc

@@ -1,4 +1,4 @@
 *Parameters*
 
 `number`::
-
+Numeric expression. If `null`, the function returns `null`.

+ 12 - 4
x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java

@@ -263,10 +263,18 @@ public final class CsvAssert {
     private static void dataFailure(List<DataFailure> dataFailures) {
         fail("Data mismatch:\n" + dataFailures.stream().map(f -> {
             Description description = new StringDescription();
-            ListMatcher expected = f.expected instanceof List
-                ? ListMatcher.matchesList().item(f.expected)
-                : ListMatcher.matchesList((List<?>) f.expected);
-            List<?> actualList = f.actual instanceof List ? List.of(f.actual) : (List<?>) f.actual;
+            ListMatcher expected;
+            if (f.expected instanceof List<?> e) {
+                expected = ListMatcher.matchesList(e);
+            } else {
+                expected = ListMatcher.matchesList().item(f.expected);
+            }
+            List<?> actualList;
+            if (f.actual instanceof List<?> a) {
+                actualList = a;
+            } else {
+                actualList = List.of(f.actual);
+            }
             expected.describeMismatch(actualList, description);
             String prefix = "row " + f.row + " column " + f.column + ":";
             return prefix + description.toString().replace("\n", "\n" + prefix);

+ 1 - 1
x-pack/plugin/esql/qa/testFixtures/src/main/resources/meta.csv-spec

@@ -11,7 +11,7 @@ atan2                    |"double atan2(y_coordinate:double|integer|long|unsigne
 auto_bucket              |"double|date auto_bucket(field:integer|long|double|date, buckets:integer, from:integer|long|double|date|string, to:integer|long|double|date|string)"           |[field, buckets, from, to] |["integer|long|double|date", "integer", "integer|long|double|date|string", "integer|long|double|date|string"]      |["", "", "", ""]                                    | "double|date"                    | "Creates human-friendly buckets and returns a datetime value for each row that corresponds to the resulting bucket the row falls into."                      | [false, false, false, false]   | false | false
 avg                      |"double avg(number:double|integer|long)"                                           |number                     |"double|integer|long"                 |   ""                                               |double                    | "The average of a numeric field."                      | false                | false | true
 case                     |"boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version case(condition:boolean, trueValue...:boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version)"                               |[condition, trueValue]             |["boolean", "boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version"]            |["", ""]                                            |"boolean|cartesian_point|date|double|geo_point|integer|ip|keyword|long|text|unsigned_long|version"                    | "Accepts pairs of conditions and values. The function returns the value that belongs to the first condition that evaluates to true."                      | [false, false]       | true | false
-ceil                     |"double|integer|long|unsigned_long ceil(number:double|integer|long|unsigned_long)"     |number                        |"double|integer|long|unsigned_long"                 | ""                                                 | "double|integer|long|unsigned_long"                    | "Round a number up to the nearest integer."                      | false                | false | false
+ceil                     |"double|integer|long|unsigned_long ceil(number:double|integer|long|unsigned_long)"     |number                        |"double|integer|long|unsigned_long"                 | "Numeric expression. If `null`, the function returns `null`." | "double|integer|long|unsigned_long"                    | "Round a number up to the nearest integer."                      | false                | false | false
 cidr_match               |boolean cidr_match(ip:ip, blockX...:keyword)                         |[ip, blockX]             |[ip, keyword]            |["", "CIDR block to test the IP against."]                                            |boolean                    | "Returns true if the provided IP is contained in one of the provided CIDR blocks."                      | [false, false]       | true | false
 coalesce                 |"boolean|text|integer|keyword|long coalesce(first:boolean|text|integer|keyword|long, ?rest...:boolean|text|integer|keyword|long)"                           |first             | "boolean|text|integer|keyword|long"            | "Expression to evaluate"                                            |"boolean|text|integer|keyword|long"                    | "Returns the first of its arguments that is not null. If all arguments are null, it returns `null`."                      | false       | true | false
 concat                   |"keyword concat(string1:keyword|text, string2...:keyword|text)"                             |[string1, string2]             |["keyword|text", "keyword|text"]            |["", ""]                                            |keyword                    | "Concatenates two or more strings."                      | [false, false]       | true | false

+ 15 - 0
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/FunctionInfo.java

@@ -18,10 +18,25 @@ import java.lang.annotation.Target;
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.CONSTRUCTOR)
 public @interface FunctionInfo {
+    /**
+     * The type(s) this function returns.
+     */
     String[] returnType();
 
+    /**
+     * The description of the function rendered in {@code META FUNCTIONS}
+     * and the docs.
+     */
     String description() default "";
 
+    /**
+     * A {@code NOTE} that's added after the {@link #description} in the docs.
+     */
+    String note() default "";
+
+    /**
+     * Is this an aggregation (true) or a scalar function (false).
+     */
     boolean isAggregation() default false;
 
     /**

+ 16 - 2
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/math/Ceil.java

@@ -9,6 +9,7 @@ package org.elasticsearch.xpack.esql.expression.function.scalar.math;
 
 import org.elasticsearch.compute.ann.Evaluator;
 import org.elasticsearch.compute.operator.EvalOperator.ExpressionEvaluator;
+import org.elasticsearch.xpack.esql.expression.function.Example;
 import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
 import org.elasticsearch.xpack.esql.expression.function.Param;
 import org.elasticsearch.xpack.esql.expression.function.scalar.UnaryScalarFunction;
@@ -30,8 +31,21 @@ import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isNumeric;
  * </p>
  */
 public class Ceil extends UnaryScalarFunction {
-    @FunctionInfo(returnType = { "double", "integer", "long", "unsigned_long" }, description = "Round a number up to the nearest integer.")
-    public Ceil(Source source, @Param(name = "number", type = { "double", "integer", "long", "unsigned_long" }) Expression n) {
+    @FunctionInfo(
+        returnType = { "double", "integer", "long", "unsigned_long" },
+        description = "Round a number up to the nearest integer.",
+        note = "This is a noop for `long` (including unsigned) and `integer`. For `double` this picks the closest `double` value to "
+            + "the integer similar to {javadoc}/java.base/java/lang/Math.html#ceil(double)[Math.ceil].",
+        examples = @Example(file = "math", tag = "ceil")
+    )
+    public Ceil(
+        Source source,
+        @Param(
+            name = "number",
+            type = { "double", "integer", "long", "unsigned_long" },
+            description = "Numeric expression. If `null`, the function returns `null`."
+        ) Expression n
+    ) {
         super(source, n);
     }
 

+ 7 - 3
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java

@@ -1102,8 +1102,9 @@ public abstract class AbstractFunctionTestCase extends ESTestCase {
             EsqlFunctionRegistry.FunctionDescription description = EsqlFunctionRegistry.description(definition);
             renderTypes(description.argNames());
             renderParametersList(description.argNames(), description.argDescriptions());
-            renderDescription(description.description());
-            boolean hasExamples = renderExamples(EsqlFunctionRegistry.functionInfo(definition));
+            FunctionInfo info = EsqlFunctionRegistry.functionInfo(definition);
+            renderDescription(description.description(), info.note());
+            boolean hasExamples = renderExamples(info);
             renderFullLayout(name, hasExamples);
             return;
         }
@@ -1155,11 +1156,14 @@ public abstract class AbstractFunctionTestCase extends ESTestCase {
         writeToTempDir("parameters", rendered, "asciidoc");
     }
 
-    private static void renderDescription(String description) throws IOException {
+    private static void renderDescription(String description, String note) throws IOException {
         String rendered = DOCS_WARNING + """
             *Description*
 
             """ + description + "\n";
+        if (note != null) {
+            rendered += "\nNOTE: " + note + "\n";
+        }
         LogManager.getLogger(getTestClass()).info("Writing description for [{}]:\n{}", functionName(), rendered);
         writeToTempDir("description", rendered, "asciidoc");
     }