graphile / migrate

Opinionated SQL-powered productive roll-forward migration tool for PostgreSQL.
MIT License
751 stars 58 forks source link

issue-163: added ability to include external files in current.sql. #195

Closed jnbarlow closed 10 months ago

jnbarlow commented 11 months ago

Description

fixes #163 This PR adds the ability to include external files into current.sql, allowing for better integration with source control. Functions, computed columns, etc can live in separate diffable files for pull requests, but still take advantage of all the goodness of graphile-migrate and the current.sql.

Performance impact

If someone decides to include a ton of files in a current.sql, the I/O to read these in will make things not super pleasant.

Security impact

unknown... shouldn't be any more risky than using current.sql

Checklist

jnbarlow commented 11 months ago

@benjie Greetings! If I understood the flow of how sql gets compiled, I think I shimmed my new compile step in so that it should work for everything. Let me know if I missed something :)

benjie commented 11 months ago

Amazing! I’ve not reviewed the code yet, but we need it to integrate with watch mode: https://github.com/graphile/migrate/blob/main/src/commands/watch.ts#L217

easiest would be to require that these files all live within one folder (migrations/includes or migrations/library or whatever) and watch that folder, however another option is to dynamically add files to chokidar when they are imported and remove them when they are no longer so. Chokidar has APIs for this.

jnbarlow commented 11 months ago

@benjie So you're thinking of having a base folder that all the includes live (with Chokidar watching it) so that any time one of them changes it reprocesses the current.sql?

Is the path something we should make configurable with a default or hard code it as part of the framework? What about placeholders? Right now the includes are brought in after the placeholder replacement. We could swap that, but I'm not sure of the use cases would warrant that. To me, it feels like the includes probably shouldn't have placeholders, but you've got more experience with how people use them.

benjie commented 11 months ago

Hardcoded is fine to start with; if someone really wants it configurable they can send a PR. Still not sure of the name; perhaps migrations/lib…

Yes, I’m thinking any change to that folder (or descendents) triggers current to run again; we already checksum the result so if it wasn’t relevant we’ll skip it.

It’s very common for roles to be placeholders, particularly on shared hosting (where you grant to a different role on dev versus staging versus production), and in fact that’s what we do in starter via :VISITOR or :VISITOR_ROLE or whatever (I forget the specifics). So it’s essential that the included files are also processed via the placeholder system. I think there’s a handy method you can call on the strings to apply the placeholders, you don’t have to concatenate first if you don’t want to.

jnbarlow commented 11 months ago

@benjie Ahh ok, thanks for pointing me to where this should go. I was trying to figure out the flow of things and shim it into a spot where it would always be called. Run seemed to be the logical spot that called the placeholder replacement to do that. Let me work on the updates then

benjie commented 11 months ago

Yeah calling it in readCurrentMigration means you don't even have to think about placeholders because they're handled for you later. (Placeholders can change at runtime, that's deliberate.)

jnbarlow commented 10 months ago

@benjie alright, I think I've address everything and pushed.

Give this a look whenever you get a chance. The only thing I've not done yet is actually run the code (been relying on tests to check everything). I'm not super sure how to go about compiling it down to something I can execute.

benjie commented 10 months ago

Awesome; will take a look when I'm back from the winter break.

I'm not super sure how to go about compiling it down to something I can execute.

You should be able to run yarn prepack which will build everything. Then you can run yarn link to create a global version of it, and in a clean folder somewhere (or in your project that uses migrate) you can do yarn link graphile-worker to install the version. I'm not 100% sure this will work, it sometimes gets confused due to modules coming from multiple places, but migrate is simple enough that I think it will.

Alternatively you can run yarn pack which will create a tgz containing the module, and then you can install that tgz into a project somewhere via yarn add file:/path/to/local/tarball.tgz or equivalent in whatever package manager you use.

jnbarlow commented 10 months ago

@benjie another round pushed up

I was able to get it to run locally too, but ran into a problem where yarn add kept importing old versions. I manually extracted the built file and it worked.

benjie commented 10 months ago

@jnbarlow I think this is good to merge now; would you care to give it a test and make sure it still works well (in particular, ensure that watch mode functions correctly)?

jnbarlow commented 10 months ago

@benjie Sure!. I'll give that a test tonight and let you know

jnbarlow commented 10 months ago

@benjie everything works :) ... Ignore my last message if you saw it, I was doing something boneheaded when I tested it :)