Комментарии 33
В мире .net есть такая же либа: https://github.com/DapperLib/Dapper
А в truej можно привязывать параметры по именам, а не по позиции?
Спасибо за ваш вопрос. С целью упрощения API, в TrueSql нет именованных параметров. TrueSql старается не ставить перед разработчиками проблемы выбора. Даже самого минимального, что позволяет направить когнитивный ресурс на разработку, собственно, бизнес логики.
Понял. Просто с моей точки зрения - позиционные параметры вещь хрупкая и к багам ведущая. Но может у вас другой опыт. Я просто всегда на именованных параметрах сидел и хрупкость чисто умозрительно говорю.
Действительно, именованные параметры более устойчивы к изменениям. Это правда. Однако, мы всегда вынуждены выбирать исходя из некоторой суммы. Наименьший синтаксис и поддержка IDE из коробки(без каких либо сторонних плагинов) были важными метриками при разработке TrueSql - обычные вопросики (? - jdbc стандарт) они понимают лучше. Также в синтаксисе PG есть : и ::, значит такие синтаксические конструкцию пользователю пришлось бы экранировать.

Посмотрел чисто из любопытства. Возник единственный вопрос - опять же из любопытства.
Вы рассматриваете 5 различающихся по возвращаемому набору методов. Но все они получают ОДИН набор данных. В то же время некоторые СУБД вполне могут возвращать и несколько наборов, если в качестве выполняемого запроса используется обращение к хранимому объекту. Например, в MySQL хранимая процедура может вывалить в выходной поток несколько, а в теории в принципе сколько угодно, наборов данных. В том числе каждый из наборов вполне может иметь оригинальную, отличающуюся от других, структуру.
Может ли обрабатываться такой случай? Ведь в таком случае просто невозможно указать какой-то определённый результирующий класс..
Добрый день! Если кратко ответить на ваш вопрос, то ДА. Но есть нюансы, связанные с тем что время жизни курсоров - connection level, плюс не будет доступно проверок на этапе компиляции так как в JDBC метаданные курсоров untyped. Если вам нужен конкретный пример под вашу задачу, то вот контакты tg: @overln2, @aka_naked_gun
Вот признаться, совсем не понял, каким боком тут курсор. Он вообще тут вторичный исполнительный механизм.
Совсем по-обывательски ежели, то курсор - это такая штука, которую мы цепляем за набор записей, она в момент присоединения формирует структуру, которая соответствует структуре набора, и потом она ползёт по набору, получая оттуда записи, раскладывая их по полям структуры и отдавая это нам. То есть в момент, когда курсор находится где-то посередине полученного набора данных, мы не можем внести изменения в структуру, которая будет принимать записи из набора. То есть курсор - он не connection-level, он rowset-level, который в свою очередь connection-level. Просто это от нас прячут.
А я как раз говорю о случае, когда один результирующий набор, полученный нами, состоит не из записей, а из наборов с записями. То есть нужен какой-то над-метод, который за каждый отдельный набор записей будет цеплять свой курсор. Ну или один и тот же, но после того, как тот отфетчил предыдущий набор, с соотв. переинициализацией приёмной структуры. Особенно с учётом того, что подобные коллекции наборов записей на стороне SQL-сервера обычно forward-only.
Нет, даже обычный одиночный набор записей, полученный от простого запроса, на самом деле имеет такую же поли-структуру. Просто дефолтно ожидается единственный набор в коллекции, и курсор сразу цепляется за самый первый набор. Как я уже сказал, от нас это прячут.
Как раз ниже у вас в комментарии есть такие слова:
Драйвер привозит ResultSet, который является, структурно, плоской таблицей.
Так вот это как раз не обязательно. Драйвер запросто может привезти пачку таких плоских таблиц, различных по структуре.
Используйте его [
fetchNone
], когда вам не нужны выходные строки, например удалим клиента […]
Удаление в PostgreSQL, например, возвращает удаленную запись или ошибку, если при попытке удаления были нарушены констрейнты. Как узнать, успех, или неудача нас постигла? Ловить exception, брошенный из ds.q
? Какой именно?
Мы рекомендуем не писать DTO руками, просто добавьте
.g
Это экспоненциально повышает плотность WTF для всех, кто этот код будет читать.
Ну и, наконец, самый интересный вопрос: не натолкнемся ли мы на проблему N+1
, печально известную по миру рельсов? Что вернется, если я получаю список записей из джойна через fetchList
, из запроса со звёздочкой в селекте? Как глубоко пойдёт маппер?
Приветствую! Для работы с исключениями есть соответствующий API. Наличие/отсутствие в БД констрейнта с нужным именем также проверяется на этапе компиляции. Если вам нужно вернуть поля из удаленной строки, то воспользуйтесь .asGeneratedKeys() в TrueSql или returning в PG и, соответствующим fetch (уже не fetchNone). Если нужно количество "затронутых" строк, в TrueSql есть .withUpdateCount. Подробное описание этого функционала будет дано в следующих статьях.
По поводу плотности WTF
мы вас не поняли, вы можете смотреть на выходные колонки в запросе или сгенерированные DTO. Также, эти сгенерированные DTO автоматически появятся и в open API (см. комментарий выше).

В TrueSql нет проблемы N+1, аналогичной ORM-библиотекам, TrueSql вообще не ORM-библиотека. TrueSql исполняет запрос на стороне базы данных. Драйвер привозит ResultSet, который является, структурно, плоской таблицей. Из неё собирается одна/несколько DTO. Собираются они через дополнительный group-by на Java стороне в случае, если в dto появляются не только скаляры, но и списки.
А что мешает оставить один fetchStream, а пользователь сам разберётся сколько объектов он ожидает в ответ?
Действительно, fetchStream является наиболее общим интерфейсом, но дальше начинаются нюансы Java и ее stdlib.
FetchStream ленивый и держит внутри себя ResultSet и Connection, а в Java нет деструкторов, поэтому fetchStream можно использовать только через try-with-resource, иначе будут утечки
На Stream нет многих utility методов, которые есть, например, в Kotlin. Соответственно, разработчикам будет просто не удобно каждый раз писать один и тот же код: v = stream.findFirst(); if( v,isEmpty) throw ... и так далее
Если в джаве нет материализации стримов, то стоит её, наконец, изобрести.
А как материализовать бесконечный стрим?
А sql умеет возвращать беконечные наборы?
Ну сущность StreamThatCannotBeInfinite
— выглядит крайне странно, я затрудняюсь назвать хоть одну команду разработки языка, которая бы согласилась добавить такое в корку.
Кроме того, sql умеет возвращать очень большие объёмы данных, для которых был придуман метод fetchStream
и если разработчику возвращать всегда именно стрим, то разработчик начнет везде писать result.materialize()
, что приведет к отыквенью в самый неожиданный момент и (это же джава) повалит весь сервис.
https://dlang.org/phobos/std_array.html#array
Это ничем не отличается от fetchList.
void main()
{
import std.array;
import std.range : repeat;
import std.stdio: write, writeln, writef, writefln;
auto a = 42.repeat;
writeln(a);
}
Такой код написать сложно даже джуну. А вот такой:
void log(Range range) => writeln(range);
уже проще.
А уж если это вообще сторонняя библиотечная функция — так и вообще.
Я же не предлагаю отказаться от стримов. Я всего лишь сообщил, что полагаться на интеллект и внимательность всех пользователей библиотеки — путь в никуда. Особенно, если неверная реализация через materialize
выстрелит через год в продакшене.
fetchStream можно использовать только через try-with-resource
При желании это всё решаемо простым flatMap()
-ом.
Stream.of(fetchStream()).flatMap(Function.identity())
Почему в JS нельзя оставить один setTimeout
для имитации асинхронности, а пользователь потом сам разберется, как ему определить все эти async
и await
как промисы?
Читаю не первую статью о ваше библиотеке. Смотрели ли вы в сторону JOOQ https://www.jooq.org/? Ваше решение реализует такой же принцип работы с базой, но при этом в JOOQ очень хорошо реализована типобезопасность параметров запросов, да и при сборке запроса также осуществляется его валидация на этапе компиляции. Чем ваше решение лучше?
Добрый день! Вы видимо считаете что JOOQ хорошая технология, однако подумайте о том что JOOQ существует более 16 лет и при этом имеет <<1% market-share. TrueSql не стоит денег. Ваш вопрос про валидацию: в TrueSql всё это есть и даже лучше, следите за будущими публикациями. Тезисно ответил чем TrueSql лучше JOOQ в нашем тг-канале: https://t.me/TrueSql.
Прочитал ваши тезисы, жаль, что вы не изложили их здесь. Пока из ответов явных преимуществ не увидел. Как реализуется валидация средствами БД? Отправкой некорректного запроса и получением ошибки?
<<1% market share
6300 звёзд, 1200 форков
Для сравнения у спринга 57500 звёзд, а у trueSql - 14.
У кого нет своего мозга, тот думает чужим.
Это вы что имеете ввиду? Поясните, пожалуйста.
Ну раз вы так просите, то подумаю за вас: вы меряетесь звёздами, форками и маркет шарами, надеясь, что все те миллионы мух провели технический анализ и выбрали лучшее решение из возможных, а на самом деле большая часть из них не то что технического, а вообще никакого анализа не сделала и порой даже не пробовала в деле.
Поэтому имеет смысл публиковать бенчмарки и прочие сравнения с теми, комго уже выбрали миллионы мух, если ты, по сути, повторяешь их решение с незаметными глазу отличиями.
Было бы в тексте: «вот пример на JOOQ, вот на TrueSql, мы в триста раз быстрее, а JOOQ вообще возвращает таймаут и валится в корку».
Пока сравнений нет, у библиотеки с 1200 форков есть, как минимум, 1200 пользователей, которые погоняли её, понаступали на грабли, понаприсылали пуллреквестов (шучу, конечно, понаоставляли гневных ишью), и так далее.
А библиотека с 14 звездами, скорее всего, тестировалась только в тепличных условиях.
Вы меня извините, но я отвечал на конкретный тезис про "<<1% market share". Что, очевидно, не правда - и количество звёзд в репозитории здесь отличный показатель.
Ещё меня несколько напрягает токсичность евангелистов этой вашей чудо-библиотеки: вместо того, чтобы ответить по существу, они зачем-то сравнивают незнакомых людей с мухами и делают необоснованные выводы о чужих умственных способностях. Не надо так!
Сначала люди думают, что звёзды сложно накрутить, а потом обижаются на сравнения с мухами. Если вы не готовы воспринимать чужую аналитику - думайте своей головой.
TrueSql – заново учимся ходить в базу данных. Часть 1 – пять Fetch’ей