dimitarvp
How to express composite primary key? And how to populate virtual field on Repo.get?
Hello all,
I am casually working on, as a hobbyist project, every now and then, a WordPress read-only Elixir viewer. I am working my way through several dumped WP databases and making Ecto schema modules out of their tables.
I stumbled upon this one today:
mysql> desc wp_wfBlockedIPLog;
+-------------+------------------+------+-----+------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+------------------+-------+
| IP | binary(16) | NO | PRI | | |
| countryCode | varchar(2) | NO | | NULL | |
| blockCount | int(10) unsigned | NO | | 0 | |
| unixday | int(10) unsigned | NO | PRI | NULL | |
+-------------+------------------+------+-----+------------------+-------+
4 rows in set (0.01 sec)
Primary question
How can I express a primary key – through the @primary_key attribute, I imagine – for this module?
So far my first try (without the double primary key) is:
defmodule WP.WfBlockedIpLog do
use Ecto.Schema
@primary_key {:id, :binary_id, autogenerate: false, source: :IP}
schema "wp_wfBlockedIPLog" do
field :block_count, :integer, source: :blockCount
field :country_code, :string, source: :countryCode
field :unixday, :integer
field :date, :date, virtual: true # <- Note this for the secondary question.
end
end
Example of a loaded Ecto.Schema:
%WP.WfBlockedIpLog{
__meta__: #Ecto.Schema.Metadata<:loaded, "wp_wfBlockedIPLog">,
block_count: 5,
country_code: "UA",
date: nil,
id: "00000000-0000-0000-0000-ffff2573bf43",
unixday: 17030
}
The above module gives me a string UUID which I am not very happy with. Is there a way to make the ID a true binary?
Secondary question
I realized after inspecting the dumped WP databases that unixday above is basically a date:
17_030
|> Kernel.*(24*60*60)
|> DateTime.from_unix!()
|> DateTime.to_date()
Is there a way to have the date virtual field above be filled at Repo.get, transparently? Or is there a way to do it at all? What alternative approaches would you recommend?
Thank you.
Marked As Solved
fuelen
Hello,
- try just
stringinstead ofbinary_id - obvious solution for me is to have simple helper that will fill virtual fields on demand
def load_virtual_fields(query) do
select_merge(query, [log], %{date: type(fragment("to_timestamp(? * 24*60*60)", log.unixday), :date)})
end
# ...
WfBlockedIpLog
|> load_virtual_fields()
|> ...
|> Repo.get()
Also Liked
Matsa59
It’s not possible to define multiple primary key. But you can set @primary_key to false and then define the option primary_key to true on your fields IP and unixday. Everything is well explains in the doc @fuelen sent, at the bottom.
In your case it will be
defmodule WP.WfBlockedIpLog do
use Ecto.Schema
@primary_key false
schema "wp_wfBlockedIPLog" do
field :ip, :binary, primary_key: true
field :unixday, :integer, primary_key: true
field :block_count, :integer, source: :blockCount
field :country_code, :string, source: :countryCode
field :date, :date, virtual: true # <- Note this for the secondary question.
end
end
(Write with my phone so may contains some errors).
akashv
You can set multiple fields as primary key.
Matsa59
What do you mean?
You can use ˋget_byand for preloads define your own function that use customjoin`.







