feat: #312 Add support for table modifiers and storage parameters#2756
feat: #312 Add support for table modifiers and storage parameters#2756obabichevjb merged 10 commits intomainfrom
Conversation
Add tests to demonstrate the need for tableOption() extension function that allows specifying MySQL/MariaDB table options like ENGINE=MEMORY. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add two new open properties to the Table class:
- modifiers: List<String> - for table modifiers like ENGINE=InnoDB (MySQL/MariaDB)
- storageParameters: List<String> - for WITH clause parameters (PostgreSQL, SQL Server)
These properties allow users to specify database-specific table options:
- MySQL/MariaDB: ENGINE, DEFAULT CHARSET, etc.
- PostgreSQL: fillfactor, autovacuum_enabled, etc.
- SQL Server: various table options
Example usage:
```kotlin
object Users : Table("users") {
val id = integer("id")
override val primaryKey = PrimaryKey(id)
override val modifiers = listOf("ENGINE=InnoDB", "DEFAULT CHARSET=utf8mb4")
override val storageParameters = listOf("fillfactor=70")
}
```
This generates:
```sql
CREATE TABLE users (id INT NOT NULL, PRIMARY KEY (id))
ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 WITH (fillfactor=70)
```
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add comprehensive documentation to Working-with-Tables.topic explaining: - Table modifiers for MySQL/MariaDB (ENGINE, CHARSET, etc.) - Storage parameters for PostgreSQL (fillfactor, autovacuum, etc.) - Common use cases and examples - Notes about database-specific behavior Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
55176e8 to
730cc3a
Compare
|
This feature was made using the new claude skill. The skill works better, it stopped after creating a test and making proposal. It suggested one API, which actually could not be compiled.. and I suggested him the API which is in the PR. I also added the section about website documentation to the skill, so it verifies if the changes should be reflected in the documentation. |
…meters Add comprehensive integration tests that actually create tables in the database: - testTableWithMemoryEngineCreatedSuccessfully: Creates MEMORY engine table, inserts data, and verifies engine type via information_schema - testTableWithCharsetModifierCreatedSuccessfully: Creates utf8mb4 table, inserts Unicode/emoji data, and verifies charset configuration - testTableWithStorageParametersCreatedSuccessfully: Creates PostgreSQL table with fillfactor parameter and verifies via pg_class These tests complement the DDL generation tests by ensuring the modifiers actually work in real database operations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
e5l
left a comment
There was a problem hiding this comment.
Could you add a test to execute a query (both for JDBC and R2DBC)? It looks like an impossible combination of modifiers is possible
| */ | ||
| open val storageParameters: List<String> = emptyList() |
There was a problem hiding this comment.
I don't see a problem with having a database-specific syntactic sugar, I just don't think it should be biased towards one, if it's potentially more general. I get that for PostgreSQL they may all be storage-related properties, but are 100% of the SQL Server WITH properties really the same?
Maybe it would be more unopinionated to call it something everybody would understand like literally:
withOptionswithParameters
There was a problem hiding this comment.
One of the questions I'm thinking of is, why are we adding this when we already have the new property above? Is it because it will get special coverage in migration methods after? Or it was specifically requested?
Why not open val partitionOption (PARTITION BY / ON) too, which seems to be more common across databases?
Is it just for ease? Because there's nothing stopping a user from relying entirely on modifiers for basically every possible SQL syntax under the sun now (which I think personally is a great thing):
override val modifiers = listOf(
"PARTITION BY HASH (order_id)",
"WITH (fillfactor=70)",
"TABLESPACE dbspace"
)I guess my question is:
Would it be more simple to give a single API to append whatever they want to the end of a table definition?
Otherwise, what is the value between 1 and the other, other than not needing to type WITH?
Is it now potentially confusing that they need to remember that:
modifierscomes after(column value,...)block- And
storageParameterscomes after that, at the absolute end - But if they want anything after
WITH ..., they need to go back and only usemodifiers(not sure about this last one, whether the order is important; i.e. is there any clause that must go after WITH?)
There was a problem hiding this comment.
It's a good question, I made it as 2 different parameters (options and storage parameters) mostly because they have quite different meaning from database perspective.
Technically it's possible to have options as a one string only and put there all the parameters which are needed.
After the review changes I made it also better types (with separate classes for known options and parameters), so now it's possible to avoid using of row strings (and making errors inside them) and use class instances.
Minor, but if I'm right all the storage parameters should be inside one with, so it will not be possible to write something like options = listOf("WITH(fillfactor=75)", "WITH(log_autovacuum_min_duration=10)"), but I'm not sure
btw I updated api with better typing for parameters and we can discuss it again, probably we will find a better option.
I had an idea to make something like:
override val modifiers = onModifiers { //withModifiers/buildModifiers
tableSpace(DB_SPACE),
engine(INNO_DB)
}but it was looking so non-Exposed way...
0d3d778 to
eebbde0
Compare
|
I'm still not sure about the final API, I can's say I like that we add classes for particular options/parameters to the global scope, it will be possible to call them from anywhere, what will add noise. Probably we should define it inside At the current moment all the options/parameters have no information about database it should be used with. Another options is to defined them like: class PostgresOptions {
class Engine {}
...
}I didn't do that because wanted to avoid mentioning of particular databases on the table definition level, because in this case it will be potentially necessary to create different definitions for different databases. But since the options are quite db specific it will be necessary to do with the current variant too. |
bog-walk
left a comment
There was a problem hiding this comment.
Just a comment about R2DBC tests
Description
Summary of the change: This PR adds support for database-specific table options through two new properties:
modifiersandstorageParameters.Detailed description:
ENGINE=MEMORY) and other database-specific table options. Issue Allow use of other database engines #312 specifically requested ENGINE support for MySQL/MariaDB, but the implementation is flexible enough to support other database-specific options.openproperties to theTableclass:modifiers: List<String>- for options appended after table definition (e.g.,ENGINE=InnoDB,DEFAULT CHARSET=utf8mb4)storageParameters: List<String>- for options in theWITHclause (e.g.,fillfactor=70for PostgreSQL)createStatement()method inTable.ktto append these options to the generated CREATE TABLE DDL. The pattern follows the existing approach used forprimaryKeyproperty.Example usage:
This generates:
Type of Change
Please mark the relevant options with an "X":
Updates/remove existing public API methods:
Affected databases:
Checklist
Related Issues
Closes #312
🤖 Generated with Claude Code