Skip to content

Commit

Permalink
Improve edge cases for belong to with required foreign key
Browse files Browse the repository at this point in the history
  • Loading branch information
s1owjke committed Oct 28, 2024
1 parent 28d37b6 commit a94daa8
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 32 deletions.
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,12 @@ After that, all non-raw queries will be executed according to the defined permis

## Edge cases

A known edge case involves one-to-one mandatory relationships on the owner side (the entity containing the foreign key).
A known edge case involves all belongs-to mandatory relationships on the owner side (the entity containing the foreign key).

Prisma [doesn't generate](https://github.com/prisma/prisma/issues/15708) filters in that case due to potential referential integrity violations, which could lead to inconsistent query results.
Prisma [doesn't generate](https://github.com/prisma/prisma/issues/15708) filters in that case due to potential referential integrity violations, which could lead to inconsistent query results. Because we can't apply RLS filters in this case, no additional "where" clauses are added.

As a temporary solution, because we can't apply RLS filters in this case, no additional "where" clauses are added. Please handle this at the policy level.
When models have required foreign keys with restricted read access, you have three options:

- make them optional - change required foreign keys to allow `null` values when policy restricts reading
- handle at policy level - restrict reading models with required foreign keys using consistent policy filters
- accept current behavior - be aware that such relations are readable or handle it at app level
58 changes: 29 additions & 29 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,35 +164,8 @@ const resolveRelationSelect = async (
const relationModelName = fieldDef.type;
const relationPermissions = permissionsConfig[relationModelName];

if (fieldDef.isList) {
if (!relationPermissions.read) {
return { where: generateImpossibleWhere(fieldsMap[modelName]) };
} else if (relationPermissions.read !== true && selectValue === true) {
return { where: await resolvePermissionDefinition(relationPermissions.read, context) }; //
} else if (relationPermissions.read !== true && selectValue !== false) {
const [selectAndInclude, permissionDefinition] = await Promise.all([
resolveSelectAndInclude(
permissionsConfig,
context,
authorizationError,
fieldsMap,
relationModelName,
selectValue.select,
selectValue.include,
),
resolvePermissionDefinition(relationPermissions.read, context),
]);

return {
...selectValue,
...selectAndInclude,
where: mergeWhere(selectValue.where, permissionDefinition),
};
}
} else {
const foreignKeys = fieldDef.relationFromFields?.map((relationFromField) => fieldsMap[modelName][relationFromField]) || [];

if (foreignKeys.every((foreignKey) => foreignKey.isRequired) && relationPermissions.read !== true && selectValue !== false) {
if (!fieldDef.isList && fieldDef.isRequired) {
if (relationPermissions.read !== true && selectValue !== false) {
return {
...selectValue,
...(await resolveSelectAndInclude(
Expand All @@ -205,9 +178,36 @@ const resolveRelationSelect = async (
selectValue.include,
)),
};
} else {
return selectValue;
}
}

if (!relationPermissions.read) {
return { where: generateImpossibleWhere(fieldsMap[modelName]) };
} else if (relationPermissions.read !== true && selectValue === true) {
return { where: await resolvePermissionDefinition(relationPermissions.read, context) }; //
} else if (relationPermissions.read !== true && selectValue !== false) {
const [selectAndInclude, permissionDefinition] = await Promise.all([
resolveSelectAndInclude(
permissionsConfig,
context,
authorizationError,
fieldsMap,
relationModelName,
selectValue.select,
selectValue.include,
),
resolvePermissionDefinition(relationPermissions.read, context),
]);

return {
...selectValue,
...selectAndInclude,
where: mergeWhere(selectValue.where, permissionDefinition),
};
}

return selectValue;
});
};
Expand Down

0 comments on commit a94daa8

Please sign in to comment.