public int GetLength(ITableParser tableParser, Type modelType, IEnumerable <ICell> primaryParts) { var parserState = new List <(IAtomicValueParser parser, ICell cell, Type itemType)>(); foreach (var primaryPart in primaryParts) { var childModelPath = ExcelTemplatePath.FromRawExpression(primaryPart.StringValue); var childModelType = ObjectPropertiesExtractor.ExtractChildObjectTypeFromPath(modelType, childModelPath); var parser = parserCollection.GetAtomicValueParser(); parserState.Add((parser, primaryPart, childModelType)); } for (var i = 0; i <= ParsingParameters.MaxEnumerableLength; i++) { var parsed = false; foreach (var(parser, cell, type) in parserState) { tableParser.PushState(cell.CellPosition.Add(new ObjectSize(0, i))); if (parser.TryParse(tableParser, type, out var result) && result != null) { parsed = true; } tableParser.PopState(); } if (!parsed) { return(i); } } throw new EnumerableTooLongException(ParsingParameters.MaxEnumerableLength); }
public TModel Parse <TModel>([NotNull] ITableParser tableParser, [NotNull] RenderingTemplate template, Action <string, string> addFieldMapping) where TModel : new() { var model = new TModel(); var enumerablesLengths = GetEnumerablesLengths <TModel>(tableParser, template); foreach (var row in template.Content.Cells) { foreach (var cell in row) { tableParser.PushState(cell.CellPosition); var expression = cell.StringValue; if (TemplateDescriptionHelper.IsCorrectValueDescription(expression)) { ParseCellularValue(tableParser, addFieldMapping, model, ExcelTemplatePath.FromRawExpression(expression), enumerablesLengths); continue; } if (TemplateDescriptionHelper.IsCorrectFormValueDescription(expression)) { ParseFormValue(tableParser, addFieldMapping, model, cell, ExcelTemplatePath.FromRawExpression(expression)); continue; } tableParser.PopState(); } } return(model); }
private static object ExtractChildIfCorrectDescription(string expression, object model) { var excelTemplatePath = ExcelTemplatePath.FromRawExpression(expression); try { return(ObjectPropertiesExtractor.ExtractChildObject(model, excelTemplatePath)); } catch (ObjectPropertyExtractionException exception) { throw new InvalidOperationException($"Failed to extract child by path '{excelTemplatePath.RawPath}' in model of type {model.GetType()}", exception); } }
public void AtomicObjectsArrayExtractionTest() { const string valueDesсription = "Value::Bs[].Cs[].S"; var child = ObjectPropertiesExtractor.ExtractChildObject(model, ExcelTemplatePath.FromRawExpression(valueDesсription)); var childArray = child as object[]; childArray.Should().NotBeNull(); childArray.Length.Should().Be(2); childArray[0].Should().BeEquivalentTo(model.Bs[0].Cs.Select(x => x.S)); childArray[1].Should().BeEquivalentTo(model.Bs[1].Cs.Select(x => x.S)); }
private Dictionary <ExcelTemplatePath, int> GetEnumerablesLengths <TModel>([NotNull] ITableParser tableParser, [NotNull] RenderingTemplate template) { var enumerableCellsGroups = new Dictionary <ExcelTemplatePath, List <ICell> >(); foreach (var row in template.Content.Cells) { foreach (var cell in row) { var expression = cell.StringValue; if (TemplateDescriptionHelper.IsCorrectValueDescription(expression) && ExcelTemplatePath.FromRawExpression(expression).HasArrayAccess) { var cleanPathToEnumerable = ExcelTemplatePath.FromRawExpression(expression) .SplitForEnumerableExpansion() .pathToEnumerable .WithoutArrayAccess(); if (!enumerableCellsGroups.ContainsKey(cleanPathToEnumerable)) { enumerableCellsGroups[cleanPathToEnumerable] = new List <ICell>(); } enumerableCellsGroups[cleanPathToEnumerable].Add(cell); } } } var enumerablesLengths = new Dictionary <ExcelTemplatePath, int>(); foreach (var enumerableCells in enumerableCellsGroups) { var cleanPathToEnumerable = enumerableCells.Key; var childEnumerableType = ObjectPropertiesExtractor.ExtractChildObjectTypeFromPath(typeof(TModel), cleanPathToEnumerable); if (!TypeCheckingHelper.IsIList(childEnumerableType)) { throw new InvalidOperationException($"Only ILists are supported as collections, but tried to use '{childEnumerableType}'. (path: {cleanPathToEnumerable.RawPath})"); } var primaryParts = enumerableCells.Value.Where(x => ExcelTemplatePath.FromRawExpression(x.StringValue).HasPrimaryKeyArrayAccess).ToList(); if (primaryParts.Count == 0) { primaryParts = enumerableCells.Value.Take(1).ToList(); } var measurer = parserCollection.GetEnumerableMeasurer(); enumerablesLengths[cleanPathToEnumerable] = measurer.GetLength(tableParser, typeof(TModel), primaryParts); } return(enumerablesLengths); }
public void AllNullValuesArrayExtractionTest() { const string valueDesription = "Value::Bs[]"; var localModel = new A { Bs = new B[] { null, null, null } }; var child = ObjectPropertiesExtractor.ExtractChildObject(localModel, ExcelTemplatePath.FromRawExpression(valueDesription)); var childArray = child as object[]; childArray.Should().BeEquivalentTo(localModel.Bs); }
public void NullArrayExtractionTestWithBraces() { const string valueDesription = "Value::Bs[]"; var child = ObjectPropertiesExtractor.ExtractChildObject(new A(), ExcelTemplatePath.FromRawExpression(valueDesription)); child.Should().BeNull(); }
private void ParseFormValue(ITableParser tableParser, Action <string, string> addFieldMapping, object model, ICell cell, ExcelTemplatePath path) { var childSetter = ObjectPropertySettersExtractor.ExtractChildObjectSetter(model, path); var childModelType = ObjectPropertiesExtractor.ExtractChildObjectTypeFromPath(model.GetType(), path); var(childFormControlType, childFormControlName) = GetFormControlDescription(cell); if (path.HasArrayAccess) { throw new InvalidOperationException("Enumerables are not supported for form controls"); } var parser = parserCollection.GetFormValueParser(childFormControlType, childModelType); var parsedObject = parser.ParseOrDefault(tableParser, childFormControlName, childModelType); childSetter(parsedObject); addFieldMapping(path.RawPath, childFormControlName); }
private void ParseEnumerableValue(ITableParser tableParser, Action <string, string> addFieldMapping, object model, ExcelTemplatePath path, Action <object> leafSetter, Type leafModelType, Dictionary <ExcelTemplatePath, int> enumerablesLengths) { var(rawPathToEnumerable, childPath) = path.SplitForEnumerableExpansion(); var cleanPathToEnumerable = rawPathToEnumerable.WithoutArrayAccess(); var enumerableType = ObjectPropertiesExtractor.ExtractChildObjectTypeFromPath(model.GetType(), cleanPathToEnumerable); if (!typeof(IList).IsAssignableFrom(enumerableType)) { throw new Exception($"Only ILists are supported as collections, but tried to use '{enumerableType}'. (path: {cleanPathToEnumerable.RawPath})"); } var parser = parserCollection.GetEnumerableParser(enumerableType); var count = enumerablesLengths[cleanPathToEnumerable]; var parsedList = parser.Parse(tableParser, leafModelType, count, (name, value) => addFieldMapping($"{cleanPathToEnumerable.RawPath}{name}.{childPath.RawPath}", value)); leafSetter(parsedList); }
private void ParseSingleValue(ITableParser tableParser, Action <string, string> addFieldMapping, Action <object> leafSetter, ExcelTemplatePath childModelPath, Type childModelType) { var parser = parserCollection.GetAtomicValueParser(); addFieldMapping(childModelPath.RawPath, tableParser.CurrentState.Cursor.CellReference); if (!parser.TryParse(tableParser, childModelType, out var parsedObject)) { logger.Error($"Failed to parse value from '{tableParser.CurrentState.Cursor.CellReference}' with childModelType='{childModelType}' via AtomicValueParser"); return; } leafSetter(parsedObject); }
private void ParseCellularValue(ITableParser tableParser, Action <string, string> addFieldMapping, object model, ExcelTemplatePath path, Dictionary <ExcelTemplatePath, int> enumerablesLengths) { var leafSetter = ObjectPropertySettersExtractor.ExtractChildObjectSetter(model, path); var leafModelType = ObjectPropertiesExtractor.ExtractChildObjectTypeFromPath(model.GetType(), path); if (path.HasArrayAccess) { ParseEnumerableValue(tableParser, addFieldMapping, model, path, leafSetter, leafModelType, enumerablesLengths); } else { ParseSingleValue(tableParser, addFieldMapping, leafSetter, path, leafModelType); } }