Skip to content

Conversation

@rwillians
Copy link

@rwillians rwillians commented Nov 28, 2025

This PR introduces the :modifiers field to Ecto.Migration.Table struct, which can be provided as an option to Ecto.Migration.table/2.

Modifiers¹ are known keywords that can be inserted between the tokens "CREATE" and "TABLE", for example the "UNLOGGED" keyword in PostgreSQL (see Create Table - PostgreSQL).

create table(:sessions, modifiers: "UNLOGGED") do
  # ...
end

The statement above now produces the following DDL:

CREATE UNLOGGED TABLE sessions ...

Also, the DDL logs have been updated to include the modifiers when creating a table (seemed like a nice touch):

$ mix ecto.migrate

17:11:49.826 [info] == Running 20251128173650 MyApp.Repo.Migrations.CreateWebhooksTable.change/0 forward

17:11:49.828 [info] create unlogged table webhooks

17:11:49.838 [info] == Migrated 20251128173650 in 0.0s

¹ It was discussed here the use of the nomenclature parameters for this, but parameters aren't limited to show up between "CREATE" and "TABLE". For example, they can appear at the end of create table the statement. That's why I'm using the term modifiers.

These modifiers are keywords that can be inserted between the tokens "CREATE" and "TABLE".
See https://www.postgresql.org/docs/current/sql-createtable.html.

For example, in postgres we can use :modifiers to create unlogged tables:

    create table(:sessions, modifiers: UNLOGGED)

The statement above now produces the following DDL:

    CREATE UNLOGGED TABLE sessions ...
@rwillians rwillians changed the title Create unlogged table Support for creating unlogged tables (simplified) Nov 28, 2025
Copy link
Member

@greg-rychlewski greg-rychlewski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR. It looks good. Besides the comment I left we should also add this to MySQL and SQL Server or raise if they don't support it.

Comment on lines +1766 to +1767
defp modifiers_expr(<<_, _::binary>> = value), do: [String.upcase(String.trim(value)), ?\s]
defp modifiers_expr(value), do: error!(nil, "PostgreSQL adapter expects :modifiers to be a non-empty string or nil, got #{inspect(value)}")
Copy link
Member

@greg-rychlewski greg-rychlewski Nov 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
defp modifiers_expr(<<_, _::binary>> = value), do: [String.upcase(String.trim(value)), ?\s]
defp modifiers_expr(value), do: error!(nil, "PostgreSQL adapter expects :modifiers to be a non-empty string or nil, got #{inspect(value)}")
defp modifiers_expr(modifiers) when is_binary(modifiers), do: [modifiers, ?\s]
defp modifiers_expr(other), do: error!(nil, "PostgreSQL adapter expects :modifiers to be a string, got #{inspect(other)}")

This is for consistency with similar things like options. The existing pattern is not to normalize and not to care if they send an empty string. Raising seems a bit harsh for empty string as well since it's still valid SQL and they might populate this from a configuration value that is empty in some environments.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, thanks for explaining

@rwillians
Copy link
Author

Thanks for the review @greg-rychlewski, I'll most likely have an update on it in the next weekend

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants