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


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="coen.bakker" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/coen.bakker/120/39732_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  coen.bakker
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Here is some more context.</p>
<p>The idea is that a user (i.e., author) can create story drafts. Later those can be published. Publishing deletes the StoryDraft and creates a Story. When published, the users can make edits to the published story. In that case a new StoryDraft will be created by copying a large subset of the fields of the published story. If the user commits to the edits made in the new StoryDraft, the published story gets updated and the StoryDraft gets deleted.</p>
<p><strong>stories schema</strong></p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  schema "stories" do
    field :title, :string, default: "Untitled Story"
    ...

    has_one :story_draft, StoryDraft

    many_to_many(:authors, User,
      join_through: "authors_stories",
      join_keys: [story_id: :id, author_id: :id],
      on_replace: :delete
    )

    field :published_at, :utc_datetime
    timestamps()
  end
</code></pre>
<p><strong>story_draft schema</strong></p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  schema "story_drafts" do
    field :title, :string, default: "Untitled Story"
    ...

    belongs_to :story, Story
    many_to_many(:authors, User,
      join_through: "authors_story_drafts",
      join_keys: [story_draft_id: :id, author_id: :id],
      on_replace: :delete
    )

    timestamps()
  end
</code></pre>
<p>I am making changes to my schemas, however, because some improvements are necessary. But this is the status quo.</p>
<p>The code snippet from my original post returned a list of maps. I have now changed this to the database returning a list of structs.</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">  def last_updated_stories_and_drafts_by_author(%User{} = user, amount \\ 8) do
    story_query =
      from s in Story,
        join: u in assoc(s, :authors),
        where: u.id == ^user.id,
        select: [
          :id,
          :title,
          :updated_at,
          :cover_image,
          :published_at
        ]

    story_draft_query =
      from sd in StoryDraft,
        join: u in assoc(sd, :authors),
        where: u.id == ^user.id,
        select: %Story{
          id: sd.id,
          title: sd.title,
          updated_at: sd.updated_at,
          cover_image: sd.cover_image,
          published_at: nil
        }

    authors_query =
      from a in User,
        select: [:id, :username, :verified]

    union_query =
      from q in story_query,
        union: ^story_draft_query,
        order_by: fragment("updated_at DESC"),
        limit: ^amount,
        preload: [authors: ^authors_query]

    Repo.all(union_query)
  end
</code></pre>
<p>As you can see, I used %Story{} as the return struct in the story_draft_query. That works, but feels a bit hacky. The Story struct is a superset, let’s say, of StoryDraft. But that is not enforced in any way (e.g., a marco).</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="292700" 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/failing-to-use-union-and-also-preload-or-select-associated-data/56677/12">Post #11</a>
	                </div>
	            </div>
              <div id="likers-container-292700" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="292700"
                     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="292708" data-post-id="292708">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="coen.bakker" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/coen.bakker/120/39732_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  coen.bakker
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="GazeIntoTheAbyss" data-post="11" data-topic="56677">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/eb8c5e/48.png" class="avatar"> GazeIntoTheAbyss:</div>
<blockquote>
<p>Also I changed the order_by to just normal elixir instead of a fragment and added distinct to stop you getting duplicate results if a story and draft are both within the limit. Not sure if its needed or not.</p>
</blockquote>
</aside>
<p>I believe I ran into an error when combining <code>union</code> with Ecto’s  <code>order_by</code>. That’s why I used the fragment to order.</p>
<p>This is where I got more information about that error: <a href="https://github.com/elixir-ecto/ecto/issues/2825" class="inline-onebox" rel="noopener nofollow ugc">Ecto 3: union/union_all + order_by gives "(undefined_table)" Postgres error · Issue #2825 · elixir-ecto/ecto · GitHub</a>.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="292708" 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/failing-to-use-union-and-also-preload-or-select-associated-data/56677/13">Post #12</a>
	                </div>
	            </div>
              <div id="likers-container-292708" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="292708"
                     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="292719" data-post-id="292719">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="coen.bakker" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/coen.bakker/120/39732_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  coen.bakker
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="coen.bakker" data-post="12" data-topic="56677">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/coen.bakker/48/39732_2.png" class="avatar"> coen.bakker:</div>
<blockquote>
<p>As you can see, I used %Story{} as the return struct in the story_draft_query. That works, but feels a bit hacky. The Story struct is a superset, let’s say, of StoryDraft. But that is not enforced in any way (e.g., a marco).</p>
</blockquote>
</aside>
<p>That also means I cannot pattern match on the struct (i.e., inside a HEEx markup of a LiveView) to determine whether a particular item is a story or a story draft. That was my initial strategy. So something like:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">&lt;%= for s in @latest_updated %&gt;
  &lt;StoryComponent :if={s.__struct__ == MyApp.Story}/&gt;
  &lt;StoryDraftComponent :if={s.__struct__ == MyApp.StoryDraft}/&gt;
&lt;% end %&gt;
</code></pre>
<p>That seemed like a nice approach to me. But now I have to use one of the fields of the structs to determine whether an item is a story or a story draft. For example, with if-statements like so:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">&lt;%= for s in @latest_updated %&gt;
  &lt;% if s.type == :story do %&gt;
    &lt;StoryComponent/&gt;
  &lt;% if s.type == :draft %&gt;
    &lt;StoryDraftComponent/&gt;
  &lt;% end %&gt;
&lt;% end %&gt;
</code></pre>
<p>From what I understand a Ecto union that returns a list of structs will returns only one struct type. So this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">   union_query =
      from q in story_query,
        union: ^story_draft_query,
        order_by: fragment("updated_at DESC"),
        limit: ^amount,
        preload: [authors: ^authors_query]
</code></pre>
<p>Returns a list of %Story{} (just like the <code>story_query</code>), even if the <code>story_draft_query</code> would return some other struct.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="292719" 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/failing-to-use-union-and-also-preload-or-select-associated-data/56677/14">Post #13</a>
	                </div>
	            </div>
              <div id="likers-container-292719" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="292719"
                     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="292724" data-post-id="292724">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>You can use the same <code>:if</code> syntax with the condition on the fields: <code>&lt;StoryComponent :if={s.type == :story} /&gt;</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="292724" 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/failing-to-use-union-and-also-preload-or-select-associated-data/56677/15">Post #14</a>
	                </div>
	            </div>
              <div id="likers-container-292724" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="292724"
                     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="292725" data-post-id="292725">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="coen.bakker" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/coen.bakker/120/39732_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  coen.bakker
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>For sure! I gladly make use of that normally. <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="292725" 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/failing-to-use-union-and-also-preload-or-select-associated-data/56677/16">Post #15</a>
	                </div>
	            </div>
              <div id="likers-container-292725" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="292725"
                     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>