"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.HasManyTransformer = 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 = __importDefault(require("immer"));
const schema_1 = require("./schema");
const utils_1 = require("./utils");
const generator_factory_1 = require("./resolver/generator-factory");
const has_many_directive_transformer_factory_1 = require("./has-many/has-many-directive-transformer-factory");
const directiveName = 'hasMany';
const defaultLimit = 100;
const directiveDefinition = `
  directive @${directiveName}(indexName: String, fields: [String!], references: [String!], limit: Int = ${defaultLimit}) on FIELD_DEFINITION
`;
class HasManyTransformer extends graphql_transformer_core_1.TransformerPluginBase {
    constructor() {
        super('amplify-has-many-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,
                limit: defaultLimit,
            }, (0, graphql_transformer_core_1.generateGetArgumentsInput)(context.transformParameters));
            validate(args, context);
            this.directiveList.push(args);
        };
        this.mutateSchema = (context) => {
            const resultDoc = (0, immer_1.default)(context.inputDocument, (draftDoc) => {
                var _a, _b;
                const connectingFieldsMap = new Map();
                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 = filteredDefs;
                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) => {
                        const baseFieldType = (0, graphql_transformer_common_1.getBaseType)(field.type);
                        const connectionAttributeName = (0, utils_1.getConnectionAttributeName)(context.transformParameters, def.name.value, field.name.value, (0, utils_1.getObjectPrimaryKey)(def).name.value);
                        const newField = (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'), []);
                        const sortKeyFields = (0, schema_1.convertSortKeyFieldsToSortKeyConnectionFields)((0, schema_1.getSortKeyFieldsNoContext)(def), def, field);
                        const allNewFields = [newField, ...sortKeyFields];
                        connectingFieldsMap.set(baseFieldType, allNewFields);
                    });
                });
                (_b = objectDefs === null || objectDefs === void 0 ? void 0 : objectDefs.filter((def) => connectingFieldsMap.has(def.name.value))) === null || _b === void 0 ? void 0 : _b.forEach((def) => {
                    const fieldsToAdd = connectingFieldsMap.get(def.name.value);
                    if (fieldsToAdd) {
                        (0, schema_1.addFieldsToDefinition)(def, fieldsToAdd);
                    }
                });
            });
            return resultDoc;
        };
        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_many_directive_transformer_factory_1.getHasManyDirectiveTransformer)(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_many_directive_transformer_factory_1.getHasManyDirectiveTransformer)(dbType);
                dataSourceBasedTransformer.transformSchema(ctx, config);
                (0, schema_1.ensureHasManyConnectionField)(config, context);
                (0, schema_1.extendTypeWithConnection)(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 dataSourceBasedTransformer = (0, has_many_directive_transformer_factory_1.getHasManyDirectiveTransformer)(dbType);
                dataSourceBasedTransformer.generateResolvers(ctx, config);
                const generator = (0, generator_factory_1.getGenerator)(dbType);
                generator.makeHasManyGetItemsConnectionWithKeyResolver(config, context);
            }
        };
    }
}
exports.HasManyTransformer = HasManyTransformer;
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_many_directive_transformer_factory_1.getHasManyDirectiveTransformer)(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} must be used with a list. Use @hasOne for non-list types.`);
    }
    config.connectionFields = [];
    (0, utils_1.validateRelatedModelDirective)(config);
    (0, utils_1.validateDisallowedDataStoreRelationships)(config, ctx);
};
//# sourceMappingURL=graphql-has-many-transformer.js.map