ponyorm / pony

Pony Object Relational Mapper
Apache License 2.0
3.6k stars 244 forks source link

OR filtering not working when attribute is null #508

Open sostholmwork opened 4 years ago

sostholmwork commented 4 years ago

Hello, I've ran into an issue when attempting to filter objects from a postgres DB, where the filtered attribute can be null: I've got these classes:

class User(db.Entity):
    id          = PrimaryKey(str,)
    given_name  = Required(str)
    surname     = Required(str)

class Agent(User):
    service_desk    = Optional('ServiceDesk')

class ServiceDesk(db.Entity):
    id              = PrimaryKey(str)
    name            = Required(str, unique=True)

The "Agent" Marta's service_desk attribute is null.

When running this filter: result_set.filter(lambda e: "Marta" in e.given_name or "Marta" in e.surname or "Marta" in e.service_desk.name)[:] I get the an empty result.

When running this filter: result_set.filter(lambda e: "Marta" in e.given_name or "Marta" in e.surname)[:]

I successfully find Marta

This is the sql output of the first filter:

SELECT "e"."id", "e"."given_name", "e"."surname", "e"."service_desk"
FROM "user" "e", "servicedesk" "servicedesk"
WHERE "e"."classtype" IN ('Agent')
  AND ("e"."given_name" LIKE '%%Marta%%' OR "e"."surname" LIKE '%%Marta%%' OR "e"."service_desk" IS NOT NULL AND "servicedesk"."name" LIKE '%%Marta%%')
  AND "e"."service_desk" = "servicedesk"."id"

removing the last AND condition, turning it into:

SELECT "e"."id", "e"."given_name", "e"."surname", "e"."service_desk"
FROM "user" "e", "servicedesk" "servicedesk"
WHERE "e"."classtype" IN ('Agent')
  AND ("e"."given_name" LIKE '%%Marta%%' OR "e"."surname" LIKE '%%Marta%%' OR "e"."service_desk" IS NOT NULL AND "servicedesk"."name" LIKE '%%Marta%%')

I successfully get the expected result.

I've checked documentation and forums but I haven't been able to find any examples or solutions to this problem.

Am I doing something wrong here? Is there a way to prevent the last AND condition from being added?

sostholmwork commented 4 years ago

I'm actually having this issue with sorting as well.

If I do: count(result_set) prior to sorting, I get 45 and after running: count(result_set.order_by(lambda: e.service_desk.name))

I get 1, namely the only result where the service_desk relation is not null.

Any variation of this that I can think of like:

result_set.order_by(lambda: (e.service_desk, e.service_desk.name)

yield the same results.