Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #11493 (closed enhancement: fixed)

Opened 1 month ago

Last modified 1 month ago

Support for interleaved migrations

Reported by: jordi Assigned to: technoweenie
Priority: normal Milestone: 2.x
Component: ActiveRecord Version: edge
Severity: normal Keywords:
Cc: nzkoz, jbarnette

Description

This patch builds on the work of jbarnette (see [9122])

UTC timestamps are great as migration version numbers when developing with Git or Mercurial, but after a merge you're still left with the responsibility of figuring out which new migrations you're missing, and then running them manually.

This patch ensures that rake db:migrate automatically picks up the new ones for you. It also makes migrating down smarter, in the sense that it knows not to try and revert a migration it never applied.

It works by replacing the schema_info table with a schema_migrations table, that contains one row for each migration applied. The suggested approach is backwards-compatible with sites with a schema_info table, and existing migration files. Also, it does not change the format of schema.rb.

This approach works both in the case of DHH's preferred practice of running rake db:schema:load (if you do that, it doesn't migrate all over again), and in the case of folks that insist in migrating all the way every time.

It passes all existing tests for SQLite3 and MySQL. If there's interest from core, I can test further, including new tests and other databases.

Attachments

interleaved_migrations.diff (16.1 kB) - added by jordi on 04/01/08 07:50:09.
Support for new migrations in the middle of the sequence
interleaved_migrations_with_repeatable_loads.diff (16.1 kB) - added by ddollar on 04/01/08 16:45:10.
Interleaved Migrations patch but with a fix to repeatable schema loading
interleaved_migrations_with_repeatable_loads_and_test.diff (20.5 kB) - added by jordi on 04/01/08 17:56:42.
Interleaved migrations patch with ddollar's repeatable schema loading fix, and a unit test
interleaved_migrations_with_tests_and_docs.diff (21.5 kB) - added by jordi on 04/08/08 04:40:48.
Interleaved migrations patch with bugfixes, tests and docs
interleaved_migrations_with_tests_and_docs.2.diff (21.5 kB) - added by jordi on 04/08/08 04:51:17.
Interleaved migrations patch bugfixes, tests and docs

Change History

04/01/08 07:45:41 changed by jordi

Argh. Due to a last minute change from a decimal to string column to store version info, this is now broken. Working on a fix.

04/01/08 07:50:09 changed by jordi

  • attachment interleaved_migrations.diff added.

Support for new migrations in the middle of the sequence

04/01/08 07:52:36 changed by jordi

I've replaced the broken diff with the fixed one.

04/01/08 07:55:46 changed by jordi

  • milestone changed from 2.1 to 2.x.

Just realized that the 2.1 milestone is reserved for core members.

04/01/08 15:20:33 changed by ddollar

I'd love to see this make its way into Rails, this has been a significant pain point for us due to our extensive branching.

04/01/08 16:40:43 changed by ddollar

+1 from me, looks good

Uploading a new diff to fix a minor issue with repeatable schema loads, very small change

04/01/08 16:45:10 changed by ddollar

  • attachment interleaved_migrations_with_repeatable_loads.diff added.

Interleaved Migrations patch but with a fix to repeatable schema loading

04/01/08 17:56:42 changed by jordi

  • attachment interleaved_migrations_with_repeatable_loads_and_test.diff added.

Interleaved migrations patch with ddollar's repeatable schema loading fix, and a unit test

04/01/08 17:58:25 changed by jordi

interleaved_migrations_with_repeatable_loads_and_test.diff contains a unit test that runs migration 3, then 1, checking that nothing raises and that 1 applies.

Finally, we try to revert 2, which never ran, and make sure that it does not revert.

04/02/08 12:01:31 changed by nwiger

+1

love the idea and the patch is nice and clean.

04/03/08 16:40:54 changed by ryanb

+1, I would love to see this functionality included.

04/03/08 17:32:03 changed by jordi

  • keywords set to verified.

04/03/08 19:56:51 changed by stouset

+1. Tested the patch and it works as advertised. Normal migrations work as expected, and new migrations interleaved into old ones are applied on a migrate.

(follow-up: ↓ 12 ) 04/05/08 11:20:26 changed by nzkoz

  • keywords deleted.

There are several places in this patch where you do:

 @version = @connection.select_values( 
 	34	          "SELECT version FROM schema_migrations").map(&:to_i).max rescue nil 

That should really just be

select MAX(version) FROM schema_migrations

Also we should probably document the two kinds of tables and how we've moved between them somewhat.

(in reply to: ↑ 11 ) 04/05/08 14:25:06 changed by jordi

  • cc set to nzkoz.

Replying to nzkoz:

There are several places in this patch where you do: {{{ @version = @connection.select_values( 34 "SELECT version FROM schema_migrations").map(&:to_i).max rescue nil }}} That should really just be {{{ select MAX(version) FROM schema_migrations }}}

Sadly, SELECT MAX() here gives me back the numbers in ASCIIabetic order, which is not quite what you want, I think. It would put a migration version of '30' above a timestamp on 2008.

I thought about making version either an int8 column, or a decimal with no precision, but I figured things would get too different from database to database, so I decided instead to just do what jbarnette did to schema_info in [9122] and make it a string column, which sadly needs the .map(&:to_i).max bit.

Also we should probably document the two kinds of tables and how we've moved between them somewhat.

Glad to do it. Where would such documentation go? As comments in the code, or somewhere in the API?

(follow-ups: ↓ 15 ↓ 16 ) 04/05/08 16:18:27 changed by nzkoz

Hmm, I didn't see the fact that it was a stringnow? Out of interest, why is that? The nice thing about those timestamps is that they sort numerically as well as alphabetically, so I can't see why we need to change it?

As for the documentation, stick it alongside the rest of the docs in migration.rb as a new heading.

04/05/08 16:22:28 changed by nzkoz

  • cc changed from nzkoz to nzkoz, jbarnette.

Can you shed any light on the string column for us jbarnette?

(in reply to: ↑ 13 ; follow-up: ↓ 17 ) 04/05/08 16:23:41 changed by jordi

Replying to nzkoz:

Hmm, I didn't see the fact that it was a stringnow? Out of interest, why is that? The nice thing about those timestamps is that they sort numerically as well as alphabetically, so I can't see why we need to change it?

DHH wanted the whole system to be backwards compatible with existing migration files. So migration 3 would happen after today's timestamp, which is no good.

As for the documentation, stick it alongside the rest of the docs in migration.rb as a new heading.

Got it. Will post patch later today.

(in reply to: ↑ 13 ) 04/05/08 16:25:08 changed by jordi

Replying to nzkoz:

Hmm, I didn't see the fact that it was a stringnow? Out of interest, why is that?

I presume also we didn't want to assume that all databases have int8. But maybe jbarnette can elaborate. I mostly just went with the flow.

(in reply to: ↑ 15 ) 04/05/08 17:51:27 changed by jbarnette

Replying to nzkoz:

It's an integer-size-across-databases thing: 20081231060606 is big. :) I preferred the simplicity of storing the same notation used for filename prefixes. I suppose we could store epoch seconds in the DB instead.

04/07/08 05:45:51 changed by jordi

The way I see it:

Epoch seconds in the DB is are tricky, because some you'd want to fetch verbatim (like 1, 2, 3, 4), but some you'd want to convert to timestamps. We'd need logic to determine that. It's not hard by any means, just cumbersome (we would need to basically define the jbarnette's epoch, *grin*). Saving the migration files themselves with seconds from epoch as opposed to UTC timestamps would avoid that logic, but if I recall correctly DHH didn't want them to be named after seconds from the epoch.

The other alternative is to add the creation of that table to the adapters, so that they can all create their version of what an int8 column is. Again, too much work for little gain in my opinion.

Let me zoom back out for a second, and ask this: what are we trying to avoid by not making that column a varchar? Ruby iterating over a few thousand values at worst? Considering that it would happen during a task that was never snappy to begin with (rake db:migrate), I don't think it's worth the effort or code size.

That said, I have personal interest in this patch making it in (we branch a lot!), so if either int8, seconds from the epoch or something else is a better solution in the eyes of the core team, I'd be happy to code away.

04/07/08 05:48:25 changed by jordi

Oh, and those documentation comments are coming. Busy weekend.

04/07/08 06:11:04 changed by jbarnette

The varchar is the best way to go, IMHO. No need for conversions or heuristics on the 'legacy' migration numbers.

04/07/08 14:38:28 changed by nzkoz

Yeah, looks fine to me, though the repeated '.map(&:to_i).max' stuff should be encapsulated somehow rather than repeated in a few places.

Once that's done and the docs are ready, looks good to me.

04/08/08 04:40:48 changed by jordi

  • attachment interleaved_migrations_with_tests_and_docs.diff added.

Interleaved migrations patch with bugfixes, tests and docs

04/08/08 04:44:10 changed by jordi

Behold: documented the destiny of schema_info, and encapsulated the scary .map(&:to_i).max.

04/08/08 04:51:17 changed by jordi

  • attachment interleaved_migrations_with_tests_and_docs.2.diff added.

Interleaved migrations patch bugfixes, tests and docs

04/08/08 12:13:05 changed by jordi

Just realized that there're two of the latest patch "interleaved_migrations_with_tests_and_docs". They're both the same according to md5sum. I posted twice by accident, I guess.

04/08/08 17:57:03 changed by technoweenie

  • owner changed from core to technoweenie.
  • status changed from new to assigned.

I was just bitching about timestamp migrations, which earned me a PDI on this plugin :) I'll check it out later tonight and see about getting this into 2.1. I'll be in #rails-contrib when i'm working on it.

04/09/08 16:20:20 changed by rick

  • status changed from assigned to closed.
  • resolution set to fixed.

(In [9244]) Add support for interleaving migrations by storing which migrations have run in the new schema_migrations table. Closes #11493 [jordi]