001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.beanquery.sql;
018
019import java.util.*;
020
021import org.apache.juneau.commons.beanquery.*;
022
023/**
024 * The SQL callback an application supplies for a <b>custom</b> search operator (design ยง5.3) so a SQL context can
025 * render it into a {@code WHERE} clause.
026 *
027 * <p>
028 * The renderer receives the target {@link SqlDialect}, the already-quoted column reference, the column's
029 * {@link SearchType value type} (so it can bind values as the right JDBC type), and the operator's arguments (typed
030 * values when the operator asks for them, otherwise the literal strings; see {@link org.apache.juneau.commons.beanquery.SearchOperator.Builder#typedArgs(boolean) SearchOperator.Builder#typedArgs(boolean)}),
031 * and returns a {@link SqlFragment} (a boolean SQL expression plus its ordered bind values).  It is the
032 * SQL-side analog of {@link SearchPredicate} (the in-memory evaluator): built-in operators do not use it &mdash; their
033 * SQL comes from {@link SqlDialect#builtinRenderer(String)}.
034 *
035 * <p>
036 * A renderer is attached to a {@link SearchOperator} as a typed extension keyed by this interface, with
037 * {@link org.apache.juneau.commons.beanquery.SearchOperator.Builder#extension(Class, Object)
038 * extension(SearchSqlRenderer.class, renderer)}; the context retrieves it with {@link SearchOperator#extension(Class)},
039 * so commons never depends on SQL dialect types.  A
040 * renderer that does not support the supplied dialect returns <jk>null</jk>; the context then fails with a clear error
041 * rather than emitting wrong SQL.  Values must be returned as {@link SqlFragment} binds, never concatenated into the
042 * SQL text.
043 *
044 * <p>
045 * For the built-in value operators, and for a custom operator built with {@code typedArgs(true)}, each argument arrives
046 * already parsed by {@link SearchType#parse(String)} during query resolution: a {@link java.math.BigDecimal} for a
047 * {@code NUMERIC} column, a {@link Boolean} for {@code BOOLEAN}, and an {@link java.time.OffsetDateTime},
048 * {@link java.time.LocalDateTime} or {@link java.time.LocalDate} for {@code TIMESTAMP}.  Text-like types
049 * ({@code TEXT}, {@code ID}, {@code ENUM}, {@code VERSION}) are always {@link String}.  A malformed value never reaches a
050 * renderer; it fails resolution with code {@code BAD_VALUE}.
051 *
052 * <h5 class='section'>Example:</h5>
053 * <p class='bjava'>
054 *    <jc>// A custom "$even" operator rendered as a modulo check (one bind-free fragment).</jc>
055 *    SearchSqlRenderer <jv>renderer</jv> = (<jv>dialect</jv>, <jv>col</jv>, <jv>type</jv>, <jv>args</jv>) -&gt;
056 *       SqlFragment.<jsm>of</jsm>(<js>"("</js> + <jv>col</jv> + <js>" % 2 = 0)"</js>);
057 *
058 *    <jc>// A typed-args operator: args.get(0) is a BigDecimal on a NUMERIC column, bound as-is.</jc>
059 *    SearchSqlRenderer <jv>divisibleBy</jv> = (<jv>dialect</jv>, <jv>col</jv>, <jv>type</jv>, <jv>args</jv>) -&gt;
060 *       SqlFragment.<jsm>of</jsm>(<js>"("</js> + <jv>col</jv> + <js>" % ? = 0)"</js>, <jv>args</jv>.get(0));
061 *
062 *    SearchOperator <jv>even</jv> = SearchOperator
063 *       .<jsm>create</jsm>(<js>"$even"</js>, <js>"Matches even numbers. Example: $even()"</js>)
064 *       .minArgs(0).maxArgs(0)
065 *       .extension(SearchSqlRenderer.<jk>class</jk>, <jv>renderer</jv>)
066 *       .build();
067 * </p>
068 *
069 * @since 10.0.0
070 */
071@FunctionalInterface
072public interface SearchSqlRenderer {
073
074   /**
075    * Renders this custom operator into a SQL predicate fragment.
076    *
077    * @param dialect The target SQL dialect.  Never <jk>null</jk>.
078    * @param columnSql The dialect-quoted column reference the predicate applies to (for example {@code "\"age\""}).
079    *    Never <jk>null</jk>.
080    * @param type The column's value type, so the renderer can bind values as the right JDBC type.  Never <jk>null</jk>.
081    * @param args The operator's arguments (never <jk>null</jk>; may be empty): {@link SearchExpression#typedArgs() typed
082    *    values} ({@link java.math.BigDecimal}, {@link Boolean}, {@link java.time.OffsetDateTime},
083    *    {@link java.time.LocalDateTime}, {@link java.time.LocalDate}, or {@link String} for text-like types) for a built-in
084    *    value operator or a custom operator with {@code typedArgs(true)}; plain {@link String} literals otherwise.
085    * @return The predicate fragment, or <jk>null</jk> if this renderer does not support {@code dialect}.
086    */
087   SqlFragment render(SqlDialect dialect, String columnSql, SearchType type, List<Object> args);
088}