Skip to content

Commit

Permalink
fixes unit tests issues
Browse files Browse the repository at this point in the history
  • Loading branch information
pksorensen committed Aug 6, 2024
1 parent 03da5e5 commit cc47003
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 53 deletions.
23 changes: 18 additions & 5 deletions sdk/DTO/AttributeDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ public class AttributeObjectDefinition : AttributeDefinitionBase
[JsonExtensionData]
public Dictionary<string, JsonElement> AdditionalFields { get; set; }

[JsonPropertyName("maxLength")]
public int? MaxLength { get; set; }


[JsonPropertyName("isPrimaryKey")]
public bool? IsPrimaryKey { get; set; }
Expand All @@ -88,9 +87,7 @@ public class AttributeObjectDefinition : AttributeDefinitionBase

public bool? IsRequired { get; set; }

[JsonPropertyName("required")]

public bool? Required { get; set; }


[JsonPropertyName("isRowVersion")]
public bool IsRowVersion { get; set; }
Expand Down Expand Up @@ -146,6 +143,16 @@ public class CascadeOptions
[JsonPropertyName("update")]
[JsonConverter(typeof(JsonStringEnumConverter))]
public CascadeAction? OnUpdate { get; set; }

public override bool Equals(object obj)
{
if (obj is CascadeOptions cascadeOptions)
{
return OnDelete == cascadeOptions.OnDelete && OnUpdate == cascadeOptions.OnUpdate;
}

return base.Equals(obj);
}
}

public enum CascadeAction
Expand Down Expand Up @@ -201,6 +208,12 @@ public class TypeDefinition
[JsonPropertyName("index")]
public IndexInfo IndexInfo { get; set; }

[JsonPropertyName("required")]

public bool? Required { get; set; }
[JsonPropertyName("maxLength")]
public int? MaxLength { get; set; }

/// <summary>
/// Exclusively used to capture non-spec items
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions sdk/DTO/EntityDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ public class EntityDefinition
[JsonProperty("wizards")]
public Dictionary<string, WizardDefinition> Wizards { get; set; }

[JsonPropertyName("keys")]
[JsonProperty("keys")]
public Dictionary<string, string[]> Keys { get; set; }


/// <summary>
/// Exclusively used to capture non-spec items
/// </summary>
Expand Down
56 changes: 55 additions & 1 deletion sdk/DTO/ManifestDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,60 @@ public class MigrationAttributeDefinition
public AttributeObjectDefinition Target { get; set; }
public string Key { get; set; }
public MigrationEntityDefinition Entity { get; set; }

public bool HasCascadeChanges()
{

if (Source.AttributeType.Cascades == null && Target.AttributeType.Cascades != null)
return true;
if (Source.AttributeType.Cascades != null && Target.AttributeType.Cascades == null)
return true;
if (Source.AttributeType.Cascades != null && !Source.AttributeType.Cascades.Equals(Target.AttributeType.Cascades))
return true;

return false;
}
public bool HasChanged()
{
if ((Source.IsRequired??false) != (Target.IsRequired??false))
return true;
if(Source.AttributeType.Type != Target.AttributeType.Type)
return true;
if (Source.AttributeType.MaxLength != Target.AttributeType.MaxLength)
return true;


//if (Source.AttributeType.Cascades == null && Target.AttributeType.Cascades != null)
// return true;
//if (Source.AttributeType.Cascades != null && Target.AttributeType.Cascades == null)
// return true;
//if (Source.AttributeType.Cascades != null && !Source.AttributeType.Cascades.Equals(Target.AttributeType.Cascades))
// return true;


if (Source.AttributeType.SqlOptions == null && Target.AttributeType.SqlOptions != null)
return true;
if (Source.AttributeType.SqlOptions != null && Target.AttributeType.SqlOptions == null)
return true;

if (Source.AttributeType.SqlOptions != null)
{
if (Source.AttributeType.SqlOptions.Count != Target.AttributeType.SqlOptions.Count)
return true;
if (Source.AttributeType.SqlOptions.Keys.Except(Target.AttributeType.SqlOptions.Keys).Any())
return true;
if (Target.AttributeType.SqlOptions.Keys.Except(Source.AttributeType.SqlOptions.Keys).Any())
return true;
if (Target.AttributeType.SqlOptions.Any(kv => Source.AttributeType.SqlOptions[kv.Key].Equals(kv.Value)))
return true;
}





return false;
}
}

public enum MappingStrategyChangeEnum
Expand Down Expand Up @@ -115,7 +169,7 @@ public MigrationEntityDefinition GetEntityMigration(string entityKey)
return new MigrationEntityDefinition
{
MigrationDefinition = this,
Source = Source.Entities[entityKey],
Source = (Source?.Entities.ContainsKey(entityKey) ??false) ? Source.Entities[entityKey] : null,

Target = Target.Entities[entityKey]
};
Expand Down
2 changes: 1 addition & 1 deletion src/DynamicContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ public MigrationsInfo GetMigrations()
foreach (var migration in test.Migrations)
{

var name = $"{modelOptions.Value.Schema}_{migration.Target.Version.Replace(".", "_") ?? MigrationDefaultName}";
var name = $"{modelOptions.Value.Schema}_{migration.Target.Version?.Replace(".", "_") ?? MigrationDefaultName}";

var model = manager.CreateMigration(name, migration, this.modelOptions.Value);

Expand Down
2 changes: 1 addition & 1 deletion src/Shared/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2702,7 +2702,7 @@ private string GenerateSourceCode(Type type, bool generatePoco)
}
else
{
sb.AppendLine($"\tpublic{(type.IsAbstract ? " abstract " : " ")}partial class {type.Name}{inherience}\r\n\t{{");
sb.AppendLine($"\tpublic{(options.GenerateAbstractClasses && type.IsAbstract ? " abstract " : " ")}partial class {type.Name}{inherience}\r\n\t{{");
{
foreach (var ctor in type.GetConstructors())
{
Expand Down
4 changes: 3 additions & 1 deletion src/Shared/V2/CodeGenerationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ public class GeoSpatialOptions
}
public class CodeGenerationOptions
{


public bool GenerateAbstractClasses { get; set; } = true;

/// <summary>
/// The constructor used for the Newtonsoft JsonPropertyAttribute when setting DTO Property Attributes.
/// </summary>
Expand Down
122 changes: 79 additions & 43 deletions src/Shared/V2/ManifestService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -863,18 +863,18 @@ private Dictionary<PropertyInfo, object> BuildParametersForcolumn(ILGenerator en
{


case "maxLength" when propertyInfo.MaxLength.HasValue:
case "maxLength" when propertyInfo.AttributeType.MaxLength.HasValue:

dynamicCodeService.EmitPropertyService.EmitNullable(entityCtorBuilderIL, () => entityCtorBuilderIL.Emit(OpCodes.Ldc_I4, propertyInfo.MaxLength.Value), arg1);
dynamicCodeService.EmitPropertyService.EmitNullable(entityCtorBuilderIL, () => entityCtorBuilderIL.Emit(OpCodes.Ldc_I4, propertyInfo.AttributeType.MaxLength.Value), arg1);

AddParameterComparison(parameters, argName, propertyInfo.MaxLength.Value);
AddParameterComparison(parameters, argName, propertyInfo.AttributeType.MaxLength.Value);

break;
case "table" when !string.IsNullOrEmpty(tableName): entityCtorBuilderIL.Emit(OpCodes.Ldstr, tableName); break;
case "schema" when !string.IsNullOrEmpty(schema): dynamicCodeService.EmitPropertyService.EmitNullable(entityCtorBuilderIL, () => entityCtorBuilderIL.Emit(OpCodes.Ldstr, schema), arg1); break;
case "columnName": entityCtorBuilderIL.Emit(OpCodes.Ldstr, propertyInfo.SchemaName); break;
case "nullable" when (propertyInfo.IsPrimaryKey ?? false):
case "nullable" when options.RequiredSupport && ((propertyInfo.Required ?? false) || (propertyInfo.IsRequired ?? false)):
case "nullable" when options.RequiredSupport && ((propertyInfo.AttributeType.Required ?? false) || (propertyInfo.IsRequired ?? false)):
case "nullable" when (propertyInfo.IsRowVersion):
dynamicCodeService.EmitPropertyService.EmitNullable(entityCtorBuilderIL, () => entityCtorBuilderIL.Emit(OpCodes.Ldc_I4_0), arg1);
break;
Expand All @@ -885,8 +885,8 @@ private Dictionary<PropertyInfo, object> BuildParametersForcolumn(ILGenerator en
dynamicCodeService.EmitPropertyService.EmitNullable(entityCtorBuilderIL, () => entityCtorBuilderIL.Emit(OpCodes.Ldstr, "nvarchar(max)"), arg1);
break;

case "type" when string.Equals(propertyInfo.AttributeType.Type, "text", StringComparison.OrdinalIgnoreCase) && !propertyInfo.MaxLength.HasValue:
case "type" when string.Equals(propertyInfo.AttributeType.Type, "string", StringComparison.OrdinalIgnoreCase) && !propertyInfo.MaxLength.HasValue:
case "type" when string.Equals(propertyInfo.AttributeType.Type, "text", StringComparison.OrdinalIgnoreCase) && !propertyInfo.AttributeType.MaxLength.HasValue:
case "type" when string.Equals(propertyInfo.AttributeType.Type, "string", StringComparison.OrdinalIgnoreCase) && !propertyInfo.AttributeType.MaxLength.HasValue:
dynamicCodeService.EmitPropertyService.EmitNullable(entityCtorBuilderIL, () => entityCtorBuilderIL.Emit(OpCodes.Ldstr, $"nvarchar({((propertyInfo.IsPrimaryField) ? 255 : 100)})"), arg1);
break;
case "rowVersion" when propertyInfo.IsRowVersion:
Expand Down Expand Up @@ -1067,6 +1067,7 @@ internal IDynamicTable[] CreateMigrationTables(MigrationDefinition migration, Dy

var entityKey = pair.Key;
var entity = pair.Value;
var entityMigration = migration.GetEntityMigration(entityKey);

foreach (var field in GetFields(entity).Where(v => IsAttributeLookup(v.Value)))
{
Expand Down Expand Up @@ -1156,20 +1157,20 @@ internal IDynamicTable[] CreateMigrationTables(MigrationDefinition migration, Dy
else
{

var entityMigration = migration.GetEntityMigration(entityKey);

var migrationStrategy = entityMigration.MappingStrategyChange();



foreach (var newField in entityMigration.GetNewAttributes().OfType<AttributeObjectDefinition>())
{
var required = (newField.IsRequired ?? false) || (newField.IsRequired ?? false);
var required = (newField.IsRequired ?? false) || (newField.AttributeType.Required ?? false);

//We cant add a required column to existing table, rely on it being altered after data is set.
//this is a case when we are changing from TPT to TPC
newField.IsRequired = newField.Required = false;
newField.IsRequired = newField.AttributeType.Required = false;
EmitAddColumn(migrationBuilder.UpMethodIL, entity.CollectionSchemaName, schema, newField);
newField.IsRequired = newField.Required = required;
newField.IsRequired = newField.AttributeType.Required = required;

if (IsFieldLookup(newField))
{
Expand Down Expand Up @@ -1227,36 +1228,32 @@ INNER JOIN
foreach (var existingField in entityMigration.GetExistingFields())
{

//if (!existingField.Target.IsRowVersion && IsBaseMember(migration.Entities, entity, existingField.Key, out var parent) && migrationStrategy == MappingStrategyChangeEnum.TPT2TPC)
//{
// var upSql1 = $@"UPDATE
// [{schema}].[{entity.CollectionSchemaName}]
// SET
// [{schema}].[{entity.CollectionSchemaName}].[{existingField.Target.SchemaName}] = BaseRecords.[{existingField.Target.SchemaName}]
// FROM
// [{schema}].[{entity.CollectionSchemaName}] Records
// INNER JOIN
// [{schema}].[{parent.CollectionSchemaName}] BaseRecords
// ON
// records.Id = BaseRecords.Id;";

// EmitSQLUp(migrationBuilder.UpMethodIL, upSql1);

// // see comment above for why we alter the column to required.
// if (IsFieldRequired(existingField.Source))
// {
// EmitAlterColumn(migrationBuilder.UpMethodIL, entity.CollectionSchemaName, schema, existingField.Target);
// }

//}

if (IsFieldLookup(existingField.Target)
&& !string.IsNullOrEmpty(existingField.Target.AttributeType.ReferenceType) && migration.Entities[existingField.Target.AttributeType.ReferenceType] is EntityDefinition referenceType
&& (referenceType.Abstract ?? false)
&& migration.GetEntityMigration(existingField.Target.AttributeType.ReferenceType).MappingStrategyChange() == MappingStrategyChangeEnum.TPT2TPC)
if (existingField.HasChanged())
{
EmitAlterColumn(migrationBuilder.UpMethodIL, entity.CollectionSchemaName, schema, existingField.Target);

}

if (IsFieldLookup(existingField.Target) && existingField.HasCascadeChanges())
{
var referenceType = migration.Entities[existingField.Target.AttributeType.ReferenceType];
migrationBuilder.DropForeignKey(entity.CollectionSchemaName, schema,
$"FK_{entity.CollectionSchemaName}_{referenceType.CollectionSchemaName}_{existingField.Target.SchemaName}".Replace(" ", ""));
$"FK_{entity.CollectionSchemaName}_{referenceType.CollectionSchemaName}_{existingField.Target.SchemaName}".Replace(" ", ""));
AddForeignKey(entity.CollectionSchemaName, schema, migrationBuilder.UpMethodIL, existingField.Target,
referenceType);
}

{

if (IsFieldLookup(existingField.Target)
&& !string.IsNullOrEmpty(existingField.Target.AttributeType.ReferenceType) && migration.Entities[existingField.Target.AttributeType.ReferenceType] is EntityDefinition referenceType
&& (referenceType.Abstract ?? false)
&& migration.GetEntityMigration(existingField.Target.AttributeType.ReferenceType).MappingStrategyChange() == MappingStrategyChangeEnum.TPT2TPC)
{
migrationBuilder.DropForeignKey(entity.CollectionSchemaName, schema,
$"FK_{entity.CollectionSchemaName}_{referenceType.CollectionSchemaName}_{existingField.Target.SchemaName}".Replace(" ", ""));
}

}

}
Expand All @@ -1267,7 +1264,19 @@ INNER JOIN

}


// var fields = entity.GetAllProperties(migration.Entities).Values.OfType<AttributeObjectDefinition>().ToArray();
foreach (var key in entityMigration.GetNewKeys())
{

var props = key.Value;
var name = key.Key;

var colums = props.Select(p => entity.GetField(p,migration.Entities).SchemaName).ToArray();
migrationBuilder.CreateIndex(entity.CollectionSchemaName,entity.Schema ?? dynamicCodeService.Options.Schema ?? "dbo",
name, true, colums);

}



Expand Down Expand Up @@ -1308,7 +1317,7 @@ INNER JOIN

private bool IsFieldRequired(AttributeObjectDefinition source)
{
return source.IsRequired ?? source.Required ?? false;
return source.IsRequired ?? source.AttributeType.Required ?? false;
}

public bool IsFieldLookup(AttributeObjectDefinition source)
Expand Down Expand Up @@ -1555,6 +1564,23 @@ public static EntityDefinition GetParentEntity(this EntityDefinition entity, Dic
return null;
}

public static AttributeObjectDefinition GetField(this EntityDefinition entity,string key, Dictionary<string, EntityDefinition> entities)
{


while (entity != null)
{
if (entity.Attributes.ContainsKey(key) && entity.Attributes[key] is AttributeObjectDefinition attr)
return attr;

entity = entity.GetParentEntity(entities);
}

throw new KeyNotFoundException($"Field {key} not found in entity {entity.CollectionSchemaName} or its parent entities.");


}

public static Dictionary<string, AttributeDefinitionBase> GetAllProperties(this EntityDefinition entity, Dictionary<string, EntityDefinition> entities)
{

Expand Down Expand Up @@ -1598,14 +1624,24 @@ public static IEnumerable<AttributeDefinitionBase> GetAttributesMovingFromBase(t
return targetAttributes.Where(e => !sourceAttributes.ContainsKey(e.Key) && !target.Attributes.ContainsKey(e.Key)).Select(c => c.Value);
}

public static Dictionary<string, AttributeDefinitionBase> GetProperties(this EntityDefinition entity,
public static Dictionary<string, AttributeObjectDefinition> GetProperties(this EntityDefinition entity,
Dictionary<string, EntityDefinition> entities)
{
return (entity.GetMappingStrategy(entities) == MappingStrategy.TPC ?
entity.GetAllProperties(entities) : entity.Attributes);
return (entity.GetMappingStrategy(entities) == MappingStrategy.TPC ?
entity.GetAllProperties(entities) : entity.Attributes)
.OfType<string,AttributeDefinitionBase,AttributeObjectDefinition>()
.OrderByDescending(c => c.Value.IsPrimaryKey)
.ThenByDescending(c => c.Value.IsPrimaryField)
.ThenBy(c => c.Value.LogicalName)
.ToDictionary(k=>k.Key,v=>v.Value);

}

public static Dictionary<string, string[]> GetNewKeys(this MigrationEntityDefinition migrationEntity)
{
return migrationEntity.Target?.Keys?
.Where(kv=> !(migrationEntity.Source?.Keys?.ContainsKey(kv.Key) ??false))
.ToDictionary(k=>k.Key,v=>v.Value) ?? new Dictionary<string, string[]>();
}
public static MappingStrategyChangeEnum MappingStrategyChange(this MigrationEntityDefinition migrationEntity)
{

Expand Down
Loading

0 comments on commit cc47003

Please sign in to comment.