Bug in AppleScript command "get record at"?

Hi all…

How to open the root folder of a Database via “get record at” ?

I think:

get record at "/" in database "Eingang"

should reference it, but it returns missing value.

I also tried:

get record at "" in database "Eingang"

which also returns missing value.

I worked around it using

if grp is "/" then
	root of database db
else
	get record at grp in database db
end if
set root of viewer window 1 to result

which in my case needs an ugly if construct.

Is there a better way?

Best regards
Jens

Welcome @jerl

There is no record there.

tell application id "DNtp"
	get record at "/" in database "TEST-01"
	--> missing value
	get location of (root of database "TEST-01")
	--> "/"
end tell

Ok, then it is expected behavior. Makes sense, the “Root”-reference isn’t really a record.
So my workaround should be perfectly fine in this case.

Thanks.

You’re welcome.

So my workaround should be perfectly fine in this case.

Your case is undefined, so I can’t offer any other suggestions.

Maybe I should explain some more context.

Because of my bad eyesight, I can’t use the build-in “Move to…” or “Open…” dialogs. The interface is simply to small. So I tried to recreate them using Keyboard Maestros “Prompt with List” action. It has a bigger, more Spotlight/Alfred like interface:

For this reason, I use two AppleScripts (per macro). The first one compiles a list of paths into a multiline string. To support multiple Databases, the Database name becomes the first Path element, followed by the groups and sub groups. To simplify things, I use posix format:

database/group/subgroup/

Here comes the script:

tell application id "DNtp"
	set grpList to {}
	repeat with db in databases
		set end of grpList to (name of db) & "/" & return
		repeat with par in every parent of db
			set thePath to name of db & location of par & name of par & return
			if thePath does not contain "/Papierkorb" and thePath does not contain "/Tags" then
				set end of grpList to thePath
			end if
		end repeat
	end repeat
	grpList as text
end tell

The “grpList” result will be feed into Keyboard Maestros “Prompt with List” dialog, which will return the user selected line to a KM variable “selectedGroupPath”:

The following scipt decomposes the string to its 2 components (database and location) and will finally open the selected group in DEVONthink:

property grp : ""

tell application "Keyboard Maestro Engine"
	set grp to getvariable "selectedGroupPath"
end tell

tell application id "DNtp"
	activate
	set pos to offset of "/" in grp
	set db to characters 1 thru (pos - 1) of grp as string
	set grp to characters pos thru end of grp as string
	if grp is "/" then
		root of database db
	else
		get record at grp in database db
	end if
	set root of viewer window 1 to result
end tell

I felt “get record at grp in database db” should easily get the job done. But because “/” isn’t returning a reference to “root”, I had to workaround this case by returning “root” explicitly in the IF construct above. Not a great deal, but not pretty either.

Thanks.
Jens

1 Like

If I understand you correctly, you first compose a list of strings from which to chose. After you have chosen, you partially decompose the selection again to get the database and the path (location) to the group in it.

I don’t know KM well enough, but if it’s possible to attach data to the strings in the list, this might ease the process a bit. That is, if something like the name/value pair in HTML’s selection element exits in KM, you could use the string to show the user what to select (name) and the value to store the database and group (if it exists), perhaps in an AS record. Or maybe that would be over-engineered.

Thanks for pointing out.

This is exactly what one will usually do in “normal” languages. Unfortunately, KM doesn’t support “payloads” when using the Spotlight-like interface (there is some way to have one string for display, and another one as an return code, but in any case only a single string will be returned). For this reason I had to “encode” the database in some form into the string.

Another way I tried was to keep two separate lists (couldn’t figure out how user defined lists of records work in AppleScript). One list of Strings for display in KM, and second one with the actual Record objects from DEVONthink. This way I was able to dereference the right group simply by index. But that code reads awkward, too (but it also has upsides: it will correctly work if you have two groups with exactly the same pathname).

This was the first version using recursion and two lists:

use scripting additions

property listOfGroups : {}
property listOfGroupPaths : {}
property tempPath : {}

tell application "DEVONthink 3"
	
	repeat with db in databases
		my getGroups(root of db)
	end repeat
	
	set tid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to ASCII character 10
	set output to listOfGroupPaths as text
	set AppleScript's text item delimiters to tid
	
end tell

tell application "Keyboard Maestro Engine"
	setvariable "listOfGroupPaths" to output
	do script "BC5FEB81-210F-488D-AD05-3B0BCEB58640"
	set selectedGroupPath to getvariable "selectedGroupPath"
end tell

tell application "DEVONthink 3"
	
	set pos to my list_position(selectedGroupPath, listOfGroupPaths)
	
	set test to location of item pos of listOfGroups & name of item pos of listOfGroups
	return test
	
end tell

on list_position(this_item, this_list)
	repeat with i from 1 to the count of this_list
		if item i of this_list is this_item then return i
	end repeat
	return 0
end list_position

on getGroups(aGroup)
	
	tell application "DEVONthink 3"
		
		if name of aGroup is "Tags" then return
		if name of aGroup is "Papierkorb" then return
		
		set end of tempPath to name of aGroup
		
		set tid to AppleScript's text item delimiters
		set AppleScript's text item delimiters to " ➤ "
		set end of listOfGroupPaths to tempPath as text
		set AppleScript's text item delimiters to tid
		
		set end of listOfGroups to aGroup
		set subGroups to every child of aGroup whose type is group
		
		repeat with theGroup in subGroups
			my getGroups(theGroup)
		end repeat
		
		set tempPath to reverse of (rest of (reverse of tempPath))
		
	end tell
	
end getGroups

Two thoughts:

  • Maybe Alfred is easier for this use case
  • AppleScript is, imho, not the best language for advanced data structures. In JavaScript, you’d simply have an array of objects.