Skip to content

Commit cffe8df

Browse files
committed
feat(builder): add ColumnType for type-safe column definitions in CreateBuilder
- Add ColumnType final class with 25 fixed-type constants (TINYINT through UUID), 7 parameterised factory methods (varChar, charType, decimal, numeric, binary, varBinary, timestamp), and 4 chainable modifier methods (notNull, unique, autoIncrement, defaultValue) - Add CreateBuilder.column(String, ColumnType) overload; delegates to the existing column(String, String) via ColumnType.toSql() — fully backward compatible - Add ColumnTypeTest: 32 tests covering constants, factories, modifiers, chaining, and CreateBuilder integration
1 parent 341d8f3 commit cffe8df

3 files changed

Lines changed: 538 additions & 5 deletions

File tree

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
package com.github.ezframework.javaquerybuilder.query.builder;
2+
3+
/**
4+
* Type-safe column type definitions for use with
5+
* {@link CreateBuilder#column(String, ColumnType)}.
6+
*
7+
* <p>Use the pre-defined constants for fixed-width types, the static factory
8+
* methods for parameterised types, and the modifier methods to append
9+
* column-level constraints:</p>
10+
*
11+
* <pre>{@code
12+
* QueryBuilder.createTable("users")
13+
* .column("id", ColumnType.INT.notNull().autoIncrement())
14+
* .column("username", ColumnType.varChar(64).notNull().unique())
15+
* .column("balance", ColumnType.decimal(10, 2))
16+
* .column("created_at", ColumnType.TIMESTAMP)
17+
* .primaryKey("id")
18+
* .build();
19+
* // → CREATE TABLE users (
20+
* // id INT NOT NULL AUTO_INCREMENT,
21+
* // username VARCHAR(64) NOT NULL UNIQUE,
22+
* // balance DECIMAL(10, 2),
23+
* // created_at TIMESTAMP,
24+
* // PRIMARY KEY (id))
25+
* }</pre>
26+
*
27+
* <p>Raw SQL type strings are still accepted by
28+
* {@link CreateBuilder#column(String, String)} for any type not covered here.</p>
29+
*
30+
* @author EzFramework
31+
* @version 1.1.0
32+
*/
33+
public final class ColumnType {
34+
35+
// ── Exact-width integer types ──────────────────────────────────────────
36+
37+
/** 1-byte signed integer ({@code TINYINT}). Supported by MySQL, MariaDB. */
38+
public static final ColumnType TINYINT = new ColumnType("TINYINT");
39+
40+
/** 2-byte signed integer ({@code SMALLINT}). */
41+
public static final ColumnType SMALLINT = new ColumnType("SMALLINT");
42+
43+
/** 4-byte signed integer ({@code INT}). */
44+
public static final ColumnType INT = new ColumnType("INT");
45+
46+
/** 4-byte signed integer ({@code INTEGER}). Alias for {@link #INT} in most databases. */
47+
public static final ColumnType INTEGER = new ColumnType("INTEGER");
48+
49+
/** 8-byte signed integer ({@code BIGINT}). */
50+
public static final ColumnType BIGINT = new ColumnType("BIGINT");
51+
52+
// ── Floating-point types ───────────────────────────────────────────────
53+
54+
/** Single-precision floating point ({@code FLOAT}). */
55+
public static final ColumnType FLOAT = new ColumnType("FLOAT");
56+
57+
/** Double-precision floating point ({@code DOUBLE}). */
58+
public static final ColumnType DOUBLE = new ColumnType("DOUBLE");
59+
60+
/** Double-precision floating point ({@code REAL}). Standard SQL alias for {@link #DOUBLE}. */
61+
public static final ColumnType REAL = new ColumnType("REAL");
62+
63+
// ── Boolean ───────────────────────────────────────────────────────────
64+
65+
/** Boolean value ({@code BOOLEAN}). */
66+
public static final ColumnType BOOLEAN = new ColumnType("BOOLEAN");
67+
68+
// ── Fixed-size text types ──────────────────────────────────────────────
69+
70+
/**
71+
* Unbounded text ({@code TEXT}).
72+
* For length-limited strings use {@link #varChar(int)}.
73+
*/
74+
public static final ColumnType TEXT = new ColumnType("TEXT");
75+
76+
/** Small text up to 255 characters ({@code TINYTEXT}). MySQL / MariaDB only. */
77+
public static final ColumnType TINYTEXT = new ColumnType("TINYTEXT");
78+
79+
/** Medium text up to 16 MB ({@code MEDIUMTEXT}). MySQL / MariaDB only. */
80+
public static final ColumnType MEDIUMTEXT = new ColumnType("MEDIUMTEXT");
81+
82+
/** Large text up to 4 GB ({@code LONGTEXT}). MySQL / MariaDB only. */
83+
public static final ColumnType LONGTEXT = new ColumnType("LONGTEXT");
84+
85+
/** Character large object ({@code CLOB}). Standard SQL; map to TEXT on MySQL. */
86+
public static final ColumnType CLOB = new ColumnType("CLOB");
87+
88+
// ── Binary types ───────────────────────────────────────────────────────
89+
90+
/** Binary large object ({@code BLOB}). */
91+
public static final ColumnType BLOB = new ColumnType("BLOB");
92+
93+
/** Small binary up to 255 bytes ({@code TINYBLOB}). MySQL / MariaDB only. */
94+
public static final ColumnType TINYBLOB = new ColumnType("TINYBLOB");
95+
96+
/** Medium binary up to 16 MB ({@code MEDIUMBLOB}). MySQL / MariaDB only. */
97+
public static final ColumnType MEDIUMBLOB = new ColumnType("MEDIUMBLOB");
98+
99+
/** Large binary up to 4 GB ({@code LONGBLOB}). MySQL / MariaDB only. */
100+
public static final ColumnType LONGBLOB = new ColumnType("LONGBLOB");
101+
102+
// ── Date and time types ────────────────────────────────────────────────
103+
104+
/** Calendar date without time-of-day ({@code DATE}). */
105+
public static final ColumnType DATE = new ColumnType("DATE");
106+
107+
/** Time-of-day without date ({@code TIME}). */
108+
public static final ColumnType TIME = new ColumnType("TIME");
109+
110+
/** Date and time without timezone ({@code DATETIME}). MySQL / MariaDB / SQLite. */
111+
public static final ColumnType DATETIME = new ColumnType("DATETIME");
112+
113+
/** Date and time, often auto-updated ({@code TIMESTAMP}). */
114+
public static final ColumnType TIMESTAMP = new ColumnType("TIMESTAMP");
115+
116+
// ── Miscellaneous types ────────────────────────────────────────────────
117+
118+
/** JSON document ({@code JSON}). MySQL 5.7+, PostgreSQL 9.2+, SQLite 3.38+. */
119+
public static final ColumnType JSON = new ColumnType("JSON");
120+
121+
/**
122+
* Auto-incrementing 4-byte integer ({@code SERIAL}).
123+
* PostgreSQL only; equivalent to {@code INT NOT NULL AUTO_INCREMENT} on MySQL.
124+
*/
125+
public static final ColumnType SERIAL = new ColumnType("SERIAL");
126+
127+
/**
128+
* Auto-incrementing 8-byte integer ({@code BIGSERIAL}).
129+
* PostgreSQL only; equivalent to {@code BIGINT NOT NULL AUTO_INCREMENT} on MySQL.
130+
*/
131+
public static final ColumnType BIGSERIAL = new ColumnType("BIGSERIAL");
132+
133+
/**
134+
* Universally unique identifier ({@code UUID}).
135+
* Native on PostgreSQL; stored as {@code CHAR(36)} or {@code BINARY(16)} on others.
136+
*/
137+
public static final ColumnType UUID = new ColumnType("UUID");
138+
139+
// ── Internal state ─────────────────────────────────────────────────────
140+
141+
/** The SQL fragment representing this column type definition. */
142+
private final String sql;
143+
144+
/**
145+
* Creates a {@code ColumnType} from an arbitrary SQL type fragment.
146+
*
147+
* <p>Use this constructor for database-specific types not covered by the
148+
* pre-defined constants, e.g. {@code new ColumnType("GEOMETRY")}.</p>
149+
*
150+
* @param sql the SQL type string; must not be {@code null} or blank
151+
*/
152+
public ColumnType(final String sql) {
153+
this.sql = sql;
154+
}
155+
156+
// ── Parameterised factory methods ──────────────────────────────────────
157+
158+
/**
159+
* Variable-length character string: {@code VARCHAR(length)}.
160+
*
161+
* @param length maximum number of characters; must be positive
162+
* @return a new {@code ColumnType} representing {@code VARCHAR(length)}
163+
*/
164+
public static ColumnType varChar(final int length) {
165+
return new ColumnType("VARCHAR(" + length + ")");
166+
}
167+
168+
/**
169+
* Fixed-length character string: {@code CHAR(length)}.
170+
*
171+
* @param length number of characters; must be positive
172+
* @return a new {@code ColumnType} representing {@code CHAR(length)}
173+
*/
174+
public static ColumnType charType(final int length) {
175+
return new ColumnType("CHAR(" + length + ")");
176+
}
177+
178+
/**
179+
* Exact decimal number: {@code DECIMAL(precision, scale)}.
180+
*
181+
* @param precision total number of significant digits; must be positive
182+
* @param scale number of digits after the decimal point; must be &ge; 0
183+
* @return a new {@code ColumnType} representing {@code DECIMAL(precision, scale)}
184+
*/
185+
public static ColumnType decimal(final int precision, final int scale) {
186+
return new ColumnType("DECIMAL(" + precision + ", " + scale + ")");
187+
}
188+
189+
/**
190+
* Exact numeric value: {@code NUMERIC(precision, scale)}.
191+
* Equivalent to {@link #decimal(int, int)} in most databases.
192+
*
193+
* @param precision total number of significant digits; must be positive
194+
* @param scale number of digits after the decimal point; must be &ge; 0
195+
* @return a new {@code ColumnType} representing {@code NUMERIC(precision, scale)}
196+
*/
197+
public static ColumnType numeric(final int precision, final int scale) {
198+
return new ColumnType("NUMERIC(" + precision + ", " + scale + ")");
199+
}
200+
201+
/**
202+
* Fixed-length binary string: {@code BINARY(length)}.
203+
*
204+
* @param length number of bytes; must be positive
205+
* @return a new {@code ColumnType} representing {@code BINARY(length)}
206+
*/
207+
public static ColumnType binary(final int length) {
208+
return new ColumnType("BINARY(" + length + ")");
209+
}
210+
211+
/**
212+
* Variable-length binary string: {@code VARBINARY(length)}.
213+
*
214+
* @param length maximum number of bytes; must be positive
215+
* @return a new {@code ColumnType} representing {@code VARBINARY(length)}
216+
*/
217+
public static ColumnType varBinary(final int length) {
218+
return new ColumnType("VARBINARY(" + length + ")");
219+
}
220+
221+
/**
222+
* Timestamp with fractional seconds precision: {@code TIMESTAMP(precision)}.
223+
* Useful for {@code TIMESTAMP(6)} (microseconds) on MySQL and PostgreSQL.
224+
*
225+
* @param precision fractional seconds digits (0–6); must be between 0 and 6 inclusive
226+
* @return a new {@code ColumnType} representing {@code TIMESTAMP(precision)}
227+
*/
228+
public static ColumnType timestamp(final int precision) {
229+
return new ColumnType("TIMESTAMP(" + precision + ")");
230+
}
231+
232+
// ── Column-level constraint modifiers ──────────────────────────────────
233+
234+
/**
235+
* Appends {@code NOT NULL} to this column type.
236+
*
237+
* @return a new {@code ColumnType} with {@code NOT NULL} appended
238+
*/
239+
public ColumnType notNull() {
240+
return new ColumnType(sql + " NOT NULL");
241+
}
242+
243+
/**
244+
* Appends {@code UNIQUE} to this column type.
245+
*
246+
* @return a new {@code ColumnType} with {@code UNIQUE} appended
247+
*/
248+
public ColumnType unique() {
249+
return new ColumnType(sql + " UNIQUE");
250+
}
251+
252+
/**
253+
* Appends {@code AUTO_INCREMENT} to this column type (MySQL / MariaDB).
254+
* Use {@link #SERIAL} or {@link #BIGSERIAL} for PostgreSQL auto-increment columns.
255+
*
256+
* @return a new {@code ColumnType} with {@code AUTO_INCREMENT} appended
257+
*/
258+
public ColumnType autoIncrement() {
259+
return new ColumnType(sql + " AUTO_INCREMENT");
260+
}
261+
262+
/**
263+
* Appends {@code DEFAULT value} to this column type.
264+
*
265+
* <p>The {@code value} string is inserted verbatim into the SQL column definition.
266+
* Use only static, known-safe values here (e.g. {@code "0"}, {@code "false"},
267+
* {@code "CURRENT_TIMESTAMP"}). Never pass user-supplied input.</p>
268+
*
269+
* @param value the default SQL expression or literal to append; must not be {@code null}
270+
* @return a new {@code ColumnType} with {@code DEFAULT value} appended
271+
*/
272+
public ColumnType defaultValue(final String value) {
273+
return new ColumnType(sql + " DEFAULT " + value);
274+
}
275+
276+
// ── Accessors ──────────────────────────────────────────────────────────
277+
278+
/**
279+
* Returns the SQL fragment for this column type, including any modifiers.
280+
*
281+
* @return the SQL column type string (e.g. {@code "VARCHAR(64) NOT NULL"})
282+
*/
283+
public String toSql() {
284+
return sql;
285+
}
286+
287+
/**
288+
* Returns the SQL fragment for this column type.
289+
* Equivalent to {@link #toSql()}.
290+
*
291+
* @return the SQL column type string
292+
*/
293+
@Override
294+
public String toString() {
295+
return sql;
296+
}
297+
}

‎src/main/java/com/github/ezframework/javaquerybuilder/query/builder/CreateBuilder.java‎

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,37 @@ public CreateBuilder table(String table) {
3939
}
4040

4141
/**
42-
* Adds a column definition.
43-
* @param name the column name
44-
* @param sqlType the SQL type (e.g. "VARCHAR(255)", "INT")
45-
* @return this builder
42+
* Adds a column definition using a raw SQL type string.
43+
*
44+
* @param name the column name
45+
* @param sqlType the SQL type string (e.g. {@code "VARCHAR(255)"}, {@code "INT NOT NULL"})
46+
* @return this builder instance for chaining
4647
*/
47-
public CreateBuilder column(String name, String sqlType) {
48+
public CreateBuilder column(final String name, final String sqlType) {
4849
columns.put(name, sqlType);
4950
return this;
5051
}
5152

53+
/**
54+
* Adds a column definition using a type-safe {@link ColumnType}.
55+
*
56+
* <p>Example:</p>
57+
* <pre>{@code
58+
* QueryBuilder.createTable("users")
59+
* .column("id", ColumnType.INT.notNull().autoIncrement())
60+
* .column("username", ColumnType.varChar(64).notNull())
61+
* .primaryKey("id")
62+
* .build();
63+
* }</pre>
64+
*
65+
* @param name the column name
66+
* @param columnType the column type; must not be {@code null}
67+
* @return this builder instance for chaining
68+
*/
69+
public CreateBuilder column(final String name, final ColumnType columnType) {
70+
return column(name, columnType.toSql());
71+
}
72+
5273
/**
5374
* Adds a primary key column.
5475
* @param name the column name

0 commit comments

Comments
 (0)