edgedb

How to access tuple property with dynamic key in Gel (EdgeDB)?


I'm thinking about using tuple for i18n names e.g.:

type Category {
  required property i18nName: tuple<pl: str, en: str>;
}

It's possible to select from tuple by dot property:

> select (pl := "bober", en:= "beaver")).pl;
{"bober"}

But let's say I want to make the language key dynamic:

> with lng := <str>$lng select (pl := "bober", en:= "beaver")[lng];
gel error: QueryError: index indirection cannot be applied to collection 'tuple<pl: std::str, en: std::str>'

Can this be achieved with the tuple?


Solution

  • I came up with a way by casting the tuple to JSON, and then using json_get:

    with lng := $lng
    select <str>json_get(<json>(pl := "bober", en:= "beaver"), lng))));
    

    Also, I was able to constrain the keys by going through a function, to make sure only valid calls are made:

      scalar type Lang extending str {
        constraint one_of("pl", 'en');
      }
    
      function get_tuple_lang(tpl: tuple<pl: str, en: str>, lng: Lang) -> str
        using (assert_exists(assert_single(<str>json_get(<json>tpl, lng))));
      
    

    This works:

    project:main> with t := (pl:="bober", en:="beaver") select get_tuple_lang(t, "pl");
    {'bober'}
    project:main> with t := (pl:="bober", en:="beaver") select get_tuple_lang(t, "en");
    {'beaver'}
    project:main> with t := (pl:="bober", en:="beaver") select get_tuple_lang(t, "cz");
    gel error: ConstraintViolationError: Lang must be one of: ['pl', 'en'].
      Detail: violated constraint 'std::one_of' on scalar type 'default::Lang'