Skip to content

Commit

Permalink
feat: 🎸 support auto increment
Browse files Browse the repository at this point in the history
Implements support for auto increment (serial) fields from Postgres
datasources. Such fields are denoted by an empty `@default` applied to
an `Int` field.
  • Loading branch information
p5quared committed Sep 18, 2024
1 parent 9351b4d commit ed91877
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
InputObjectDefinitionWrapper,
InvalidDirectiveError,
isDynamoDbModel,
isPostgresModel,
MappingTemplate,
TransformerPluginBase,
} from '@aws-amplify/graphql-transformer-core';
Expand All @@ -22,7 +23,6 @@ import {
Kind,
ObjectTypeDefinitionNode,
StringValueNode,
TypeNode,
} from 'graphql';
import { methodCall, printBlock, qref, raw, ref, str } from 'graphql-mapping-template';
import { getBaseType, isEnum, isListType, isScalarOrEnum, ModelResourceIDs, toCamelCase } from 'graphql-transformer-common';
Expand All @@ -31,16 +31,24 @@ import { TypeValidators } from './validators';

const nonStringTypes = ['Int', 'Float', 'Boolean', 'AWSTimestamp', 'AWSJSON'];

const validateFieldType = (ctx: TransformerSchemaVisitStepContextProvider, type: TypeNode): void => {
const validateFieldType = (ctx: TransformerSchemaVisitStepContextProvider, config: DefaultValueDirectiveConfiguration): void => {
const type = config.field.type;
const argc = config.directive.arguments!.length;
const enums = ctx.output.getTypeDefinitionsOfKind(Kind.ENUM_TYPE_DEFINITION) as EnumTypeDefinitionNode[];
if (isListType(type) || !isScalarOrEnum(type, enums)) {
throw new InvalidDirectiveError('The @default directive may only be added to scalar or enum field types.');
}
if (isPostgresModel(ctx, config.object.name.value) && argc === 0 && getBaseType(type) !== 'Int') {
throw new InvalidDirectiveError('The empty @default (auto-increment) may only be applied to integer fields.');
}
};

const validateDirectiveArguments = (directive: DirectiveNode): void => {
if (directive.arguments!.length === 0) throw new InvalidDirectiveError('The @default directive must have a value property');
if (directive.arguments!.length > 1) throw new InvalidDirectiveError('The @default directive only takes a value property');
const validateDirectiveArguments = (ctx: TransformerSchemaVisitStepContextProvider, config: DefaultValueDirectiveConfiguration): void => {
const argc = config.directive.arguments!.length;
const isPostgres = isPostgresModel(ctx, config.object.name.value);
if (!isPostgres && argc === 0)
throw new InvalidDirectiveError('The @default directive requires a value property on non Postgres datasources.');
if (argc > 1) throw new InvalidDirectiveError('The @default directive only takes a value property');
};

const validateModelDirective = (config: DefaultValueDirectiveConfiguration): void => {
Expand Down Expand Up @@ -74,8 +82,8 @@ const validateDefaultValueType = (ctx: TransformerSchemaVisitStepContextProvider

const validate = (ctx: TransformerSchemaVisitStepContextProvider, config: DefaultValueDirectiveConfiguration): void => {
validateModelDirective(config);
validateFieldType(ctx, config.field.type);
validateDirectiveArguments(config.directive);
validateFieldType(ctx, config);
validateDirectiveArguments(ctx, config);

// Validate the default values only for the DynamoDB datasource.
// For SQL, the database determines and sets the default value. We will not validate the value in transformers.
Expand Down Expand Up @@ -123,6 +131,10 @@ export class DefaultValueTransformer extends TransformerPluginBase {
const input = InputObjectDefinitionWrapper.fromObject(name, config.object, ctx.inputDocument);
const fieldWrapper = input.fields.find((f) => f.name === config.field.name.value);
fieldWrapper?.makeNullable();

if (isPostgresModel(ctx, typeName)) {
ctx.output.updateInput(input.serialize());
}
}
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ exports[`Directive Definitions DefaultDirective 1`] = `
Object {
"defaults": Object {},
"definition": "
directive @default(value: String!) on FIELD_DEFINITION
directive @default(value: String) on FIELD_DEFINITION
",
"name": "default",
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Directive } from './directive';

const name = 'default';
const definition = /* GraphQL */ `
directive @${name}(value: String!) on FIELD_DEFINITION
directive @${name}(value: String) on FIELD_DEFINITION
`;
const defaults = {};

Expand Down

0 comments on commit ed91877

Please sign in to comment.