@cerbos/orm-prisma 2.0.0-alpha.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -4
- package/lib/cjs/index.d.ts +6 -4
- package/lib/index.d.ts +6 -4
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,22 +1,37 @@
|
|
|
1
1
|
# Cerbos + Prisma ORM Adapter
|
|
2
2
|
|
|
3
|
-
An adapter library that takes a [Cerbos](https://cerbos.dev) Query Plan ([PlanResources API](https://docs.cerbos.dev/cerbos/latest/api/index.html#resources-query-plan)) response and converts it into a [Prisma](https://prisma.io) where
|
|
3
|
+
An adapter library that takes a [Cerbos](https://cerbos.dev) Query Plan ([PlanResources API](https://docs.cerbos.dev/cerbos/latest/api/index.html#resources-query-plan)) response and converts it into a [Prisma](https://prisma.io) where clause object. This is designed to work alongside a project using the [Cerbos Javascript SDK](https://github.com/cerbos/cerbos-sdk-javascript).
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
### Supported Operators
|
|
8
8
|
|
|
9
|
+
#### Basic Operators
|
|
10
|
+
|
|
9
11
|
- Logical operators: `and`, `or`, `not`
|
|
10
12
|
- Comparison operators: `eq`, `ne`, `lt`, `gt`, `lte`, `gte`, `in`
|
|
11
|
-
- Relation operators: `some`, `none`, `is`, `isNot`, `hasIntersection`
|
|
12
13
|
- String operations: `startsWith`, `endsWith`, `contains`, `isSet`
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
#### Relation Operators
|
|
16
|
+
|
|
17
|
+
- One-to-one: `is`, `isNot`
|
|
18
|
+
- One-to-many/Many-to-many: `some`, `none`, `every`
|
|
19
|
+
- Collection operators: `exists`, `exists_one`, `all`, `filter`
|
|
20
|
+
- Set operations: `hasIntersection`
|
|
21
|
+
|
|
22
|
+
#### Advanced Features
|
|
23
|
+
|
|
24
|
+
- Deep nested relations support
|
|
25
|
+
- Automatic field inference
|
|
26
|
+
- Collection mapping and filtering
|
|
27
|
+
- Complex condition combinations
|
|
28
|
+
- Type-safe field mappings
|
|
15
29
|
|
|
16
30
|
## Requirements
|
|
17
31
|
|
|
18
32
|
- Cerbos > v0.40
|
|
19
33
|
- `@cerbos/http` or `@cerbos/grpc` client
|
|
34
|
+
- Prisma > v6.0
|
|
20
35
|
|
|
21
36
|
## Installation
|
|
22
37
|
|
|
@@ -42,6 +57,49 @@ queryPlanToPrisma({
|
|
|
42
57
|
|
|
43
58
|
### Basic Example
|
|
44
59
|
|
|
60
|
+
1. Create a basic policy file in the `policies` directory:
|
|
61
|
+
|
|
62
|
+
```yaml
|
|
63
|
+
apiVersion: api.cerbos.dev/v1
|
|
64
|
+
resourcePolicy:
|
|
65
|
+
resource: resource
|
|
66
|
+
version: default
|
|
67
|
+
rules:
|
|
68
|
+
- actions: ["view"]
|
|
69
|
+
effect: EFFECT_ALLOW
|
|
70
|
+
roles: ["USER"]
|
|
71
|
+
condition:
|
|
72
|
+
match:
|
|
73
|
+
expr: request.resource.attr.status == "active"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
2. Start Cerbos PDP:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
docker run --rm -i -p 3592:3592 -v $(pwd)/policies:/policies ghcr.io/cerbos/cerbos:latest
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
3. Create Prisma schema (`prisma/schema.prisma`):
|
|
83
|
+
|
|
84
|
+
```prisma
|
|
85
|
+
datasource db {
|
|
86
|
+
provider = "sqlite"
|
|
87
|
+
url = env("DATABASE_URL")
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
generator client {
|
|
91
|
+
provider = "prisma-client-js"
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
model Resource {
|
|
95
|
+
id Int @id @default(autoincrement())
|
|
96
|
+
title String
|
|
97
|
+
status String
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
4. Implement the mapper
|
|
102
|
+
|
|
45
103
|
```ts
|
|
46
104
|
import { GRPC as Cerbos } from "@cerbos/grpc";
|
|
47
105
|
import { PrismaClient } from "@prisma/client";
|
|
@@ -263,6 +321,89 @@ const result = await primsa.resource.findMany({
|
|
|
263
321
|
});
|
|
264
322
|
```
|
|
265
323
|
|
|
324
|
+
## Types
|
|
325
|
+
|
|
326
|
+
### Query Plan Response Types
|
|
327
|
+
|
|
328
|
+
The adapter is fully typed and provides clear type definitions for all responses:
|
|
329
|
+
|
|
330
|
+
```ts
|
|
331
|
+
import { PlanKind, QueryPlanToPrismaResult } from "@cerbos/orm-prisma";
|
|
332
|
+
|
|
333
|
+
// The result will be one of these types:
|
|
334
|
+
type QueryPlanToPrismaResult =
|
|
335
|
+
| {
|
|
336
|
+
kind: PlanKind.ALWAYS_ALLOWED | PlanKind.ALWAYS_DENIED;
|
|
337
|
+
}
|
|
338
|
+
| {
|
|
339
|
+
kind: PlanKind.CONDITIONAL;
|
|
340
|
+
filters: Record<string, any>;
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
// Example usage with type narrowing:
|
|
344
|
+
const result = queryPlanToPrisma({ queryPlan });
|
|
345
|
+
|
|
346
|
+
if (result.kind === PlanKind.CONDITIONAL) {
|
|
347
|
+
// TypeScript knows `filters` exists here
|
|
348
|
+
const records = await prisma.resource.findMany({
|
|
349
|
+
where: result.filters,
|
|
350
|
+
});
|
|
351
|
+
} else if (result.kind === PlanKind.ALWAYS_ALLOWED) {
|
|
352
|
+
// No filters needed
|
|
353
|
+
const records = await prisma.resource.findMany();
|
|
354
|
+
} else {
|
|
355
|
+
// Must be ALWAYS_DENIED
|
|
356
|
+
return [];
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
### Mapper Types
|
|
361
|
+
|
|
362
|
+
The mapper configuration is also fully typed:
|
|
363
|
+
|
|
364
|
+
```ts
|
|
365
|
+
type MapperConfig = {
|
|
366
|
+
field?: string;
|
|
367
|
+
relation?: {
|
|
368
|
+
name: string;
|
|
369
|
+
type: "one" | "many";
|
|
370
|
+
field?: string;
|
|
371
|
+
fields?: {
|
|
372
|
+
[key: string]: MapperConfig; // Recursive for nested fields
|
|
373
|
+
};
|
|
374
|
+
};
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
type Mapper = { [key: string]: MapperConfig } | ((key: string) => MapperConfig);
|
|
378
|
+
```
|
|
379
|
+
|
|
266
380
|
## Full Example
|
|
267
381
|
|
|
268
382
|
A complete example application using this adapter can be found at [https://github.com/cerbos/express-prisma-cerbos](https://github.com/cerbos/express-prisma-cerbos)
|
|
383
|
+
|
|
384
|
+
## Resources
|
|
385
|
+
|
|
386
|
+
### Documentation
|
|
387
|
+
|
|
388
|
+
- [Cerbos Documentation](https://docs.cerbos.dev)
|
|
389
|
+
- [Prisma Documentation](https://www.prisma.io/docs)
|
|
390
|
+
- [Query Plan API Reference](https://docs.cerbos.dev/cerbos/latest/api/index.html#resources-query-plan)
|
|
391
|
+
|
|
392
|
+
### Examples and Tutorials
|
|
393
|
+
|
|
394
|
+
- [Express + Prisma + Cerbos Example](https://github.com/cerbos/express-prisma-cerbos)
|
|
395
|
+
- [Cerbos Query Planning Guide](https://docs.cerbos.dev/cerbos/latest/policies/compile.html)
|
|
396
|
+
- [Prisma Filtering Guide](https://www.prisma.io/docs/concepts/components/prisma-client/filtering-and-sorting)
|
|
397
|
+
|
|
398
|
+
### Related Projects
|
|
399
|
+
|
|
400
|
+
- [Cerbos JavaScript SDK](https://github.com/cerbos/cerbos-sdk-javascript)
|
|
401
|
+
|
|
402
|
+
### Community
|
|
403
|
+
|
|
404
|
+
- [Cerbos Slack](https://community.cerbos.dev)
|
|
405
|
+
- [Cerbos GitHub Discussions](https://github.com/cerbos/cerbos/discussions)
|
|
406
|
+
|
|
407
|
+
## License
|
|
408
|
+
|
|
409
|
+
Apache 2.0 - See [LICENSE](../LICENSE) for more information.
|
package/lib/cjs/index.d.ts
CHANGED
|
@@ -19,10 +19,12 @@ export interface QueryPlanToPrismaArgs {
|
|
|
19
19
|
queryPlan: PlanResourcesResponse;
|
|
20
20
|
mapper?: Mapper;
|
|
21
21
|
}
|
|
22
|
-
export
|
|
23
|
-
kind: PlanKind;
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
export type QueryPlanToPrismaResult = {
|
|
23
|
+
kind: PlanKind.ALWAYS_ALLOWED | PlanKind.ALWAYS_DENIED;
|
|
24
|
+
} | {
|
|
25
|
+
kind: PlanKind.CONDITIONAL;
|
|
26
|
+
filters: Record<string, any>;
|
|
27
|
+
};
|
|
26
28
|
/**
|
|
27
29
|
* Converts a Cerbos query plan to a Prisma filter.
|
|
28
30
|
* @param {QueryPlanToPrismaArgs} args - The arguments containing the query plan and mapper.
|
package/lib/index.d.ts
CHANGED
|
@@ -19,10 +19,12 @@ export interface QueryPlanToPrismaArgs {
|
|
|
19
19
|
queryPlan: PlanResourcesResponse;
|
|
20
20
|
mapper?: Mapper;
|
|
21
21
|
}
|
|
22
|
-
export
|
|
23
|
-
kind: PlanKind;
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
export type QueryPlanToPrismaResult = {
|
|
23
|
+
kind: PlanKind.ALWAYS_ALLOWED | PlanKind.ALWAYS_DENIED;
|
|
24
|
+
} | {
|
|
25
|
+
kind: PlanKind.CONDITIONAL;
|
|
26
|
+
filters: Record<string, any>;
|
|
27
|
+
};
|
|
26
28
|
/**
|
|
27
29
|
* Converts a Cerbos query plan to a Prisma filter.
|
|
28
30
|
* @param {QueryPlanToPrismaArgs} args - The arguments containing the query plan and mapper.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cerbos/orm-prisma",
|
|
3
|
-
"version": "2.0.0
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"homepage": "https://cerbos.dev",
|
|
5
5
|
"description": "",
|
|
6
6
|
"private": false,
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "tsc -p tsconfig.json && tsc -p tsconfig-cjs.json",
|
|
14
14
|
"prepare": "npm run build",
|
|
15
|
-
"preversion": "npm run lint",
|
|
16
15
|
"version": "git add -A src",
|
|
17
16
|
"postversion": "git push && git push --tags",
|
|
18
17
|
"test": "npx prisma db push --force-reset && cerbos run --log-level=error --set=storage.disk.directory=../policies --set=telemetry.disabled=true -- jest src/**.test.ts",
|
|
@@ -27,7 +26,8 @@
|
|
|
27
26
|
"prisma": "^6.4.1",
|
|
28
27
|
"ts-jest": "^29.0.0",
|
|
29
28
|
"ts-node": "^10.4.0",
|
|
30
|
-
"typescript": "^5.0.0"
|
|
29
|
+
"typescript": "^5.0.0",
|
|
30
|
+
"expect-type": "^1.1.0"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@cerbos/core": "^0.21.0",
|