<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Hugo Duksis</title>
    <description>The latest articles on DEV Community by Hugo Duksis (@duksis).</description>
    <link>https://dev.to/duksis</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F81132%2Fed1b4344-0c3f-4567-a9d6-2d9d91bb0f80.jpeg</url>
      <title>DEV Community: Hugo Duksis</title>
      <link>https://dev.to/duksis</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/duksis"/>
    <language>en</language>
    <item>
      <title>Ecto order by a dynamic fragment</title>
      <dc:creator>Hugo Duksis</dc:creator>
      <pubDate>Tue, 20 Feb 2024 14:35:21 +0000</pubDate>
      <link>https://dev.to/elixir-berlin/ecto-order-by-a-dynamic-fragment-5eic</link>
      <guid>https://dev.to/elixir-berlin/ecto-order-by-a-dynamic-fragment-5eic</guid>
      <description>&lt;h2&gt;
  
  
  Problem description:
&lt;/h2&gt;

&lt;p&gt;Urgent need to return the results of a query in a predefined sort order by id. The project uses Ecto, MySQL and in SQL the sorting would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;FIELD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and in Ecto something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;order_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fragment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"FIELD(?, ?, ?, ?)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks good! dosen't it?&lt;/p&gt;

&lt;p&gt;No. The problem is that the list of ID's is dynamic, including its size. And this means two things&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;fragment&lt;/code&gt; function should be called with different arity based on values provided at runtime. (e.g. &lt;code&gt;fragment/5&lt;/code&gt;, &lt;code&gt;fragment/10&lt;/code&gt;, ...)&lt;/li&gt;
&lt;li&gt;first parameter of the &lt;code&gt;fragment&lt;/code&gt; function changes at runtime as well because we need as many question marks as there are elements in the list + 1 for the field reference.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;And out of nr. 2 comes another problem. &lt;br&gt;
We can not just pass an interpolated string to fragment as this is not allowed do to potential SQL injections.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(Ecto.Query.CompileError) to prevent SQL injection attacks, fragment(...) does not allow strings to be interpolated as the first argument via the `^` operator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Solution &lt;code&gt;splice&lt;/code&gt;:
&lt;/h2&gt;

&lt;p&gt;If you are or have the possibility to upgrade your Ecto version to &lt;code&gt;3.11&lt;/code&gt; or above you can use &lt;a href="https://hexdocs.pm/ecto/3.11.0/Ecto.Query.API.html#splice/1"&gt;&lt;code&gt;splice(list)&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;fragment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"? in (?)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;splice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and this will be the same as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="no"&gt;Post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;where:&lt;/span&gt; &lt;span class="n"&gt;fragment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"? in (?,?,?)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;^&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I first encountered this problem before ecto 3.11 and if you are on an older project and not able to upgrade your version of ecto there are few options for you&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reconsider upgrading Ecto&lt;/li&gt;
&lt;li&gt;Try &lt;a href="https://github.com/elixir-ecto/ecto/blob/a5187f3b7aef528b501cd505de4ac1a656b43634/lib/ecto/query/builder.ex#L688"&gt;backporting &lt;code&gt;splice&lt;/code&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Write a less sophisticated macro that serves your specific needs&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://hexdocs.pm/ecto/3.11.0/Ecto.Query.API.html#splice/1"&gt;https://hexdocs.pm/ecto/3.11.0/Ecto.Query.API.html#splice/1&lt;/a&gt;&lt;br&gt;
&lt;a href="https://stackoverflow.com/questions/59042043/using-unquote-splicing-in-macros-with-modified-lists"&gt;https://stackoverflow.com/questions/59042043/using-unquote-splicing-in-macros-with-modified-lists&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ecto</category>
      <category>elixir</category>
      <category>phoenix</category>
      <category>mysql</category>
    </item>
  </channel>
</rss>
