RobertCraigie / prisma-client-py

Prisma Client Python is an auto-generated and fully type-safe database client designed for ease of use
https://prisma-client-py.readthedocs.io
Apache License 2.0
1.9k stars 81 forks source link

Add support for including count of relational fields #26

Open RobertCraigie opened 3 years ago

RobertCraigie commented 3 years ago

Problem

Prisma supports including the count of a relational field, so we should too.

const users = await prisma.user.findMany({
  include: {
    _count: {
      select: { posts: true },
    },
  },
})

which returns an object like this

{
  id: 1,
  email: 'alice@prisma.io',
  name: 'Alice',
  _count: { posts: 2 }
}

Prisma also have support for filtering by the count of the relation, see https://www.prisma.io/docs/concepts/components/prisma-client/aggregation-grouping-summarizing#filter-the-relation-count

rxsine commented 3 months ago

This feature is needed.

rijenkii commented 2 weeks ago

If anyone need this, it is possible to retrieve the _count using this library internal methods (very unsafe, can break after any update):

db = prisma.Prisma()

class _UserCount(pydantic.BaseModel):
    posts: int

class _User(prisma.models.User):
    # Aliasing because of https://github.com/pydantic/pydantic/issues/2105
    count_: typing.Annotated[_UserCount, pydantic.Field(alias="_count")]

    @classmethod
    async def select_with_post_count(
        cls,
        *,
        where: prisma.types.UserWhereInput | None,
        include: prisma.types.UserInclude | None,
    ):
        # shut up pydantic
        make_query_builder = (
            db._make_query_builder  # pyright: ignore [reportPrivateUsage]
        )
        engine = db._engine  # pyright: ignore [reportPrivateUsage]

        # generate a graphql query to the prisma engine
        query = make_query_builder(
            method="find_many",
            model=models.License,
            arguments={"where": where, "include": include},
            root_selection=None,
        ).build()

        # add the _count
        suffix = r'\n  }\n}"}'
        query = query.removesuffix(suffix) + r"\n    _count { posts }" + suffix

        # execute the query, be sure to set tx_id if you are in a transaction
        response = (await engine.query(query, tx_id=None))["data"]["result"]
        return [cls.model_validate(x) for x in response]

users = await _User.select_with_count()

This will stop working once this library has been moved from GraphQL to the JSON protocol (#748).