geldata / geldata/gel-python

Code generator use query_single instead of query for Set result

Open
#605 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
415
Forks
50
PR merge metrics
No merged PRs in 30d

Description

**Describe the bug**

In some scenario, the code generator wrongly generates python code that does not match the possible queried data cardinality. To be specific, the generated code of selecting the result set of updating possibly multiple objects has the following behavior:
1. use `query_single` instead `query`
2. decorate the function returned typing as `Result` instead of `list[Result]`

**Reproduction**

Using schema and query like the following:

```esdl
module default {
abstract type Resource {
required created_at: datetime {
readonly := true;
default := datetime_of_statement();
}
}

type Release extending Resource {
required major: uint16 {
readonly := true;
};
required minor: uint16 {
readonly := true;
};
required patch: uint16 {
readonly := true;
};
required disabled: bool {
default := false;
};
required updated_at: datetime {
rewrite insert, update using (datetime_of_statement());
};

constraint exclusive on ((.major, .minor, .patch));
}
}
```

```edgeql
select (
update Release
set {disabled := true}
) { id };

```

The generated python code will be:

```python
# AUTOGENERATED FROM '../test_edgeql/test.edgeql' WITH:
# $ gel-py -I local --dir ../test_edgeql

from __future__ import annotations
import dataclasses
import gel
import uuid

class NoPydanticValidation:
@classmethod
def __get_pydantic_core_schema__(cls, _source_type, _handler):
# Pydantic 2.x
from pydantic_core.core_schema import any_schema
return any_schema()

@classmethod
def __get_validators__(cls):
# Pydantic 1.x
from pydantic.dataclasses import dataclass as pydantic_dataclass
_ = pydantic_dataclass(cls)
cls.__pydantic_model__.__get_validators__ = lambda: []
return []

@dataclasses.dataclass
class TestResult(NoPydanticValidation):
id: uuid.UUID

async def test(
executor: gel.AsyncIOExecutor,
) -> TestResult:
return await executor.query_single(
"""\
select (
update Release
set {disabled := true}
) { id };\
""",
)
```

**Expected behavior**

The generated function should be decorated as `list[TestResult]` and use `executor.query` instead.

**Versions (please complete the following information):**

Local development environment
- OS: macOS Sonoma 14.6.1
- EdgeDB version: 6.4+e5a21c9
- EdgeDB CLI version: 7.1.1+616a110
- `edgedb-python` version: gel 3.0.1
- Python version: 3.12.2

CI codegen environment
- OS: Debian GNU/Linux 12 (bookworm)
- EdgeDB version: 6.4+1240dde
- EdgeDB CLI version: 7.1.1+754cfa2
- `edgedb-python` version: gel 3.0.1
- Python version: 3.12.9

**Additional context**

This behavior does not occur after performing the following migration (for testing purpose):

```edgeql
{
ALTER TYPE default::Release {
DROP PROPERTY updated_at;
};
};
```

The generated python will become as expected:

```python
# AUTOGENERATED FROM '../test_edgeql/test.edgeql' WITH:
# $ gel-py --dir ../test_edgeql

from __future__ import annotations
import dataclasses
import gel
import uuid

class NoPydanticValidation:
@classmethod
def __get_pydantic_core_schema__(cls, _source_type, _handler):
# Pydantic 2.x
from pydantic_core.core_schema import any_schema
return any_schema()

@classmethod
def __get_validators__(cls):
# Pydantic 1.x
from pydantic.dataclasses import dataclass as pydantic_dataclass
_ = pydantic_dataclass(cls)
cls.__pydantic_model__.__get_validators__ = lambda: []
return []

@dataclasses.dataclass
class TestResult(NoPydanticValidation):
id: uuid.UUID

async def test(
executor: gel.AsyncIOExecutor,
) -> list[TestResult]:
return await executor.query(
"""\
select (
update Release
set {disabled := true}
) { id };\
""",
)
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.