Isn't that where the test coverage has a hole?
I somehow expected the blog post to extend testing for this. A pre-populated database which is then migrated. That seems to catch a wider class of issues than parsing sql and shielding against just checking for non-null without default.
Just to clarify a bit, the test ofc isn't a fully general solution to solving issues with database migrations (I hinted what that might be in the blog post), although it's still useful to provide a nice error message even if a more general solution was implemented.
That was not at all the goal of the post. I just wanted to appreciate how easy it was to achieve this specific task in Rust. In any other systems programming language that I used (even most other languages, except maybe for Python), I would never even imagine something like this being feasible, and so easy to do. That's it :)
https://github.com/sbdchd/squawk
"linter for PostgreSQL, focused on migrations"
It covers this class of problem I think
(great = simple, short, easy to write, read, maintain. at very least no more complex than the thing it testing!)
I currently prevent this sort of thing using a populated database. This database has actual real data (user info overwritten with random data).
Using a pre-populated database catches many more errors than this article's approach does.
Using a pre-populated database that has actual data generated by the users over a year or so catches even more errors.
This approach is fragile and misses the actual error, fixing only the symptom. The actual error is "there's a hole in my tests big enough to fly a passenger jet through".
The correct approach is to take a dump of the production database, scrub PII from it, and then perform your migration.
There's a range of errors you just won't catch until you run your code against the real thing. Especially if you write SQL directly, which feels like a lost art even amongst experienced developers.
Doing that is simple and can potentially catch all sorts of bugs, including the bugs you didn't think of yet. His solution is complicated but only catches one very specific type of bug.
> Apart from parsing the SQL query, I also considered an alternative testing approach that I might implement in the future: go through each migration one by one, and insert some dummy data into the database before applying it, to make sure that we test each migration being applied on a non-empty database. The data would either have to be generated automatically based on the current database schema, or we could commit some example DB dataset together with each migration, to make sure that we have some representative data sample available.
Ideally both approaches would be used, with the general case being used to detect and inform more targeted tests.
The problem to solve is "given my database in an arbitrary but valid state, applying a migration should succeed and leave the database in a equally valid state". Not "how do I stop people adding NOT NULL columns into tables".
I'd characterize it less as the cool solution and more as the quick & dirty solution that gets you a lot of value for little effort.
Perform some arbitrary list of valid actions. (This alone is valuable)
Run the new migrations.
Perform some arbitrary list of valid actions.
Assert no crashes/errors.
I've found this great for testing APIs - just "perform some list of user actions and make sure things don't explode" can catch a lot.
I've found it to be a pretty useful way of establishing patterns for data modelling in a team.
And that's great. Note that I specifically said that "for me personally", I found that article less valuable. But I'm certainly not claiming that everyone else should feel the same.
As a matter of fact, I'm sure a lot of people find my comment to be of little value.
The author isn’t just recounting their story, they’re selling it as a lesson in a generic approach that will make you a better engineer.
Whether they can deliver on that promise doesn’t matter. It’s the feeling that’s clickable.
Are we going to criticise every little innocent blog post just because somebody liked it, submitted it to HN and it got enough upvotes?
"Oh I found some niche issue that bothered me and wrote some code to fix it."
-> HN Front Page
No mocking or anything. This tests that your migrations are safe to run against real data.
Neon Branches are zero-copy snapshots of the database, with all the same data, on an isolated postgres instance. You can run migrations on that data without risking any modifications to data or performance in production. You can set up scripts to run it in CI[1].
This isn't perfect. If performance matters, some migrations might hide table locks which can cause major slowdowns. I'm not sure how you might detect this currently, I had some discussions recently about whether we can add "explain analyze" to DDL queries in postgres.
[0]: https://neon.tech/docs/introduction/branching [1]: https://neon.tech/docs/guides/branching-github-actions
Do you mean that the migration might work on a side branch, but then it might not work on the main branch, because there's no other activity running on the side branch?
Postgre sql parser, mysql sql parser, …
(Solid advise though)
If you look at https://github.com/rust-lang/bors it's not a standard library package, it's a tool to support the Rust development process. And the person who opened and landed that PR is the lead developer of that project.
Skipping a code review from someone else feels OK to me for that.
The rust-lang/rust repository has higher scrutiny (in part driven by tools like bors, the subject of the article).
In this day and age of increasingly rampant supply chain attacks & dependency vulnerabilities, I'd definitely be second guessing the approach of "just write a test for it" if that test involved blowing up your attack/vuln surface
How common is this kind of code in practice ?
I'm sure there are plenty of other use cases for lifetimes, but they don't come up very often when writing standard "application" code.