Code Monkey home page Code Monkey logo

domo's People

Contributors

basilenouvellet avatar graupe avatar idabmat avatar kianmeng avatar xpgdk avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

domo's Issues

Domo Compiler tripped up by Ecto.Schema.Metadata type

Environment

  • Elixir version (elixir -v): Erlang/OTP 24 [erts-12.0.3] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit] Elixir 1.12.2 (compiled with Erlang/OTP 24)
  • Domo version (mix deps | grep domo | head -1): locked at 1.3.3 (domo) 10374b4a
  • TypedStruct version (mix deps | grep typed_struct | head -1): not present

Actual behavior

** (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

Expected behavior

Compiles

Is there a way to avoid the default values validation during the compilation?

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.

Support for `@opaque` types in `precond`

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.

Renaming/Removing modules requires a clean build

Environment

  • Elixir version (elixir -v): 1.14.0
  • Domo version (mix deps | grep domo | head -1): 1.5

Actual behavior

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.

Expected behavior

Renaming and removing modules should not require cleaning.

Verbose output

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

Runtime checks are not executed in development

Environment

  • Elixir version: 1.13.4
  • Domo version: 1.5.3
  • TypedStruct version: 0.3.0

Actual behavior

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."
 ]}

Expected behavior

I expect a consistent behavior, with runtime checks executed in development.

Thank you.

mix test.coverage --export-coverage fails

Environment

  • Elixir version (elixir -v): 1.13.3
  • Domo version (mix deps | grep domo | head -1): master
  • TypedStruct version (mix deps | grep typed_struct | head -1): N/A

Actual behavior

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

Full Log (click to expand)
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

Expected behavior

I'd expect the coverage export to not fail.

From the top of my head, I could imagine multiple ways to attempt a solution:

  • have the source code available to the coverage task
  • or to add the TypeEnsurer Modules to the ignore_modules List of the test_coverage config
  • or provide a Function to get a list of all the TypeEnsurer's to easily ignore them, maybe including an example as part of the setup guide

For 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.

no such file or directory error in deps.compile

Environment

  • Elixir version (elixir -v): 1.15
  • Erlang: OTP 26
  • Domo version (mix deps | grep domo | head -1): 1.5.12

Actual behavior

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"

How to properly represent [a | b]?

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?

Implement an API more aligned with Elixir style

Hey, thanks for this great library!

I was wondering if you would consider implementing an API more aligned with Elixir style, such as below:

  • adding an alias new/2 for new_ok/2
  • adding an alias 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.

Reviews and general feedback

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:

  • How do you feel about the idea?
  • What is done well and can be done even better?

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.

Domo is causing compilation error in ElixirLS

Environment

  • Elixir version (elixir -v). 13.4
  • Domo version (mix deps | grep domo | head -1): 1.5.8

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"

Difficulty working with TypedEctoSchema and PolymorphicEmbed

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 warning on `validate_type` for embed_many

Environment

  • Elixir version (elixir -v): 1.14.5
  • Domo version (mix deps | grep domo | head -1): 1.15.13

Actual behavior

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

Expected behavior

No warning

Verbose output

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

Compose preconditions?

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

Production Release: Function Mix.Compilers.ApplicationTracer.trace/2 is undefined

Proof of Concept

https://github.com/Exadra37/elixir-library-domo-bug

Environment

  • Elixir version (elixir -v):
$ ./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)
  • Domo version (mix deps | grep domo | head -1):
$ mix deps | grep domo | head -1
* domo 1.0.1 (Hex package) (mix)
  • TypedStruct version (mix deps | grep typed_struct | head -1):
$ 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

Actual behavior

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

Expected behavior

In production is throwing the reported error that crashes the app, but in development it works ok.

Default values vs custom constructors

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.

Possible to use Domo with types defined not in a struct?

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 :)

Ensure types for TypedStruct in Tests

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

Environment

  • Elixir version (elixir -v): 1.12.3
  • Domo version (mix deps | grep domo | head -1): 1.3.4
  • TypedStruct version (mix deps | grep typed_struct | head -1): 0.2.1

Actual behavior

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 behavior

Expected the tests to fail when the type is not valid

Is there anything I'm missing regarding running tests?

unowned structs cannot be compiled

Environment

  • Elixir version (elixir -v): 1.12.3
  • Domo version (mix deps | grep domo | head -1): 1.3.2
  • TypedStruct version (mix deps | grep typed_struct | head -1): 2.0.1

Actual behavior

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.".

Expected behavior

Get a hint, who I can get the same behaviour like in 1.3.1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.