mirror of
https://github.com/moparisthebest/JdbcMapper
synced 2024-11-25 10:22:17 -05:00
Start PreparedStatement binding documentation, fix some omissions/inconsistencies between QueryMapper and JdbcMapper
This commit is contained in:
parent
73729f5622
commit
29ec477334
@ -25,12 +25,12 @@ public class PreparedStatementUtil {
|
|||||||
|
|
||||||
public static void setObject(final PreparedStatement ps, final int index, final Object o) throws SQLException {
|
public static void setObject(final PreparedStatement ps, final int index, final Object o) throws SQLException {
|
||||||
// we are going to put most common ones up top so it should execute faster normally
|
// we are going to put most common ones up top so it should execute faster normally
|
||||||
if (o == null || o instanceof String || o instanceof Number)
|
if (o == null || o instanceof String || o instanceof Number || o instanceof Boolean)
|
||||||
ps.setObject(index, o);
|
ps.setObject(index, o);
|
||||||
// java.util.Date support, put it in a Timestamp
|
// java.util.Date support, put it in a Timestamp
|
||||||
else if (o instanceof java.util.Date)
|
else if (o instanceof java.util.Date)
|
||||||
ps.setObject(index, o.getClass().equals(java.util.Date.class) ? new java.sql.Timestamp(((java.util.Date)o).getTime()) : o);
|
ps.setObject(index, o.getClass().equals(java.util.Date.class) ? new java.sql.Timestamp(((java.util.Date)o).getTime()) : o);
|
||||||
//IFJAVA8_START// todo: other java.time types
|
//IFJAVA8_START// todo: other java.time types, Year, ZoneId, ZoneOffset
|
||||||
else if (o instanceof Instant)
|
else if (o instanceof Instant)
|
||||||
ps.setObject(index, java.sql.Timestamp.from((Instant)o));
|
ps.setObject(index, java.sql.Timestamp.from((Instant)o));
|
||||||
else if (o instanceof LocalDateTime)
|
else if (o instanceof LocalDateTime)
|
||||||
@ -73,6 +73,8 @@ public class PreparedStatementUtil {
|
|||||||
ps.setArray(index, (java.sql.Array) o);
|
ps.setArray(index, (java.sql.Array) o);
|
||||||
else if (o instanceof Enum)
|
else if (o instanceof Enum)
|
||||||
ps.setObject(index, ((Enum)o).name());
|
ps.setObject(index, ((Enum)o).name());
|
||||||
|
else if (o instanceof java.sql.Ref)
|
||||||
|
ps.setRef(index, (java.sql.Ref) o);
|
||||||
else
|
else
|
||||||
ps.setObject(index, o); // probably won't get here ever, but just in case...
|
ps.setObject(index, o); // probably won't get here ever, but just in case...
|
||||||
/*
|
/*
|
||||||
|
@ -65,8 +65,8 @@ public class JdbcMapperProcessor extends AbstractProcessor {
|
|||||||
return messager;
|
return messager;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TypeMirror sqlExceptionType, stringType, numberType, utilDateType, readerType, clobType, connectionType, jdbcMapperType,
|
static TypeMirror sqlExceptionType, stringType, numberType, booleanType, utilDateType, readerType, clobType, connectionType, jdbcMapperType,
|
||||||
byteArrayType, inputStreamType, fileType, blobType, sqlArrayType, collectionType, iterableType, bindableType, calendarType, cleanerType, enumType;
|
byteArrayType, inputStreamType, fileType, blobType, sqlArrayType, refType, collectionType, iterableType, bindableType, calendarType, cleanerType, enumType;
|
||||||
//IFJAVA8_START
|
//IFJAVA8_START
|
||||||
static TypeMirror streamType, instantType, localDateTimeType, localDateType, localTimeType, zonedDateTimeType, offsetDateTimeType, offsetTimeType;
|
static TypeMirror streamType, instantType, localDateTimeType, localDateType, localTimeType, zonedDateTimeType, offsetDateTimeType, offsetTimeType;
|
||||||
//IFJAVA8_END
|
//IFJAVA8_END
|
||||||
@ -99,6 +99,7 @@ public class JdbcMapperProcessor extends AbstractProcessor {
|
|||||||
sqlExceptionType = elements.getTypeElement(SQLException.class.getCanonicalName()).asType();
|
sqlExceptionType = elements.getTypeElement(SQLException.class.getCanonicalName()).asType();
|
||||||
stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
|
stringType = elements.getTypeElement(String.class.getCanonicalName()).asType();
|
||||||
numberType = elements.getTypeElement(Number.class.getCanonicalName()).asType();
|
numberType = elements.getTypeElement(Number.class.getCanonicalName()).asType();
|
||||||
|
booleanType = elements.getTypeElement(Boolean.class.getCanonicalName()).asType();
|
||||||
utilDateType = elements.getTypeElement(java.util.Date.class.getCanonicalName()).asType();
|
utilDateType = elements.getTypeElement(java.util.Date.class.getCanonicalName()).asType();
|
||||||
readerType = elements.getTypeElement(Reader.class.getCanonicalName()).asType();
|
readerType = elements.getTypeElement(Reader.class.getCanonicalName()).asType();
|
||||||
clobType = elements.getTypeElement(Clob.class.getCanonicalName()).asType();
|
clobType = elements.getTypeElement(Clob.class.getCanonicalName()).asType();
|
||||||
@ -124,6 +125,7 @@ public class JdbcMapperProcessor extends AbstractProcessor {
|
|||||||
//byteArrayType = elements.getTypeElement(byte.class.getCanonicalName()).asType();
|
//byteArrayType = elements.getTypeElement(byte.class.getCanonicalName()).asType();
|
||||||
byteArrayType = types.getArrayType(types.getPrimitiveType(TypeKind.BYTE));
|
byteArrayType = types.getArrayType(types.getPrimitiveType(TypeKind.BYTE));
|
||||||
sqlArrayType = elements.getTypeElement(java.sql.Array.class.getCanonicalName()).asType();
|
sqlArrayType = elements.getTypeElement(java.sql.Array.class.getCanonicalName()).asType();
|
||||||
|
refType = elements.getTypeElement(java.sql.Ref.class.getCanonicalName()).asType();
|
||||||
collectionType = types.getDeclaredType(elements.getTypeElement(Collection.class.getCanonicalName()), types.getWildcardType(null, null));
|
collectionType = types.getDeclaredType(elements.getTypeElement(Collection.class.getCanonicalName()), types.getWildcardType(null, null));
|
||||||
iterableType = types.getDeclaredType(elements.getTypeElement(Iterable.class.getCanonicalName()), types.getWildcardType(null, null));
|
iterableType = types.getDeclaredType(elements.getTypeElement(Iterable.class.getCanonicalName()), types.getWildcardType(null, null));
|
||||||
|
|
||||||
@ -987,7 +989,7 @@ public class JdbcMapperProcessor extends AbstractProcessor {
|
|||||||
// we are going to put most common ones up top so it should execute faster normally
|
// we are going to put most common ones up top so it should execute faster normally
|
||||||
// todo: avoid string concat here
|
// todo: avoid string concat here
|
||||||
if (method == null)
|
if (method == null)
|
||||||
if (o.getKind().isPrimitive() || types.isAssignable(o, stringType) || types.isAssignable(o, numberType)) {
|
if (o.getKind().isPrimitive() || types.isAssignable(o, stringType) || types.isAssignable(o, numberType) || types.isAssignable(o, booleanType)) {
|
||||||
method = "Object";
|
method = "Object";
|
||||||
// java.util.Date support, put it in a Timestamp
|
// java.util.Date support, put it in a Timestamp
|
||||||
} else if (types.isAssignable(o, utilDateType)) {
|
} else if (types.isAssignable(o, utilDateType)) {
|
||||||
@ -1038,6 +1040,8 @@ public class JdbcMapperProcessor extends AbstractProcessor {
|
|||||||
} else if (types.isAssignable(o, enumType)) {
|
} else if (types.isAssignable(o, enumType)) {
|
||||||
method = "Object";
|
method = "Object";
|
||||||
variableName = variableName + " == null ? null : " + variableName + ".name()";
|
variableName = variableName + " == null ? null : " + variableName + ".name()";
|
||||||
|
} else if (types.isAssignable(o, refType)) {
|
||||||
|
method = "Ref";
|
||||||
} else {
|
} else {
|
||||||
// shouldn't get here ever, if we do the types should be more specific
|
// shouldn't get here ever, if we do the types should be more specific
|
||||||
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@JdbcMapper.SQL could not properly infer PreparedStatement bind call for param", param);
|
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@JdbcMapper.SQL could not properly infer PreparedStatement bind call for param", param);
|
||||||
|
137
readme.md
137
readme.md
@ -429,6 +429,143 @@ String s = rs.getString(index);
|
|||||||
return s == null ? null : ZoneOffset.of(s);
|
return s == null ? null : ZoneOffset.of(s);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Object to Column (PreparedStatement) Mapping
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
This explains how specific java types map to specific PreparedStatement calls, this can be different between JdbcMapper and QueryMapper because of the
|
||||||
|
different information available. With JdbcMapper we have type information regardless of the value, so a String is a String even if you send in null. With
|
||||||
|
QueryMapper if the value is null, we have no idea if that was supposed to be a Date or a String or what.
|
||||||
|
|
||||||
|
If you are thinking 'shut up and show me the code already' refer to [PreparedStatementUtil.java](https://github.com/moparisthebest/JdbcMapper/blob/master/common/src/main/java/com/moparisthebest/jdbc/util/PreparedStatementUtil.java#L26) for the runtime mapping, and [JdbcMapperProcessor.java](https://github.com/moparisthebest/JdbcMapper/blob/master/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/JdbcMapperProcessor.java#L918) for the compile-time mapping, which should end up being identical where possible.
|
||||||
|
|
||||||
|
For the purposes of this mapping, consider 'ps' an instance of PreparedStatement, 'index' an int index of a PreparedStatement column, and 'o' as the Object being mapped to the PreparedStatement column.
|
||||||
|
|
||||||
|
### Misc Objects
|
||||||
|
##### String / Number / Boolean / primitives
|
||||||
|
```java
|
||||||
|
ps.setObject(index, o);
|
||||||
|
```
|
||||||
|
##### null
|
||||||
|
This only applies at runtime, in which case we don't have a type, we always have a type at compile-time.
|
||||||
|
```java
|
||||||
|
ps.setObject(index, o);
|
||||||
|
```
|
||||||
|
##### java.lang.Enum (any enum)
|
||||||
|
```java
|
||||||
|
ps.setObject(index, o.name());
|
||||||
|
```
|
||||||
|
##### byte[]
|
||||||
|
```java
|
||||||
|
ps.setBlob(index, new ByteArrayInputStream(o));
|
||||||
|
```
|
||||||
|
##### java.sql.Ref
|
||||||
|
```java
|
||||||
|
ps.setRef(index, o);
|
||||||
|
```
|
||||||
|
##### java.sql.Blob / java.io.InputStream
|
||||||
|
```java
|
||||||
|
ps.setBlob(index, o);
|
||||||
|
```
|
||||||
|
##### String as Blob
|
||||||
|
Where `s` is the String, and `charset` is the character set to convert the String to bytes with,
|
||||||
|
if not provided, charset defaults to UTF-8:
|
||||||
|
```java
|
||||||
|
ps.setBlob(index, s == null ? null : new ByteArrayInputStream(s.getBytes(charset)));
|
||||||
|
```
|
||||||
|
At runtime using QueryMapper, you signal you want this by wrapping s with `PreparedStatementUtil.wrapBlob(s)` or `PreparedStatementUtil.wrapBlob(s, charset)`
|
||||||
|
At compile-time using JdbcMapper, you signal you want this in the SQL like `{blob:s}` or `{blob:utf-8:s}` any charset supported by your java works
|
||||||
|
##### java.io.File
|
||||||
|
```java
|
||||||
|
try {
|
||||||
|
ps.setBlob(index, new FileInputStream(o)); // todo: does this close this or leak a file descriptor?
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
throw new SQLException("File to Blob FileNotFoundException", e);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
This will likely change in the near future to read file to byte[] and behave like byte[] from above, since we probably
|
||||||
|
can't count on the FileInputStream being properly closed...
|
||||||
|
##### java.sql.Clob / java.io.Reader
|
||||||
|
```java
|
||||||
|
ps.setClob(index, o);
|
||||||
|
```
|
||||||
|
##### String as Clob
|
||||||
|
Where `s` is the String:
|
||||||
|
```java
|
||||||
|
ps.setClob(index, s == null ? null : new StringReader(s));
|
||||||
|
```
|
||||||
|
At runtime using QueryMapper, you signal you want this by wrapping s with `PreparedStatementUtil.wrapClob(s)`
|
||||||
|
At compile-time using JdbcMapper, you signal you want this in the SQL like `{clob:s}`
|
||||||
|
##### java.sql.Array
|
||||||
|
```java
|
||||||
|
ps.setRef(index, o);
|
||||||
|
```
|
||||||
|
##### *
|
||||||
|
If nothing else fits, we call setObject and cross our fingers with QueryMapper at runtime, this is a compile-time error
|
||||||
|
with JdbcMapper.
|
||||||
|
```java
|
||||||
|
ps.setObject(index, o);
|
||||||
|
```
|
||||||
|
### Date/Time Objects
|
||||||
|
##### exactly java.util.Date
|
||||||
|
```java
|
||||||
|
ps.setObject(index, new java.sql.Timestamp(o.getTime());
|
||||||
|
```
|
||||||
|
##### instanceof java.util.Date, but not exactly java.util.Date
|
||||||
|
so from stdlib this includes java.sql.Date, java.sql.Timestamp, and java.sql.Time
|
||||||
|
```java
|
||||||
|
ps.setObject(index, o);
|
||||||
|
```
|
||||||
|
##### java.time.Instant
|
||||||
|
```java
|
||||||
|
ps.setObject(index, java.sql.Timestamp.from(o);
|
||||||
|
```
|
||||||
|
##### java.time.LocalDateTime
|
||||||
|
```java
|
||||||
|
ps.setObject(index, java.sql.Timestamp.valueOf(o));
|
||||||
|
```
|
||||||
|
##### java.time.LocalDate
|
||||||
|
```java
|
||||||
|
ps.setObject(index, java.sql.Date.valueOf(o));
|
||||||
|
```
|
||||||
|
##### java.time.LocalTime
|
||||||
|
```java
|
||||||
|
ps.setObject(index, java.sql.Time.valueOf(o));
|
||||||
|
```
|
||||||
|
##### java.time.ZonedDateTime
|
||||||
|
```java
|
||||||
|
ps.setObject(index, java.sql.Timestamp.from(o.toInstant()));
|
||||||
|
```
|
||||||
|
##### java.time.OffsetDateTime
|
||||||
|
```java
|
||||||
|
ps.setObject(index, java.sql.Timestamp.from(o.toInstant()));
|
||||||
|
```
|
||||||
|
##### java.time.OffsetTime
|
||||||
|
```java
|
||||||
|
ps.setObject(index, java.sql.Time.valueOf(o.toLocalTime()));
|
||||||
|
```
|
||||||
|
##### java.time.Year
|
||||||
|
done this way instead of Year.of(int) because usually int->string database coercion is allowed and the other way is not
|
||||||
|
```java
|
||||||
|
// todo
|
||||||
|
```
|
||||||
|
##### java.time.ZoneId
|
||||||
|
```java
|
||||||
|
// todo
|
||||||
|
```
|
||||||
|
##### java.time.ZoneOffset
|
||||||
|
```java
|
||||||
|
// todo
|
||||||
|
```
|
||||||
|
### Special objects
|
||||||
|
##### InLists
|
||||||
|
```java
|
||||||
|
// todo
|
||||||
|
```
|
||||||
|
##### Bindable / SqlBuilder
|
||||||
|
```java
|
||||||
|
// todo
|
||||||
|
```
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
----
|
----
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user