ponyorm / pony

Pony Object Relational Mapper
Apache License 2.0
3.63k stars 245 forks source link

error constructing query from stored subqueries #707

Open ne555 opened 6 months ago

ne555 commented 6 months ago
from pony import orm

db = orm.Database()

class Person(db.Entity):
    name = orm.Optional(str)
    vehicles = orm.Set('Car')

class Person_fts(db.Entity):
    rowid = orm.Optional(int)

class Car(db.Entity):
    model = orm.Optional(str)
    owner = orm.Optional('Person')

class Car_fts(db.Entity):
    rowid = orm.Optional(int)

db.bind('sqlite', ':memory:')
db.generate_mapping(create_tables=True)

with orm.db_session:
    person_sql = orm.select(
        x
        for x in Person
        for fts in Person_fts
        if x.id == fts.rowid
    )
    car_sql = orm.select(
        x
        for x in Car
        for fts in Car_fts
        if x.id == fts.rowid
    )

    query = orm.select(
        (person, car)
        for person in person_sql
        for car in car_sql
        if car.owner == person
    )
Traceback (most recent call last):
  File "complex_join.py", line 36, in <module>
    query_small = orm.select(
                  ^^^^^^^^^^^
  File "lib/python3.11/site-packages/pony/orm/core.py", line 5560, in select
    return make_query(args, frame_depth=cut_traceback_depth+1)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "lib/python3.11/site-packages/pony/orm/core.py", line 5556, in make_query
    return Query(code_key, tree, globals, locals, cells, left_join)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "lib/python3.11/site-packages/pony/orm/core.py", line 5717, in __init__
    translator = translator_cls(tree_copy, None, code_key, filter_num, extractors, vars, vartypes.copy(), left_join=left_join)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "lib/python3.11/site-packages/pony/orm/sqltranslation.py", line 242, in __init__
    translator.init(tree, parent_translator, code_key, filter_num, extractors, vars, vartypes, left_join, optimize)
  File "lib/python3.11/site-packages/pony/orm/sqltranslation.py", line 357, in init
    translator.process_query_qual(prev_translator, prev_limit, prev_offset,
  File "lib/python3.11/site-packages/pony/orm/sqltranslation.py", line 613, in process_query_qual
    subquery_ast = prev_translator.construct_subquery_ast(prev_limit, prev_offset, aliases=aliases)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "lib/python3.11/site-packages/pony/orm/sqltranslation.py", line 640, in construct_subquery_ast
    assert not star and len(aliases) == len(select_ast) - 1
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError

if replace the person_sql and car_sql queries by their content it builds the query correctly

query = orm.select(
    (person, car)
    for person in orm.select(
        x
        for x in Person
        for fts in Person_fts
        if x.id == fts.rowid
    )
    for car in orm.select(
        x
        for x in Car
        for fts in Car_fts
        if x.id == fts.rowid
    )
    if car.owner == person
)
SELECT DISTINCT "x"."id", "car"."id"
FROM "Person" "x", "Person_fts" "fts", (
    SELECT DISTINCT "x-2"."id" AS "car-id"
    FROM "Car" "x-2", "Car_fts" "fts-2"
    WHERE "x-2"."id" = "fts-2"."rowid"
    ) "t-1", "Car" "car"
WHERE "x"."id" = "fts"."rowid"
  AND "car"."owner" = "x"."id"
  AND "t-1"."car-id" = "car"."id"

Python 3.11.6 pony 0.7.17

ne555 commented 6 months ago

weird «solution», ask for an extra field

    person_sql = orm.select(
        (1, x)
        for x in Person
        for fts in Person_fts
        if x.id == fts.rowid
    )
    car_sql = orm.select(
        (1, x)
        for x in Car
        for fts in Car_fts
        if x.id == fts.rowid
    )

    query = orm.select(
        (person, car)
        for a, person in person_sql # it must have a name, can't use _
        for b, car in car_sql
        if car.owner == person
    )
SELECT DISTINCT "x"."id", "car"."id"
FROM "Person" "x", "Person_fts" "fts", (
    SELECT DISTINCT 1 AS "b", "x"."id" AS "car-id"
    FROM "Car" "x", "Car_fts" "fts"
    WHERE "x"."id" = "fts"."rowid"
    ) "t-1", "Car" "car"
WHERE "x"."id" = "fts"."rowid"
  AND "car"."owner" = "x"."id"
  AND "t-1"."car-id" = "car"."id"