Skip to content

Commit 2a9282b

Browse files
zxl629iartemiev
andcommitted
Disable additional .array() modifier (#406)
Co-authored-by: Ivan Artemiev <[email protected]>
1 parent cd8f4bd commit 2a9282b

File tree

5 files changed

+41
-3
lines changed

5 files changed

+41
-3
lines changed

.changeset/selfish-comics-kiss.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@aws-amplify/data-schema': minor
3+
---
4+
5+
Disable additional .array() modifier on model field definition

packages/data-schema/__tests__/ModelField.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,8 @@ describe('field level auth', () => {
9999
expect(field.data.authorization).toMatchSnapshot();
100100
});
101101
});
102+
103+
it('array modifier becomes unavailable after being used once', () => {
104+
// @ts-expect-error .array() is not a valid modifier after being used once
105+
a.model({ values: a.string().required().array().required().array().required() });
106+
});

packages/data-schema/docs/data-schema.modelfield.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ Public API for the chainable builder methods exposed by Model Field. The type is
1212
export type ModelField<T extends ModelFieldTypeParamOuter = ModelFieldTypeParamOuter, UsedMethod extends UsableModelFieldKey = never, Auth = undefined> = Omit<{
1313
[__auth]?: Auth;
1414
[brandSymbol]: typeof brandName;
15+
[internal](): ModelField<T>;
1516
required(): ModelField<Required<T>, UsedMethod | 'required'>;
16-
array(): ModelField<ArrayField<T>, Exclude<UsedMethod, 'required'>>;
17+
array(): ModelField<ArrayField<T>, Exclude<UsedMethod, 'required'> | 'array'>;
1718
default(value?: ModelFieldTypeParamOuter): ModelField<T, UsedMethod | 'default'>;
1819
authorization<AuthRuleType extends Authorization<any, any, any>>(callback: (allow: Omit<AllowModifier, 'resource'>) => AuthRuleType | AuthRuleType[]): ModelField<T, UsedMethod | 'authorization', AuthRuleType>;
1920
}, UsedMethod>;

packages/data-schema/src/ModelField.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export const __auth = Symbol('__auth');
1414
export const __generated = Symbol('__generated');
1515

1616
const brandName = 'modelField';
17+
const internal = Symbol('internal');
1718

1819
export enum ModelFieldType {
1920
Id = 'ID',
@@ -82,7 +83,7 @@ export type BaseModelField<
8283

8384
export type UsableModelFieldKey = satisfy<
8485
methodKeyOf<ModelField>,
85-
'required' | 'default' | 'authorization'
86+
'required' | 'default' | 'authorization' | 'array'
8687
>;
8788

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

106+
/**
107+
* Internal non-omittable method that allows `BaseModelField` to retain a reference to `T` type arg in `ModelField`.
108+
* Since all public methods are omittable, the evaluated `BaseModelField` loses type information unless
109+
* some property on the type is guaranteed to reference `T`
110+
* Context: https://github.com/aws-amplify/amplify-api-next/pull/406/files#r1869481467
111+
*/
112+
[internal](): ModelField<T>;
113+
105114
/**
106115
* Marks a field as required.
107116
*/
@@ -110,7 +119,7 @@ export type ModelField<
110119
/**
111120
* Converts a field type definition to an array of the field type.
112121
*/
113-
array(): ModelField<ArrayField<T>, Exclude<UsedMethod, 'required'>>;
122+
array(): ModelField<ArrayField<T>, Exclude<UsedMethod, 'required'> | 'array'>;
114123
// TODO: should be T, but .array breaks this constraint. Fix later
115124
/**
116125
* Sets a default value for the scalar type.
@@ -199,6 +208,9 @@ function _field<T extends ModelFieldTypeParamOuter>(fieldType: ModelFieldType) {
199208
return this;
200209
},
201210
...brand(brandName),
211+
[internal]() {
212+
return this;
213+
},
202214
} as ModelField<T>;
203215

204216
// this double cast gives us a Subtyping Constraint i.e., hides `data` from the public API,

packages/integration-tests/__tests__/defined-behavior/1-patterns/add-fields.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,3 +681,18 @@ describe('Specify an enum field type', () => {
681681
});
682682
});
683683
});
684+
685+
test('Disallow additional array modifier', () => {
686+
a.schema({
687+
ToDo: a.model({
688+
values: a
689+
.string()
690+
.required()
691+
.array()
692+
.required()
693+
// @ts-expect-error
694+
.array()
695+
.required(),
696+
}),
697+
})
698+
});

0 commit comments

Comments
 (0)