"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DDBRelationalResolverGenerator = void 0;
const graphql_transformer_core_1 = require("@aws-amplify/graphql-transformer-core");
const graphql_mapping_template_1 = require("graphql-mapping-template");
const graphql_transformer_common_1 = require("graphql-transformer-common");
const resolvers_1 = require("../resolvers");
const generator_1 = require("./generator");
const SORT_KEY_VALUE = 'sortKeyValue';
const CONNECTION_STACK = 'ConnectionStack';
const authFilter = (0, graphql_mapping_template_1.ref)('ctx.stash.authFilter');
const PARTITION_KEY_VALUE = 'partitionKeyValue';
class DDBRelationalResolverGenerator extends generator_1.RelationalResolverGenerator {
    constructor() {
        super(...arguments);
        this.makeExpression = (keySchema, connectionAttributes) => {
            if (keySchema[1] && connectionAttributes[1]) {
                let condensedSortKeyValue;
                if (connectionAttributes.length > 2) {
                    const rangeKeyFields = connectionAttributes.slice(1);
                    condensedSortKeyValue = rangeKeyFields
                        .map((keyField, idx) => `\${${SORT_KEY_VALUE}${idx}}`)
                        .join(graphql_transformer_common_1.ModelResourceIDs.ModelCompositeKeySeparator());
                }
                return (0, graphql_mapping_template_1.obj)({
                    expression: (0, graphql_mapping_template_1.str)('#partitionKey = :partitionKey AND #sortKey = :sortKey'),
                    expressionNames: (0, graphql_mapping_template_1.obj)({
                        '#partitionKey': (0, graphql_mapping_template_1.str)(keySchema[0].attributeName),
                        '#sortKey': (0, graphql_mapping_template_1.str)(keySchema[1].attributeName),
                    }),
                    expressionValues: (0, graphql_mapping_template_1.obj)({
                        ':partitionKey': (0, graphql_mapping_template_1.ref)(`util.dynamodb.toDynamoDB($${PARTITION_KEY_VALUE})`),
                        ':sortKey': (0, graphql_mapping_template_1.ref)(`util.dynamodb.toDynamoDB(${condensedSortKeyValue ? `"${condensedSortKeyValue}"` : `$${SORT_KEY_VALUE}0`})`),
                    }),
                });
            }
            return (0, graphql_mapping_template_1.obj)({
                expression: (0, graphql_mapping_template_1.str)('#partitionKey = :partitionKey'),
                expressionNames: (0, graphql_mapping_template_1.obj)({
                    '#partitionKey': (0, graphql_mapping_template_1.str)(keySchema[0].attributeName),
                }),
                expressionValues: (0, graphql_mapping_template_1.obj)({
                    ':partitionKey': (0, graphql_mapping_template_1.ref)(`util.dynamodb.toDynamoDB($${PARTITION_KEY_VALUE})`),
                }),
            });
        };
        this.makeHasManyGetItemsConnectionWithKeyResolver = (config, ctx) => {
            const { connectionFields, field, fields, indexName, limit, object, relatedType } = config;
            const connectionAttributes = fields.length > 0 ? fields : connectionFields;
            if (connectionAttributes.length === 0) {
                throw new Error('Either connection fields or local fields should be populated.');
            }
            const table = (0, graphql_transformer_core_1.getTable)(ctx, relatedType);
            const dataSourceName = (0, graphql_transformer_core_1.getModelDataSourceNameForTypeName)(ctx, relatedType.name.value);
            const dataSource = ctx.api.host.getDataSource(dataSourceName);
            const keySchema = (0, graphql_transformer_core_1.getKeySchema)(table, indexName);
            const setup = [
                (0, graphql_mapping_template_1.set)((0, graphql_mapping_template_1.ref)('limit'), (0, graphql_mapping_template_1.ref)(`util.defaultIfNull($context.args.limit, ${limit})`)),
                ...connectionAttributes
                    .slice(1)
                    .map((ca, idx) => (0, graphql_mapping_template_1.set)((0, graphql_mapping_template_1.ref)(`${SORT_KEY_VALUE}${idx}`), (0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('util.defaultIfNull'), (0, graphql_mapping_template_1.ref)(`ctx.stash.connectionAttibutes.get("${ca}")`), (0, graphql_mapping_template_1.ref)(`ctx.source.${ca}`)))),
                (0, graphql_mapping_template_1.set)((0, graphql_mapping_template_1.ref)('query'), this.makeExpression(keySchema, connectionAttributes)),
            ];
            if (keySchema[1] && !connectionAttributes[1]) {
                const sortKeyFieldName = keySchema[1].attributeName;
                const sortKeyField = relatedType.fields.find((f) => f.name.value === sortKeyFieldName);
                if (sortKeyField) {
                    setup.push((0, graphql_transformer_common_1.applyKeyConditionExpression)(sortKeyFieldName, (0, graphql_transformer_common_1.attributeTypeFromScalar)(sortKeyField.type), 'query'));
                }
                else {
                    const sortKeyFieldNames = sortKeyFieldName.split(graphql_transformer_common_1.ModelResourceIDs.ModelCompositeKeySeparator());
                    setup.push((0, graphql_transformer_common_1.applyCompositeKeyConditionExpression)(sortKeyFieldNames, 'query', (0, graphql_transformer_common_1.toCamelCase)(sortKeyFieldNames), sortKeyFieldName));
                }
            }
            setup.push(graphql_transformer_common_1.setArgs, (0, graphql_mapping_template_1.ifElse)((0, graphql_mapping_template_1.not)((0, graphql_mapping_template_1.isNullOrEmpty)(authFilter)), (0, graphql_mapping_template_1.compoundExpression)([
                (0, graphql_mapping_template_1.set)((0, graphql_mapping_template_1.ref)('filter'), authFilter),
                (0, graphql_mapping_template_1.iff)((0, graphql_mapping_template_1.not)((0, graphql_mapping_template_1.isNullOrEmpty)((0, graphql_mapping_template_1.ref)('args.filter'))), (0, graphql_mapping_template_1.set)((0, graphql_mapping_template_1.ref)('filter'), (0, graphql_mapping_template_1.obj)({ and: (0, graphql_mapping_template_1.list)([(0, graphql_mapping_template_1.ref)('filter'), (0, graphql_mapping_template_1.ref)('args.filter')]) }))),
            ]), (0, graphql_mapping_template_1.iff)((0, graphql_mapping_template_1.not)((0, graphql_mapping_template_1.isNullOrEmpty)((0, graphql_mapping_template_1.ref)('args.filter'))), (0, graphql_mapping_template_1.set)((0, graphql_mapping_template_1.ref)('filter'), (0, graphql_mapping_template_1.ref)('args.filter')))), (0, graphql_mapping_template_1.iff)((0, graphql_mapping_template_1.not)((0, graphql_mapping_template_1.isNullOrEmpty)((0, graphql_mapping_template_1.ref)('filter'))), (0, graphql_mapping_template_1.compoundExpression)([
                (0, graphql_mapping_template_1.set)((0, graphql_mapping_template_1.ref)('filterExpression'), (0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('util.parseJson'), (0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('util.transform.toDynamoDBFilterExpression'), (0, graphql_mapping_template_1.ref)('filter')))),
                (0, graphql_mapping_template_1.iff)((0, graphql_mapping_template_1.not)((0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('util.isNullOrBlank'), (0, graphql_mapping_template_1.ref)('filterExpression.expression'))), (0, graphql_mapping_template_1.compoundExpression)([
                    (0, graphql_mapping_template_1.iff)((0, graphql_mapping_template_1.equals)((0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('filterExpression.expressionValues.size')), (0, graphql_mapping_template_1.int)(0)), (0, graphql_mapping_template_1.qref)((0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('filterExpression.remove'), (0, graphql_mapping_template_1.str)('expressionValues')))),
                    (0, graphql_mapping_template_1.set)((0, graphql_mapping_template_1.ref)('filter'), (0, graphql_mapping_template_1.ref)('filterExpression')),
                ])),
            ])));
            const queryArguments = {
                query: (0, graphql_mapping_template_1.raw)('$util.toJson($query)'),
                scanIndexForward: (0, graphql_mapping_template_1.ifElse)((0, graphql_mapping_template_1.ref)('context.args.sortDirection'), (0, graphql_mapping_template_1.ifElse)((0, graphql_mapping_template_1.equals)((0, graphql_mapping_template_1.ref)('context.args.sortDirection'), (0, graphql_mapping_template_1.str)('ASC')), (0, graphql_mapping_template_1.bool)(true), (0, graphql_mapping_template_1.bool)(false)), (0, graphql_mapping_template_1.bool)(true)),
                filter: (0, graphql_mapping_template_1.ifElse)((0, graphql_mapping_template_1.ref)('filter'), (0, graphql_mapping_template_1.ref)('util.toJson($filter)'), (0, graphql_mapping_template_1.nul)()),
                limit: (0, graphql_mapping_template_1.ref)('limit'),
                nextToken: (0, graphql_mapping_template_1.ifElse)((0, graphql_mapping_template_1.ref)('context.args.nextToken'), (0, graphql_mapping_template_1.ref)('util.toJson($context.args.nextToken)'), (0, graphql_mapping_template_1.nul)()),
            };
            if (indexName) {
                queryArguments.index = (0, graphql_mapping_template_1.str)(indexName);
            }
            const queryObj = graphql_mapping_template_1.DynamoDBMappingTemplate.query(queryArguments);
            const resolverResourceId = graphql_transformer_common_1.ResolverResourceIDs.ResolverResourceID(object.name.value, field.name.value);
            const resolver = ctx.resolvers.generateQueryResolver(object.name.value, field.name.value, resolverResourceId, dataSource, graphql_transformer_core_1.MappingTemplate.s3MappingTemplateFromString((0, graphql_mapping_template_1.print)((0, graphql_mapping_template_1.compoundExpression)([
                (0, graphql_mapping_template_1.iff)((0, graphql_mapping_template_1.ref)('ctx.stash.deniedField'), (0, graphql_mapping_template_1.raw)('#return($util.toJson(null))')),
                (0, graphql_mapping_template_1.set)((0, graphql_mapping_template_1.ref)(PARTITION_KEY_VALUE), (0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('util.defaultIfNull'), (0, graphql_mapping_template_1.ref)(`ctx.stash.connectionAttributes.get("${connectionAttributes[0]}")`), (0, graphql_mapping_template_1.ref)(`ctx.source.${connectionAttributes[0]}`))),
                (0, graphql_mapping_template_1.ifElse)((0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('util.isNull'), (0, graphql_mapping_template_1.ref)(PARTITION_KEY_VALUE)), (0, graphql_mapping_template_1.compoundExpression)([(0, graphql_mapping_template_1.set)((0, graphql_mapping_template_1.ref)('result'), (0, graphql_mapping_template_1.obj)({ items: (0, graphql_mapping_template_1.list)([]) })), (0, graphql_mapping_template_1.raw)('#return($result)')]), (0, graphql_mapping_template_1.compoundExpression)([...setup, queryObj])),
            ])), `${object.name.value}.${field.name.value}.req.vtl`), graphql_transformer_core_1.MappingTemplate.s3MappingTemplateFromString((0, graphql_mapping_template_1.print)(graphql_mapping_template_1.DynamoDBMappingTemplate.dynamoDBResponse(false, (0, graphql_mapping_template_1.compoundExpression)([(0, graphql_mapping_template_1.iff)((0, graphql_mapping_template_1.raw)('!$result'), (0, graphql_mapping_template_1.set)((0, graphql_mapping_template_1.ref)('result'), (0, graphql_mapping_template_1.ref)('ctx.result'))), (0, graphql_mapping_template_1.raw)('$util.toJson($result)')]))), `${object.name.value}.${field.name.value}.res.vtl`));
            resolver.setScope(ctx.stackManager.getScopeFor(resolverResourceId, CONNECTION_STACK));
            ctx.resolvers.addResolver(object.name.value, field.name.value, resolver);
        };
        this.makeHasOneGetItemConnectionWithKeyResolver = (config, ctx) => {
            this.makeHasOneBelongToGetItemConnectionWithKeyResolver(config, ctx);
        };
        this.makeBelongsToGetItemConnectionWithKeyResolver = (config, ctx) => {
            this.makeHasOneBelongToGetItemConnectionWithKeyResolver(config, ctx);
        };
        this.makeHasOneBelongToGetItemConnectionWithKeyResolver = (config, ctx) => {
            const { connectionFields, field, fields, object, relatedType, relatedTypeIndex } = config;
            if (relatedTypeIndex.length === 0) {
                throw new Error('Expected relatedType index fields to be set for connection.');
            }
            const localFields = fields.length > 0 ? fields : connectionFields;
            const table = (0, graphql_transformer_core_1.getTable)(ctx, relatedType);
            const { keySchema } = table;
            const dataSourceName = (0, graphql_transformer_core_1.getModelDataSourceNameForTypeName)(ctx, relatedType.name.value);
            const dataSource = ctx.api.host.getDataSource(dataSourceName);
            const partitionKeyName = keySchema[0].attributeName;
            const totalExpressions = ['#partitionKey = :partitionValue'];
            const totalExpressionNames = {
                '#partitionKey': (0, graphql_mapping_template_1.str)(partitionKeyName),
            };
            const totalExpressionValues = {
                ':partitionValue': this.buildKeyValueExpression(localFields[0], ctx.output.getObject(object.name.value), true),
            };
            if (relatedTypeIndex.length > 2) {
                const rangeKeyFields = localFields.slice(1);
                const sortKeyName = keySchema[1].attributeName;
                const condensedSortKeyValue = (0, resolvers_1.condenseRangeKey)(rangeKeyFields.map((keyField) => `\${ctx.source.${keyField}}`));
                totalExpressions.push('#sortKeyName = :sortKeyName');
                totalExpressionNames['#sortKeyName'] = (0, graphql_mapping_template_1.str)(sortKeyName);
                totalExpressionValues[':sortKeyName'] = (0, graphql_mapping_template_1.ref)(`util.parseJson($util.dynamodb.toDynamoDBJson($util.defaultIfNullOrBlank("${condensedSortKeyValue}", "${graphql_transformer_common_1.NONE_VALUE}")))`);
            }
            else if (relatedTypeIndex.length === 2) {
                const sortKeyName = keySchema[1].attributeName;
                totalExpressions.push('#sortKeyName = :sortKeyName');
                totalExpressionNames['#sortKeyName'] = (0, graphql_mapping_template_1.str)(sortKeyName);
                totalExpressionValues[':sortKeyName'] = this.buildKeyValueExpression(localFields[1], ctx.output.getObject(object.name.value));
            }
            const resolverResourceId = graphql_transformer_common_1.ResolverResourceIDs.ResolverResourceID(object.name.value, field.name.value);
            const resolver = ctx.resolvers.generateQueryResolver(object.name.value, field.name.value, resolverResourceId, dataSource, graphql_transformer_core_1.MappingTemplate.s3MappingTemplateFromString((0, graphql_mapping_template_1.print)((0, graphql_mapping_template_1.compoundExpression)([
                (0, graphql_mapping_template_1.iff)((0, graphql_mapping_template_1.ref)('ctx.stash.deniedField'), (0, graphql_mapping_template_1.raw)('#return($util.toJson(null))')),
                (0, graphql_mapping_template_1.set)((0, graphql_mapping_template_1.ref)(PARTITION_KEY_VALUE), (0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('util.defaultIfNull'), (0, graphql_mapping_template_1.ref)(`ctx.stash.connectionAttibutes.get("${localFields[0]}")`), (0, graphql_mapping_template_1.ref)(`ctx.source.${localFields[0]}`))),
                (0, graphql_mapping_template_1.ifElse)((0, graphql_mapping_template_1.or)([
                    (0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('util.isNull'), (0, graphql_mapping_template_1.ref)(PARTITION_KEY_VALUE)),
                    ...localFields.slice(1).map((f) => (0, graphql_mapping_template_1.raw)(`$util.isNull($ctx.source.${f})`)),
                ]), (0, graphql_mapping_template_1.raw)('#return'), (0, graphql_mapping_template_1.compoundExpression)([
                    (0, graphql_mapping_template_1.set)((0, graphql_mapping_template_1.ref)('GetRequest'), (0, graphql_mapping_template_1.obj)({ version: (0, graphql_mapping_template_1.str)('2018-05-29'), operation: (0, graphql_mapping_template_1.str)('Query') })),
                    (0, graphql_mapping_template_1.qref)((0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('GetRequest.put'), (0, graphql_mapping_template_1.str)('query'), (0, graphql_mapping_template_1.obj)({
                        expression: (0, graphql_mapping_template_1.str)(totalExpressions.join(' AND ')),
                        expressionNames: (0, graphql_mapping_template_1.obj)(totalExpressionNames),
                        expressionValues: (0, graphql_mapping_template_1.obj)(totalExpressionValues),
                    }))),
                    (0, graphql_mapping_template_1.iff)((0, graphql_mapping_template_1.not)((0, graphql_mapping_template_1.isNullOrEmpty)(authFilter)), (0, graphql_mapping_template_1.qref)((0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('GetRequest.put'), (0, graphql_mapping_template_1.str)('filter'), (0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('util.parseJson'), (0, graphql_mapping_template_1.methodCall)((0, graphql_mapping_template_1.ref)('util.transform.toDynamoDBFilterExpression'), authFilter))))),
                    (0, graphql_mapping_template_1.toJson)((0, graphql_mapping_template_1.ref)('GetRequest')),
                ])),
            ])), `${object.name.value}.${field.name.value}.req.vtl`), graphql_transformer_core_1.MappingTemplate.s3MappingTemplateFromString((0, graphql_mapping_template_1.print)(graphql_mapping_template_1.DynamoDBMappingTemplate.dynamoDBResponse(false, (0, graphql_mapping_template_1.ifElse)((0, graphql_mapping_template_1.and)([(0, graphql_mapping_template_1.not)((0, graphql_mapping_template_1.ref)('ctx.result.items.isEmpty()')), (0, graphql_mapping_template_1.equals)((0, graphql_mapping_template_1.ref)('ctx.result.scannedCount'), (0, graphql_mapping_template_1.int)(1))]), (0, graphql_mapping_template_1.toJson)((0, graphql_mapping_template_1.ref)('ctx.result.items[0]')), (0, graphql_mapping_template_1.compoundExpression)([
                (0, graphql_mapping_template_1.iff)((0, graphql_mapping_template_1.and)([(0, graphql_mapping_template_1.ref)('ctx.result.items.isEmpty()'), (0, graphql_mapping_template_1.equals)((0, graphql_mapping_template_1.ref)('ctx.result.scannedCount'), (0, graphql_mapping_template_1.int)(1))]), (0, graphql_mapping_template_1.ref)('util.unauthorized()')),
                (0, graphql_mapping_template_1.toJson)((0, graphql_mapping_template_1.nul)()),
            ])))), `${object.name.value}.${field.name.value}.res.vtl`));
            resolver.setScope(ctx.stackManager.getScopeFor(resolverResourceId, CONNECTION_STACK));
            ctx.resolvers.addResolver(object.name.value, field.name.value, resolver);
        };
        this.buildKeyValueExpression = (fieldName, object, isPartitionKey = false) => {
            var _a;
            const field = (_a = object.fields) === null || _a === void 0 ? void 0 : _a.find((it) => it.name.value === fieldName);
            const attributeType = field ? (0, graphql_transformer_common_1.attributeTypeFromScalar)(field.type) : 'S';
            return (0, graphql_mapping_template_1.ref)(`util.parseJson($util.dynamodb.toDynamoDBJson($util.${attributeType === 'S' ? 'defaultIfNullOrBlank' : 'defaultIfNull'}(${isPartitionKey ? `$${PARTITION_KEY_VALUE}` : `$ctx.source.${fieldName}`}, "${graphql_transformer_common_1.NONE_VALUE}")))`);
        };
    }
}
exports.DDBRelationalResolverGenerator = DDBRelationalResolverGenerator;
//# sourceMappingURL=ddb-generator.js.map