Support plain SQL migrations#440
Open
alassek wants to merge 1 commit into
Open
Conversation
This introduces ROM::SQL::Migration::SQLMigration, which allows you to write migrations as a .sql file in the migration directory. SQL migrations have a very simple grammar: 1. Files are organized into two directions (up and down). Each direction may contain one or more `begin..end` sections; all sections for a direction execute sequentially in source order at apply time. Each section keeps its own `split=` setting, so a single direction may mix splitting strategies across sections. 2. Directives are written as SQL line comments using the `-- @migrate` sigil. The leading `--` keeps directive lines valid SQL syntax (so editors, syntax highlighters, and linters treat them as comments); the `@migrate` sigil disambiguates them from author-written `--` comments. Plain `-- ...` comments without the `@migrate` sigil are treated as part of the SQL body and pass through verbatim. 3. Optional settings may be provided in a pragma line before the up/down sections 4. Pragma and begin lines accept `key=value` settings separated by spaces or tabs 5. Each direction begins with a direction directive followed by one or more begin directives 6. The begin directive may itself carry settings (e.g. statement splitting strategy) 7. Each section concludes with an end directive 8. Down migrations are optional, but they always must follow the up migration 9. Empty sections (begin..end with no SQL body) are silently skipped
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This introduces
ROM::SQL::Migration::SQLMigration, which allows you to write migrations as a.sqlfile in the migration directory. This takes inspiration from my experience using pressly/goose.SQL migrations have a very simple grammar:
begin..endsections; all sections for a direction execute sequentially in source order at apply time. Each section keeps its ownsplit=setting, so a single direction may mix splitting strategies across sections.-- @migratesigil. The leading--keeps directive lines valid SQL syntax (so editors, syntax highlighters, and linters treat them as comments); the@migratesigil disambiguates them from author-written--comments. Plain-- ...comments without the@migratesigil are treated as part of the SQL body and pass through verbatim.key=valuesettings separated by spaces or tabsRationale
For very simple cases, using a Ruby DSL is fine and makes your migrations user-friendly. But a major problem with migration DSLs is that they don't look very much like the SQL they intend to replace. This means when you start to do complex things in your DB, it gets increasingly difficult to figure out how to write it. Eventually you are bound to encounter situations where it makes sense to just shove a whole SQL string into
execute.This extension aims to solve this problem by giving users an escape hatch into plain SQL that can sit alongside their Ruby migrations.
Statement Splitting
Providing multiple ways to manage how your statements get split up is necessary, because different database engines have difference precise rules about it. There are three options demonstrated here: the whole body in one statement, split by line, and split by semicolon. You can also provide multiple statement sections per migration direction if you wish.
Pragma:
transactionSet whether or not to use a DDL transaction via a top-level pragma:
Pragma:
envYou can opt into environment-substitution by passing the
env=truepragma. This replaces instances of${NAME}withENV["NAME"]in your migration statements before execution.Comments for reviewers
Data, but the gemspec is outdated. We should probably bump the requirement to 3.3hanami-clifollowon rather than live here.rom-corerequiresdry-structso I felt it was acceptable to use it here, but do we want to elevate the transitive dependency to a direct one?AI Disclosure
The first pass at the tokenizer / compiler was crafted by hand, but I used Claude extensively here to track down edge cases. Everything I did not write has been carefully reviewed.