<div dir="ltr"><div class="gmail_default" style="font-family:monospace,monospace">Приветствую!<br><br></div><div class="gmail_default" style="font-family:monospace,monospace">  Очередная безумная идея, рождённая вследствие просмотра SQL::Abstract и всяких прочих LINQ. Периодически возникает ситуация, когда мы что-то выбираем из базы, но конкретные критерии неизвестны заранее (date < ? или date > ? или оба). Тут мне известны варианты:<br><br></div><div class="gmail_default" style="font-family:monospace,monospace">* сделать нужный запрос руками ($sql .= (defined $x ? " foo = ?" : " foo IS NULL");<br></div><div class="gmail_default" style="font-family:monospace,monospace">* прогенерить из DSL;<br></div><div class="gmail_default" style="font-family:monospace,monospace">* написать один раз функцию, которая генерит селект_заданного_типа для данной конкретной модели;<br></div><div class="gmail_default" style="font-family:monospace,monospace">* использовать ORM.<br><br></div><div class="gmail_default" style="font-family:monospace,monospace">(Что я пропустил?..) <br></div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">Ну и вот, собственно, идея: в большинстве случаев "каждый раз другие" критерии - это на самом деле просто группа отношений, которые надо применить к заранее известной таблице. Поэтому пишем шаблон запроса (как с плейсхолдерами (foo =?)) + добавляем хеши условий вместо одиночных значений. Т.е. используем SQL как DSL для описания SQL.<br><br></div><div class="gmail_default" style="font-family:monospace,monospace">Что-то вроде<br><br></div><div class="gmail_default" style="font-family:monospace,monospace">    my $template_query = "SELECT * FROM foobar f WHERE f.??? ORDER BY created LIMIT ?";<br></div><div class="gmail_default" style="font-family:monospace,monospace">    my %criteria = ( foo => 42, bar => undef );<br></div><div class="gmail_default" style="font-family:monospace,monospace">    my ($normal_query, @param_list) = decorate_query( $template_query, \%criteria, 12 );<br><br></div><div class="gmail_default" style="font-family:monospace,monospace">    на выходе вместо трёх вопросов - "f.foo = ? AND f.bar IS NULL" и потом два параметра (42, 12). <br><br></div><div class="gmail_default" style="font-family:monospace,monospace">??? выбрано потому, что вряд ли кто-то в здравом уме напишет три плейсхолдера подряд без пробелов. А префикс f. мы требуем, ибо может быть более 1 таблицы (да и скорее всего будет много таблиц - типа пришёл DBA с листочком - "я вам тут запросы соптимизировал, ннннадо?..").<br></div><div class="gmail_default" style="font-family:monospace,monospace"><br></div><div class="gmail_default" style="font-family:monospace,monospace">И вторая часть - а как нам покороче записать foo < 5? SQL::Abstract предлагает foo => { "<" => 5 }, но мне кажется, что можно сделать через прототипы + overload (точнее, я уже сделал, но там такой код, что его показывать стыдно):<br><br></div><div class="gmail_default" style="font-family:monospace,monospace">    {<br></div><div class="gmail_default" style="font-family:monospace,monospace">        foo => (value < 5) & (value != 3),<br></div><div class="gmail_default" style="font-family:monospace,monospace">        bar => value->in("дыр", "бул", "щыл")),<br>    }<br><br></div><div class="gmail_default" style="font-family:monospace,monospace">1. Чего не хватает в списке вариантов?<br></div><div class="gmail_default" style="font-family:monospace,monospace">2. Есть ли уже что-то подобное?<br></div><div class="gmail_default" style="font-family:monospace,monospace">3. Достаточно ли выразителен синтаксис t.???, или надо что-то поинтереснее? А если мы хотим заранее определить поля? У меня была идея "t.???[city cost created]", но, может, что-то получше можно? <br><br></div><div class="gmail_default" style="font-family:monospace,monospace">Всем хорошего (остатка) дня!<br></div><br>-- <br><div class="gmail_signature"><div dir="ltr"><div><div><div><font face="monospace,monospace">Konstantin S. Uvarin<br></font></div><font face="monospace,monospace">jabber: see <from><br></font></div><font face="monospace,monospace">skype: kuvarin<br></font></div><font face="monospace,monospace"><a href="http://github.com/dallaylaen" target="_blank">http://github.com/dallaylaen</a><br></font></div></div>
</div>