/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.trino.plugin.jdbc.expression;

import io.trino.matching.Pattern;
import io.trino.matching.Property;
import io.trino.spi.connector.AggregateFunction;
import io.trino.spi.expression.ConnectorExpression;
import io.trino.spi.expression.Variable;
import io.trino.spi.type.Type;

import java.util.List;
import java.util.Optional;

public final class AggregateFunctionPatterns
{
    private AggregateFunctionPatterns() {}

    public static Pattern<AggregateFunction> basicAggregation()
    {
        return Pattern.typeOf(AggregateFunction.class)
                .with(hasSortOrder().equalTo(false))
                .with(distinct().equalTo(false))
                .with(hasFilter().equalTo(false));
    }

    public static Property<AggregateFunction, ?, String> functionName()
    {
        return Property.property("functionName", AggregateFunction::getFunctionName);
    }

    public static Property<AggregateFunction, ?, Type> outputType()
    {
        return Property.property("outputType", AggregateFunction::getOutputType);
    }

    public static Property<AggregateFunction, ?, List<ConnectorExpression>> inputs()
    {
        return Property.property("inputs", AggregateFunction::getInputs);
    }

    public static Property<AggregateFunction, ?, ConnectorExpression> singleInput()
    {
        return Property.optionalProperty("inputs", aggregateFunction -> {
            List<ConnectorExpression> inputs = aggregateFunction.getInputs();
            if (inputs.size() != 1) {
                return Optional.empty();
            }
            return Optional.of(inputs.get(0));
        });
    }

    public static Property<AggregateFunction, ?, Boolean> hasSortOrder()
    {
        return Property.property("hasSortOrder", aggregateFunction -> !aggregateFunction.getSortItems().isEmpty());
    }

    public static Property<AggregateFunction, ?, Boolean> distinct()
    {
        return Property.property("distinct", AggregateFunction::isDistinct);
    }

    public static Property<AggregateFunction, ?, Boolean> hasFilter()
    {
        return Property.property("hasFilter", aggregateFunction -> aggregateFunction.getFilter().isPresent());
    }

    public static Pattern<Variable> variable()
    {
        return Pattern.typeOf(Variable.class);
    }

    public static Property<ConnectorExpression, ?, Type> expressionType()
    {
        return Property.property("type", ConnectorExpression::getType);
    }
}

@@ -608,33 +608,189 @@
 ort 
-io.trino.matching.Pattern
+com.google.common.collect.ImmutableList;%0Aimport io.trino.matching.Captures;%0Aimport io.trino.matching.Match;%0Aimport io.trino.matching.Pattern;%0Aimport io.trino.matching.PatternVisitor
 ;%0Aim
@@ -1015,24 +1015,24 @@
 .util.List;%0A
-
 import java.
@@ -1045,16 +1045,205 @@
 ptional;
+%0Aimport java.util.function.Predicate;%0Aimport java.util.stream.Stream;%0A%0Aimport static com.google.common.collect.ImmutableList.toImmutableList;%0Aimport static java.util.Objects.requireNonNull;
 %0A%0Apublic
@@ -3204,138 +3204,1336 @@
 ic P
-roperty%3CConnectorExpression, ?, Type%3E expressionType()%0A    %7B%0A        return Property.property(%22type%22, ConnectorExpression::getType
+attern%3CList%3CVariable%3E%3E variables()%0A    %7B%0A        return new Pattern%3C%3E(Optional.empty())%0A        %7B%0A            @Override%0A            public %3CC%3E Stream%3CMatch%3E accept(Object object, Captures captures, C context)%0A            %7B%0A                if (!(object instanceof List)) %7B%0A                    return Stream.of();%0A                %7D%0A                @SuppressWarnings(%22unchecked%22)%0A                List%3CConnectorExpression%3E arguments = (List%3CConnectorExpression%3E) object;%0A                if (!arguments.stream().allMatch(Variable.class::isInstance)) %7B%0A                    return Stream.of();%0A                %7D%0A                return Stream.of(Match.of(captures));%0A            %7D%0A%0A            @Override%0A            public void accept(PatternVisitor patternVisitor)%0A            %7B%0A            %7D%0A        %7D;%0A    %7D%0A%0A    public static Property%3CConnectorExpression, ?, Type%3E expressionType()%0A    %7B%0A        return Property.property(%22type%22, ConnectorExpression::getType);%0A    %7D%0A%0A    public static Predicate%3CList%3C? extends ConnectorExpression%3E%3E expressionTypes(Type... types)%0A    %7B%0A        List%3CType%3E expectedTypes = ImmutableList.copyOf(requireNonNull(types, %22types is null%22));%0A        return expressions -%3E expectedTypes.equals(expressions.stream()%0A                .map(ConnectorExpression::getType)%0A                .collect(toImmutableList())
 );%0A 

Add pattern for multi-variable aggregation functions