From 78804565790de5b5d76d1671be06d9205d618cdd Mon Sep 17 00:00:00 2001 From: Damien Date: Wed, 25 Oct 2023 13:53:43 +0200 Subject: [PATCH 1/7] Ajout parsing property params sur mapper from --- TopModel.Core/FileModel/ModelFile.cs | 4 +- TopModel.Core/Loaders/ClassLoader.cs | 89 +++++++++++++------ TopModel.Core/Loaders/PropertyLoader.cs | 2 +- TopModel.Core/Model/DataFlowSource.cs | 2 +- TopModel.Core/Model/FromMapper.cs | 10 ++- TopModel.Core/Model/PropertyMapping.cs | 13 +++ TopModel.Core/ModelExtensions.cs | 4 +- TopModel.Core/ModelStore.cs | 20 ++--- TopModel.Core/TopModel.Core.csproj | 1 + TopModel.Core/schema.json | 87 +++++++++++------- .../MapperGeneratorBase.cs | 6 +- TopModel.Generator.Csharp/CsharpConfig.cs | 2 +- TopModel.Generator.Csharp/MapperGenerator.cs | 12 +-- .../ImportsJpaExtensions.cs | 2 +- TopModel.Generator.Jpa/JpaConfig.cs | 2 +- TopModel.Generator.Jpa/JpaMapperGenerator.cs | 14 +-- .../JpaModelConstructorGenerator.cs | 12 +-- .../SpringDataFlowGenerator.cs | 6 +- 18 files changed, 182 insertions(+), 106 deletions(-) create mode 100644 TopModel.Core/Model/PropertyMapping.cs diff --git a/TopModel.Core/FileModel/ModelFile.cs b/TopModel.Core/FileModel/ModelFile.cs index 1ad4559d..96636b88 100644 --- a/TopModel.Core/FileModel/ModelFile.cs +++ b/TopModel.Core/FileModel/ModelFile.cs @@ -61,8 +61,8 @@ public class ModelFile .Concat(Classes.SelectMany(c => new[] { c.DefaultPropertyReference, c.OrderPropertyReference, c.FlagPropertyReference }.Select(r => (r, (object)c.ExtendedProperties.FirstOrDefault(p => p.Name == r?.ReferenceName))))) .Concat(Classes.SelectMany(c => c.UniqueKeyReferences.SelectMany(uk => uk).Select(propRef => (propRef, (object)c.Properties.FirstOrDefault(p => p.Name == propRef.ReferenceName))))) .Concat(Classes.SelectMany(c => c.ValueReferences.SelectMany(rv => rv.Value).Select(prop => (prop.Key, (object)c.ExtendedProperties.FirstOrDefault(p => p.Name == prop.Key.ReferenceName))))) - .Concat(Classes.SelectMany(c => c.FromMappers.SelectMany(m => m.Params).Concat(c.ToMappers)).Select(p => (p.ClassReference as Reference, (object)p.Class))) - .Concat(Classes.SelectMany(c => c.FromMappers.SelectMany(m => m.Params).Concat(c.ToMappers).SelectMany(m => m.MappingReferences.SelectMany(mr => new[] { (mr.Key, (object)c.ExtendedProperties.FirstOrDefault(k => k.Name == mr.Key.ReferenceName)), (mr.Value, mr.Value.ReferenceName == "this" || mr.Value.ReferenceName == "false" ? new Keyword { ModelFile = c.ModelFile } : m.Mappings.Values.FirstOrDefault(k => k.Name == mr.Value.ReferenceName)) })))) + .Concat(Classes.SelectMany(c => c.FromMappers.SelectMany(m => m.ClassParams).Concat(c.ToMappers)).Select(p => (p.ClassReference as Reference, (object)p.Class))) + .Concat(Classes.SelectMany(c => c.FromMappers.SelectMany(m => m.ClassParams).Concat(c.ToMappers).SelectMany(m => m.MappingReferences.SelectMany(mr => new[] { (mr.Key, (object)c.ExtendedProperties.FirstOrDefault(k => k.Name == mr.Key.ReferenceName)), (mr.Value, mr.Value.ReferenceName == "this" || mr.Value.ReferenceName == "false" ? new Keyword { ModelFile = c.ModelFile } : m.Mappings.Values.FirstOrDefault(k => k.Name == mr.Value.ReferenceName)) })))) .Concat(Converters.SelectMany(c => c.DomainsFromReferences.Select(d => (d as Reference, c.From.FirstOrDefault(dom => dom.Name == d.ReferenceName) as object)))) .Concat(Converters.SelectMany(c => c.DomainsToReferences.Select(d => (d as Reference, c.To.FirstOrDefault(dom => dom.Name == d.ReferenceName) as object)))) .Concat(DataFlows.Select(d => (d.ClassReference as Reference, d.Class as object))) diff --git a/TopModel.Core/Loaders/ClassLoader.cs b/TopModel.Core/Loaders/ClassLoader.cs index afc0a643..4d3200f0 100644 --- a/TopModel.Core/Loaders/ClassLoader.cs +++ b/TopModel.Core/Loaders/ClassLoader.cs @@ -152,37 +152,74 @@ public Class Load(Parser parser) mapper.Reference = new LocatedString(prop); parser.ConsumeSequence(() => { - var param = new ClassMappings(); - mapper.Params.Add(param); + parser.Consume(); + if (parser.Current is Scalar { Value: "class" }) + { + var param = new ClassMappings(); + mapper.Params.Add(param); + + Scalar classScalar = null!; + while (parser.Current is not MappingEnd) + { + var prop = parser.Consume(); + switch (prop.Value) + { + case "class": + classScalar = parser.Consume(); + param.ClassReference = new ClassReference(classScalar); + break; + case "required": + param.Required = parser.Consume().Value == "true"; + break; + case "comment": + param.Comment = parser.Consume().Value; + break; + case "name": + param.Name = new LocatedString(parser.Consume()); + break; + case "mappings": + parser.ConsumeMapping(prop => + { + param.MappingReferences.Add(new Reference(prop), new Reference(parser.Consume())); + }); + break; + } + } - Scalar classScalar = null!; - parser.ConsumeMapping(prop => + param.Name ??= new LocatedString(classScalar) { Value = param.ClassReference.ReferenceName.ToCamelCase(strictIfUppercase: true) }; + } + else if (parser.Current is Scalar { Value: "property" }) { - switch (prop.Value) + while (parser.Current is not MappingEnd) { - case "class": - classScalar = parser.Consume(); - param.ClassReference = new ClassReference(classScalar); - break; - case "required": - param.Required = parser.Consume().Value == "true"; - break; - case "comment": - param.Comment = parser.Consume().Value; - break; - case "name": - param.Name = new LocatedString(parser.Consume()); - break; - case "mappings": - parser.ConsumeMapping(prop => - { - param.MappingReferences.Add(new Reference(prop), new Reference(parser.Consume())); - }); - break; + var prop = parser.Consume(); + switch (prop.Value) + { + case "property": + foreach (var p in _propertyLoader.Load(parser)) + { + var param = new PropertyMapping { Property = p }; + mapper.Params.Add(param); + } + + break; + case "target": + var targetReference = new Reference(parser.Consume()); + foreach (var cp in mapper.PropertyParams) + { + cp.TargetPropertyReference = targetReference; + } + + break; + } } - }); + } + else + { + throw new ModelException(classe, $"Erreur dans la construction des paramètres du mapper 'from'."); + } - param.Name ??= new LocatedString(classScalar) { Value = param.ClassReference.ReferenceName.ToCamelCase(strictIfUppercase: true) }; + parser.Consume(); }); break; } diff --git a/TopModel.Core/Loaders/PropertyLoader.cs b/TopModel.Core/Loaders/PropertyLoader.cs index 5d4b92dc..4544006a 100644 --- a/TopModel.Core/Loaders/PropertyLoader.cs +++ b/TopModel.Core/Loaders/PropertyLoader.cs @@ -19,7 +19,7 @@ public IEnumerable Load(Parser parser) parser.Consume(); switch (parser.Current) { - case Scalar { Value: "name" } s: + case Scalar { Value: "name" }: var rp = new RegularProperty { UseLegacyRoleName = _modelConfig.UseLegacyRoleNames }; while (parser.Current is not MappingEnd) diff --git a/TopModel.Core/Model/DataFlowSource.cs b/TopModel.Core/Model/DataFlowSource.cs index cb826eb5..158f56c7 100644 --- a/TopModel.Core/Model/DataFlowSource.cs +++ b/TopModel.Core/Model/DataFlowSource.cs @@ -24,7 +24,7 @@ public class DataFlowSource #nullable enable public FromMapper? TargetFromMapper { - get => DataFlow.Class.FromMappers.FirstOrDefault(fm => fm.Params.Count == 1 && fm.Params.First().Class == Class); + get => DataFlow.Class.FromMappers.FirstOrDefault(fm => fm.Params.Count == 1 && fm.ClassParams.First().Class == Class); } public ClassMappings? FirstSourceToMapper diff --git a/TopModel.Core/Model/FromMapper.cs b/TopModel.Core/Model/FromMapper.cs index 199ec20e..69740c77 100644 --- a/TopModel.Core/Model/FromMapper.cs +++ b/TopModel.Core/Model/FromMapper.cs @@ -1,11 +1,17 @@ -namespace TopModel.Core; +using OneOf; + +namespace TopModel.Core; public class FromMapper { #nullable enable public string? Comment { get; set; } - public List Params { get; } = new(); + public List> Params { get; } = new(); + + public IEnumerable ClassParams => Params.Where(p => p.IsT0).Select(p => p.AsT0); + + public IEnumerable PropertyParams => Params.Where(p => p.IsT1).Select(p => p.AsT1); #nullable disable internal LocatedString Reference { get; set; } diff --git a/TopModel.Core/Model/PropertyMapping.cs b/TopModel.Core/Model/PropertyMapping.cs new file mode 100644 index 00000000..c56ea808 --- /dev/null +++ b/TopModel.Core/Model/PropertyMapping.cs @@ -0,0 +1,13 @@ +#nullable disable +using TopModel.Core.FileModel; + +namespace TopModel.Core; + +public class PropertyMapping +{ + public IProperty Property { get; set; } + + public IProperty TargetProperty { get; set; } + + public Reference TargetPropertyReference { get; set; } +} diff --git a/TopModel.Core/ModelExtensions.cs b/TopModel.Core/ModelExtensions.cs index 2a9fe79c..5826c82c 100644 --- a/TopModel.Core/ModelExtensions.cs +++ b/TopModel.Core/ModelExtensions.cs @@ -27,7 +27,7 @@ public static class ModelExtensions .Select(c => (Reference: c.ExtendsReference!, File: c.GetFile()))) .Concat(modelStore.DataFlows.Where(d => d.Class == classe).Select(d => (Reference: d.ClassReference, File: d.GetFile()))) .Concat(modelStore.DataFlows.SelectMany(d => d.Sources.Where(s => s.Class == classe).Select(s => (Reference: s.ClassReference, File: d.GetFile())))) - .Concat(modelStore.Classes.SelectMany(c => c.FromMappers.SelectMany(c => c.Params).Concat(c.ToMappers).Where(m => m.Class == classe).Select(m => (Reference: m.ClassReference, File: c.GetFile())))) + .Concat(modelStore.Classes.SelectMany(c => c.FromMappers.SelectMany(c => c.ClassParams).Concat(c.ToMappers).Where(m => m.Class == classe).Select(m => (Reference: m.ClassReference, File: c.GetFile())))) .Where(r => r.Reference is not null) .DistinctBy(l => l.File.Name + l.Reference.Start.Line); } @@ -198,7 +198,7 @@ public static ModelFile GetFile(this object? objet) foreach (var classe in modelStore.Classes) { - foreach (var mappings in classe.FromMappers.SelectMany(m => m.Params).Concat(classe.ToMappers)) + foreach (var mappings in classe.FromMappers.SelectMany(m => m.ClassParams).Concat(classe.ToMappers)) { if (mappings.Mappings.ContainsKey(fp)) { diff --git a/TopModel.Core/ModelStore.cs b/TopModel.Core/ModelStore.cs index 65b00255..b0e8679b 100644 --- a/TopModel.Core/ModelStore.cs +++ b/TopModel.Core/ModelStore.cs @@ -1074,7 +1074,7 @@ IEnumerable ResolveAliases(IEnumerable alps) // Résolutions des mappers foreach (var classe in modelFile.Classes) { - foreach (var mappings in classe.FromMappers.SelectMany(m => m.Params).Concat(classe.ToMappers)) + foreach (var mappings in classe.FromMappers.SelectMany(m => m.ClassParams).Concat(classe.ToMappers)) { if (!referencedClasses.TryGetValue(mappings.ClassReference.ReferenceName, out var mappedClass)) { @@ -1174,12 +1174,12 @@ IEnumerable ResolveAliases(IEnumerable alps) foreach (var mapper in classe.FromMappers) { - foreach (var param in mapper.Params.Where((e, i) => mapper.Params.Where((p, j) => p.Name == e.Name && j < i).Any())) + foreach (var param in mapper.ClassParams.Where((e, i) => mapper.ClassParams.Where((p, j) => p.Name == e.Name && j < i).Any())) { yield return new ModelError(classe, $"Le nom '{param.Name}' est déjà utilisé.", param.GetLocation()) { ModelErrorType = ModelErrorType.TMD0003 }; } - var mappings = mapper.Params.SelectMany(p => p.MappingReferences); + var mappings = mapper.ClassParams.SelectMany(p => p.MappingReferences); var hasDoublon = false; foreach (var mapping in mappings.Where((e, i) => e.Value.ReferenceName != "false" && mappings.Where((p, j) => p.Value.ReferenceName != "false" && p.Key.ReferenceName == e.Key.ReferenceName && j < i).Any())) @@ -1190,9 +1190,9 @@ IEnumerable ResolveAliases(IEnumerable alps) if (!hasDoublon) { - var explicitMappings = mapper.Params.SelectMany(p => p.Mappings).ToList(); + var explicitMappings = mapper.ClassParams.SelectMany(p => p.Mappings).ToList(); - foreach (var param in mapper.Params.Where(p => p.Class != null)) + foreach (var param in mapper.ClassParams.Where(p => p.Class != null)) { foreach (var property in classe.ExtendedProperties.OfType().Where(property => !property.Readonly && !explicitMappings.Any(m => m.Key == property) && !param.MappingReferences.Any(m => m.Key.ReferenceName == property.Name && m.Value.ReferenceName == "false"))) { @@ -1208,9 +1208,9 @@ IEnumerable ResolveAliases(IEnumerable alps) } } - var explicitAndAliasMappings = mapper.Params.SelectMany(p => p.Mappings).ToList(); + var explicitAndAliasMappings = mapper.ClassParams.SelectMany(p => p.Mappings).ToList(); - foreach (var param in mapper.Params.Where(p => p.Class != null)) + foreach (var param in mapper.ClassParams.Where(p => p.Class != null)) { foreach (var property in classe.ExtendedProperties.OfType().Where(property => !property.Readonly && !explicitAndAliasMappings.Any(m => m.Key == property) && !param.MappingReferences.Any(m => m.Key.ReferenceName == property.Name && m.Value.ReferenceName == "false"))) { @@ -1224,11 +1224,11 @@ IEnumerable ResolveAliases(IEnumerable alps) } } - var finalMappings = mapper.Params.SelectMany(p => p.Mappings).ToList(); + var finalMappings = mapper.ClassParams.SelectMany(p => p.Mappings).ToList(); foreach (var mapping in finalMappings.Where((e, i) => finalMappings.Where((p, j) => p.Key == e.Key && j < i).Any())) { - yield return new ModelError(classe, $"Plusieurs propriétés de la classe peuvent être mappées sur '{mapping.Key.Name}' : {string.Join(", ", mapper.Params.SelectMany(p => p.Mappings.Where(m => m.Key == mapping.Key).Select(m => $"'{p.Name}.{m.Value}'")))}.", mapper.GetLocation()) { ModelErrorType = ModelErrorType.TMD1016 }; + yield return new ModelError(classe, $"Plusieurs propriétés de la classe peuvent être mappées sur '{mapping.Key.Name}' : {string.Join(", ", mapper.ClassParams.SelectMany(p => p.Mappings.Where(m => m.Key == mapping.Key).Select(m => $"'{p.Name}.{m.Value}'")))}.", mapper.GetLocation()) { ModelErrorType = ModelErrorType.TMD1016 }; } } } @@ -1287,7 +1287,7 @@ IEnumerable ResolveAliases(IEnumerable alps) { foreach (var mapper in classe.FromMappers) { - if (!mapper.Params.SelectMany(p => p.Mappings).Any()) + if (!mapper.ClassParams.SelectMany(p => p.Mappings).Any()) { yield return new ModelError(classe, "Aucun mapping n'a été trouvé sur ce mapper.", mapper.GetLocation()) { ModelErrorType = ModelErrorType.TMD1025 }; } diff --git a/TopModel.Core/TopModel.Core.csproj b/TopModel.Core/TopModel.Core.csproj index 69ef96de..5502909b 100644 --- a/TopModel.Core/TopModel.Core.csproj +++ b/TopModel.Core/TopModel.Core.csproj @@ -38,6 +38,7 @@ + diff --git a/TopModel.Core/schema.json b/TopModel.Core/schema.json index 412000ca..42466b84 100644 --- a/TopModel.Core/schema.json +++ b/TopModel.Core/schema.json @@ -826,44 +826,63 @@ "type": "array", "description": "Liste des paramètres du mapper.", "items": { - "type": "object", - "description": "Paramètre pour le mapper.", - "required": [ - "class" - ], - "additionalProperties": false, - "properties": { - "class": { - "type": "string", - "description": "Classe depuis laquelle recopier des propriétés." - }, - "required": { - "type": "boolean", - "description": "Paramètre obligatoire. 'true' par défaut." - }, - "comment": { - "type": "string", - "description": "Commentaire facultatif du mapper." - }, - "name": { - "type": "string", - "description": "Nom du paramètre. Utilise le nom de la classe par défaut." - }, - "mappings": { + "oneOf": [ + { "type": "object", - "description": "Correspondances de champs entre la classe courante et la classe en paramètre. Les propriétés doivent avoir le même domaine pour pouvoir établir une correspondance.\n\nLes correspondances entre alias, puis entre propriétés de même nom et de même domaine sont ajoutées automatiquement sauf indication contraire (correspondance explicite sur une autre propriété, ou correspondance renseignée à `false` pour la désactiver).", - "additionalProperties": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "boolean" + "description": "Paramètre pour le mapper.", + "required": [ + "class" + ], + "additionalProperties": false, + "properties": { + "class": { + "type": "string", + "description": "Classe depuis laquelle recopier des propriétés." + }, + "required": { + "type": "boolean", + "description": "Paramètre obligatoire. 'true' par défaut." + }, + "comment": { + "type": "string", + "description": "Commentaire facultatif du mapper." + }, + "name": { + "type": "string", + "description": "Nom du paramètre. Utilise le nom de la classe par défaut." + }, + "mappings": { + "type": "object", + "description": "Correspondances de champs entre la classe courante et la classe en paramètre. Les propriétés doivent avoir le même domaine pour pouvoir établir une correspondance.\n\nLes correspondances entre alias, puis entre propriétés de même nom et de même domaine sont ajoutées automatiquement sauf indication contraire (correspondance explicite sur une autre propriété, ou correspondance renseignée à `false` pour la désactiver).", + "additionalProperties": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "boolean" + } + ] } - ] + } + } + }, + { + "type": "object", + "description": "Paramètre pour le mapper", + "required": [ "property" ], + "additionalProperties": false, + "properties": { + "property": { + "$ref": "#/definitions/property" + }, + "target": { + "type": "string", + "description": "Propriété cible de la classe courante pour cette propriété. Cette propriété doit avoir le même domaine que la propriété source." + } } } - } + ] } } } diff --git a/TopModel.Generator.Core/MapperGeneratorBase.cs b/TopModel.Generator.Core/MapperGeneratorBase.cs index dda12813..eac00e83 100644 --- a/TopModel.Generator.Core/MapperGeneratorBase.cs +++ b/TopModel.Generator.Core/MapperGeneratorBase.cs @@ -19,7 +19,7 @@ public MapperGeneratorBase(ILogger> logger) protected IEnumerable<(Class Classe, FromMapper Mapper)> FromMappers => Classes .SelectMany(classe => classe.FromMappers.Select(mapper => (classe, mapper))) - .Where(mapper => mapper.mapper.Params.All(p => Classes.Contains(p.Class))) + .Where(mapper => mapper.mapper.ClassParams.All(p => Classes.Contains(p.Class))) .Select(c => (c.classe, c.mapper)); protected IEnumerable<(Class Classe, ClassMappings Mapper)> ToMappers => Classes @@ -46,7 +46,7 @@ protected override void HandleFiles(IEnumerable files) .Distinct() .OrderBy(m => m.Classe.NamePascal, StringComparer.Ordinal) .ThenBy(m => m.Mapper.Params.Count) - .ThenBy(m => string.Join(',', m.Mapper.Params.Select(p => p.Name)), StringComparer.Ordinal) + .ThenBy(m => string.Join(',', m.Mapper.ClassParams.Select(p => p.Name)), StringComparer.Ordinal) .ToArray(), Tags: tags); }); @@ -81,7 +81,7 @@ private IEnumerable GetMapperTags((Class Classe, FromMapper Mapper) mapp return mapper.Classe.Tags; } - var persistentParam = mapper.Mapper.Params.FirstOrDefault(p => IsPersistent(p.Class)); + var persistentParam = mapper.Mapper.ClassParams.FirstOrDefault(p => IsPersistent(p.Class)); if (persistentParam != null) { return persistentParam.Class.Tags; diff --git a/TopModel.Generator.Csharp/CsharpConfig.cs b/TopModel.Generator.Csharp/CsharpConfig.cs index 73f7db67..66bcab5d 100644 --- a/TopModel.Generator.Csharp/CsharpConfig.cs +++ b/TopModel.Generator.Csharp/CsharpConfig.cs @@ -272,7 +272,7 @@ public string GetMapperFilePath((Class Classe, ClassMappings Mapper) mapper, str return (mapper.Classe.Namespace, pmp); } - var persistentParam = mapper.Mapper.Params.FirstOrDefault(p => p.Class.IsPersistent); + var persistentParam = mapper.Mapper.ClassParams.FirstOrDefault(p => p.Class.IsPersistent); if (persistentParam != null) { return (persistentParam.Class.Namespace, pmp); diff --git a/TopModel.Generator.Csharp/MapperGenerator.cs b/TopModel.Generator.Csharp/MapperGenerator.cs index 9eac26f2..001081dc 100644 --- a/TopModel.Generator.Csharp/MapperGenerator.cs +++ b/TopModel.Generator.Csharp/MapperGenerator.cs @@ -39,7 +39,7 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla var ns = Config.GetNamespace(mapperNs, modelPath, tag); - var usings = fromMappers.SelectMany(m => m.Mapper.Params.Select(p => p.Class).Concat(new[] { m.Classe })) + var usings = fromMappers.SelectMany(m => m.Mapper.ClassParams.Select(p => p.Class).Concat(new[] { m.Classe })) .Concat(toMappers.SelectMany(m => new[] { m.Classe, m.Mapper.Class })) .Select(c => Config.GetNamespace(c, GetBestClassTag(c, tag))) .Where(@using => !ns.Contains(@using)) @@ -62,7 +62,7 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla var (classe, mapper) = fromMapper; w.WriteSummary(1, $"Crée une nouvelle instance de '{classe.NamePascal}'{(mapper.Comment != null ? $"\n{mapper.Comment}" : string.Empty)}"); - foreach (var param in mapper.Params) + foreach (var param in mapper.ClassParams) { if (param.Comment != null) { @@ -85,7 +85,7 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla w.Write(1, $"public static {classe.NamePascal} Create{classe.NamePascal}"); } - w.WriteLine($"({string.Join(", ", mapper.Params.Select(p => $"{(p.Class.Abstract ? "I" : string.Empty)}{p.Class.NamePascal} {p.Name}{(!p.Required ? " = null" : string.Empty)}"))})"); + w.WriteLine($"({string.Join(", ", mapper.ClassParams.Select(p => $"{(p.Class.Abstract ? "I" : string.Empty)}{p.Class.NamePascal} {p.Name}{(!p.Required ? " = null" : string.Empty)}"))})"); if (classe.Abstract) { @@ -94,7 +94,7 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla w.WriteLine(1, "{"); - foreach (var param in mapper.Params.Where(p => p.Required)) + foreach (var param in mapper.ClassParams.Where(p => p.Required)) { w.WriteLine(2, $"if ({param.Name} is null)"); w.WriteLine(2, "{"); @@ -113,7 +113,7 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla w.WriteLine(2, "{"); } - foreach (var param in mapper.Params) + foreach (var param in mapper.ClassParams) { var mappings = param.Mappings.ToList(); foreach (var mapping in mappings) @@ -152,7 +152,7 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla } } - if (mapper.Params.IndexOf(param) < mapper.Params.Count - 1 || mappings.IndexOf(mapping) < mappings.Count - 1) + if (mapper.Params.IndexOf(param) < mapper.ClassParams.Count() - 1 || mappings.IndexOf(mapping) < mappings.Count - 1) { w.Write(","); } diff --git a/TopModel.Generator.Jpa/ImportsJpaExtensions.cs b/TopModel.Generator.Jpa/ImportsJpaExtensions.cs index 7512cba1..a7000309 100644 --- a/TopModel.Generator.Jpa/ImportsJpaExtensions.cs +++ b/TopModel.Generator.Jpa/ImportsJpaExtensions.cs @@ -21,7 +21,7 @@ public static List GetImports(this Class classe, JpaConfig config, strin if (config.MappersInClass) { imports - .AddRange(classe.FromMappers.Where(fm => fm.Params.All(fmp => availableClasses.Contains(fmp.Class))).SelectMany(fm => fm.Params).Select(fmp => fmp.Class.GetImport(config, tag))); + .AddRange(classe.FromMappers.Where(fm => fm.ClassParams.All(fmp => availableClasses.Contains(fmp.Class))).SelectMany(fm => fm.ClassParams).Select(fmp => fmp.Class.GetImport(config, tag))); imports .AddRange(classe.ToMappers.Where(tm => availableClasses.Contains(tm.Class)).Select(fmp => fmp.Class.GetImport(config, tag))); } diff --git a/TopModel.Generator.Jpa/JpaConfig.cs b/TopModel.Generator.Jpa/JpaConfig.cs index c2ed0b98..116a4a98 100644 --- a/TopModel.Generator.Jpa/JpaConfig.cs +++ b/TopModel.Generator.Jpa/JpaConfig.cs @@ -229,7 +229,7 @@ public string GetMapperImport(Namespace ns, string modelPath, string tag) return (mapper.Classe.Namespace, EntitiesPath); } - var persistentParam = mapper.Mapper.Params.FirstOrDefault(p => p.Class.IsPersistent); + var persistentParam = mapper.Mapper.ClassParams.FirstOrDefault(p => p.Class.IsPersistent); if (persistentParam != null) { return (persistentParam.Class.Namespace, EntitiesPath); diff --git a/TopModel.Generator.Jpa/JpaMapperGenerator.cs b/TopModel.Generator.Jpa/JpaMapperGenerator.cs index fcd68a4a..e2326488 100644 --- a/TopModel.Generator.Jpa/JpaMapperGenerator.cs +++ b/TopModel.Generator.Jpa/JpaMapperGenerator.cs @@ -40,7 +40,7 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla using var fw = new JavaWriter(fileName, _logger, package, null); - var imports = fromMappers.SelectMany(m => m.Mapper.Params.Select(p => p.Class).Concat(new[] { m.Classe })) + var imports = fromMappers.SelectMany(m => m.Mapper.ClassParams.Select(p => p.Class).Concat(new[] { m.Classe })) .Concat(toMappers.SelectMany(m => new[] { m.Classe, m.Mapper.Class })) .Where(c => Classes.Contains(c)) .Select(c => c.GetImport(Config, c.Tags.Contains(tag) ? tag : c.Tags.Intersect(Config.Tags).First())) @@ -118,9 +118,9 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla getter = $"{Config.GetMapperName(cpMapperNs, cpMapperModelPath)}.{cpMapper.Name.Value.ToCamelCase()}({sourceName}.{cp.NameByClassPascal.WithPrefix(getterPrefix)}(), target.get{apSource.NameByClassPascal}())"; fw.AddImport(Config.GetMapperImport(cpMapperNs, cpMapperModelPath, tag)!); } - else if (cp.Composition.FromMappers.Any(f => f.Params.Count == 1 && f.Params.First().Class == apSource.Association)) + else if (cp.Composition.FromMappers.Any(f => f.Params.Count == 1 && f.ClassParams.First().Class == apSource.Association)) { - var cpMapper = cp.Composition.FromMappers.Find(f => f.Params.Count == 1 && f.Params.First().Class == apSource.Association)!; + var cpMapper = cp.Composition.FromMappers.Find(f => f.Params.Count == 1 && f.ClassParams.First().Class == apSource.Association)!; var (cpMapperNs, cpMapperModelPath) = Config.GetMapperLocation((cp.Composition, cpMapper)); getter = $"{sourceName}.{apSource.NameByClassPascal.WithPrefix(getterPrefix)}()"; @@ -234,7 +234,7 @@ private void WriteFromMapper(Class classe, FromMapper mapper, JavaWriter fw, str fw.WriteLine(); fw.WriteDocStart(1, $"Map les champs des classes passées en paramètre dans l'objet target'"); fw.WriteParam("target", $"Instance de '{classe}' (ou null pour créer une nouvelle instance)"); - foreach (var param in mapper.Params) + foreach (var param in mapper.ClassParams) { if (param.Comment != null) { @@ -248,7 +248,7 @@ private void WriteFromMapper(Class classe, FromMapper mapper, JavaWriter fw, str fw.WriteReturns(1, $"Une nouvelle instance de '{classe.NamePascal}' ou bien l'instance passée en paramètres sur lesquels les champs sources ont été mappée"); fw.WriteDocEnd(1); - fw.WriteLine(1, $"public static {classe.NamePascal} create{classe.NamePascal}({string.Join(", ", mapper.Params.Select(p => $"{p.Class} {p.Name.ToCamelCase()}"))}, {classe.NamePascal} target) {{"); + fw.WriteLine(1, $"public static {classe.NamePascal} create{classe.NamePascal}({string.Join(", ", mapper.ClassParams.Select(p => $"{p.Class} {p.Name.ToCamelCase()}"))}, {classe.NamePascal} target) {{"); fw.WriteLine(2, "if (target == null) {"); if (classe.Abstract) { @@ -269,7 +269,7 @@ private void WriteFromMapper(Class classe, FromMapper mapper, JavaWriter fw, str var isFirst = true; - foreach (var param in mapper.Params.Where(p => p.Mappings.Count > 0)) + foreach (var param in mapper.ClassParams.Where(p => p.Mappings.Count > 0)) { if (param.Required && !classe.Abstract) { @@ -280,7 +280,7 @@ private void WriteFromMapper(Class classe, FromMapper mapper, JavaWriter fw, str } } - foreach (var param in mapper.Params.Where(p => p.Mappings.Count > 0)) + foreach (var param in mapper.ClassParams.Where(p => p.Mappings.Count > 0)) { var mappings = param.Mappings.ToList(); var indent = 2; diff --git a/TopModel.Generator.Jpa/JpaModelConstructorGenerator.cs b/TopModel.Generator.Jpa/JpaModelConstructorGenerator.cs index 486cc5c0..2ff39f51 100644 --- a/TopModel.Generator.Jpa/JpaModelConstructorGenerator.cs +++ b/TopModel.Generator.Jpa/JpaModelConstructorGenerator.cs @@ -80,9 +80,9 @@ public void WriteEnumConstructor(JavaWriter fw, Class classe, List availa public void WriteFromMappers(JavaWriter fw, Class classe, List availableClasses, string tag) { - var fromMappers = classe.FromMappers.Where(c => c.Params.All(p => availableClasses.Contains(p.Class))).Select(m => (classe, m)) - .OrderBy(m => m.classe.NamePascal) - .ToList(); + var fromMappers = classe.FromMappers.Where(c => c.ClassParams.All(p => availableClasses.Contains(p.Class))).Select(m => (classe, m)) + .OrderBy(m => m.classe.NamePascal) + .ToList(); foreach (var fromMapper in fromMappers) { @@ -94,7 +94,7 @@ public void WriteFromMappers(JavaWriter fw, Class classe, List availableC fw.WriteLine(1, $" * {mapper.Comment}"); } - foreach (var param in mapper.Params) + foreach (var param in mapper.ClassParams) { if (param.Comment != null) { @@ -106,14 +106,14 @@ public void WriteFromMappers(JavaWriter fw, Class classe, List availableC fw.WriteReturns(1, $"Une nouvelle instance de '{classe.NamePascal}'"); fw.WriteDocEnd(1); - fw.WriteLine(1, $"public {classe.NamePascal}({string.Join(", ", mapper.Params.Select(p => $"{p.Class.NamePascal} {p.Name.ToCamelCase()}"))}) {{"); + fw.WriteLine(1, $"public {classe.NamePascal}({string.Join(", ", mapper.ClassParams.Select(p => $"{p.Class.NamePascal} {p.Name.ToCamelCase()}"))}) {{"); if (classe.Extends != null) { fw.WriteLine(2, $"super();"); } var (mapperNs, mapperModelPath) = _config.GetMapperLocation(fromMapper); - fw.WriteLine(2, $"{_config.GetMapperName(mapperNs, mapperModelPath)}.create{classe.NamePascal}({string.Join(", ", mapper.Params.Select(p => p.Name.ToCamelCase()))}, this);"); + fw.WriteLine(2, $"{_config.GetMapperName(mapperNs, mapperModelPath)}.create{classe.NamePascal}({string.Join(", ", mapper.ClassParams.Select(p => p.Name.ToCamelCase()))}, this);"); fw.AddImport(_config.GetMapperImport(mapperNs, mapperModelPath, tag)!); fw.WriteLine(1, "}"); } diff --git a/TopModel.Generator.Jpa/SpringDataFlowGenerator.cs b/TopModel.Generator.Jpa/SpringDataFlowGenerator.cs index f7d4a9c7..115f6ac6 100644 --- a/TopModel.Generator.Jpa/SpringDataFlowGenerator.cs +++ b/TopModel.Generator.Jpa/SpringDataFlowGenerator.cs @@ -477,9 +477,9 @@ private void WriteWriterMapper(JavaWriter fw, DataFlow dataFlow, string tag) var mapper = dataFlow.Class.FromMappers.Where(m => { var result = true; - for (int i = 0; i < m.Params.Count; i++) + for (int i = 0; i < m.ClassParams.Count(); i++) { - result = result && m.Params[i].Class == dataFlow.Sources[i].Class; + result = result && m.ClassParams.ElementAt(i).Class == dataFlow.Sources[i].Class; } return result; @@ -491,7 +491,7 @@ private void WriteWriterMapper(JavaWriter fw, DataFlow dataFlow, string tag) } foreach (var property in dataFlow.Class.ExtendedProperties.OfType() - .Where(p => mapper == null || mapper.Params.SelectMany(pa => pa.Mappings).Select(mapping => mapping.Key).Contains(p))) + .Where(p => mapper == null || mapper.ClassParams.SelectMany(pa => pa.Mappings).Select(mapping => mapping.Key).Contains(p))) { var sqlType = property.Domain.Implementations["sql"].Type ?? string.Empty; string dataType = sqlType.ToUpper() switch From a92e125daee4d57cac6973138cd0ea1fbdcf48cc Mon Sep 17 00:00:00 2001 From: Damien Date: Wed, 25 Oct 2023 15:04:25 +0200 Subject: [PATCH 2/7] Mappers 'from' : Retrait mapping "this" --- TopModel.Core/FileModel/ModelFile.cs | 2 +- TopModel.Core/Model/ClassMappings.cs | 2 +- TopModel.Core/ModelStore.cs | 16 +------- TopModel.Generator.Csharp/MapperGenerator.cs | 37 ++++++++----------- .../SemanticTokensHandler.cs | 2 +- 5 files changed, 19 insertions(+), 40 deletions(-) diff --git a/TopModel.Core/FileModel/ModelFile.cs b/TopModel.Core/FileModel/ModelFile.cs index 96636b88..6e36cad1 100644 --- a/TopModel.Core/FileModel/ModelFile.cs +++ b/TopModel.Core/FileModel/ModelFile.cs @@ -62,7 +62,7 @@ public class ModelFile .Concat(Classes.SelectMany(c => c.UniqueKeyReferences.SelectMany(uk => uk).Select(propRef => (propRef, (object)c.Properties.FirstOrDefault(p => p.Name == propRef.ReferenceName))))) .Concat(Classes.SelectMany(c => c.ValueReferences.SelectMany(rv => rv.Value).Select(prop => (prop.Key, (object)c.ExtendedProperties.FirstOrDefault(p => p.Name == prop.Key.ReferenceName))))) .Concat(Classes.SelectMany(c => c.FromMappers.SelectMany(m => m.ClassParams).Concat(c.ToMappers)).Select(p => (p.ClassReference as Reference, (object)p.Class))) - .Concat(Classes.SelectMany(c => c.FromMappers.SelectMany(m => m.ClassParams).Concat(c.ToMappers).SelectMany(m => m.MappingReferences.SelectMany(mr => new[] { (mr.Key, (object)c.ExtendedProperties.FirstOrDefault(k => k.Name == mr.Key.ReferenceName)), (mr.Value, mr.Value.ReferenceName == "this" || mr.Value.ReferenceName == "false" ? new Keyword { ModelFile = c.ModelFile } : m.Mappings.Values.FirstOrDefault(k => k.Name == mr.Value.ReferenceName)) })))) + .Concat(Classes.SelectMany(c => c.FromMappers.SelectMany(m => m.ClassParams).Concat(c.ToMappers).SelectMany(m => m.MappingReferences.SelectMany(mr => new[] { (mr.Key, (object)c.ExtendedProperties.FirstOrDefault(k => k.Name == mr.Key.ReferenceName)), (mr.Value, mr.Value.ReferenceName == "false" ? new Keyword { ModelFile = c.ModelFile } : m.Mappings.Values.FirstOrDefault(k => k.Name == mr.Value.ReferenceName)) })))) .Concat(Converters.SelectMany(c => c.DomainsFromReferences.Select(d => (d as Reference, c.From.FirstOrDefault(dom => dom.Name == d.ReferenceName) as object)))) .Concat(Converters.SelectMany(c => c.DomainsToReferences.Select(d => (d as Reference, c.To.FirstOrDefault(dom => dom.Name == d.ReferenceName) as object)))) .Concat(DataFlows.Select(d => (d.ClassReference as Reference, d.Class as object))) diff --git a/TopModel.Core/Model/ClassMappings.cs b/TopModel.Core/Model/ClassMappings.cs index 4edec231..f9ecd602 100644 --- a/TopModel.Core/Model/ClassMappings.cs +++ b/TopModel.Core/Model/ClassMappings.cs @@ -18,7 +18,7 @@ public class ClassMappings #nullable enable public string? Comment { get; set; } - public Dictionary Mappings { get; } = new(); + public Dictionary Mappings { get; } = new(); public Dictionary MappingReferences { get; } = new(); } diff --git a/TopModel.Core/ModelStore.cs b/TopModel.Core/ModelStore.cs index b0e8679b..af147cd1 100644 --- a/TopModel.Core/ModelStore.cs +++ b/TopModel.Core/ModelStore.cs @@ -1099,20 +1099,6 @@ IEnumerable ResolveAliases(IEnumerable alps) continue; } - if (currentProperty != null && mapping.Value.ReferenceName == "this") - { - if (currentProperty is CompositionProperty cp && cp.Composition == mappedClass) - { - mappings.Mappings.Add(currentProperty, null); - } - else - { - yield return new ModelError(classe, $"La classe '{mappedClass.Name}' ne peut pas être mappée sur la propriété '{currentProperty.Name}' car ce n'est pas une composition de cette classe.", mapping.Value) { ModelErrorType = ModelErrorType.TMD1020 }; - } - - continue; - } - var mappedProperty = mappedClass.ExtendedProperties.OfType().FirstOrDefault(p => p.Name == mapping.Value.ReferenceName); if (mappedProperty == null) { @@ -1287,7 +1273,7 @@ IEnumerable ResolveAliases(IEnumerable alps) { foreach (var mapper in classe.FromMappers) { - if (!mapper.ClassParams.SelectMany(p => p.Mappings).Any()) + if (!mapper.ClassParams.SelectMany(p => p.Mappings).Any() && !mapper.PropertyParams.Any()) { yield return new ModelError(classe, "Aucun mapping n'a été trouvé sur ce mapper.", mapper.GetLocation()) { ModelErrorType = ModelErrorType.TMD1025 }; } diff --git a/TopModel.Generator.Csharp/MapperGenerator.cs b/TopModel.Generator.Csharp/MapperGenerator.cs index 001081dc..428dbaa5 100644 --- a/TopModel.Generator.Csharp/MapperGenerator.cs +++ b/TopModel.Generator.Csharp/MapperGenerator.cs @@ -127,29 +127,22 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla w.Write(3, $"{mapping.Key.NamePascal} = "); } - if (mapping.Value == null) + var value = $"{param.Name}{(!param.Required && mapping.Key is not CompositionProperty ? "?" : string.Empty)}.{mapping.Value.NamePascal}"; + + if (mapping.Key is CompositionProperty cp) { - w.Write(param.Name); + w.Write($"{(!param.Required ? $"{param.Name} is null ? null : " : string.Empty)}new() {{ {cp.Composition.PrimaryKey.SingleOrDefault()?.NamePascal} = "); } else { - var value = $"{param.Name}{(!param.Required && mapping.Key is not CompositionProperty ? "?" : string.Empty)}.{mapping.Value.NamePascal}"; - - if (mapping.Key is CompositionProperty cp) - { - w.Write($"{(!param.Required ? $"{param.Name} is null ? null : " : string.Empty)}new() {{ {cp.Composition.PrimaryKey.SingleOrDefault()?.NamePascal} = "); - } - else - { - value = Config.GetConvertedValue(value, mapping.Value?.Domain, (mapping.Key as IFieldProperty)?.Domain); - } - - w.Write(value); - - if (mapping.Key is CompositionProperty) - { - w.Write(" }"); - } + value = Config.GetConvertedValue(value, mapping.Value.Domain, (mapping.Key as IFieldProperty)?.Domain); + } + + w.Write(value); + + if (mapping.Key is CompositionProperty) + { + w.Write(" }"); } if (mapper.Params.IndexOf(param) < mapper.ClassParams.Count() - 1 || mappings.IndexOf(mapping) < mappings.Count - 1) @@ -227,11 +220,11 @@ static string GetSourceMapping(IProperty property) var mappings = mapper.Mappings.ToList(); foreach (var mapping in mapper.Mappings) { - var value = Config.GetConvertedValue($"source.{GetSourceMapping(mapping.Key)}", (mapping.Key as IFieldProperty)?.Domain, mapping.Value?.Domain); + var value = Config.GetConvertedValue($"source.{GetSourceMapping(mapping.Key)}", (mapping.Key as IFieldProperty)?.Domain, mapping.Value.Domain); if (mapper.Class.Abstract) { - w.Write(3, $"{mapping.Value?.NameCamel}: {value}"); + w.Write(3, $"{mapping.Value.NameCamel}: {value}"); if (mappings.IndexOf(mapping) < mappings.Count - 1) { @@ -244,7 +237,7 @@ static string GetSourceMapping(IProperty property) } else { - w.WriteLine(2, $"dest.{mapping.Value?.NamePascal} = {value};"); + w.WriteLine(2, $"dest.{mapping.Value.NamePascal} = {value};"); } } diff --git a/TopModel.LanguageServer/SemanticTokensHandler.cs b/TopModel.LanguageServer/SemanticTokensHandler.cs index d8fb0fec..13ece247 100644 --- a/TopModel.LanguageServer/SemanticTokensHandler.cs +++ b/TopModel.LanguageServer/SemanticTokensHandler.cs @@ -63,7 +63,7 @@ protected override Task Tokenize(SemanticTokensBuilder builder, ITextDocumentIde ClassReference or DecoratorReference => SemanticTokenType.Class, DataFlowReference => SemanticTokenType.Operator, DomainReference => SemanticTokenType.EnumMember, - Reference r when r.ReferenceName == "this" || r.ReferenceName == "false" => SemanticTokenType.Keyword, + Reference r when r.ReferenceName == "false" => SemanticTokenType.Keyword, _ => SemanticTokenType.Function }; From 3b79b057b2c9f2360fe5c4981ace35307b3ccfd1 Mon Sep 17 00:00:00 2001 From: Damien Date: Wed, 25 Oct 2023 16:34:42 +0200 Subject: [PATCH 3/7] =?UTF-8?q?Parsing=20des=20propri=C3=A9t=C3=A9s=20dans?= =?UTF-8?q?=20les=20from=20mapper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TopModel.Core/FileModel/ModelFile.cs | 1 + TopModel.Core/Loaders/ClassLoader.cs | 17 ++++----- TopModel.Core/Loaders/DecoratorLoader.cs | 5 +-- TopModel.Core/Loaders/EndpointLoader.cs | 11 +++--- TopModel.Core/Loaders/PropertyLoader.cs | 22 ++++++------ TopModel.Core/Model/AliasProperty.cs | 2 ++ TopModel.Core/Model/AssociationProperty.cs | 2 ++ TopModel.Core/Model/Class.cs | 2 ++ TopModel.Core/Model/CompositionProperty.cs | 2 ++ TopModel.Core/Model/FromMapper.cs | 3 +- TopModel.Core/Model/IProperty.cs | 2 ++ TopModel.Core/Model/PropertyMapping.cs | 2 ++ TopModel.Core/Model/RegularProperty.cs | 2 ++ TopModel.Core/ModelExtensions.cs | 3 ++ TopModel.Core/ModelStore.cs | 41 +++++++++++++++++++++- 15 files changed, 81 insertions(+), 36 deletions(-) diff --git a/TopModel.Core/FileModel/ModelFile.cs b/TopModel.Core/FileModel/ModelFile.cs index 6e36cad1..cc69125a 100644 --- a/TopModel.Core/FileModel/ModelFile.cs +++ b/TopModel.Core/FileModel/ModelFile.cs @@ -80,6 +80,7 @@ public class ModelFile .ToList(); public IList Properties => Classes.SelectMany(c => c.Properties) + .Concat(Classes.SelectMany(c => c.FromMapperProperties)) .Concat(Endpoints.SelectMany(e => e.Params)) .Concat(Endpoints.Select(e => e.Returns)) .Concat(Decorators.SelectMany(e => e.Properties)) diff --git a/TopModel.Core/Loaders/ClassLoader.cs b/TopModel.Core/Loaders/ClassLoader.cs index 4d3200f0..8d117934 100644 --- a/TopModel.Core/Loaders/ClassLoader.cs +++ b/TopModel.Core/Loaders/ClassLoader.cs @@ -98,10 +98,7 @@ public Class Load(Parser parser) case "properties": parser.ConsumeSequence(() => { - foreach (var property in _propertyLoader.Load(parser)) - { - classe.Properties.Add(property); - } + classe.Properties.Add(_propertyLoader.Load(parser)); }); break; case "unique": @@ -138,7 +135,7 @@ public Class Load(Parser parser) case "from": parser.ConsumeSequence(() => { - var mapper = new FromMapper(); + var mapper = new FromMapper { Class = classe }; classe.FromMappers.Add(mapper); parser.ConsumeMapping(prop => @@ -196,12 +193,10 @@ public Class Load(Parser parser) switch (prop.Value) { case "property": - foreach (var p in _propertyLoader.Load(parser)) - { - var param = new PropertyMapping { Property = p }; - mapper.Params.Add(param); - } - + var p = _propertyLoader.Load(parser); + var param = new PropertyMapping { Property = p, FromMapper = mapper }; + p.PropertyMapping = param; + mapper.Params.Add(param); break; case "target": var targetReference = new Reference(parser.Consume()); diff --git a/TopModel.Core/Loaders/DecoratorLoader.cs b/TopModel.Core/Loaders/DecoratorLoader.cs index 768ec9fe..6d8a7b7c 100644 --- a/TopModel.Core/Loaders/DecoratorLoader.cs +++ b/TopModel.Core/Loaders/DecoratorLoader.cs @@ -38,10 +38,7 @@ public Decorator Load(Parser parser) case "properties": parser.ConsumeSequence(() => { - foreach (var property in _propertyLoader.Load(parser)) - { - decorator.Properties.Add(property); - } + decorator.Properties.Add(_propertyLoader.Load(parser)); }); break; default: diff --git a/TopModel.Core/Loaders/EndpointLoader.cs b/TopModel.Core/Loaders/EndpointLoader.cs index a718e765..f7ab4456 100644 --- a/TopModel.Core/Loaders/EndpointLoader.cs +++ b/TopModel.Core/Loaders/EndpointLoader.cs @@ -45,17 +45,14 @@ public Endpoint Load(Parser parser) case "params": parser.ConsumeSequence(() => { - foreach (var property in _propertyLoader.Load(parser)) - { - property.Endpoint = endpoint; - endpoint.Params.Add(property); - } + var property = _propertyLoader.Load(parser); + property.Endpoint = endpoint; + endpoint.Params.Add(property); }); break; case "returns": - endpoint.Returns = _propertyLoader.Load(parser).First(); + endpoint.Returns = _propertyLoader.Load(parser); endpoint.Returns.Endpoint = endpoint; - parser.Consume(); break; case "decorators": parser.ConsumeSequence(() => diff --git a/TopModel.Core/Loaders/PropertyLoader.cs b/TopModel.Core/Loaders/PropertyLoader.cs index 4544006a..e653b465 100644 --- a/TopModel.Core/Loaders/PropertyLoader.cs +++ b/TopModel.Core/Loaders/PropertyLoader.cs @@ -4,7 +4,7 @@ namespace TopModel.Core.Loaders; -public class PropertyLoader : ILoader> +public class PropertyLoader : ILoader { private readonly ModelConfig _modelConfig; @@ -14,7 +14,7 @@ public PropertyLoader(ModelConfig modelConfig) } /// - public IEnumerable Load(Parser parser) + public IProperty Load(Parser parser) { parser.Consume(); switch (parser.Current) @@ -67,8 +67,8 @@ public IEnumerable Load(Parser parser) rp.Required = true; } - yield return rp; - break; + parser.Consume(); + return rp; case Scalar { Value: "association" } s: var ap = new AssociationProperty @@ -136,8 +136,8 @@ public IEnumerable Load(Parser parser) ap.Required = true; } - yield return ap; - break; + parser.Consume(); + return ap; case Scalar { Value: "composition" } s: var cp = new CompositionProperty @@ -172,8 +172,8 @@ public IEnumerable Load(Parser parser) } } - yield return cp; - break; + parser.Consume(); + return cp; case Scalar { Value: "alias" } s: var aliasReference = new AliasReference(); @@ -274,13 +274,11 @@ public IEnumerable Load(Parser parser) } alp.Reference = aliasReference; - yield return alp; - break; + parser.Consume(); + return alp; default: throw new ModelException($"Type de propriété inconnu."); } - - parser.Consume(); } } \ No newline at end of file diff --git a/TopModel.Core/Model/AliasProperty.cs b/TopModel.Core/Model/AliasProperty.cs index 27fff770..00dc3b19 100644 --- a/TopModel.Core/Model/AliasProperty.cs +++ b/TopModel.Core/Model/AliasProperty.cs @@ -39,6 +39,8 @@ public IFieldProperty Property public Decorator Decorator { get; set; } + public PropertyMapping PropertyMapping { get; set; } + #nullable enable public LocatedString? Trigram { get; set; } diff --git a/TopModel.Core/Model/AssociationProperty.cs b/TopModel.Core/Model/AssociationProperty.cs index f9ee3990..2b4ede23 100644 --- a/TopModel.Core/Model/AssociationProperty.cs +++ b/TopModel.Core/Model/AssociationProperty.cs @@ -31,6 +31,8 @@ public IFieldProperty Property public Endpoint Endpoint { get; set; } public Decorator Decorator { get; set; } + + public PropertyMapping PropertyMapping { get; set; } #nullable enable public string? Role { get; set; } diff --git a/TopModel.Core/Model/Class.cs b/TopModel.Core/Model/Class.cs index 480d8091..5fea0807 100644 --- a/TopModel.Core/Model/Class.cs +++ b/TopModel.Core/Model/Class.cs @@ -66,6 +66,8 @@ public class Class : IPropertyContainer public List FromMappers { get; } = new(); + public IEnumerable FromMapperProperties => FromMappers.SelectMany(fm => fm.PropertyParams.Select(pp => pp.Property)); + public List ToMappers { get; } = new(); public string PluralName diff --git a/TopModel.Core/Model/CompositionProperty.cs b/TopModel.Core/Model/CompositionProperty.cs index d371b4d7..ecf3f27e 100644 --- a/TopModel.Core/Model/CompositionProperty.cs +++ b/TopModel.Core/Model/CompositionProperty.cs @@ -32,6 +32,8 @@ public class CompositionProperty : IProperty public Decorator Decorator { get; set; } + public PropertyMapping PropertyMapping { get; set; } + public string Label => Name; public bool PrimaryKey => false; diff --git a/TopModel.Core/Model/FromMapper.cs b/TopModel.Core/Model/FromMapper.cs index 69740c77..757fad6c 100644 --- a/TopModel.Core/Model/FromMapper.cs +++ b/TopModel.Core/Model/FromMapper.cs @@ -4,7 +4,6 @@ namespace TopModel.Core; public class FromMapper { -#nullable enable public string? Comment { get; set; } public List> Params { get; } = new(); @@ -14,5 +13,7 @@ public class FromMapper public IEnumerable PropertyParams => Params.Where(p => p.IsT1).Select(p => p.AsT1); #nullable disable + public Class Class { get; set; } + internal LocatedString Reference { get; set; } } diff --git a/TopModel.Core/Model/IProperty.cs b/TopModel.Core/Model/IProperty.cs index a8b08adb..6e32f351 100644 --- a/TopModel.Core/Model/IProperty.cs +++ b/TopModel.Core/Model/IProperty.cs @@ -30,6 +30,8 @@ public interface IProperty Decorator Decorator { get; set; } + PropertyMapping PropertyMapping { get; set; } + IPropertyContainer Parent => Class ?? (IPropertyContainer)Endpoint ?? Decorator; IProperty CloneWithClassOrEndpoint(Class? classe = null, Endpoint? endpoint = null); diff --git a/TopModel.Core/Model/PropertyMapping.cs b/TopModel.Core/Model/PropertyMapping.cs index c56ea808..48e42b90 100644 --- a/TopModel.Core/Model/PropertyMapping.cs +++ b/TopModel.Core/Model/PropertyMapping.cs @@ -10,4 +10,6 @@ public class PropertyMapping public IProperty TargetProperty { get; set; } public Reference TargetPropertyReference { get; set; } + + public FromMapper FromMapper { get; set; } } diff --git a/TopModel.Core/Model/RegularProperty.cs b/TopModel.Core/Model/RegularProperty.cs index 976289b6..1c352c54 100644 --- a/TopModel.Core/Model/RegularProperty.cs +++ b/TopModel.Core/Model/RegularProperty.cs @@ -41,6 +41,8 @@ public class RegularProperty : IFieldProperty public Decorator Decorator { get; set; } + public PropertyMapping PropertyMapping { get; set; } + public DomainReference DomainReference { get; set; } #nullable enable diff --git a/TopModel.Core/ModelExtensions.cs b/TopModel.Core/ModelExtensions.cs index 5826c82c..acb96e55 100644 --- a/TopModel.Core/ModelExtensions.cs +++ b/TopModel.Core/ModelExtensions.cs @@ -7,6 +7,7 @@ public static class ModelExtensions public static IEnumerable<(ClassReference Reference, ModelFile File)> GetClassReferences(this ModelStore modelStore, Class classe) { return modelStore.Classes.SelectMany(c => c.Properties) + .Concat(modelStore.Classes.SelectMany(c => c.FromMapperProperties)) .Concat(modelStore.Endpoints.SelectMany(e => e.Properties)) .Concat(modelStore.Decorators.SelectMany(d => d.Properties)) .Where(p => @@ -54,6 +55,7 @@ public static class ModelExtensions public static IEnumerable<(DomainReference Reference, ModelFile File)> GetDomainReferences(this ModelStore modelStore, Domain domain) { return modelStore.Classes.SelectMany(c => c.Properties) + .Concat(modelStore.Classes.SelectMany(c => c.FromMapperProperties)) .Concat(modelStore.Decorators.SelectMany(c => c.Properties)) .Concat(modelStore.Endpoints.SelectMany(e => e.Properties)) .Where(p => @@ -86,6 +88,7 @@ public static ModelFile GetFile(this object? objet) IProperty { Decorator: Decorator decorator } => decorator.ModelFile, IProperty { Class: Class classe } => classe.ModelFile, IProperty { Endpoint: Endpoint endpoint } => endpoint.ModelFile, + IProperty { PropertyMapping: PropertyMapping param } => param.FromMapper.Class.ModelFile, Domain domain => domain.ModelFile, Converter converter => converter.ModelFile, Decorator decorator => decorator.ModelFile, diff --git a/TopModel.Core/ModelStore.cs b/TopModel.Core/ModelStore.cs index af147cd1..fec94afb 100644 --- a/TopModel.Core/ModelStore.cs +++ b/TopModel.Core/ModelStore.cs @@ -670,13 +670,32 @@ private IEnumerable ResolveReferences(ModelFile modelFile) if (alp.OriginalAliasProperty is not null) { var index = classe.Properties.IndexOf(alp); - classe.Properties.RemoveAt(classe.Properties.IndexOf(alp)); + classe.Properties.RemoveAt(index); if (!classe.Properties.Contains(alp.OriginalAliasProperty)) { classe.Properties.Insert(index, alp.OriginalAliasProperty); } } } + + foreach (var alp in classe.FromMapperProperties.OfType().ToList()) + { + if (alp.OriginalAliasProperty is not null) + { + var index = alp.PropertyMapping.FromMapper.Params.IndexOf(alp.PropertyMapping); + alp.PropertyMapping.FromMapper.Params.RemoveAt(index); + if (!alp.PropertyMapping.FromMapper.Params.Contains(alp.OriginalAliasProperty.PropertyMapping)) + { + alp.PropertyMapping.FromMapper.Params.Insert(index, new PropertyMapping + { + FromMapper = alp.PropertyMapping.FromMapper, + Property = alp.OriginalAliasProperty, + TargetProperty = alp.PropertyMapping.TargetProperty, + TargetPropertyReference = alp.PropertyMapping.TargetPropertyReference + }); + } + } + } } // Reset des alias déjà résolus sur les endpoints. @@ -803,6 +822,22 @@ IEnumerable ResolveAliases(IEnumerable alps) alp.Decorator.Properties.Insert(index + 1, prop); } } + else if (alp.PropertyMapping != null) + { + var index = alp.PropertyMapping.FromMapper.Params.IndexOf(alp.PropertyMapping); + if (index >= 0) + { + var mapping = new PropertyMapping + { + FromMapper = alp.PropertyMapping.FromMapper, + Property = prop, + TargetProperty = alp.PropertyMapping.TargetProperty, + TargetPropertyReference = alp.PropertyMapping.TargetPropertyReference, + }; + prop.PropertyMapping = mapping; + alp.PropertyMapping.FromMapper.Params.Insert(index + 1, mapping); + } + } } if (alp.Class != null) @@ -813,6 +848,10 @@ IEnumerable ResolveAliases(IEnumerable alps) { alp.Endpoint.Params.Remove(alp); } + else if (alp.PropertyMapping != null) + { + alp.PropertyMapping.FromMapper.Params.Remove(alp.PropertyMapping); + } else { alp.Decorator?.Properties.Remove(alp); From d7dd0d166a94ff47db56625f06ff43e16362c245 Mon Sep 17 00:00:00 2001 From: Damien Date: Sun, 26 Nov 2023 13:46:00 +0100 Subject: [PATCH 4/7] =?UTF-8?q?[PropertyMapping]=20R=C3=A9solution=20Targe?= =?UTF-8?q?tProperty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 117 ++++++++++++++++++ TopModel.Core/FileModel/ModelFile.cs | 1 + TopModel.Core/Loaders/ClassLoader.cs | 15 +-- TopModel.Core/Model/ClassMappings.cs | 2 +- TopModel.Core/Model/MappingExtensions.cs | 11 ++ TopModel.Core/ModelErrorType.cs | 10 ++ TopModel.Core/ModelExtensions.cs | 16 ++- TopModel.Core/ModelStore.cs | 80 ++++++++++-- TopModel.Core/TopModel.Core.csproj | 1 + .../TopModel.Generator.Core.csproj | 1 + .../TopModel.Generator.Csharp.csproj | 1 + .../TopModel.Generator.Javascript.csproj | 1 + .../TopModel.Generator.Jpa.csproj | 1 + .../TopModel.Generator.Php.csproj | 1 + .../TopModel.Generator.Sql.csproj | 1 + .../TopModel.Generator.Translation.csproj | 1 + TopModel.Generator/TopModel.Generator.csproj | 1 + TopModel.LanguageServer/CompletionHandler.cs | 6 +- .../TopModel.LanguageServer.csproj | 1 + .../TopModel.ModelGenerator.csproj | 1 + TopModel.UI/TopModel.UI.csproj | 2 +- TopModel.Utils/TopModel.Utils.csproj | 1 + 22 files changed, 250 insertions(+), 22 deletions(-) create mode 100644 TopModel.Core/Model/MappingExtensions.cs diff --git a/.editorconfig b/.editorconfig index 2e2d2e5e..fefcd11d 100644 --- a/.editorconfig +++ b/.editorconfig @@ -19,3 +19,120 @@ dotnet_diagnostic.SA1642.severity = none dotnet_diagnostic.SA1643.severity = none dotnet_diagnostic.SX1309.severity = warning dotnet_diagnostic.CA2254.severity = none + +[*.cs] +#### Styles de nommage #### + +# Règles de nommage + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Spécifications de symboles + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Styles de nommage + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent +csharp_style_prefer_switch_expression = true:suggestion +csharp_style_prefer_pattern_matching = true:silent +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion +csharp_prefer_simple_using_statement = true:suggestion +csharp_prefer_braces = true:silent +dotnet_diagnostic.SA1010.severity = none + +[*.vb] +#### Styles de nommage #### + +# Règles de nommage + +dotnet_naming_rule.interface_should_be_commence_par_i.severity = suggestion +dotnet_naming_rule.interface_should_be_commence_par_i.symbols = interface +dotnet_naming_rule.interface_should_be_commence_par_i.style = commence_par_i + +dotnet_naming_rule.types_should_be_casse_pascal.severity = suggestion +dotnet_naming_rule.types_should_be_casse_pascal.symbols = types +dotnet_naming_rule.types_should_be_casse_pascal.style = casse_pascal + +dotnet_naming_rule.membres_autres_que_des_champs_should_be_casse_pascal.severity = suggestion +dotnet_naming_rule.membres_autres_que_des_champs_should_be_casse_pascal.symbols = membres_autres_que_des_champs +dotnet_naming_rule.membres_autres_que_des_champs_should_be_casse_pascal.style = casse_pascal + +# Spécifications de symboles + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.membres_autres_que_des_champs.applicable_kinds = property, event, method +dotnet_naming_symbols.membres_autres_que_des_champs.applicable_accessibilities = public, friend, private, protected, protected_friend, private_protected +dotnet_naming_symbols.membres_autres_que_des_champs.required_modifiers = + +# Styles de nommage + +dotnet_naming_style.commence_par_i.required_prefix = I +dotnet_naming_style.commence_par_i.required_suffix = +dotnet_naming_style.commence_par_i.word_separator = +dotnet_naming_style.commence_par_i.capitalization = pascal_case + +dotnet_naming_style.casse_pascal.required_prefix = +dotnet_naming_style.casse_pascal.required_suffix = +dotnet_naming_style.casse_pascal.word_separator = +dotnet_naming_style.casse_pascal.capitalization = pascal_case + +dotnet_naming_style.casse_pascal.required_prefix = +dotnet_naming_style.casse_pascal.required_suffix = +dotnet_naming_style.casse_pascal.word_separator = +dotnet_naming_style.casse_pascal.capitalization = pascal_case + +[*.{cs,vb}] +tab_width = 4 +indent_size = 4 \ No newline at end of file diff --git a/TopModel.Core/FileModel/ModelFile.cs b/TopModel.Core/FileModel/ModelFile.cs index cc69125a..d0df9311 100644 --- a/TopModel.Core/FileModel/ModelFile.cs +++ b/TopModel.Core/FileModel/ModelFile.cs @@ -62,6 +62,7 @@ public class ModelFile .Concat(Classes.SelectMany(c => c.UniqueKeyReferences.SelectMany(uk => uk).Select(propRef => (propRef, (object)c.Properties.FirstOrDefault(p => p.Name == propRef.ReferenceName))))) .Concat(Classes.SelectMany(c => c.ValueReferences.SelectMany(rv => rv.Value).Select(prop => (prop.Key, (object)c.ExtendedProperties.FirstOrDefault(p => p.Name == prop.Key.ReferenceName))))) .Concat(Classes.SelectMany(c => c.FromMappers.SelectMany(m => m.ClassParams).Concat(c.ToMappers)).Select(p => (p.ClassReference as Reference, (object)p.Class))) + .Concat(Classes.SelectMany(c => c.FromMappers.SelectMany(m => m.PropertyParams)).Select(p => (p.TargetPropertyReference as Reference, (object)p.TargetProperty))) .Concat(Classes.SelectMany(c => c.FromMappers.SelectMany(m => m.ClassParams).Concat(c.ToMappers).SelectMany(m => m.MappingReferences.SelectMany(mr => new[] { (mr.Key, (object)c.ExtendedProperties.FirstOrDefault(k => k.Name == mr.Key.ReferenceName)), (mr.Value, mr.Value.ReferenceName == "false" ? new Keyword { ModelFile = c.ModelFile } : m.Mappings.Values.FirstOrDefault(k => k.Name == mr.Value.ReferenceName)) })))) .Concat(Converters.SelectMany(c => c.DomainsFromReferences.Select(d => (d as Reference, c.From.FirstOrDefault(dom => dom.Name == d.ReferenceName) as object)))) .Concat(Converters.SelectMany(c => c.DomainsToReferences.Select(d => (d as Reference, c.To.FirstOrDefault(dom => dom.Name == d.ReferenceName) as object)))) diff --git a/TopModel.Core/Loaders/ClassLoader.cs b/TopModel.Core/Loaders/ClassLoader.cs index 8d117934..7a9318c8 100644 --- a/TopModel.Core/Loaders/ClassLoader.cs +++ b/TopModel.Core/Loaders/ClassLoader.cs @@ -187,24 +187,19 @@ public Class Load(Parser parser) } else if (parser.Current is Scalar { Value: "property" }) { + var param = new PropertyMapping { FromMapper = mapper }; + mapper.Params.Add(param); while (parser.Current is not MappingEnd) { var prop = parser.Consume(); switch (prop.Value) { case "property": - var p = _propertyLoader.Load(parser); - var param = new PropertyMapping { Property = p, FromMapper = mapper }; - p.PropertyMapping = param; - mapper.Params.Add(param); + param.Property = _propertyLoader.Load(parser); + param.Property.PropertyMapping = param; break; case "target": - var targetReference = new Reference(parser.Consume()); - foreach (var cp in mapper.PropertyParams) - { - cp.TargetPropertyReference = targetReference; - } - + param.TargetPropertyReference = new Reference(parser.Consume()); break; } } diff --git a/TopModel.Core/Model/ClassMappings.cs b/TopModel.Core/Model/ClassMappings.cs index f9ecd602..9e7b8ec9 100644 --- a/TopModel.Core/Model/ClassMappings.cs +++ b/TopModel.Core/Model/ClassMappings.cs @@ -18,7 +18,7 @@ public class ClassMappings #nullable enable public string? Comment { get; set; } - public Dictionary Mappings { get; } = new(); + public Dictionary Mappings { get; } = new(); public Dictionary MappingReferences { get; } = new(); } diff --git a/TopModel.Core/Model/MappingExtensions.cs b/TopModel.Core/Model/MappingExtensions.cs new file mode 100644 index 00000000..6b3fc8f5 --- /dev/null +++ b/TopModel.Core/Model/MappingExtensions.cs @@ -0,0 +1,11 @@ +using OneOf; + +namespace TopModel.Core; + +public static class MappingExtensions +{ + public static string GetName(this OneOf mapping) + { + return mapping.Match(c => c.Name.ToString(), p => p.Property.Name); + } +} diff --git a/TopModel.Core/ModelErrorType.cs b/TopModel.Core/ModelErrorType.cs index 67633284..6a0fb244 100644 --- a/TopModel.Core/ModelErrorType.cs +++ b/TopModel.Core/ModelErrorType.cs @@ -202,6 +202,16 @@ public enum ModelErrorType /// TMD1031, + /// + /// La propriété '{mapping.Property.Name}' doit être une composition de la même classe que '{mapping.TargetProperty.Name}' pour définir un mapping entre les deux. + /// + TMD1032, + + /// + /// La propriété '{mapping.Property.Name}' ne peut pas être une composition pour définir un mapping vers '{mapping.TargetProperty.Name}'. + /// + TMD1033, + /// /// Le flux de données est introuvable dans le fichier ou l'une de ses références. /// diff --git a/TopModel.Core/ModelExtensions.cs b/TopModel.Core/ModelExtensions.cs index acb96e55..b897b7d5 100644 --- a/TopModel.Core/ModelExtensions.cs +++ b/TopModel.Core/ModelExtensions.cs @@ -1,4 +1,5 @@ -using TopModel.Core.FileModel; +using OneOf; +using TopModel.Core.FileModel; namespace TopModel.Core; @@ -118,6 +119,8 @@ public static ModelFile GetFile(this object? objet) DataFlow d => d.Location, FromMapper m => m.Reference.Location, ClassMappings c => c.Name.Location, + PropertyMapping p => p.Property.GetLocation(), + OneOf p => p.Match(c => c.GetLocation(), p => p.GetLocation()), Converter c => c.Location, _ => null }; @@ -140,6 +143,17 @@ public static ModelFile GetFile(this object? objet) } } + if (property.Class != null) + { + foreach (var mapping in property.Class.FromMappers.SelectMany(fm => fm.PropertyParams)) + { + if (mapping.TargetPropertyReference != null && mapping.TargetProperty == property) + { + yield return (mapping.TargetPropertyReference, mapping.TargetProperty.GetFile()); + } + } + } + if (property is IFieldProperty fp) { foreach (var alp in modelStore.Files.SelectMany(c => c.Properties).OfType()) diff --git a/TopModel.Core/ModelStore.cs b/TopModel.Core/ModelStore.cs index fec94afb..262bc485 100644 --- a/TopModel.Core/ModelStore.cs +++ b/TopModel.Core/ModelStore.cs @@ -1197,25 +1197,85 @@ IEnumerable ResolveAliases(IEnumerable alps) } } + foreach (var mapping in classe.FromMappers.SelectMany(fm => fm.PropertyParams)) + { + if (mapping.Property != null) + { + if (mapping.TargetPropertyReference != null) + { + var currentProperty = classe.ExtendedProperties.FirstOrDefault(p => p.Name == mapping.TargetPropertyReference.ReferenceName); + if (currentProperty == null) + { + yield return new ModelError(classe, $"La propriété '{{0}}' est introuvable sur la classe '{classe}'.", mapping.TargetPropertyReference) { ModelErrorType = ModelErrorType.TMD1004 }; + } + + mapping.TargetProperty = currentProperty; + } + else + { + var mappedProperty = classe.ExtendedProperties.FirstOrDefault(p => p.Name == mapping.Property.Name); + if (mappedProperty == null) + { + yield return new ModelError(classe, $"La propriété '{mapping.Property.Name}' est introuvable sur la classe '{classe}'.", mapping.Property.GetLocation()) { ModelErrorType = ModelErrorType.TMD1004 }; + } + + mapping.TargetProperty = mappedProperty; + } + + if (mapping.TargetProperty != null) + { + if (mapping.TargetProperty is not CompositionProperty && mapping.Property is CompositionProperty) + { + yield return new ModelError(classe, $"La propriété '{mapping.Property.Name}' ne peut pas être une composition pour définir un mapping vers '{mapping.TargetProperty.Name}'.", mapping.Property.GetLocation()) { ModelErrorType = ModelErrorType.TMD1033 }; + } + + if (mapping.TargetProperty is CompositionProperty { Composition: Class cpClass } && (mapping.Property is not CompositionProperty || ((CompositionProperty)mapping.Property).Composition != cpClass)) + { + yield return new ModelError(classe, $"La propriété '{mapping.Property.Name}' doit être une composition de la même classe que '{mapping.TargetProperty.Name}' pour définir un mapping entre les deux.", mapping.Property.GetLocation()) { ModelErrorType = ModelErrorType.TMD1032 }; + } + + if (mapping.Property.Domain != mapping.TargetProperty.Domain + && !Converters.Any(c => c.From.Any(cf => cf == mapping.Property.Domain) && c.To.Any(ct => ct == mapping.TargetProperty.Domain))) + { + yield return new ModelError(classe, $"La propriété '{mapping.Property.Name}' ne peut pas être mappée à '{mapping.TargetProperty.Name}' car elle n'a pas le même domaine ('{mapping.Property.Domain?.Name}' au lieu de '{mapping.TargetProperty.Domain?.Name}') et qu'il n'existe pas de convertisseur entre les deux.", mapping.Property.GetLocation()) { ModelErrorType = ModelErrorType.TMD1014 }; + } + } + } + } + foreach (var mapper in classe.FromMappers) { - foreach (var param in mapper.ClassParams.Where((e, i) => mapper.ClassParams.Where((p, j) => p.Name == e.Name && j < i).Any())) + foreach (var param in mapper.Params.Where((e, i) => mapper.Params.Where((p, j) => p.GetName() == e.GetName() && j < i).Any())) { - yield return new ModelError(classe, $"Le nom '{param.Name}' est déjà utilisé.", param.GetLocation()) { ModelErrorType = ModelErrorType.TMD0003 }; + yield return new ModelError(classe, $"Le nom '{param.GetName()}' est déjà utilisé.", param.GetLocation()) { ModelErrorType = ModelErrorType.TMD0003 }; } - var mappings = mapper.ClassParams.SelectMany(p => p.MappingReferences); + var mappedProperties = mapper.Params.SelectMany(p => p.Match( + p => p.MappingReferences.Where(e => e.Value.ReferenceName != "false").Select(e => e.Key), + p => + { + if (p.TargetPropertyReference != null) + { + return [p.TargetPropertyReference]; + } + + var propRef = p.Property.GetLocation() ?? new Reference(); + propRef.ReferenceName = p.Property.Name; + return [propRef]; + })); var hasDoublon = false; - foreach (var mapping in mappings.Where((e, i) => e.Value.ReferenceName != "false" && mappings.Where((p, j) => p.Value.ReferenceName != "false" && p.Key.ReferenceName == e.Key.ReferenceName && j < i).Any())) + foreach (var mapping in mappedProperties.Where((e, i) => mappedProperties.Where((p, j) => p.ReferenceName == e.ReferenceName && j < i).Any())) { hasDoublon = true; - yield return new ModelError(classe, $"La propriété '{mapping.Key.ReferenceName}' est déjà initialisée dans ce mapper.", mapping.Key) { ModelErrorType = ModelErrorType.TMD1015 }; + yield return new ModelError(classe, $"La propriété '{mapping.ReferenceName}' est déjà initialisée dans ce mapper.", mapping) { ModelErrorType = ModelErrorType.TMD1015 }; } if (!hasDoublon) { - var explicitMappings = mapper.ClassParams.SelectMany(p => p.Mappings).ToList(); + var explicitMappings = mapper.ClassParams.SelectMany(p => p.Mappings) + .Concat(mapper.PropertyParams.Select(p => new KeyValuePair(p.TargetProperty, p.Property))) + .ToList(); foreach (var param in mapper.ClassParams.Where(p => p.Class != null)) { @@ -1233,7 +1293,9 @@ IEnumerable ResolveAliases(IEnumerable alps) } } - var explicitAndAliasMappings = mapper.ClassParams.SelectMany(p => p.Mappings).ToList(); + var explicitAndAliasMappings = mapper.ClassParams.SelectMany(p => p.Mappings) + .Concat(mapper.PropertyParams.Select(p => new KeyValuePair(p.TargetProperty, p.Property))) + .ToList(); foreach (var param in mapper.ClassParams.Where(p => p.Class != null)) { @@ -1249,7 +1311,9 @@ IEnumerable ResolveAliases(IEnumerable alps) } } - var finalMappings = mapper.ClassParams.SelectMany(p => p.Mappings).ToList(); + var finalMappings = mapper.ClassParams.SelectMany(p => p.Mappings) + .Concat(mapper.PropertyParams.Select(p => new KeyValuePair(p.TargetProperty, p.Property))) + .ToList(); foreach (var mapping in finalMappings.Where((e, i) => finalMappings.Where((p, j) => p.Key == e.Key && j < i).Any())) { diff --git a/TopModel.Core/TopModel.Core.csproj b/TopModel.Core/TopModel.Core.csproj index 5502909b..6d92fc44 100644 --- a/TopModel.Core/TopModel.Core.csproj +++ b/TopModel.Core/TopModel.Core.csproj @@ -2,6 +2,7 @@ net6.0;net8.0 + 12 enable enable true diff --git a/TopModel.Generator.Core/TopModel.Generator.Core.csproj b/TopModel.Generator.Core/TopModel.Generator.Core.csproj index dad5fb95..74317d27 100644 --- a/TopModel.Generator.Core/TopModel.Generator.Core.csproj +++ b/TopModel.Generator.Core/TopModel.Generator.Core.csproj @@ -2,6 +2,7 @@ net6.0;net8.0 + 12 enable enable true diff --git a/TopModel.Generator.Csharp/TopModel.Generator.Csharp.csproj b/TopModel.Generator.Csharp/TopModel.Generator.Csharp.csproj index 49db8666..4c77dd65 100644 --- a/TopModel.Generator.Csharp/TopModel.Generator.Csharp.csproj +++ b/TopModel.Generator.Csharp/TopModel.Generator.Csharp.csproj @@ -2,6 +2,7 @@ net6.0;net8.0 + 12 enable enable true diff --git a/TopModel.Generator.Javascript/TopModel.Generator.Javascript.csproj b/TopModel.Generator.Javascript/TopModel.Generator.Javascript.csproj index c9ee89a1..2f68f654 100644 --- a/TopModel.Generator.Javascript/TopModel.Generator.Javascript.csproj +++ b/TopModel.Generator.Javascript/TopModel.Generator.Javascript.csproj @@ -2,6 +2,7 @@ net6.0;net8.0 + 12 enable enable true diff --git a/TopModel.Generator.Jpa/TopModel.Generator.Jpa.csproj b/TopModel.Generator.Jpa/TopModel.Generator.Jpa.csproj index c7c1233a..08125ec2 100644 --- a/TopModel.Generator.Jpa/TopModel.Generator.Jpa.csproj +++ b/TopModel.Generator.Jpa/TopModel.Generator.Jpa.csproj @@ -2,6 +2,7 @@ net6.0;net8.0 + 12 enable enable true diff --git a/TopModel.Generator.Php/TopModel.Generator.Php.csproj b/TopModel.Generator.Php/TopModel.Generator.Php.csproj index 1a03a545..73fa0194 100644 --- a/TopModel.Generator.Php/TopModel.Generator.Php.csproj +++ b/TopModel.Generator.Php/TopModel.Generator.Php.csproj @@ -2,6 +2,7 @@ net6.0;net8.0 + 12 enable enable true diff --git a/TopModel.Generator.Sql/TopModel.Generator.Sql.csproj b/TopModel.Generator.Sql/TopModel.Generator.Sql.csproj index 7c02aa0e..b38dc3c6 100644 --- a/TopModel.Generator.Sql/TopModel.Generator.Sql.csproj +++ b/TopModel.Generator.Sql/TopModel.Generator.Sql.csproj @@ -2,6 +2,7 @@ net6.0;net8.0 + 12 enable enable true diff --git a/TopModel.Generator.Translation/TopModel.Generator.Translation.csproj b/TopModel.Generator.Translation/TopModel.Generator.Translation.csproj index b43d462d..9cf005ff 100644 --- a/TopModel.Generator.Translation/TopModel.Generator.Translation.csproj +++ b/TopModel.Generator.Translation/TopModel.Generator.Translation.csproj @@ -2,6 +2,7 @@ net6.0;net8.0 + 12 enable enable true diff --git a/TopModel.Generator/TopModel.Generator.csproj b/TopModel.Generator/TopModel.Generator.csproj index c3d6b104..d043d172 100644 --- a/TopModel.Generator/TopModel.Generator.csproj +++ b/TopModel.Generator/TopModel.Generator.csproj @@ -2,6 +2,7 @@ net6.0;net8.0 + 12 Exe enable enable diff --git a/TopModel.LanguageServer/CompletionHandler.cs b/TopModel.LanguageServer/CompletionHandler.cs index 281a4df1..27166f35 100644 --- a/TopModel.LanguageServer/CompletionHandler.cs +++ b/TopModel.LanguageServer/CompletionHandler.cs @@ -367,9 +367,13 @@ public override Task Handle(CompletionParams request, Cancellati var includeCompositions = false; var includeExtends = false; - if (currentLine.Contains("defaultProperty:") || currentLine.Contains("flagProperty:") || currentLine.Contains("orderProperty:")) + if (currentLine.Contains("defaultProperty:") || currentLine.Contains("flagProperty:") || currentLine.Contains("orderProperty:") || currentLine.Contains("target:")) { searchText = currentLine.Split(":")[1].Trim(); + if (currentLine.Contains("target")) + { + includeCompositions = true; + } } else { diff --git a/TopModel.LanguageServer/TopModel.LanguageServer.csproj b/TopModel.LanguageServer/TopModel.LanguageServer.csproj index 13dd7599..f27ebcef 100644 --- a/TopModel.LanguageServer/TopModel.LanguageServer.csproj +++ b/TopModel.LanguageServer/TopModel.LanguageServer.csproj @@ -3,6 +3,7 @@ Exe net6.0;net8.0 + 12 enable enable ../TopModel.VSCode/language-server-$(TargetFramework) diff --git a/TopModel.ModelGenerator/TopModel.ModelGenerator.csproj b/TopModel.ModelGenerator/TopModel.ModelGenerator.csproj index 44ac9e6d..c8f234af 100644 --- a/TopModel.ModelGenerator/TopModel.ModelGenerator.csproj +++ b/TopModel.ModelGenerator/TopModel.ModelGenerator.csproj @@ -2,6 +2,7 @@ net6.0;net8.0 + 12 Exe enable enable diff --git a/TopModel.UI/TopModel.UI.csproj b/TopModel.UI/TopModel.UI.csproj index 3b627e95..b19f1eef 100644 --- a/TopModel.UI/TopModel.UI.csproj +++ b/TopModel.UI/TopModel.UI.csproj @@ -2,7 +2,7 @@ net6.0;net8.0 - latest + 12 enable enable true diff --git a/TopModel.Utils/TopModel.Utils.csproj b/TopModel.Utils/TopModel.Utils.csproj index 6dd0d791..8e2b855f 100644 --- a/TopModel.Utils/TopModel.Utils.csproj +++ b/TopModel.Utils/TopModel.Utils.csproj @@ -2,6 +2,7 @@ net6.0;net8.0 + 12 enable enable true From 195ee41d947ef5fab5d9a72ea6ec22994274b531 Mon Sep 17 00:00:00 2001 From: Damien Date: Sun, 26 Nov 2023 17:26:43 +0100 Subject: [PATCH 5/7] `required` sur les compositions --- TopModel.Core/Loaders/PropertyLoader.cs | 3 +++ TopModel.Core/Model/CompositionProperty.cs | 2 ++ TopModel.Core/Model/IFieldProperty.cs | 2 -- TopModel.Core/Model/IProperty.cs | 2 ++ TopModel.Core/schema.json | 4 ++++ TopModel.Generator.Csharp/CSharpClassGenerator.cs | 2 +- 6 files changed, 12 insertions(+), 3 deletions(-) diff --git a/TopModel.Core/Loaders/PropertyLoader.cs b/TopModel.Core/Loaders/PropertyLoader.cs index e653b465..9d6819e3 100644 --- a/TopModel.Core/Loaders/PropertyLoader.cs +++ b/TopModel.Core/Loaders/PropertyLoader.cs @@ -167,6 +167,9 @@ public IProperty Load(Parser parser) case "readonly": cp.Readonly = value!.Value == "true"; break; + case "required": + cp.Required = value!.Value == "true"; + break; default: throw new ModelException($"Propriété ${prop} inconnue pour une propriété"); } diff --git a/TopModel.Core/Model/CompositionProperty.cs b/TopModel.Core/Model/CompositionProperty.cs index ecf3f27e..b7298b17 100644 --- a/TopModel.Core/Model/CompositionProperty.cs +++ b/TopModel.Core/Model/CompositionProperty.cs @@ -38,6 +38,8 @@ public class CompositionProperty : IProperty public bool PrimaryKey => false; + public bool Required { get; set; } = true; + public ClassReference Reference { get; set; } internal Reference Location { get; set; } diff --git a/TopModel.Core/Model/IFieldProperty.cs b/TopModel.Core/Model/IFieldProperty.cs index 4859a00e..ed93d371 100644 --- a/TopModel.Core/Model/IFieldProperty.cs +++ b/TopModel.Core/Model/IFieldProperty.cs @@ -4,8 +4,6 @@ namespace TopModel.Core; public interface IFieldProperty : IProperty { - bool Required { get; } - string? DefaultValue { get; } LocatedString? Trigram { get; set; } diff --git a/TopModel.Core/Model/IProperty.cs b/TopModel.Core/Model/IProperty.cs index 6e32f351..457eb473 100644 --- a/TopModel.Core/Model/IProperty.cs +++ b/TopModel.Core/Model/IProperty.cs @@ -16,6 +16,8 @@ public interface IProperty bool PrimaryKey { get; } + bool Required { get; } + Domain Domain { get; } string[] DomainParameters { get; } diff --git a/TopModel.Core/schema.json b/TopModel.Core/schema.json index 42466b84..b907f591 100644 --- a/TopModel.Core/schema.json +++ b/TopModel.Core/schema.json @@ -341,6 +341,10 @@ "readonly": { "type": "boolean", "description": "Une propriété 'readonly' ne pourra pas être renseignée par un mapper et aucun setter ne sera généré si la classe contenant la propriété est abstraite." + }, + "required": { + "type": "boolean", + "description": "Précise si la propriété est obligatoire (`true` par défaut sur les compositions). Une composition obligatoire sera initialisée avec une instance vide." } } } diff --git a/TopModel.Generator.Csharp/CSharpClassGenerator.cs b/TopModel.Generator.Csharp/CSharpClassGenerator.cs index d0c2748b..4e8f2e73 100644 --- a/TopModel.Generator.Csharp/CSharpClassGenerator.cs +++ b/TopModel.Generator.Csharp/CSharpClassGenerator.cs @@ -432,7 +432,7 @@ private void GenerateProperty(CSharpWriter w, IProperty property, HashSet Date: Sun, 26 Nov 2023 23:45:35 +0100 Subject: [PATCH 6/7] =?UTF-8?q?[C#]=20Gestion=20des=20mappings=20de=20prop?= =?UTF-8?q?ri=C3=A9t=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TopModel.Core/Model/IProperty.cs | 2 +- TopModel.Core/Model/MappingExtensions.cs | 16 ++ TopModel.Core/Model/PropertyMapping.cs | 16 +- TopModel.Core/ModelErrorType.cs | 5 + TopModel.Core/ModelStore.cs | 5 + .../CSharpApiClientGenerator.cs | 2 +- TopModel.Generator.Csharp/MapperGenerator.cs | 161 +++++++++++------- 7 files changed, 146 insertions(+), 61 deletions(-) diff --git a/TopModel.Core/Model/IProperty.cs b/TopModel.Core/Model/IProperty.cs index 457eb473..19ad5d9c 100644 --- a/TopModel.Core/Model/IProperty.cs +++ b/TopModel.Core/Model/IProperty.cs @@ -34,7 +34,7 @@ public interface IProperty PropertyMapping PropertyMapping { get; set; } - IPropertyContainer Parent => Class ?? (IPropertyContainer)Endpoint ?? Decorator; + IPropertyContainer Parent => Class ?? (IPropertyContainer)Endpoint ?? (IPropertyContainer)Decorator ?? PropertyMapping; IProperty CloneWithClassOrEndpoint(Class? classe = null, Endpoint? endpoint = null); } \ No newline at end of file diff --git a/TopModel.Core/Model/MappingExtensions.cs b/TopModel.Core/Model/MappingExtensions.cs index 6b3fc8f5..49aeae4c 100644 --- a/TopModel.Core/Model/MappingExtensions.cs +++ b/TopModel.Core/Model/MappingExtensions.cs @@ -1,11 +1,27 @@ using OneOf; +using TopModel.Utils; namespace TopModel.Core; public static class MappingExtensions { + public static string GetComment(this OneOf mapping) + { + return mapping.Match(c => c.Comment ?? $"Instance de '{c.Class.NamePascal}'", p => p.Property.Comment); + } + public static string GetName(this OneOf mapping) { return mapping.Match(c => c.Name.ToString(), p => p.Property.Name); } + + public static string GetNameCamel(this OneOf mapping) + { + return mapping.GetName().ToCamelCase(); + } + + public static bool GetRequired(this OneOf mapping) + { + return mapping.Match(c => c.Required, p => p.Property.Required && p.Property is not IFieldProperty { DefaultValue: not null }); + } } diff --git a/TopModel.Core/Model/PropertyMapping.cs b/TopModel.Core/Model/PropertyMapping.cs index 48e42b90..23d20d52 100644 --- a/TopModel.Core/Model/PropertyMapping.cs +++ b/TopModel.Core/Model/PropertyMapping.cs @@ -3,7 +3,7 @@ namespace TopModel.Core; -public class PropertyMapping +public class PropertyMapping : IPropertyContainer { public IProperty Property { get; set; } @@ -12,4 +12,18 @@ public class PropertyMapping public Reference TargetPropertyReference { get; set; } public FromMapper FromMapper { get; set; } + + public ModelFile ModelFile => throw new NotImplementedException(); + + public LocatedString Name => throw new NotImplementedException(); + + public string NamePascal => Property.NamePascal; + + public string NameCamel => Property.NameCamel; + + public Namespace Namespace => throw new NotImplementedException(); + + public IList Properties => [Property]; + + public bool PreservePropertyCasing => false; } diff --git a/TopModel.Core/ModelErrorType.cs b/TopModel.Core/ModelErrorType.cs index 6a0fb244..a5ae4109 100644 --- a/TopModel.Core/ModelErrorType.cs +++ b/TopModel.Core/ModelErrorType.cs @@ -212,6 +212,11 @@ public enum ModelErrorType /// TMD1033, + /// + /// Le paramètre '{param.GetName()}' du mapper ne peut pas être obligatoire si l'un des paramètres précédents ne l'est pas. + /// + TMD1034, + /// /// Le flux de données est introuvable dans le fichier ou l'une de ses références. /// diff --git a/TopModel.Core/ModelStore.cs b/TopModel.Core/ModelStore.cs index 262bc485..fe348f63 100644 --- a/TopModel.Core/ModelStore.cs +++ b/TopModel.Core/ModelStore.cs @@ -1319,6 +1319,11 @@ IEnumerable ResolveAliases(IEnumerable alps) { yield return new ModelError(classe, $"Plusieurs propriétés de la classe peuvent être mappées sur '{mapping.Key.Name}' : {string.Join(", ", mapper.ClassParams.SelectMany(p => p.Mappings.Where(m => m.Key == mapping.Key).Select(m => $"'{p.Name}.{m.Value}'")))}.", mapper.GetLocation()) { ModelErrorType = ModelErrorType.TMD1016 }; } + + foreach (var param in mapper.Params.Where((p, i) => p.GetRequired() && mapper.Params.Where((q, j) => !q.GetRequired() && j < i).Any())) + { + yield return new ModelError(classe, $"Le paramètre '{param.GetName()}' du mapper ne peut pas être obligatoire si l'un des paramètres précédents ne l'est pas.", param.GetLocation()) { ModelErrorType = ModelErrorType.TMD1034 }; + } } } diff --git a/TopModel.Generator.Csharp/CSharpApiClientGenerator.cs b/TopModel.Generator.Csharp/CSharpApiClientGenerator.cs index a1fa9271..fc6c3801 100644 --- a/TopModel.Generator.Csharp/CSharpApiClientGenerator.cs +++ b/TopModel.Generator.Csharp/CSharpApiClientGenerator.cs @@ -67,7 +67,7 @@ protected override void HandleFile(string filePath, string fileName, string tag, } } - foreach (var property in endpoints.SelectMany(e => e.Params.Concat(new[] { e.Returns! }).Where(p => p != null))) + foreach (var property in endpoints.SelectMany(e => e.Properties)) { usings.AddRange(Config.GetDomainImports(property, tag)); diff --git a/TopModel.Generator.Csharp/MapperGenerator.cs b/TopModel.Generator.Csharp/MapperGenerator.cs index 428dbaa5..5691e175 100644 --- a/TopModel.Generator.Csharp/MapperGenerator.cs +++ b/TopModel.Generator.Csharp/MapperGenerator.cs @@ -42,13 +42,37 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla var usings = fromMappers.SelectMany(m => m.Mapper.ClassParams.Select(p => p.Class).Concat(new[] { m.Classe })) .Concat(toMappers.SelectMany(m => new[] { m.Classe, m.Mapper.Class })) .Select(c => Config.GetNamespace(c, GetBestClassTag(c, tag))) - .Where(@using => !ns.Contains(@using)) - .Distinct() - .ToArray(); + .ToList(); - if (usings.Any()) + foreach (var mapping in fromMappers.SelectMany(fm => fm.Mapper.PropertyParams)) { - w.WriteUsings(usings); + usings.AddRange(Config.GetDomainImports(mapping.Property, tag)); + + if (mapping.Property is IFieldProperty fp) + { + usings.AddRange(Config.GetValueImports(fp)); + } + + switch (mapping.Property) + { + case AssociationProperty ap when Classes.Contains(ap.Association) && Config.CanClassUseEnums(ap.Association, Classes, ap.Property): + usings.Add(Config.GetNamespace(ap.Association, GetBestClassTag(ap.Association, tag))); + break; + case AliasProperty { Property: AssociationProperty ap2 } when Classes.Contains(ap2.Association) && Config.CanClassUseEnums(ap2.Association, Classes, ap2.Property): + usings.Add(Config.GetNamespace(ap2.Association, GetBestClassTag(ap2.Association, tag))); + break; + case AliasProperty { Property: RegularProperty rp } alp when Classes.Contains(rp.Class) && Config.CanClassUseEnums(rp.Class, Classes, rp): + usings.Add(Config.GetNamespace(rp.Class, GetBestClassTag(rp.Class, tag))); + break; + case CompositionProperty cp: + usings.Add(Config.GetNamespace(cp.Composition, GetBestClassTag(cp.Composition, tag))); + break; + } + } + + if (usings.Any(@using => !ns.Contains(@using))) + { + w.WriteUsings(usings.Where(@using => !ns.Contains(@using)).Distinct().ToArray()); w.WriteLine(); } @@ -62,16 +86,9 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla var (classe, mapper) = fromMapper; w.WriteSummary(1, $"Crée une nouvelle instance de '{classe.NamePascal}'{(mapper.Comment != null ? $"\n{mapper.Comment}" : string.Empty)}"); - foreach (var param in mapper.ClassParams) + foreach (var param in mapper.Params) { - if (param.Comment != null) - { - w.WriteParam(param.Name, param.Comment); - } - else - { - w.WriteParam(param.Name, $"Instance de '{param.Class.NamePascal}'"); - } + w.WriteParam(param.GetNameCamel(), param.GetComment()); } w.WriteReturns(1, $"Une nouvelle instance de '{classe.NamePascal}'"); @@ -85,7 +102,9 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla w.Write(1, $"public static {classe.NamePascal} Create{classe.NamePascal}"); } - w.WriteLine($"({string.Join(", ", mapper.ClassParams.Select(p => $"{(p.Class.Abstract ? "I" : string.Empty)}{p.Class.NamePascal} {p.Name}{(!p.Required ? " = null" : string.Empty)}"))})"); + w.WriteLine($"({string.Join(", ", mapper.Params.Select(mp => mp.Match( + c => $"{(c.Class.Abstract ? "I" : string.Empty)}{c.Class.NamePascal} {c.Name}{(!c.Required ? " = null" : string.Empty)}", + p => $"{Config.GetType(p.Property)} {p.Property.NameCamel}{(!mp.GetRequired() ? $" = {Config.GetValue(p.Property, Classes)}" : string.Empty)}")))})"); if (classe.Abstract) { @@ -94,11 +113,11 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla w.WriteLine(1, "{"); - foreach (var param in mapper.ClassParams.Where(p => p.Required)) + foreach (var param in mapper.Params.Where(p => p.GetRequired())) { - w.WriteLine(2, $"if ({param.Name} is null)"); + w.WriteLine(2, $"if ({param.GetNameCamel()} is null)"); w.WriteLine(2, "{"); - w.WriteLine(3, $"throw new ArgumentNullException(nameof({param.Name}));"); + w.WriteLine(3, $"throw new ArgumentNullException(nameof({param.GetNameCamel()}));"); w.WriteLine(2, "}"); w.WriteLine(); } @@ -113,49 +132,75 @@ protected override void HandleFile(string fileName, string tag, IList<(Class Cla w.WriteLine(2, "{"); } - foreach (var param in mapper.ClassParams) + foreach (var lol in mapper.Params) { - var mappings = param.Mappings.ToList(); - foreach (var mapping in mappings) - { - if (classe.Abstract) - { - w.Write(3, $"{mapping.Key.NameCamel}: "); - } - else + lol.Switch( + param => { - w.Write(3, $"{mapping.Key.NamePascal} = "); - } - - var value = $"{param.Name}{(!param.Required && mapping.Key is not CompositionProperty ? "?" : string.Empty)}.{mapping.Value.NamePascal}"; - - if (mapping.Key is CompositionProperty cp) - { - w.Write($"{(!param.Required ? $"{param.Name} is null ? null : " : string.Empty)}new() {{ {cp.Composition.PrimaryKey.SingleOrDefault()?.NamePascal} = "); - } - else - { - value = Config.GetConvertedValue(value, mapping.Value.Domain, (mapping.Key as IFieldProperty)?.Domain); - } - - w.Write(value); - - if (mapping.Key is CompositionProperty) + var mappings = param.Mappings.ToList(); + foreach (var mapping in mappings) + { + if (classe.Abstract) + { + w.Write(3, $"{mapping.Key.NameCamel}: "); + } + else + { + w.Write(3, $"{mapping.Key.NamePascal} = "); + } + + var value = $"{param.Name}{(!param.Required && mapping.Key is not CompositionProperty ? "?" : string.Empty)}.{mapping.Value.NamePascal}"; + + if (mapping.Key is CompositionProperty cp) + { + w.Write($"{(!param.Required ? $"{param.Name} is null ? null : " : string.Empty)}new() {{ {cp.Composition.PrimaryKey.SingleOrDefault()?.NamePascal} = "); + } + else + { + value = Config.GetConvertedValue(value, mapping.Value.Domain, (mapping.Key as IFieldProperty)?.Domain); + } + + w.Write(value); + + if (mapping.Key is CompositionProperty) + { + w.Write(" }"); + } + + if (mapper.Params.IndexOf(param) < mapper.Params.Count() - 1 || mappings.IndexOf(mapping) < mappings.Count - 1) + { + w.Write(","); + } + else if (classe.Abstract) + { + w.Write(");"); + } + + w.WriteLine(); + } + }, + param => { - w.Write(" }"); - } - - if (mapper.Params.IndexOf(param) < mapper.ClassParams.Count() - 1 || mappings.IndexOf(mapping) < mappings.Count - 1) - { - w.Write(","); - } - else if (classe.Abstract) - { - w.Write(");"); - } - - w.WriteLine(); - } + if (classe.Abstract) + { + w.Write(3, $"{param.TargetProperty.NameCamel}: {param.NameCamel}"); + } + else + { + w.Write(3, $"{param.TargetProperty.NamePascal} = {param.NameCamel}"); + } + + if (mapper.Params.IndexOf(param) < mapper.Params.Count() - 1) + { + w.Write(","); + } + else if (classe.Abstract) + { + w.Write(");"); + } + + w.WriteLine(); + }); } if (!classe.Abstract) From 07c4fda47275a0553d9c57282c44474ec843b7db Mon Sep 17 00:00:00 2001 From: Damien Date: Mon, 27 Nov 2023 00:14:29 +0100 Subject: [PATCH 7/7] =?UTF-8?q?Fix=20tri=20mappers=20par=20noms=20de=20par?= =?UTF-8?q?am=C3=A8tres?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TopModel.Generator.Core/MapperGeneratorBase.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TopModel.Generator.Core/MapperGeneratorBase.cs b/TopModel.Generator.Core/MapperGeneratorBase.cs index eac00e83..f3c9b300 100644 --- a/TopModel.Generator.Core/MapperGeneratorBase.cs +++ b/TopModel.Generator.Core/MapperGeneratorBase.cs @@ -46,7 +46,7 @@ protected override void HandleFiles(IEnumerable files) .Distinct() .OrderBy(m => m.Classe.NamePascal, StringComparer.Ordinal) .ThenBy(m => m.Mapper.Params.Count) - .ThenBy(m => string.Join(',', m.Mapper.ClassParams.Select(p => p.Name)), StringComparer.Ordinal) + .ThenBy(m => string.Join(',', m.Mapper.Params.Select(p => p.GetName())), StringComparer.Ordinal) .ToArray(), Tags: tags); });