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

New client APIs #447

Open
medz opened this issue Nov 5, 2024 · 3 comments
Open

New client APIs #447

medz opened this issue Nov 5, 2024 · 3 comments

Comments

@medz
Copy link
Owner

medz commented Nov 5, 2024

TL;DR:

  final prisma = PrismaClient();

  // Unsafe JSON params query
  final user = prisma.user.findUnique.fromJson({
    'where': {'id': 1},
    'select': {'id': true, name: true},
  });

  // Type-safe inputs query
  final user = prisma.user.findUnique(
    where: UserWhereUniqueInput(
        id: PrismaUnion.$1(1)
    ),
    select: UserSelect(id: true, name: true),
  );

  // Type-safe fluent query
  final user = prisma.user.findUnique
      .where((where) => where.id(1))
      .select((user) => [user.id, user.name]);

  // Default serialized User
  final defaultUser = await user; // User class

  // Custom serialize
  final customUser = await user.serialize(CustomUserResul.fromJson);

In previous versions, in order to avoid the learning cost of Prisma, we always used the API of Prisma TS client as the reference implementation.

Obviously, this is not applicable in Dart. For Type-safety, we have to write a lot of boilerplate code:

 final user = await prisma.user.findFirst(
  where: UserWhereInput(
    posts: PostListRelationFilter(
      some: PostWhereInput(
        likes: PrismaUnion.$1(
          IntFilter(gt: PrismaUnion.$1(100)),
        ),
      ),
    ),
  ),
  orderBy: PrismaUnion.$2(
    UserOrderByWithRelationInput(id: SortOrder.desc),
  ),
);

to new fluent API:

final user = await prisma.user.findFirst
           .where((where) => where.posts.some.likes.gt(100))
           .orderBy((order) => order.id.desc)

In the new API design, we keep Type-safe inputs and add several new requirements:

  1. fromJson(): You can pass in a JSON as a parameter like the Prisma TS client, which is completely consistent with the TS client. But using Map in Dart will completely lose safety.
  2. serialize(): This is an interface that allows you to customize the serialization return data. In the v5 version, nullable Model entities are always returned, which is inconvenient for users to always check whether it is a null value. The new serialize allows you to fully control the serialization. You can simply extension type xxx impl Map to implement the type packaging of data.
  3. Fluent API, previously we always used the Type-safe inputs class as parameters. For operations with escaping or multi-type values, we always have to wrap PrismaUnion and promote the parameters to the outside. We also need to be extra careful to avoid type errors. Fluent API splits it up. You can gradually pass in parameters according to the type builder to prevent external promotion from causing incorrect type signatures. In addition, it may also provide some auxiliary functions to help you more easily promote external conditional logic.

This is a discussion. Do we really need to add these new APIs?

@medz medz pinned this issue Nov 5, 2024
@medz
Copy link
Owner Author

medz commented Nov 5, 2024

Also, should we keep the old API? Or should we write a new generator to complete the new API.

Actually, I don’t want to keep the old API because it will generate a lot of boilerplate code.

@mocki-toki
Copy link

I believe that developing a new API would be a significant step toward enhancing the user experience of the package. The current API code appears too cluttered compared to the rest of the codebase, and a new API would align the coding style more closely with that used in Dart.

Eliminating the PrismaUnion construct would be excellent, as it not only complicates code readability and maintenance but also raises the entry barrier for the package. Additionally, with the increasing use of AI for code generation, tools like Copilot frequently confuse whether to use PrismaUnion.$1 or $2.

However, the transition from the old API poses a considerable challenge since developers have written a substantial amount of code that would need to be manually rewritten. To address this, we could develop a migration utility similar to the one that facilitated the transition to Dart's null safety.

It would be beneficial to retain the old API for a transitional period by allowing its usage through a generator argument and marking it as deprecated, while making the new API the default. This approach would provide developers with ample time to migrate.

@medz
Copy link
Owner Author

medz commented Nov 10, 2024

@mocki-toki My idea is to keep the original typed inputs and then make a new generator to enable the new API. That is to say, the new API and typed inputs are retained at the same time, and all typed inputs are marked as deprecated, allowing existing programs to be migrated gradually.

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

No branches or pull requests

2 participants