diff --git a/.circleci/config.yml b/.circleci/config.yml
index c8cf69f262..3e15ab7c83 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -341,7 +341,7 @@ jobs:
- run:
name: 'Test'
command: |
- ./mvnw -ntp -B install -Pci -Dgroups=com.querydsl.core.testutil.EmbeddedDatabase
+ ./mvnw -ntp -B install -Pci -Dgroups=com.querydsl.core.testutil.EmbeddedDatabase,com.querydsl.core.testutil.Turso
- save-test-results
testDB2:
# Use the machine executor so we have full VM capabilities (e.g. docker running as admin)
diff --git a/pom.xml b/pom.xml
index 45ce55fe24..5d4b4575b4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -113,6 +113,7 @@
13.4.0.jre11
9.3.9.0002
3.53.2.0
+ 0.6.0
13.10.00.35
6.0.5
5.8.0
@@ -998,6 +999,7 @@
com.querydsl.core.testutil.Oracle,
com.querydsl.core.testutil.PostgreSQL,
com.querydsl.core.testutil.SQLite,
+ com.querydsl.core.testutil.Turso,
com.querydsl.core.testutil.SQLServer,
com.querydsl.core.testutil.SlowTest,
com.querydsl.core.testutil.Performance,
diff --git a/querydsl-libraries/pom.xml b/querydsl-libraries/pom.xml
index 5bbd59b8f7..7dd7dc429f 100644
--- a/querydsl-libraries/pom.xml
+++ b/querydsl-libraries/pom.xml
@@ -124,6 +124,7 @@
cubrid:cubrid-jdbc:*:*:compile
org.firebirdsql.jdbc:jaybird:*:*:compile
org.xerial:sqlite-jdbc:*:*:compile
+ tech.turso:turso:*:*:compile
org.hibernate:hibernate-entitymanager
diff --git a/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/FilterFactory.java b/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/FilterFactory.java
index e52af3c415..ac6ce17da6 100644
--- a/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/FilterFactory.java
+++ b/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/FilterFactory.java
@@ -329,6 +329,7 @@ public Collection string(
&& !target.equals(Target.HSQLDB)
&& !target.equals(Target.H2)
&& !target.equals(Target.SQLITE)
+ && !target.equals(Target.TURSO)
&& !target.equals(Target.SQLSERVER)) {
rv.add(expr.matches(knownValue.substring(0, 1) + ".*"));
rv.add(expr.matches(".*" + knownValue.substring(1)));
diff --git a/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/MatchingFiltersFactory.java b/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/MatchingFiltersFactory.java
index 00155e6a9d..4d08ea32df 100644
--- a/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/MatchingFiltersFactory.java
+++ b/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/MatchingFiltersFactory.java
@@ -272,6 +272,7 @@ public Collection string(StringExpression expr, StringExpression othe
&& !target.equals(Target.DB2)
&& !target.equals(Target.DERBY)
&& !target.equals(Target.SQLITE)
+ && !target.equals(Target.TURSO)
&& !target.equals(Target.SQLSERVER))) {
rv.add(expr.matches(other));
diff --git a/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/Target.java b/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/Target.java
index 7aecc0d56f..316d6f88b2 100644
--- a/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/Target.java
+++ b/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/Target.java
@@ -41,6 +41,8 @@ public enum Target {
SQLSERVER,
/** SQLite */
SQLITE,
+ /** Turso (SQLite-compatible) */
+ TURSO,
/** */
TERADATA,
/** */
diff --git a/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/testutil/Turso.java b/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/testutil/Turso.java
new file mode 100644
index 0000000000..5233ba7047
--- /dev/null
+++ b/querydsl-libraries/querydsl-core/src/test/java/com/querydsl/core/testutil/Turso.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2015, The Querydsl Team (http://www.querydsl.com/team)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.querydsl.core.testutil;
+
+public interface Turso extends EmbeddedDatabase {}
diff --git a/querydsl-libraries/querydsl-jpa/src/test/java/com/querydsl/jpa/Mode.java b/querydsl-libraries/querydsl-jpa/src/test/java/com/querydsl/jpa/Mode.java
index 967658d13a..ee6624d920 100644
--- a/querydsl-libraries/querydsl-jpa/src/test/java/com/querydsl/jpa/Mode.java
+++ b/querydsl-libraries/querydsl-jpa/src/test/java/com/querydsl/jpa/Mode.java
@@ -12,6 +12,7 @@
import com.querydsl.sql.SQLTemplates;
import com.querydsl.sql.SQLiteTemplates;
import com.querydsl.sql.TeradataTemplates;
+import com.querydsl.sql.TursoTemplates;
/**
* @author tiwe
@@ -33,6 +34,7 @@ public static SQLTemplates getSQLTemplates() {
case ORACLE -> new OracleTemplates();
case POSTGRESQL -> new PostgreSQLTemplates();
case SQLITE -> new SQLiteTemplates();
+ case TURSO -> new TursoTemplates();
case TERADATA -> new TeradataTemplates();
default -> throw new IllegalStateException("Unknown mode " + mode);
};
diff --git a/querydsl-libraries/querydsl-sql/pom.xml b/querydsl-libraries/querydsl-sql/pom.xml
index 6ba4fb6095..7b9d6f4a9d 100644
--- a/querydsl-libraries/querydsl-sql/pom.xml
+++ b/querydsl-libraries/querydsl-sql/pom.xml
@@ -148,6 +148,13 @@
test
+
+ tech.turso
+ turso
+ ${turso.version}
+ test
+
+
io.github.openfeign.querydsl
querydsl-core
diff --git a/querydsl-libraries/querydsl-sql/src/main/java/com/querydsl/sql/Keywords.java b/querydsl-libraries/querydsl-sql/src/main/java/com/querydsl/sql/Keywords.java
index 1b9232219b..3cbace9ca9 100644
--- a/querydsl-libraries/querydsl-sql/src/main/java/com/querydsl/sql/Keywords.java
+++ b/querydsl-libraries/querydsl-sql/src/main/java/com/querydsl/sql/Keywords.java
@@ -50,6 +50,7 @@ private static Set readLines(String path) {
public static final Set ORACLE = readLines("oracle");
public static final Set POSTGRESQL = readLines("postgresql");
public static final Set SQLITE = readLines("sqlite");
+ public static final Set TURSO = readLines("turso");
public static final Set SQLSERVER2005 = readLines("sqlserver2005");
public static final Set SQLSERVER2008 = readLines("sqlserver2008");
public static final Set SQLSERVER2012 = readLines("sqlserver2012");
diff --git a/querydsl-libraries/querydsl-sql/src/main/java/com/querydsl/sql/SQLTemplatesRegistry.java b/querydsl-libraries/querydsl-sql/src/main/java/com/querydsl/sql/SQLTemplatesRegistry.java
index 0514e4b32b..dc4fd2f326 100644
--- a/querydsl-libraries/querydsl-sql/src/main/java/com/querydsl/sql/SQLTemplatesRegistry.java
+++ b/querydsl-libraries/querydsl-sql/src/main/java/com/querydsl/sql/SQLTemplatesRegistry.java
@@ -58,6 +58,8 @@ public SQLTemplates.Builder getBuilder(DatabaseMetaData md) throws SQLException
return PostgreSQLTemplates.builder();
} else if (name.equals("sqlite")) {
return SQLiteTemplates.builder();
+ } else if (name.equals("turso")) {
+ return TursoTemplates.builder();
} else if (name.startsWith("teradata")) {
return TeradataTemplates.builder();
} else if (name.equals("microsoft sql server")) {
diff --git a/querydsl-libraries/querydsl-sql/src/main/java/com/querydsl/sql/TursoTemplates.java b/querydsl-libraries/querydsl-sql/src/main/java/com/querydsl/sql/TursoTemplates.java
new file mode 100644
index 0000000000..ac95640768
--- /dev/null
+++ b/querydsl-libraries/querydsl-sql/src/main/java/com/querydsl/sql/TursoTemplates.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2015, The Querydsl Team (http://www.querydsl.com/team)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.querydsl.sql;
+
+import com.querydsl.core.types.Ops;
+import com.querydsl.sql.types.BigDecimalAsDoubleType;
+import com.querydsl.sql.types.BigIntegerAsLongType;
+import java.sql.Types;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoField;
+
+/**
+ * {@code TursoTemplates} is a SQL dialect for Turso (https://github.com/tursodatabase/turso), a
+ * SQLite-compatible database
+ *
+ * @author tiwe
+ */
+public class TursoTemplates extends SQLTemplates {
+
+ private static final DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+
+ private static final DateTimeFormatter dateTimeFormatter =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+
+ private static final DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
+
+ @SuppressWarnings("FieldNameHidesFieldInSuperclass") // Intentional
+ public static final TursoTemplates DEFAULT = new TursoTemplates();
+
+ public static Builder builder() {
+ return new Builder() {
+ @Override
+ protected SQLTemplates build(char escape, boolean quote) {
+ return new TursoTemplates(escape, quote);
+ }
+ };
+ }
+
+ public TursoTemplates() {
+ this('\\', false);
+ }
+
+ public TursoTemplates(boolean quote) {
+ this('\\', quote);
+ }
+
+ public TursoTemplates(char escape, boolean quote) {
+ super(Keywords.TURSO, "\"", escape, quote, false);
+ setDummyTable(null);
+ addCustomType(BigDecimalAsDoubleType.DEFAULT);
+ addCustomType(BigIntegerAsLongType.DEFAULT);
+ setUnionsWrapped(false);
+ setLimitRequired(true);
+ setNullsFirst(null);
+ setNullsLast(null);
+ setDefaultValues("\ndefault values");
+ setArraysSupported(false);
+ setBatchToBulkSupported(false);
+
+ setPrecedence(Precedence.COMPARISON - 1, Ops.LT, Ops.GT, Ops.LOE, Ops.GOE);
+ setPrecedence(Precedence.COMPARISON, Ops.EQ, Ops.EQ_IGNORE_CASE, Ops.NE);
+
+ add(Ops.MOD, "{0} % {1}", Precedence.ARITH_HIGH);
+
+ add(Ops.INDEX_OF, "charindex({1},{0},1)-1", Precedence.ARITH_LOW);
+ add(Ops.INDEX_OF_2ARGS, "charindex({1},{0},{2s}+1)-1", Precedence.ARITH_LOW);
+
+ add(Ops.StringOps.LOCATE, "charindex({0},{1})");
+ add(Ops.StringOps.LOCATE2, "charindex({0},{1},{2s})");
+
+ // TODO : optimize
+ add(
+ Ops.DateTimeOps.YEAR,
+ "cast(strftime('%Y',{0} / 1000, 'unixepoch', 'localtime') as integer)");
+ add(
+ Ops.DateTimeOps.MONTH,
+ "cast(strftime('%m',{0} / 1000, 'unixepoch', 'localtime') as integer)");
+ add(
+ Ops.DateTimeOps.WEEK,
+ "cast(strftime('%W',{0} / 1000, 'unixepoch', 'localtime') as integer) + 1");
+ add(
+ Ops.DateTimeOps.DAY_OF_MONTH,
+ "cast(strftime('%d',{0} / 1000, 'unixepoch', 'localtime') as integer)");
+ add(
+ Ops.DateTimeOps.DAY_OF_WEEK,
+ "cast(strftime('%w',{0} / 1000, 'unixepoch', 'localtime') as integer) + 1");
+ add(
+ Ops.DateTimeOps.DAY_OF_YEAR,
+ "cast(strftime('%j',{0} / 1000, 'unixepoch', 'localtime') as integer)");
+ add(
+ Ops.DateTimeOps.HOUR,
+ "cast(strftime('%H',{0} / 1000, 'unixepoch', 'localtime') as integer)");
+ add(
+ Ops.DateTimeOps.MINUTE,
+ "cast(strftime('%M',{0} / 1000, 'unixepoch', 'localtime') as integer)");
+ add(
+ Ops.DateTimeOps.SECOND,
+ "cast(strftime('%S',{0} / 1000, 'unixepoch', 'localtime') as integer)");
+
+ add(
+ Ops.DateTimeOps.YEAR_MONTH,
+ """
+ cast(strftime('%Y',{0} / 1000, 'unixepoch', 'localtime') * 100 + strftime('%m',{0} / 1000,\
+ 'unixepoch', 'localtime') as integer)\
+ """);
+ add(
+ Ops.DateTimeOps.YEAR_WEEK,
+ "cast(strftime('%Y%W',{0} / 1000, 'unixepoch', 'localtime') as integer)");
+
+ add(Ops.DateTimeOps.ADD_YEARS, "date({0}, '+{1s} year')");
+ add(Ops.DateTimeOps.ADD_MONTHS, "date({0}, '+{1s} month')");
+ add(Ops.DateTimeOps.ADD_WEEKS, "date({0}, '+{1s} week')");
+ add(Ops.DateTimeOps.ADD_DAYS, "date({0}, '+{1s} day')");
+ add(Ops.DateTimeOps.ADD_HOURS, "date({0}, '+{1s} hour')");
+ add(Ops.DateTimeOps.ADD_MINUTES, "date({0}, '+{1s} minute')");
+ add(Ops.DateTimeOps.ADD_SECONDS, "date({0}, '+{1s} second')");
+
+ add(Ops.MathOps.RANDOM, "random()");
+ add(Ops.MathOps.RANDOM2, "random({0})");
+ add(Ops.MathOps.LN, "log({0})");
+ add(Ops.MathOps.LOG, "log({0}) / log({1})", Precedence.ARITH_HIGH);
+
+ add(SQLOps.GROUP_CONCAT2, "group_concat({0},{1})");
+
+ addTypeNameToCode("text", Types.VARCHAR);
+ }
+
+ @Override
+ public String serialize(String literal, int jdbcType) {
+ // XXX doesn't work with LocalDate, LocalDateTime and LocalTime
+ return switch (jdbcType) {
+ case Types.TIMESTAMP, TIMESTAMP_WITH_TIMEZONE ->
+ String.valueOf(
+ dateTimeFormatter
+ .parse(literal, LocalDateTime::from)
+ .toInstant(ZoneOffset.UTC)
+ .toEpochMilli());
+ case Types.DATE ->
+ String.valueOf(
+ dateFormatter
+ .parse(literal, LocalDate::from)
+ .atStartOfDay(ZoneOffset.UTC)
+ .toInstant()
+ .toEpochMilli());
+ case Types.TIME, TIME_WITH_TIMEZONE ->
+ String.valueOf(
+ timeFormatter.parse(literal, LocalTime::from).get(ChronoField.MILLI_OF_DAY));
+ default -> super.serialize(literal, jdbcType);
+ };
+ }
+}
diff --git a/querydsl-libraries/querydsl-sql/src/main/resources/keywords/turso b/querydsl-libraries/querydsl-sql/src/main/resources/keywords/turso
new file mode 100644
index 0000000000..9eded2e9c9
--- /dev/null
+++ b/querydsl-libraries/querydsl-sql/src/main/resources/keywords/turso
@@ -0,0 +1,146 @@
+# source https://github.com/tursodatabase/turso (SQLite-compatible)
+ABORT
+ACTION
+ADD
+AFTER
+ALL
+ALTER
+ALWAYS
+ANALYZE
+AND
+AS
+ASC
+ATTACH
+AUTOINCREMENT
+BEFORE
+BEGIN
+BETWEEN
+BY
+CASCADE
+CASE
+CAST
+CHECK
+COLLATE
+COLUMN
+COMMIT
+CONFLICT
+CONSTRAINT
+CREATE
+CROSS
+CURRENT
+CURRENT_DATE
+CURRENT_TIME
+CURRENT_TIMESTAMP
+DATABASE
+DEFAULT
+DEFERRABLE
+DEFERRED
+DELETE
+DESC
+DETACH
+DISTINCT
+DO
+DROP
+EACH
+ELSE
+END
+ESCAPE
+EXCEPT
+EXCLUSIVE
+EXISTS
+EXPLAIN
+FAIL
+FILTER
+FIRST
+FOLLOWING
+FOR
+FOREIGN
+FROM
+FULL
+GENERATED
+GLOB
+GROUP
+GROUPS
+HAVING
+IF
+IGNORE
+IMMEDIATE
+IN
+INDEX
+INDEXED
+INITIALLY
+INNER
+INSERT
+INSTEAD
+INTERSECT
+INTO
+IS
+ISNULL
+JOIN
+KEY
+LAST
+LEFT
+LIKE
+LIMIT
+MATCH
+MATERIALIZED
+NATURAL
+NO
+NOT
+NOTHING
+NOTNULL
+NULL
+NULLS
+OF
+OFFSET
+ON
+OR
+ORDER
+OTHERS
+OUTER
+OVER
+PARTITION
+PLAN
+PRAGMA
+PRECEDING
+PRIMARY
+QUERY
+RAISE
+RECURSIVE
+REFERENCES
+REGEXP
+REINDEX
+RELEASE
+RENAME
+REPLACE
+RESTRICT
+RETURNING
+RIGHT
+ROLLBACK
+ROW
+ROWS
+SAVEPOINT
+SELECT
+SET
+TABLE
+TEMP
+TEMPORARY
+THEN
+TIES
+TO
+TRANSACTION
+TRIGGER
+UNBOUNDED
+UNION
+UNIQUE
+UPDATE
+USING
+VACUUM
+VALUES
+VIEW
+VIRTUAL
+WHEN
+WHERE
+WINDOW
+WITH
+WITHOUT
diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/AbstractBaseTest.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/AbstractBaseTest.java
index 0246544972..80644dc134 100644
--- a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/AbstractBaseTest.java
+++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/AbstractBaseTest.java
@@ -30,6 +30,7 @@
import java.util.List;
import java.util.logging.Logger;
import org.jetbrains.annotations.Nullable;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
@ExtendWith({TargetExtension.class, SkipForQuotedExtension.class})
@@ -84,6 +85,22 @@ public AbstractBaseTest() {
}
}
+ // Turso (early-stage SQLite reimplementation) closes the shared connection when a statement
+ // errors, which would otherwise cascade "database connection closed" across every later test.
+ // Reconnecting per test isolates each test so we see its true pass/fail result.
+ @BeforeEach
+ public void reconnectClosedTursoConnection() throws java.sql.SQLException {
+ if (target == Target.TURSO && (connection == null || connection.isClosed())) {
+ try {
+ Connections.initTurso();
+ } catch (ClassNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
+ connection = Connections.getConnection();
+ configuration = Connections.getConfiguration();
+ }
+ }
+
protected void add(List list, T arg, Target... exclusions) {
if (exclusions.length > 0) {
for (Target t : exclusions) {
diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/BeanPopulationBase.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/BeanPopulationBase.java
index 2e206882f8..f324a1601e 100644
--- a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/BeanPopulationBase.java
+++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/BeanPopulationBase.java
@@ -21,6 +21,7 @@
import static com.querydsl.core.Target.SQLITE;
import static com.querydsl.core.Target.SQLSERVER;
import static com.querydsl.core.Target.TERADATA;
+import static com.querydsl.core.Target.TURSO;
import static org.assertj.core.api.Assertions.assertThat;
import com.querydsl.core.testutil.ExcludeIn;
@@ -40,6 +41,7 @@ public void tearDown() {
delete(e).where(e.firstname.eq("John")).execute();
}
+ @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812
@Test
public void custom_projection() {
// Insert
@@ -87,6 +89,7 @@ public void custom_projection() {
assertThat(delete(e).where(e.id.eq(employee.getId())).execute()).isEqualTo(1L);
}
+ @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812
@Test
public void insert_update_query_and_delete() {
// Insert
@@ -109,6 +112,7 @@ public void insert_update_query_and_delete() {
assertThat(delete(e).where(e.id.eq(employee.getId())).execute()).isEqualTo(1L);
}
+ @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812
@Test
public void populate_with_beanMapper() {
var employee = new Employee();
diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/Connections.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/Connections.java
index 5dfc844e90..d8e0f73275 100644
--- a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/Connections.java
+++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/Connections.java
@@ -75,6 +75,7 @@ public final class Connections {
oracleInited,
postgresqlInited,
sqliteInited,
+ tursoInited,
teradataInited,
firebirdInited;
@@ -170,6 +171,11 @@ private static Connection getSQLite() throws SQLException, ClassNotFoundExceptio
return DriverManager.getConnection("jdbc:sqlite:target/sample.db");
}
+ private static Connection getTurso() throws SQLException, ClassNotFoundException {
+ Class.forName("tech.turso.JDBC");
+ return DriverManager.getConnection("jdbc:turso:target/turso-sample.db");
+ }
+
private static Connection getTeradata() throws SQLException, ClassNotFoundException {
Class.forName("com.teradata.jdbc.TeraDriver");
return DriverManager.getConnection("jdbc:teradata://teradata/dbc", "querydsl", "querydsl");
@@ -1107,6 +1113,78 @@ CONSTRAINT FK_SUPERIOR FOREIGN KEY(SUPERIOR_ID) REFERENCES EMPLOYEE(ID) \
sqliteInited = true;
}
+ public static void initTurso() throws SQLException, ClassNotFoundException {
+ targetHolder.set(Target.TURSO);
+ var c = getTurso();
+ connHolder.set(c);
+ var stmt = c.createStatement();
+ stmtHolder.set(stmt);
+
+ if (tursoInited) {
+ return;
+ }
+
+ // qtest
+ stmt.execute("drop table if exists QTEST");
+ stmt.execute("create table QTEST (ID int IDENTITY(1,1) NOT NULL, C1 int NULL)");
+
+ // survey
+ stmt.execute("drop table if exists SURVEY");
+ stmt.execute(
+ """
+ create table SURVEY(ID int auto_increment, \
+ NAME varchar(30),\
+ NAME2 varchar(30),\
+ constraint survey_pk primary key(ID))\
+ """);
+ stmt.execute("insert into SURVEY values (1,'Hello World','Hello');");
+
+ // test
+ stmt.execute("drop table if exists TEST");
+ stmt.execute(CREATE_TABLE_TEST);
+ try (var pstmt = c.prepareStatement(INSERT_INTO_TEST_VALUES)) {
+ for (var i = 0; i < TEST_ROW_COUNT; i++) {
+ pstmt.setString(1, "name" + i);
+ pstmt.addBatch();
+ }
+ pstmt.executeBatch();
+ }
+
+ // employee
+ stmt.execute("drop table if exists EMPLOYEE");
+ stmt.execute(
+ """
+ create table EMPLOYEE ( \
+ ID INT AUTO_INCREMENT, \
+ FIRSTNAME VARCHAR(50), \
+ LASTNAME VARCHAR(50), \
+ SALARY DECIMAL, \
+ DATEFIELD DATE, \
+ TIMEFIELD TIME, \
+ SUPERIOR_ID INT, \
+ CONSTRAINT PK_EMPLOYEE PRIMARY KEY(ID),\
+ CONSTRAINT FK_SUPERIOR FOREIGN KEY(SUPERIOR_ID) REFERENCES EMPLOYEE(ID) \
+ )\
+ """);
+ addEmployees(INSERT_INTO_EMPLOYEE);
+
+ // date_test and time_test
+ stmt.execute("drop table if exists TIME_TEST");
+ stmt.execute("drop table if exists DATE_TEST");
+ stmt.execute(CREATE_TABLE_TIMETEST);
+ stmt.execute(CREATE_TABLE_DATETEST);
+
+ // numbers
+ stmt.execute("drop table if exists NUMBER_TEST");
+ stmt.execute("create table NUMBER_TEST(col1 integer)");
+
+ // xml
+ stmt.execute("drop table if exists XML_TEST");
+ stmt.execute("create table XML_TEST(COL varchar(128))");
+
+ tursoInited = true;
+ }
+
public static void initSQLServer() throws SQLException, ClassNotFoundException {
targetHolder.set(Target.SQLSERVER);
SQLTemplates templates = new SQLServerTemplates();
diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/DateArithmeticTest.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/DateArithmeticTest.java
index 5e892f0ff3..9358d61d77 100644
--- a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/DateArithmeticTest.java
+++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/DateArithmeticTest.java
@@ -29,6 +29,7 @@ public void test() {
list.add(new OracleTemplates());
list.add(new PostgreSQLTemplates());
list.add(new SQLiteTemplates());
+ list.add(new TursoTemplates());
list.add(new SQLServerTemplates());
list.add(new SQLServer2005Templates());
list.add(new SQLServer2012Templates());
diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/DeleteBase.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/DeleteBase.java
index da50efd59e..bc317b5b03 100644
--- a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/DeleteBase.java
+++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/DeleteBase.java
@@ -20,6 +20,7 @@
import static com.querydsl.core.Target.ORACLE;
import static com.querydsl.core.Target.SQLITE;
import static com.querydsl.core.Target.SQLSERVER;
+import static com.querydsl.core.Target.TURSO;
import static com.querydsl.sql.Constants.survey;
import static org.assertj.core.api.Assertions.assertThat;
@@ -51,6 +52,7 @@ public void tearDown() throws SQLException {
reset();
}
+ @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812
@Test
public void batch() throws SQLException {
insert(survey).values(2, "A", "B").execute();
@@ -65,7 +67,7 @@ public void batch() throws SQLException {
}
@Test
- @ExcludeIn({CUBRID, SQLITE, FIREBIRD})
+ @ExcludeIn({CUBRID, SQLITE, FIREBIRD, TURSO})
public void batch_templates() throws SQLException {
insert(survey).values(2, "A", "B").execute();
insert(survey).values(3, "B", "C").execute();
@@ -77,7 +79,7 @@ public void batch_templates() throws SQLException {
}
@Test
- @ExcludeIn(MYSQL)
+ @ExcludeIn({MYSQL, TURSO})
public void delete() throws SQLException {
var count = query().from(survey).fetchCount();
assertThat(delete(survey).where(survey.name.eq("XXX")).execute()).isEqualTo(0);
@@ -94,6 +96,7 @@ public void delete_limit() {
assertThat(delete(survey).limit(2).execute()).isEqualTo(2);
}
+ @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812
@Test
public void delete_with_subQuery_exists() {
var survey1 = new QSurvey("s1");
@@ -104,6 +107,7 @@ public void delete_with_subQuery_exists() {
assertThat(delete.execute()).isEqualTo(0);
}
+ @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812
@Test
public void delete_with_subQuery_exists_Params() {
var survey1 = new QSurvey("s1");
@@ -118,6 +122,7 @@ public void delete_with_subQuery_exists_Params() {
assertThat(delete.execute()).isEqualTo(0);
}
+ @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812
@Test
public void delete_with_subQuery_exists2() {
var survey1 = new QSurvey("s1");
@@ -130,7 +135,7 @@ public void delete_with_subQuery_exists2() {
}
@Test
- @ExcludeIn({CUBRID, SQLITE, FIREBIRD})
+ @ExcludeIn({CUBRID, SQLITE, FIREBIRD, TURSO})
public void delete_with_tempateExpression_in_batch() {
assertThat(
delete(survey)
diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/InsertBase.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/InsertBase.java
index eac6a9fca0..b4c7539a79 100644
--- a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/InsertBase.java
+++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/InsertBase.java
@@ -24,6 +24,7 @@
import static com.querydsl.core.Target.POSTGRESQL;
import static com.querydsl.core.Target.SQLITE;
import static com.querydsl.core.Target.SQLSERVER;
+import static com.querydsl.core.Target.TURSO;
import static com.querydsl.sql.Constants.survey;
import static com.querydsl.sql.Constants.survey2;
import static com.querydsl.sql.SQLExpressions.select;
@@ -78,7 +79,7 @@ public void tearDown() throws SQLException {
@Test
@ExcludeIn({
- CUBRID, SQLITE, DERBY, ORACLE
+ CUBRID, SQLITE, DERBY, ORACLE, TURSO
}) // https://bitbucket.org/xerial/sqlite-jdbc/issue/133/prepstmtsetdate-int-date-calendar-seems
public void insert_dates() {
var dateTest = QDateTest.qDateTest;
@@ -256,7 +257,7 @@ public void insert_with_columns() {
}
@Test
- @ExcludeIn({CUBRID, SQLSERVER, SQLITE})
+ @ExcludeIn({CUBRID, SQLSERVER, SQLITE, TURSO})
public void insert_with_keys() throws SQLException {
var rs = insert(survey).set(survey.name, "Hello World").executeWithKeys();
assertThat(rs.next()).isTrue();
@@ -265,7 +266,7 @@ public void insert_with_keys() throws SQLException {
}
@Test
- @ExcludeIn({CUBRID, SQLSERVER, SQLITE})
+ @ExcludeIn({CUBRID, SQLSERVER, SQLITE, TURSO})
public void insert_with_keys_listener() throws SQLException {
final var result = new AtomicBoolean();
SQLListener listener =
@@ -286,13 +287,13 @@ public void end(SQLListenerContext context) {
}
@Test
- @ExcludeIn({CUBRID, SQLSERVER, SQLITE})
+ @ExcludeIn({CUBRID, SQLSERVER, SQLITE, TURSO})
public void insert_with_keys_Projected() throws SQLException {
assertThat(insert(survey).set(survey.name, "Hello you").executeWithKey(survey.id)).isNotNull();
}
@Test
- @ExcludeIn({CUBRID, SQLSERVER, SQLITE})
+ @ExcludeIn({CUBRID, SQLSERVER, SQLITE, TURSO})
public void insert_with_keys_Projected2() throws SQLException {
Path
+
+ tech.turso
+ turso
+ ${turso.version}
+ test
+
+
io.github.openfeign.querydsl
querydsl-core
diff --git a/querydsl-tooling/querydsl-sql-codegen/src/test/java/com/querydsl/sql/codegen/ExportTursoTest.java b/querydsl-tooling/querydsl-sql-codegen/src/test/java/com/querydsl/sql/codegen/ExportTursoTest.java
new file mode 100644
index 0000000000..ff9ae3d0af
--- /dev/null
+++ b/querydsl-tooling/querydsl-sql-codegen/src/test/java/com/querydsl/sql/codegen/ExportTursoTest.java
@@ -0,0 +1,18 @@
+package com.querydsl.sql.codegen;
+
+import com.querydsl.sql.Connections;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Tag;
+
+// Turso 0.6.0 JDBC DatabaseMetaData.getPrimaryKeys() returns null, so schema export codegen
+// cannot read the database metadata. Re-enable once the driver implements it. See #1812.
+@Disabled("Turso 0.6.0 JDBC metadata (getPrimaryKeys) incomplete, see #1812")
+@Tag("com.querydsl.core.testutil.Turso")
+public class ExportTursoTest extends ExportBaseTest {
+
+ @BeforeAll
+ public static void setUpClass() throws Exception {
+ Connections.initTurso();
+ }
+}