Язык формул Creatium спроектирован таким образом, чтобы его можно было быстро освоить и начать использовать за максимально короткий период времени, при этом он дает большие возможности для работы с данными, которые никак иначе не доступны.
В этой статье мы разберем основы формул.
Целые числа: 123
, -34
, 0
и т.д.
Дробные числа: 10.22
, 0.01
и т.д.
Поддерживается математическая запись для очень больших и очень маленьких чисел:
1.602176565e-19
, 6.02214129e+23
и т.д.
Особые значения чисел: Infinity
(бесконечность) и NaN
(”Not a Number”, может возникать в тригонометрических функциях).
Заключаются в одинарные ('
) или в двойные кавычки ("
). Разного рода типографские кавычки (вроде ‘
, ’
, ‟
, ”
, и т.д.) не принимаются.
Примеры: "Hello!"
, "123"
, 'Test'
и т.д.
Если внутри строки встречается такая же кавычка, как та, что используется для формирования строки, перед ней нужно поставить знак \
.
Пример: "Это просто \"чудо\" какое-то"
. Или заключить строку в кавычки другого типа, чтобы не было конфликта кавычек одного типа: 'Это просто "чудо" какое-то'
.
Или true
или false
, всего 2 возможных значения. Обычно true
означает нечто положительное, а false
— нечто отрицательное. Да/нет, включено/выключено, в наличии/отсутвует и так далее.
Массив или список — это набор значений, разделенных запятыми, заключенный в квадратные скобки: [1, 2, 3]
, ["a", "b", "c"]
и т.д.
Массив может содержать значения разных типов: [1, "b", false]
, включая вложенные массивы: [1, [12, 13], ["a", "b"]]
.
Объект — это набор пар ключ-значение, разделенных запятыми, заключенный в фигурные скобки. Значение может быть любого типа, а ключем может быть только строка. Между ключем и значением всегда ставится двоеточие: {"x": 12, "y": 44}
, {"type": "house", "price": 1200}
и т.д.
Если в названии ключа используются только латинские буквы, цифры (но не в самом начале) и символ _
, то ключ можно не заключать в скобки: {name: "Hohn", age: 34}
.
Как и массивы, объекты могут содержать другие вложенные объекты. Ключи в объекте не должны повторяться, но если такое случается, то “верным” значением считается последнее. То есть в объекте {x: 1, x: 2}
значением ключа x
будет 2
.
Даты записываются между двумя знаками #
, в формате “год-месяц-день”: #2022-04-22#
, #1994-05-04#
и т.д. Ведущий ноль обязателен, то есть #1994-5-4#
это уже неправильный формат.
Дата может включать так же и время:
#2022-04-22 14:05#
#2022-04-22 14:05:15#
(с секундами)
#2022-04-22 14:05:15.245#
(с миллисекундами)
Если не указано иное, то по умолчанию используется время по Гринвичу. Можно дополнительно указать и часовой пояс:
#2022-04-22 14:30 +05#
(Нью-Йорк)
#2022-04-22 14:30 -03#
(Москва)
Можно указать часовой пояс, опустив время:
#2022-04-22 -03#
(00:00 по Москве)
#2022-04#
(только год и месяц, то же что #2022-04-01 00:00#
)
#2022-07-02T15:22:35.313Z#
(формат ISO 8601)
#2022-04-22 14:30:15 -09:30#
(часовой пояс с минутами)
Означает отсутствующее значение. Единственным возможным значением этого типа данных является null
.
Переменные обеспечивают доступ к значениям, которые могут меняться. Переменная может содержать значение любого типа — число, объект, массив, дату и т.д.
Название переменной может содержать латинские буквы, цифры и знак “_”, но не может начинаться с цифры. Несколько примеров названий переменных: member_id
, url
, test123
.
Есть возможность объявлять переменные для использования внутри формулы.
text = 'Это текст, который обрезается по длине';
length = 20;
if(
length(text) > length,
substr(text, 0, length) & '…',
text
)
В значениях переменных так же можно использовать формулы. Общий синтаксис такой:
название_переменной = формула;
название_переменной2 = формула;
...
формула
Если в переменной хранится массив, доступ к элементам осуществляется следующим образом: array[0]
, где 0
это номер элемента.
Обратите внимание, что нумерация начинается с 0! Первый элемент, это элемент под номером 0, второй элемент под номером 1 и так далее.
Допустим, у нас есть переменная prices
, содержащая массив [25, 33, 11]
. Получить второе значение массива можно следующим образом: prices[1]
.
Так же есть удобный способ получения последнего элемента: prices[-1]
, то есть при использовании отрицательного номера, элементы считаются с конца.
Похожим образом осуществляется и доступ к значениям объекта, только вместо номера в квадратных скобках мы передаем строку: object["a"]
, где "a"
это ключ.
Допустим, у нас есть переменная man
, которая содержит объект { "firts name": "John", "age": 34 }
. Получить значение “first name” этого объекта можно следующим образом: man["first name"]
.
А так получаем значение “age”: man["age"]
. Если ключ содержит только латинские буквы, цифры и символ “_”, то синтаксис можно упростить: man.age
.
В код формулы можно вставлять комментарии двумя способами.
Первый — конструкция /* комментарий */
, которая может быть многострочной, а может занимать только часть строки.
Пример:
myDate + /* сутки */ 86400000
Часть кода /* сутки */
будет проигнорирована при выполнении формулы.
Второй — кострукция // комментарий
, которая превращает в комментарий всю оставшуюся часть строки, и которую удобно использовать при перечислении элементов массива или значений объектов.
Пример:
sum([
10,
20,
// 30,
40,
])
В данном случае мы “закомментировали” третий элемент массива, и он не будет учитываться при сложении.
Оператор — это простейшая конструкция языка.
+
, -
2 + 2
⇒ 4
6 - 3
⇒ 3
Порядок операций важен, но можно использовать скобки:
5 - 2 + 5
⇒ 8
5 - (2 + 5)
⇒ -2
Оператор сложения нельзя использовать со строками. Для этого есть специальный оператор объединения строк (&
).
Оба оператора умеют работать с датой. В этом случае они прибавляют или вычитают миллисекунды.
#2012-04-21 14:12:00# + 5
⇒ #2012-04-21 14:12:00.005#
В сутках 86400000 миллисекунд (1000 миллисекнуд * 60 секунд * 60 минут * 24 часа), так можно прибавлять или вычитать дни:
#2012-04-21 14:12:00# + 86400000
⇒ #2012-04-22 14:12:00#
#2012-04-21 14:12:00# - 86400000
⇒ #2012-04-20 14:12:00#
*
, /
25 * 4
⇒ 100
10 / 5
⇒ 2
Приоритет умножения и деления выше, чем у сложения, то есть умножение всегда выполняется первым.
2 + 2 * 2
⇒ 6
2 * 2 + 2
⇒ 6
Но тут тоже можно использовать скобки:
(2 + 2) * 2
⇒ 8
==
, !=
, >
, >=
, <
, <=
Оператор “равно”: ==
10 == 20
⇒ true
"10" == 20
⇒ false
[1, 2, 3] == [1, 2, 3]
⇒ true
[1, 2, 3] == [1, 3, 2]
⇒ false
Оператор “не равно”: !=
2 != 4
⇒ true
"4" != 4
⇒ true
true != true
⇒ false
Оператор “больше”: >
56 > 12
⇒ true
"b" > "a"
⇒ trueОператор “больше или равно”: >=
Работает как оператор “больше”, но допускает так же равенство.
Оператор “меньше”: <
45 < 111
⇒ true
"e" < "z"
⇒ true
Оператор “меньше или равно”: <=
Работает как оператор “меньше”, но допускает так же равенство.
%
10 % 3
⇒ 1
5 % 7
⇒ 5
7 % 5
⇒ 2
&
"abc" & "def"
⇒ "abcdef"
24 & 55
⇒ "2455"
and
Возвращает true
если И левое И правое выражение равняются true
.
15 > 10 and 15 < 20
⇒ true
125 > 10 and 125 < 20
⇒ false
or
Возвращает true
если левое ИЛИ правое выражение равняются true
.
15 > 10 or 15 < 20
⇒ true
125 > 10 or 125 < 20
⇒ true
??
Позволяет указать значение, которое будет использована, если переменная, элемент массива или свойство объекта равно null
.
null ?? "default"
⇒ "default"
123 ?? "default"
⇒ 123
Этот оператор удобно использовать при обращении к элементам массивов или значениям объектов, которых может не существовать.
array[1] ?? "something"
⇒ "something"
, если array[1]
не существует, или равен null
object.key ?? "something"
⇒ "something"
, если object.key
не существует, или равен null
?
Является сокращенной версией оператора ??
, в котором значением по умолчанию является null
.
in
2 in [1, 2, 3]
⇒ true
22 in [1, 2, 3]
⇒ false
Есть 2 способа вызвать функцию для работы со значением.
Первый — передать значение в качестве первого аргумента функции:
locate('Hello, world!', 'Hello')
Второй — выполнить функцию над значением через точку:
'Hello, world!'.locate('Hello')
Оба способа эквивалентны.
sum([1, 2, 3]) == 6
multiply([2, 3, 4]) == 24
abs(12) == 12
abs(-44) == 44
round(12.46) == 12
round(12.46, 1) == 12.5
round(12.462, 2) == 12.46
round(12.46, -1) == 10
round(123456, -3) == 123000
Используется округление 0.5 до ближайшего четного числа.
round(12.5) == 12
round(13.5) == 14
round(14.5) == 14
round(15.5) == 16
trunc(12.46) == 12
trunc(12.46, 1) == 12.4
trunc(12.462, 2) == 12.46
trunc(12.46, -1) == 10
trunc(123456, -3) == 123000
floor(12.7) == 12
floor(-12.7) == -13
ceil(12.3) == 13
ceil(-12.3) == -12
Возвращает дробные числа в диапазоне от 0 до 1:
random() == 0.2850926978256794
random() == 0.7654290091085383
Это дробное число можно преобразовать в целое число в рамках заданного диапазона.
Целое число в диапазоне от 0 до 10 (включая 0 и 10):
round(random() * 10) == 7
round(random() * 10) == 3
round(random() * 10) == 10
round(random() * 10) == 5
Целое число в диапазоне от 10 до 20:
10 + round(random() * (20 - 10)) == 12
10 + round(random() * (20 - 10)) == 10
10 + round(random() * (20 - 10)) == 17
10 + round(random() * (20 - 10)) == 18
min([6, 2, 3]) == 2
min([0, -44, -2]) == -44
Функция умеет работать с любыми типами, а не только с числами.
min(["b", "e", "a"]) == "a"
min([#2012-05-22#, #2012-05-21#]) == #2012-05-22#
max([3, 6, 2]) == 6
max([-3, 0, -2]) == 0
Функция умеет работать с любыми типами, а не только с числами.
max(["b", "e", "a"]) == "e"
max([#2012-05-22#, #2012-05-25#]) == #2012-05-25#
pow(2, 2) == 4
pow(2, 3) == 8
pow(3, 2) == 9
pow(3, 3) == 27
sqrt(4) == 2
sqrt(25) == 25
Логарифм это показатель степени, в которую надо возвести число, называемое основанием, чтобы получить данное число.
log(100, 10) == 2
log(16, 2) == 4
Где e
— число Эйлера, основание натурального логарифма.
Тригонометрия: acos, acosh, asin, asinh, atan2, atan, atanh, cos, cosh, sin, sinh, tan, tanh
length('') == 0
length('abcd') == 4
locate('Hello, world!', 'Hello') == 0
locate('Hello, world!', 'world') == 7
Аргумент start позволяет указать позицию, откуда начинать поиск.
locate('Hello, world!', 'o') == 4
locate('Hello, world!', 'o', 5) == 8
Если подстрока не найдена, результатом будет -1.
locate('Hello, world!', 'something') == -1
substr('Hello, world!', 7) == 'world!'
Аргумент count позволяет ограничить количество символов подстроки.
substr('Hello, world!', 7, 3) == 'wor'
join(['a', 'b']) == 'ab'
join(['a', 123, null, false]) == 'a123false'
Аргумент $$delimiter
используется в качестве разделителя:
join(['a', 'b', 'c'], ':') == 'a:b:c'
join([1, 2, 3, 4], ' + ') == '1 + 2 + 3 + 4'
trim(' test ') == 'test'
trimStart(' test ') == 'test '
trimEnd(' test ') == ' test'
split('1, 2, 3', ', ') == ['1', '2', '3']
split('Some words', ' ') == ['Some', 'words']
replace('Hello, world!', 'world', 'test') == 'Hello, test!'
replace('one, one', 'one', 'two') == 'two, one'
replaceAll('Hello, world!', 'o', 'O') == 'HellO, wOrld!'
replaceAll('one, one', 'one', 'two') == 'two, two'
lower('Hello, World!') == 'hello, world!'
upper('Hello, World!') == 'HELLO, WORLD!'
count([1, 2, 3]) == 3
range(0, 5) == [0, 1, 2, 3, 4]
range(0, 5, 2) == [0, 2, 4]
range(0, -20, -5) == [0, -5, -10, -15]
Внутри expression доступна переменная item со значением элемента массива.
map([1, 2, 3], item * 2) == [2, 4, 6]
merge([2, 4], [6, 8]) == [2, 4, 6, 8]
Внутри expression доступна переменная item со значением элементов массива.
Так же доступна переменная value, которая аккумулирует результирующее значение.
reduce(['a', 'b', 'c'], value & '-' & item, '') == 'a-b-c'
reverse([1, 2, 3]) == [3, 2, 1]
Внутри expression доступна переменная item со значением элемента массива.
filter([-5, 3, -22, 34], item > 0) == [3, 34]
sort([4, 6, -3, 22]) == [-3, 4, 6, 22]
С помощью аргумента expression можно задать критерий, по которому осуществляется сортировка. Внутри доступна переменная item со значением элемента массива.
sort(
[{x: 5, y: 10}, {x: 10, y: 5}],
item.y
) == [{x: 10, y: 5}, {x: 5, y: 10}]
slice([1, 2, 3, 4], 1) == [2, 3, 4]
slice([1, 2, 3, 4], 3) == [4]
slice([1, 2, 3, 4], 1, 1) == [2]
slice([1, 2, 3, 4], 1, 2) == [2, 3]
Отрицательный count позволяет делать срез с конца массива.
slice([1, 2, 3, 4], -1) == [4]
slice([1, 2, 3, 4], -3) == [2, 3, 4]
slice([1, 2, 3, 4], -3, 1) == [2]
slice([1, 2, 3, 4], -3, 2) == [2, 3]
unique([1, 2, 1, 3]) == [1, 2, 3]
indexOf([1, 2, 3], 2) == 1
indexOf([1, 2, 3], 20) == -1
Массив должен содержать объекты, содержащие значения “k” (ключ) и “v” (значение):
arrayToObject([
{ "k": "item", "v": "abc123" },
{ "k": "qty", "v": 25 }
]) == {
"item": "abc123",
"qty": 25
}
Ключ (”k”) обязательно должен быть строкой.
Так же вместо набора объектов можно передать набор массивов из двух значений:
arrayToObject([
[ "item", "abc123" ],
[ "qty", 25 ]
]) == {
"item": "abc123",
"qty": 25
}
objectToArray({
"item": "abc123",
"qty": 25
}) == [
{ "k": "item", "v": "abc123" },
{ "k": "qty", "v": 25 }
]
now() == Date(2022-06-24T14:47:33.000Z)
Допустимые единицы: year, quarter, month, week, day, hour, minute, second, millisecond
dateAdd(now(), "year", 1) // Прибавить 1 год
dateAdd(now(), "quarter", 1) // Прибавить 1 квартал (3 месяца)
dateAdd(now(), "month", 1) // Прибавить 1 месяц
dateAdd(now(), "week", 1) // Прибавить 1 неделю (7 дней)
dateAdd(now(), "day", 1) // Прибавить 1 день
dateAdd(now(), "hour", 1) // Прибавить 1 час
dateAdd(now(), "minute", 1) // Прибавить 1 минуту
dateAdd(now(), "second", 1) // Прибавить 1 секунду
dateAdd(now(), "millisecond", 1) // Прибавить 1 миллисекунду
Месяцем считается период времени до того же числа (и времени) следующего месяца. Если мы к 31 числу прибавляем месяц, а в следующем месяце отсутствует 31 число, то результатом будет 30 число, то есть последний день месяца.
Примеры:
dateAdd(#2022-01-15 14:05#, "month", 1) == #2022-02-15 14:05#
dateAdd(#2022-08-31 14:05#, "month", 1) == #2022-09-30 14:05#
dateAdd(#2022-01-30 14:05#, "month", 1) == #2022-02-28 14:05#
dateAdd(#2022-01-31 14:05#, "month", 1) == #2022-02-28 14:05#
Все то же самое, что в addDate, только в вычитании.
См. также toDate
if(12 > 4, 'more', 'less') == 'more'
if(12 > 54, 'more', 'less') == 'less'
Поддерживаются множественные условия.
if(condition, then, condition2, then2, …, else)
if(
price < 100000, "До 100 000 р/мес",
price < 200000, "От 100 000 до 200 000 р/мес",
"От 200 000 р/мес"
)
not(true) == false
not(false) == true
let({
var1: 2 + 2 * 2,
}, var1 + var1) == 16
type(123) == 'number'
type('hello') == 'string'
type(true) == 'boolean'
type(#2012-12-23#) == 'date'
type([11, 22]) == 'array'
type({ x: 1, y: 2 }) == 'object'
type(null) == 'null'
toBoolean(0) == false
toBoolean(1) == true
toBoolean(22) == true
toBoolean('') == false
toBoolean('abc') == true
toBoolean(null) == false
Любые массивы, объекты и даты приводятся к true.
toBoolean([]) == true
toBoolean([0]) == true
toBoolean(now()) == true
toBoolean({}) == true
toBoolean({ "x": 0 }) == true
toNumber('0') == 0
toNumber('123') == 123
toNumber('123.4') == 123.4
toNumber(null) == 0
Если передать в функцию дату, результатом будет метка времени (количество миллисекунд с 1 января 1970 года).
toNumber(now()) == 1656083246000
Массивы и объекты к числу не приводятся, возвращают ошибку.
toString(1) == '1'
toString(123.4) == '123.4'
toString(null) == ''
Если передать в функцию дату, результатом будет метка времени в формате ISO 8601.
toString(now()) == '2022-06-24T15:11:17.000Z'
Массивы и объекты к строке не приводятся, возвращают ошибку.
toDate(0) == Date(1970-01-01T00:00:00.000Z)
toDate(1656083935000) == Date(2022-06-24T15:18:55.000Z)
toDate(null) == null
Функция понимает разные варианты формата даты ISO 8601:
toDate('2022-06-24T15:18:55.000Z') == Date(2022-06-24T15:18:55.000Z)
toDate('2022-06-24 15:18') == Date(2022-06-24T15:18:00.000Z)
toDate('2022-06-24') == Date(2022-06-24T00:00:00.000Z)
toDate('2022-06') == Date(2022-06-01T00:00:00.000Z)
toDate('2022-06-24T15:18+02:00') == Date(2022-06-24T13:18:00.000Z)
toDate('2022-06-24 15:18 +02:00') == Date(2022-06-24T13:18:00.000Z)
Массивы и объекты к дате не приводятся, возвращают ошибку.
Проверяет существование переменных, значений объектов и массивов.
exists(a)
exists(a.b)
exists(a[2])