chazwatkins
Is it possible to define structs at runtime
I’m considering writing an integration with Salesforce. Salesforce has SObjects of various types like Case, Quote, Lead, CustomObject__c, etc. These SObjects are like database tables with their own schemas. I’d like to convert the JSON responses I get back from Salesforce into structs that represent the SObject type. For example, %Case{}, %Quote{} instead of something more generic and known at compile time like %SObject{type: "Case"}. There are hundreds of SObject types, so defining them all isn’t reasonable and wouldn’t cover custom SObjects or custom SObject fields not provided by Salesforce itself.
Is there any way to define structs at runtime to achieve something like %{SObjectName}{}?
Most Liked
zachdaniel
For folks looking to do something similar in the future, my suggestion here would be to dump some representation (ideally a json schema) of the salesforce objects into a file, and then derive your structs from that at compile time. Then, rebuild and redeploy as necessary. If you actually need these structs, of course
I agree with @D4no0 and @sodapopcan that in this case you’re not getting any benefit from dynamic runtime struct definition, in exchange for “weirdness” later down the line.
If what you’re looking for is something syntactic to signal that you’re operating on a salesforce object of X type, or to pattern match on that in some interesting or novel way, consider a macro. To be clear, I’m not suggesting that you do this necessarily, just showing that you don’t need structs to get customized pattern matching. Elixir has effectively all the facilities you need to modify the language.
defmodule SObject do
defstruct [:type, data: %{}]
defmacro so({:%, _, [type, {:%{}, meta, keys]}) do
string_keys =
Enum.map(keys, fn {key, value} ->
{to_string(key), value}
end)
contents_with_string_keys = {:%{}, meta, keys}
quote do
%SObject{type: unquote(to_string(type)), data: unquote(contents_with_string_keys)}
end
end
end
Then you can do this kind of thing
defmodule SomeModule do
import SObject
def do_something(so(%Case{number: case_number})) do
case_number
end
end
That all works without ever having to turn salesforce data from strings to atoms. You could then build in a known set of fields that exist for certain builtin objects (or don’t exist) and validate that at compile time with your macro.
Whether you ultimately want to use something like this is 100% up to you, but the main point I want to get across is that, with macros, you can often approach syntax that you like, without having to sacrifice how the underlying system works.
D4no0
It highly depends on what you are looking for, first of all ecto can be used without a database, and it is widely used for data validation. In your case, from what I understand the protocol defines the type of the structure in one of its fields.
As long as you can define those types in your codebase, you can always use ecto + polymorphic embed.
VOUwCNOD
Yes, you can create structs in runtime. Consider this code
def create_struct(name, fields) do
defmodule name do
defstrcut fields
end
end
This is a dark magic, but there is no need to limit yourself, be expressive, break laws, make people be afraid of yourself and make them treat your code with fear and respect.
To match on such structs in runtime, consider something like
name = Case
create_struct(name, [x: 1, y: 2])
...
case something do
%^name{} ->
...
end
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









