Skip to content

Commit

Permalink
Disable additional .array() modifier (#406)
Browse files Browse the repository at this point in the history
Co-authored-by: Ivan Artemiev <29709626+iartemiev@users.noreply.github.com>
  • Loading branch information
zxl629 and iartemiev committed Dec 9, 2024
1 parent cd8f4bd commit 2a9282b
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/selfish-comics-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@aws-amplify/data-schema': minor
---

Disable additional .array() modifier on model field definition
5 changes: 5 additions & 0 deletions packages/data-schema/__tests__/ModelField.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,8 @@ describe('field level auth', () => {
expect(field.data.authorization).toMatchSnapshot();
});
});

it('array modifier becomes unavailable after being used once', () => {
// @ts-expect-error .array() is not a valid modifier after being used once
a.model({ values: a.string().required().array().required().array().required() });
});
3 changes: 2 additions & 1 deletion packages/data-schema/docs/data-schema.modelfield.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ Public API for the chainable builder methods exposed by Model Field. The type is
export type ModelField<T extends ModelFieldTypeParamOuter = ModelFieldTypeParamOuter, UsedMethod extends UsableModelFieldKey = never, Auth = undefined> = Omit<{
[__auth]?: Auth;
[brandSymbol]: typeof brandName;
[internal](): ModelField<T>;
required(): ModelField<Required<T>, UsedMethod | 'required'>;
array(): ModelField<ArrayField<T>, Exclude<UsedMethod, 'required'>>;
array(): ModelField<ArrayField<T>, Exclude<UsedMethod, 'required'> | 'array'>;
default(value?: ModelFieldTypeParamOuter): ModelField<T, UsedMethod | 'default'>;
authorization<AuthRuleType extends Authorization<any, any, any>>(callback: (allow: Omit<AllowModifier, 'resource'>) => AuthRuleType | AuthRuleType[]): ModelField<T, UsedMethod | 'authorization', AuthRuleType>;
}, UsedMethod>;
Expand Down
16 changes: 14 additions & 2 deletions packages/data-schema/src/ModelField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const __auth = Symbol('__auth');
export const __generated = Symbol('__generated');

const brandName = 'modelField';
const internal = Symbol('internal');

export enum ModelFieldType {
Id = 'ID',
Expand Down Expand Up @@ -82,7 +83,7 @@ export type BaseModelField<

export type UsableModelFieldKey = satisfy<
methodKeyOf<ModelField>,
'required' | 'default' | 'authorization'
'required' | 'default' | 'authorization' | 'array'
>;

/**
Expand All @@ -102,6 +103,14 @@ export type ModelField<
[__auth]?: Auth;
[brandSymbol]: typeof brandName;

/**
* Internal non-omittable method that allows `BaseModelField` to retain a reference to `T` type arg in `ModelField`.
* Since all public methods are omittable, the evaluated `BaseModelField` loses type information unless
* some property on the type is guaranteed to reference `T`
* Context: https://github.com/aws-amplify/amplify-api-next/pull/406/files#r1869481467
*/
[internal](): ModelField<T>;

/**
* Marks a field as required.
*/
Expand All @@ -110,7 +119,7 @@ export type ModelField<
/**
* Converts a field type definition to an array of the field type.
*/
array(): ModelField<ArrayField<T>, Exclude<UsedMethod, 'required'>>;
array(): ModelField<ArrayField<T>, Exclude<UsedMethod, 'required'> | 'array'>;
// TODO: should be T, but .array breaks this constraint. Fix later
/**
* Sets a default value for the scalar type.
Expand Down Expand Up @@ -199,6 +208,9 @@ function _field<T extends ModelFieldTypeParamOuter>(fieldType: ModelFieldType) {
return this;
},
...brand(brandName),
[internal]() {
return this;
},
} as ModelField<T>;

// this double cast gives us a Subtyping Constraint i.e., hides `data` from the public API,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -681,3 +681,18 @@ describe('Specify an enum field type', () => {
});
});
});

test('Disallow additional array modifier', () => {
a.schema({
ToDo: a.model({
values: a
.string()
.required()
.array()
.required()
// @ts-expect-error
.array()
.required(),
}),
})
});

0 comments on commit 2a9282b

Please sign in to comment.