Сравнения/расширенные запросы в Javascript для автоматизации (JXA), чей()

Если бы я хотел просмотреть свой календарь OS X (ранее «iCal»), чтобы найти события, сводка которых была «Обед», я мог бы сделать что-то вроде этого:

var eventsContainer = Application('Calendar').calendars[0].events
for (var i = 0; i < eventsContainer.length; i++) {
    var thisEvent = eventsContainer[i];
    if (thisEvent.summary() == 'Lunch') { doSomething() }
} 

даже принимая во внимание тот факт, что поиск выполняется только в первом календаре, это очень, очень, очень медленно, поскольку для запуска каждое событие iCal необходимо преобразовать в объект Javascript. Вот формулировка, которая значительно быстрее:

var foundEvents = Application('Calendar').calendars.events.whose({summary: 'Lunch'});

Это отлично работает для точного совпадения summary == 'Lunch'. А как насчет таких сравнений, как endDate: > new Date() или summary: /lunch/i? Можно ли передать собственный (ObjC) код в чей() селектор? Есть ли где-нибудь документация по whose(), которая могла бы помочь?


person Michael Scott Cuthbert    schedule 25.06.2016    source источник
comment
Этот связанный вопрос: stackoverflow.com/questions/27072977/ в первую очередь касался того, чтобы простая форма whose() работала в начальной реализации JXA с ошибками. Это не дубликат Q.   -  person Michael Scott Cuthbert    schedule 25.06.2016


Ответы (1)


Соответствующая документация оказалась в примечаниях к выпуску межприложенной связи для OS X 10.10: https://developer.apple.com/library/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/Articles/OSX10-10.html

Правая часть объекта в аргументе whose() может принимать другой одноэлементный объект, где левая часть дает оператор, а правая часть дает значение. Например:

.calendars.events.whose({summary: {_beginsWith: 'Lunch'}});

или в моем случае, чтобы найти события, начинающиеся сегодня:

    var startOfDay = new Date();
    startOfDay.setHours(0);
    startOfDay.setMinutes(0);
    startOfDay.setSeconds(0);
    startOfDay.setMilliseconds(0);
    var endOfDay = new Date();
    endOfDay.setHours(23);
    endOfDay.setMinutes(59);
    endOfDay.setSeconds(59);
    endOfDay.setMilliseconds(999);

    var events = Application('Calendar').calendars.events.whose({
        _and: [
            { startDate: { _greaterThan: startOfDay }},
            { startDate: { _lessThan: endOfDay }}
        ]
    });
    var convertedEvents = events();
    for (var cal of convertedEvents) {
        for (var ev of cal) { 
            console.log(ev.summary());
        }
    }  
person Michael Scott Cuthbert    schedule 25.06.2016
comment
Спасибо, что поделились отличным вопросом и ответом! - person JMichaelTX; 26.06.2016
comment
Спасибо! Я оставлю принятый ответ открытым, чтобы посмотреть, сможет ли кто-нибудь улучшить синтаксис/скорость. Запрос занимает 20 секунд на моем компьютере. - person Michael Scott Cuthbert; 26.06.2016
comment
На моем компьютере запрос занимает 20 секунд — это меня удивляет. Было бы интересно время просто через var events = . . . утверждение. Я бы сделал это, но я не использую Apple Calendar. Меня больше интересовал общий подход и использование функции who(). - person JMichaelTX; 27.06.2016
comment
Оператор var events = ... вообще не требует времени, потому что он является своего рода эквивалентом оператора подготовки SQL. Это оператор var convertedEvents = events(), который занимает все время, но занимает одинаковое количество времени (приблизительно), независимо от того, сколько событий извлекается. На него приходится › 90% времени выполнения. Предположительно, это O (n) от количества событий в моих календарях, которое, я думаю, составляет где-то около 2000 (50 x месяц * 4 года). Очевидно, что у iCal более быстрая система. - person Michael Scott Cuthbert; 27.06.2016
comment
@MichaelScottCuthbert Где вы запускали свой код? ScriptEditor не нуждается в console.log() - person OrigamiEye; 18.03.2020
comment
console.log() предназначен для демонстрации того, что вы можете сделать с объектом события. Это заменяет фактическую логику приложения. - person Michael Scott Cuthbert; 21.03.2020
comment
Есть ли способ ограничить количество возвращаемых результатов? Часто я ожидаю только одно совпадение (например, whose с идентификатором), и из соображений производительности я бы предпочел .whose({id: myId}, {limit: 1})[0] вместо .whose({id: myId})[0]. Но я не могу понять синтаксис для включения первого, если он существует. - person BallpointBen; 07.12.2020