A1sCode библиотека 1С

Справочник A1sCode

Зачем: быстрые паттерны на базе A1sQ (запросы) и A1sS (строки/шаблоны/вывод). Клик по коду — копирование.

Обзор модулей

  • A1sQ — короткие вызовы для Запроса (шаблоны, параметры, извлечение значений).
  • A1sS — строки/форматирование/шаблоны/вывод (AsString, Join, шаблон‑builder, Print*).

A1sQ: самое нужное

TL;DR: ValueQ() — вместо «QT → ExecuteQ → FirstRow».

// Получить одно значение по параметру
Значение = A1sQ.ValueQ(
    "ПЕРВЫЕ 1 Ссылка, Наименование ИЗ Справочник.Пользователи ГДЕ ИдентификаторПользователяИБ = &UID",
    Новый Структура("UID", ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор),
    "Наименование"); // ключ поля (или 1-й столбец, если не указан)
      

// Массив значений (1 столбец)
Список = A1sQ.ValuesQ(
    "ВЫБРАТЬ Наименование ИЗ Справочник.Номенклатура ГДЕ ПометкаУдаления = &F",
    Новый Структура("F", Ложь));
      

// ТаблицаЗначений целиком
Таб = A1sQ.Unload( A1sQ.ExecuteQ( A1sQ.QT("ВЫБРАТЬ ПЕРВЫЕ 50 Ссылка, Наименование ИЗ Справочник.Номенклатура ПОРЯДОК ПО Наименование") ) );
      

A1sS: строки и формат


// Универсальное приведение к строке с масками
Опции = Новый Структура("NumberFormat,DateFormat", "ЧГ=0; ЧД=2; N=,; T= ", "ДФ=dd.MM.yyyy");
Текст = A1sS.AsString(12345.6, Опции);        // "12 345,60" (пример)
Текст = A1sS.ToAnyReadable(МассивЗначений);   // "[...]" удобное представление
      

// Join / Replace / Wrap / Normalize
Список = Новый Массив; Список.Добавить("R"); Список.Добавить("G"); Список.Добавить("B");
A1sS.Join(Список, ", ");                       // "R, G, B"
A1sS.ReplaceText("контракт, контрактор", "контракт", "договор", Новый Структура("WholeWord", Истина));
A1sS.Wrap("текст", "[", "]");                  // "[текст]"
A1sS.NormalizeWhitespace("  Привет   мир  ");  // "Привет мир"
      

A1sS: шаблоны


// Быстрый текст с подстановкой {{Ключ}}
Парам = Новый Структура("Имя,Баланс", "Иван", 123.45);
A1sS.AddTextToTemplate("Клиент: {{Имя}}, баланс: {{Баланс}} ₽", Парам);
      

// Builder-подход
B = A1sS.CreateTemplateBuilder();
A1sS.AddTextToTemplate("Заголовок", Неопределено, "— ", " —");
A1sS.AddTextToTemplate("Список: {{Список}}", Новый Структура("Список", A1sS.Join(Список, ", ")));
Результат = B.ToString(); // или A1sS.GetTemplate()
      

// Полная обработка шаблона
Tpl = "Товар: {{Имя}} ({{Цена}} ₽)";
A1sS.ProcessTemplate(Tpl, Новый Структура("Имя,Цена", "Яблоко", 10));
      

Вывод / печать / сериализация


A1sS.Print("Старт процедуры");
A1sS.PrintYN(Проверка());              // Да/Нет
A1sS.PrintJSON(МояСтруктура);          // Красиво отформатированный JSON
A1sS.PrintXML(МойОбъект);              // XML‑вывод
      

Проверки и утилиты


Если A1sS.IsValidURL("https://a1scode.ru") Тогда
    // ...
КонецЕсли;

Если A1sS.HasText(Стр) Тогда
    // не пустая/не пробельная строка
КонецЕсли;
      

Ошибки и «дымовая» проверка


Процедура SmokeTestA1s() Экспорт
    Попытка
        Assert = Новый Массив;
        Assert.Добавить(A1sS.Join(Новый Массив, ", ") = "");
        Assert.Добавить(A1sS.IsValidURL("https://example.com"));
        Для Каждого Ок Из Assert Цикл
            Если Ок = Ложь Тогда ВызватьИсключение "Smoke failed"; КонецЕсли;
        КонецЦикла;
        A1sS.Print("Smoke OK");
    Исключение
        A1sS.Print("Smoke FAIL: " + ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры
      

Расширенные примеры

A1sQ: временные таблицы


ТекстЗапроса =
"ВЫБРАТЬ
|   Ном.Ссылка КАК Товар,
|   Сумма(Обороты.Количество) КАК Количество
|ПОМЕСТИТЬ ВТОбороты
|ИЗ РегистрНакопления.ОстаткиТоваров.Обороты(&ДатаНач, &ДатаКон, , ) КАК Обороты
|    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Ном
|    ПО Обороты.Номенклатура = Ном.Ссылка
|СГРУППИРОВАТЬ ПО
|   Ном.Ссылка;
|
|ВЫБРАТЬ ПЕРВЫЕ 20
|   Товар,
|   Количество
|ИЗ ВТОбороты
|ГДЕ Количество > 0
|УПОРЯДОЧИТЬ ПО Количество УБЫВ";
Таб = A1sQ.Unload( A1sQ.ExecuteQ( A1sQ.QT(ТекстЗапроса), Новый Структура("ДатаНач,ДатаКон", НачалоДня(Нач), КонецДня(Кон)) ) );

A1sQ: параметры дат и диапазоны


Текст =
"ВЫБРАТЬ
|   Дата, Ссылка, Наименование
|ИЗ Документ.ЗаказПокупателя КАК Дк
|ГДЕ Дк.Дата МЕЖДУ &Нач И &Кон
|И Дк.Проведен
|УПОРЯДОЧИТЬ ПО Дата УБЫВ";
Парам = Новый Структура("Нач,Кон", НачалоДня(ТекущаяДата() - 7), КонецДня(ТекущаяДата()));
Таб = A1sQ.Unload( A1sQ.ExecuteQ( A1sQ.QT(Текст), Парам ) );

Логи: ToAnyReadable + NormalizeWhitespace


Процедура ЛогСобытие(Контекст) Экспорт
    // Читабельное представление + нормализация пробелов/переводов
    СтрЛог = A1sS.ToAnyReadable(Контекст, Новый Структура("MaxLen", 2000));
    СтрЛог = A1sS.NormalizeWhitespace(СтрЛог);
    A1sS.Print("[LOG] " + СтрЛог);
КонецПроцедуры

Мини‑демо: smoke после деплоя


Процедура SmokeTestA1sCode() Экспорт
    Попытка
        // 1) Строковые утилиты
        Текст = A1sS.Join(Новый Массив("A", "B", "C"), ", ");
        Если Текст <> "A, B, C" Тогда ВызватьИсключение "Join"; КонецЕсли;

        // 2) Валидация
        Если Не A1sS.IsValidURL("https://example.com") Тогда ВызватьИсключение "IsValidURL"; КонецЕсли;

        // 3) Запрос (таблица не пустая или без ошибки)
        Таб = A1sQ.Unload( A1sQ.ExecuteQ( A1sQ.QT("ВЫБРАТЬ ПЕРВЫЕ 1 Ссылка ИЗ Справочник.Пользователи") ) );
        Если Таб.Количество() = 0 Тогда A1sS.Print("Внимание: нет пользователей"); КонецЕсли;

        A1sS.Print("Smoke OK");
    Исключение
        A1sS.Print("Smoke FAIL: " + ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

JSON / XML: round‑trip

Идея: сериализуем структуру в строку и читаем обратно. Удобно для логов/кэша/обмена.

// JSON → строка → объект
Данные = Новый Структура("Имя,Сумма,Состав",
    "Счёт 42", 123.45, Новый Массив("A","B","C"));
// Запись в строку
Зап = Новый ЗаписьJSON; Зап.УстановитьСтроку();
ЗаписатьJSON(Зап, Данные);
JSONСтрока = Зап.Закрыть();
// Чтение обратно
Чт = Новый ЧтениеJSON; Чт.УстановитьСтроку(JSONСтрока);
Клон = ПрочитатьJSON(Чт);
// Проверка
A1sS.PrintJSON(Клон);

// XML: общий паттерн (если тип поддерживает сериализацию в XML)
ЗапXML = Новый ЗаписьXML; ЗапXML.УстановитьСтроку();
ЗаписатьXML(ЗапXML, Данные); // для соответствующих типов/схем
XMLСтрока = ЗапXML.Закрыть();
ЧтXML = Новый ЧтениеXML; ЧтXML.УстановитьСтроку(XMLСтрока);
КлонXML = ПрочитатьXML(ЧтXML);
A1sS.PrintXML(КлонXML);

Regex‑утилиты A1sS


// Соответствие шаблону
Если A1sS.RegexMatch("abc-123", "^[a-z]+-\d+$") Тогда
    // ok
КонецЕсли;

// Замена чисел на # (везде)
Текст = A1sS.RegexReplace("a1 b22 c333", "\d+", "#"); // "a# b# c#"

// Разбиение по запятым/точкам с запятой + пробелам
Части = A1sS.RegexSplit("a, b; c", "[,;]\s*"); // ["a","b","c"]

Мини‑ORM на базе ValueQ/ValuesQ

Цель: компактные «репозитории» — функции, возвращающие структуры/массивы/таблицы.

Пользователь по UID


Функция Repo_ПользовательПоUID(UID) Экспорт
    Текст = "ВЫБРАТЬ ПЕРВЫЕ 1 Ссылка ИЗ Справочник.Пользователи
             ГДЕ ИдентификаторПользователяИБ = &UID";
    Ссылка = A1sQ.ValueQ(Текст, Новый Структура("UID", UID), "Ссылка");
    Если Ссылка = Неопределено Тогда Возврат Неопределено; КонецЕсли;

    // Детали
    Текст2 = "ВЫБРАТЬ Наименование ИЗ Справочник.Пользователи ГДЕ Ссылка = &Ссылка";
    Имя = A1sQ.ValueQ(Текст2, Новый Структура("Ссылка", Ссылка), "Наименование");
    Возврат Новый Структура("Ссылка,Имя", Ссылка, Имя);
КонецФункции

ТОП‑товары для отчёта


Функция Repo_ТопНоменклатуры(Лимит = 20) Экспорт
    Текст = "ВЫБРАТЬ ПЕРВЫЕ &N Ссылка, Наименование
             ИЗ Справочник.Номенклатура
             ПОРЯДОК ПО Наименование";
    Парам = Новый Структура("N", Лимит);
    Возврат A1sQ.Unload( A1sQ.ExecuteQ( A1sQ.QT(Текст), Парам ) );
КонецФункции

Upsert‑паттерн (найти/создать)


Функция Repo_ПолучитьИлиСоздатьНоменклатуру(Имя) Экспорт
    Ссылка = A1sQ.ValueQ(
        "ВЫБРАТЬ ПЕРВЫЕ 1 Ссылка ИЗ Справочник.Номенклатура ГДЕ Наименование = &Имя",
        Новый Структура("Имя", Имя),
        "Ссылка");
    Если Ссылка <> Неопределено Тогда Возврат Ссылка; КонецЕсли;

    // Создание
    Объект = Справочники.Номенклатура.СоздатьЭлемент();
    Объект.Наименование = Имя;
    Объект.Записать();
    Возврат Объект.Ссылка;
КонецФункции

JSON → плоская структура

Зачем: удобно логировать и экспортировать ключевые поля без вложенности.

Функция JSONПлоско(JSONСтрока) Экспорт
    Ч = Новый ЧтениеJSON; Ч.УстановитьСтроку(JSONСтрока);
    Д = ПрочитатьJSON(Ч);
    Р = Новый Структура;
    _JSONПлоскоВнутр("", Д, Р);
    Возврат Р;
КонецФункции

Процедура _JSONПлоскоВнутр(Префикс, Знач, Рез) Экспорт
    Если ТипЗнч(Знач) = Тип("Структура") Тогда
        Для Каждого П Из Знач Цикл
            Ключ = П.Ключ;
            Имя = ?(Префикс = "", Ключ, Префикс + "." + Ключ);
            _JSONПлоскоВнутр(Имя, П.Значение, Рез);
        КонецЦикла;
    ИначеЕсли ТипЗнч(Знач) = Тип("Соответствие") Тогда
        Для Каждого К Из Знач.Ключи() Цикл
            Имя = ?(Префикс = "", К, Префикс + "." + К);
            _JSONПлоскоВнутр(Имя, Знач.Получить(К), Рез);
        КонецЦикла;
    ИначеЕсли ТипЗнч(Знач) = Тип("Массив") Тогда
        Для И = 0 По Знач.Количество()-1 Цикл
            Имя = ?(Префикс = "", Строка(И), Префикс + "[" + Строка(И) + "]");
            _JSONПлоскоВнутр(Имя, Знач[И], Рез);
        КонецЦикла;
    Иначе
        Рез.Вставить(Префикс, Знач);
    КонецЕсли;
КонецПроцедуры

Regex: именованные группы


// Вариант через расширение A1sS (если доступно):
Совп = A1sS.RegexMatchEx("email: john@example.com", "(?i)(?[a-z0-9._%+-]+)@(?[a-z0-9.-]+\.[a-z]{2,})");
Если Совп.Нашлось Тогда
    Пользователь = Совп.Группы["user"];
    Хост = Совп.Группы["host"];
КонецЕсли;

// Или классическая нумерация групп с последующей раскладкой:
Если A1sS.RegexMatch("john@example.com", "^([a-z0-9._%+-]+)@([a-z0-9.-]+\.[a-z]{2,})$") Тогда
    Части = A1sS.RegexExtract("john@example.com", "^([a-z0-9._%+-]+)@([a-z0-9.-]+\.[a-z]{2,})$");
    Пользователь = Части[0]; // первая группа
    Хост = Части[1];         // вторая группа
КонецЕсли;

Экспорт отчёта: CSV / Excel

CSV: кроссплатформенно и быстро. Excel: через COM‑автоматизацию (Windows, толстый клиент).

Процедура ExportCSV(Таблица, Путь = "report.csv", Разделитель = ";") Экспорт
    П = Новый ЗаписьТекста(Путь, КодировкаТекста.UTF8);
    // Заголовок
    Заг = Новый Массив;
    Для Каждого К Из Таблица.Колонки Цикл
        Заг.Добавить(К.Имя);
    КонецЦикла;
    П.ЗаписатьСтроку(A1sS.Join(Заг, Разделитель));
    // Строки
    Для Каждого Р Из Таблица Цикл
        М = Новый Массив;
        Для Каждого К Из Таблица.Колонки Цикл
            М.Добавить(A1sS.AsString(Р[К.Имя]));
        КонецЦикла;
        П.ЗаписатьСтроку(A1sS.Join(М, Разделитель));
    КонецЦикла;
    П.Закрыть();
КонецПроцедуры

Процедура ExportXLSX(Таблица, ПутьXLSX = "report.xlsx") Экспорт
#Если Клиент Тогда
    ВызватьИсключение "Экспорт XLSX доступен на сервере/тонком клиенте Windows";
#КонецЕсли
    Эксель = Новый COMОбъект("Excel.Application");
    Книга = Эксель.Workbooks.Add();
    Лист = Книга.ActiveSheet;
    // Заголовок
    Кол = 1;
    Для Каждого К Из Таблица.Колонки Цикл
        Лист.Cells(1, Кол).Value = К.Имя;
        Кол = Кол + 1;
    КонецЦикла;
    // Данные
    СтрНом = 2;
    Для Каждого Р Из Таблица Цикл
        Кол = 1;
        Для Каждого К Из Таблица.Колонки Цикл
            Лист.Cells(СтрНом, Кол).Value = Р[К.Имя];
            Кол = Кол + 1;
        КонецЦикла;
        СтрНом = СтрНом + 1;
    КонецЦикла;
    Книга.SaveAs(ПутьXLSX);
    Книга.Close();
    Эксель.Quit();
КонецПроцедуры

Отчёт → ТабличныйДокумент (минимальный шаблон)

Идея: быстро собрать печатный документ без макета. Потом легко заменить на макет.

&НаКлиенте
Процедура ПоказатьОтчет(Команда)
    Таб = A1sQ.Unload( A1sQ.ExecuteQ( A1sQ.QT("ВЫБРАТЬ ПЕРВЫЕ 20 Ссылка, Наименование ИЗ Справочник.Номенклатура ПОРЯДОК ПО Наименование") ) );
    ТД = ПостроитьТабДок(Таб, "Топ-20 номенклатуры");
    ТД.Показать();
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПостроитьТабДок(Таблица, Заголовок) Экспорт
    ТД = Новый ТабличныйДокумент;
    ТД.Вывести(Заголовок);
    ТД.Вывести("");
    // Шапка
    СтрЗаг = "";
    Для Каждого К Из Таблица.Колонки Цикл
        СтрЗаг = СтрЗаг + ?(СтрЗаг = "", "", "; ") + К.Имя;
    КонецЦикла;
    ТД.Вывести(СтрЗаг);
    // Строки
    Для Каждого Р Из Таблица Цикл
        М = Новый Массив;
        Для Каждого К Из Таблица.Колонки Цикл
            М.Добавить(A1sS.AsString(Р[К.Имя]));
        КонецЦикла;
        ТД.Вывести(A1sS.Join(М, "; "));
    КонецЦикла;
    Возврат ТД;
КонецФункции

Пагинация / батч‑выборки (seek‑метод)

Надёжно: вместо смещений используйте «продолжить после ключа» (по возрастанию).

Функция ПеребратьНоменклатуруПакетами(Пакет = 500) Экспорт
    Последняя = Неопределено;
    Пока Истина Цикл
        Текст = "ВЫБРАТЬ ПЕРВЫЕ &N Ссылка, Наименование
                 ИЗ Справочник.Номенклатура
                 ГДЕ (&Last ЕСТЬ NULL) ИЛИ (Ссылка > &Last)
                 ПОРЯДОК ПО Ссылка";
        Парам = Новый Структура("N,Last", Пакет, Последняя);
        Таб = A1sQ.Unload( A1sQ.ExecuteQ( A1sQ.QT(Текст), Парам ) );
        Если Таб.Количество() = 0 Тогда
            Прервать;
        КонецЕсли;
        // Обработка пакета
        Для Каждого Р Из Таб Цикл
            // ... делаем дело ...
        КонецЦикла;
        // Сдвигаем маркер
        Последняя = Таб[Таб.Количество()-1].Ссылка;
    КонецЦикла;
    Возврат Истина;
КонецФункции

Мини‑валидатор схемы JSON (структуры)

Схема: Соответствие вида {Ключ: "Тип" | ВложеннаяСхема | МассивТипов}. Проверка — рекурсивная.

Функция ТипOK(Знч, ИмяТипа) Экспорт
    В = СтрЗаменить(СтрЗаглавныеБуквы(НРег(ИмяТипа)), " ", "");
    Возврат
        (В = "Строка"       И ТипЗнч(Знч) = Тип("Строка")) ИЛИ
        (В = "Число"        И ТипЗнч(Знч) = Тип("Число")) ИЛИ
        (В = "Дата"         И ТипЗнч(Знч) = Тип("Дата")) ИЛИ
        (В = "Булево"       И ТипЗнч(Знч) = Тип("Булево")) ИЛИ
        (В = "Структура"    И ТипЗнч(Знч) = Тип("Структура")) ИЛИ
        (В = "Соответствие" И ТипЗнч(Знч) = Тип("Соответствие")) ИЛИ
        (В = "Массив"       И ТипЗнч(Знч) = Тип("Массив"));
КонецФункции

Процедура JSONПроверитьПоСхеме(Данные, Схема, Ошибки) Экспорт
    // Ошибки — Массив строк
    Для Каждого К Из Схема.Ключи() Цикл
        Ожидаем = Схема.Получить(К);
        Есть = Неопределено;
        Если ТипЗнч(Данные) = Тип("Структура") Тогда
            Есть = Данные.Свойство(К);
        ИначеЕсли ТипЗнч(Данные) = Тип("Соответствие") Тогда
            Есть = Данные.Содержит(К);
        КонецЕсли;
        Если Не Есть Тогда
            Ошибки.Добавить("Нет ключа: " + К);
            Продолжить;
        КонецЕсли;
        Значение = ?(ТипЗнч(Данные) = Тип("Структура"), Данные[К], Данные.Получить(К));
        // Варианты правил
        Если ТипЗнч(Ожидаем) = Тип("Строка") Тогда
            Если Не ТипOK(Значение, Ожидаем) Тогда
                Ошибки.Добавить("Тип поля " + К + " != " + Ожидаем);
            КонецЕсли;
        ИначеЕсли ТипЗнч(Ожидаем) = Тип("Соответствие") Тогда
            JSONПроверитьПоСхеме(Значение, Ожидаем, Ошибки);
        ИначеЕсли ТипЗнч(Ожидаем) = Тип("Массив") Тогда
            // массив допустимых типов
            Подходит = Ложь;
            Для Каждого ИмяТипа Из Ожидаем Цикл
                Если ТипOK(Значение, ИмяТипа) Тогда Подходит = Истина; Прервать; КонецЕсли;
            КонецЦикла;
            Если Не Подходит Тогда
                Ошибки.Добавить("Поле " + К + " не соответствует одному из типов: " + A1sS.Join(Ожидаем, ", "));
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

// Пример использования
Схема = Новый Соответствие;
Схема.Вставить("Имя", "Строка");
Схема.Вставить("Дата", "Дата");
Схема.Вставить("Сумма", "Число");
Схема.Вставить("Состав", Новый Массив("Массив","Структура"));

Ошибки = Новый Массив;
JSONПроверитьПоСхеме(Новый Структура("Имя,Дата,Сумма,Состав", "Заказ", ТекущаяДата(), 123.45, Новый Массив), Схема, Ошибки);
Если Ошибки.Количество() > 0 Тогда
    A1sS.Print("Проблемы: " + A1sS.Join(Ошибки, "; "));
Иначе
    A1sS.Print("OK");
КонецЕсли;

ТабличныйДокумент по макету (Области)

Шаблон макета: создайте ОбщийМакет ОтчетНоменклатура с областями: Шапка, Строка, Итог.

&НаСервереБезКонтекста
Функция ПостроитьТабДокПоМакету(Таблица) Экспорт
    Макет = ОбщийМакет("ОтчетНоменклатура");
    ОблШапка = Макет.ПолучитьОбласть("Шапка");
    ОблСтрока = Макет.ПолучитьОбласть("Строка");
    ОблИтог = Макет.ПолучитьОбласть("Итог");

    ТД = Новый ТабличныйДокумент;
    // Шапка
    ТД.Вывести(ОблШапка);

    // Строки
    Для Каждого Р Из Таблица Цикл
        ОблСтрока.Параметры.Очистить();
        Для Каждого К Из Таблица.Колонки Цикл
            ОблСтрока.Параметры.Вставить(К.Имя, Р[К.Имя]);
        КонецЦикла;
        ТД.Вывести(ОблСтрока);
    КонецЦикла;

    // Итог
    ОблИтог.Параметры.Вставить("Количество", Таблица.Количество());
    ТД.Вывести(ОблИтог);

    Возврат ТД;
КонецФункции

Экспорт ТабличногоДокумента в HTML / PDF


Процедура СохранитьТД(ТД, ПутьHTML = "report.html", ПутьPDF = "report.pdf") Экспорт
    Попытка
        // HTML — как правило, доступен из коробки
        ТД.Записать(ПутьHTML, ФорматТабличногоДокумента.HTML);
    Исключение
        A1sS.Print("HTML export failed: " + ОписаниеОшибки());
    КонецПопытки;

    Попытка
        // PDF — при наличии поддержки в вашей версии/сборке
        ТД.Записать(ПутьPDF, ФорматТабличногоДокумента.PDF);
    Исключение
        A1sS.Print("PDF export not available: " + ОписаниеОшибки());
    КонецПопытки;
КонецПроцедуры

Пагинация по составному ключу (Дата + Ссылка)

Порядок: сортируем по (Дата, Ссылка); берём записи «строго после» последней пары.

Процедура ОбойтиДокументыПакетами(Пакет = 500) Экспорт
    ПоследДата = Дата("00010101");
    ПоследСсылка = Неопределено;
    Пока Истина Цикл
        Текст =
"ВЫБРАТЬ ПЕРВЫЕ &N
|   Дата, Ссылка, Номер
|ИЗ Документ.ЗаказПокупателя
|ГДЕ (Дата > &D) ИЛИ (Дата = &D И Ссылка > &R)
|УПОРЯДОЧИТЬ ПО Дата, Ссылка";
        Парам = Новый Структура("N,D,R", Пакет, ПоследДата, ПоследСсылка);
        Таб = A1sQ.Unload( A1sQ.ExecuteQ( A1sQ.QT(Текст), Парам ) );
        Если Таб.Количество() = 0 Тогда Прервать; КонецЕсли;

        // обработка
        Для Каждого Р Из Таб Цикл
            // ...
        КонецЦикла;

        // сдвинуть маркер
        ПоследДата = Таб[Таб.Количество()-1].Дата;
        ПоследСсылка = Таб[Таб.Количество()-1].Ссылка;
    КонецЦикла;
КонецПроцедуры

JSON‑схема 2.0: required / enum / диапазоны / pattern

Схема: Соответствие {Ключ: Структура("type,required,enum,min,max,pattern", ...)}.

Процедура JSONПроверитьПоСхемеV2(Данные, Схема, Ошибки, Путь = "") Экспорт
    Для Каждого П Из Схема Цикл
        Ключ = П.Ключ; Прав = П.Значение;
        ИмяПоля = ?(Путь = "", Ключ, Путь + "." + Ключ);

        // required
        Есть = Ложь; Знач = Неопределено;
        Если ТипЗнч(Данные) = Тип("Структура") Тогда
            Есть = Данные.Свойство(Ключ, Знач);
        ИначеЕсли ТипЗнч(Данные) = Тип("Соответствие") Тогда
            Есть = Данные.Содержит(Ключ); Если Есть Тогда Знач = Данные.Получить(Ключ); КонецЕсли;
        КонецЕсли;

        Если Прав.Свойство("required") И Прав.required И Не Есть Тогда
            Ошибки.Добавить("Требуется поле: " + ИмяПоля); Продолжить;
        КонецЕсли;
        Если Не Есть Тогда Продолжить;

        // type (строка или массив допустимых типов)
        ДопТипы = ?(ТипЗнч(Прав.type) = Тип("Массив"), Прав.type, Новый Массив(Прав.type));
        Подходит = Ложь;
        Для Каждого ИмяТипа Из ДопТипы Цикл
            Если ТипOK(Знач, ИмяТипа) Тогда Подходит = Истина; Прервать; КонецЕсли;
        КонецЦикла;
        Если Не Подходит Тогда
            Ошибки.Добавить("Тип " + ИмяПоля + " не входит в: " + A1sS.Join(ДопТипы, ", "));
            Продолжить;
        КонецЕсли;

        // enum
        Если Прав.Свойство("enum") Тогда
            ЕстьЛи = Ложь;
            Для Каждого Вариант Из Прав.enum Цикл
                Если Знач = Вариант Тогда ЕстьЛи = Истина; Прервать; КонецЕсли;
            КонецЦикла;
            Если Не ЕстьЛи Тогда
                Ошибки.Добавить("Поле " + ИмяПоля + " не из допустимых: " + A1sS.Join(Прав.enum, ", "));
            КонецЕсли;
        КонецЕсли;

        // min/max для чисел и дат
        Если Прав.Свойство("min") Тогда
            Если Знач < Прав.min Тогда Ошибки.Добавить("Поле " + ИмяПоля + " < min"); КонецЕсли;
        КонецЕсли;
        Если Прав.Свойство("max") Тогда
            Если Знач > Прав.max Тогда Ошибки.Добавить("Поле " + ИмяПоля + " > max"); КонецЕсли;
        КонецЕсли;

        // pattern для строк
        Если Прав.Свойство("pattern") Тогда
            Если Не A1sS.RegexMatch(A1sS.AsString(Знач), Прав.pattern) Тогда
                Ошибки.Добавить("Поле " + ИмяПоля + " не соответствует шаблону");
            КонецЕсли;
        КонецЕсли;

        // nested schema
        Если Прав.Свойство("schema") Тогда
            JSONПроверитьПоСхемеV2(Знач, Прав.schema, Ошибки, ИмяПоля);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

// Пример схемы
Схема = Новый Соответствие;
Схема.Вставить("Имя",    Новый Структура("type,required,pattern", "Строка", Истина, "^[A-Яа-яA-Za-z ]{2,}$"));
Схема.Вставить("Сумма",  Новый Структура("type,required,min,max", "Число", Истина, 0, 1000000));
Схема.Вставить("Валюта", Новый Структура("type,enum", "Строка", Новый Массив("RUB","USD","EUR")));
Схема.Вставить("Дата",   Новый Структура("type,required", "Дата", Истина));
// Вложенный адрес
АдресСх = Новый Соответствие;
АдресСх.Вставить("Город",  Новый Структура("type,required", "Строка", Истина));
АдресСх.Вставить("Индекс", Новый Структура("type,pattern", "Строка", "\\d{6}"));
Схема.Вставить("Адрес",   Новый Структура("type,schema", "Структура", АдресСх));

Ошибки = Новый Массив;
JSONПроверитьПоСхемеV2(Данные, Схема, Ошибки);
Если Ошибки.Количество() > 0 Тогда
    A1sS.Print("Проблемы: " + A1sS.Join(Ошибки, "; "));
Иначе
    A1sS.Print("OK");
КонецЕсли;
Совет: начинайте с ValueQ + AsString + Join. Это покрывает 80% задач.

Паттерны по хелперам

A1sQ.ValueQ — одно значение по параметрам


// 1) По одному параметру, вернуть поле "Наименование"
ИмяПольз = A1sQ.ValueQ(
    "ВЫБРАТЬ ПЕРВЫЕ 1 Наименование ИЗ Справочник.Пользователи ГДЕ ИдентификаторПользователяИБ = &UID",
    Новый Структура("UID", ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор),
    "Наименование");

// 2) Несколько параметров, поле по умолчанию — первый столбец
Цена = A1sQ.ValueQ(
    "ВЫБРАТЬ ПЕРВЫЕ 1 Цена ИЗ Справочник.Номенклатура ГДЕ Ссылка = &Сс AND ЕдиницаИзмерения = &Ед",
    Новый Структура("Сс,Ед", СсылкаНоменклатуры, ЕдиницаРуб));

A1sQ.ValuesQ — массив из одного столбца


// Активные пользователи списком имён
Имена = A1sQ.ValuesQ(
    "ВЫБРАТЬ Наименование ИЗ Справочник.Пользователи ГДЕ ПометкаУдаления = &F ПОРЯДОК ПО Наименование",
    Новый Структура("F", Ложь));
A1sS.Print("Пользователи: " + A1sS.Join(Имена, ", "));

A1sQ.TableQ — таблица для UI/экспорта


// Топ-50 номенклатуры алфавитом
Таб = A1sQ.Unload( A1sQ.ExecuteQ( A1sQ.QT("ВЫБРАТЬ ПЕРВЫЕ 50 Ссылка, Наименование ИЗ Справочник.Номенклатура ПОРЯДОК ПО Наименование") ) );
// ТаблицаЗначений готова для формы/экспорта

A1sS.AsString — форматирование чисел и дат


Опц = Новый Структура("NumberFormat,DateFormat", "ЧГ=0; ЧД=2; N=,; T= ", "ДФ=dd.MM.yyyy");
СуммаСтр = A1sS.AsString(12345.678, Опц);  // "12 345,68" (пример)
ДатаСтр  = A1sS.AsString(ТекущаяДата(), Опц);

A1sS.Join — аккуратно соединить


Список = Новый Массив; Список.Добавить("R"); Список.Добавить(""); Список.Добавить("B");
// Фильтруем пустые и соединяем
Непустые = Новый Массив; Для Каждого Э Из Список Цикл Если A1sS.HasText(Э) Тогда Непустые.Добавить(Э); КонецЕсли; КонецЦикла;
Результат = A1sS.Join(Непустые, ", ", Неопределено, "Цвета: ", ".");
// "Цвета: R, B."

A1sS.ReplaceText — замены без регулярок


Текст = "контракт, контрактор"; 
Опции = Новый Структура("WholeWord", Истина);
Текст = A1sS.ReplaceText(Текст, "контракт", "договор", Опции);
// "договор, контрактор"

A1sS.AddTextToTemplate / CreateTemplateBuilder — быстрый шаблон


B = A1sS.CreateTemplateBuilder();
Для Каждого Т Из Товары Цикл
    A1sS.AddTextToTemplate("• {{Имя}} — {{Цена}} ₽", Новый Структура("Имя,Цена", Т.Имя, Т.Цена));
КонецЦикла;
Итог = B.ToString();

A1sS.ProcessTemplate — подстановка по структуре


Шаблон = "Пользователь: {{Имя}} ({{Роль}})";
Стркт = Новый Структура("Имя,Роль", "Иван", "Администратор");
Рез = A1sS.ProcessTemplate(Шаблон, Стркт);
// "Пользователь: Иван (Администратор)"

A1sS.Print* — диагностический вывод


A1sS.Print("Старт");
A1sS.PrintYN(Истина);          // "Да"
A1sS.PrintJSON(Новый Структура("A", 1, "B", 2));
A1sS.PrintXML(Новый Соответствие);

A1sS.IsValidURL / HasText / Wrap — валидация и мелочёвка


Если A1sS.IsValidURL("https://a1scode.ru") Тогда
    Сообщить("ok");
КонецЕсли;

Если A1sS.HasText(Имя) Тогда
    Имя = A1sS.Wrap(Имя, """, """); // "Имя" в кавычках
КонецЕсли;