Hi, Kentin,
Thank you for those strategies. In the past, I have used both event sourcing and versioning. The versioning was for a system where it was critical for legal reasons to track and store every change, when it was made, who made it, and for what reason. Those are both way more heavy weight than I need here. I was planning on a pretty basic solution of writing a change log to another table whenever my client updated anything in the database. Basically just flatten the row and write out strings/numbers/arrays/objects to a new table. Or probably I’ll just write one big JSON blob and be done with it. The most likely scenario is that she’ll do something…make a mistake…and then email me saying “help help! I messed something up!” and I’ll go into the change history and restore what she wants. If she does this habitually, I’ll make her a UI so she can skip the “help help!” email and restore the change without my intervention. This is a small operation. I don’t need to restore changes for thousands of users on a big enterprise system. It’s one store owner who is a friend of mine. I don’t anticipate this will happen often, but I want to plan for it because I know it eventually will happen.
You’re right, I could do this in an after insert/update hook, but…as you mentioned…multirefs…don’t even get me started on multirefs. Too late…you got me started…Why…oh why…are they so crucial, yet so utterly dysfunctional all at the same time? Without them, there is NO other way of modeling m:n relationships. Yes, I have multirefs. I use them to enforce specific values in columns (basically, enums. ie, if I have a column for “color”, I have a reference table with Red, Yellow, etc. I don’t want someone typing in “Yabba Dabba Doo!” for color).
Oh…you got me started on multirefs, and it is actually is pertinent to the solution I’m implementing for the change log.
First. I don’t allow anyone to make changes through the content manager other than me. And even I don’t really use it. My client is not a site admin. Instead, I have created web UIs that allow her to update the database.
Second. I had to “solve” (polite for “hack”) a solution for the invisible multiref update problem for another purpose, so I will re-use the same strategy here. Since I only allow updates through a single UI, I can actually be my own “after” hook. After the save, I just run whatever I want. Since I control the code that is run in the event handlers, I can run whatever I want, even if only a multiref has changed. Right now, whenever she hits the save button, I save the object, and then call my own reindex function that writes the whole record out to a separate table that is in a better format for searching and displaying search results. While I’m doing that, I’ll also write it out to a third table that is the change log. I’ll delete old rows in the change log with a cron job. I don’t need to keep anything older than a couple of months.
Why am I doing this? It requires some back story. I have a main table that has a pile of multirefs. I want to be able to search/filter the main table on various columns/attributes. Filtering on multirefs is actually very easy. But then I need to display the results in a repeater, and this is quite literally impossible if some of those columns are multirefs. To get around this, I have a separate Search Index table that contains all the searchable fields from the main table, and all of its reference and multiref fields (the IDs) flattened out in arrays. The problem I had was how to update that table? I could not use hooks, because updating multirefs is…as you mentioned…invisible. Even if you update another column AND a multiref, afterUpdate runs before the multiref is updated, so if you have code in the afterUpdate that writes out the multiref, you’re writing out the old value. Oh…don’t get me going…too late…
I call the indexer after a save, and not by using a hook. Basically, my click handler is my hook. I also have a cron job set up as a sweeper, just in case I miss an update, or I update something using the content manager.
I have a “wish list” request to add 2 changes that would fix multirefs and make them useful. 1. Give me a hook that triggers on an insert/replace/remove reference. 2. Return the IDs in the multiref column as an array when you query the main table similar to how single ref IDs are already returned. Just the IDs…not the entire referenced row. All I need to make life happy are the IDs in an array.
The addition of these two things would allow me to actually use the only mechanism Wix provides to model m:n relationships.
OK. I think I over-answered this…
Cheers