diff --git a/src/main/java/typewriter/maria/MariaDB.java b/src/main/java/typewriter/maria/MariaDB.java index 904297f3..76f8a1d8 100644 --- a/src/main/java/typewriter/maria/MariaDB.java +++ b/src/main/java/typewriter/maria/MariaDB.java @@ -100,11 +100,11 @@ public void createDatabase(String url) { * {@inheritDoc} */ @Override - public void commandLimitAndOffset(SQL builder, long limit, long offset) { - if (0 < limit) builder.write("LIMIT").write(limit); + public void commandLimitAndOffset(SQL sql, long limit, long offset) { + sql.limit(limit); if (0 < offset) { - if (limit <= 0) builder.write("LIMIT 18446744073709551615"); - builder.write(" OFFSET ").write(offset); + if (limit <= 0) sql.limit(Long.MAX_VALUE); + sql.offset(offset); } } diff --git a/src/main/java/typewriter/query/Query.java b/src/main/java/typewriter/query/Query.java new file mode 100644 index 00000000..2fa7ce59 --- /dev/null +++ b/src/main/java/typewriter/query/Query.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2023 Nameless Production Committee + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://opensource.org/licenses/mit-license.php + */ +package typewriter.query; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import typewriter.api.Identifiable; +import typewriter.api.Specifier; + +public abstract class Query { + + private final List select = new ArrayList(); + + /** + * Declare SELECT statement. + * + * @param names + */ + protected final void SELECT(Specifier... names) { + SELECT(Stream.of(names).map(Specifier::propertyName).toList()); + } + + /** + * Declare SELECT statement. + * + * @param names + */ + protected final void SELECT(String... names) { + SELECT(List.of(names)); + } + + /** + * Declare SELECT statement. + * + * @param names + */ + protected final void SELECT(List names) { + select.addAll(names); + } + + /** + * Test query. + * + * @param query + * @return + */ + public boolean is(String query) { + return query.equals(toString()); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + + // SELECT + builder.append("SELECT ").append(select.stream().collect(Collectors.joining(", "))); + + return builder.toString(); + } +} diff --git a/src/main/java/typewriter/rdb/Dialect.java b/src/main/java/typewriter/rdb/Dialect.java index 79644381..b1c9dddc 100644 --- a/src/main/java/typewriter/rdb/Dialect.java +++ b/src/main/java/typewriter/rdb/Dialect.java @@ -149,8 +149,7 @@ public String commandUpdate() { * @param offset */ public void commandLimitAndOffset(SQL sql, long limit, long offset) { - if (0 < limit) sql.write("LIMIT").write(limit); - if (0 < offset) sql.write("OFFSET").write(offset); + sql.limit(limit).offset(offset); } /** diff --git a/src/main/java/typewriter/rdb/RDB.java b/src/main/java/typewriter/rdb/RDB.java index 3ca23d22..fb3cb18b 100644 --- a/src/main/java/typewriter/rdb/RDB.java +++ b/src/main/java/typewriter/rdb/RDB.java @@ -142,7 +142,7 @@ protected RDBQuery createQueryable() { */ @Override public long count() { - return new SQL<>(this).write("SELECT count(*) N").from(tableName).qurey().map(result -> result.getLong("N")).to().exact(); + return new SQL<>(this).select("count(*)").from(tableName).qurey().map(result -> result.getLong(1)).to().exact(); } /** diff --git a/src/main/java/typewriter/rdb/SQL.java b/src/main/java/typewriter/rdb/SQL.java index 9cbdbe5f..3806dc99 100644 --- a/src/main/java/typewriter/rdb/SQL.java +++ b/src/main/java/typewriter/rdb/SQL.java @@ -300,6 +300,26 @@ public SQL orderBy(Specifier specifier1, boolean ascending1, Specifier< return this; } + /** + * Write SELECT statement. + * + * @return + */ + public SQL distinct(String... specifiers) { + text.append(" SELECT DISTINCT ").append(Stream.of(specifiers).collect(Collectors.joining(", "))); + return this; + } + + /** + * Write SELECT statement. + * + * @return + */ + public SQL select(String... specifiers) { + text.append(" SELECT ").append(Stream.of(specifiers).collect(Collectors.joining(", "))); + return this; + } + /** * Write SELECT statement. * @@ -321,6 +341,16 @@ public SQL avg(Specifier specifier, int windowSize) { return this; } + public SQL limit(long size) { + if (0 < size) text.append(" LIMIT ").append(size); + return this; + } + + public SQL offset(long size) { + if (0 < size) text.append(" OFFSET ").append(size); + return this; + } + /** * Write WHERE statement. * diff --git a/src/test/java/typewriter/query/QueryTest.java b/src/test/java/typewriter/query/QueryTest.java new file mode 100644 index 00000000..4e493030 --- /dev/null +++ b/src/test/java/typewriter/query/QueryTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2023 Nameless Production Committee + * + * Licensed under the MIT License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://opensource.org/licenses/mit-license.php + */ +package typewriter.query; + +import org.junit.jupiter.api.Test; + +import typewriter.api.model.IdentifiableModel; + +public class QueryTest { + + @Test + void selectName() { + Query query = new Query() { + { + SELECT("test"); + } + }; + + assert query.is("SELECT test"); + } + + @Test + void selectNames() { + Query query = new Query() { + { + SELECT("first", "second"); + } + }; + + assert query.is("SELECT first, second"); + } + + @Test + void selectSpecifier() { + Query query = new Query() { + { + SELECT(Person::getName); + } + }; + + assert query.is("SELECT name"); + } + + @Test + void selectSpecifiers() { + Query query = new Query() { + { + SELECT("first", "second"); + } + }; + + assert query.is("SELECT first, second"); + } + + /** + * + */ + static class Person extends IdentifiableModel { + + public String name; + + public int age; + + /** + * Create empty model. + */ + public Person() { + } + + /** + * @param name + * @param age + */ + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + /** + * Get the name property of this {@link Person}. + * + * @return The name property. + */ + public String getName() { + return name; + } + + /** + * Get the age property of this {@link Person}. + * + * @return The age property. + */ + public int getAge() { + return age; + } + } +}