[Pharo-users] Glorp: #includesKey:

Herby Vojčík herby at mailbox.sk
Wed Oct 25 06:23:33 EDT 2017

Tom Robinson wrote:
> Hi Herby,
> In my opinion, the way you found to make it work is the way it should
> be. The reason is that the first way doesn't translate into SQL and the
> second one does. It might be possible to add includesKey: functionality
> but resolving that to SQL would be more complex. I would not call this a

I think I disagree with this, but correct me if I am wrong.

With DictionaryMapping, you map a set of (key, value) pairs into 
appropriate fields in a table. In essence, it does not differ at all to 
mapping any other collection containing objects with fields (actually, 
from what I understood, it does internal tricks to do just that - create 
internal "class mapping" for an association of that particular 
dictionary mapping).

In case of primitive value dictionaries, it even _is_ the same: key is 
mapped to one field, value is mapped to different field. If I want to 
create subquery using value, I can freely use things like #anySatisfy: 
to filter on that value (which I did in my case, but I come to that 
later). Since Dictionary enumerates values in do:, select:, collect: 
(and anySatisfy:), writing

   each tools anySatisfy: [...]

is the same as writing

   each tools values anySatisfy: [...]

but what if I wanted to write

   each tools keys anySatisfy: [...]

? I cannot, Glorp fails on 'keys' (I tried to use `keys includes:` 
instead of `includesKey:`, to no avail).

So what I want to point here is, that in DictionaryMapping I map keys 
and values to different fields in table (values can be complex, in which 
keys they are mapped to more fields, but that is not important 
distinction here), but Glorp only allows me to use values (and only 
implicitly) in where clauses; I have no way to use keys at all there.

So I assert here that "resolving that to SQL would be more complex" is 
not true. Key is mapped the same way value is; if I can use where clause 
that uses value in certain way, I should be able to use key as well - 
SQL generating from one or the other have same level of difficulty (in 
fact, I think key is easier, as you do not actually need to join the 
foreign table); the generated SQL could be something like

     WHERE a.tool_id = <toolId asDbValue>

The fact that I found a

   each tools anySatisfy: [ :tool | tool id = aToolId ]

is in fact only because non-primitive mappings are processed differently 
in DictionaryMapping, a non-primitive values are _required_ to have a 
field defined (not in table, that is understandable, I need to be able 
to make a join, but in descriptor) a mapping that contains the key. So 
in essence, that could be represented as

     WHERE a.tool_id IN
        WHERE t.agent_id = a.id
          AND t.id = a.tool_id
          AND t.id = <aToolId asDbValue>)

which is basically same as above, as actually, "a.tool_id = <aToolId 
asDbValue>" is executed here as well (plus checking that such dictionary 
actually exists at all; maybe that should be present in previous case as 
well, but Glorp can generate the join, that's not the question here).

It is actually interesting question what SQL Glorp actually generated 
for "TgAgent readOneOf: [:a|a tools anySatisfy: [:t|t id = toolId]]".

Point here is:

   1. Why do I need to work it around via [:tool | tool id = aToolId] 
when I am only interested on "which tools the agent uses" (in fact, give 
me all agents using this tool).
   2. Should this be key -> primitive value mapping, I have simple _no 
way_ to ask the equivalent of #includesKey: at all (as the value is, for 
example, a String or an Integer, so no `tool id` is available).

> bug. I would call it a limitation of the implementation. I don't know of
> anyone planning to add this feature to Glorp right now.

That's why I would say #keys (and, ideally, #includesKey:) are actually 
needed addition to Glorp's set of known-and-translated selectors in case 
of DictionaryMapping.

> Regards,
> Tom

Thanks, Herby

More information about the Pharo-users mailing list