{"id":18609803,"url":"https://github.com/unlight/prisma-permissions-experiment","last_synced_at":"2025-11-02T20:30:30.306Z","repository":{"id":138161438,"uuid":"318613040","full_name":"unlight/prisma-permissions-experiment","owner":"unlight","description":"Prisma experiment - permissions stored in database","archived":false,"fork":false,"pushed_at":"2021-12-04T16:16:47.000Z","size":410,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-12-27T01:25:44.571Z","etag":null,"topics":["prisma","prisma2"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unlight.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-04T19:13:16.000Z","updated_at":"2022-12-24T15:31:59.000Z","dependencies_parsed_at":null,"dependency_job_id":"8ae3bbc3-c3ca-4420-b103-1d6fb6f006d4","html_url":"https://github.com/unlight/prisma-permissions-experiment","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unlight%2Fprisma-permissions-experiment","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unlight%2Fprisma-permissions-experiment/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unlight%2Fprisma-permissions-experiment/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unlight%2Fprisma-permissions-experiment/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unlight","download_url":"https://codeload.github.com/unlight/prisma-permissions-experiment/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239400596,"owners_count":19632049,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["prisma","prisma2"],"created_at":"2024-11-07T03:07:20.261Z","updated_at":"2025-11-02T20:30:30.266Z","avatar_url":"https://github.com/unlight.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# prisma-permissions-experiment\n\n```sh\nnpm run dbpush\nnpx ts-node src/feed\n```\n\nGoal is to have permissions stored in database and restrict access to entries.\n\nFor example, we have blog with posts, each post can be published in one category.\nUser can have multiple roles. Permission table will look:\n\n| permissionId | roleId | categoryId | viewPosts | editAny |\n| -----------: | -----: | ---------: | --------: | ------: |\n|            1 |      1 |          1 |         1 |       0 |\n|            2 |      2 |       NULL |         1 |       1 |\n\nFirst row tells that user with roleId = 1 can view posts in categoryId = 1.  \nSecond row tells that user with roleId = 2 can view posts in any category.\n\nOur query should look (does not work).\n\n```ts\nconst feed = await prisma.post.findMany({\n  where: {\n    category: {\n      permissions: {\n        some: {\n          OR: [\n            { viewPosts: true, categoryId: null },\n            {\n              viewPosts: true,\n              role: {\n                users: {\n                  some: {\n                    userId: user.userId,\n                  },\n                },\n              },\n            },\n          ],\n        },\n      },\n    },\n  },\n});\n```\n\nAnd it does not work because prisma generates contradictory join conditions something like\n`t1.category is not null and t2.categoryId is null`\n\n### Solution 1\n\nSeparate query for checking `categoryId = null`\n\n```ts\nconst hasFullPermissions = Boolean(\n  await prisma.permission.findFirst({\n    select: {\n      categoryId: true,\n    },\n    where: {\n      viewPosts: true,\n      categoryId: null,\n      role: {\n        users: {\n          some: {\n            userId: { equals: user.userId },\n          },\n        },\n      },\n    },\n  }),\n);\n```\n\n```ts\nconst feed = await prisma.post.findMany({\n  where: {\n    category: hasFullPermissions\n      ? {}\n      : {\n          permissions: {\n            some: {\n              viewPosts: true,\n              role: {\n                users: {\n                  some: {\n                    userId: user.userId,\n                  },\n                },\n              },\n            },\n          },\n        },\n  },\n});\n```\n\n#### Pros/cons\n\n- (-) Additional query/code\n- (+) Posts can be published without category\n\n### Solution 2\n\nExplicitly define permissions for specific role and category\n\n| permissionId | roleId | categoryId | viewPosts | editAny |\n| -----------: | -----: | ---------: | --------: | ------: |\n|            1 |      1 |          1 |         1 |       0 |\n|            2 |      2 |          1 |         1 |       1 |\n|            3 |      2 |          2 |         1 |       1 |\n\nWe replaced recored for roleId = 2 with categoryId = null by 2 rows for each categories\n\n#### Pros/Cons\n\n- (+) No additional code\n- (-) Post cannot be published without category\n- (+/-) Additional rows in tables which grows by M\\*N\n  (with 20 categories and 5 roles we must insert 5\\*20 = 100 records which is not big deal for database)\n\n### Non categorized permissions\n\nFor example, extend solution 2\n\n| permissionId | roleId | categoryId | viewPosts | editAny | searchPosts | favoritePosts |\n| -----------: | -----: | ---------: | --------: | ------: | ----------- | ------------- |\n|            1 |      1 |          1 |         1 |       0 | NULL        | NULL          |\n|            2 |      2 |          1 |         1 |       1 | NULL        | NULL          |\n|            3 |      2 |          2 |         1 |       1 | NULL        | NULL          |\n|            4 |      1 |       NULL |      NULL |    NULL | 1           | 1             |\n\n### 3rd party\n\n- https://github.com/stalniy/casl/tree/master/packages/casl-prisma\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funlight%2Fprisma-permissions-experiment","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funlight%2Fprisma-permissions-experiment","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funlight%2Fprisma-permissions-experiment/lists"}