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


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="phcurado" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/phcurado/120/39030_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  phcurado
                    <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>Following up on the discussion here. I have started working on <code>Zoi.Ecto</code> integration.</p>
<p>The idea is to define the schema with Zoi and derive an Ecto embedded schema from it, so Zoi remains the source schema for validation, coercion and Ecto provides the struct and changeset interface.</p>
<p>The API looks like this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule MyApp.User do
  require Zoi.Ecto

  @schema Zoi.map(%{
            email: Zoi.email(),
            name: Zoi.string(),
            address:
              Zoi.map(%{
                street: Zoi.string(),
                number: Zoi.integer()
              })
          })

  Zoi.Ecto.generate_embedded_schema(@schema)
end

</code></pre>
<p>This generates the <code>embedded_schema</code> from the Zoi schema, I’m mapping Zoi types to ecto, including <code>embeds_one</code> and <code>embeds_many</code> from Zoi map/lists. Unsuported types for now I’m defaulting to :map.<br>
For example using the Zoi changeset function, zoi parses it and encapsulate to a changeset struct:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">iex&gt; Zoi.Ecto.changeset(%MyApp.User{}, %{email: "invalid", address: %{street: "street"}})
#Ecto.Changeset&lt;
  changes: %{
    address: #Ecto.Changeset&lt;
      changes: %{street: "street"},
      errors: [number: {"is required", [code: :required]}],
      valid?: false
    &gt;,
    email: "invalid"
  },
  errors: [email: {"invalid email format", [code: :invalid_format]}],
  valid?: false
&gt;
</code></pre>
<p>You can track the issue here:</p>
<ul>
<li>Issue: <a href="https://github.com/phcurado/zoi/issues/158" class="inline-onebox" rel="noopener nofollow ugc">Zoi + Ecto and Changesets · Issue #158 · phcurado/zoi · GitHub</a></li>
<li>Draft PR: <a href="https://github.com/phcurado/zoi/pull/159" class="inline-onebox" rel="noopener nofollow ugc">add integration with ecto embedded schemas and changeset by phcurado · Pull Request #159 · phcurado/zoi · GitHub</a></li>
</ul>
<p>If you are interested in this integration, feel free to jump in. It’s still an early implementation so feel free to give feedback and suggestions. If you have a codebase you want to validate even better, I can change/adapt things  on the code as need it. It can be extended to generate ecto schemas (not only embeds) if people are interested in that but first good to validate this simpler use case.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="386154" data-batch-url="/posts/batch_likers">
                        6
                      </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/zoi-schema-validation-library-inspired-by-zod/72108/42">Post #41</a>
	                </div>
	            </div>
              <div id="likers-container-386154" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386154"
                     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 #41"></div>
  </section>
</div>
    <div class="postbit" id="386156" data-post-id="386156">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p><a class="mention" href="/u/phcurado" rel="nofollow">@phcurado</a> Awesome, this is what I was hoping for, thanks a lot for starting it.</p>
<p>Just to make it crystal clear: where do you want us to continue the discussion? I checked quickly and I love what I see – there are still gaps that I need, chief among them <code>discriminated_union</code> and <code>extend</code> and <code>pick</code>. And a few more small-ish things.</p>
<p>Where do you want the comments posted? Here? In the GH issue? In the GH PR?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="386156" 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/zoi-schema-validation-library-inspired-by-zod/72108/43">Post #42</a>
	                </div>
	            </div>
              <div id="likers-container-386156" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386156"
                     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 #42"></div>
  </section>
</div>
    <div class="postbit" id="386158" data-post-id="386158">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="phcurado" data-post="42" data-topic="72108">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/phcurado/48/39030_2.png" class="avatar"> phcurado:</div>
<blockquote>
<p>It can be extended to generate ecto schemas</p>
</blockquote>
</aside>
<p>Excellent. I’m interested in this.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="386158" 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/zoi-schema-validation-library-inspired-by-zod/72108/44">Post #43</a>
	                </div>
	            </div>
              <div id="likers-container-386158" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386158"
                     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 #43"></div>
  </section>
</div>
    <div class="postbit" id="386161" data-post-id="386161">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="phcurado" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/phcurado/120/39030_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  phcurado
                    <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>Let’s continue on the issue, I think it will be better because it will be a dedicated thread for this feature. If you prefer the forum in general no probs also.<br>
As for your request, I will think how to add <code>discriminated_union</code> because there is no similar type on Ecto.  Feel free to drop your use cases and I will do my best to fill the gaps and implement 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="386161" 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/zoi-schema-validation-library-inspired-by-zod/72108/45">Post #44</a>
	                </div>
	            </div>
              <div id="likers-container-386161" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386161"
                     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 #44"></div>
  </section>
</div>
    <div class="postbit" id="386204" data-post-id="386204">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Detailed response posted. Let’s continue in there. <a class="mention" href="/u/jam" rel="nofollow">@jam</a> you might want to sub for the GH issue if you want to follow the discussion.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="386204" 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/zoi-schema-validation-library-inspired-by-zod/72108/46">Post #45</a>
	                </div>
	            </div>
              <div id="likers-container-386204" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386204"
                     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 #45"></div>
  </section>
</div>
    <div class="postbit" id="386810" data-post-id="386810">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Opened an LLM-assisted PR with a lot of iteration by me.</p>
<p><a class="mention" href="/u/phcurado" rel="nofollow">@phcurado</a> I have a few follow-up items that seem like gaps in the Zoi API to me. What’s the best channel for us to start discussing them? GitHub issues? Or do you prefer we start here for more community visibility first?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="386810" 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/zoi-schema-validation-library-inspired-by-zod/72108/47">Post #46</a>
	                </div>
	            </div>
              <div id="likers-container-386810" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386810"
                     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 #46"></div>
  </section>
</div>
    <div class="postbit" id="386822" data-post-id="386822">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="phcurado" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/phcurado/120/39030_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  phcurado
                    <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>Sure let’s discuss here, let me know what you found</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="386822" 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/zoi-schema-validation-library-inspired-by-zod/72108/48">Post #47</a>
	                </div>
	            </div>
              <div id="likers-container-386822" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386822"
                     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 #47"></div>
  </section>
</div>
    <div class="postbit" id="386854" data-post-id="386854">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Right, I’ll have one comment for each.</p>
<p>(1) Parsing / validating arrays: no access to partially successful results – needed for emulating <code>Ecto.Changeset</code></p>
<p>TL;DR: when we parse arrays we want the returned list to have valid changesets on <em>every</em> position. Currently <code>Zoi.parse</code> gives us errored out positions only. So if we’re to use the upcoming <code>Zoi.Ecto.errors_to_changeset</code> then we can’t f.ex. repopulate a normal or a LiveView form because the <em>successfully</em> parsed items will come back as empty valid changesets.</p>
<p>I’ve noticed in your own draft PR you are using <code>Zoi.Context</code> which has all the data and I want to update my PR (<span class="hashtag-raw">#162</span>) to use it – but wanted to first ask you: is this a “blessed” / public API one can rely on? If not, can we then have <code>Zoi.parse</code> return a tri-tuple with the last element being what has been successfully parsed so far? Or a recursive two-tuple; anything works really, as long as the data is exposed.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="386854" 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/zoi-schema-validation-library-inspired-by-zod/72108/49">Post #48</a>
	                </div>
	            </div>
              <div id="likers-container-386854" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386854"
                     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 #48"></div>
  </section>
</div>
    <div class="postbit" id="386855" data-post-id="386855">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>(2) Enum values are a joined string and not a list</p>
<p>Currently Zoi gives you this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{"invalid enum value: expected one of %{values}", [type: :enum, values: "USD, EUR, GBP"]}
</code></pre>
<p>To emulate Ecto fully, and to have better way of accessing the underlying enum really, I’d prefer having this instead:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{"invalid enum value: expected one of %{values}", [type: :enum, values: ["USD", "EUR", "GBP"]]}
</code></pre>
<p>Because Ecto usually gives you this error:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">{"is invalid", [validation: :inclusion, enum: ["USD", "EUR", "GBP"]]}
</code></pre>
<p>In my PR I am using <code>String.split</code> to achieve the same but it’s fragile and would break the first time any value has to have a comma inside 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="386855" 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/zoi-schema-validation-library-inspired-by-zod/72108/50">Post #49</a>
	                </div>
	            </div>
              <div id="likers-container-386855" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386855"
                     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 #49"></div>
  </section>
</div>
    <div class="postbit" id="386858" data-post-id="386858">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Probably the one that slowed me down the most:</p>
<p>(3) Zoi produces identical codes for different types</p>
<p>Like this:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">Zoi.integer() |&gt; Zoi.min(1)
code: :greater_than_or_equal_to, issue: {"must be at least %{count}", [count: 1]}

Zoi.string()  |&gt; Zoi.min(3)
code: :greater_than_or_equal_to, issue: {"must have at least %{count} character(s)", [count: 3]}

Zoi.array(x)  |&gt; Zoi.min(1)
code: :greater_than_or_equal_to, issue: {"must have at least %{count} item(s)", [count: 1]
</code></pre>
<p>However, Ecto distinguishes them and that’s IMO clearer:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">validate_number(cs, :age, greater_than_or_equal_to: 1)
[validation: :number, kind: :greater_than_or_equal_to, number: 1]

validate_length(cs, :name, min: 3)
[validation: :length, kind: :min, count: 3, type: :string]

validate_length(cs, :tags, min: 1)
[validation: :length, kind: :min, count: 1, type: :list]
</code></pre>
<p>Can you add something like f.ex. <code>target: :string|:integer|:array</code> so the “size” validation can be programmatically distinguished between integers / strings / arrays (lists)?</p>
<p>In my PR I am using string matching on the validation message Zoi returns but I’d rather really not match on text for this; it’s fragile.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="386858" 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/zoi-schema-validation-library-inspired-by-zod/72108/51">Post #50</a>
	                </div>
	            </div>
              <div id="likers-container-386858" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="386858"
                     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 #50"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/72108/load_more?page=6">Load more posts (5 remaining)</a>
</div></template></turbo-stream>