Cascade delete, is this supported with a hook on th-deleting-tiddler?

On a couple of threads I have discussed creating a JavaScript method to detect the deletion of a tiddler, upon which the JavaScript invokes actions to update all title and list fields this newly deleted tiddler is referencing. This works well. Thanks to @saqimtiaz

However, what if the next step in the hook logic was to delete this tiddler being referenced? As an experiment, I invoked a delete action request–which also worked.

What did not work is that this request to delete another tiddler did NOT invoke the hook. ie. I was expecting either a recursive call to my method to process the newly deleted tiddler or I was expecting it to be queued, waiting for the current instance to finish before processing the next deleted tiddler. Instead, nothing occurred; the hook was not called.

Hence the question: with a hook to th-deleting-tiddler, where the hook deletes another tiddler, should it also be called? Hope this makes sense?

Thanks,

Craig

My advice is to keep the hook as minimal as possible and keep the remaining logic in wikitext.

Edit: no it’s not called recursively so that needs to be handled by your code, see https://tiddlywiki.com/dev/#Hook%3A%20th-deleting-tiddler

The hook is only invoked by the navigator widget in response to the tm-delete-tiddler widget message

1 Like

Aside: I got it to work by managing the recusive calls. The hook calls a method which, if it deletes a tiddler, calls the method again recusively (but only if it successfully did in fact delete the tiddler), enabling for a true cascading delete behaviour.

1 Like

This is fantastic! Are you working in a generic manner, where you somewhere define the foreign key relationships and update based on those? Or are you working specifically with your particular tag/tiddler structure? I was planning on doing the latter for myself, but if you’re doing the former, I’d really love to see what you’ve come up with, with an eye towards stealing borrowing it.

Yes.It is generic. Users write very simple TW filters to define cascade deletes. If the filter passes, it gets deleted; otherwise it does not. I’ll post what I have in the coming days. I’m doing a bit of clean up. I’ll post details on how to use it here.

2 Likes

The purpose of this feature is to provide cascade delete of tiddlers, the automatic deletion of tiddlers when a tiddler is deleted. The initial deletion of a tiddler is typically initiated by the user. This code was prompted from a DB model discussion initiated by @Bob_Jansen and further discussed with @Scott_Sauyet

There are four tiddlers in the json supplied (below). The primary tiddler is a startup js tiddler to provide the hook on tiddler deletions and logic to perform cascade deletions. The others are action tiddlers used by the cascade delete method.

NOTE: Caution is to be used here. There has been very limited tests performed with code. You are testing the deletion and modification of potentially many tiddlers when a delete occurs. IF NOT PROPERLY CONFIGURED, THIS COULD REMOVE MORE THAN EXPECTED. Test on test data.

I am continuing to test and exercise this… not ready for release of any kind… except peer review.

Note: This code requires the Relink plugin, as it uses its configuration to determine what fields are configured as list and title fields. Therefore, code would need to be changed if you are not using Relink.

Note: I have only tested this in my own application, The Memory Keeper (MK) (genealogy research tool)

I’ll attempt to describe this with an example I have in the Memory Keeper.

In a database implementation, for this example, I would have four tables. In TW I have 4 tiddler types that are tagged similar to how I might name tables in a DB. These are:

  • person
  • event
  • role
  • event-role

In this example I have 4 tiddlers, one for each tiddler type above (tag used for each in brackets):

Smith, John (person)
1889-09-07 - burial - May Benson (event)
pallbearer (role)
Pallbearers at Mary Benson’s burial (event-role)

The event-role acts like an intersection table in a relational database. This tiddler has 3 list fields: people, event, and role. In this example, all 3 list fields are populated with values that represent that John Smith was a pallbearer at Mary’s burial. Keep in mind there could be more pallbearers.

What happens when I delete tiddler “Smith, John” from the system?

The first thing it will do is remove the entry “Smith, John” from any field it is found in (based on Relink configuration). In this example it would be found in field “people” in tiddler “Pallbearers at Mary Benson’s burial”. It therefore would remove that entry from the field.

It would then test for the deletion of this tiddler, ie. attempt to perform a cascade delete on this tiddler. It should not be automatic. Rather, like a relational database, it needs to be configurable and based on a set of rules. The rules I define for a given entity may not align with those of other users. Therefore, this needs to be configurable. If the rules are met, the tiddler is deleted; otherwise, it is not, and the process continues to remove “Smith, John” from other fields in other tiddlers (and cascade delete rules are validated on those entities).

Here is the rule I have defined for the event-role entity: If any list field is empty (people, event, role) then an event-role is not valid and is to be deleted.

You write rules in the form of a TW filter. All of these filters are applied, and if any one of them returns a value, the tiddler is deleted. If no rules are found, then cascade deletes cannot be performed.

Here are the filter rules for event-role (as per my rule):

[<currentTiddler>tag[event-role]!has[people]]
[<currentTiddler>tag[event-role]!has[event]]
[<currentTiddler>tag[event-role]!has[role]]

Filter rules are defined in the text field of tiddlers tagged: $:/config/mk/cascade/delete/filter

Rename this tag in the code to meet your needs. Actually, that is a bad tag name… I will be changing this.

Therefore, continuing with my example, if “Smith, John” was the only person in the “people” list field, then the event-role tiddler would be deleted; otherwise, no, it would remain.

NOTE: This code will need to be changed to meet your needs. I left this as I implemented it in the Memory Keeper. There are 3 functions it provided:

logresults - used to log results to a temporary tiddler for the user to review. You’ll want to change the log tiddler or remove this function. If you remove the function, replace the calls to it with a console.log commands.

createSpaces - used when writing to the log (or console) to indent spaces to make the log more readable.

processDeletion - this is the main function to perform cascade delete. There are three lines you’ll want to change or remove. Search for “conftiddlers”. These lines are controlling how I want to configure this feature in MK. I have a single setting which has 3 states:

  1. disabled (this feature is not to used)
  2. update (this feature is only to update list and title fields, and is not to perform cascade deletes)
  3. delete (this feature is to perform updates to list and title fields, and cascade deletes)

If you remove these lines, it means it will always perform a full cascade delete. Be sure to also remove the closing brace of those IF statements you remove. Otherwise, implement something similar.

Thoughts? Be critical.

$__plugins_cls_mk_delete-startup.js.json (5.9 KB)

1 Like

I very much look forward to looking at this, but it will likely be a few days.

1 Like

Interesting stuff. Appreciate the the time and effort put into not just making the thing, but documenting it too. I think i understood most of that! :wink:

1 Like