class Visitor extends SymbolVisitor<Context, Query> {

        @Override
        public Query visitFunction(Function function, Context context) {<FILL_FUNCTION_BODY>}

        private Query queryFromInnerFunction(Function parent, Context context) {
            for (Symbol arg : parent.arguments()) {
                if (arg instanceof Function inner) {
                    FunctionImplementation implementation = context.nodeContext.functions().getQualified(inner);
                    Query query = implementation instanceof FunctionToQuery funcToQuery
                        ? funcToQuery.toQuery(parent, inner, context)
                        : null;
                    if (query != null) {
                        return query;
                    }
                }
            }
            return null;
        }

        private static boolean fieldIgnored(Function function, Context context) {
            if (function.arguments().size() != 2) {
                return false;
            }
            Symbol left = function.arguments().get(0);
            Symbol right = function.arguments().get(1);
            if (left.symbolType() == SymbolType.REFERENCE && right.symbolType().isValueSymbol()) {
                String columnName = ((Reference) left).column().name();
                if (Context.FILTERED_FIELDS.contains(columnName)) {
                    context.filteredFieldValues.put(columnName, ((Input<?>) right).value());
                    return true;
                }
                String unsupportedMessage = Context.UNSUPPORTED_FIELDS.get(columnName);
                if (unsupportedMessage != null) {
                    throw new UnsupportedFeatureException(unsupportedMessage);
                }
            }
            return false;
        }

        private static Function rewriteAndValidateFields(Function function, Context context) {
            List<Symbol> arguments = function.arguments();
            if (arguments.size() == 2) {
                Symbol left = arguments.get(0);
                Symbol right = arguments.get(1);
                if (left.symbolType() == SymbolType.REFERENCE && right.symbolType().isValueSymbol()) {
                    Reference ref = (Reference) left;
                    if (ref.column().equals(DocSysColumns.UID)) {
                        return new Function(
                            function.signature(),
                            List.of(DocSysColumns.forTable(ref.ident().tableIdent(), DocSysColumns.ID), right),
                            function.valueType()
                        );
                    } else {
                        String unsupportedMessage = context.unsupportedMessage(ref.column().name());
                        if (unsupportedMessage != null) {
                            throw new UnsupportedFeatureException(unsupportedMessage);
                        }
                    }
                }
            }
            return function;
        }


        @Override
        public Query visitReference(Reference ref, Context context) {
            DataType<?> type = ref.valueType();
            // called for queries like: where boolColumn
            if (type == DataTypes.BOOLEAN) {
                EqQuery<? super Boolean> eqQuery = DataTypes.BOOLEAN.storageSupportSafe().eqQuery();
                if (eqQuery != null) {
                    return eqQuery.termQuery(
                        ref.storageIdent(), Boolean.TRUE, ref.hasDocValues(), ref.indexType() != IndexType.NONE);
                }
            }
            return super.visitReference(ref, context);
        }

        @Override
        public Query visitLiteral(Literal<?> literal, Context context) {
            Object value = literal.value();
            if (value == null) {
                return new MatchNoDocsQuery("WHERE null -> no match");
            }
            try {
                return (boolean) value
                    ? new MatchAllDocsQuery()
                    : new MatchNoDocsQuery("WHERE false -> no match");
            } catch (ClassCastException e) {
                // Throw a nice error if the top-level literal doesn't have a boolean type
                // (This is currently caught earlier, so this code is just a safe-guard)
                return visitSymbol(literal, context);
            }
        }

        @Override
        protected Query visitSymbol(Symbol symbol, Context context) {
            throw new UnsupportedOperationException(
                    Symbols.format("Can't build query from symbol %s", symbol));
        }
    }

            assert function != null : "function must not be null";
            if (fieldIgnored(function, context)) {
                return new MatchAllDocsQuery();
            }
            function = rewriteAndValidateFields(function, context);

            FunctionImplementation implementation = context.nodeContext.functions().getQualified(function);
            if (implementation instanceof FunctionToQuery funcToQuery) {
                Query query;
                try {
                    query = funcToQuery.toQuery(function, context);
                    if (query == null) {
                        query = queryFromInnerFunction(function, context);
                    }
                } catch (UnsupportedOperationException e) {
                    return genericFunctionFilter(function, context);
                }
                if (query != null) {
                    return query;
                }
            }
            return genericFunctionFilter(function, context);
        
<no_super_class>