Skip to content

Commit

Permalink
Improved partOf facet audit.
Browse files Browse the repository at this point in the history
  • Loading branch information
CBenghi committed Oct 16, 2023
1 parent 904ce73 commit 0aa65f1
Show file tree
Hide file tree
Showing 20 changed files with 216 additions and 146 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# PartOfRelationInformation class

Metadata container for relations that are primarily one-to-many between IFC entities

```csharp
public class PartOfRelationInformation
```

## Public Members

| name | description |
| --- | --- |
| [PartOfRelationInformation](PartOfRelationInformation/PartOfRelationInformation.md)(…) | Default constructor, ensures static nullable analysis |
| [OwnerIfcType](PartOfRelationInformation/OwnerIfcType.md) { get; set; } | Name of the IFC entity on the owner-side of the one-to-many relation |
| [PartIfcType](PartOfRelationInformation/PartIfcType.md) { getset; } | Name of the IFC entity on the part-side of the one-to-many relation |
| [RelationIfcName](PartOfRelationInformation/RelationIfcName.md) { getset; } | Name of the IFC entity for the relation |

## See Also

* namespace [IdsLib.IfcSchema](../ids-lib.md)
* [PartOfRelationInformation.cs](https://github.com/buildingSMART/IDS-Audit-tool/tree/main/ids-lib/IfcSchema/PartOfRelationInformation.cs)
<!-- DO NOT EDIT: generated by xmldocmd for ids-lib.dll -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# PartOfRelationInformation.OwnerIfcType property

Name of the IFC entity on the owner-side of the one-to-many relation

```csharp
public string OwnerIfcType { get; set; }
```

## See Also

* class [PartOfRelationInformation](../PartOfRelationInformation.md)
* namespace [IdsLib.IfcSchema](../../ids-lib.md)

<!-- DO NOT EDIT: generated by xmldocmd for ids-lib.dll -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# PartOfRelationInformation.PartIfcType property

Name of the IFC entity on the part-side of the one-to-many relation

```csharp
public string PartIfcType { get; set; }
```

## See Also

* class [PartOfRelationInformation](../PartOfRelationInformation.md)
* namespace [IdsLib.IfcSchema](../../ids-lib.md)

<!-- DO NOT EDIT: generated by xmldocmd for ids-lib.dll -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# PartOfRelationInformation constructor

Default constructor, ensures static nullable analysis

```csharp
public PartOfRelationInformation(string relationName, string oneSideType, string manySideType = "")
```

## See Also

* class [PartOfRelationInformation](../PartOfRelationInformation.md)
* namespace [IdsLib.IfcSchema](../../ids-lib.md)

<!-- DO NOT EDIT: generated by xmldocmd for ids-lib.dll -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# PartOfRelationInformation.RelationIfcName property

Name of the IFC entity for the relation

```csharp
public string RelationIfcName { get; set; }
```

## See Also

* class [PartOfRelationInformation](../PartOfRelationInformation.md)
* namespace [IdsLib.IfcSchema](../../ids-lib.md)

<!-- DO NOT EDIT: generated by xmldocmd for ids-lib.dll -->
2 changes: 1 addition & 1 deletion ids-lib-documentation/IdsLib.IfcSchema/SchemaInfo.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class SchemaInfo : IEnumerable<ClassInfo>
| static [SchemaIfc2x3](SchemaInfo/SchemaIfc2x3.md) { get; } | Static property for the Ifc2x3 schema |
| static [SchemaIfc4](SchemaInfo/SchemaIfc4.md) { get; } | Static property for the Ifc4 schema |
| static [SchemaIfc4x3](SchemaInfo/SchemaIfc4x3.md) { get; } | Static property for the Ifc4 schema |
| [AllPartOfRelations](SchemaInfo/AllPartOfRelations.md) { get; } | The names of classes across all schemas. |
| [Item](SchemaInfo/Item.md) { get; } | Get the classinfo by name string. |
| [PropertySets](SchemaInfo/PropertySets.md) { get; } | Provides access to the property sets of the schema |
| [Version](SchemaInfo/Version.md) { get; } | The version of the schema represented in the info |
Expand All @@ -25,7 +26,6 @@ public class SchemaInfo : IEnumerable<ClassInfo>
| static [AllAttributes](SchemaInfo/AllAttributes.md) { get; } | The names of all attributes across all schemas. |
| static [AllClasses](SchemaInfo/AllClasses.md) { get; } | The names of classes across all schemas. |
| static [AllMeasures](SchemaInfo/AllMeasures.md) { get; } | The names of classes across all schemas. |
| static [AllPartOfRelations](SchemaInfo/AllPartOfRelations.md) { get; } | The names of classes across all schemas. |
| static [GetSchemas](SchemaInfo/GetSchemas.md)(…) | Returns the schema metadata information for the required versions. |
| static [TryParseIfcMeasure](SchemaInfo/TryParseIfcMeasure.md)(…) | Attempts to convert a string value to an instance of the IfcMeasureInformation |
| enum [ClassAttributeMode](SchemaInfo.ClassAttributeMode.md) | Relation that allows to connect an available attribute to an entity |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
The names of classes across all schemas.

```csharp
public static IEnumerable<IfcOneToManyRelationInformation> AllPartOfRelations { get; }
public IEnumerable<PartOfRelationInformation> AllPartOfRelations { get; }
```

## See Also

* class [IfcOneToManyRelationInformation](../IfcOneToManyRelationInformation.md)
* class [PartOfRelationInformation](../PartOfRelationInformation.md)
* class [SchemaInfo](../SchemaInfo.md)
* namespace [IdsLib.IfcSchema](../../ids-lib.md)

Expand Down
2 changes: 1 addition & 1 deletion ids-lib-documentation/ids-lib.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@
| class [IfcAttributeInformation](./IdsLib.IfcSchema/IfcAttributeInformation.md) | Metadata container for attributes of entities in IfcSchema |
| class [IfcClassInformation](./IdsLib.IfcSchema/IfcClassInformation.md) | Metadata container for entities of an IfcSchema |
| class [IfcMeasureInformation](./IdsLib.IfcSchema/IfcMeasureInformation.md) | Metadata container for entities containing measures of an IfcSchema |
| class [IfcOneToManyRelationInformation](./IdsLib.IfcSchema/IfcOneToManyRelationInformation.md) | Metadata container for relations that are primarily one-to-many between IFC entities |
| class [IfcSchemaAttribute](./IdsLib.IfcSchema/IfcSchemaAttribute.md) | Metadata attribute to define if a value of [`IfcSchemaVersions`](./IdsLib.IfcSchema/IfcSchemaVersions.md) identifies a single version of the schema |
| [Flags] enum [IfcSchemaVersions](./IdsLib.IfcSchema/IfcSchemaVersions.md) | Enumerations for the identification of multiple schema versions. |
| interface [IPropertyTypeInfo](./IdsLib.IfcSchema/IPropertyTypeInfo.md) | Generalised metadata on IFC properties |
| static class [IPropertyTypeInfoExtensions](./IdsLib.IfcSchema/IPropertyTypeInfoExtensions.md) | Static class to contain extension method helpers for [`IPropertyTypeInfo`](./IdsLib.IfcSchema/IPropertyTypeInfo.md). |
| class [NamedPropertyType](./IdsLib.IfcSchema/NamedPropertyType.md) | Schema metadata for properties with name |
| class [PartOfRelationInformation](./IdsLib.IfcSchema/PartOfRelationInformation.md) | Metadata container for relations that are primarily one-to-many between IFC entities |
| class [PropertySetInfo](./IdsLib.IfcSchema/PropertySetInfo.md) | Information about standard property sets defined from bS |
| class [SchemaInfo](./IdsLib.IfcSchema/SchemaInfo.md) | Provides static methods to get the collection of classes in the published schemas. |
| class [SingleValuePropertyType](./IdsLib.IfcSchema/SingleValuePropertyType.md) | Schema metadata for single value properties |
Expand Down
82 changes: 37 additions & 45 deletions ids-lib.codegen/IfcSchema_PartOfRelationGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,42 +1,19 @@
using System.Text;
using Xbim.Common.Metadata;
using static NSubstitute.Arg;

namespace IdsLib.codegen;

public class IfcSchema_PartOfRelationGenerator
{
private class GenOneToManyRelationInfo
{
public void AddSchema(string schema, string oneType, string manyType)
{
Schemas.Add(schema);
if (manyType != ManyType)
throw new ArgumentException($"Inconsistent type across schemas on enumerable side of the {RelationName} relation ({manyType} vs. {ManyType}), we need to rethink auditing logic.");
if (oneType != OneType)
throw new ArgumentException($"Inconsistent type across schemas on one-side of the {RelationName} relation ({oneType} vs. {OneType}), we need to rethink auditing logic.");
}

public GenOneToManyRelationInfo(string relationName, string schema, string oneType, string enumerableType)
{
RelationName = relationName;
OneType = oneType;
ManyType = enumerableType;
Schemas = new List<string>() { schema };
}

internal List<string> Schemas { get; set; }
internal string ManyType { get; set; }
internal string OneType { get; set; }
internal string RelationName { get; set; }
}

internal static string Execute()
{
var relationNames = GetRelationNames();

var measureInfos = new Dictionary<string, GenOneToManyRelationInfo>();
var schemaInfos = new Dictionary<string, StringBuilder>();
foreach (var schema in Program.schemas)
{
var sb = new StringBuilder();
System.Reflection.Module module = SchemaHelper.GetModule(schema);
var metaD = ExpressMetaData.GetMetadata(module);
foreach (var daRelation in relationNames)
Expand All @@ -46,34 +23,39 @@ internal static string Execute()
var t = metaD.ExpressType(daRelation.ToUpperInvariant());
if (t is null)
continue;

var propOnManySide = t.Properties.Single(x => x.Value.EnumerableType is not null).Value;
var manyType = propOnManySide.EnumerableType;
var manyExpressType = metaD.ExpressType(manyType.Name.ToUpperInvariant());

var propOnOneSide = t.Properties.Single(x => x.Value.EnumerableType is null && x.Value.Name.StartsWith("Relating")).Value;
var oneType = propOnOneSide.PropertyInfo.PropertyType;
var oneExpressType = metaD.ExpressType(oneType.Name.ToUpperInvariant());
var propOnPartSide = t.Properties.SingleOrDefault(x => x.Value.EnumerableType is not null).Value;
Type? partType = null;
if (propOnPartSide is not null)
{
partType = propOnPartSide.EnumerableType;
}
else
{
propOnPartSide = t.Properties.Single(x => x.Value.EnumerableType is null && x.Value.Name.StartsWith("Related")).Value;
partType = propOnPartSide.PropertyInfo.PropertyType;
}
var partExpressType = metaD.ExpressType(partType.Name.ToUpperInvariant());

if (measureInfos.TryGetValue(daRelation, out var lst))
lst.AddSchema(schema, oneExpressType.Name, manyType.Name);
else
measureInfos.Add(daRelation, new GenOneToManyRelationInfo(daRelation, schema, oneExpressType.Name, manyType.Name));
var propOnOwnerSide = t.Properties.Single(x => x.Value.EnumerableType is null && x.Value.Name.StartsWith("Relating")).Value;
var ownerType = propOnOwnerSide.PropertyInfo.PropertyType;
var ownerExpressType = metaD.ExpressType(ownerType.Name.ToUpperInvariant());

sb.AppendLine($""" yield return new PartOfRelationInformation("{daRelation}", "{ownerExpressType.Name.ToUpperInvariant()}", "{partExpressType.Name.ToUpperInvariant()}");""");
}
catch
{
continue;
}
}
schemaInfos.Add(schema.ToString(), sb);
}
var source = stub;
var sbMeasures = new StringBuilder();
foreach (var clNm in measureInfos.Keys.OrderBy(x => x))
foreach (var schema in schemaInfos.Keys.OrderBy(x => x))
{
var relInfo = measureInfos[clNm];
sbMeasures.AppendLine($""" yield return new IfcOneToManyRelationInformation("{clNm}", {CodeHelpers.NewStringArray(relInfo.Schemas)}, "{relInfo.OneType}", "{relInfo.ManyType}");""");
source = source.Replace($"<PlaceHolderRelations{schema}>\r\n", schemaInfos[schema].ToString());
}
source = source.Replace($"<PlaceHolderRelations>\r\n", sbMeasures.ToString());

source = source.Replace($"<PlaceHolderVersion>", VersionHelper.GetFileVersion(typeof(ExpressMetaData)));
return source;
}
Expand Down Expand Up @@ -102,16 +84,26 @@ public partial class SchemaInfo
/// <summary>
/// The names of classes across all schemas.
/// </summary>
public static IEnumerable<IfcOneToManyRelationInformation> AllPartOfRelations
public IEnumerable<PartOfRelationInformation> AllPartOfRelations
{
get
{
<PlaceHolderRelations>
if (Version == IfcSchemaVersions.Ifc2x3)
{
<PlaceHolderRelationsIfc2x3>
}
if (Version == IfcSchemaVersions.Ifc4)
{
<PlaceHolderRelationsIfc4>
}
if (Version == IfcSchemaVersions.Ifc4x3)
{
<PlaceHolderRelationsIfc4x3>
}
}
}
}
}
";

}
10 changes: 5 additions & 5 deletions ids-lib.codegen/IfcSchema_PropertiesGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ namespace IdsLib.codegen;

public class IfcSchema_PropertiesGenerator
{
/// <summary>
/// Computes the GetPropertiesIFC2x3 and GetPropertiesIFC4 of the PropertySetInfo.Generated.cs file
/// Depends on the Xbim.Properties assembly.
/// </summary>
public static string Execute()
/// <summary>
/// Computes the GetPropertiesIFC2x3, GetPropertiesIFC4 and GetPropertiesIFC4x3 of the PropertySetInfo.Generated.cs file
/// Depends on the Xbim.Properties assembly.
/// </summary>
public static string Execute()
{
var source = stub;
var schemas = new[] { Xbim.Properties.Version.IFC2x3, Xbim.Properties.Version.IFC4, Xbim.Properties.Version.IFC4x3 };
Expand Down
44 changes: 21 additions & 23 deletions ids-lib/IdsSchema/IdsNodes/Facets/IdsPartOf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,7 @@ internal protected override Audit.Status PerformAudit(ILogger? logger)

// relation child is always a valid string matcher
var relMatcher = new StringListMatcher(relationValue, this);
var possibleRelationNames = SchemaInfo.AllPartOfRelations
.Where(x => (x.ValidSchemaVersions & requiredSchemaVersions) == requiredSchemaVersions)
.Select(y => y.IfcName);
// this triggers a log error if there's anything but a single match
ret |= relMatcher.HasSingleMatch(possibleRelationNames, false, logger, out var matchedRelationName, "relation names", requiredSchemaVersions);


// if the facet is not required we don't check if it makes sense semantically
if (!IsRequired)
Expand All @@ -66,28 +62,31 @@ internal protected override Audit.Status PerformAudit(ILogger? logger)
return ret;
}

// if we have a match then there are other constraints we can evaluate on the
// types of both sides of the relation
//
if (matchedRelationName is null)
return SetInvalid();
var relationInfo = SchemaInfo.AllPartOfRelations.FirstOrDefault(x => x.IfcName == matchedRelationName);
if (relationInfo is null)
{
ret |= IdsErrorMessages.Report501UnexpectedScenario(logger, $"no valid relation found for {matchedRelationName}", this);
return SetInvalid(ret);
}


requiredSchemaVersions.TryGetSchemaInformation(out var schemas);
foreach (var schema in schemas)
{
var possibleRelationNames = schema.AllPartOfRelations.Select(y => y.RelationIfcName);
// this triggers a log error if there's anything but a single match
ret |= relMatcher.HasSingleMatch(possibleRelationNames, false, logger, out var matchedRelationName, "relation names", requiredSchemaVersions);

// if we have a match then there are other constraints we can evaluate on the
// types of both sides of the relation
//
if (matchedRelationName is null)
return SetInvalid();
var relationInfo = schema.AllPartOfRelations.FirstOrDefault(x => x.RelationIfcName == matchedRelationName);
if (relationInfo is null)
{
ret |= IdsErrorMessages.Report501UnexpectedScenario(logger, $"no valid relation found for {matchedRelationName}", this);
return SetInvalid(ret);
}

// Entities of the partOf need to be of type of relationInfo.ManySideIfcType
//
var filter = new IfcInheritanceTypeConstraint(relationInfo.ManySideIfcType, schema.Version);
//
var filter = new IfcInheritanceTypeConstraint(relationInfo.PartIfcType, schema.Version);
if (IfcTypeConstraint.IsNotNullAndEmpty(filter))
{
ret |= IdsErrorMessages.Report501UnexpectedScenario(logger, $"no valid types found for {relationInfo.ManySideIfcType}", this);
ret |= IdsErrorMessages.Report501UnexpectedScenario(logger, $"no valid types found for {relationInfo.PartIfcType}", this);
return SetInvalid(ret);
}
typeFilters.Add(schema, filter);
Expand All @@ -100,14 +99,13 @@ internal protected override Audit.Status PerformAudit(ILogger? logger)
return SetInvalid(ret);
}

var validChildEntityType = new IfcInheritanceTypeConstraint(relationInfo.OneSideIfcType, schema.Version);
var validChildEntityType = new IfcInheritanceTypeConstraint(relationInfo.OwnerIfcType, schema.Version);
var possible = validChildEntityType.Intersect(childEntity.GetTypesFilter(schema));
if (possible.IsEmpty)
{
ret |= IdsErrorMessages.Report201IncompatibleClauses(logger, this, schema, "relation not compatible with provided child entity");
return SetInvalid(ret);
}

}
IsValid = true;
return ret;
Expand Down
38 changes: 0 additions & 38 deletions ids-lib/IfcSchema/IfcOneToManyRelationInformation.cs

This file was deleted.

Loading

0 comments on commit 0aa65f1

Please sign in to comment.