Brendonovich / prisma-client-rust

Type-safe database access for Rust
https://prisma.brendonovich.dev
Apache License 2.0
1.75k stars 106 forks source link

Composible select! and include! #333

Open aidangilmore opened 1 year ago

aidangilmore commented 1 year ago

Forgive me if this already exists, but I think it would be neat and rather useful if you could compose define several instances of select! and include!. Currently, when working with complex schemas involving multiple models and nested relations, it can be a tedious process to repeatedly specify all the fields to be included or selected.

Consider the following Prisma schema:

model Foo {
    id   String  @id
    name String
    bar  Bar[]
    qux  Boolean
}

model Bar {
    id     String @id
    foo    Foo    @relation(fields: [foo_id], references: [id])
    foo_id String
    baz    Baz[]
    bongo  Bongo[]
}

model Baz {
    id     String @id
    bar    Bar    @relation(fields: [bar_id], references: [id])
    bar_id String
    thud   Int
    wibble DateTime
}

model Bongo {
    id     String @id
    bar    Bar    @relation(fields: [bar_id], references: [id])
    bar_id String
    grunt  String
}

Here is a rendered example of what I think an enhanced select! and include! could look like

// Define a 'select' directive for Foo that only fetches 'name'
// This could be used in situations where only the 'name' field is required.
foo::select!(foo_summary {
    name
})

// Define a more detailed 'select' directive for Foo
// This fetches 'name' and includes 'bar' relations using a nested 'include' directive, 'bar_with_children'
foo::select!(foo_detailed {
    name
    bar: bar_with_children // Include the contents of bar_with_children
})

// Define an 'include' directive for Bar
// This specifies what child relations and fields to fetch when a Bar instance is requested.
bar::include!(bar_with_children {
    baz: select {
        thud // When fetching 'baz', only get the 'thud' field
    }
    bongo: select {
        grunt // When fetching 'bongo', only get the 'grunt' field
    }
});

Thank you very much for the wonderful library!

Brendonovich commented 1 year ago

I was actually thinking about this the other day, it should be possible after #250. I'd want it to look something like this:

foo::select!(foo_detailed {
    name
    bar: #bar_with_children
})

bar::include!(bar_with_children {
    baz: select {
        thud
    }
    bongo: select {
        grunt
    }
});