[C++] StringFormatting — сборщик SQL-строки

Полезным в программировании является то, что полезно (как бы это трудно не звучало). Иначе говоря, при применении тех или иных инструментов (или API), сам способ чтения при разборе должен быть таким, как читаешь свою любимую книгу (если она у вас есть) - от первой строки до последней строки полностью понимая, что происходит в каждой строчке кода - как вызывается, куда заходит, что выходит.

Так и в коде, а код или для себя или для других. В любом случае на всякие мелочи не нужно тратить времени на воспроизведение того, что хотел сделать тот или иной автор этим выражением. Одна из таких мелочей и удобств является составление или подготовка выражения SQL для дальнейшей отправки на выполнения данного выражения в качестве запроса (почти в каждом любом моем проекте такое встречается)

Задался вопросом об удобстве подобного механизма. На просторах интернета есть нечто подобное, которое могло б удовлетворить свои хотелки, однако они либо сильно наворочены (с большим избытком функционала) либо так же сложны в понимании (хотя иногда какая разница как плюшка работает, если оно работает, но это только иногда). Так же, с тех интернетов и древних публикаций собрал для себя простой класс с функцией сборки выражения

Немного кода

Смотрите. Существует достаточно простое действия сложения строк - конкатенация. Например

t1 = "age";
tableName = "human";
name = "Andr";
output = "SELECT * FROM " + tableName + " WHERE t1=" + t1 + " AND name=" + name;

В итоге получим

SELECT * FROM human WHERE t1=age AND name=Andr

Это один из способов сложения строк. Можно output разделить и через операцию += сложить строки

Однако такой метод не всегда удобен в особенности, если это касается больших, объемных запросов. Код просто превращается в сочинение с перемазываниями :)

Поэтому было решено использовать метод, который был давно реализов в Си через println. То есть использовать функцию с бесконечным количеством параметров. Где первым параметром будет являться шаблонное выражение, а последующие параметры будут подстанавливаться в шаблон-выражение через специальные теги, например %s.

Сам код:

std::string format(const char *str, ...){
        va_list args; //составляем список параметром
        va_start(args, str); //читаем список параметров

        va_list argsCopy;
        va_copy(argsCopy, args); //копируем список для подсчета количества записанных символов
        const int lengthSymbols = std::vsnprintf(NULL, 0, str, argsCopy);
        va_end(argsCopy);

        std::vector<char> newChar(lengthSymbols + 1); //выделяем память для записи всех аргументов на основе предыдущего чтения и подсчета
        std::vsnprintf(newChar.data(), newChar.size(), str, args);
        va_end(args);

        return std::string(newChar.data(), newChar.size());
    }

Исходники лежат тут - https://github.com/c-e-dev/StringFormatting

На суперское решение непретендую, но и в помощь многим надеюсь пригодится данное решение. Что по коду. Функция выводит string, но в функцию желательно все вторые аргументы уже преобразовать в const char, если они не были преобразованы ранее - так функция будет работать быстрее.

Дальше, через макросы va_* мы получаем все аргументы функции, так же копируем в отдельный список для дополнительных просчетов - размер всего сия, иначе - если не знать какой размер строки в итоге должен быть у нас на выходе, то программа может в иной раз захлебнуться, конечно же нам этого не особо то и хочется.

Дальше подсчетов размеров, выделяем заранее память под строку и собираем по всем аргументам. Есть встроенная функция vsnprintf, которая записывает форматированные выходные данные с помощью указателя на список аргументов (va_list).

В итоге у нас получается такое

format("SELECT * FROM %s WHERE t1=%s AND name=%s", "tableName", "123123", "Andrii");

Вывод будет таким

SELECT * FROM tableName WHERE t1=123123 AND name=Andrii

Воспринимается намного приятнее и более удобночитабильнее

Tags:
конкатенация строк, string, c++, работа со строками, удобная конкатенация в C++, string format, string formatting, string sql, sql c++

You can't comment this post because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author's username will be hidden by an alias.