001/* 002 * Copyright 2015-2022 Transmogrify LLC, 2022-2026 Revetware LLC. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package com.pyranid; 018 019import org.jspecify.annotations.NonNull; 020 021import java.sql.PreparedStatement; 022import java.sql.SQLException; 023import java.util.List; 024 025import static java.util.Objects.requireNonNull; 026 027/** 028 * Contract for binding parameters to SQL prepared statements. 029 * <p> 030 * A production-ready concrete implementation is available via the following static methods: 031 * <ul> 032 * <li>{@link #withDefaultConfiguration()}</li> 033 * <li>{@link #withCustomParameterBinders(List)}</li> 034 * </ul> 035 * How to acquire an instance: 036 * <pre>{@code // With out-of-the-box defaults 037 * PreparedStatementBinder default = PreparedStatementBinder.withDefaultConfiguration(); 038 * 039 * // Customized 040 * PreparedStatementBinder custom = PreparedStatementBinder.withCustomParameterBinders(List.of(...));}</pre> 041 * Or, implement your own: <pre>{@code PreparedStatementBinder myImpl = new PreparedStatementBinder() { 042 * @Override 043 * <T> void bindParameter( 044 * @NonNull StatementContext<T> statementContext, 045 * @NonNull PreparedStatement preparedStatement, 046 * @NonNull Integer parameterIndex, 047 * @NonNull Object parameter 048 * ) throws SQLException { 049 * // Bind the parameter at the specified index to the PreparedStatement 050 * } 051 * };}</pre> 052 * 053 * @author <a href="https://www.revetkn.com">Mark Allen</a> 054 * @since 1.0.0 055 */ 056@FunctionalInterface 057public interface PreparedStatementBinder { 058 /** 059 * Binds a single parameter to a SQL prepared statement. 060 * <p> 061 * This function is only invoked when {@code parameter} is non-null. 062 * 063 * @param preparedStatement the prepared statement to bind to 064 * @param statementContext current SQL context 065 * @param parameterIndex the index of the parameter we are binding 066 * @param parameter the parameter we are binding to the {@link PreparedStatement}, if any 067 * @throws SQLException if an error occurs during binding 068 */ 069 <T> void bindParameter(@NonNull StatementContext<T> statementContext, 070 @NonNull PreparedStatement preparedStatement, 071 @NonNull Integer parameterIndex, 072 @NonNull Object parameter) throws SQLException; 073 074 /** 075 * Acquires a concrete implementation of this interface with out-of-the-box defaults. 076 * <p> 077 * The returned instance is thread-safe. 078 * 079 * @return a concrete implementation of this interface with out-of-the-box defaults 080 */ 081 @NonNull 082 static PreparedStatementBinder withDefaultConfiguration() { 083 return new DefaultPreparedStatementBinder(); 084 } 085 086 /** 087 * Acquires a concrete implementation of this interface, specifying "surgical" per-type custom parameter binders. 088 * <p> 089 * The returned instance is thread-safe. 090 * 091 * @param customParameterBinders the "surgical" per-type custom parameter binders 092 * @return a concrete implementation of this interface 093 */ 094 @NonNull 095 static PreparedStatementBinder withCustomParameterBinders(@NonNull List<CustomParameterBinder> customParameterBinders) { 096 requireNonNull(customParameterBinders); 097 return new DefaultPreparedStatementBinder(customParameterBinders); 098 } 099}