|
@@ -0,0 +1,106 @@
|
|
|
+/*
|
|
|
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
|
|
+ * or more contributor license agreements. Licensed under the Elastic License;
|
|
|
+ * you may not use this file except in compliance with the Elastic License.
|
|
|
+ */
|
|
|
+
|
|
|
+package org.elasticsearch.xpack.eql.expression.function.scalar.string;
|
|
|
+
|
|
|
+import org.elasticsearch.xpack.ql.expression.Expression;
|
|
|
+import org.elasticsearch.xpack.ql.expression.Expressions;
|
|
|
+import org.elasticsearch.xpack.ql.expression.Expressions.ParamOrdinal;
|
|
|
+import org.elasticsearch.xpack.ql.expression.FieldAttribute;
|
|
|
+import org.elasticsearch.xpack.ql.expression.function.scalar.ScalarFunction;
|
|
|
+import org.elasticsearch.xpack.ql.expression.gen.pipeline.Pipe;
|
|
|
+import org.elasticsearch.xpack.ql.expression.gen.script.ScriptTemplate;
|
|
|
+import org.elasticsearch.xpack.ql.expression.gen.script.Scripts;
|
|
|
+import org.elasticsearch.xpack.ql.tree.NodeInfo;
|
|
|
+import org.elasticsearch.xpack.ql.tree.Source;
|
|
|
+import org.elasticsearch.xpack.ql.type.DataType;
|
|
|
+import org.elasticsearch.xpack.ql.type.DataTypes;
|
|
|
+
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Locale;
|
|
|
+
|
|
|
+import static java.lang.String.format;
|
|
|
+import static org.elasticsearch.xpack.eql.expression.function.scalar.string.LengthFunctionProcessor.doProcess;
|
|
|
+import static org.elasticsearch.xpack.ql.expression.TypeResolutions.isStringAndExact;
|
|
|
+import static org.elasticsearch.xpack.ql.expression.gen.script.ParamsBuilder.paramsBuilder;
|
|
|
+
|
|
|
+/**
|
|
|
+ * EQL specific length function acting on every type of field, not only strings.
|
|
|
+ * For strings it will return the length of that specific string, for any other type it will return 0.
|
|
|
+ */
|
|
|
+public class Length extends ScalarFunction {
|
|
|
+
|
|
|
+ private final Expression source;
|
|
|
+
|
|
|
+ public Length(Source source, Expression src) {
|
|
|
+ super(source, Arrays.asList(src));
|
|
|
+ this.source = src;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected TypeResolution resolveType() {
|
|
|
+ if (!childrenResolved()) {
|
|
|
+ return new TypeResolution("Unresolved children");
|
|
|
+ }
|
|
|
+
|
|
|
+ return isStringAndExact(source, sourceText(), ParamOrdinal.DEFAULT);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected Pipe makePipe() {
|
|
|
+ return new LengthFunctionPipe(source(), this, Expressions.pipe(source));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean foldable() {
|
|
|
+ return source.foldable();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Object fold() {
|
|
|
+ return doProcess(source.fold());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected NodeInfo<? extends Expression> info() {
|
|
|
+ return NodeInfo.create(this, Length::new, source);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ScriptTemplate asScript() {
|
|
|
+ ScriptTemplate sourceScript = asScript(source);
|
|
|
+
|
|
|
+ return new ScriptTemplate(format(Locale.ROOT, formatTemplate("{eql}.%s(%s)"),
|
|
|
+ "length",
|
|
|
+ sourceScript.template()),
|
|
|
+ paramsBuilder()
|
|
|
+ .script(sourceScript.params())
|
|
|
+ .build(), dataType());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ScriptTemplate scriptWithField(FieldAttribute field) {
|
|
|
+ return new ScriptTemplate(processScript(Scripts.DOC_VALUE),
|
|
|
+ paramsBuilder().variable(field.exactAttribute().name()).build(),
|
|
|
+ dataType());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public DataType dataType() {
|
|
|
+ return DataTypes.INTEGER;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public Expression replaceChildren(List<Expression> newChildren) {
|
|
|
+ if (newChildren.size() != 1) {
|
|
|
+ throw new IllegalArgumentException("expected [1] children but received [" + newChildren.size() + "]");
|
|
|
+ }
|
|
|
+
|
|
|
+ return new Length(source(), newChildren.get(0));
|
|
|
+ }
|
|
|
+
|
|
|
+}
|