@ -1,289 +1,294 @@
using System.Collections.Concurrent ;
using System.Collections.Concurrent ;
using System.Linq.Expressions ;
using System.Linq.Expressions ;
using System.Reflection ;
using System.Reflection ;
using System.Text.Json ;
using System.Text.Json ;
using System.Text.Json.Serialization ;
using System.Text.Json.Serialization ;
using Azure ;
using Azure ;
using Azure.Data.Tables ;
using Azure.Data.Tables ;
namespace Microsoft.OneFuzz.Service.OneFuzzLib.Orm ;
namespace Microsoft.OneFuzz.Service.OneFuzzLib.Orm ;
public abstract record EntityBase {
public abstract record EntityBase {
[JsonIgnore] public ETag ? ETag { get ; set ; }
[JsonIgnore] public ETag ? ETag { get ; set ; }
public DateTimeOffset ? TimeStamp { get ; set ; }
public DateTimeOffset ? TimeStamp { get ; set ; }
// https://docs.microsoft.com/en-us/rest/api/storageservices/designing-a-scalable-partitioning-strategy-for-azure-table-storage#yyy
// https://docs.microsoft.com/en-us/rest/api/storageservices/designing-a-scalable-partitioning-strategy-for-azure-table-storage#yyy
// Produce "good-quality-table-key" based on a DateTimeOffset timestamp
// Produce "good-quality-table-key" based on a DateTimeOffset timestamp
public static string NewSortedKey = > $"{DateTimeOffset.MaxValue.Ticks - DateTimeOffset.UtcNow.Ticks}" ;
public static string NewSortedKey = > $"{DateTimeOffset.MaxValue.Ticks - DateTimeOffset.UtcNow.Ticks}" ;
}
}
public abstract record StatefulEntityBase < T > ( [ property : JsonIgnore ] T State ) : EntityBase ( ) where T : Enum ;
public abstract record StatefulEntityBase < T > ( [ property : JsonIgnore ] T State ) : EntityBase ( ) where T : Enum ;
/// Indicates that the enum cases should no be renamed
[AttributeUsage(AttributeTargets.Enum)]
/// Indicates that the enum cases should no be renamed
public class SkipRename : Attribute { }
[AttributeUsage(AttributeTargets.Enum)]
public class RowKey Attribute : Attribute { }
public class SerializeValue Attribute : Attribute { }
public class PartitionKeyAttribute : Attribute { }
public class TypeDiscrimnatorAttribute : Attribute {
/// Indicates that the enum cases should no be renamed
public string FieldName { get ; }
[AttributeUsage(AttributeTargets.Enum)]
// the type of a function that takes the value of fieldName as an input and return the type
public class SkipRename : Attribute { }
public Type ConverterTyp e { get ; }
public class RowKeyAttribut e : Attribute { }
public class PartitionKeyAttribute : Attribute { }
public TypeDiscrimnatorAttribute( string fieldName , Type converterType ) {
public class TypeDiscrimnatorAttribute : Attribute {
if ( ! converterType . IsAssignableTo ( typeof ( ITypeProvider ) ) ) {
public string FieldName { get ; }
throw new ArgumentException ( $"the provided type needs to implement ITypeProvider" ) ;
// the type of a function that takes the value of fieldName as an input and return the type
}
public Type ConverterType { get ; }
FieldName = fieldName ;
public TypeDiscrimnatorAttribute ( string fieldName , Type converterType ) {
ConverterType = converterType ;
if ( ! converterType . IsAssignableTo ( typeof ( ITypeProvider ) ) ) {
}
throw new ArgumentException ( $"the provided type needs to implement ITypeProvider" ) ;
}
}
public interface ITypeProvider {
FieldName = fieldName ;
Type GetTypeInfo ( object input ) ;
ConverterType = converterType ;
}
}
}
public enum EntityPropertyKind {
PartitionKey ,
public interface ITypeProvider {
RowKey ,
Type GetTypeInfo ( object input ) ;
Column
}
}
public record EntityProperty ( string name , string columnName , Type type , EntityPropertyKind kind , ( TypeDiscrimnatorAttribute , ITypeProvider ) ? discriminator ) ;
public enum EntityPropertyKind {
public record EntityInfo ( Type type , ILookup < string , EntityProperty > properties , Func < object? [ ] , object > constructor ) ;
PartitionKey ,
RowKey ,
class OnefuzzNamingPolicy : JsonNamingPolicy {
Column
public override string ConvertName ( string name ) {
}
return CaseConverter . PascalToSnake ( name ) ;
public record EntityProperty ( string name , string columnName , Type type , EntityPropertyKind kind , ( TypeDiscrimnatorAttribute , ITypeProvider ) ? discriminator ) ;
}
public record EntityInfo ( Type type , ILookup < string , EntityProperty > properties , Func < object? [ ] , object > constructor ) ;
}
public class EntityConverter {
class OnefuzzNamingPolicy : JsonNamingPolicy {
private readonly Js onS erializerOptions _options ;
public override string C onv ertName ( string name ) {
return CaseConverter . PascalToSnake ( name ) ;
private readonly ConcurrentDictionary < Type , EntityInfo > _cache ;
}
}
private readonly ETag _emptyETag = new ETag ( ) ;
public class EntityConverter {
private readonly JsonSerializerOptions _options ;
public EntityConverter ( ) {
_options = GetJsonSerializerOptions ( ) ;
private readonly ConcurrentDictionary < Type , EntityInfo > _cache ;
_cache = new ConcurrentDictionary < Type , EntityInfo > ( ) ;
private readonly ETag _emptyETag = new ETag ( ) ;
}
public EntityConverter ( ) {
_options = GetJsonSerializerOptions ( ) ;
public static JsonSerializerOptions GetJsonSerializerOptions ( ) {
_cache = new ConcurrentDictionary < Type , EntityInfo > ( ) ;
var options = new JsonSerializerOptions ( ) {
PropertyNamingPolicy = new OnefuzzNamingPolicy ( ) ,
}
} ;
options . Converters . Add ( new CustomEnumConverterFactory ( ) ) ;
options . C onv erters . Add ( new PolymorphicC onv erterFactory ( ) ) ;
public static Js onS erializerOptions GetJs onS erializerOptions ( ) {
return options ;
var options = new JsonSerializerOptions ( ) {
}
PropertyNamingPolicy = new OnefuzzNamingPolicy ( ) ,
} ;
internal static Func < object? [ ] , object > BuildConstructerFrom ( ConstructorInfo constructorInfo ) {
options . Converters . Add ( new CustomEnumConverterFactory ( ) ) ;
var constructorParameters = Expression . Parameter ( typeof ( object? [ ] ) ) ;
options . Converters . Add ( new PolymorphicConverterFactory ( ) ) ;
return options ;
var parameterExpressions =
}
constructorInfo . GetParameters ( ) . Select ( ( parameterInfo , i ) = > {
var ithIndex = Expression . Constant ( i ) ;
internal static Func < object? [ ] , object > BuildConstructerFrom ( ConstructorInfo constructorInfo ) {
var ith Parameter = Expression . ArrayIndex ( constructor Parameters , ithIndex ) ;
var constructor Parameters = Expression . Parameter ( typeof ( object? [ ] ) ) ;
var unboxedIthParameter = Expression . Convert ( ithParameter , parameterInfo . ParameterType ) ;
return unboxedIthParameter ;
var parameterExpressions =
constructorInfo . GetParameters ( ) . Select ( ( parameterInfo , i ) = > {
} ) . ToArray ( ) ;
var ithIndex = Expression . Constant ( i ) ;
var ithParameter = Expression . ArrayIndex ( constructorParameters , ithIndex ) ;
NewExpression constructorCall = Expression . New ( constructo rInfo, p arameterExpressions ) ;
var unboxedIthParameter = Expression . Convert ( ithParameter , paramete rInfo . P arameterType ) ;
return unboxedIthParameter ;
Func < object? [ ] , object > ctor = Expression . Lambda < Func < object? [ ] , object > > ( constructorCall , constructorParameters ) . Compile ( ) ;
return ctor ;
} ) . ToArray ( ) ;
}
NewExpression constructorCall = Expression . New ( constructorInfo , parameterExpressions ) ;
private IEnumerable < EntityProperty > GetEntityProperties < T > ( ParameterInfo parameterInfo ) {
var name = parameterInfo . N ame . EnsureNotNull ( $"Invalid paramter {parameterInfo}" ) ;
Func < object? [ ] , object > ctor = Expression . L ambda < Func < object? [ ] , object > > ( constructorCall , constructorParameters ) . Compile ( ) ;
var parameterType = parameterInfo . ParameterType . EnsureNotNull ( $"Invalid paramter {parameterInfo}" ) ;
return ctor ;
var isRowkey = parameterInfo . GetCustomAttribute ( typeof ( RowKeyAttribute ) ) ! = null ;
}
var isPartitionkey = parameterInfo . GetCustomAttribute ( typeof ( PartitionKeyAttribute ) ) ! = null ;
private IEnumerable < EntityProperty > GetEntityProperties < T > ( ParameterInfo parameterInfo ) {
var discriminatorAttribute = typeof ( T ) . GetProperty ( n ame) ? . GetCustomAttribute < TypeDiscrimnatorAttribute > ( ) ;
var name = parameterInfo . N ame. EnsureNotNull ( $"Invalid paramter {parameterInfo}" ) ;
var parameterType = parameterInfo . ParameterType . EnsureNotNull ( $"Invalid paramter {parameterInfo}" ) ;
( TypeDiscrimna tor Attribute, ITypeProvider ) ? discriminator = null ;
var isRowkey = parameterInfo . GetCus tom Attribute( typeof ( RowKeyAttribute ) ) ! = null ;
if ( discriminator Attribute ! = null ) {
var isPartitionkey = parameterInfo . GetCustomAttribute ( typeof ( PartitionKey Attribute) ) ! = null ;
var t = ( ITypeProvider ) ( discriminatorAttribute . ConverterType . GetConstructor ( new Type [ ] { } ) ? . Invoke ( null ) ? ? throw new Exception ( "unable to retrive the type provider" ) ) ;
discriminator = ( d iscrimi natorAttribute , t ) ;
var discriminatorAttribute = typeof ( T ) . GetProperty ( name ) ? . GetCustomAttribute < TypeD iscrimnatorAttribute > ( ) ;
}
( TypeDiscrimnatorAttribute , ITypeProvider ) ? discriminator = null ;
if ( discriminatorAttribute ! = null ) {
if ( isPartitionkey ) {
var t = ( ITypeProvider ) ( d iscriminatorAttribute . ConverterType . GetConstructor ( new Type [ ] { } ) ? . Invoke ( null ) ? ? throw new Exception ( "unable to retrive the type provider" ) ) ;
yield return new EntityProperty ( name , "PartitionKey" , parameterType , EntityPropertyKind . PartitionKey , discriminator ) ;
discriminator = ( discriminatorAttribute , t ) ;
}
}
if ( isRowkey ) {
yield return new EntityProperty ( name , "RowKey" , parameterType , EntityPropertyKind . RowKey , discriminator ) ;
if ( isPartitionkey ) {
}
yield return new EntityProperty ( name , "PartitionKey" , parameterType , EntityPropertyKind . PartitionKey , discriminator ) ;
}
if ( ! isPartitionkey & & ! isRowkey ) {
var columnName = typeof ( T ) . GetProperty ( name ) ? . GetCustomAttribute < JsonPropertyNameAttribute > ( ) ? . Name ? ? CaseConverter . PascalToSnake ( name ) ;
if ( isRowkey ) {
yield return new EntityProperty ( name , columnName , parameterType , EntityPropertyKind . Column , discriminator ) ;
yield return new EntityProperty ( name , "RowKey" , parameterType , EntityPropertyKind . RowKey , discriminator ) ;
}
}
}
if ( ! isPartitionkey & & ! isRowkey ) {
var columnName = typeof ( T ) . GetProperty ( name ) ? . GetCustomAttribute < JsonPropertyNameAttribute > ( ) ? . Name ? ? CaseConverter . PascalToSnake ( name ) ;
private EntityInfo GetEntityInfo < T > ( ) {
yield return new EntityProperty ( name , columnName , parameterType , EntityPropertyKind . Column , discriminator ) ;
return _cache . GetOrAdd ( typeof ( T ) , type = > {
}
var constructor = type . GetConstructors ( ) [ 0 ] ;
}
var parameterInfos = constructor . GetParameters ( ) ;
var parameters =
parameterInfos . SelectMany ( GetEntityProperties < T > ) . ToArray ( ) ;
private EntityInfo GetEntityInfo < T > ( ) {
return _cache . GetOrAdd ( typeof ( T ) , type = > {
return new EntityInfo ( typeof ( T ) , parameters . ToLookup ( x = > x . name ) , BuildConstructerFrom ( constructor ) ) ;
var constructor = type . GetConstructors ( ) [ 0 ] ;
} ) ;
var parameterInfos = constructor . GetParameters ( ) ;
}
var parameters =
parameterInfos . SelectMany ( GetEntityProperties < T > ) . ToArray ( ) ;
public string ToJsonString < T > ( T typedEntity ) {
var serialized = JsonSerializer . Serialize ( typedEntity , _options ) ;
return new EntityInfo ( typeof ( T ) , parameters . ToLookup ( x = > x . name ) , BuildConstructerFrom ( constructor ) ) ;
return serialized ;
} ) ;
}
}
public TableEntity ToTableEntity < T > ( T typedEntity ) where T : EntityBase {
public string ToJsonString < T > ( T typedEntity ) {
if ( typedEntity = = null ) {
var serialized = JsonSerializer . Serialize ( typedEntity , _options ) ;
throw new NullReferenceException ( ) ;
return serialized ;
}
}
var type = typeof ( T ) ! ;
if ( type is null ) {
public TableEntity ToTableEntity < T > ( T typedEntity ) where T : EntityBase {
throw new NullReferenceException ( ) ;
if ( typedEntity = = null ) {
}
throw new NullReferenceException ( ) ;
var tableEntity = new TableEntity ( ) ;
}
var entityInfo = GetEntityInfo < T > ( ) ;
var type = typeof ( T ) ! ;
foreach ( var prop in entityInfo . properties . SelectMany ( x = > x ) ) {
if ( type is null ) {
//var prop = kvp.First() ;
throw new NullReferenceException ( ) ;
var value = entityInfo . type . GetProperty ( prop . name ) ? . GetValue ( typedEntity ) ;
}
if ( prop . kind = = EntityPropertyKind . PartitionKey | | prop . kind = = EntityPropertyKind . RowKey ) {
var tableEntity = new TableEntity ( ) ;
tableEntity . Add ( prop . columnName , value ? . ToString ( ) ) ;
var entityInfo = GetEntityInfo < T > ( ) ;
} else if ( prop . type = = typeof ( Guid ) | | prop . type = = typeof ( Guid ? ) ) {
foreach ( var prop in entityInfo . properties . SelectMany ( x = > x ) ) {
tableEntity . Add ( prop . columnName , value ? . ToString ( ) ) ;
//var prop = kvp.First() ;
} else if ( prop . type = = typeof ( bool )
var value = entityInfo . type . GetProperty ( prop . name ) ? . GetValue ( typedEntity ) ;
| | prop . type = = typeof ( bool? )
if ( prop . kind = = EntityPropertyKind . PartitionKey | | prop . kind = = EntityPropertyKind . RowKey ) {
| | prop . type = = typeof ( string )
tableEntity . Add ( prop . columnName , value ? . ToString ( ) ) ;
| | prop . type = = typeof ( DateTime )
} else if ( prop . type = = typeof ( Guid ) | | prop . type = = typeof ( Guid ? ) ) {
| | prop . type = = typeof ( DateTime ? )
tableEntity . Add ( prop . columnName , value ? . ToString ( ) ) ;
| | prop . type = = typeof ( DateTimeOffset )
} else if ( prop . type = = typeof ( bool )
| | prop . type = = typeof ( DateTimeOffset ?)
| | prop . type = = typeof ( bool ?)
| | prop . type = = typeof ( int )
| | prop . type = = typeof ( str ing )
| | prop . type = = typeof ( int? )
| | prop . type = = typeof ( DateTime )
| | prop . type = = typeof ( Int64 )
| | prop . type = = typeof ( DateTime ? )
| | prop . type = = typeof ( Int64 ? )
| | prop . type = = typeof ( DateTimeOffset )
| | prop . type = = typeof ( double )
| | prop . type = = typeof ( DateTimeOffset ? )
| | prop . type = = typeof ( double? )
| | prop . type = = typeof ( int )
| | prop . type = = typeof ( int? )
) {
| | prop . type = = typeof ( Int64 )
tableEntity . Add ( prop . columnName , value ) ;
| | prop . type = = typeof ( Int64 ? )
} else if ( prop . type . IsEnum ) {
| | prop . type = = typeof ( double )
var values =
| | prop . type = = typeof ( double? )
( value ? . ToString ( ) ? . Split ( ',' , StringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries )
. Select ( CaseConverter . PascalToSnake ) ) . EnsureNotNull ( $"Unable to read enum data {value}" ) ;
) {
tableEntity . Add ( prop . columnName , value ) ;
tableEntity . Add ( prop . columnName , string . Join ( "," , values ) ) ;
} else if ( prop . type . IsEnum ) {
} else {
var values =
var serialized = JsonSerializer . Se rialize ( value , _options ) ;
( value ? . ToString ( ) ? . Split ( ',' , St ringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries )
tableEntity . Add ( prop . columnName , serialized . Trim ( '"' ) ) ;
. Select ( CaseConverter . PascalToSnake ) ) . EnsureNotNull ( $"Unable to read enum data {value}" ) ;
}
tableEntity . Add ( prop . columnName , string . Join ( "," , values ) ) ;
}
} else {
var serialized = JsonSerializer . Serialize ( value , _options ) ;
if ( typedEntity . ETag . HasValue ) {
tableEntity . Add ( prop . columnName , serialized . Trim ( '"' ) ) ;
tableEntity . ETag = typedEntity . ETag . Value ;
}
}
}
return tableEntity ;
}
if ( typedEntity . ETag . HasValue ) {
tableEntity . ETag = typedEntity . ETag . Value ;
}
private object? GetFieldValue ( EntityInfo info , string name , TableEntity entity ) {
var ef = info . properties [ name ] . First ( ) ;
return tableEntity ;
if ( ef . kind = = EntityPropertyKind . PartitionKey | | ef . kind = = EntityPropertyKind . RowKey ) {
}
if ( ef . type = = typeof ( string ) )
return entity . GetString ( ef . kind . ToString ( ) ) ;
else if ( ef . type = = typeof ( Guid ) )
private object? GetFieldValue ( EntityInfo info , string name , TableEntity entity ) {
return Guid . Parse ( entity . GetString ( ef . kind . ToString ( ) ) ) ;
var ef = info . properties [ name ] . First ( ) ;
else if ( ef . type = = typeof ( int ) )
if ( ef . kind = = EntityPropertyKind . PartitionKey | | ef . kind = = EntityPropertyKind . RowKey ) {
return int . Parse ( entity . GetString ( ef . kind . ToS tring( )) ) ;
if ( ef . type = = typeof ( s tring) )
else {
return entity . GetString ( ef . kind . ToString ( ) ) ;
throw new Exception ( "invalid " ) ;
else if ( ef . type = = typeof ( Guid ) )
}
return Guid . Parse ( entity . GetString ( ef . kind . ToString ( ) ) ) ;
}
else if ( ef . type = = typeof ( int ) )
return int . Parse ( entity . GetString ( ef . kind . ToString ( ) ) ) ;
var fieldName = ef . columnName ;
else {
var obj = entity [ fieldName ] ;
throw new Exception ( "invalid " ) ;
if ( obj = = null ) {
}
return null ;
}
}
var objTyp e = obj . GetType ( ) ;
var fieldNam e = ef . columnName ;
var obj = entity [ fieldName ] ;
if ( ef . type = = typeof ( string ) ) {
if ( obj = = null ) {
return entity . GetString ( fieldName ) ;
return null ;
} else if ( ef . type = = typeof ( bool ) | | ef . type = = typeof ( bool? ) ) {
}
return entity . GetBoolean ( fieldName ) ;
var objType = obj . GetType ( ) ;
} else if ( ef . type = = typeof ( DateTimeOffset ) | | ef . type = = typeof ( DateTimeOffset ? ) ) {
return entity . GetDateTimeOffset ( fieldName ) ;
if ( ef . type = = typeof ( string ) ) {
} else if ( ef . type = = typeof ( DateTime ) | | ef . type = = typeof ( DateTime ? ) ) {
return entity . GetString ( fieldName ) ;
return entity . GetDateTime ( fieldName ) ;
} else if ( ef . type = = typeof ( bool ) | | ef . type = = typeof ( bool? ) ) {
} else if ( ef . type = = typeof ( double ) | | ef . type = = typeof ( double? ) ) {
return entity . GetBoolean ( fieldName ) ;
return entity . GetDouble ( fieldName ) ;
} else if ( ef . type = = typeof ( DateTimeOffset ) | | ef . type = = typeof ( DateTimeOffset ? ) ) {
} else if ( ef . type = = typeof ( Guid ) | | ef . type = = typeof ( Guid ? ) ) {
return entity . GetDateTimeOffset ( fieldName ) ;
return ( object? ) Guid . Parse ( entity . GetString ( fieldName ) ) ;
} else if ( ef . type = = typeof ( DateTime ) | | ef . type = = typeof ( DateTime ? ) ) {
} else if ( ef . type = = typeof ( int ) | | ef . type = = typeof ( short ) | | ef . type = = typeof ( int? ) | | ef . type = = typeof ( short? ) ) {
return entity . GetDateTime ( fieldName ) ;
return entity . GetInt32 ( fieldName ) ;
} else if ( ef . type = = typeof ( double ) | | ef . type = = typeof ( double? ) ) {
} else if ( ef . type = = typeof ( long ) | | ef . type = = typeof ( long? ) ) {
return entity . GetDouble ( fieldName ) ;
return entity . GetInt64 ( fieldName ) ;
} else if ( ef . type = = typeof ( Guid ) | | ef . type = = typeof ( Guid ? ) ) {
} else if ( ef . type . IsEnum ) {
return ( object? ) Guid . Parse ( entity . GetString ( fieldName ) ) ;
var stringValues =
} else if ( ef . type = = typeof ( int ) | | ef . type = = typeof ( short ) | | ef . type = = typeof ( int? ) | | ef . type = = typeof ( short? ) ) {
entity . GetString ( fieldName ) . Split ( "," , StringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries )
return entity . GetInt32 ( fieldName ) ;
. Select ( CaseConverter . SnakeToPascal ) ;
} else if ( ef . type = = typeof ( long ) | | ef . type = = typeof ( long? ) ) {
return entity . GetInt64 ( fieldName ) ;
return Enum . Parse ( ef . type , string . Join ( "," , stringValues ) ) ;
} else if ( ef . type . IsEnum ) {
} else {
var stringValues =
var outputType = ef . type ;
entity . GetString ( fieldName ) . Split ( "," , StringSplitOptions . RemoveEmptyEntries | StringSplitOptions . TrimEntries )
if ( ef . discriminator ! = nul l) {
. Select ( CaseConverter . SnakeToPasca l) ;
var ( attr , typeProvider ) = ef . discriminator . Value ;
var v = GetFieldValue ( info , attr . FieldName , entity ) ? ? throw new Exception ( $"No value for {attr.FieldName}" ) ;
return Enum . Parse ( ef . type , string . Join ( "," , stringValues ) ) ;
outputType = typeProvider . GetTypeInfo ( v ) ;
} else {
}
var outputType = ef . type ;
if ( ef . discriminator ! = null ) {
var ( attr , typeProvider ) = ef . discriminator . Value ;
if ( objType = = typeof ( string ) ) {
var v = GetFieldValue ( info , attr . FieldName , entity ) ? ? throw new Exception ( $"No value for {attr.FieldName}" ) ;
var value = entity . GetString ( fieldName ) ;
outputType = typeProvider . GetTypeInfo ( v ) ;
if ( value . StartsWith ( '[' ) | | value . StartsWith ( '{' ) | | value = = "null" ) {
}
return JsonSerializer . Deserialize ( value , outputType , options : _options ) ;
} else {
return JsonSerializer . Deserialize ( $"\" { value } \ "" , outputType , options : _options ) ;
if ( objType = = typeof ( string ) ) {
}
var value = entity . GetString ( fieldName ) ;
} else {
if ( value . StartsWith ( '[' ) | | value . StartsWith ( '{' ) | | value = = "null" ) {
var value = entity . GetString ( fieldName ) ;
return JsonSerializer . Deserialize ( value , outputType , options : _options ) ;
return JsonSerializer . Deserialize ( value , outputType , options : _options ) ;
} else {
}
return JsonSerializer . Deserialize ( $"\" { value } \ "" , outputType , options : _options ) ;
}
}
}
} else {
var value = entity . GetString ( fieldName ) ;
return JsonSerializer . Deserialize ( value , outputType , options : _options ) ;
public T ToRecord < T > ( TableEntity entity ) where T : EntityBase {
}
var entityInfo = GetEntityInfo < T > ( ) ;
}
var parameters =
}
entityInfo . properties . Select ( grouping = > GetFieldValue ( entityInfo , grouping . Key , entity ) ) . ToArray ( ) ;
try {
var entityRecord = ( T ) entityInfo . constructor . Invoke ( parameters ) ;
public T ToRecord < T > ( TableEntity entity ) where T : EntityBase {
if ( e ntity . ETag ! = _emptyETag ) {
var entityInfo = GetE ntityInfo < T > ( ) ;
entityRecord . ETag = entity . ETag ;
var parameters =
}
entityInfo . properties . Select ( grouping = > GetFieldValue ( entityInfo , grouping . Key , entity ) ) . ToArray ( ) ;
entityRecord . TimeStamp = entity . Timestamp ;
try {
return entityRecord ;
var entityRecord = ( T ) entityInfo . constructor . Invoke ( parameters ) ;
if ( entity . ETag ! = _emptyETag ) {
} catch ( Exception ex ) {
entityRecord . ETag = entity . ETag ;
var stringParam = string . Join ( ", " , parameters ) ;
}
throw new Exception ( $"Could not initialize object of type {typeof(T)} with the following parameters: {stringParam} constructor {entityInfo.constructor} : {ex}" ) ;
entityRecord . TimeStamp = entity . Timestamp ;
}
return entityRecord ;
}
} catch ( Exception ex ) {
var stringParam = string . Join ( ", " , parameters ) ;
}
throw new Exception ( $"Could not initialize object of type {typeof(T)} with the following parameters: {stringParam} constructor {entityInfo.constructor} : {ex}" ) ;
}
}
}