Open bvkimball opened 5 months ago
Hi @bvkimball , thank you for filing this FR with a great explanation! If I'm understanding it correctly, the proposal covers two aspects:
# 1 is similar to #1402. We can probably start by allowing the args()
construct at the client level and then extend it to the query level for better flexibility. The latter will involve extending PrismaClient
's current TS interface, but we're already doing it in V2 anyway 😄.
# 2 may be related to another thing that I've been thinking about for a while. Let me try to explain it here.
The current way policies are modeled in ZenStack is probably not good enough for modeling applications with multiple "sides". For example, an EC app can have a storefront "side" and a fulfillment "side". Authoring their rather different authorization rules in a "flat" way can be quite cumbersome and hard to maintain. So maybe we should introduce something like "profile" to segregate different sets of rules. (Please ignore the syntax, as it's just for showing the idea).
model Order {
...
@@profile('storefront', [
allow('read', ...),
deny('update', ...)
])
@@profile('fulfillment', [
allow('read', ...),
deny('update', ...)
])
}
So at enhancement time we can do:
const storefrontDb = enhance(prisma, ..., { profiles: ['storefront'] });
We can also allow overriding profiles at query time.
Back to your proposal, the equivalent will probably be something like:
model Post {
//...
effectiveStart DateTime
effectiveEnd DateTime
comments Comment[]
@@profile('asOf', [
deny('read', !(effectiveStart < args().timestamp && (effectiveEnd > args().timestamp || effectiveEnd == null))))
])
}
await db.post.findMany({
select: {
title: true,
comments: {
select: {
id: true,
message: true,
},
},
},
profiles: [ 'asOf' ],
args: { timestamp: '2024-12-24' }
});
I'm still not really sure to what extent this really overlaps with your original thoughts, but just wanted to throw out some wild ideas 😄.
Is your feature request related to a problem? Please describe.
Sometimes i want baked in logic like soft delete mechanism into my model access policy. But sometimes the user/client can still access the data but only in implicit circumstances. Most of this could be implemented through the access policy and passing the parameter to the auth() but then you would need to create a new enhanced client. i believe you might want to enable/disable the access at the transaction level.
To rephrase, sometimes a single user of elevated "role" wants to view the application data the same as other users but by toggling an "flag" they can now include rows previously excluded (ie. archived, deleted)
Describe the solution you'd like
This could then be used as such:
Describe alternatives you've considered
Now some the examples above are contrived and arguably pointless, for example the
publishedBetween
could/should just be written in the where clause and this layer of abstraction is complicated. I agree, the example was to illustrate the concept.The real benefit here is for complex use-cases like effectiveDated/Versioned/Temporal models and "version" control, where a filter enabled at the top level will be enabled for relations that invoke the same filter name.
Then query the tree -->