public async Task <IActionResult> GetProductCharacteristics()
        {
            var listCharacteristicsCommand = new Jibberwock.Persistence.DataAccess.Commands.Products.ListAllCharacteristics(Logger);
            var characteristics            = await listCharacteristicsCommand.Execute(SqlServerDataSource);

            return(Ok(characteristics));
        }
        private async Task <IEnumerable <TierProductCharacteristic> > parseProductCharacteristicsAsync(long productId, IEnumerable <TierCharacteristicValue> characteristicValues)
        {
            var suppliedCharacteristicValues = new List <TierProductCharacteristic>();

            if (characteristicValues != null && characteristicValues.Any())
            {
                // Get the characteristics, filtering to Enabled ones for sanity's sake.
                // Focus on the global characteristics list, then the product's applicable characteristics
                var listCharacteristicsCommand = new Jibberwock.Persistence.DataAccess.Commands.Products.ListAllCharacteristics(Logger);
                var globalCharacteristicsList  = await listCharacteristicsCommand.Execute(SqlServerDataSource);

                var globalCharacteristics = globalCharacteristicsList.Where(c => c.Enabled).ToDictionary(ch => ch.Id);

                var currentUser = await CurrentUserRetriever.GetCurrentUserAsync();

                var getProductCommand = new Jibberwock.Persistence.DataAccess.Commands.Products.GetById(Logger, currentUser, new Product()
                {
                    Id = productId
                });
                var productDetails = await getProductCommand.Execute(SqlServerDataSource);

                var productCharacteristics = productDetails.ApplicableCharacteristics.Where(c => c.Enabled).ToDictionary(ch => ch.Id);

                foreach (var charValue in characteristicValues)
                {
                    // Discard any supplied characteristics which don't exist in the lists
                    if (!globalCharacteristics.ContainsKey(charValue.CharacteristicId) | !productCharacteristics.ContainsKey(charValue.CharacteristicId))
                    {
                        ModelState.AddModelError(ErrorResponses.InvalidCharacteristic, $"{{ \"id\": {charValue.CharacteristicId} }}");
                        continue;
                    }

                    var prodChar     = productCharacteristics[charValue.CharacteristicId];
                    var resultantTpc = new TierProductCharacteristic()
                    {
                        ProductCharacteristic = prodChar
                    };

                    // Handle the translation, converting from strings to booleans, longs or strings
                    switch (prodChar.ValueType)
                    {
                    case ProductCharacteristicValueType.Boolean:
                        if (!bool.TryParse(charValue.Value, out var parsedBool))
                        {
                            ModelState.AddModelError(ErrorResponses.InvalidCharacteristicValue, $"{{ \"id\": {charValue.CharacteristicId}, \"type\": {(int)prodChar.ValueType} }}");
                            continue;
                        }

                        resultantTpc.CharacteristicValue = parsedBool;
                        break;

                    case ProductCharacteristicValueType.Numeric:
                        if (!long.TryParse(charValue.Value, out var parsedLong))
                        {
                            ModelState.AddModelError(ErrorResponses.InvalidCharacteristicValue, $"{{ \"id\": {charValue.CharacteristicId}, \"type\": {(int)prodChar.ValueType} }}");
                            continue;
                        }

                        resultantTpc.CharacteristicValue = parsedLong;
                        break;

                    case ProductCharacteristicValueType.String:
                        resultantTpc.CharacteristicValue = charValue.Value;
                        break;
                    }

                    suppliedCharacteristicValues.Add(resultantTpc);
                }
            }

            return(suppliedCharacteristicValues);
        }