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

Add support for selecting fields #19

Closed
Tracked by #116
RobertCraigie opened this issue Jun 14, 2021 · 4 comments · Fixed by #651
Closed
Tracked by #116

Add support for selecting fields #19

RobertCraigie opened this issue Jun 14, 2021 · 4 comments · Fixed by #651
Labels
Projects

Comments

@RobertCraigie
Copy link
Owner

RobertCraigie commented Jun 14, 2021

Problem

A crucial part of modern and performant ORMs is the ability to choose what fields are returned, Prisma Client Python is currently missing this feature.

Mypy solution

As we have a mypy plugin we can dynamically modify types on the fly, this means we would be able to make use of a more ergonomic solution.

class Model(BaseModel):
  id: str
  name: str
  points: Optional[int]

class SelectedModel(BaseModel):
  id: Optional[str]
  name: Optional[str]
  points: Optional[int]

ModelSelect = Iterable[Literal['id', 'name', 'points']]

@overload
def action(
	...
) -> Model:
	...

@overload
def action(
	...
	select: ModelSelect
) -> SelectedModel:
	...

model = action(select={'id', 'name'})

The mypy plugin would then dynamically remove the Optional from the model for every field that is selected, we might also be able to remove the fields that aren't selected although I don't know if this is possible.

The downside to a solution like this is that unreachable code will not trigger an error when type checking with a type checker other than mypy, e.g.

user = await client.user.find_first(select={'name'})
if user.id is not None:
  print(user.id)

Will pass type checks although the if block will never be ran.

EDIT: A potential solution for the above would be to not use optional and instead use our own custom type, e.g. maybe something like PrismaMaybeUnset. This has its own downsides though.

EDIT: I also think we may also want to support setting a "default include" value so that relations will always be fetched unless explicitly given False. This will not change the generated types and they will still be Optional[T].

Type checker agnostic solution

After #59 is implemented the query builder should only select the fields that are present on the given BaseModel.

This would mean that users could generate partial types and then easily use them to select certain fields.

User.create_partial('UserOnlyName', include={'name'})
from prisma.partials import UserOnlyName

user = await UserOnlyName.prisma().find_unique(where={'id': 'abc'})

Or create models by themselves

class User(BaseUser):
  name: str

user = await User.prisma().find_unique(where={'id': 'abc'})

This will make typing generic functions to process models more difficult, for example, the following function would not accept custom models.:

def process_user(user: User) -> None:
  ...

It could however be modified to accept objects with the correct properties by using a Protocol.

class UserWithID(Protocol):
  id: str

def process_user(user: UserWithID):
  ...
@RobertCraigie RobertCraigie changed the title Add select argument to all actions Add support for selecting fields Jun 16, 2021
@RobertCraigie RobertCraigie added the kind/feature A request for a new feature. label Jun 16, 2021
@RobertCraigie RobertCraigie added this to To do in v1.0.0 via automation Jun 16, 2021
@RobertCraigie RobertCraigie added this to the Public Release milestone Jul 6, 2021
@RobertCraigie RobertCraigie mentioned this issue Jul 24, 2021
42 tasks
@RobertCraigie RobertCraigie removed this from the Public Release milestone Aug 17, 2021
@RobertCraigie
Copy link
Owner Author

RobertCraigie commented Jan 30, 2022

An interesting potential solution would be to make use of PEP 646 which would mean returning tuples instead of BaseModels though.

@RobertCraigie RobertCraigie added the process/candidate Candidate for the next release label Feb 10, 2022
@RobertCraigie RobertCraigie removed the process/candidate Candidate for the next release label Dec 4, 2022
@AndersonatAMC
Copy link

Selecting fields is really helpful, hope this feature will be implemented soon, thank you.

@lekhnath
Copy link

lekhnath commented Mar 8, 2023

Is model field selection available ?

@RobertCraigie
Copy link
Owner Author

@lekhnath Yes the solution mentioned in the "Type checker agnostic" section has been implemented, see these docs for more information: https://prisma-client-py.readthedocs.io/en/stable/reference/selecting-fields/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Development

Successfully merging a pull request may close this issue.

3 participants