"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.HasOneTransformer = void 0;
const graphql_transformer_core_1 = require("@aws-amplify/graphql-transformer-core");
const graphql_transformer_common_1 = require("graphql-transformer-common");
const immer_1 = require("immer");
const schema_1 = require("./schema");
const utils_1 = require("./utils");
const generator_factory_1 = require("./resolver/generator-factory");
const has_one_directive_transformer_factory_1 = require("./has-one/has-one-directive-transformer-factory");
const directiveName = 'hasOne';
const directiveDefinition = `
  directive @${directiveName}(fields: [String!], references: [String!]) on FIELD_DEFINITION
`;
class HasOneTransformer extends graphql_transformer_core_1.TransformerPluginBase {
    constructor() {
        super('amplify-has-one-transformer', directiveDefinition);
        this.directiveList = [];
        this.field = (parent, definition, directive, context) => {
            const directiveWrapped = new graphql_transformer_core_1.DirectiveWrapper(directive);
            const args = directiveWrapped.getArguments({
                directiveName,
                object: parent,
                field: definition,
                directive,
            }, (0, graphql_transformer_core_1.generateGetArgumentsInput)(context.transformParameters));
            validate(args, context);
            this.directiveList.push(args);
        };
        this.mutateSchema = (context) => {
            const document = (0, immer_1.produce)(context.inputDocument, (draftDoc) => {
                var _a;
                const filteredDefs = (_a = draftDoc === null || draftDoc === void 0 ? void 0 : draftDoc.definitions) === null || _a === void 0 ? void 0 : _a.filter((def) => def.kind === 'ObjectTypeDefinition' || def.kind === 'ObjectTypeExtension');
                const objectDefs = new Map(filteredDefs.map((def) => [def.name.value, def]));
                objectDefs === null || objectDefs === void 0 ? void 0 : objectDefs.forEach((def) => {
                    var _a;
                    const filteredFields = (_a = def === null || def === void 0 ? void 0 : def.fields) === null || _a === void 0 ? void 0 : _a.filter((field) => { var _a; return (_a = field === null || field === void 0 ? void 0 : field.directives) === null || _a === void 0 ? void 0 : _a.some((dir) => dir.name.value === directiveName); });
                    filteredFields === null || filteredFields === void 0 ? void 0 : filteredFields.forEach((field) => {
                        var _a;
                        (_a = field === null || field === void 0 ? void 0 : field.directives) === null || _a === void 0 ? void 0 : _a.forEach((dir) => {
                            var _a, _b;
                            const connectionAttributeName = (0, utils_1.getConnectionAttributeName)(context.transformParameters, def.name.value, field.name.value, (0, utils_1.getObjectPrimaryKey)(def).name.value);
                            let hasFieldsDefined = false;
                            let removalIndex = -1;
                            (_a = dir === null || dir === void 0 ? void 0 : dir.arguments) === null || _a === void 0 ? void 0 : _a.forEach((arg, idx) => {
                                if (arg.name.value === 'fields') {
                                    if ((arg.value.kind === 'StringValue' && arg.value.value) ||
                                        (arg.value.kind === 'ListValue' && arg.value.values && arg.value.values.length > 0)) {
                                        hasFieldsDefined = true;
                                    }
                                    else {
                                        removalIndex = idx;
                                    }
                                }
                            });
                            if (removalIndex !== -1) {
                                (_b = dir === null || dir === void 0 ? void 0 : dir.arguments) === null || _b === void 0 ? void 0 : _b.splice(removalIndex, 1);
                            }
                            const relatedType = objectDefs.get((0, graphql_transformer_common_1.getBaseType)(field.type));
                            if (!hasFieldsDefined && relatedType) {
                                const sortKeyFields = (0, schema_1.convertSortKeyFieldsToSortKeyConnectionFields)((0, schema_1.getSortKeyFieldsNoContext)(relatedType), def, field);
                                const connField = (0, graphql_transformer_common_1.makeField)(connectionAttributeName, [], (0, graphql_transformer_common_1.isNonNullType)(field.type) ? (0, graphql_transformer_common_1.makeNonNullType)((0, graphql_transformer_common_1.makeNamedType)('ID')) : (0, graphql_transformer_common_1.makeNamedType)('ID'), []);
                                dir.arguments = [
                                    (0, graphql_transformer_common_1.makeArgument)('fields', (0, graphql_transformer_common_1.makeValueNode)([connectionAttributeName, ...sortKeyFields.map((skf) => skf.name.value)])),
                                ];
                                (0, schema_1.addFieldsToDefinition)(def, [connField, ...sortKeyFields]);
                            }
                        });
                    });
                });
            });
            return document;
        };
        this.prepare = (context) => {
            this.directiveList.forEach((config) => {
                const modelName = config.object.name.value;
                const dbType = (0, graphql_transformer_core_1.getStrategyDbTypeFromModel)(context, modelName);
                const dataSourceBasedTransformer = (0, has_one_directive_transformer_factory_1.getHasOneDirectiveTransformer)(dbType);
                dataSourceBasedTransformer.prepare(context, config);
            });
        };
        this.transformSchema = (ctx) => {
            const context = ctx;
            for (const config of this.directiveList) {
                const dbType = (0, graphql_transformer_core_1.getStrategyDbTypeFromTypeNode)(config.field.type, context);
                const dataSourceBasedTransformer = (0, has_one_directive_transformer_factory_1.getHasOneDirectiveTransformer)(dbType);
                dataSourceBasedTransformer.transformSchema(ctx, config);
                (0, schema_1.ensureHasOneConnectionField)(config, context);
            }
        };
        this.generateResolvers = (ctx) => {
            const context = ctx;
            for (const config of this.directiveList) {
                const dbType = (0, graphql_transformer_core_1.getStrategyDbTypeFromTypeNode)(config.field.type, context);
                const generator = (0, generator_factory_1.getGenerator)(dbType);
                generator.makeHasOneGetItemConnectionWithKeyResolver(config, context);
            }
        };
    }
}
exports.HasOneTransformer = HasOneTransformer;
const validate = (config, ctx) => {
    const { field } = config;
    const dbType = (0, graphql_transformer_core_1.getStrategyDbTypeFromTypeNode)(field.type, ctx);
    config.relatedType = (0, utils_1.getRelatedType)(config, ctx);
    const dataSourceBasedTransformer = (0, has_one_directive_transformer_factory_1.getHasOneDirectiveTransformer)(dbType);
    dataSourceBasedTransformer.validate(ctx, config);
    (0, utils_1.validateModelDirective)(config);
    if ((0, graphql_transformer_common_1.isListType)(field.type)) {
        throw new graphql_transformer_core_1.InvalidDirectiveError(`@${directiveName} cannot be used with lists. Use @hasMany instead.`);
    }
    config.connectionFields = [];
    (0, utils_1.validateRelatedModelDirective)(config);
    (0, utils_1.validateDisallowedDataStoreRelationships)(config, ctx);
};
//# sourceMappingURL=graphql-has-one-transformer.js.map