w EventKit Predicate to find Event UID

If I have an event UID, how do I script EventKit to isolate that one event, using a predicate that refers to the UID string. I wrote the following script to show that I can isolate EventKit events by dates, but have to resort to a loop to isolate EventKit events by a sharedUID.

I used Shane’s “CalendarLib EC” to gather the elements of the event itself in that loop.

The following applescript example finds an event whose UID is “34C4450E-70C0-48D5-B94C-03240284C1BD” scheduled in a calendar named “Personal Web” in period ranging from 7 days prior to 5 days hence.

The script correctly yields the following:
{event_external_ID:“34C4450E-70C0-48D5-B94C-03240284C1BD”, event_location:missing value, event_end_date:date “Sunday, June 3, 2018 at 2:00:00 PM”, event_start_date:date “Sunday, June 3, 2018 at 1:45:00 PM”, event_time_zone:“America/Los_Angeles”, event_status:“confirmed”, event_description:missing value, event_url:missing value, event_organizer:missing value, calendar_type:“cloud”, all_day:false, event_creation_date:date “Sunday, June 3, 2018 at 5:32:03 PM”, event_original_date:missing value, event_attendees:{}, event_is_recurring:false, event_summary:“Trial Event”, calendar_name:“Personal Web”}

How can I script the final repeat loop using a predicate method?

use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "EventKit"
use script "CalendarLib EC"

set targetUID to "34C4450E-70C0-48D5-B94C-03240284C1BD"
set listOfCalNames to {"Personal Web"} -- list of one or more calendar names
set DaysBefore to 7
set DaysAhead to 5
set eventInformation to my getEventInfoForUID:targetUID inCalendarList:listOfCalNames fromDaysBefore:DaysBefore toDaysAhead:DaysAhead
on getEventInfoForUID:targetUID inCalendarList:listOfCalNames fromDaysBefore:DaysBefore toDaysAhead:DaysAhead
	# Create event store and get access to Calendars
	set theEKEventStore to current application's EKEventStore's alloc()'s init()
	theEKEventStore's requestAccessToEntityType:0 completion:(missing value)
	# Get event store authorization status
	my authorizationStatus()
	# Arrange date predicates
	set {DaysBehindDate, DaysAheadDate} to my prepareDateRangeFromDaysBefore:DaysBefore toDaysAhead:DaysAhead
	# Arrange calendar predicate
	set calsToSearch to my getCalendarsToSearch:listOfCalNames withEKEventStore:theEKEventStore
	if calsToSearch is false then return false --abort script
	# Find matching events for date using predicate method
	set theDatePred to theEKEventStore's predicateForEventsWithStartDate:DaysBehindDate endDate:DaysAheadDate calendars:calsToSearch
	set theEvents to (theEKEventStore's eventsMatchingPredicate:theDatePred)
	# Find matching event for UID using loop method
	# I am unable to write an EventKit predicate method
	set eventInformation to my LoopThroughEvents:theEvents ToGetEventInformationFromTargetUID:targetUID
end getEventInfoForUID:inCalendarList:fromDaysBefore:toDaysAhead:

on getCalendarsToSearch:listOfCalNames withEKEventStore:theEKEventStore
	--set calendar type for EventStore Predicate
	set listOfCaTypes to {0, 1, 2} -- list of one or more calendar types: : Local = 0, CalDAV/iCloud = 1, Exchange = 2, Subscription = 3, Birthday = 4
	-- get calendars that store events
	set theCalendars to theEKEventStore's calendarsForEntityType:0
	-- filter for desired calendars
	set theNSPredicate to current application's NSPredicate's predicateWithFormat_("title IN %@ AND type IN %@", listOfCalNames, listOfCaTypes)
	set calsToSearch to theCalendars's filteredArrayUsingPredicate:theNSPredicate
	if (count of calsToSearch) < 1 then set calsToSearch to false
end getCalendarsToSearch:withEKEventStore:

on authorizationStatus()
	-- check if app has access and authorization
	set authorizationStatus to current application's EKEventStore's authorizationStatusForEntityType:0 -- work around enum bug 
	if authorizationStatus is not 3 then
		display dialog "Access must be given in System Preferences" & linefeed & "-> Security & Privacy first." buttons {"OK"} default button 1
		tell application "System Preferences"
			tell pane id "com.apple.preference.security" to reveal anchor "Privacy"
		end tell
		error number -128
	end if
end authorizationStatus

on prepareDateRangeFromDaysBefore:DaysBefore toDaysAhead:DaysAhead
	# create start date and end date for occurances
	--set nowNSDate variable to represent  current  UTC  Universal Time-Coordinated  date, previously Zulu Time Zone
	set nowDate to current application's NSDate's |date|
	--startOfDayForDate returns the first UTC moment of a given date as a date instance, based upon the current time zone.
	set todaysStartofDayDate to current application's NSCalendar's currentCalendar()'s startOfDayForDate:nowDate
	--set the days that will define the date predicate range
	set DaysBehindDate to todaysStartofDayDate's dateByAddingTimeInterval:(-1) * DaysBefore * days
	set DaysAheadDate to todaysStartofDayDate's dateByAddingTimeInterval:DaysAhead * days
	{DaysBehindDate, DaysAheadDate}
end prepareDateRangeFromDaysBefore:toDaysAhead:

on LoopThroughEvents:theEvents ToGetEventInformationFromTargetUID:targetUID
	# Question:  What EventKit predicate method  can  avoid the following loop, so that a large list can be evaluated?
	repeat with anEvent in theEvents
		set shareUID to (anEvent's sharedUID as string)
		if targetUID is shareUID then
			return (event info for event anEvent)
			exit repeat
		end if
	end repeat
end LoopThroughEvents:ToGetEventInformationFromTargetUID:

If I understand you correctly, this:

set theNSPredicate to current application's NSPredicate's predicateWithFormat:"calendarItemExternalIdentifier == %@" argumentArray:{targetUID}

As shown below, I am far from mastering the Objective C EventKit language via Applescript.
Using the following instantiation of an NSPredicate,

	set theNSPredicate to current application's NSPredicate's predicateWithFormat:"calendarItemExternalIdentifier == %@" argumentArray:{targetUID}

I have tried three methods, yielding three different Applescript responses:

	set theEvents to (theEKEventStore's eventWithIdentifier:theNSPredicate)

–>-[NSComparisonPredicate length]: unrecognized selector sent to instance 0x604002042760

	set theEvents to (theEKEventStore's eventsMatchingPredicate:theNSPredicate)

–>predicate was not created with EKEventStore methods

	set theEvents to (theEKEventStore's eventWithIdentifier:targetUID)


What might be an effective EventKit predicate command to isolate an event by means of its External Identifier?

That’s a standard predicate, not specific to EventKit. It assumes you have a standard array, as you have in your code after using the dates-based predicate. So something like:

set theNSPredicate to current application's NSPredicate's predicateWithFormat:"calendarItemExternalIdentifier == %@" argumentArray:{targetUID}
set filteredEvents to theEvents's filteredArrayUsingPredicate:theNSPredicate