While working on a larger project, i was working on testing updates to records - it seems if i have a script that rename a record and then sets its content (or vice versa) it will likely fail if its done in a database that was recently created, but likely succeed if its in an existing one.. seems timing dependent.
The script creates a new text record at the root of a DB, and then attempts to rename it and change the content of it. If the script is run with “new” as an argument, it will create a new DT database, if it’s run with “existing ” it’ll use an existing one. It then tries to read back the updated content.
Running with ./test_DEVONthink.applescript existing <existing db name> causes it to always succeed. Running with ./test_DEVONthink.applescript new causes it to fail most (but not all) times.. switching the order of updating the record name vs changing the content has some effect.
It looks like in the failure cases, the content is updated, but the record’s path attribute still points to the old name.
Maybe i’m just missing something obvious i should be (not) doing? I don’t want to insert arbitrary delays into the script, and it’s not clear that helps in any case.
i’m happy to make it simpler; it doesn’t do much as it is; it’s largely log entries and comments.
because i wanted a simple as possible test case with no other variables that i could trigger via osascript.
i’m writing some Go code that bridges to DEVONthink via objective-c that will ultimately be used in a larger program that will make a lot of searches, lists and updates to the DB. It’s using ScriptingBridge/Apple Events there, and has integration tests to prove that it’s working as intended. The integration tests create a new database to run their tests against, and tear it down at the end. Those were working fine with existing databases, and in near all cases with their ephemeral databases too, except for an operation where a record rename and a content update happen around the same time as part of a larger “update record operation”. I had assumed it was a bug with some level of my code, so this LLM example was an attempt to prove that to be the case with as few touch points as possible. It so far persists, even with AppleScript doing similar operations.
Well, for example there is no log command in DEVONthink. There is a log message.
Try Data > New > Script… and feed it your requirements in a prompt. It has more DEVONthink-specific knowledge and can produce something that can be opened, run, and debugged in Script Editor.
You also haven’t said what kind of documents you’re attempting to modify.
I’m just using text. Per your suggestion, i had Data > Script generate an example for me.. it almost gave me something that worked; some tweaks and the following runs in Script Editor.
The renamed record still has a path to “Sample Record” after the set name operation and the “log message” call logs an empty updatedContent. Clicking on “Renamed Record” in the UI results in a “File missing” error. Commenting out the set name line causes it to work as expected, with the text updated and logged.
Interestingly this behavior is the same whether i have it create a new database, or use an already open one.
tell application id "DNtp"
try
-- create the new database
set testDatabase to create database "/tmp/test-db-000.dtBase2"
-- set testDatabase to database "test-db-000"
set rootGroup to root of testDatabase
-- create a text record in the new database
set recordProps to {name:"Sample Record", type:txt, plain text:"This is the initial content."}
set createdRecord to create record with recordProps in rootGroup
-- rename the record
set name of createdRecord to "Renamed Record"
-- replace its content
set plain text of createdRecord to "This is the updated content."
-- read back and log the updated content
set updatedContent to plain text of createdRecord
set updatedPath to path of createdRecord
set msg to "Updated content: " & updatedContent & " | Path: " & updatedPath
log message info "Updated Content: " & updatedContent record createdRecord
log message info "Updated Path: " & updatedPath record createdRecord
on error errMsg number errNum
display alert "DEVONthink Script Error" message (errMsg & " (Error " & errNum & ")")
end try
end tell
I log the path as it reflects the path to the underlying text file on disk, which is the same path the UI will show when reporting the “File missing error”.
In DEVONthink 4 the correct property name is record type, not type. I don’t know how much that matters in your example. (From what I understand type should still mostly work as a synonym for backwards compatabilty, but the developers advise using record type going forward.)
The suggested location for your databases is ~/Databases. Other locations should generally be fine, as long as they’re not in the cloud. But I’m not sure about system folders like /tmp… Seems like a bad idea to me. I wouldn’t be surprised if that’s the main problem.
Running with your contrived example, the following works flawlessly on my machine and executes in under a second. I’m still on DT3, which does use type, but I think that’s the only thing you’d need to change.
tell application id "DNtp"
set dir to POSIX path of (path to home folder) & "Databases/" -- or some other folder in your User directory
set dbPath to dir & "test-DB-script.dtBase2"
set db to create database dbPath
if db is missing value then
set db to open database dbPath
log message (dbPath & " already exists" & linefeed & "(UUID: " & uuid of db & ")")
else
log message (dbPath & " created" & linefeed & "(UUID: " & uuid of db & ")")
end if
set newRec to create record with {type:txt, name:"Test record", plain text:"Content of test record"} in root of db -- for DT4 use 'record type'
set msg1 to "[NAME] " & (name of newRec) & linefeed & "[CONTENT] " & (plain text of newRec) & linefeed & "[PATH] " & (path of newRec)
log message info msg1 record newRec
set name of newRec to "Updated test record"
set plain text of newRec to "Updated content. Just a little change for testing."
set msg2 to "[NAME] " & (name of newRec) & linefeed & "[CONTENT] " & (plain text of newRec) & linefeed & "[PATH] " & (path of newRec)
log message info msg2 record newRec
end tell