Created
January 7, 2021 16:37
-
-
Save leikind/5574e1f2d40aeee239959b337c416df9 to your computer and use it in GitHub Desktop.
some ETS features
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
test "ets match, select, and select_delete" do | |
ets_table_name = :bar | |
:ets.new(ets_table_name, [:named_table, :set, :private]) | |
expires_at1 = ~U[2021-01-07 15:00:00.000000Z] | |
# ~U is just a syntax sugar for struct DateTime | |
IO.inspect(~U[2021-01-07 15:00:00.000000Z], structs: false) | |
# I would convert DateTime to unix seconds and put it as a separate field to the ets record | |
# just for selecting expired records | |
expires_at1_unix = DateTime.to_unix(expires_at1) | |
token_login1 = %RemoteLogin.Models.TokenLogin{ | |
encrypted_keystore_token: "encrypted_keystore_token1", | |
encrypted_pdk: "encrypted_pdk1", | |
encrypted_vault_token: "encrypted_vault_token1", | |
expires_at: expires_at1, | |
public_key: "PK1", | |
token: "token1" | |
} | |
expires_at2 = ~U[2021-01-07 15:33:33.000000Z] | |
expires_at2_unix = DateTime.to_unix(expires_at2) | |
token_login2 = %RemoteLogin.Models.TokenLogin{ | |
encrypted_keystore_token: "encrypted_keystore_token2", | |
encrypted_pdk: "encrypted_pdk2", | |
encrypted_vault_token: "encrypted_vault_token2", | |
expires_at: expires_at2, | |
public_key: "PK2", | |
token: "token2" | |
} | |
# store unix seconds as the third item in the tuple | |
:ets.insert(ets_table_name, {"token1", token_login1, expires_at1_unix}) | |
:ets.insert(ets_table_name, {"token2", token_login2, expires_at2_unix}) | |
# return all records, that's what you do | |
ets_table_name |> :ets.tab2list() |> IO.inspect() | |
# match and match_object can only do `==`, not `>` or `<`. I think :-) | |
# so this is not what you are looking for | |
ets_table_name |> :ets.match_object({:"$1", :"$2", 1_610_031_600}) |> IO.inspect() | |
# we need to use :ets.select | |
select_specification = [ | |
{ | |
# initial match pattern the same as in `match_object` and `match` | |
{:"$1", :"$2", :"$3"}, | |
# this is your WHERE clause :) | |
[{:<, :"$3", 1_610_031_601}], | |
# this is your SELECT clause, $_ will return the whole tuple | |
[:"$_"] | |
} | |
] | |
ets_table_name |> :ets.select(select_specification) |> IO.inspect() | |
# let's only return the key so that you can then run :ets.delete inside Enum.each | |
select_specification = [ | |
{ | |
{:"$1", :"$2", :"$3"}, | |
[{:<, :"$3", 1_610_031_601}], | |
# only the key, the first item in the tuple | |
[:"$1"] | |
} | |
] | |
ets_table_name |> :ets.select(select_specification) |> IO.inspect() | |
# but we can do better, you don't need to run Enum.each with :ets.delete, you can delete all expired records in 1 ets call: select_delete | |
select_specification = [ | |
{ | |
{:"$1", :"$2", :"$3"}, | |
[{:<, :"$3", 1_610_031_601}], | |
# it must be true for select_delete | |
# the docs: | |
# The match specification has to return the atom true if the object is to | |
# be deleted. No other return value gets the object deleted. So one cannot use | |
# the same match specification for looking up elements as for deleting them. | |
[true] | |
} | |
] | |
# will delete token1 | |
:ets.select_delete(ets_table_name, select_specification) | |
# token2 is left | |
ets_table_name |> :ets.tab2list() |> IO.inspect() | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment