Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@
- [x] JSDoc for CRUD methods
- [x] Cache validation schemas
- [x] Compound ID
- [ ] Cross field comparison
- [x] Many-to-many relation
- [x] Self relation
- [ ] Empty AND/OR/NOT behavior
Expand All @@ -101,6 +100,7 @@
- [x] Validation
- [ ] Access Policy
- [ ] Short-circuit pre-create check for scalar-field only policies
- [x] Field-level policies
- [x] Inject "on conflict do update"
- [x] `check` function
- [ ] Custom functions
Expand Down
7 changes: 7 additions & 0 deletions packages/language/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,13 @@ export function isRelationshipField(field: DataField) {
return isDataModel(field.type.reference?.ref);
}

/**
* Returns if the given field is a computed field.
*/
export function isComputedField(field: DataField) {
return hasAttribute(field, '@computed');
}

export function isDelegateModel(node: AstNode) {
return isDataModel(node) && hasAttribute(node, '@@delegate');
}
Expand Down
24 changes: 12 additions & 12 deletions packages/language/src/validators/attribute-application-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
isAuthOrAuthMemberAccess,
isBeforeInvocation,
isCollectionPredicate,
isComputedField,
isDataFieldReference,
isDelegateModel,
isRelationshipField,
Expand Down Expand Up @@ -261,23 +262,22 @@ export default class AttributeApplicationValidator implements AstValidator<Attri
});
return;
}
const kindItems = this.validatePolicyKinds(kind, ['read', 'update', 'all'], attr, accept);
this.validatePolicyKinds(kind, ['read', 'update', 'all'], attr, accept);

const expr = attr.args[1]?.value;
if (expr && AstUtils.streamAst(expr).some((node) => isBeforeInvocation(node))) {
accept('error', `"before()" is not allowed in field-level policy rules`, { node: expr });
accept('error', `"before()" is not allowed in field-level policies`, { node: expr });
}

// 'update' rules are not allowed for relation fields
if (kindItems.includes('update') || kindItems.includes('all')) {
const field = attr.$container as DataField;
if (isRelationshipField(field)) {
accept(
'error',
`Field-level policy rules with "update" or "all" kind are not allowed for relation fields. Put rules on foreign-key fields instead.`,
{ node: attr },
);
}
// relation fields are not allowed
const field = attr.$container as DataField;

if (isRelationshipField(field)) {
accept('error', `Field-level policies are not allowed for relation fields.`, { node: attr });
}

if (isComputedField(field)) {
accept('error', `Field-level policies are not allowed for computed fields.`, { node: attr });
}
}

Expand Down
Loading