Язык Expr используется в столбцах формулы и в других местах структуры для получения вычисляемых значений на основе данных Jira и структуры. Эта ссылка представляет собой подробное описание языка Expr, его синтаксиса и правил вычисления.
Чтобы начать изучать Expr и то, что вы можете делать со структурными формулами, ознакомьтесь с примерами формул или более высокоуровневым описанием языка Expr. Это расширенный материал, который может быть полезен для более глубокого изучения, устранения неполадок или создания сложных формул. Это может потребовать некоторых знаний в области программирования.
Этот справочник содержит схемы железных дорог, иллюстрирующие некоторые элементы синтаксиса языка. Они намеренно упрощены и не должны рассматриваться как полное определение языка.
Вступление
В своей простейшей форме язык Expr похож на формулы Excel или Google Sheets. Сходство с формулами электронной таблицы, когда это возможно, было целью разработки, особенно при выполнении арифметических операций, использовании функций и ссылках на значения из электронной таблицы (поля Jira или результаты других формул). Язык становится более сложным, когда вам нужно работать с массивами или элементами со свойствами.
Expr — это декларативный динамически типизированный язык с элементами функционального программирования.
Вот несколько свойств языка:
- Expr нечувствителен к регистру. Два идентификатора, различающиеся только в верхнем или нижнем регистре, будут означать одно и то же.
- Пробелы, включая новые строки, не имеют значения. Требуется только разделить словесные операторы и идентификаторы; во всех остальных случаях может быть произвольное количество пробельных символов.
- За исключением текстовых литералов, язык поддерживает только английские (ASCII) буквы, цифры и некоторые знаки препинания.
- Агрессивное преобразование типов: когда функции требуется определенный тип, а переданное значение имеет другой тип, Expr приложит все усилия, чтобы преобразовать переданное значение в требуемый тип.
Языковые версии Expr
Версии Expr |
Версия структуры |
главные улучшения |
Выражение 1.0 |
Структура 4.0 |
Представлена исходная версия |
Выражение 1.5 |
Структура 4.2 |
Локальные переменные, агрегатные функции, комментарии |
Expr 2.0 |
Структура 7.0 |
Массивы, элементы и свойства, пользовательские функции, связанные вызовы функций, встроенные запросы, условное выражение, текстовые фрагменты, оператор конкатенации |
Замечания по совместимости в Expr 2.0 см. в разделе Изменения в Expr в структуре 7.
Выражения и значения
Программа, написанная на языке Expr, является выражением. Выражение оценивается структурой и возвращает значение. В столбце Формула выражение вычисляется для каждой строки путем применения выражения к проблеме или другому элементу в этой строке, а результат отображается в соответствующей ячейке столбца Формула.
Язык Expr является компонуемым. Если у вас есть действительное выражение, вы можете включить его как часть другого выражения, и оно будет действительным. Иногда для этого потребуется заключить его в круглые скобки.
Ленивый расчет
Выражения expr вычисляются лениво (исключая агрегатные функции и встроенные запросы). Это означает, что, например, будет вычисляться только одна ветвь в выражении ЕСЛИ.
Отображение результата вычисления в столбце формулы
Столбец формул — это основное средство создания и использования формул. В настоящее время он может отображать простые значения, элементы и плоские массивы. (См. Значения и типы ниже.) Если формула возвращает более сложную конструкцию — вложенные массивы или сопоставления «ключ-значение», текущая версия столбца не сможет ее отобразить. Однако это не означает, что формула не вычисляется!
Комментарии
В любом месте, где формула допускает пробелы, вы можете использовать комментарии. Комментарии могут занимать несколько строк или только одну.
- Многострочные комментарии начинаются с «/*» и заканчиваются «*/» и могут занимать несколько строк. Многострочные комментарии не могут быть вложенными.
- Однострочные комментарии начинаются с «//» и продолжаются до конца строки.
Идентификаторы
Все именованные элементы Expr — переменные, локальные переменные, функции и другие — должны иметь допустимый идентификатор в качестве имени.
Идентификатор состоит из букв (только латинский алфавит: a-z, A-Z), цифр (0-9) или символов подчеркивания (_). Первый символ должен быть буквой или символом подчеркивания. Идентификатор не должен быть ключевым словом.
Версии 1.x Expr также позволяли символу точки (.) быть частью идентификатора. Эта возможность была удалена в Expr 2.0.
Ключевые слова
Следующие ключевые слова нельзя использовать в качестве идентификаторов.
AND, CONCAT, ELSE, IF, NOT, OR, UNDEFINED, WITH
Значения и типы
Все выражения при вычислении дают либо значение, либо ошибку. Все значения неизменяемы — если вам нужно изменить значение, вы извлекаете из него другое значение.
Каждое значение принадлежит определенному типу. Есть простые и сложные виды.
Простые типы представляют только одно значение и позволяют записывать литеральные значения (константы). Простые типы:
- Неопределенный
- Текст
- Число
Сложные типы представляют значение, имеющее некоторую внутреннюю структуру. Сложные виды бывают:
- Элемент
- Массив
- Функция пользователя
- Карта ключ-значение
Ошибки — это специальные значения, но они обычно приводят к тому, что все выражение возвращает ошибку.
Библиотечная функция может ожидать определенные типы в качестве параметров и в результате будет создавать определенный тип. Expr также попытается преобразовать один тип в другой по мере необходимости.
Неопределенный Undefined
Undefined — это специальное значение, которое представляет собой «отсутствие значения» или отсутствующее значение. Например, переменная Assignee будет иметь неопределенное значение, если задача не назначена.
Вместо значения любого другого типа можно использовать неопределенное значение.
Чтобы явно использовать неопределенное значение в формуле, вы можете написать undefined.
Функции могут возвращать значение undefined, если результат функции не указан. Например, функция IF (N = 0; «Нет яблок»; N = 1; «Одно яблоко») имеет указанное значение только тогда, когда N равно 0 или 1. Если N равно чему-то еще, она возвращает неопределенное значение.
Текст
Текстовое значение состоит из 0 или более символов Unicode. Его буквальное представление состоит из значения, заключенного в одинарные кавычки (') или двойные кавычки ("). Пример: "Major" представляет текстовое значение Major. Аналогично, "Major" представляет то же самое текстовое значение.
Если само текстовое значение содержит кавычки, перед ними необходимо вставить обратную косую черту (\). Пример: "Charlie \"Bird\" Parker" представляет текстовое значение Charlie "Bird"Parker. Кроме того, вы можете использовать другой тип кавычек, чтобы заключить буквальное представление: ‘Чарли “Бёрд” Паркер’.
Если вам нужно использовать обратную косую черту в конце текстового значения, вам нужно будет вставить другую обратную косую черту перед ним. Пример: "C:\Users\John\\" представляет текстовое значение C:\Users\John\.
Фрагменты текста (""")
Иногда вам нужно длинное текстовое значение, содержащее несколько слов и символов, а также значение определенного выражения или переменной. Один из способов создать его — использовать функцию CONCAT и соединить все фрагменты текста вместе. Более удобным способом может быть написание текстового фрагмента.
Фрагмент текста начинается с тройных двойных кавычек (""") и продолжается до следующих тройных двойных кавычек. Он включает концы строк, поэтому с помощью фрагмента текста можно создавать многострочные текстовые значения.
Фрагменты текста могут содержать специальные последовательности, которые заменяются вычисляемым значением:
- Знак доллара, за которым следует имя переменной, заменяется значением этой переменной. Например, """Назначено: $assignee""".
- Знак доллара, за которым следует выражение Expr в фигурных скобках, заменяется значением этого выражения. Например, """Общая оценка: ${score + subtasks.score.SUM() }""".
Число
Число представляет собой одно числовое значение. Помимо представления некоторого количества, числовое значение также может представлять момент времени или продолжительность времени. В этом случае вы можете использовать настройки формата в столбце «Формула», чтобы правильно отображать результаты в виде дат или длительности.
Есть две формы буквального представления чисел:
- целое число: 42
- дробное число: 0,239
Обратите внимание, что в качестве десятичного разделителя можно использовать только точку (.). Запятая (,) используется для разделения аргументов функции. Таким образом, MAX(X, 0,618) будет пониматься как максимальное из трех значений: X, 0 и 618.
Разделители групп не поддерживаются, поэтому 100 000 не является буквальным представлением числа 100 000. Однако вы можете написать строковое значение и явно вызвать функцию преобразования – NUMBER("100 000"). См. преобразование чисел.
Техническое примечание: внутренне числа представляются как десятичные числа с плавающей запятой с точностью до 16 цифр и получетным округлением. В этой форме проводится большинство операций; однако некоторые более сложные функции, такие как SQRT, могут сначала преобразовывать числа в двоичные числа с плавающей запятой, вычислять результат, а затем преобразовывать его обратно в десятичные числа с плавающей запятой.
Дата и дата/время
Значение даты/времени представлено как целое число миллисекунд с эпохи Unix (1970-01-01 00:00:00 по Гринвичу). Функции даты помогут вам преобразовать эти числа в читаемые текстовые значения.
Значение даты (без компонента времени) представляется так же, как значение даты/времени, рассчитанное для полуночи указанного дня — в текущем часовом поясе пользователя РИСУНОК warning.png (предупреждение). Это означает, что выражения, включающие значения даты (например, с использованием поля «Дата выполнения» Jira), могут давать разные результаты для разных пользователей, если они находятся в разных часовых поясах.
Продолжительность
Значение Duration представлено целым числом миллисекунд. Функции длительности помогают преобразовывать значения длительности в читаемые текстовые значения.
Boolean
Логическое значение, например, возвращаемое из функций сравнения, представлено числом 1, если оно истинно, или 0, если оно ложно.
Кроме того, все значения могут быть преобразованы в логические значения в зависимости от того, являются ли они «правдивыми». (См. Преобразование значений.)
Элемент
Значение элемента представляет собой объект, который вы потенциально можете иметь в виде строки в структуре — задача Jira, проект, спринт, версия, пользователь, статус, приоритет и другие. Он также может представлять чисто принадлежащие структуре объекты, такие как папки.
У элементов есть свойства, к которым вы можете получить доступ, написав item.propertyName или (выражение-результат элемента).propertyName. Типы элементов, их свойства и их тип перечислены в Справочнике свойств элементов.
Специальное преобразование значений Item
Значения элемента всегда можно использовать как текст. Затем каждый элемент будет представлен текстом — проблема по ключу проблемы, проект по его названию и т. д.
Кроме того, элементы можно сравнивать с использованием функций UMAX и UMIN, которые будут учитывать «естественный» порядок элементов. Большинство элементов будут сравниваться в алфавитном порядке, но некоторые будут иметь предопределенный порядок, например приоритетные элементы.
Специальная обработка значений Item генераторами
Подобно операциям max/min, если столбец формулы создает значения Item, вы можете сортировать по этому столбцу (или использовать сортировщик атрибутов), чтобы изменить порядок структуры в соответствии с естественным порядком результирующих элементов.
Если группировщик атрибутов настроен с формулой, которая создает значения элементов, группы станут этими элементами.
Массив
Значение массива представляет собой список других значений. Каждое значение в массиве называется элементом массива.
Каждое значение в массиве может быть любого типа — у вас может быть массив текстов, массив элементов, массив массивов и так далее. Массив может содержать различные типы значений в каждом элементе — первое может быть числом, второе — элементом, а третье — массивом других элементов.
К значениям в массиве можно получить доступ по их индексу. Первое значение имеет индекс 0, второе значение имеет индекс 1 и так далее.
Существует ряд функций массива, которые позволяют вам писать формулы, работающие с несколькими значениями — см. Функции массива.
Создание массива
Вы можете создать массив, вызвав функцию ARRAY: ARRAY (элемент1, элемент2, элемент3, ...)
Когда вам нужно изменить массив, вы применяете некоторые преобразования к существующему массиву — чаще всего это FILTER и MAP. Это эффективно создает новый массив.
Доступ к элементам массива
Вы можете получить доступ к элементу массива по его индексу, используя функцию GET: array.GET(index)
Однако обычно в этом нет необходимости, так как вычисления с массивами выполняются в основном с помощью FILTER, MAP и REDUCE.
Специальная обработка значений массива генератором группы атрибутов
Когда значение массива возвращается формулой в генератор группировщика атрибутов, он создает несколько групп — по одной для каждого непустого, отдельного значения, возвращаемого формулой.
Функция пользователя
Значение пользовательской функции (иногда называемое «лямбда-значением») представляет собой фрагмент кода Expr, который определяет функцию — см. Пользовательские функции ниже.
Как правило, вы создаете значение пользовательской функции, чтобы применить его к массиву с помощью одной из системных функций, таких как FILTER или MAP.
Например, рассмотрим следующий код:
worklogs.FILTER($.author = ME()).MAP(w -> w.timeSpent).REDUCE((a, b) -> a + b)
Здесь есть три пользовательские функции: $.author = ME() , w -> w.timeSpent и (a, b) -> a + b . Первый определяет условие для фильтрации рабочих журналов, второй определяет, как преобразовать каждый рабочий журнал в число, а третий определяет, как объединить несколько чисел в один.
Каждая из этих трех частей Expr оценивается и представляется значением типа «Пользовательская функция» и передается в FILTER, MAP и подобные функции.
Как и любое другое значение, значение пользовательской функции может быть присвоено переменной. Для этого можно использовать более традиционную форму определения функции. Следующие два определения идентичны:
WITH square = x -> x * x :
...
WITH square(x) = x * x :
...
Карта ключ-значение
Карта ключ-значение создается некоторыми функциями Expr и представляет собой набор пар, где «ключ» — это имя свойства, а «значение» — значение свойства.
В настоящее время только функция GROUP создает карту «ключ-значение», при этом группа ключей сопоставляется со значением, по которому сгруппирован массив, а ключевые элементы сопоставляются с массивом соответствующих элементов.
Чтобы получить доступ к значению, вам нужно написать kvm.keyName, где kvm — это локальная переменная или выражение, представляющее карту ключ-значение.
Ключи должны быть хорошо известны; нет возможности перебрать все ключи.
Пользователь не может создать произвольную карту значений ключа; этот тип предназначен только для некоторых системных функций.
Ошибки
Ошибки — это специальные значения, которые указывают на то, что при вычислении некоторой части или всего выражения возникла проблема.
Список возможных ошибок доступен на Expr Error Codes.
Обычно, если где-то в формуле возникает ошибка, результатом всего вычисления также является ошибка. Но если получение ошибки из части выражения допустимо, вы можете использовать функции IFERR и ISERR для ее обработки.
Преобразования значения
Каждая функция Expr ожидает, что в качестве каждого из ее параметров будет передано значение определенного типа. (См. Справочник по функциям Expr.) Когда встречается значение другого типа, предпринимается попытка автоматического преобразования. Если преобразование невозможно, возникнет ошибка.
Правила преобразования следуют некоторым основным принципам:
- Прилагаются все усилия для преобразования простых типов, таких как преобразование текста в число.
- Элемент может быть преобразован в текст, который представляет его
- Любое значение может быть преобразовано в массив из одного элемента (массив «обернутый вокруг» значения)
- Массив только с одним значением может быть преобразован в это значение («развертывание» массива)
Существуют некоторые более специализированные случаи, связанные с параметрами Text/Joined, параметрами, помеченными как /Each, и параметрами типа User Function.
В таблице ниже приведены все правила преобразования.
Фактический тип Требуемый тип |
Число |
текст |
элемент |
Массив |
Карта ключ-значение |
неопределено |
Текст/присоединился |
то же, что и выше |
· собрать значение Text (не Text/Joined!) для каждого элемента, не являющегося неопределенным · объединять элементы в одну строку с "," в качестве разделителя |
то же, что и выше |
|||
Текст |
Преобразуется в текст |
Проходит как есть |
использовать текстовое представление элемента, в зависимости от типа элемента |
· пустой массив → неопределенный/ пустой текст · имеет только один элемент → попробуйте преобразовать этот элемент · иначе: ошибка |
ошибка |
не определена/пустой текст |
Число |
Проходит как есть |
· пустая строка → не определено · попытка преобразовать в число · в случае неудачи: ошибка |
использовать текстовое представление элемента в соответствии с типом элемента, а затем использовать правила преобразования текста в число |
· пустой массив → не определен · имеет только один элемент → попытка преобразовать этот элемент · иначе: ошибка |
ошибка |
неопределено |
Карта ключ-значение |
ошибка |
ошибка |
ошибка |
· пустой массив → не определен · имеет только один элемент → попытка преобразовать этот элемент · иначе: ошибка |
Проходит как есть |
неопределено |
Элемент |
ошибка |
ошибка |
Проходит как есть |
· пустой массив → не определен · имеет только один элемент → попытка преобразовать этот элемент · иначе: ошибка |
ошибка |
неопределено |
Целое |
· использовать, если целочисленное значение · иначе: ошибка |
то же, что и выше, и попробуйте преобразовать в целое число |
||||
Дата |
· то же, что и выше: метки времени представлены как «миллисекунды эпохи unix» · даты представлены как временная метка полуночи соответствующего дня в часовом поясе пользователя · использование нецелых значений может привести к ошибке |
|||||
Boolean |
· ложь, если ноль · верно иначе |
· false, если пусто или только пробелы · true в противном случае (включая "0"!) |
верно |
· ложь, если пусто · true в противном случае (включая массив с 0 в качестве элемента) |
true |
false |
Массив |
массив с одним элементом |
массив с одним элементом |
массив с одним элементом |
Проходит как есть |
массив с одним элементом |
Неопределено/пустой массив |
Любое |
любое значение работает |
Преобразование текста в число
Некоторые функции ожидают, что их аргументы будут числовыми значениями. Если аргумент является текстовым значением, мы пытаемся интерпретировать его как число. Это может быть полезно, если значение исходит из переменной, представляющей текстовое настраиваемое поле, содержащее числа, например, импортированное из какой-то внешней системы.
Если преобразование прошло успешно, это число используется в качестве значения для этого аргумента. Если преобразование не удалось, функции могут либо выдать ошибку, либо проигнорировать этот аргумент, либо заменить какое-либо значение по умолчанию — это зависит от функции; подробности см. в Справочнике по функциям Expr.
Первый шаг — учесть различия в форматировании чисел. Преобразование поддерживает следующие символы форматирования:
- Разделители десятичных дробей: запятая (,), точка (.)
- Разделители групп цифр: запятая (,), точка (.), апостроф ('), пробел (␣)
Преобразование предполагает, что текст содержит 0 или 1 десятичный знак и 0 или более разделителей групп одного типа. Если текст содержит любые другие символы форматирования, преобразование завершается ошибкой. Десятичный знак должен стоять после всех разделителей групп, иначе преобразование завершится ошибкой.
Если текст содержит только один символ форматирования, и это точка (.), он всегда обрабатывается как десятичный знак. Если текст содержит только один символ форматирования, и это запятая (,), то он обрабатывается как десятичный знак, если запятая используется в качестве десятичного разделителя на языке Jira по умолчанию; в противном случае он рассматривается как разделитель групп. Например, если языком Jira по умолчанию является английский, «101 112» станет 101112, а если это немецкий язык, то будет 101.112. И независимо от языка "1 100,23" станет 1100,23: пробел интерпретируется как разделитель групп, а запятая здесь может быть только разделителем десятичной дроби.
Если разделителем групп является точка (.), то все группы, кроме первой, должны состоять из 3 цифр; в противном случае преобразование завершится ошибкой.
После определения десятичного знака и символов-разделителей групп преобразование удаляет все символы-разделители групп и заменяет десятичный знак точкой. Обратите внимание, что если текст содержит несколько целых чисел, разделенных пробелами, преобразование будет считать, что это одно число, например, «10 11 12» станет 101112. Точно так же «10,11,12» станет 101112.
Последним шагом преобразования является распознавание результирующего текста либо как буквальное числовое представление Expr, либо как научная или инженерная нотация. Примеры:
0,239
-1.32e5
12е-3
Преобразование в логические значения: ложные и истинные значения
Значение является ложным, если оно:
- неопределено,
- число 0,
- пустое текстовое значение ("" или '') или текстовое значение, содержащее только пробелы,
- пустой массив.
Все остальные значения являются истинными.
При преобразовании в логическое значение истинные значения становятся истинными, а ложные значения становятся ложными.
По соглашению, когда функции или логические операторы должны построить истинное значение, они используют число 1.
Текст против текста/объединения
Когда функция объявляет, что ей требуется значение "Text/Joined", это означает, что значение будет преобразовано в текст с дополнительной специальной обработкой типа массива:
Если это пустой массив или массив только с одним элементом, преобразование будет таким же, как и для типа "Текст".
Если передается массив с несколькими значениями, то а) каждый элемент массива будет преобразован в значение Text, б) все эти тексты будут объединены запятой в качестве разделителя.
Вот пример, иллюстрирующий разницу, когда fixVersion передается в качестве параметра — обратите внимание, что в третьей строке есть несколько значений в fixVersion (поскольку это массив), поэтому Text и Text/Joined обрабатываются по-разному:
Версия исправления |
Функция, принимающая текст, получит |
Функция, принимающая Text/Joined, получит |
(нет значения) |
неопределено |
неопределено |
v1 |
“v1” |
“v1” |
v1, v2 |
ошибка |
“v1, v2” |
Передача неявной пользовательской функции в качестве параметра
Вы всегда можете передать неявную пользовательскую функцию (ту, которая содержит символ «$») в качестве аргумента функции. Это приведет к тому, что вызов этой функции сам станет неявным значением пользовательской функции.
Например, рассмотрим следующее выражение:
КОД
fixVersions.FILTER(ГОД($.releaseDate) = 2021)
Функция YEAR() ожидает дату, но вместо этого получает функцию пользователя ($.releaseDate), которая выдает дату выпуска для каждой переданной версии. В результате применения YEAR() к этой пользовательской функции мы получим другую пользовательскую функцию, которая выдает год даты выпуска для каждой переданной версии.
Эта логика применяется только к неявным функциям пользователя, определенным со знаком $.
Функции, которые ожидают параметр User Function, например FILTER, являются исключениями из этого правила.
Переменные
Переменные (также известные как свободные или устанавливаемые извне переменные) представляют некоторые значения, которые будут переданы в формулу для каждой строки структуры, к которой будет применяться формула.
Например:
КОД
ЕСЛИ приоритет = «Блокировщик»: parent.estimate + x
В этой формуле «приоритет», «родительский элемент» и «x» являются переменными — они меняются от одной строки к другой. (Они не изменят значение при вычислении выражения для одной строки.)
Нет необходимости объявлять переменную, вы можете сразу начать ее использовать. Все допустимые идентификаторы, которые используются как переменные, будут рассматриваться как таковые.
Каждая формула должна содержать хотя бы одну переменную, иначе результат будет одинаковым для каждой строки.
Отображение переменной в атрибут
Каждая переменная должна быть сопоставлена с действительным атрибутом, таким как поле Jira или атрибут структуры, поэтому, когда выражение вычисляется для определенного элемента, значение этого атрибута становится значением переменной.
Если вы используете одно из четко определенных имен переменных, оно будет автоматически сопоставлено с соответствующим атрибутом. См. Справочник по стандартным переменным.
Если вы используете произвольное имя переменной, например «x», вам нужно будет сопоставить его, как описано на странице «Сопоставление переменных».
Если переменная не сопоставлена или элемент не поддерживает сопоставленный атрибут, значением переменной будет неопределенное значение.
"this" переменная
Одним из хорошо определенных имен переменных является «this». Он сопоставляется с атрибутом, предоставляющим значение типа элемента, представляющее элемент, для которого вычисляется формула.
Это может пригодиться в определенных случаях. Например, чтобы проанализировать ссылки на проблемы и выбрать «другую сторону» ссылки, независимо от того, входящая это ссылка или исходящая:
issueLinks.MAP(ЕСЛИ $.source = это: $.destination ELSE $.source)
В качестве альтернативы вы можете использовать «предмет» с тем же значением.
Локальные переменные
Локальные переменные похожи на переменные, но они не сопоставляются с атрибутом элемента или полем Jira, а скорее определяются и вычисляются прямо в выражении.
Синтаксис объявления следующий:
Обратите внимание на двоеточие (":"), которое разделяет выражение, присвоенное переменной, и выражение, в котором эта переменная используется.
Несколько фактов о локальных переменных:
- ExpressionWithLocalVariable может начинаться с другого определения локальной переменной, поэтому вы можете вводить множество локальных переменных последовательно. При определении второй переменной вы можете использовать уже определенную первую переменную и так далее.
- Локальные переменные могут «затенять» ранее определенные локальные и свободные (сопоставленные) переменные с тем же именем. Если написать WITH priority = 10: <выражение>, то при вычислении <выражения> значение priority будет равно 10, даже если в объемлющей области видимости к приоритету задачи была привязана переменная.
- Конструкция WITH... сама по себе является выражением, поэтому вы можете использовать ее, заключенную в круглые скобки, везде, где может использоваться выражение. Имя, определенное в этом выражении, не видно вне выражения WITH....
Неизменность
Языковые конструкции Expr неизменяемы. Как только локальная переменная определена, она не может изменить свое значение. (Поэтому на самом деле называть ее «переменной» не совсем правильно. Хотя, если локальная переменная зависит от внешних переменных, которые варьируются от элемента к элементу, сама локальная переменная также будет варьироваться от элемента к элементу.)
Поэтому, если вы строите свою формулу и вам нужно взять ряд значений через ряд вычислений, вам может понадобиться использовать несколько локальных переменных, проходя каждый шаг и назначая каждый промежуточный результат другой локальной переменной.
Операторы
Операторы позволяют записывать формулы удобным способом, используя традиционные логические и арифметические операции. Каждый оператор имеет один (унарные операторы) или два операнда. Каждый операнд может быть переменной, числом или просто любым выражением, которое иногда нужно заключать в круглые скобки.
Операторы преобразуются в вызов соответствующих функций с операндами в качестве аргументов. Если выражение операнда оценивается как ошибка, то результатом операции также будет ошибка.
Доступные операторы:
Оператор(ы) |
Символ |
Приоритет |
Тип операндов |
Тип результата |
Соотвествующая функция |
Логическое отрицание |
NOT |
7 |
любой |
Число(логическое) |
NOT |
Унарный знак |
+ - |
7 |
Преобразование в число |
Число |
SUM, MINUS |
Умножение и деление |
* / |
6 |
Преобразование в число |
Число |
MUL, DIV |
Складывание и вычитание |
+ - |
5 |
Преобразование в число |
Число |
SUM, MINUS |
Котенкация |
CONCAT |
4 |
Преобразовать в текстовый/объединенный |
Текст |
CONCAT |
Проверка равенства/неравенства |
=!= |
3 |
любое |
Число(логическое) |
EQ, NE |
Числовое сравнение |
< > <= >= |
3 |
число |
Число(логическое) |
LT, GT, LE, GE |
Логическое AND |
AND |
2 |
любое |
Любое(*) |
AND |
Логическое OR |
OR |
1(найнизшее) |
любое |
Любое(*) |
OR |
Операторы перечислены в порядке их приоритета. Приоритет важен, когда выражение может допускать различные интерпретации того, какие операторы применяются первыми.
Например, в выражении progress + parent.progress * weight < threshold AND priority != "Blocker" сначала выполняется умножение, затем сложение, затем сравнения, а затем логическое И. Если вы хотите изменить порядок применения операторов, используйте круглые скобки.
Логическое отрицание (NOT)
Чтобы инвертировать логическое значение или выражение, используйте оператор NOT. Вместо NOT можно использовать восклицательный знак (!)
Оператор возвращает 0, если операнд является истинным значением, и 1 в противном случае. Поэтому его можно применить к любому значению.
Если инвертированное значение является выражением с другими операторами, оно должно быть заключено в круглые скобки.
Примеры:
- NOT resolved
- NOT (storyPoints > 0 AND storyPoints < parent.maxStoryPoints)
Унарный знак (+ -)
Сначала оператор пытается преобразовать значение выражения в число. Если преобразование выполнено успешно, + выдает это число, а - выдает число с инверсией.
Если преобразование в число не удается, а значение выражения ложно, то отрицание дает неопределенное значение. В противном случае выдает ошибку.
Арифметические операторы (*/+-)
Арифметические операторы: сложение (+), вычитание (-), умножение (*) и деление (/).
Умножение и деление имеют приоритет перед сложением и вычитанием.
Эти операторы преобразуют свои аргументы в числа. Непустой аргумент, не являющийся числом, вызовет ошибку. Ложные нечисловые значения обрабатываются как нулевые.
Примеры:
- "" + 1 → 1
- "foo" + 1 → ошибка
- "" * 1 → 0
- "foo" * 1 → ошибка
- "" - 1 → -1
- 1/0 → ошибка
Если какое-либо подвыражение выдает ошибку, оператор выдает ту же ошибку.
Конкатенация (CONCAT)
Оператор конкатенации преобразует каждый операнд в текстовое значение (точнее, Text/Joined) и создает новый текст, объединяя их вместе. Это идентично вызову функции CONCAT для ее операндов:
value1 CONCAT value2 CONCAT value3 = CONCAT(value1, value2, value3)
Оператор может использоваться для повышения удобочитаемости формулы.
Обратите внимание, что CONCAT применяется после всех арифметических операторов, но перед сравнениями и логическими операторами.
Проверка равенства (= !=)
Оператор «равно» (=) проверяет, что оба аргумента «по существу являются одним и тем же значением». Оператор «не равно» (!= или <>) создает обратное значение.
Правила сравнения основаны на типе сравниваемых значений.
Оператор равенства вернет true (1), если выполняется любое из следующих условий:
- Оба значения не определены Undefined.
- Одно значение — это число Number, а второе значение — это то же число или может быть преобразовано в то же число.
- Одно значение представляет собой текст, а второе значение может быть преобразовано в текст (используя Text/Joined), и оба значения «по существу одинаковы».
- Различия в формах букв и начальных и конечных пробелах игнорируются (таким образом, " cote " = "côte").
- Одно значение — это элемент, а другое значение — тот же элемент. (Обратите внимание, что если другим значением является текст, оба значения можно сравнивать как текстовые значения.)
- Одно значение представляет собой карту «ключ-значение», а другое значение также является картой «ключ-значение» с тем же содержимым (эти правила равенства применяются ко всем элементам).
- Одно значение — это функция пользователя, а другое значение — точно такая же пользовательская функция (а не только та же логика).
- Одно значение является массивом, и верно одно из следующих утверждений:
- Другое значение также является массивом, имеет такое же количество элементов, и элементы соответственно равны.
- Другое значение не определено, и массив не содержит элементов, отличных от неопределенных.
- Этот массив содержит только один элемент, и этот элемент равен другому значению, не являющемуся массивом, с которым мы сравниваем массив.
Во всех остальных случаях равенство возвращает false (0).
Обратите внимание, что вы можете сравнить элемент с текстом, например,
IF Project = "Мой проект": ...
Элемент будет преобразован в текст с использованием правил преобразования значений, описанных ранее.
Если одно значение является числом, а другое значение может быть преобразовано в число, оба значения рассматриваются как числа. Однако если оба значения являются текстовыми, они будут рассматриваться как текстовые, даже если оба могут быть преобразованы в число. Вы можете использовать функцию NUMBER, ЧИСЛО, чтобы сделать значение числовым.
- 3,4 = 3,40 → 1
- 3.4 = «3.40» → 1
- «3.4» = «3.40» → 0
- NUMBER ("3.4") = "3.40" → 1
Числовое сравнение (< > <= >=)
Операторы упорядочивания/сравнения работают только с числами:
- < (меньше чем)
- > (больше чем)
- <= (меньше или равно)
- >= (больше или равно)
Если какое-либо из значений является текстом, оператор пытается преобразовать его в число. Если преобразование не удается, результатом является ошибка.
Если какое-либо значение не определено, строгие операторы (<, >) выдают 0. Нестрогие (<=, >=) выдают 0, если только оба значения не определены (поскольку они равны).
Логические операторы AND OR (И ИЛИ)
Логические операторы используются для объединения других логических условий или для выбора альтернативного или условного значения.
- OR ИЛИ также может быть записано как "||" или "|"
- AND И также может быть записано как «&&» или «&»
Когда оба операнда являются числовыми (логическими), операторы выполняют соответствующую логическую операцию.
Однако вы можете использовать эти операторы с небулевыми операндами в "коротком замыкании", в зависимости от того, являются ли операнды "правдивыми" (см. выше).
- a OR b – если «a» истинно, «b» не оценивается и результатом операции является «a»; в противном случае результатом операции будет "b".
- a AND b – если «a» ложно, «b» не оценивается и результатом операции является «a»; в противном случае результатом операции будет "b".
Обратите внимание, что "b" не оценивается, если результат операции равен "a". Это может быть важно, если вычисление "b" может привести к ошибке.
Примеры:
- assignee ИЛИ «UNASSIGNED» — будет создан либо пользовательский ключ уполномоченного для задачи, либо (если задача не назначена) текстовое значение «UNDEFINED».
- !assignee AND status = «OPEN» — это даст 1, если задача не назначена и находится в статусе OPEN, и 0 в противном случае.
- count AND total / count — Это даст некоторое среднее число (total / count), если только count не равен 0 — в этом случае результатом будет 0. Обратите внимание, что не будет ошибки деления на ноль.
Условное выражение
Условное выражение IF, «ЕСЛИ» позволяет переключаться между двумя выражениями в зависимости от того, является ли условие истинным (истинным) или ложным. Это идентично вызову функции IF, ЕСЛИ с двумя или тремя аргументами.
Часть «ELSE», а также двоеточие («:») после ELSE являются необязательными. Если часть ELSE опущена, а тестовое выражение оценивается как false, результат не определен.
Если вы используете вложенные выражения IF только с одним ELSE, часть ELSE применяется к самому внутреннему IF. Мы рекомендуем использовать круглые скобки, чтобы было понятно, к какому ЕСЛИ он относится.
Вы можете использовать отступ, чтобы сделать формулу с вложенными ЕСЛИ более читабельной, но отступ не влияет на анализ формулы. Используйте скобки!
Примеры:
КОД
IF assignee = ME() : "mine!"
---
IF dueDate < NOW() : "overdue!" ELSE: """${DAYS_BETWEEN(NOW(), dueDate) - 1} days left!"""
---
IF priority = "Critical":
IF dueDate < DATE_ADD(TODAY(), 7, "days"):
"critical and urgent"
ELSE:
"critical and not urgent"
Доступ к свойствам
Некоторые значения Expr — элементы и карты «ключ-значение» — содержат «свойства», именованные значения, которые являются частями большего значения. Например, элемент «Версия» содержит такие свойства, как «имя», «описание», «дата выпуска». И функция GROUP возвращает значение, которое представляет собой массив карт значений ключа, каждая карта имеет свойства «группа» и «элементы».
Чтобы получить доступ к свойству, используйте точку ("."), за которой следует имя свойства. Имена нечувствительны к регистру.
Примеры:
- releaseDate
- startDate
- isSubtask
Альтернативным способом доступа к свойству является использование функции ACCESS() — таким образом можно вычислить само имя свойства:
- ACCESS("Story Points ")
(предупреждение) Если значение не имеет запрошенного свойства или если значение не является ни элементом, ни картой ключ-значение, результирующее значение не определено — это не ошибка! (См. также примечание о массивах ниже.) РИСУНОК warning.png (предупреждение)
Невозможно проверить, содержит ли значение определенное свойство (кроме как попытаться получить к нему доступ), или перечислить все доступные свойства для элемента.
Доступ к настраиваемым полям через свойства
В большинстве случаев формула будет ссылаться на настраиваемые поля задачи непосредственно по имени — например, формула Impact / StoryPoints использует значения двух настраиваемых полей, Impact и Story Points, вычисляемой в настоящее время проблемы для расчета отношения выгод к затратам. соотношение.
Однако вы можете использовать формулу для доступа к другим связанным задачам и соответствующим им настраиваемым полям — например, формула влияние / (storyPoints + subtasks.storyPoints.SUM()) вычисляет аналогичное значение, но учитывает стоимость ( в сюжетных очках) всех подзадач.
Обратите внимание, что фактическое настраиваемое поле называется «Story Points» с пробелом. Когда вы обращаетесь к свойству элемента задачи, Structure пытается сопоставить имя свойства с доступными именами настраиваемых полей, используя нечеткие правила, отбрасывая пробелы и любые неудобные для идентификации символы. Имя свойства также нечувствительно к регистру.
Вы также можете использовать функцию ACCESS(), чтобы точно указать имя поля, или использовать имя свойства «customfield_NNNNN», чтобы идентифицировать поле по его идентификатору.
- storyPoints
- ACCESS("Очки истории")
- parent.customfield_10000
Вы можете использовать эту переменную для доступа к свойствам текущего вычисляемого элемента. Обычно в этом нет необходимости, поскольку в качестве соответствующих переменных доступны те же значения.
Доступ к свойству каждого элемента в массиве
Вы можете применить доступ к свойствам к массиву значений. Затем Expr применит доступ к свойствам для каждого элемента и вернет результат в виде массива.
Например:
- releaseDate — вернет массив дат выпуска
- author.UNIQUE () — возвращает список людей, которые зарегистрировали работу
- remainingEstimate.SUM() — возвращает общую оставшуюся оценку подзадач.
В результирующем массиве все неопределенные результаты будут удалены, а массив сведен к минимуму. Это то же самое поведение, которое демонстрируют функции с типом параметра /Each.
Функции
Функция принимает ноль или более значений и возвращает другое значение. Вызов функции состоит из имени функции (идентификатора), за которым следуют ее аргументы, заключенные в круглые скобки. Аргументом может быть любое выражение. Разные аргументы разделяются запятыми (,) или точками с запятой (;) — для одного вызова функции все разделители должны быть одинаковыми.
РИСУНОК image2021-5-22_15-21-44.png
Примеры:
- NOW()
- ROUND(storyPoints / 10)
- FILTER(sprint, $.state = "active")
- MAKE_DATETIME(2017; 12; 31; 23; 59; 59)
- myUserFunction("argument1", "argument2")
Вызов функции может оценивать только некоторые аргументы или даже ни один из них, в зависимости от функции. Это полезно для функций, которые выполняют выбор. Например, в функции IF аргумент, который не был выбран, не оценивается, поэтому все выражение не создает ошибку, когда этот аргумент вызывает ошибку.
Системные и пользовательские функции
Системные функции предоставляются Structure. Функции перечислены в Expr Function Reference. Каждая функция ожидает определенное количество и тип параметров.
Функции пользователя объясняются в следующем разделе. Пользовательская функция вызывается с использованием того же синтаксиса, что и системная функция.
Пользовательские функции могут принимать любое количество аргументов, независимо от того, сколько аргументов объявлено. Если параметр был объявлен, но при вызове функции не было указано значение, значение параметра будет неопределенным.
Сцепленные вызовы функций
Другой способ вызвать функцию — «связать» ее с первым аргументом, добавив точку («.»), имя функции, круглые скобки и любые дополнительные параметры, если таковые имеются.
РИСУНОК image2021-5-22_16-49-44.png
Например, sprint.FILTER($.state = "active") совпадает с FILTER(sprint, $.state = "active").
Это позволяет создавать приятные, удобочитаемые выражения, в которых значение последовательно преобразуется путем применения функций к результату предыдущего вызова функции:
- MAP($.releaseDate - $.startDate).MAX()
- FILTER(x -> NOT x.resolution).MAP(x -> x.remainingEstimate).SUM()
В отличие от некоторых других языков, в Expr любая функция может быть записана с использованием цепного синтаксиса, независимо от значения.
Применение функций к массивам
Когда функция применяется к значению массива (это означает, что массив передается в качестве первого аргумента функции), результат может быть рассчитан несколькими способами, в зависимости от того, какая функция вызывается и какой тип аргумента она ожидает.
ü
Вы всегда можете применить функцию к каждому элементу массива, используя функцию MAP. Например:
array.MAP(SOME_FUNCTION($))
Приведенные ниже случаи относятся к случаям, когда массив передается непосредственно в качестве аргумента: SOME_FUNCTION(массив).
ü
Использование функции массива
Существуют специальные функции, которые ожидают массив в качестве первого аргумента — FILTER, MAP и другие.
Особого поведения в этом случае нет — ожидается массив. На самом деле, если переданное значение не является массивом, оно будет преобразовано либо в массив из одного элемента (содержащего это значение), либо в пустой массив, если значение не определено.
Передача массива в качестве аргумента типа Text/Joined
Если функция объявляет, что она ожидает Text/Joined в качестве аргумента, то система попытается преобразовать массив в текстовое значение. См. раздел "Text vs Text/Joined" выше.
Например:
- CONCAT("Versions: ", fixVersion) → "Versions: v1, v2, v3"
Передача массива в качестве аргумента типа /каждый
Если функция объявляет, что она ожидает "Число/Каждый" или "Текст/Каждый" или любой другой тип "/Каждый" в качестве аргумента, то она будет работать с этим простым типом, но если передан массив, она применит его логика для каждого элемента в этом массиве. Результатом вызова этой функции будет массив, каждый элемент которого является результатом применения функции к исходному элементу.
Например:
- UPPER(fixVersion) → ARRAY("V1", "V2", "V3")
Кроме того, при применении функции к массиву таким образом результирующий массив «сглаживается» (элементы любых подмассивов перемещаются в элементы верхнего массива) и «уплотняется» (все неопределенные элементы удаляются).
Передача массива в пользовательскую функцию
Вы можете вызвать пользовательскую функцию и передать массив в качестве аргумента. Никакой специальной обработки не происходит — как и в случае с системной функцией, ожидающей массив.
Все остальные случаи
Если системная функция не ожидает массив, но он передается в качестве аргумента, она попытается преобразовать его в ожидаемый тип значения. Одноэлементный массив будет преобразован в его единственный элемент, а пустой массив будет преобразован в неопределенный. См. «Преобразование значений» выше.
Если преобразование невозможно, результатом будет ошибка.
Пользовательские функции
Пользовательские функции — это функциональные выражения, определяемые пользователем. (Их также можно было бы назвать «лямбда-выражениями».) Пользовательские функции полезны, когда пользователю нужно применить какое-то повторяющееся действие или передать действие, которое будет применено к каждому элементу в массиве.
Пользовательская функция содержит список параметров, а затем выражение, вычисляемое для этих параметров.
Пользовательская функция — это тип значения, поэтому вы можете назначить пользовательскую функцию локальной переменной или передать ее какой-либо функции более высокого порядка в качестве параметра.
Существует три способа определения пользовательской функции.
Функциональное выражение
Функциональное выражение — это каноническая форма пользовательских функций. Он содержит список параметров в круглых скобках, за которым следует символ «сопоставляется с» (->), за которым следует выражение, вычисляемое функцией. При наличии только одного параметра круглые скобки можно опустить.
Примеры:
- () -> START_OF_MONTH(NOW())
- (x) -> x * x
- version -> version.releaseDate - version.startDate
- (s1, s2) -> s1 CONCAT " " CONCAT s2
Во всех этих примерах оценивается тип значения «Функция пользователя», который может быть присвоен переменной:
- WITH square = x -> x * x : ...
Традиционное определение функции
Более традиционное определение функции похоже на определение переменной, только за переменной следует список параметров в круглых скобках, и выражение основано на этих параметрах.
Чтобы переписать приведенные выше примеры:
- WITH currentMonth() = START_OF_MONTH(NOW()) : ...
- WITH square(x) = x * x : ...
- WITH versionDuration(version) = version.releaseDate - version.startDate : ...
- WITH joined(s1, s2) = s1 CONCAT " " CONCAT s2 : ...
Эти объявления идентичны соответствующим примерам в предыдущем разделе с локальными переменными, назначенными соответствующим значениям функций пользователя.
Неявное функциональное выражение ($)
В большинстве случаев, когда мы создаем формулу с массивом, нам нужно применить какую-то операцию к каждому элементу массива. Неявные функциональные выражения помогают легко определить соответствующую пользовательскую функцию, поскольку «$» обозначает «каждый элемент».
Например:
- FILTER($.startDate < NOW())
- FILTER($.type = "Relates").MAP($.destination)
- UMAX_BY(IF $.author = ME() : $.timeSpent)
В каждом случае выражение с «$» преобразуется в пользовательскую функцию с одним параметром, который затем заменяется на $. Итак, последний пример из списка выше идентичен:
- UMAX_BY(w -> IF w.author = ME() : w.timeSpent)
Читая эти выражения, вы можете сказать «каждый», когда встречается знак доллара.
Неявная пользовательская функция всегда должна использоваться в аргументе системной функции, которая ожидает пользовательскую функцию. В противном случае он не будет принят.
Например, вот как мы можем отфильтровать массив, чтобы он содержал только четные числа:
Правильно |
Ошибка неправильного синтаксического анализа |
ARRAY(1, 2, 3).FILTER(MOD($, 2) = 0) ... илииначе ... WITH even(e) = MOD(e, 2) = 0 : ARRAY(1, 2, 3).FILTER(even) |
WITH even = MOD($, 2) = 0 : ARRAY(1, 2, 3).FILTER(even) |
Вызов пользовательских функций
Если пользовательская функция назначена переменной, вы можете вызвать ее в своем выражении так же, как вы вызываете системную функцию.
- WITH square(x) = x * x :
square(impact) / square(cost)
Вы также можете использовать нотацию вызова связанной функции:
- WITH square(x) = x * x :
WITH fquare(x) = x.square().square() :
storyPoints.fquare()
Обратите внимание, что вы не можете вызывать функциональное выражение, если оно не назначено локальной переменной. Следующее вызовет ошибку: (x -> x * x)(3)
Конфликты имен функций
Как системные, так и пользовательские функции вызываются одинаковым образом – ИМЯ_ФУНКЦИИ(arg1, arg2, arg3, ...) или с помощью синтаксиса цепного вызова – arg1.ИМЯ_ФУНКЦИИ(arg2, arg3, ...). Это оставляет пользователю возможность определить функцию с тем же именем, что и у системной функции.
РИСУНОК warning.png (предупреждение) Когда Expr встречает вызов функции, сначала он ищет, существует ли системная функция с таким именем. (предупреждение)
Системная функция будет вызываться, даже если есть локальная переменная с таким же именем. Чтобы защитить пользователя от конфликтов имен, Expr покажет ошибку, если вы попытаетесь определить функцию с именем, совпадающим с именем системной функции. (Однако он не сможет обнаружить коллизию, если локальная переменная определена через серию присваиваний функционального выражения.)
Вы можете определить локальную переменную любого другого типа с именем, идентичным имени системной функции.
Работает как ожидается |
Ошибка |
|
|
Обратите внимание, что разрешение конфликтов имен функций создает потенциальные проблемы при обновлении до более новой версии Structure, если в этой версии представлены новые системные функции.
Предположим, вы определили пользовательскую функцию LAST_COMMENT() в своей формуле и успешно использовали ее в более старой версии Structure. Если в новую версию Structure добавлена системная функция LAST_COMMENT(), эта формула, скорее всего, перестанет работать после обновления, и вам нужно будет переименовать пользовательскую функцию.
Чтобы свести к минимуму вероятность этого, мы предлагаем назвать вашу пользовательскую функцию таким образом, чтобы сделать потенциальную коллизию маловероятной. Это может быть имя, очень специфичное для вашей конфигурации, или вы всегда можете добавить к имени символ подчеркивания — в нашем примере назовите его _LAST_COMMENT().
Агрегатные функции
Агрегатная функция вычисляет значения для некоторых других строк в структуре (например, для всех подэлементов), агрегирует эти значения (например, складывает их вместе) и создает результирующее значение для использования в формуле.
Например:
- SUM#children { storyPoints } — подсчитывает общее количество баллов за все дочерние выпуски.
- PARENT { fixVersion } — предоставляет значение поля fixVersion из родительской задачи.
- VALUES {components} — собирает все отдельные компоненты, установленные для любой из подпроблем текущей строки.
Агрегатные функции позволяют вычислять сложные значения, зависящие не только от «текущего» элемента, но и от других элементов, связанных с ним.
Агрегатная функция начинается с имени, за которым могут следовать модификаторы, затем фигурные скобки ("{}"), а внутри них — "внутреннее выражение", которое будет вычислено для некоторых других строк. Вы можете использовать пробелы между любыми элементами вызовов агрегатных функций.
Внутреннее выражение может возвращать любой тип значения — число, текст, массив и другие — кроме пользовательской функции. Вы не можете передать пользовательскую функцию из внутренней формулы во внешнюю формулу.
Доступные агрегатные функции перечислены в Справочнике по агрегатным функциям.
Модификаторы агрегатных функций
Агрегатная функция может иметь один или несколько модификаторов, управляющих аспектами выполнения функции. Каждый модификатор начинается со знака решетки ("#"); затем идет имя модификатора; необязательно, за которым следует знак равенства ("=") и значение, которое может быть строкой или числовой константой. Если значение опущено, предполагается, что оно равно 1 (представление true в Expr).
Примеры:
- SUM#all { cost }
- SUM#all#leaves { IF type = "story": storyPoints }
- JOIN#separator=", " { key }
- JOIN #separator=", " #fromDepth=0 #toDepth=-1 { key }
Каждая агрегатная функция поддерживает определенный набор модификаторов, а не все. Использование несовместимого модификатора приведет к ошибке. Чтобы узнать больше о доступных модификаторах и их ограничениях, см. Модификаторы агрегации.
Разделение значений между внешними и внутренними формулами
Важно понимать, что формула внутри агрегатной функции — внутренняя формула — рассчитывается полностью отдельно от «внешней» формулы. Обе формулы будут иметь общие сопоставления переменных (с атрибутами), но любые локальные переменные и пользовательские функции, определенные на одной стороне, будут недоступны на другой стороне.
Не будет работать |
Правильная версия |
|
|
Как видно из приведенного выше примера, вместо этого вам может понадобиться использовать вложенные агрегатные функции.
Использование формул с агрегатными функциями в генераторах и преобразованиях
Обратите внимание, что когда вы используете агрегатную функцию, она опирается на существующую структуру для определения родительского элемента, дочерних элементов и других связанных элементов, к которым обращается формула. Когда формула используется для построения или преобразования структуры, иерархия и элементы, которые «видят» агрегатные функции, будут соответствовать структуре, существующей непосредственно перед применением генератора или преобразования.
Поэтому при использовании формулы с фильтром атрибутов, группировщиком атрибутов, сортировщиком атрибутов и другими генераторами следует осторожно применять агрегатные функции, понимая, что представляет собой предшествующая структура, до применения генератора. Например, если вы используете группировщик для папки с плоским списком задач, формула в группировщике увидит задачи, а папка будет их родительским элементом — групп еще нет!
Встроенные запросы
Вы можете встроить JQL и S-JQL в формулу, чтобы проверить, удовлетворяет ли элемент (тот, для которого рассчитывается формула) условию запроса, то есть он будет частью результата запроса.
Синтаксис аналогичен вызову агрегатной функции:
- IF JQL { assignee in membersOf("Team-Alpha") } : ...
- IF NOT SJQL { descendant of folder("Excluded") } : ...
Результат оценки JQL {} или SJQL {} всегда равен 0 (ложь) или 1 (истина).
Когда используется SJQL, он всегда применяется к текущей структуре. (Или тот, который создается — см. примечание ниже.)
Обратите внимание, что, в отличие от агрегатных функций, эти конструкции используют не Expr, а другие языки в качестве внутреннего выражения. Используйте соответствующую документацию в качестве справочной информации для JQL и S-JQL.
Встроенные запросы рассчитываются отдельно от формулы Expr, в которой они используются. Поэтому вы не можете использовать какие-либо значения из формулы Expr внутри запроса JQL или SJQL или наоборот. Кроме того, вы не можете проверить соответствие запросу для любого другого элемента, кроме того, для которого рассчитывается формула.
Другими словами, между встроенным запросом и внешней формулой Expr передаются только данные 1 или 0 в зависимости от того, соответствует ли текущий элемент запросу.
Использование S-JQL в генераторах и преобразованиях
Запрос S-JQL обычно зависит от структуры, для которой он рассчитывается. Таким образом, аналогично агрегатным функциям, когда вы используете формулу со встроенным S-JQL в генераторе или преобразовании, запрос будет применяться к базовой «предшествующей» структуре, которая существует до применения генератора.
Производительность запросов S-JQL
Структура оптимизирует вызовы встроенных запросов. Запрос будет выполняться только один раз для нескольких элементов, для которых рассчитывается формула, и результат будет проверяться отдельно при расчетах для каждой строки.
Тем не менее, сам JQL потенциально может быть интенсивным вычислением, если он использует функции JQL или исторические условия, такие как WAS. Пожалуйста, будьте осторожны при использовании этого JQL в формуле и следите за тем, как долго вычисляется значение, прежде чем публиковать формулу для других пользователей. Обычно вычисление «тяжелой» формулы не должно мешать пользователям выполнять другие действия в Structure (в том числе использовать другие столбцы с формулами), но может вызвать некоторую нагрузку на сервер Jira.
Пожалуйста, избегайте использования функции JQL Structure() в JQL или S-JQL, которая встраивается в формулу.
По материалам Atlassian JIRA Structure: Expr Advanced Reference