chazwatkins

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

zachdaniel

Creator of Ash

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

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

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

Where Next?

Popular in Questions Top

sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
JulienCorb
I am trying to implement my new.html.eex file to create new posts on my website. new.html.eex: <h1>Create Post</h1> <%= ...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: The documentation above suggests that while ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29377 241
New
lastday4you
I wanted to check elixir version in phoenix because i found that my elixir is 1.5 but when i use Enum.chunk_by it said the function is un...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43622 214
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36128 110
New
boundedvariable
I am going through the kafka architecture. All the features what the kafka is providing are already in Erlang. I would like hear your opi...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

We're in Beta

About us Mission Statement