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 — 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>) -> 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>) -> 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}