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 idPath = ExpressionUtils.path(Object.class, "id"); Object id = insert(survey).set(survey.name, "Hello you").executeWithKey(idPath); diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/KeywordQuotingBase.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/KeywordQuotingBase.java index 94220ef73a..0b9a94ad4c 100644 --- a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/KeywordQuotingBase.java +++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/KeywordQuotingBase.java @@ -101,6 +101,7 @@ public void validateKeywordsCompleteness() throws SQLException { case ORACLE -> Keywords.ORACLE; case POSTGRESQL -> Keywords.POSTGRESQL; case SQLITE -> Keywords.SQLITE; + case TURSO -> Keywords.TURSO; case SQLSERVER -> Keywords.SQLSERVER2012; case TERADATA -> Keywords.DEFAULT; }; diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/MergeBase.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/MergeBase.java index b613745dde..6bc85f396e 100644 --- a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/MergeBase.java +++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/MergeBase.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 com.querydsl.sql.Constants.survey; import static com.querydsl.sql.Constants.survey2; import static org.assertj.core.api.Assertions.assertThat; @@ -56,7 +57,7 @@ public void tearDown() throws SQLException { } @Test - @ExcludeIn({H2, CUBRID, SQLSERVER, SQLITE}) + @ExcludeIn({H2, CUBRID, SQLSERVER, SQLITE, TURSO}) public void merge_with_keys() throws SQLException { var rs = merge(survey) @@ -70,7 +71,7 @@ public void merge_with_keys() throws SQLException { } @Test - @ExcludeIn({H2, CUBRID, SQLSERVER, SQLITE}) + @ExcludeIn({H2, CUBRID, SQLSERVER, SQLITE, TURSO}) public void merge_with_keys_listener() throws SQLException { final var result = new AtomicBoolean(); SQLListener listener = @@ -139,7 +140,7 @@ public void merge_with_keys_columns_and_values_using_null() { } @Test - @ExcludeIn({CUBRID, DB2, DERBY, POSTGRESQL, SQLSERVER, TERADATA, SQLITE}) + @ExcludeIn({CUBRID, DB2, DERBY, POSTGRESQL, SQLSERVER, TERADATA, SQLITE, TURSO}) public void merge_with_keys_Null_Id() throws SQLException { var rs = merge(survey) @@ -153,7 +154,7 @@ public void merge_with_keys_Null_Id() throws SQLException { } @Test - @ExcludeIn({H2, CUBRID, SQLSERVER, SQLITE}) + @ExcludeIn({H2, CUBRID, SQLSERVER, SQLITE, TURSO}) public void merge_with_keys_Projected() throws SQLException { assertThat( merge(survey) @@ -165,7 +166,7 @@ public void merge_with_keys_Projected() throws SQLException { } @Test - @ExcludeIn({H2, CUBRID, SQLSERVER, SQLITE}) + @ExcludeIn({H2, CUBRID, SQLSERVER, SQLITE, TURSO}) public void merge_with_keys_Projected2() throws SQLException { Path idPath = ExpressionUtils.path(Object.class, "id"); Object id = diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/SelectBase.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/SelectBase.java index 1773e4f329..ff4cf44f6d 100644 --- a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/SelectBase.java +++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/SelectBase.java @@ -26,6 +26,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 com.querydsl.sql.Constants.date; import static com.querydsl.sql.Constants.employee; import static com.querydsl.sql.Constants.employee2; @@ -130,6 +131,7 @@ private Tuple firstResult(Expression... exprs) { return query().select(exprs).fetchFirst(); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void aggregate_list() { int min = 30000, avg = 65000, max = 160000; @@ -142,6 +144,7 @@ public void aggregate_list() { .isEqualTo(max); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void aggregate_uniqueResult() { int min = 30000, avg = 65000, max = 160000; @@ -214,6 +217,7 @@ private void arithmeticTests( assertThat(firstResult(four.divide(two.multiply(two))).intValue()).isEqualTo(1); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void arithmetic() { NumberExpression one = Expressions.numberTemplate(Integer.class, "(1.0)"); @@ -289,6 +293,7 @@ public void array_projection() { } } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void beans() { var rows = query().from(employee, employee2).select(new QBeans(employee, employee2)).fetch(); @@ -313,7 +318,7 @@ public void between() { } @Test - @ExcludeIn({ORACLE, CUBRID, FIREBIRD, DB2, DERBY, SQLSERVER, SQLITE, TERADATA}) + @ExcludeIn({ORACLE, CUBRID, FIREBIRD, DB2, DERBY, SQLSERVER, SQLITE, TERADATA, TURSO}) public void boolean_all() { assertThat( query() @@ -324,7 +329,7 @@ public void boolean_all() { } @Test - @ExcludeIn({ORACLE, CUBRID, FIREBIRD, DB2, DERBY, SQLSERVER, SQLITE, TERADATA}) + @ExcludeIn({ORACLE, CUBRID, FIREBIRD, DB2, DERBY, SQLSERVER, SQLITE, TERADATA, TURSO}) public void boolean_any() { assertThat( query() @@ -415,6 +420,7 @@ public void complex_boolean() { .isEqualTo(0); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void complex_subQuery() { // alias for the salary @@ -533,7 +539,7 @@ public void custom_projection() { } @Test - @ExcludeIn({CUBRID, DB2, DERBY, HSQLDB, POSTGRESQL, SQLITE, TERADATA, H2, FIREBIRD}) + @ExcludeIn({CUBRID, DB2, DERBY, HSQLDB, POSTGRESQL, SQLITE, TERADATA, H2, FIREBIRD, TURSO}) public void dates() throws SQLException { if (!configuration.getUseLiterals()) { dates(false); @@ -541,7 +547,7 @@ public void dates() throws SQLException { } @Test - @ExcludeIn({CUBRID, DB2, DERBY, SQLITE, TERADATA, FIREBIRD}) + @ExcludeIn({CUBRID, DB2, DERBY, SQLITE, TERADATA, FIREBIRD, TURSO}) public void dates_literals() throws SQLException { if (configuration.getUseLiterals()) { dates(true); @@ -647,7 +653,7 @@ private void dates(boolean literals) throws SQLException { } @Test - @ExcludeIn({SQLITE}) + @ExcludeIn({SQLITE, TURSO}) public void date_add() { SQLQuery query = query().from(employee); var date1 = query.select(employee.datefield).fetchFirst(); @@ -661,7 +667,7 @@ public void date_add() { } @Test - @ExcludeIn({SQLITE}) + @ExcludeIn({SQLITE, TURSO}) public void date_add_Timestamp() { List> exprs = new ArrayList<>(); var dt = Expressions.currentTimestamp(); @@ -679,7 +685,7 @@ public void date_add_Timestamp() { } @Test - @ExcludeIn({DB2, SQLITE, TERADATA}) + @ExcludeIn({DB2, SQLITE, TERADATA, TURSO}) public void date_diff() { var employee2 = new QEmployee("employee2"); SQLQuery query = query().from(employee).orderBy(employee.id.asc()); @@ -720,7 +726,7 @@ public void date_diff() { // TDO Date_diff with timestamps @Test - @ExcludeIn({DB2, HSQLDB, SQLITE, TERADATA, ORACLE}) + @ExcludeIn({DB2, HSQLDB, SQLITE, TERADATA, ORACLE, TURSO}) public void date_diff2() { SQLQuery query = query().from(employee).orderBy(employee.id.asc()); @@ -757,7 +763,7 @@ public void date_diff2() { } @Test - @ExcludeIn({SQLITE, H2}) // FIXME + @ExcludeIn({SQLITE, H2, TURSO}) // FIXME public void date_trunc() { var expr = DateTimeExpression.currentTimestamp(); @@ -776,7 +782,7 @@ public void date_trunc() { } @Test - @ExcludeIn({SQLITE, TERADATA, DERBY, H2}) // FIXME + @ExcludeIn({SQLITE, TERADATA, DERBY, H2, TURSO}) // FIXME public void date_trunc2() { DateTimeExpression expr = DateTimeExpression.currentTimestamp(LocalDateTime.class); @@ -854,6 +860,7 @@ public void date_trunc2() { assertThat(toSecond.getSecond()).isEqualTo(date.getSecond()); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void dateTime() { SQLQuery query = query().from(employee).orderBy(employee.id.asc()); @@ -867,7 +874,7 @@ public void dateTime() { } @Test - @ExcludeIn({SQLITE}) + @ExcludeIn({SQLITE, TURSO}) public void dateTime_to_date() { firstResult(SQLExpressions.date(DateTimeExpression.currentTimestamp())); } @@ -920,7 +927,7 @@ public void factoryExpression_in_groupBy() { } @Test - @ExcludeIn({H2, SQLITE, DERBY, CUBRID, MYSQL}) + @ExcludeIn({H2, SQLITE, DERBY, CUBRID, MYSQL, TURSO}) public void full_join() throws SQLException { assertThat( query() @@ -990,7 +997,7 @@ public void groupBy_yearMonth() { } @Test - @ExcludeIn({H2, DB2, DERBY, ORACLE, SQLSERVER}) + @ExcludeIn({H2, DB2, DERBY, ORACLE, SQLSERVER, TURSO}) public void groupBy_validate() { NumberPath alias = Expressions.numberPath(BigDecimal.class, "alias"); assertThat( @@ -1061,6 +1068,7 @@ public void illegalUnion() throws SQLException { }); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void in() { assertThat( @@ -1255,6 +1263,7 @@ public void limit_and_offset() throws SQLException { .isEqualTo(Arrays.asList(20, 13, 10, 2)); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void limit_and_offset_Group() { assertThat( @@ -1377,6 +1386,7 @@ public void listResults2() { assertThat(results.getTotal()).isEqualTo(10); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void listResults_factoryExpression() { var results = @@ -1419,7 +1429,7 @@ private double log(double x, int y) { } @Test - @ExcludeIn({SQLITE, DERBY}) + @ExcludeIn({SQLITE, DERBY, TURSO}) public void lPad() { assertThat(firstResult(StringExpressions.lpad(ConstantImpl.create("ab"), 4))).isEqualTo(" ab"); assertThat(firstResult(StringExpressions.lpad(ConstantImpl.create("ab"), 4, '!'))) @@ -1459,13 +1469,13 @@ protected Pair map(Tuple row) { } @Test - @ExcludeIn({HSQLDB, SQLITE}) // FIXME + @ExcludeIn({HSQLDB, SQLITE, TURSO}) // FIXME public void math() { math(Expressions.numberTemplate(Double.class, "0.50")); } @Test - @ExcludeIn({FIREBIRD, SQLSERVER, HSQLDB, SQLITE}) // FIXME + @ExcludeIn({FIREBIRD, SQLSERVER, HSQLDB, SQLITE, TURSO}) // FIXME public void math2() { math(Expressions.constant(0.5)); } @@ -1536,7 +1546,7 @@ public void nested_tuple_projection() { } @Test - @ExcludeIn({SQLITE}) + @ExcludeIn({SQLITE, TURSO}) public void no_from() { assertThat(firstResult(DateExpression.currentDate())).isNotNull(); } @@ -1691,7 +1701,7 @@ public void params_not_set() { } @Test - @ExcludeIn({DB2, DERBY, FIREBIRD, HSQLDB, ORACLE, SQLSERVER}) + @ExcludeIn({DB2, DERBY, FIREBIRD, HSQLDB, ORACLE, SQLSERVER, TURSO}) @SkipForQuoted public void path_alias() { expectedQuery = @@ -1824,17 +1834,19 @@ private double radians(double x) { return x * Math.PI / 180.0; } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void random() { firstResult(MathExpressions.random()); } @Test - @ExcludeIn({FIREBIRD, ORACLE, POSTGRESQL, SQLITE, TERADATA}) + @ExcludeIn({FIREBIRD, ORACLE, POSTGRESQL, SQLITE, TERADATA, TURSO}) public void random2() { firstResult(MathExpressions.random(10)); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void relationalPath_projection() { var results = @@ -1918,7 +1930,7 @@ public void round() { } @Test - @ExcludeIn({SQLITE, DERBY}) + @ExcludeIn({SQLITE, DERBY, TURSO}) public void rpad() { assertThat(firstResult(StringExpressions.rpad(ConstantImpl.create("ab"), 4))).isEqualTo("ab "); assertThat(firstResult(StringExpressions.rpad(ConstantImpl.create("ab"), 4, '!'))) @@ -1957,13 +1969,13 @@ public void select_concat() throws SQLException { } @Test - @ExcludeIn({SQLITE, CUBRID, TERADATA}) + @ExcludeIn({SQLITE, CUBRID, TERADATA, TURSO}) public void select_for_update() { assertThat(query().from(survey).forUpdate().select(survey.id).fetch()).hasSize(1); } @Test - @ExcludeIn({SQLITE, CUBRID, TERADATA}) + @ExcludeIn({SQLITE, CUBRID, TERADATA, TURSO}) public void select_for_update_Where() { assertThat( query().from(survey).forUpdate().where(survey.id.isNotNull()).select(survey.id).fetch()) @@ -1971,7 +1983,7 @@ public void select_for_update_Where() { } @Test - @ExcludeIn({SQLITE, CUBRID, TERADATA}) + @ExcludeIn({SQLITE, CUBRID, TERADATA, TURSO}) public void select_for_update_UniqueResult() { query().from(survey).forUpdate().select(survey.id).fetchOne(); } @@ -2063,6 +2075,7 @@ public void specialChars() { .isEqualTo(0); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void standardTest() { standardTest.runBooleanTests(employee.firstname.isNull(), employee2.lastname.isNotNull()); @@ -2077,7 +2090,7 @@ public void standardTest() { standardTest.runStringTests(employee.firstname, employee2.firstname, "Jennifer"); var target = Connections.getTarget(); - if (target != SQLITE) { + if (target != SQLITE && target != TURSO) { standardTest.runTimeTests(employee.timefield, employee2.timefield, time); } @@ -2097,7 +2110,7 @@ public void standardTest_turkish() { } @Test - @ExcludeIn(SQLITE) + @ExcludeIn({SQLITE, TURSO}) public void string() { StringExpression str = Expressions.stringTemplate("' abcd '"); @@ -2110,7 +2123,7 @@ public void string() { } @Test - @ExcludeIn(SQLITE) + @ExcludeIn({SQLITE, TURSO}) public void string_withTemplate() { StringExpression str = Expressions.stringTemplate("' abcd '"); @@ -2127,7 +2140,7 @@ public void string_withTemplate() { } @Test - @ExcludeIn({POSTGRESQL, SQLITE}) + @ExcludeIn({POSTGRESQL, SQLITE, TURSO}) public void string_indexOf() { StringExpression str = Expressions.stringTemplate("' abcd '"); @@ -2149,7 +2162,7 @@ public void stringFunctions2() throws SQLException { } @Test - @ExcludeIn(SQLITE) + @ExcludeIn({SQLITE, TURSO}) public void string_left() { assertThat( query() @@ -2161,7 +2174,7 @@ public void string_left() { } @Test - @ExcludeIn({DERBY, SQLITE}) + @ExcludeIn({DERBY, SQLITE, TURSO}) public void string_right() { assertThat( query() @@ -2173,7 +2186,7 @@ public void string_right() { } @Test - @ExcludeIn({DERBY, SQLITE}) + @ExcludeIn({DERBY, SQLITE, TURSO}) public void string_left_Right() { assertThat( query() @@ -2185,7 +2198,7 @@ public void string_left_Right() { } @Test - @ExcludeIn({DERBY, SQLITE}) + @ExcludeIn({DERBY, SQLITE, TURSO}) public void string_right_Left() { assertThat( query() @@ -2246,6 +2259,7 @@ public void templateExpression() { .isEqualTo(Collections.singletonList(1)); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void transform_groupBy() { var employee = new QEmployee("employee"); @@ -2334,6 +2348,7 @@ public void unique_wildcard() { assertThat(row.get(1, Object.class)).as(row.get(0, Object.class) + " is not null").isNotNull(); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void uniqueResultContract() { assertThrows( @@ -2541,7 +2556,7 @@ public void withinGroup() { } @Test - @ExcludeIn({DB2, DERBY, H2}) + @ExcludeIn({DB2, DERBY, H2, TURSO}) public void yearWeek() { SQLQuery query = query().from(employee).orderBy(employee.id.asc()); assertThat(query.select(employee.datefield.yearWeek()).fetchFirst()) @@ -2556,6 +2571,7 @@ public void yearWeek_h2() { .isEqualTo(Integer.valueOf(200007)); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void statementOptions() { diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/SubqueriesBase.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/SubqueriesBase.java index aa2eb718db..2e3a7f6fbd 100644 --- a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/SubqueriesBase.java +++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/SubqueriesBase.java @@ -11,6 +11,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 com.querydsl.sql.Constants.employee; import static com.querydsl.sql.Constants.employee2; import static com.querydsl.sql.Constants.survey; @@ -89,6 +90,7 @@ public void subQueries() throws SQLException { assertThat(list).isNotEmpty(); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void subQuery_alias() { query() @@ -98,7 +100,7 @@ public void subQuery_alias() { } @Test - @ExcludeIn(SQLITE) + @ExcludeIn({SQLITE, TURSO}) public void subQuery_all() { query() .from(employee) @@ -107,7 +109,7 @@ public void subQuery_all() { } @Test - @ExcludeIn(SQLITE) + @ExcludeIn({SQLITE, TURSO}) public void subQuery_any() { query() .from(employee) diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/TursoTemplatesTest.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/TursoTemplatesTest.java new file mode 100644 index 0000000000..8a839525f6 --- /dev/null +++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/TursoTemplatesTest.java @@ -0,0 +1,83 @@ +/* + * 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 static com.querydsl.sql.SQLExpressions.select; +import static org.assertj.core.api.Assertions.assertThat; + +import com.querydsl.core.types.Ops; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.dsl.Expressions; +import org.junit.jupiter.api.Test; + +public class TursoTemplatesTest extends AbstractSQLTemplatesTest { + + @Override + protected SQLTemplates createTemplates() { + return new TursoTemplates(); + } + + @SuppressWarnings("unchecked") + @Test + @Override + public void union() { + var one = Expressions.ONE; + var two = Expressions.TWO; + var three = Expressions.THREE; + Path col1 = Expressions.path(Integer.class, "col1"); + Union union = query.union(select(one.as(col1)), select(two), select(three)); + + assertThat(union.toString()) + .isEqualTo( + """ + select 1 as col1 + union + select 2 + union + select 3"""); + } + + @Test + public void precedence() { + // || + // * / % + var p1 = getPrecedence(Ops.MULT, Ops.DIV, Ops.MOD); + // + - + var p2 = getPrecedence(Ops.ADD, Ops.SUB); + // << >> & | + // < <= > >= + var p3 = getPrecedence(Ops.LT, Ops.GT, Ops.LOE, Ops.GOE); + // = == != <> IS IS NOT IN LIKE GLOB MATCH REGEXP + var p4 = + getPrecedence( + Ops.EQ, + Ops.EQ_IGNORE_CASE, + Ops.IS_NULL, + Ops.IS_NOT_NULL, + Ops.IN, + Ops.LIKE, + Ops.LIKE_ESCAPE, + Ops.MATCHES); + // AND + var p5 = getPrecedence(Ops.AND); + // OR + var p6 = getPrecedence(Ops.OR); + + assertThat(p1 < p2).isTrue(); + assertThat(p2 < p3).isTrue(); + assertThat(p3 < p4).isTrue(); + assertThat(p4 < p5).isTrue(); + assertThat(p5 < p6).isTrue(); + } +} diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/TypesBase.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/TypesBase.java index 8d90454c63..95d0d33bb5 100644 --- a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/TypesBase.java +++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/TypesBase.java @@ -3,6 +3,7 @@ import static com.querydsl.core.Target.CUBRID; import static com.querydsl.core.Target.POSTGRESQL; import static com.querydsl.core.Target.TERADATA; +import static com.querydsl.core.Target.TURSO; import com.querydsl.core.testutil.ExcludeIn; import com.querydsl.core.types.Path; @@ -51,7 +52,7 @@ public void create_tables() { } @Test - @ExcludeIn({CUBRID, POSTGRESQL, TERADATA}) + @ExcludeIn({CUBRID, POSTGRESQL, TERADATA, TURSO}) public void dump_types() throws SQLException { var conn = Connections.getConnection(); var md = conn.getMetaData(); diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/UpdateBase.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/UpdateBase.java index a82749c28b..b241555522 100644 --- a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/UpdateBase.java +++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/UpdateBase.java @@ -21,6 +21,7 @@ import static com.querydsl.core.Target.ORACLE; import static com.querydsl.core.Target.SQLSERVER; import static com.querydsl.core.Target.TERADATA; +import static com.querydsl.core.Target.TURSO; import static com.querydsl.sql.Constants.survey; import static com.querydsl.sql.SQLExpressions.selectOne; import static org.assertj.core.api.Assertions.assertThat; @@ -56,6 +57,7 @@ public void tearDown() throws SQLException { reset(); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void update() throws SQLException { // original state @@ -81,6 +83,7 @@ public void update_limit() { assertThat(update(survey).set(survey.name, "S").limit(2).execute()).isEqualTo(2); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void update2() throws SQLException { List> paths = Collections.>singletonList(survey.name); @@ -105,6 +108,7 @@ public void update3() { assertThat(update(survey).set(survey.name, survey.name.append("X")).execute()).isEqualTo(1); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void update4() { assertThat(insert(survey).values(2, "A", "B").execute()).isEqualTo(1); @@ -112,6 +116,7 @@ public void update4() { .isEqualTo(1); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void update5() { assertThat(insert(survey).values(3, "B", "C").execute()).isEqualTo(1); @@ -142,6 +147,7 @@ public void setNullEmptyRootPath() { assertThat(execute(update(survey).setNull(name))).isEqualTo(count); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void batch() throws SQLException { assertThat(insert(survey).values(2, "A", "B").execute()).isEqualTo(1); @@ -155,6 +161,7 @@ public void batch() throws SQLException { assertThat(update.execute()).isEqualTo(2); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void batch_templates() throws SQLException { assertThat(insert(survey).values(2, "A", "B").execute()).isEqualTo(1); @@ -172,6 +179,7 @@ public void batch_templates() throws SQLException { assertThat(update.execute()).isEqualTo(2); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void update_with_subQuery_exists() { var survey1 = new QSurvey("s1"); @@ -197,6 +205,7 @@ public void update_with_subQuery_exists_Params() { assertThat(update.execute()).isEqualTo(0); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void update_with_subQuery_exists2() { var survey1 = new QSurvey("s1"); @@ -207,6 +216,7 @@ public void update_with_subQuery_exists2() { assertThat(update.execute()).isEqualTo(0); } + @ExcludeIn(TURSO) // Turso 0.6.0 gap, see #1812 @Test public void update_with_subQuery_notExists() { var survey1 = new QSurvey("s1"); diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/suites/TursoLiteralsSuiteTest.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/suites/TursoLiteralsSuiteTest.java new file mode 100644 index 0000000000..704111d0a7 --- /dev/null +++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/suites/TursoLiteralsSuiteTest.java @@ -0,0 +1,62 @@ +package com.querydsl.sql.suites; + +import com.querydsl.sql.BeanPopulationBase; +import com.querydsl.sql.Connections; +import com.querydsl.sql.DeleteBase; +import com.querydsl.sql.InsertBase; +import com.querydsl.sql.KeywordQuotingBase; +import com.querydsl.sql.LikeEscapeBase; +import com.querydsl.sql.MergeBase; +import com.querydsl.sql.SelectBase; +import com.querydsl.sql.SubqueriesBase; +import com.querydsl.sql.TursoTemplates; +import com.querydsl.sql.TypesBase; +import com.querydsl.sql.UnionBase; +import com.querydsl.sql.UpdateBase; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Tag; + +@Tag("com.querydsl.core.testutil.Turso") +public class TursoLiteralsSuiteTest extends AbstractSuite { + + @Nested + class BeanPopulation extends BeanPopulationBase {} + + @Nested + class Delete extends DeleteBase {} + + @Nested + class Insert extends InsertBase {} + + @Nested + class KeywordQuoting extends KeywordQuotingBase {} + + @Nested + class LikeEscape extends LikeEscapeBase {} + + @Nested + class Merge extends MergeBase {} + + @Nested + class Select extends SelectBase {} + + @Nested + class Subqueries extends SubqueriesBase {} + + @Nested + class Types extends TypesBase {} + + @Nested + class Union extends UnionBase {} + + @Nested + class Update extends UpdateBase {} + + @BeforeAll + public static void setUp() throws Exception { + Connections.initTurso(); + Connections.initConfiguration(TursoTemplates.builder().newLineToSingleSpace().build()); + Connections.getConfiguration().setUseLiterals(true); + } +} diff --git a/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/suites/TursoSuiteTest.java b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/suites/TursoSuiteTest.java new file mode 100644 index 0000000000..b8e0395c7a --- /dev/null +++ b/querydsl-libraries/querydsl-sql/src/test/java/com/querydsl/sql/suites/TursoSuiteTest.java @@ -0,0 +1,61 @@ +package com.querydsl.sql.suites; + +import com.querydsl.sql.BeanPopulationBase; +import com.querydsl.sql.Connections; +import com.querydsl.sql.DeleteBase; +import com.querydsl.sql.InsertBase; +import com.querydsl.sql.KeywordQuotingBase; +import com.querydsl.sql.LikeEscapeBase; +import com.querydsl.sql.MergeBase; +import com.querydsl.sql.SelectBase; +import com.querydsl.sql.SubqueriesBase; +import com.querydsl.sql.TursoTemplates; +import com.querydsl.sql.TypesBase; +import com.querydsl.sql.UnionBase; +import com.querydsl.sql.UpdateBase; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Tag; + +@Tag("com.querydsl.core.testutil.Turso") +public class TursoSuiteTest extends AbstractSuite { + + @Nested + class BeanPopulation extends BeanPopulationBase {} + + @Nested + class Delete extends DeleteBase {} + + @Nested + class Insert extends InsertBase {} + + @Nested + class KeywordQuoting extends KeywordQuotingBase {} + + @Nested + class LikeEscape extends LikeEscapeBase {} + + @Nested + class Merge extends MergeBase {} + + @Nested + class Select extends SelectBase {} + + @Nested + class Subqueries extends SubqueriesBase {} + + @Nested + class Types extends TypesBase {} + + @Nested + class Union extends UnionBase {} + + @Nested + class Update extends UpdateBase {} + + @BeforeAll + public static void setUp() throws Exception { + Connections.initTurso(); + Connections.initConfiguration(TursoTemplates.builder().newLineToSingleSpace().build()); + } +} diff --git a/querydsl-tooling/querydsl-sql-codegen/pom.xml b/querydsl-tooling/querydsl-sql-codegen/pom.xml index 2492d0074e..1921790949 100644 --- a/querydsl-tooling/querydsl-sql-codegen/pom.xml +++ b/querydsl-tooling/querydsl-sql-codegen/pom.xml @@ -142,6 +142,13 @@ test + + 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(); + } +}