Micah,
Thanks for your input. I’ve looked over your recommendations and I *mostly* agree with your approach. It might even be something that I can add into our umbrella application only under development so we don’t have to keep a separate repository for the migration generator (if I can get this working with a dynamic Repo, then it won’t even be something that is visible to the deploy flow).
That said, I thought I’d share my recent tests and the changes that I want to propose for ecto_sql to offer that extra telemetry event. Where I’ve placed it seems to be the place where least repetition will be required, but there is some loss of data from the perspective of the migrator API vs wrapping `ecto.migrate`.
Using the capture logic in
https://github.com/halostatue/ecto_migrate_capture, I’ve been able to produce the following output with `mix ecto.migrate.capture && mix ecto.rollback.capture --all` where I have separate migrations for each of Oban's 11 schema migrations.
priv/repo/migrations/migrate/20230515212821/00000000000000_ecto_migrate_preamble.sql
priv/repo/migrations/migrate/20230515212821/20230515193510_oban_version1.sql
…
priv/repo/migrations/migrate/20230515212821/20230515193523_oban_version11.sql
priv/repo/migrations/rollback/20230515212825/00000000000000_ecto_rollback_preamble.sql
priv/repo/migrations/rollback/20230515212825/20230515193510_oban_version1.sql
…
priv/repo/migrations/rollback/20230515212825/20230515193523_oban_version11.sql
The code in EctoMigrateCapture is a bit messy, and I probably could have chosen to record an event stream that got filtered later, but this works reasonably well. The biggest issue is that the Ecto.Migrator API returns pending migrations as `{state, version, string}` such as `{:down, 20230515193510, "oban_version_1"}` and because I’m only emitting the module in the telemetry event (`EctoMigrateCapture.Repo.Migrations.ObanVersion1`), that module is converted back as `oban_version1` instead of `oban_version_1`.
I’ve lifted the formatting code from ecto_dev_logger, but I could have just as well lifted it from code we implemented internally four or five years ago. The `preamble` code are queries that are executed before the first migration is run, generally to find which schema version is the starting point (these are marked with `schema_migration: true`, IIRC). I had to *skip* `schema_migration: true` as a filter because Oban doesn't currently implement it in its delegated migrations (and this was a bit of a "footnote" update to a point release of ecto_sql).
For my needs, I would probably *eliminate* all queries related to the `schema_migrations` table, since it’s completely unused by Sqitch. It would be useful to have those queries tagged *explicitly* in telemetry, but string matching is probably sufficient for my needs (I wouldn’t be overriding the name of the schema migrations name). I probably need to add an index value so that it’s clear in which *order* the migration vs rollback ran. I also probably need to have it generate both in sequence, so this would definitely be a custom task for me.
So, to my feature request questions / suggestions:
1. I think that the new telemetry event should be added, even if it’s somewhat different than what I provided. It would be great if we could get *both* the module name and the "string" version name, but as the module *mostly* converts back to the string nicely, I think that is a nice-to-have, not a must-have. (I implemented this as a span, but I really only *need* the start event; other peoples' needs may benefit from the *stop* event.)
2. I think that EctoSQL should provide a query string formatter with callbacks to EctoSQL adapter modules for dialect differences, as well as an option in the formatter function for a callback to user code. I’d be happy to share what we’ve done at Kinetic (I think we handle a few possible data type cases better for normal SQL inspection, but especially as PostgreSQL types are so extensible…), but what @fuelen has done with fuelen/ecto_dev_logger is also a really good start.
3. Even though I will probably adjust my immediate approach to do what has been suggested by Micah as my needs are very *custom*, I *still* think that being able to write the executed SQL to a file during migration would be a good optional flag to add to `ecto.migrate` and `ecto.roleback`.
4. I think that the query capture via telemetry should be documented somewhere in EctoSQL documentation in the event that someone *else* has a similar need.
-a