ivanrublev / domo Goto Github PK
View Code? Open in Web Editor NEWA library to validate values of nested structs with their type spec t() and associated precondition functions
License: MIT License
A library to validate values of nested structs with their type spec t() and associated precondition functions
License: MIT License
** (MatchError) no match of right hand side value: {:"::", [], [{:t, [], []}, {:t, [line: 50], [{:module, [line: 50], []}]}]}
(domo 1.3.3) lib/domo/type_ensurer_factory.ex:37: Domo.TypeEnsurerFactory.collect_types_for_domo_compiler/3
(elixir 1.12.2) lib/enum.ex:930: Enum."-each/2-lists^foreach/1-0-"/2
(domo 1.3.3) lib/mix/tasks.compile.domo_compiler.ex:73: Mix.Tasks.Compile.DomoCompiler.build_ensurer_modules/2
(domo 1.3.3) lib/mix/tasks.compile.domo_compiler.ex:57: Mix.Tasks.Compile.DomoCompiler.run/1
(mix 1.12.2) lib/mix/task.ex:394: anonymous fn/3 in Mix.Task.run_task/3
(mix 1.12.2) lib/mix/tasks/compile.all.ex:92: Mix.Tasks.Compile.All.run_compiler/2
(mix 1.12.2) lib/mix/tasks/compile.all.ex:72: Mix.Tasks.Compile.All.compile/4
(mix 1.12.2) lib/mix/tasks/compile.all.ex:59: Mix.Tasks.Compile.All.with_logger_app/2
Compiles
Hello and thanks for this library. I very much appreciate the effort and time you have put into this library.
I have a question. Is there a way to avoid the default values validation during the compilation?
I do not need default values; So I have defined the struct with default nil values for each attribute. But the type I have defined includes some mandatory attributes. I received the error "Invalid value nil for field :name of %TestApp.User{}. Expected the value matching the <<::*8>> type." during the compilation.
I want only to validate data during the struct creation. I do not need to validate the default values because they can be incomplete, like in my case.
Thank you for your answer.
Hey, thanks for this great library!
Is support for @opaque
types in precond
macro on the roadmap by any chance?
Example:
defmodule User do
use Domo
# No errors when using usual @type
# @type id :: String.t()
# Error when using @opaque type
@opaque id :: String.t()
precond id: &validate_id/1
@type t :: %__MODULE__{id: id()}
@enforce_keys [:id]
defstruct [:id]
defp validate_id(""), do: {:error, "can't be empty"}
defp validate_id(_id), do: :ok
end
This throws the following compilation error:
** (FunctionClauseError) no function clause matching in anonymous fn/1 in Domo._plan_precond_checks/2
The following arguments were given to anonymous fn/1 in Domo._plan_precond_checks/2:
# 1
{:opaque, {:id, {:remote_type, 8, [{:atom, 0, String}, {:atom, 0, :t}, []]}, []}}
(domo 1.2.9) lib/domo.ex:562: anonymous fn/1 in Domo._plan_precond_checks/2
(elixir 1.12.3) lib/enum.ex:1582: Enum."-map/2-lists^map/1-0-"/2
(domo 1.2.9) lib/domo.ex:562: Domo._plan_precond_checks/2
(stdlib 3.16) lists.erl:1267: :lists.foldl/3
(stdlib 3.16) erl_eval.erl:685: :erl_eval.do_apply/6
If I remove the precond
line, I have no errors, even with the @opaque
type.
When removing/renaming a module that is using Domo, a mix clean
is necessary to avoid compilation errors.
I think the problem is somewhere around loading of the BEAM types in ModuleInspector.beam_types/1
.
For some reason CodeEvaluation.in_mix_compile?()
evaluates to false
, resulting in a call to ResolvePlanner.get_types/2
, which doesn't work.
Renaming and removing modules should not require cleaning.
could not compile dependency :XXX, "mix compile" failed. Errors may have been logged above. You can recompile this dependency with "mix deps.compile XXX", update it with "mix deps.update XXX" or clean it with "mix deps.clean XXX"
** (exit) exited in: GenServer.call(Domo.TypeEnsurerFactory.ResolvePlanner, {:get_types, XXX.Shared.UUID}, 5000)
** (EXIT) no process: the process is not alive or there's no process currently associated with the given name, possibly because its application isn't started
(elixir 1.14.0) lib/gen_server.ex:1027: GenServer.call/3
(domo 1.5.10) lib/domo/type_ensurer_factory/module_inspector.ex:40: Domo.TypeEnsurerFactory.ModuleInspector.beam_types_hash/1
(domo 1.5.10) lib/domo/type_ensurer_factory/dependency_resolver.ex:82: anonymous fn/1 in Domo.TypeEnsurerFactory.DependencyResolver.get_dependant_module_hashes/1
(elixir 1.14.0) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(elixir 1.14.0) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(domo 1.5.10) lib/domo/type_ensurer_factory/dependency_resolver.ex:81: Domo.TypeEnsurerFactory.DependencyResolver.get_dependant_module_hashes/1
(domo 1.5.10) lib/domo/type_ensurer_factory/dependency_resolver.ex:16: Domo.TypeEnsurerFactory.DependencyResolver.maybe_recompile_depending_structs/3
(domo 1.5.10) lib/domo/type_ensurer_factory.ex:349: Domo.TypeEnsurerFactory.recompile_depending_structs/4
First of all: thanks a lot for this great library.
Here is the issue: I defined a module like this:
defmodule DomoTest.Schema do
use Domo
use TypedStruct
typedstruct enforce: true do
field(:one, String.t())
field(:two, boolean())
field(:three, integer())
end
end
When running iex -S mix
the library works as expected:
iex> DomoTest.Schema.new(%{one: "aaa", two: 23, three: false})
{:error,
[
two: "Invalid value 23 for field :two of %DomoTest.Schema{}. Expected the value matching the false | true type.",
three: "Invalid value false for field :three of %DomoTest.Schema{}. Expected the value matching the integer() type."
]}
But when running the phoenix server in development mode the library doesn't work as expected:
DomoTest.Schema.new(%{one: "aaa", two: 23, three: false})
{:ok, %DomoTest.Schema{one: "aaa", three: false, two: 23}}
I created a minimal repository to replicate the issue. The creation of the struct happens in page_controller.ex
.
Note however that if I start the phoenix app with MIX_ENV=prod
domo starts to do its job and for the exact same code returns:
{:error,
[
two: "Invalid value 23 for field :two of %DomoTest.Schema{}. Expected the value matching the false | true type.",
three: "Invalid value false for field :three of %DomoTest.Schema{}. Expected the value matching the integer() type."
]}
I expect a consistent behavior, with runtime checks executed in development.
Thank you.
When exporting a test coverage report, the command seemingly fails due to missing *.TypeEnsurer
Module Code.
domo/example_avialia on ๎ master is ๐ฆ v0.1.0 via ๐ง v1.13.3 (OTP 24)
โฏ mix test.coverage --export-coverage
... a lot of output ...
** (MatchError) no match of right hand side value: {:error, {:no_source_code_found, ExampleAvialia.Boardings.Passenger.TypeEnsurer}}
(mix 1.13.3) lib/mix/tasks/test.coverage.ex:290: anonymous fn/3 in Mix.Tasks.Test.Coverage.html/2
(elixir 1.13.3) lib/enum.ex:2396: Enum."-reduce/3-lists^foldl/2-0-"/3
(mix 1.13.3) lib/mix/tasks/test.coverage.ex:289: Mix.Tasks.Test.Coverage.html/2
(mix 1.13.3) lib/mix/task.ex:397: anonymous fn/3 in Mix.Task.run_task/3
(mix 1.13.3) lib/mix/cli.ex:84: Mix.CLI.run_task/2
domo/example_avialia on ๎ master is ๐ฆ v0.1.0 via ๐ง v1.13.3 (OTP 24)
โฏ mix test.coverage --export-coverage
warning: use Mix.Config is deprecated. Use the Config module instead
config/config.exs:8
warning: use Mix.Config is deprecated. Use the Config module instead
config/test.exs:1
13:24:13.899 [info] The function passed as a handler with ID {Phoenix.Logger, [:phoenix, :channel_handled_in]} is a local function.
This means that it is either an anonymous function or a capture of a function without a module specified. That may cause a performance penalty when calling that handler. For more details see the note in `telemetry:attach/4` documentation.
https://hexdocs.pm/telemetry/telemetry.html#attach/4
13:24:13.910 [info] The function passed as a handler with ID {Phoenix.Logger, [:phoenix, :channel_joined]} is a local function.
This means that it is either an anonymous function or a capture of a function without a module specified. That may cause a performance penalty when calling that handler. For more details see the note in `telemetry:attach/4` documentation.
https://hexdocs.pm/telemetry/telemetry.html#attach/4
13:24:13.910 [info] The function passed as a handler with ID {Phoenix.Logger, [:phoenix, :endpoint, :start]} is a local function.
This means that it is either an anonymous function or a capture of a function without a module specified. That may cause a performance penalty when calling that handler. For more details see the note in `telemetry:attach/4` documentation.
https://hexdocs.pm/telemetry/telemetry.html#attach/4
13:24:13.910 [info] The function passed as a handler with ID {Phoenix.Logger, [:phoenix, :endpoint, :stop]} is a local function.
This means that it is either an anonymous function or a capture of a function without a module specified. That may cause a performance penalty when calling that handler. For more details see the note in `telemetry:attach/4` documentation.
https://hexdocs.pm/telemetry/telemetry.html#attach/4
13:24:13.910 [info] The function passed as a handler with ID {Phoenix.Logger, [:phoenix, :error_rendered]} is a local function.
This means that it is either an anonymous function or a capture of a function without a module specified. That may cause a performance penalty when calling that handler. For more details see the note in `telemetry:attach/4` documentation.
https://hexdocs.pm/telemetry/telemetry.html#attach/4
13:24:13.910 [info] The function passed as a handler with ID {Phoenix.Logger, [:phoenix, :router_dispatch, :start]} is a local function.
This means that it is either an anonymous function or a capture of a function without a module specified. That may cause a performance penalty when calling that handler. For more details see the note in `telemetry:attach/4` documentation.
https://hexdocs.pm/telemetry/telemetry.html#attach/4
13:24:13.910 [info] The function passed as a handler with ID {Phoenix.Logger, [:phoenix, :socket_connected]} is a local function.
This means that it is either an anonymous function or a capture of a function without a module specified. That may cause a performance penalty when calling that handler. For more details see the note in `telemetry:attach/4` documentation.
https://hexdocs.pm/telemetry/telemetry.html#attach/4
Domo will treat the following types as any() globally: Ecto.Schema.Metadata.t()
Domo is compiling type ensurer for 0 module (.ex)
Importing cover results: cover/html.coverdata
Percentage | Module
-----------|--------------------------
0.00% | ExampleAvialia.Boardings.Passenger.TypeEnsurer
0.00% | ExampleAvialia.Cargos.Measurement.TypeEnsurer
0.00% | ExampleAvialia.Cargos.Shipment.TypeEnsurer
0.00% | ExampleAvialia.Cargos.ShipmentDocument
0.00% | ExampleAvialia.Cargos.ShipmentDocument.TypeEnsurer
0.00% | ExampleAvialia.Cargos.ShipmentWeight
0.00% | ExampleAvialia.DataCase
0.00% | ExampleAvialia.SharedKernel
0.00% | ExampleAvialiaWeb
0.00% | ExampleAvialiaWeb.ChannelCase
6.67% | ExampleAvialia.Cargos.Shipment
16.67% | ExampleAvialia.Cargos.ShipmentKind
20.00% | ExampleAvialia.Cargos
20.00% | ExampleAvialiaWeb.ErrorHelpers
25.00% | ExampleAvialia.Boardings.Passenger
27.45% | ExampleAvialiaWeb.PageController
33.33% | ExampleAvialia.Cargos.Measurement
37.50% | ExampleAvialiaWeb.Router
50.00% | ExampleAvialia.BoardingsRepo
50.00% | ExampleAvialia.CargosRepo
50.00% | ExampleAvialiaWeb.LayoutView
50.00% | ExampleAvialiaWeb.PageView
55.56% | ExampleAvialia.Boardings
66.67% | ExampleAvialiaWeb.ErrorView
75.00% | ExampleAvialia.Application
100.00% | ExampleAvialia
100.00% | ExampleAvialia.TaggedTupleEctoType
100.00% | ExampleAvialiaWeb.ConnCase
100.00% | ExampleAvialiaWeb.Endpoint
100.00% | ExampleAvialiaWeb.Router.Helpers
-----------|--------------------------
13.44% | Total
Coverage test failed, threshold not met:
Coverage: 13.44%
Threshold: 90.00%
** (MatchError) no match of right hand side value: {:error, {:no_source_code_found, ExampleAvialia.Boardings.Passenger.TypeEnsurer}}
(mix 1.13.3) lib/mix/tasks/test.coverage.ex:290: anonymous fn/3 in Mix.Tasks.Test.Coverage.html/2
(elixir 1.13.3) lib/enum.ex:2396: Enum."-reduce/3-lists^foldl/2-0-"/3
(mix 1.13.3) lib/mix/tasks/test.coverage.ex:289: Mix.Tasks.Test.Coverage.html/2
(mix 1.13.3) lib/mix/task.ex:397: anonymous fn/3 in Mix.Task.run_task/3
(mix 1.13.3) lib/mix/cli.ex:84: Mix.CLI.run_task/2
I'd expect the coverage export to not fail.
From the top of my head, I could imagine multiple ways to attempt a solution:
TypeEnsurer
Modules to the ignore_modules
List of the test_coverage
configTypeEnsurer
's to easily ignore them, maybe including an example as part of the setup guideFor now we are going to manually manage the ignore_modules
List, which prevents the error but is an extra burden to remember for every Module we setup to use Domo.
If there is anything we can do to help implement a solution you think to be maintainable, we'd be happy to help out.
When I want to compile deps, it shows me this error
Domo makes type ensures for standard lib modules Date, Date.Range, DateTime, File.Stat, File.Stream, GenEvent.Stream, IO.Stream, Macro.Env, NaiveDateTime, Range, Regex, Task, Time, URI, Version.
Domo is compiling type ensurer for 15 modules (.ex)
== Compilation error in file lib/compile_stdlib_type_ensurers.ex ==
** (File.Error) could not write to file "/Users/shahryar/Documents/Programming/Elixir/mishka_pub/_build/dev/lib/domo/.mix/resolved_stdlib_types.domo": no such file or directory
(elixir 1.15.0) lib/file.ex:1117: File.write!/3
lib/compile_stdlib_type_ensurers.ex:30: (file)
(elixir 1.15.0) lib/kernel/parallel_compiler.ex:377: anonymous fn/5 in Kernel.ParallelCompiler.spawn_workers/8
could not compile dependency :domo, "mix compile" failed. Errors may have been logged above. You can recompile this dependency with "mix deps.compile domo --force", update it with "mix deps.update domo" or clean it with "mix deps.clean domo"
First of all, this library is an amazing work. Having worked with a few type-related libraries on Elixir of my own, I know how hard it is to pull something like this. I started evaluating using Domo to validate some complex nested structures here at work but found a problem that makes using it a little bit harder. I have found a workaround, so nothing is blocking us.
This might not be necessarily a bug or an issue (it can be just that this is a known limitation and no plans to fixing it exist due to the complexity), it is more a conversation starter sharing some of my experience using it.
Currently, whenever we have a type [a | b]
Domo treats it as [a] | [b]
.
Note: For me, this was not totally clear from the docs, but maybe it is the same as the limitation regarding parametric types?
That is, the following data structure
def Apple do
use Domo
defstruct []
@type t() :: %__MODULE__{}
end
def Orange do
use Domo
defstruct []
@type t() :: %__MODULE__{}
end
def FruitBasket do
use Domo
defstruct [fruits: []]
@type t() :: %__MODULE__{fruits: [Apple.t() | Orange.t()]}
end
Will result in
assert {:ok, _} = FruitBasket.ensure_type(%FruitBasket{fruits: [%Apple{}, %Apple{}]})
assert {:ok, _} = FruitBasket.ensure_type(%FruitBasket{fruits: [%Orange{}, %Orange{}]})
assert {:error, _} = FruitBasket.ensure_type(%FruitBasket{fruits: [%Apple{}, %Orange{}]})
My current workaround is to do this weird thing (I'm actually doing something slightly different to propagate the errors, but it is similar):
# Apple and Orange the same
defmodule FruitValidator do
use Domo
defstruct [:fruit]
@type t() :: %__MODULE__{fruit: Apple.t() | Orange.t()}
def valid?(fruit) do
case ensure_type(%__MODULE__{fruit: fruit}) do
{:ok, _} -> true
_ -> false
end
end
end
def FruitBasket do
use Domo
defstruct [fruits: []]
@opaque fruit() :: map()
precond(fruit: &FruitValidator.valid?/1)
@type t() :: %__MODULE__{fruits: [fruit()]}
end
So, in the end I'm almost just using Domo underneath but the ergonomics are just much worse. Is that something you think is easily integrated into Domo itself? Do you have a better suggestion on how to deal with this?
Hey, thanks for this great library!
I was wondering if you would consider implementing an API more aligned with Elixir style, such as below:
new/2
for new_ok/2
ensure_type/2
for ensure_type_ok/2
This would allow to have an API in the shape of function!/1
and function/2
instead of function!/1
and function_ok/2
, which I guess would be more aligned with Elixir coding guidelines.
Example : Ecto.insert/2
I can open a PR if you'd like.
Dear Elixir experts,
The main idea of the library is to add shape to fields of the structs to make these pieces of data to flow through the app consistently.
It'd be great if you have a look at the library and the example application within the repo and give feedback in the comments to this issue:
Code review is welcome, please, open a PR or a new issue in this repo.
If you've found a bug, please, open a new issue.
Hello I'm using your package in my project. I updated the package and now it's causing compilation error in ElixirLS.
== Compilation error in file lib/compile_stdlib_type_ensurers.ex ==
** (exit) an exception was raised:
** (CaseClauseError) no case clause matching: {:atom, [closing: [line: 355, column: 51], column: 46], []}
lib/domo/type_ensurer_factory/generator/match_fun_registry/literals.ex:60: Domo.TypeEnsurerFactory.Generator.MatchFunRegistry.Literals.guard_quoted/3
lib/domo/type_ensurer_factory/generator/match_fun_registry/literals.ex:42: Domo.TypeEnsurerFactory.Generator.MatchFunRegistry.Literals.match_spec_function_quoted/1
lib/domo/type_ensurer_factory/generator/match_fun_registry.ex:70: Domo.TypeEnsurerFactory.Generator.MatchFunRegistry.put_match_fun_if_missing/2
lib/domo/type_ensurer_factory/generator/match_fun_registry.ex:39: Domo.TypeEnsurerFactory.Generator.MatchFunRegistry.handle_call/3
(stdlib 3.17) gen_server.erl:721: :gen_server.try_handle_call/4
(stdlib 3.17) gen_server.erl:750: :gen_server.handle_msg/6
(stdlib 3.17) proc_lib.erl:226: :proc_lib.init_p_do_apply/3
[Warn - 13:40:55] could not compile dependency :domo, "mix compile" failed. Errors may have been logged above. You can recompile this dependency with "mix deps.compile domo", update it with "mix deps.update domo" or clean it with "mix deps.clean domo"
Hi guys, thanks for the fantastic library. It rocks!
Recently I'm struggling with {:type_not_found, {PolymorphicEmbed, "t", "PolymorphicEmbed.t()"}
error when using polymorphic_embed library and typed_ecto_schema.
It should be reproducible with the code below on livebook
Mix.install([
{:domo, "~> 1.5"},
{:typed_ecto_schema, "~> 0.4.1"},
{:polymorphic_embed, "~> 3.0"}
])
defmodule Foo do
use Domo, skip_defaults: true
use TypedEctoSchema
import PolymorphicEmbed
typed_schema "todos" do
field(:content, :string)
field(:title, :string)
polymorphic_embeds_one(:form,
types: [
product_form: Todos.ProductForm
],
on_type_not_found: :raise,
on_replace: :update
)
end
end
Any suggestions to solve the issue?
I believe it's not possible to define the type from external library (PolymorphicEmbed in this case)
Get this error warning when using validate_type
for a schema with embeds_many
.warning: attempting to determine the presence of embed_many field :forms with validate_required/3 or field_missing?/2 which has no effect. You can pass the :required option to Ecto.Changeset.cast_embed/3 to achieve this
schema "todos" do
embeds_many :forms, Form
end
def changeset(todo, attrs) do
todo
|> cast_embed(:forms)
|> validate_type()
end
No warning
warning: attempting to determine the presence of embed_many field :forms with validate_required/3 or field_missing?/2 which has no effect. You can pass the :required option to Ecto.Changeset.cast_embed/3 to achieve this.
(ecto 3.10.3) lib/ecto/changeset.ex:2396: Ecto.Changeset.field_missing?/2
(ecto 3.10.3) lib/ecto/changeset.ex:2354: anonymous fn/4 in Ecto.Changeset.validate_required/3
(elixir 1.14.5) lib/enum.ex:2468: Enum."-reduce/3-lists^foldl/2-0-"/3
(ecto 3.10.3) lib/ecto/changeset.ex:2353: Ecto.Changeset.validate_required/3
(domo 1.5.13) lib/domo/changeset.ex:160: Domo.Changeset.validate_schemaless_type/3
(design_sync 0.1.0) lib/design_sync_web/components/organisms/todo_detail_component.ex:342: DesignSyncWeb.Organisms.TodoDetailComponent.handle_event/3
(phoenix_live_view 0.19.5) lib/phoenix_live_view/channel.ex:630: anonymous fn/4 in Phoenix.LiveView.Channel.inner_component_handle_event/4
(telemetry 1.2.1) /Users/dr_selump14/schueco-dev/repos/design_sync/deps/telemetry/src/telemetry.erl:321: :telemetry.span/3
(phoenix_live_view 0.19.5) lib/phoenix_live_view/diff.ex:204: Phoenix.LiveView.Diff.write_component/4
(phoenix_live_view 0.19.5) lib/phoenix_live_view/channel.ex:553: Phoenix.LiveView.Channel.component_handle_event/6
(stdlib 4.2) gen_server.erl:1123: :gen_server.try_dispatch/4
(stdlib 4.2) gen_server.erl:1200: :gen_server.handle_msg/6
(stdlib 4.2) proc_lib.erl:250: :proc_lib.wake_up/3
Is there a way to compose multiple preconditions in a type?
@type non_empty_string :: String.t()
precond non_empty_string: &is_not_nil?/1
precond non_empty_string: &is_not_blank?/1
https://github.com/Exadra37/elixir-library-domo-bug
$ ./bin/tasks remote
Erlang/OTP 23 [erts-11.1.6] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1]
Interactive Elixir (1.11.3) - press Ctrl+C to exit (type h() ENTER for help)
$ mix deps | grep domo | head -1
* domo 1.0.1 (Hex package) (mix)
$ mix deps | grep typed_struct | head -1
* typed_struct 0.2.1 (Hex package) (mix)
I run it in development and in production with the docker image from the Phoenix releases docs:
https://hexdocs.pm/phoenix/releases.html#containers
Versions used to build the docker image:
ELIXIR_VERSION=1.11.3
ERLANG_OTP_VERSION=23.2.2
ALPINE_VERSION=3.12.1
The error from a production release:
09:20:32.459 | error | module=gen_server function=error_info/7 line=943 | GenServer #PID<0.2551.0> terminating
app_1 | ** (UndefinedFunctionError) function Mix.Compilers.ApplicationTracer.trace/2 is undefined (module Mix.Compilers.ApplicationTracer is not available)
app_1 | Mix.Compilers.ApplicationTracer.trace({:alias_reference, [line: 45], NaiveDateTime}, #Macro.Env<aliases: [], context: nil, context_modules: [TypeIt.Progress], file: "/app/lib/type_it/lib/progress.ex", function: nil, functions: [{Kernel, [!=: 2, !==: 2, *: 2, ...]}], lexical_tracker: #PID<3.316.0>, line: 42, macro_aliases: [], macros: [{Domo, ...}, {...}], module: TypeIt.Progress, requires: [...], ...>)
app_1 | (elixir 1.11.3) src/elixir_env.erl:36: :elixir_env."-trace/2-lc$^0/1-0-"/3
app_1 | (elixir 1.11.3) src/elixir_env.erl:36: :elixir_env.trace/2
app_1 | (elixir 1.11.3) lib/macro.ex:1440: Macro.do_expand_once/2
app_1 | (elixir 1.11.3) lib/macro.ex:1610: Macro.expand_until/2
app_1 | (domo 1.0.1) lib/domo/type_spec_matchable/remote_type.ex:11: Domo.TypeSpecMatchable.RemoteType.expand/2
app_1 | (domo 1.0.1) lib/domo/type_contract.ex:642: Domo.TypeSpecMatchable.Any.match_spec?/3
app_1 | (tasks 0.1.0) lib/type_it/lib/progress.ex:42: TypeIt.Progress.TypeChecker.__field_error/1
The Typed Struct code:
defmodule TypeIt.Progress do
use Domo
@all_states %{
backlog: "Backlog",
todo: "Todo",
doing: "Doing",
pending: "Pending",
done: "Done",
archived: "Archived",
}
@states Map.keys(@all_states)
typedstruct do
field :state, :backlog | :todo | :doing | :pending | :done | :archived
field :title, String.t()
field :since, NaiveDateTime.t()
end
def default(), do: new_for!(:todo)
def next_state(:backlog), do: :todo
def next_state(:todo), do: :done
def next_state(:done), do: :todo
def new_for!(state), do: new!(state: state, title: @all_states[state], since: NaiveDateTime.utc_now())
def new_for!(state, since: since), do: new!(state: state, title: @all_states[state], since: since)
def new_for!(state, title: title), do: new!(state: state, title: title, since: NaiveDateTime.utc_now())
def states() do
@states
end
def all() do
@all_states
end
end
In production is throwing the reported error that crashes the app, but in development it works ok.
This is a question, not a bug report.
I'm playing with Domo
for the first time (in combination with TypedStruct
) and it looks nice, but I'm immediately running into a use case that I don't see documented.
This is the code I wanted to port. Like you can see, my new
functions generates a random token on construction. Can Domo
do this as well? If so, how would I do it?
defmodule Foo do
use TypedStruct
typedstruct opaque: true do
field :id, non_neg_integer, enforce: true
field :token, String.t(), enforce: true
end
def new(id) do
%Foo{id: id, token: random_string(8)}
end
defp random_string(length),
do: :crypto.strong_rand_bytes(length) |> Base.encode64() |> binary_part(0, length)
end
Maybe I should not use Domo
here, because I do the construction myself, but then I loose all other nice things as well.
Hi. Love this library, thank you. I'm trying to use it with a commanded project, and spotted the example linked in your documentation.
Is it (still) possible to use domo with types that are defined outside of a struct? I saw this line in the example and I've been trying to get something similar to work.
This repo shows the behaviour I'm seeing - running my test or the dialyzer appears to succeed the first time, will fail the second time, and then won't start at all the third or subsequent times.
I'm new to typespecs and this library, so forgive me if I've missed something obvious. If this is a regression, l'm happy to help but would need a little guidance :)
I try to use now the library for the first time and I really like the idea.
I am using it together with TypedStruct and see some weird behaviour in the tests
I have a module like (simplified)
defmodule Entity do
use TypedStruct
use Domo
typedstruct do
field :meta, map(), default: %{}, enforce: true
end
def config(data) do
config = %{meta: data.meta}
Entity.new!(config)
end
end
In the iex console all works as expected, but when running the tests, I noticed some type inconsistencies. So I did a test.
I modified the typedstruct to take a wrong type
typedstruct do
field :meta, String.t(), default: %{}, enforce: true
end
Again. In the console, running something like Entity.config(%{meta: %{k: :v}}) would fail, trying to respect the new String.t()
Invalid value %{hello: 1} for field :meta of %Faktor.Entity{}. Expected the value matching the <<_::_*8>> type.
But in tests, no change, all tests pass, and they are passing maps to the meta.
Expected the tests to fail when the type is not valid
Is there anything I'm missing regarding running tests?
When I try to have a struct with - let's say - Decimal in it. I get the the message:
** Domo.TypeEnsurerFactory.Resolver failed to resolve fields type of the ****** struct due to "Consider to use Domo in Decimal struct for validation speed.
If you don't own the struct you can define custom user type and validate fields in the precondition function attached like the following:
@type unowned_struct :: term()
precond unowned_struct: &validate_unowned_struct/1
def validate_unowned_struct(value) do
case value do
%Decimal{} -> ...validate fields here...
_ -> {:error, \"expected Decimal struct value.\"}
end
end
".
This is clear - but when I try to do it like that I get the error, that I cannot put a precond at a term:
== Type ensurer compilation error in file lib/purchase.ex ==
** Domo.TypeEnsurerFactory.Resolver failed to resolve fields type of the ***** struct due to "Precondition for value of term() type is not allowed.".
Get a hint, who I can get the same behaviour like in 1.3.1
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.