Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement dataclass for EdgeObject #359

Merged
merged 6 commits into from
Sep 4, 2022
Merged

Implement dataclass for EdgeObject #359

merged 6 commits into from
Sep 4, 2022

Conversation

fantix
Copy link
Member

@fantix fantix commented Aug 15, 2022

This would allow using the EdgeObject as a dataclass, in particular:

  • dataclasses.is_dataclass(obj) will return True
  • dataclasses.asdict(obj) will return a proper dict
  • No impact to performance

Then we could do something like this with FastAPI as an example:

import fastapi
import edgedb
import uuid
from dataclasses import dataclass

app = fastapi.FastAPI()
client = edgedb.create_client()

@dataclass
class Role:
    id: uuid.UUID
    name: str

    @classmethod
    def __get_validators__(cls):
        return []

@dataclass
class User:
    id: uuid.UUID
    name: str
    role: Role

    @classmethod
    def __get_validators__(cls):
        return []

@app.get("/", response_model=User)
def read_root():
    return client.query("select User { name, role: { name } }")[0]

Schema:

module default {
    type User {
        property name -> str;
        link role -> Role;
    }

    type Role {
        required property name -> str;
    }
}

@i0bs
Copy link

i0bs commented Aug 15, 2022

Have not tested, but for this part:

return client.query("select User { name, role: { name } }")[0]

Will the first index return us the Role Python dataclass, or the EdgeQL schema of it?

@fantix
Copy link
Member Author

fantix commented Aug 15, 2022

Have not tested, but for this part:

return client.query("select User { name, role: { name } }")[0]

Will the first index return us the Role Python dataclass, or the EdgeQL schema of it?

Oh that's the first object in the result set as we are using query() instead of query_single().

p.s.: Ideally we could do something like:

@app.get("/", response_model=typing.Iterable[User])
def read_root():
    return client.query("select User { name, role: { name } }")

But we're blocked by tiangolo/fastapi#3913 - so using a regular list is the current alternative.

@fantix
Copy link
Member Author

fantix commented Aug 15, 2022

Furthermore, we will be able to separate this into 2 separate files:

user_role.edgeql:

select User { name, role: { name } }

user_role_edgeql.py:

import edgedb
import typing
import uuid
from dataclasses import dataclass

@dataclass
class Role:
    id: uuid.UUID
    name: str

    @classmethod
    def __get_validators__(cls):
        return []

@dataclass
class User:
    id: uuid.UUID
    name: str
    role: Role

    @classmethod
    def __get_validators__(cls):
        return []

def query(client: edgedb.Client) -> typing.Sequence[User]:
    return client.query("select User { name, role: { name } }")

So that we can generate user_role_edgeql.py from user_role.edgeql with a console command.

@i0bs
Copy link

i0bs commented Aug 15, 2022

Oh that's the first object in the result set as we are using query() instead of query_single().

p.s.: Ideally we could do something like:

@app.get("/", response_model=typing.Iterable[User])
def read_root():
    return client.query("select User { name, role: { name } }")

But we're blocked by tiangolo/fastapi#3913 - so using a regular list is the current alternative.

That would be preferred, or you could subsequently use typing.Mapping to make a relationship between the dataclass and then client-defined typings. Would that also work?

@fantix
Copy link
Member Author

fantix commented Aug 15, 2022

subsequently use typing.Mapping to make a relationship between the dataclass and then client-defined typings. Would that also work?

An example please? Sorry I'm not sure I'm 100% following.

@i0bs
Copy link

i0bs commented Aug 15, 2022

An example please? Sorry I'm not sure I'm 100% following.

typing.Mapping works like a container, you essentially would have an object that returns a value type based on the key type:

class CustomMapping(typing.Generic[KV, KT]):
    def __getitem__(self, key: KT) -> VT:
        ...

This would only be useful if you have custom-defined typings in the client library. For example, you could use type variables to represent types from EdgeQL.

This could be used as:

@app.get("/", response_model=CustomMapping[User, Role])
def read_root():
    return client.query("select User { name, role: { name } }")

@fantix fantix mentioned this pull request Aug 15, 2022
@fantix fantix requested a review from 1st1 August 22, 2022 21:17
edgedb/datatypes/object.c Outdated Show resolved Hide resolved
fantix and others added 2 commits August 25, 2022 10:28
@fantix fantix changed the title [PoC] Implement dataclass for EdgeObject Implement dataclass for EdgeObject Aug 25, 2022
@fantix fantix marked this pull request as ready for review August 25, 2022 15:38
@fantix fantix force-pushed the dataclass branch 11 times, most recently from 5c4991f to 8ec3afd Compare August 25, 2022 16:41
@fantix fantix force-pushed the dataclass branch 3 times, most recently from 49246c7 to b3912c5 Compare August 25, 2022 17:59
@fantix fantix merged commit dfb8c8b into master Sep 4, 2022
@fantix fantix deleted the dataclass branch September 4, 2022 20:32
fantix added a commit that referenced this pull request Oct 21, 2022
Changes
=======

* Implement dataclass for EdgeObject (#359)
  (by @fantix in dfb8c8b for #359)

* Redo edgedb basic types to inherit from builtin types (#366)
  (by @fantix in b11b991 for #366)

* Officially drop 3.6 support (#373)
  (by @msullivan in 7b76bc7 for #373)

* Support Python 3.11 (#375)
  (by @msullivan in 04b0da2 for #375)

* Codegen with the describe_query() API (#363)
  (by @fantix in 361221d for #363)

* Add codegen docs (#380)
  (by @colinhacks in 23dd42e for #380)

* Use typing_extension.Literal in codegen for Python 3.7
  (by @fantix in 6d0d6ab)

* Add __all__ to edgedb/__init__.py
  (by @fmoor in d3ef6d9)

Fixes
=====

* Improve duration parsing
  (by @fmoor in 241c80d)

* Tweak wording in query_single() error messages (#369)
  (by @msullivan in e24bb53 for #369)

* Fix flake tests on python3.7 (#371)
  (by @msullivan in 583e1cb for #371)

* Don't reject tuple arguments on the client side (#370)
  (by @msullivan in 09c950f for #370)

* Correct edgedb.Client.close() timeout behavior
  (by @fantix in 33a912c)

* Ping first if conn is idle for too long (#365)
  (by @fantix in 99cf78a for #365)

Deprecations
============

* Deprecate object links and simplify link property access (#379)
  (by @fantix in 2c5dcc7 for #379)
@fantix fantix mentioned this pull request Oct 21, 2022
fantix added a commit that referenced this pull request Oct 21, 2022
Changes
=======

* Implement dataclass for EdgeObject (#359)
  (by @fantix in dfb8c8b for #359)

* Redo edgedb basic types to inherit from builtin types (#366)
  (by @fantix in b11b991 for #366)

* Officially drop 3.6 support (#373)
  (by @msullivan in 7b76bc7 for #373)

* Support Python 3.11 (#375)
  (by @msullivan in 04b0da2 for #375)

* Codegen with the describe_query() API (#363)
  (by @fantix in 361221d for #363)

* Add codegen docs (#380)
  (by @colinhacks in 23dd42e for #380)

* Use typing_extension.Literal in codegen for Python 3.7
  (by @fantix in 6d0d6ab)

* Add __all__ to edgedb/__init__.py
  (by @fmoor in d3ef6d9)

Fixes
=====

* Improve duration parsing
  (by @fmoor in 241c80d)

* Tweak wording in query_single() error messages (#369)
  (by @msullivan in e24bb53 for #369)

* Fix flake tests on python3.7 (#371)
  (by @msullivan in 583e1cb for #371)

* Don't reject tuple arguments on the client side (#370)
  (by @msullivan in 09c950f for #370)

* Correct edgedb.Client.close() timeout behavior
  (by @fantix in 33a912c)

* Ping first if conn is idle for too long (#365)
  (by @fantix in 99cf78a for #365)

* Use @-prefixed keys in object codec for link properties (#384)
  (by @fantix in 68480f9 for #377)

Deprecations
============

* Deprecate object links and simplify link property access (#379)
  (by @fantix in 2c5dcc7 for #379)
@fantix fantix mentioned this pull request Oct 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants