Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add error when using an owner field as a sort key field #517

Conversation

danielleadams
Copy link
Contributor

@danielleadams danielleadams commented Jun 6, 2022

Description of changes

As discussed, there's a breaking change when using owner @auth field as the @primaryKey's sort key. Therefore, the transformer will raise an error and abort the transform process when using the sub::username identity claim in which the owner attribute in the database is being used as the sort key.

Docs PR to follow.

Issue #, if available

Description of how you validated changes

Checklist

  • PR description included
  • yarn test passes
  • Tests are changed or added
  • Relevant documentation is changed or added (and PR referenced)

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@danielleadams danielleadams requested a review from a team June 6, 2022 22:37
Comment on lines 162 to 167
if (!validateNotOwnerAuth(sortKeyFieldName, config, ctx)) {
throw new InvalidDirectiveError(
`The primary key's sort key type '${sortKeyFieldName}' cannot be used as an owner @auth field too. Please user another field for the sort key.`
);
}

Copy link
Contributor

@sundersc sundersc Jun 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could adding this validation now affect any existing customer schema?

Copy link
Contributor Author

@danielleadams danielleadams Jun 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sundersc no - the feature flag has to be enabled OR they have to be using the new feature (which is behind a feature flag) to see this (https://github.com/aws-amplify/amplify-category-api/pull/517/files#diff-5f8c05424d524274f208c275f81ac9d5b2f6fbf6a878f0bb1daa27f65f4f4289R101). Also, this will go out with a semver major, so anyone already using the feature and using the owner as a sort key will know this is a breaking change.

sachscode
sachscode previously approved these changes Jun 7, 2022
Copy link
Contributor

@sachscode sachscode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just a few comments


if (!authDir) return true;

const dirRules = (authDir.arguments?.find(arg => arg.name.value === 'rules')?.value as ListValueNode).values;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can we ensure that dirRules is non-null before the ownerRules is initialized.

packages/amplify-graphql-index-transformer/src/utils.ts Outdated Show resolved Hide resolved
@danielleadams
Copy link
Contributor Author

@sachscode @sundersc this is ready to be re-reviewed/approved.

sachscode
sachscode previously approved these changes Jun 7, 2022
Copy link
Contributor

@sachscode sachscode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@danielleadams danielleadams force-pushed the raise-error-with-owner-auth-and-sort-key branch from ac1b8e8 to a66a7ce Compare June 8, 2022 20:35
@danielleadams
Copy link
Contributor Author

(Just rebased, so ready for rereview)

@danielleadams danielleadams force-pushed the raise-error-with-owner-auth-and-sort-key branch from 8ea0dd5 to 8eb758b Compare June 8, 2022 23:09
"The primary key's sort key type 'myOwnerField' cannot be used as an owner @auth field too. Please use another field for the sort key.",
);
});
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally I had put these tests in the index transformer because the validation seemed to fit better in the sort key validations that run. There was a problem with circular dependencies though during the build, so I moved these tests to the auth transformer to prevent the circular dependency (I believe it was index transformer -> auth -> relational -> index). I can create a follow up task to organize these tests within their module, or move them to the velocity tests.

}
});

const featureFlagEnabled = ctx.featureFlags.getBoolean('useSubUsernameForDefaultIdentityClaim');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want a default value here set to false?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this value isn't set in the project, .getBoolean will return the default value as configured between "existing" and "new" Amplify apps. (https://github.com/aws-amplify/amplify-cli/blob/master/packages/amplify-cli-core/src/feature-flags/featureFlags.ts#L218)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Also, the feature flags module always errors out if the feature flag is missing from the instance because it acts as a singleton, so it always needs to be set in tests too.)


(rule as ObjectValueNode).fields?.forEach(field => {
const name: string = field.name.value;
const { value } = field?.value as StringValueNode;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm wondering if this can throw an npe if value is not defined? As written it seems like you want this to kind of behave like field?.value?.value, but I think that w/ the destructing and typecasting here it's more like field?.value!!.value.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is really desireable we may need to do (field?.value as (StringValueNode | undefined))?.value;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change this to set value as a string and have handle undefined.

if (!authDir) return true;

const dirRules = (authDir.arguments?.find(arg => arg.name.value === 'rules')?.value as ListValueNode)?.values || [];
const hasOwnerFieldAsSortKey = dirRules.some(rule => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might pull this rule validation out into it's own helper for readability, then it's clear that you're just reducing that state, i.e return dirRules.some(ruleHasOwnerFieldAsSortKey);

Comment on lines 69 to 73
let isOwner = false;
let identityClaimIsSet = false;
let ownerFieldIsSet = false;
let usesMultiClaim = false;
let sortKeyFieldIsAuthField = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll OOS for this PR, since this isn't yet an established pattern, but I prefer to avoid let wherever possible, and rely instead on returning consistent shapes, and reducing state where necessary. In general for something like this I'd probably refactor to have your inner loop (i.e. rule.fields?.forEach turn into a rule.fields.map(doesRuleHaveOwnerForSortKeyField), then just return a .some for that mapped value. As written, I'm not sure if it's possible to have sortKeyFieldIsAuthField be set to true for a single rule, and usesImplicitOwnerField for another unrelated rule, and result in a false positive here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As written, there's some chance for state interaction between rules, which I don't think is by design. If we need rules to 'see' each other, we should make that super explicit, and either preprocess the necessary cross-rule state, or otherwise allow the rule checker to look at it's neighbors rather than relying on global state.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fine with that. This was the best way I could configure for my own readability since the GQL objects can be messy to parse (I always wanted to work on some GQL adapters to integrate the code into the transformers), but I can change the pattern. I'll refactor this.

alharris-at
alharris-at previously approved these changes Jun 9, 2022
sachscode
sachscode previously approved these changes Jun 10, 2022
Copy link
Contributor

@sachscode sachscode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@danielleadams danielleadams dismissed stale reviews from sachscode and alharris-at via fe018a2 June 10, 2022 19:13
Comment on lines 8 to 10
if (value === 'useSubUsernameForDefaultIdentityClaim') {
return true;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we move the default values to a new hash map and use that here? In that way, if we have to check for any new flags in the future, we don't have to add multiple if statements in the method.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can potentially OOS for this change. I actually added a simple createFeatureFlagProviderWithOverrides util in another PR that can just become our standard to simplify behavior and keep us from reimplementing on a per-test basis. Your call if you think it's blocking or not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with this in theory and am happy to follow up, but since this isn't an established pattern (and there's a mix of using these mock objects in the current tests) is it okay if consolidating the tests is a follow up? If this is blocking I can fix it, but the reason I had to add this feature flag to each test is because this is how the other tests do it.

Comment on lines +70 to +75
getBoolean: (value: string, defaultValue: boolean): boolean => {
if (value === 'useSubUsernameForDefaultIdentityClaim') {
return true;
}
return defaultValue;
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as the previous. If possible, please move this to a hash map.

$parent: ID
$child: ModelIDKeyConditionInput
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason to remove this field from an existing test?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, $child is no longer part of the primary key's query.

@alharris-at alharris-at merged commit 201032d into aws-amplify:main Jun 11, 2022
@danielleadams danielleadams deleted the raise-error-with-owner-auth-and-sort-key branch June 12, 2022 23:32
alharris-at added a commit to aws-amplify/amplify-cli that referenced this pull request Jun 13, 2022
danielleadams pushed a commit to aws-amplify/amplify-cli that referenced this pull request Jun 16, 2022
sachscode pushed a commit to aws-amplify/amplify-cli that referenced this pull request Jun 16, 2022
* chore: upgrade api category dependencies

* chore: reflect test updates from aws-amplify/amplify-category-api#517 in mock
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants