Glorp: #includesKey:

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Glorp: #includesKey:

Herby Vojčík
Hello!

I am using a DictionaryMapping in my code, and I wanted to use
#includesKey: in #where: clause (something akin

   each tools includesKey: aToolId

) to select only rows for which DictionaryMapping uses certain key. It
failed with the error in the lines of "#tools does not resolve to
field". I had to come up with

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

Is it the bug / feature / problem in my approach? If bug, is it planned
to add #includesKey: translation to DictionaryMapping?

Thanks, Herby

--
You received this message because you are subscribed to the Google Groups "glorp-group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/glorp-group.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Glorp: #includesKey:

Tom Robinson
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
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.

Regards,

Tom

On 10/24/2017 12:27 PM, Herby Vojčík wrote:

> Hello!
>
> I am using a DictionaryMapping in my code, and I wanted to use
> #includesKey: in #where: clause (something akin
>
>   each tools includesKey: aToolId
>
> ) to select only rows for which DictionaryMapping uses certain key. It
> failed with the error in the lines of "#tools does not resolve to
> field". I had to come up with
>
>   each tools anySatisfy: [ :tool | tool id = aToolId ]
>
> Is it the bug / feature / problem in my approach? If bug, is it
> planned to add #includesKey: translation to DictionaryMapping?
>
> Thanks, Herby
>

--
You received this message because you are subscribed to the Google Groups "glorp-group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/glorp-group.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] Glorp: #includesKey:

jtuchel
In reply to this post by Herby Vojčík
Herby,

I must admit I've never used Dictionary Mappings with Glorp, so I don't
have an answer.
But I am a bit confused by your code examples. See below


Am 24.10.17 um 20:27 schrieb Herby Vojčík:
> Hello!
>
> I am using a DictionaryMapping in my code, and I wanted to use
> #includesKey: in #where: clause (something akin
>
>   each tools includesKey: aToolId

What SQL expression would you expect here?

I would guess that you want to build a subquery like exists, because the
way I understand the query, you want to find all instances of (whatever
each is) that hold an Association in their tools dictionary where the
key is aToolId.
>
> ) to select only rows for which DictionaryMapping uses certain key. It
> failed with the error in the lines of "#tools does not resolve to
> field". I had to come up with
>

> each tools anySatisfy: [ :tool | tool id = aToolId ]
Hmm. This makes me wonder. Is #tools really a Dictionary? Inside the
Block, I'd expect the :tool parameter to be an Association, and that
doesn't understand #id,does it? I guess @each is the parameter within an
Block like in

self session read: MyClass where: [:each| each tools ...]

If so, I have a hard time believing that anySatisfy: would work (never
tried)...


>
>
> Is it the bug / feature / problem in my approach? If bug, is it
> planned to add #includesKey: translation to DictionaryMapping?
>
I don't know, but would guess it is not currently on the Todo-list.

My first tip would be to try and find some slides (most likely made by
Niall and presented at an ESUG) including the words "subquery", "glorp"
and "exists". You won't find much, but that may be a starting point.

Not sure this helps, ;-)


Joachim


--
-----------------------------------------------------------------------
Objektfabrik Joachim Tuchel          mailto:[hidden email]
Fliederweg 1                         http://www.objektfabrik.de
D-71640 Ludwigsburg                  http://joachimtuchel.wordpress.com
Telefon: +49 7141 56 10 86 0         Fax: +49 7141 56 10 86 1

--
You received this message because you are subscribed to the Google Groups "glorp-group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/glorp-group.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Glorp: #includesKey:

Herby Vojčík
In reply to this post by Tom Robinson
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

   SELECT * FROM AGENT a
     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

   SELECT * FROM AGENT a
     WHERE a.tool_id IN
      (SELECT * FROM TOOL t
        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

--
You received this message because you are subscribed to the Google Groups "glorp-group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/glorp-group.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: [Pharo-users] Glorp: #includesKey:

Herby Vojčík
In reply to this post by jtuchel
[hidden email] wrote:

> Herby,
>
> I must admit I've never used Dictionary Mappings with Glorp, so I don't
> have an answer.
> But I am a bit confused by your code examples. See below
>
>
> Am 24.10.17 um 20:27 schrieb Herby Vojčík:
>> Hello!
>>
>> I am using a DictionaryMapping in my code, and I wanted to use
>> #includesKey: in #where: clause (something akin
>>
>>   each tools includesKey: aToolId
>
> What SQL expression would you expect here?

SELECT * FROM AGENT a WHERE a.tool_id = :aToolId

AFAICT, DISTINCT is not needed as <id, tool_id> are fks to other table's
compound primary key <agent_id, id>, so they are known to be unique.

> I would guess that you want to build a subquery like exists, because the
> way I understand the query, you want to find all instances of (whatever
> each is) that hold an Association in their tools dictionary where the
> key is aToolId.

Yes.

Maybe it needs EXISTS, I don't know. Semantics is clear, though.

>>
>> ) to select only rows for which DictionaryMapping uses certain key. It
>> failed with the error in the lines of "#tools does not resolve to
>> field". I had to come up with
>>
>
>> each tools anySatisfy: [ :tool | tool id = aToolId ]
> Hmm. This makes me wonder. Is #tools really a Dictionary? Inside the
> Block, I'd expect the :tool parameter to be an Association, and that
> doesn't understand #id,does it? I guess @each is the parameter within an
> Block like in
>
> self session read: MyClass where: [:each| each tools ...]
>
> If so, I have a hard time believing that anySatisfy: would work (never
> tried)...

Yes, it works. Dictionary enumerates values, as I have written in reply
to Tom's post.

>> Is it the bug / feature / problem in my approach? If bug, is it
>> planned to add #includesKey: translation to DictionaryMapping?
>>
> I don't know, but would guess it is not currently on the Todo-list.
>
> My first tip would be to try and find some slides (most likely made by
> Niall and presented at an ESUG) including the words "subquery", "glorp"
> and "exists". You won't find much, but that may be a starting point.

I actually managed to get there, but
   a) using ugly workaround IMO, #includesKey: is part of dictionary's
protocol, should be known;
   b) as I wrote in Tom's reply, the workaround only worked because
mapping was to object. If the mapping was to primitive value (number,
string), I would not have any 'tool id' ready to use and I would be left
.... without option. There is no way to construct such query atm in
Glorp, afaict, if I cannot use #keys not #includesKey: in where clause.
Is that not a bug?

> Not sure this helps, ;-)
>
>
> Joachim

Thanks, Herby

--
You received this message because you are subscribed to the Google Groups "glorp-group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/glorp-group.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Glorp: #includesKey:

Herby Vojčík
In reply to this post by Herby Vojčík
Niall Ross wrote:
> Dear Herby,
> adding #includesKey: is certainly doable. If you look at callers above
> and subcallers below #anySatisfyDefault: you will see the issues
> involved. Your includesKey: needs the same degree of platform-awareness
> that Glorp's #anySatisfy: and #allSatisfy: implementations use. But
> since #anySatisfy: is there, you have a ready template to follow.

I don't feel competent enough, from what I looked, Glorp innards are a
bit complex.

> Alternatively, I may well add #includesKey: - though not as my most
> urgent task. :-) I did a fair amount of work to extend the usability of
> DictionaryMappings in Glorp three years ago (part of demonstrating the
> ObjectStudio business-mapping/Glorp-generating tools - see my ESUG 2014
> presentation for details) but I did not then think of providing
> #includesKey:. Thanks for suggesting the idea.

My pleasure. :-)

As I wrote elsewhere, also #keys is something (probably the most
general) one that could be added as a matter of allowing to work with
the key field - as far as I was able to find out, there is no way to
actually get to the key, for which I found workaround since I mapped
object, but would be out of luck if I mapped single primitive value.

For the moment, it is not pressing, but yes, it would be nice to be able
to have #keys mapping to key field and #includesKey: as an idiomatic way
to do keys includes:.

Thanks again, Herby

> If you were to work on this, be aware:
>
> - always reinitialise FunctionExpression class after adding/changing any
> Glorp function (or just close and reopen your image, of course)
>
> - If (and only if) you construct Query whereClauses in stages (e.g. you
> have code like
>
> myQuery AND: [:customer | customer orders includesKey: #onlineOrders]
>
> or similar) then, using its callers in GlorpTest as a guide, know when
> you might need to send #setUpBaseFromSession: to your query while doing
> so. (N.B. that method is a Glorp version 8.2.1 addition; you will not
> have it in older Glorp.) The point is that stage-constructed where
> clauses must convert from block to expression before execution, to
> combine the stages. Any that use #anySatisfy:/#allSatisfy: need
> platform-specific information to do this; I would expect any
> #includesKey: implementation to be the same.
>
> HTH
> Niall Ross
>
>
> 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
> 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.
>
> Regards,
>
> Tom
>
> On 10/24/2017 12:27 PM, Herby Vojčík wrote:
>
>> Hello!
>>
>> I am using a DictionaryMapping in my code, and I wanted to use
>> #includesKey: in #where: clause (something akin
>>
>> each tools includesKey: aToolId
>>
>> ) to select only rows for which DictionaryMapping uses certain key. It
>> failed with the error in the lines of "#tools does not resolve to
>> field". I had to come up with
>>
>> each tools anySatisfy: [ :tool | tool id = aToolId ]
>>
>> Is it the bug / feature / problem in my approach? If bug, is it
>> planned to add #includesKey: translation to DictionaryMapping?
>>
>> Thanks, Herby
>

--
You received this message because you are subscribed to the Google Groups "glorp-group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
Visit this group at https://groups.google.com/group/glorp-group.
For more options, visit https://groups.google.com/d/optout.