"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const property_metadata_model_1 = require("../../decorator/metadata/property-metadata.model");
const mapper_1 = require("../mapper");
const util_1 = require("../util");
class CollectionMapper {
    fromDb(attributeValue, propertyMetadata) {
        const explicitType = propertyMetadata && propertyMetadata.typeInfo ? propertyMetadata.typeInfo.type : null;
        if (attributeValue.SS) {
            const arr = attributeValue.SS;
            return explicitType && explicitType === Array ? arr : new Set(arr);
        }
        if (attributeValue.NS) {
            const arr = attributeValue.NS.map(item => parseFloat(item));
            return explicitType && explicitType === Array ? arr : new Set(arr);
        }
        if (attributeValue.BS) {
            const arr = attributeValue.BS;
            return explicitType && explicitType === Array ? arr : new Set(arr);
        }
        if (attributeValue.L) {
            let arr;
            if (property_metadata_model_1.hasGenericType(propertyMetadata)) {
                arr = attributeValue.L.map(item => mapper_1.Mapper.fromDb(item.M, propertyMetadata.typeInfo.genericType));
            }
            else {
                arr = attributeValue.L.map(value => mapper_1.Mapper.fromDbOne(value));
            }
            return explicitType && explicitType === Set ? new Set(arr) : arr;
        }
        throw new Error('No Collection Data (SS | NS | BS | L) was found in attribute data');
    }
    toDb(propertyValue, propertyMetadata) {
        if (Array.isArray(propertyValue) || util_1.Util.isSet(propertyValue)) {
            const attributeValue = {};
            let collectionType;
            if (propertyMetadata) {
                const explicitType = propertyMetadata && propertyMetadata.typeInfo ? propertyMetadata.typeInfo.type : null;
                switch (explicitType) {
                    case Array:
                        collectionType = 'L';
                        break;
                    case Set:
                        if (propertyMetadata.isSortedCollection) {
                            // only the L(ist) type preserves order
                            collectionType = 'L';
                        }
                        else {
                            if (propertyValue.size === 0) {
                                // if the type is Set defined by propertyMetadata and the value is empty return null type, empty set is not allowed
                                return { NULL: true };
                            }
                            else {
                                if (property_metadata_model_1.hasGenericType(propertyMetadata)) {
                                    // generic type of Set is defined, so decide based on the generic type which db set type should be used
                                    if (util_1.Util.isBufferType(propertyMetadata.typeInfo.genericType)) {
                                        collectionType = 'BS';
                                    }
                                    else {
                                        switch (propertyMetadata.typeInfo.genericType) {
                                            case String:
                                                collectionType = 'SS';
                                                break;
                                            case Number:
                                                collectionType = 'NS';
                                                break;
                                            default:
                                                // fallback to list if the type is not one of String or Number
                                                collectionType = 'L';
                                        }
                                    }
                                }
                                else {
                                    // auto detect based on set item values
                                    collectionType = util_1.Util.detectCollectionType(propertyValue);
                                }
                            }
                        }
                        break;
                    default:
                        throw new Error(`only 'Array' and 'Set' are valid values for explicit type, found ${explicitType}`);
                }
            }
            else {
                // auto detect based on set item values
                collectionType = util_1.Util.detectCollectionType(propertyValue);
            }
            // convert to array if we deal with a set
            if (util_1.Util.isSet(propertyValue)) {
                propertyValue = Array.from(propertyValue);
            }
            // empty value is not allowed for S(et) (supported for L(ist))
            if (propertyValue.length === 0) {
                return null;
            }
            else {
                switch (collectionType) {
                    case 'SS':
                        attributeValue.SS = propertyValue;
                        break;
                    case 'NS':
                        attributeValue.NS = propertyValue.map(num => num.toString());
                        break;
                    case 'BS':
                        attributeValue.BS = propertyValue;
                        break;
                    case 'L':
                        if (property_metadata_model_1.hasGenericType(propertyMetadata)) {
                            attributeValue.L = propertyValue.map(value => ({
                                M: mapper_1.Mapper.toDb(value, propertyMetadata.typeInfo.genericType),
                            }));
                        }
                        else {
                            attributeValue.L = (propertyValue.map(value => mapper_1.Mapper.toDbOne(value)).filter(value => value !== null));
                        }
                        break;
                    default:
                        throw new Error(`Collection type must be one of SS | NS | BS | L found type ${collectionType}`);
                }
                return attributeValue;
            }
        }
        else {
            throw new Error(`given value is not an array ${propertyValue}`);
        }
    }
}
exports.CollectionMapper = CollectionMapper;
//# sourceMappingURL=collection.mapper.js.map