<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="157087" data-post-id="157087">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="halostatue" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/halostatue/120/2389_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  halostatue
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>That’s not necessarily a bad way to do it, but it means you have to maintain four parallel lists.</p>
<p>I’m going to be implementing this as:</p>
<pre data-code-wrap="sql"><code class="lang-sql">SELECT *
  FROM jsonb_to_recordset($1::jsonb) AS p(slug text, starts_at timestamp, ends_at timestamp, result_order integer)
  LEFT JOIN sensors AS s ON s.slug = p.slug
  LEFT JOIN sensor_installations AS si ON si.id = si.sensor_id
AND (si.activated_at, coalesce(si.deactivated_at, p.ends_at + interval '5 minutes') overlaps (p.starts_at, p.ends_at)
order by p.result_order ASC;
</code></pre>
<p>I need to do this to perform the equivalent of <code>delete_all</code> for a table with composite keys. This should be easier to do with a list of json elements because of <code>jsonb_to_recordset</code>.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="157087" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ecto-in-clauses-with-tuples/27272/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-157087" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="157087"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #11"></div>
  </section>
</div>
    <div class="postbit" id="157150" data-post-id="157150">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="benwilson512" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/benwilson512/120/1457_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  benwilson512
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Author of Craft GraphQL APIs in Elixir with Absinthe</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Oh excellent I hadn’t seen that before! Were you able to come up with any Ecto syntax that would let you use the jsonb to record set within  an ordinary ecto query? I figure the actual record set call has to be in a fragment, but it would be nice to compose that fragment inside a normal ecto query.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="157150" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ecto-in-clauses-with-tuples/27272/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-157150" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="157150"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #12"></div>
  </section>
</div>
    <div class="postbit" id="157166" data-post-id="157166">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="halostatue" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/halostatue/120/2389_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  halostatue
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>No. If/when it’s possible to specify raw SQL or a fragment as a source for <code>from</code>, then it should be pretty easy. I’m not sure how that would work, though.</p>
<p>The <code>jsonb_to_recordset</code> is something that I’ve only been looking at in the last 3–4 weeks, but it really does work well.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="157166" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ecto-in-clauses-with-tuples/27272/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-157166" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="157166"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #13"></div>
  </section>
</div>
    <div class="postbit" id="158375" data-post-id="158375">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="halostatue" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/halostatue/120/2389_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  halostatue
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I wanted to highlight how I’m using these (the code is going to production tomorrow). Essentially, I’m getting my data records like this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">activity =
  PendingDataExchange
  |&gt; where(exchange_type: ^config.exchange)
  |&gt; where([pde], pde.updated_at &lt;= ^config.timestamp)
  |&gt; select([pde], map(pde, ~w(user_id business_id exchange_type update_type)a))
  |&gt; limit(^config.size)
  |&gt; Repo.all(timeout: config.timeout)
</code></pre>
<p>Later, I’m loading records <em>based</em> on the activity in question:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">records =
  load_records_sql()
  |&gt; Repo.query([activity])
  |&gt; case do
    {:ok, %{rows: rows}} -&gt; {:ok, Enum.map(rows, &amp;hd/1)}
    error -&gt; error
  end
</code></pre>
<p>Finally, I’m purging my records:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Repo.query(purge_activity_sql(), [activity])
</code></pre>
<p>The SQL statements are complex, so I’ve simplified them some, but the <code>load_records_sql/0</code> and <code>purge_activity_sql/0</code> functions are just functions that return a triple-quoted (<code>"""</code>) string.</p>
<p><strong>load_records_sql/0</strong>:</p>
<pre data-code-wrap="sql"><code class="lang-sql">SELECT jsonb_build_object(
         'update_type', e.update_type,
         'customer_id', c.id,
         'owner_id', bo.id,
         'customer', jsonb_build_object(
           'first_name', c.first_name,
           'last_name', c.last_name,
           'role', buc.role
         ),
         'business', jsonb_build_object(
           'name', b.name
         ),
         'membership', jsonb_build_object(
           'code', m.code,
           'assigned_at', m.assigned_at
         )
       ) AS event
  FROM jsonb_to_recordset($1::jsonb) AS e(
         user_id uuid, business_id uuid, update_type update_type
       )
 INNER JOIN users AS c ON c.id = e.user_id
 INNER JOIN businesses AS b ON b.id = e.business_id
 INNER JOIN memberships AS m ON m.user_id = c.id
 INNER JOIN business_users AS buc ON buc.user_id = c.id AND buc.business_id = b.id
 INNER JOIN business_users AS buo ON buo.business_id = b.id AND buo.role = 'manager'
 INNER JOIN users AS bo ON bo.id = buo.user_id;
</code></pre>
<p>Note that this <em>returns</em> a <code>jsonb</code> object for each row, which will simplify a lot of the processing moving forward. <code>jsonb_build_record</code> is almost as awesome as <code>jsonb_to_recordset</code>.</p>
<p><strong>purge_activity_sql/0</strong>:</p>
<pre data-code-wrap="sql"><code class="lang-sql">DELETE FROM pending_data_exchange
 USING jsonb_to_recordset($1::jsonb) AS e(
         user_id uuid, business_id uuid, exchange_type citext
       )
 WHERE e.user_id = pending_data_exchange.user_id
   AND e.business_id = pending_data_exchange.business_id
   AND e.exchange_type = pending_data_exchange.exchange_type;
</code></pre>
<p>I just wish that I could <em>somehow</em> build something from a <code>Repo.query</code> or <code>fragment</code> that would let me use it as an Ecto source (e.g., just the <code>jsonb_to_recordset($1::jsonb) AS …</code> bit.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="158375" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ecto-in-clauses-with-tuples/27272/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-158375" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="158375"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #14"></div>
  </section>
</div>
    <div class="postbit" id="182117" data-post-id="182117">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="alex_weinberger" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  alex_weinberger
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Here is an example of both methods, the array per field and the jsonb_to_recordset, using ecto.</p>
<p><strong>Array per field + unnest:</strong></p>
<pre data-code-wrap="elixir"><code class="lang-elixir">ids =[ 1,  2,  1]
ages=[10, 20, 30]

from x in Friends.Person, 
inner_join: j in fragment("SELECT distinct * from unnest(?::int[],?::int[]) AS j(id,age)", ^ids, ^ages),
        on: x.id==j.id and x.age==j.age,
select: [:name]
</code></pre>
<p><strong>jsonb_to_recordset:</strong></p>
<pre data-code-wrap="elixir"><code class="lang-elixir">list = [%{id: 1, age: 10}, 
        %{id: 2, age: 20}, 
        %{id: 1, age: 30}]

from x in Friends.Person,
inner_join: j in fragment("SELECT distinct * from jsonb_to_recordset(?) AS j(id int,age int)", ^list),
        on: x.id==j.id and x.age==j.age,
select: [:name]
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="182117" data-batch-url="/posts/batch_likers">
                        9
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ecto-in-clauses-with-tuples/27272/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-182117" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="182117"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #15"></div>
  </section>
</div>
    <div class="postbit" id="335549" data-post-id="335549">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="dli" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  dli
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Late to the party, but I found a hack that builds and expands code at runtime and uses proper parameters instead of interpolation:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">def tuple_in(fields, values) do
  fields = Enum.map(fields, &amp;quote(do: field(x, unquote(&amp;1))))
  values = for v &lt;- values, do: quote(do: fragment("(?)", splice(^unquote(Tuple.to_list(v)))))
  field_params = Enum.map_join(fields, ",", fn _ -&gt; "?" end)
  value_params = Enum.map_join(values, ",", fn _ -&gt; "?" end)
  pattern = "(#{field_params}) in (#{value_params})"

  quote do
    dynamic(
      [x],
      fragment(unquote(pattern), unquote_splicing(fields), unquote_splicing(values))
    )
  end
  |&gt; Code.eval_quoted()
  |&gt; elem(0)
end

# usage
from p in Product, where: ^tuple_in([:category_id, :collection_id], [{1, 100}, {2, 200}])

# sql
SELECT
	p0."id",
	p0."title"
# more columns...
FROM
	"product" AS p0
WHERE ((p0."category_id", p0."collection_id")
	IN(($1, $2), ($3, $4));
</code></pre>
<p>Using <code>fragment("(?) in (?)", splice(^[p.category_id, p.collection_id]), splice(^values))</code> does not work because <code>p</code> is out of scope inside of a <code>^</code> statement.</p>
<p>My solution uses a dynamic statement and instead creates the field bindings with <a href="https://hexdocs.pm/ecto/3.11.2/Ecto.Query.API.html#field/2" rel="noopener nofollow ugc"><code>field/2</code></a>.</p>
<p><code>Code.eval_quoted</code> is a bit unorthodox but required to let Ecto<br>
build queries using AST. I hope this helps!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="335549" data-batch-url="/posts/batch_likers">
                        10
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ecto-in-clauses-with-tuples/27272/17">Post #16</a>
	                </div>
	            </div>
              <div id="likers-container-335549" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="335549"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #16"></div>
  </section>
</div>
    <div class="postbit" id="369294" data-post-id="369294">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="spicychickensauce" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/spicychickensauce/120/38169_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  spicychickensauce
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I landed here from some googling trying to find how to pass a list of maps into ecto as an inline table that could be used in a join expression.</p>
<p>I almost ended up doing the clever <code>jsonb_to_recordset</code> trick, however shortly after I luckily discovered <a href="https://hexdocs.pm/ecto/Ecto.Query.API.html#values/2" rel="noopener nofollow ugc">values/2</a>.</p>
<p>This probably didn’t exist at the time, but in case anyone else lands here after some searching, I hope leaving this here helps.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="369294" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ecto-in-clauses-with-tuples/27272/18">Post #17</a>
	                </div>
	            </div>
              <div id="likers-container-369294" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="369294"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #17"></div>
  </section>
</div>
    <div class="postbit" id="369311" data-post-id="369311">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="billylanchantin" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/billylanchantin/120/28428_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  billylanchantin
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thanks <a class="mention" href="/u/spicychickensauce" rel="nofollow">@spicychickensauce</a>! You’re right, I don’t think <code>values</code> existed yet.</p>
<p>I’m trying to connect the dots for how to use it with this scenario. Can you (or anyone else) confirm that this is how you’d do it?</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">value_schema = [col1: :integer, col2: :integer, col3: :integer]
value_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

value_rows = Enum.map(value_lists, &amp;Map.new(Enum.zip(Keyword.keys(value_schema), &amp;1)))
on = Enum.reduce(Keyword.keys(value_schema), dynamic(true), &amp;dynamic([x, v], ^&amp;2 and field(x, ^&amp;1) == field(v, ^&amp;1)))

from(row in :my_table, join: values(value_rows, Map.new(value_schema)), on: ^on, select: row)
</code></pre>
<p>I also played with a version that uses <a href="https://hexdocs.pm/ecto/Ecto.Schema.html#module-reflection" rel="noopener nofollow ugc">module reflection</a> so you don’t need to specify the column types:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">def tuple_in(schema_module, columns, value_lists) do
  value_schema = Map.new(columns, &amp;{&amp;1, schema_module.__schema__(:type, &amp;1)})
  value_rows = Enum.map(value_lists, &amp;Map.new(Enum.zip(columns, &amp;1)))
  on = Enum.reduce(columns, dynamic(true), &amp;dynamic([x, v], ^&amp;2 and field(x, ^&amp;1) == field(v, ^&amp;1)))
  from(row in schema_module, join: values(value_rows, value_schema), on: ^on, select: row)
end

tuple_in(My.Table, [:col1, :col2, :col3], [[1, 2, 3], [4, 5, 6], [7, 8, 9]])
</code></pre>
<p>But it didn’t seem quite general enough to be useful.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="369311" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ecto-in-clauses-with-tuples/27272/19">Post #18</a>
	                </div>
	            </div>
              <div id="likers-container-369311" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="369311"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #18"></div>
  </section>
</div>
    <div class="postbit" id="369358" data-post-id="369358">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="spicychickensauce" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/spicychickensauce/120/38169_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  spicychickensauce
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Sorry, I only came here looking for a way to use maps as parameters for a join, not for this particular scenario.<br>
I don’t really understand that <code>dynamic</code> usage, my case was much simpler didn’t require it.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="369358" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ecto-in-clauses-with-tuples/27272/20">Post #19</a>
	                </div>
	            </div>
              <div id="likers-container-369358" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="369358"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #19"></div>
  </section>
</div>
    <div class="postbit" id="374226" data-post-id="374226">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="gabrielgiordano" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/gabrielgiordano/120/17612_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  gabrielgiordano
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>For anyone looking on this, I’ve added correct type support:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  @doc """
  Builds a row constructor IN query for composite keys, also known as tuple IN query.

  It outputs `(id, name) in ((1::bigint, "Company A"::varchar), (2::bigint, "Company B"::varchar))`.

  ## Example

      iex&gt; from(s in schema, where: ^tuple_in(schema, [:id, :name], [[1, "Company A"], [2, "Company B"]]))

  """
  @spec tuple_in(Ecto.Schema.t(), [atom()], [[any()]]) :: Ecto.Query.dynamic_expr()
  def tuple_in(schema, fields, values) when length(fields) &gt; 0 and length(values) &gt; 0 do
    types = Enum.map(fields, &amp;schema.__schema__(:type, &amp;1))

    quoted_fields =
      Enum.map(fields, fn field -&gt;
        quote do
          field(s, ^unquote(field))
        end
      end)

    quoted_values =
      Enum.map(values, fn values -&gt;
        quoted_type_values =
          values
          |&gt; Enum.zip(types)
          |&gt; Enum.map(fn {value, type} -&gt;
            quote do
              type(^unquote(Macro.escape(value)), unquote(type))
            end
          end)

        params = "(#{Enum.map_join(quoted_type_values, ",", fn _ -&gt; "?" end)})"

        quote do
          fragment(unquote(params), unquote_splicing(quoted_type_values))
        end
      end)

    params =
      "(#{Enum.map_join(quoted_fields, ",", fn _ -&gt; "?" end)}) in (#{Enum.map_join(values, ",", fn _ -&gt; "?" end)})"

    {term, _bindings} =
      Code.eval_quoted(
        quote do
          dynamic(
            [s],
            fragment(unquote(params), unquote_splicing(quoted_fields), unquote_splicing(quoted_values))
          )
        end
      )

    term
  end

  def tuple_in(_schema, _fields, _values), do: dynamic(false)
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="374226" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/ecto-in-clauses-with-tuples/27272/21">Post #20</a>
	                </div>
	            </div>
              <div id="likers-container-374226" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="374226"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-last-post cat-last-post" title="Last post!"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <span class="all-loaded">— All posts loaded —</span>
</div></template></turbo-stream>