import { SetTypeSubArg } from '@aws-amplify/data-schema-types'; import { Brand } from './util'; import { AllowModifier, Authorization, allow } from './Authorization'; import { __auth } from './ModelField'; const _brandName = 'ref'; type RefTypeData = { type: 'ref'; link: string; valueRequired: boolean; array: boolean; arrayRequired: boolean; mutationOperations: MutationOperations[]; authorization: Authorization[]; }; export type RefTypeParamShape = { type: 'ref'; link: string; valueRequired: boolean; array: boolean; arrayRequired: boolean; authorization: Authorization[]; }; type MutationOperations = 'create' | 'update' | 'delete'; /** * Reference type definition interface * * @param T - The shape of the reference type * @param K - The keys already defined */ export type RefType< T extends RefTypeParamShape, K extends keyof RefType = never, Auth = undefined, // Branding the exported type allows us to detect it // nominally in our mapped types, ignoring structural overlap with other types > = Omit< { /** * Marks a field as required. */ required(): RefType< SetTypeSubArg< T, T['array'] extends true ? 'arrayRequired' : 'valueRequired', true >, K | 'required' >; /** * Marks a field as an array of the specified ref type. */ array(): RefType< SetTypeSubArg, Exclude | 'array' >; /** * Configures field-level authorization rules. Pass in an array of authorizations `(allow => allow.____)` to mix and match * multiple authorization rules for this field. */ authorization>( callback: (allow: AllowModifier) => AuthRuleType | AuthRuleType[], ): RefType; mutations(operations: MutationOperations[]): RefType; }, K > & { // This is a lie. This property is never set at runtime. It's just used to smuggle auth types through. [__auth]?: Auth; } & Brand; function brandedBuilder( builder: Record & string, any>, ): RefType { return builder as RefType; } /** * Internal representation of Ref that exposes the `data` property. * Used at buildtime. */ export type InternalRef = RefType & { data: RefTypeData; }; function _ref(link: T['link']) { const data: RefTypeData = { type: 'ref', link, valueRequired: false, array: false, arrayRequired: false, mutationOperations: [], authorization: [], }; const builder: RefType = brandedBuilder({ required() { if (data.array) { data.arrayRequired = true; } else { data.valueRequired = true; } return this; }, array() { data.array = true; return this; }, authorization>( callback: (allow: AllowModifier) => AuthRuleType | AuthRuleType[], ) { const rules = callback(allow); data.authorization = Array.isArray(rules) ? rules : [rules]; return this; }, mutations(operations: MutationOperations[]) { data.mutationOperations = operations; return this; }, }); return { ...builder, data } as InternalRef as RefType; } type RefTypeArgFactory = { type: 'ref'; link: Link; valueRequired: false; array: false; arrayRequired: false; authorization: []; }; export function ref(link: T) { return _ref>(link); }