diff --git a/pom.xml b/pom.xml index 02461b8e40..e8d72f5df1 100644 --- a/pom.xml +++ b/pom.xml @@ -44,6 +44,7 @@ https://stackoverflow.com/q/62263576/66686 --> 23.3.0.23.09 + 3.45.2.0 4.2.0 diff --git a/spring-data-jdbc/pom.xml b/spring-data-jdbc/pom.xml index fddbaab696..22f29645b8 100644 --- a/spring-data-jdbc/pom.xml +++ b/spring-data-jdbc/pom.xml @@ -153,6 +153,13 @@ test + + org.xerial + sqlite-jdbc + ${sqlite.version} + test + + diff --git a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/DialectResolver.java b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/DialectResolver.java index c55240754b..69bcd5bdf2 100644 --- a/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/DialectResolver.java +++ b/spring-data-jdbc/src/main/java/org/springframework/data/jdbc/repository/config/DialectResolver.java @@ -32,11 +32,7 @@ import org.springframework.data.jdbc.core.dialect.JdbcMySqlDialect; import org.springframework.data.jdbc.core.dialect.JdbcPostgresDialect; import org.springframework.data.jdbc.core.dialect.JdbcSqlServerDialect; -import org.springframework.data.relational.core.dialect.Dialect; -import org.springframework.data.relational.core.dialect.H2Dialect; -import org.springframework.data.relational.core.dialect.HsqlDbDialect; -import org.springframework.data.relational.core.dialect.MariaDbDialect; -import org.springframework.data.relational.core.dialect.OracleDialect; +import org.springframework.data.relational.core.dialect.*; import org.springframework.data.relational.core.sql.IdentifierProcessing; import org.springframework.data.util.Optionals; import org.springframework.jdbc.core.ConnectionCallback; @@ -50,6 +46,7 @@ * available {@link JdbcDialectProvider extensions}. * * @author Jens Schauder + * @author Rudolf Schmidt * @since 2.0 * @see Dialect * @see SpringFactoriesLoader @@ -121,6 +118,9 @@ private static Dialect getDialect(Connection connection) throws SQLException { if (name.contains("h2")) { return H2Dialect.INSTANCE; } + if (name.contains("sqlite")) { + return SQLiteDialect.INSTANCE; + } if (name.contains("mysql")) { return new JdbcMySqlDialect(getIdentifierProcessing(metaData)); } diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/SQLiteDialect.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/SQLiteDialect.java new file mode 100644 index 0000000000..e734f79bdd --- /dev/null +++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/dialect/SQLiteDialect.java @@ -0,0 +1,100 @@ +package org.springframework.data.relational.core.dialect; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.ReadingConverter; +import org.springframework.data.convert.WritingConverter; +import org.springframework.data.relational.core.sql.LockOptions; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.Collection; + +/** + * SQL Dialect for SQLite. + * + * @author Rudolf Schmidt + * @since 3.3.0 + */ +public class SQLiteDialect extends AbstractDialect { + + public static final SQLiteDialect INSTANCE = new SQLiteDialect(); + + private static final LimitClause LIMIT_CLAUSE = new LimitClause() { + @Override + public String getLimit(long limit) { + return String.format("limit %d", limit); + } + + @Override + public String getOffset(long offset) { + throw new UnsupportedOperationException("offset alone not supported"); + } + + @Override + public String getLimitOffset(long limit, long offset) { + return String.format("limit %d offset %d", limit, offset); + } + + @Override + public Position getClausePosition() { + return Position.AFTER_ORDER_BY; + } + }; + + private static final LockClause LOCK_CLAUSE = new LockClause() { + @Override + public String getLock(LockOptions lockOptions) { + return ""; + } + + @Override + public Position getClausePosition() { + return Position.AFTER_ORDER_BY; + } + }; + + private SQLiteDialect() { + } + + @Override + public LimitClause limit() { + return LIMIT_CLAUSE; + } + + @Override + public LockClause lock() { + return LOCK_CLAUSE; + } + + @Override + public Collection getConverters() { + Collection converters = new ArrayList<>(super.getConverters()); + converters.add(LocalDateTimeToNumericConverter.INSTANCE); + converters.add(NumericToLocalDateTimeConverter.INSTANCE); + return converters; + } + + @WritingConverter + private enum LocalDateTimeToNumericConverter implements Converter { + + INSTANCE; + + @Override + public Long convert(LocalDateTime source) { + return source.atZone(ZoneOffset.UTC).toInstant().toEpochMilli(); + } + } + + @ReadingConverter + private enum NumericToLocalDateTimeConverter implements Converter { + + INSTANCE; + + @Override + public LocalDateTime convert(Long source) { + return Instant.ofEpochMilli(source).atZone(ZoneOffset.UTC).toLocalDateTime(); + } + } +}