A smart rule to move tags into groups on moving into database

I am trying to create a smart rule that moves new tags into specific groups (converting them into group tags) based on the tag prefix. For example, if ‘rk’ is the prefix - i.e., rk.tag1, rk.tag2, I want to move them into RK.Group etc. for different prefixes. I have written a smart rule script that looks at each tag of an item, checks whether it exists as a group tag already, and if not, files it into the appropriate group.

I want the script to trigger when I move the item into its database from the global inbox. The smart rule works well when I run it on demand on an item in a specific database – the ordinary tags are converted into group tags in the right locations. However, when I trigger the smart rule to be ‘on moving into database’ and move an item into the database, it moves the tag into the group tag location, but the item is not there. It creates an empty group tag. The item still remains, but with the original ordinary tags.

I am not sure if I have described it well, so I am including the smart rule and code below and am happy to clarify further.

As a specific example of the problem, if tag an item with ‘rk.tag1’ and move it into the database, the item appears in the database with ordinary tag ‘rk.tag1’ and an empty group tag ‘rk.tag1’ is created in RK.Group. When I run the smart rule on demand on the same item, the ordinary tag ‘rk.tag1’ is converted/moved into a group tag ‘rk.tag1’ in RK.Group and the ordinary tag is gone. The item now appears under /RK.Group/rk.tag1.

Here is the smart rule:

and here is the script:

property pGlobalSearch : false -- Set to true to search in all opened databases. Otherwise the current database of the records will be used.

property defaultTopLocation : "/TagsToSort"
property topTagLocation : "/Tags/"

property maxPrefixCharacters : 2

--NOTE Toplocations must already exist
property FileLocations : {¬
	{prefix:"rk", Toplocation:"/Research/RK.Group"}, ¬
	{prefix:"rm", Toplocation:"/Research/RM.Group"}, ¬
	{prefix:"rj", Toplocation:"/Research/RJ.Group"}}


on PerformSmartRule(theRecords)
	tell application id "DNtp"
		try
			set oldDelimiters to AppleScript's text item delimiters
			set AppleScript's text item delimiters to "."
			repeat with thisRecord in theRecords
				set theTags to tags of thisRecord -- remove for SR
				if (count of theTags) is 0 then return -- if no tags then return - remove for SR
				repeat with thisTag in theTags
					set thisPrefix to item 1 of (text items of thisTag)
					if (count of characters of thisPrefix) is less than or equal to maxPrefixCharacters then
						set theQuery to "name==" & thisTag & space & "kind:grouptag"
						if (pGlobalSearch) then
							set theResults to search theQuery
						else
							set theResults to search theQuery in root of database of thisRecord
						end if
						
						set didMove to true
						set numResults to count of theResults
						if numResults is 0 then
							set destinationTopLocation to my retrieveTopLocation(thisPrefix)
							set tagRec to get record at topTagLocation & thisTag
							set destRec to get record at destinationTopLocation in database of thisRecord
							move record tagRec to destRec
						else if numResults is greater than 1 then
							log message info "Ambiguous destination." record thisRecord
							set didMove to false
						end if
					end if
					
				end repeat
			end repeat
		on error error_message number error_number
			if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
			set AppleScript's text item delimiters to oldDelimiters
		end try
	end tell
end PerformSmartRule

on retrieveTopLocation(prefixToTest)
	repeat with rec in my FileLocations
		if prefixToTest is prefix of rec then
			return Toplocation of rec
		end if
	end repeat
	return defaultTopLocation
end retrieveTopLocation

Any advice?

?
Do you mean “nested tags”?

No, tags which are also a group. Basically moving the tag from the /Tags/ group where it behaves like an ordinary tag into a group so it can behave as a group tag. I’m not sure the right terminology, but it behaves differently if it is a group tag. Basically, I just want to move the tag into the group I designate.

I can possibly describe the issue better: When I move an item into a database, I want to check the tags and see if they exist in a specific target location; if not, I want to move them to that location. The target location depends on the first two letters of the tag and the database that it is being moved into.

Is this feasible? I thought I had solved it, but I am running into the issues described in my first post.

I am still running into issues when I try to move the location of tag in a smart rule that triggers on moving an item into a database. The tag successfully moves to the new location, but it is empty (i.e., no longer attached to the original item). Is there another way to do this? I am not sure if it is a bug or my implementation.

I am using an applescript because I want to move the tag to different groups depending on its first two characters. I don’t want to make separate smart rules for each possibility.

A screenshot of the smart rule would be useful.

A screenshot of the smart rule is in the original post.

I have worked on this some more and I am still stumped. The script in my first post works fine when an item is already in the target database. However, it does not work as a smart rule that activates on moving into the database. I can’t figure out what is different, but it seems to be something about what database it thinks it is in when the applescript is executed.

To summarize:
As a standalone script when the item is already in the target database: the tag (for example, “rk.tag”) is moved to its target location (“RK.Group”) and removed from /Tags/rk.tag. The item is in the new location under /RK.Group/rk.tag/.
As a smart rule that activates on moving into the database: a new tag is created at the target location /RK.Group/rk.tag but the original tag remains under /Tags/rk.tag. The item is under /Tags/rk.tag and is not moved to /RK.Group/rk.tag

I tried moving the item to the new location explicitly in the script, but was getting errors. I have not been able to debug because I have not yet figured out how to debug a smart rule script (I cannot add breakpoints etc. as I can with the standalone script and the standalone script is working fine).

If a script is executed in a smart rule that is activated on Moving into the database, is the current database the original database or the database it is being moved into? If the former, is there a way to refer to the database it has been moved into within a script?

Moving a tag to another database moves all records with the tag. That’s not what you want.

It’s after moving, so it’s the destination database.

Although it’s not possible to use Script Debugger’s debugging tools with it you could try Script: Comfortably developing a Smart Rule Script.

I took a look at your script. One problem is that you didn’t set in which database things should happen. See these lines:

set tagRec to get record at topTagLocation & thisTag
set destRec to get record at destinationTopLocation in database of thisRecord

In the first line the in database of part is missing. And get record at defaults to the current database which means some “weird” things will happen … and some minutes later everything will work again … and then it fails … and so on :slight_smile:

As mentioned your approach of moving the tag won’t work. I guess you tried with only one record, right? I think what you want is create location, this creates a location if it doesn’t exist, if it exists it does nothing. So instead of moving the actual tag you could use the tag’s name to create the location, leaving the tag untouched.

No idea what to do with the actual tags, though. Maybe the easiest way is to remove them from the record (set tags of thisRecord to {}) and then use a Smart Group or Rule to delete empty tags.

property defaultTopLocation : "/TagsToSort"
property topTagLocation : "/Tags/"
property maxPrefixCharacters : 2
property FileLocations : {¬
	{prefix:"rk", Toplocation:"/Research/RK.Group"}, ¬
	{prefix:"rm", Toplocation:"/Research/RM.Group"}, ¬
	{prefix:"rj", Toplocation:"/Research/RJ.Group"}}

on performSmartRule(theRecords)
	tell application id "DNtp"
		try
			set oldDelimiters to AppleScript's text item delimiters
			set AppleScript's text item delimiters to "."
			
			repeat with thisRecord in theRecords
				set theTags to tags of thisRecord
				repeat with thisTag in theTags
					set thisPrefix to item 1 of (text items of thisTag)
					if (count of characters of thisPrefix) ≤ maxPrefixCharacters then
						set thisGroupTag_Location to my retrieveTopLocation(thisPrefix) & "/" & thisTag
						set thisGroupTag to create location thisGroupTag_Location in database of thisRecord
						replicate record thisRecord to thisGroupTag		
					end if
				end repeat
			end repeat
			
			set AppleScript's text item delimiters to oldDelimiters
		on error error_message number error_number
			set AppleScript's text item delimiters to oldDelimiters
			if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
		end try
	end tell
end performSmartRule

on retrieveTopLocation(prefixToTest)
	repeat with rec in my FileLocations
		if prefixToTest is prefix of rec then
			return Toplocation of rec
		end if
	end repeat
	return defaultTopLocation
end retrieveTopLocation
1 Like

Thank you so much for your reply. This edit worked and the script is now working well. I really appreciate it!

1 Like