diff --git a/.editorconfig b/.editorconfig index e40916ea..a9b1a8bd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -23,6 +23,9 @@ csharp_new_line_before_members_in_anonymous_types = true # Sort using and Import directives with System.* appearing first dotnet_sort_system_directives_first = false +## Primary constructors +dotnet_analyzer_diagnostic.category-Style.severity = none + # Avoid "this." if not necessary dotnet_style_qualification_for_field = false : suggestion dotnet_style_qualification_for_property = false : suggestion diff --git a/samples/YesSql.Samples.Hi/Program.cs b/samples/YesSql.Samples.Hi/Program.cs index 2925eeda..8e0b32dd 100644 --- a/samples/YesSql.Samples.Hi/Program.cs +++ b/samples/YesSql.Samples.Hi/Program.cs @@ -7,7 +7,7 @@ namespace YesSql.Samples.Hi { - internal class Program + internal sealed class Program { static void Main(string[] args) { diff --git a/src/Directory.Build.props b/src/Directory.Build.props index bb942cdb..0b4b190c 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -37,4 +37,81 @@ + + + latest-Recommended + + + $(NoWarn);CA1805 + + + $(NoWarn);CA1304;CA1305;CA1310 + + + $(NoWarn);CA1311 + + + $(NoWarn);CA1000 + + + $(NoWarn);CA1848 + + + $(NoWarn);CA1720 + + + $(NoWarn);CA1051 + + + $(NoWarn);CA1200 + + + $(NoWarn);CA1711 + + + $(NoWarn);CA1725 + + + $(NoWarn);CA1716 + + + $(NoWarn);CA1001 + + + $(NoWarn);CA2201 + + + $(NoWarn);CA1707 + + + $(NoWarn);CA1727 + + + $(NoWarn);CA1861 + + + $(NoWarn);NU1603 + + $(NoWarn);612 + + $(NoWarn);618 + + $(NoWarn);CA2211 + + + $(NoWarn);CA1016 + + + $(NoWarn);CA2254 + + $(NoWarn);CA2208 + + + $(NoWarn),1573,1591,1712 + + + $(NoWarn);NETSDK1206 + + + diff --git a/src/YesSql.Abstractions/ISqlDialect.cs b/src/YesSql.Abstractions/ISqlDialect.cs index 0c166e0f..5ee1f00f 100644 --- a/src/YesSql.Abstractions/ISqlDialect.cs +++ b/src/YesSql.Abstractions/ISqlDialect.cs @@ -27,7 +27,7 @@ public interface ISqlDialect void ResetTypeHandlers(); - void AddTypeHandler(Func handler); + void AddTypeHandler(Func handler); /// /// Gets the name of the dialect. @@ -38,7 +38,7 @@ public interface ISqlDialect /// Gets the cascade constraint sql statement. /// string CascadeConstraintsString { get; } - + /// /// Gets the create table sql statement. /// @@ -64,7 +64,7 @@ public interface ISqlDialect /// Whether the underlying database support batching. /// bool SupportsBatching { get; } - + /// /// Whether the dialect support unique queries. /// @@ -94,7 +94,7 @@ public interface ISqlDialect /// Gets the Int64 primary key with identity column SQL statement. /// string LegacyIdentityColumnString { get; } - + /// /// Gets the identity select SQL statement to append to an insert in order to return the last generated identifier. /// diff --git a/src/YesSql.Abstractions/Indexes/DescribeFor.cs b/src/YesSql.Abstractions/Indexes/DescribeFor.cs index e376c209..2688feec 100644 --- a/src/YesSql.Abstractions/Indexes/DescribeFor.cs +++ b/src/YesSql.Abstractions/Indexes/DescribeFor.cs @@ -88,19 +88,11 @@ public IGroupFor Map(Func> map) public IReduceFor Group(Expression> group) { - var memberExpression = group.Body as MemberExpression; + var memberExpression = group.Body as MemberExpression + ?? throw new ArgumentException("Group expression is not a valid member of: " + typeof(TIndex).Name); - if (memberExpression == null) - { - throw new ArgumentException("Group expression is not a valid member of: " + typeof(TIndex).Name); - } - - var property = memberExpression.Member as PropertyInfo; - - if (property == null) - { - throw new ArgumentException("Group expression is not a valid property of: " + typeof(TIndex).Name); - } + var property = memberExpression.Member as PropertyInfo + ?? throw new ArgumentException("Group expression is not a valid property of: " + typeof(TIndex).Name); GroupProperty = property; diff --git a/src/YesSql.Abstractions/SimplifiedTypeName.cs b/src/YesSql.Abstractions/SimplifiedTypeNameAttribute.cs similarity index 51% rename from src/YesSql.Abstractions/SimplifiedTypeName.cs rename to src/YesSql.Abstractions/SimplifiedTypeNameAttribute.cs index 0fadbc31..fce2ec52 100644 --- a/src/YesSql.Abstractions/SimplifiedTypeName.cs +++ b/src/YesSql.Abstractions/SimplifiedTypeNameAttribute.cs @@ -5,11 +5,12 @@ namespace YesSql /// /// Use this attribute to provide a custom string representation of a type. /// - public class SimplifiedTypeName : Attribute + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum | AttributeTargets.Interface | AttributeTargets.Delegate)] + public class SimplifiedTypeNameAttribute : Attribute { public string Name { get; set; } - public SimplifiedTypeName(string name) + public SimplifiedTypeNameAttribute(string name) { Name = name; } diff --git a/src/YesSql.Core/Commands/BatchCommand.cs b/src/YesSql.Core/Commands/BatchCommand.cs index d37a9124..53eec3db 100644 --- a/src/YesSql.Core/Commands/BatchCommand.cs +++ b/src/YesSql.Core/Commands/BatchCommand.cs @@ -12,7 +12,7 @@ public class BatchCommand : IIndexCommand public static int DefaultBuilderCapacity = 10 * 1024; public List Queries { get; set; } = new List(); - public DbCommand Command { get; set; } + public DbCommand Command { get; set; } public List> Actions = new(); public int ExecutionOrder => 0; diff --git a/src/YesSql.Core/Commands/IndexCommand.cs b/src/YesSql.Core/Commands/IndexCommand.cs index c0e0b234..67bc7a3b 100644 --- a/src/YesSql.Core/Commands/IndexCommand.cs +++ b/src/YesSql.Core/Commands/IndexCommand.cs @@ -110,7 +110,11 @@ protected string Inserts(Type type, ISqlDialect dialect) for (var i = 0; i < allProperties.Length; i++) { var property = allProperties.ElementAt(i); - sbParameterList.Append("@").Append(property.Name).Append(ParameterSuffix); + + sbParameterList.Append('@') + .Append(property.Name) + .Append(ParameterSuffix); + if (i < allProperties.Length - 1) { sbParameterList.Append(", "); @@ -186,6 +190,6 @@ private static bool IsWriteable(PropertyInfo pi) public abstract bool AddToBatch(ISqlDialect dialect, List queries, DbCommand batchCommand, List> actions, int index); - private record CompoundKey(string Dialect, string Type, string Schema, string Prefix, string Collection); + private sealed record CompoundKey(string Dialect, string Type, string Schema, string Prefix, string Collection); } } diff --git a/src/YesSql.Core/Data/NullableThumbprintFactory.cs b/src/YesSql.Core/Data/NullableThumbprintFactory.cs index 4be1d7f8..723ff7fc 100644 --- a/src/YesSql.Core/Data/NullableThumbprintFactory.cs +++ b/src/YesSql.Core/Data/NullableThumbprintFactory.cs @@ -9,9 +9,9 @@ namespace YesSql.Data /// If nullable arguments (including strings) are used, the SQL should vary. /// This class allows to generate a Thumbprint for each set of nullable compiled query properties. /// - internal class NullableThumbprintFactory + internal sealed class NullableThumbprintFactory { - private static Dictionary _discriminatorFactories = new(); + private static readonly Dictionary _discriminatorFactories = new(); internal static NullableThumbprintBuilder GetNullableThumbprintBuilder(Type type) { @@ -32,29 +32,27 @@ internal static NullableThumbprintBuilder GetNullableThumbprintBuilder(Type type public static long GetNullableThumbprint(object item) { - if (item == null) - { - throw new ArgumentNullException(nameof(item)); - } + ArgumentNullException.ThrowIfNull(item); var builder = GetNullableThumbprintBuilder(item.GetType()); + return builder.GetNullableThumbprint(item); } } - internal class NullableThumbprintBuilder + internal sealed class NullableThumbprintBuilder { - private Type _type; + private readonly Type _type; private static int _globalTypeIndex; - private long _typeIndex; + private readonly long _typeIndex; private const int MaxTypeIndex = 1 << 16; // 65536 types max, 16 bits for the type private const int MaxProperties = 48; - private List _nullableAccessors; + private readonly List _nullableAccessors; public NullableThumbprintBuilder(Type type) - { + { _type = type; // Each type gets a unique type index @@ -96,7 +94,7 @@ private interface INullablePropertyAccessor bool IsPropertyNull(object obj); } - private class NullableAccessor : INullablePropertyAccessor where T : class + private sealed class NullableAccessor : INullablePropertyAccessor where T : class { private readonly Func _getter; @@ -111,6 +109,8 @@ bool INullablePropertyAccessor.IsPropertyNull(object obj) } } + private const long _long1 = 1; + /// /// Returns an 64 bits integer representing the unique set of nullable fields as a bit mask. The 16 MSB represent the type, and the 48 LSB represent individual fields /// @@ -122,14 +122,12 @@ public long GetNullableThumbprint(object o) { return mask; } - - const long long1 = 1; - for (var i= 0; i < _nullableAccessors.Count; i++) + for (var i = 0; i < _nullableAccessors.Count; i++) { if (_nullableAccessors[i].IsPropertyNull(o)) { - mask = mask | (long1 << i); + mask = mask | (_long1 << i); } } diff --git a/src/YesSql.Core/Data/PropertyAccessorFactory.cs b/src/YesSql.Core/Data/PropertyAccessorFactory.cs index 8c318072..e75dbb95 100644 --- a/src/YesSql.Core/Data/PropertyAccessorFactory.cs +++ b/src/YesSql.Core/Data/PropertyAccessorFactory.cs @@ -9,11 +9,11 @@ namespace YesSql.Data /// public class PropertyAccessorFactory : IAccessorFactory { - const BindingFlags DefaultBindingFlags = BindingFlags.IgnoreCase - | BindingFlags.Public - | BindingFlags.Instance - | BindingFlags.GetProperty - | BindingFlags.SetProperty + const BindingFlags DefaultBindingFlags = BindingFlags.IgnoreCase + | BindingFlags.Public + | BindingFlags.Instance + | BindingFlags.GetProperty + | BindingFlags.SetProperty ; private readonly string _propertyName; @@ -41,7 +41,7 @@ public IAccessor CreateAccessor(Type tContainer) var setter = propertyInfo.GetSetMethod(true).CreateDelegate(setType); Type accessorType = null; - + if (tProperty == typeof(int)) { accessorType = typeof(IntAccessor<>); @@ -66,7 +66,7 @@ public IAccessor CreateAccessor(Type tContainer) /// An accessor to an Int32 Id property /// /// - internal class IntAccessor : IAccessor + internal sealed class IntAccessor : IAccessor { private readonly Func _getter; private readonly Action _setter; @@ -92,7 +92,7 @@ void IAccessor.Set(object obj, long value) /// An accessor to an Int64 Id property /// /// - internal class LongAccessor : IAccessor + internal sealed class LongAccessor : IAccessor { private readonly Func _getter; private readonly Action _setter; diff --git a/src/YesSql.Core/Data/WorkerQueryKey.cs b/src/YesSql.Core/Data/WorkerQueryKey.cs index 6a347e3a..bafce098 100644 --- a/src/YesSql.Core/Data/WorkerQueryKey.cs +++ b/src/YesSql.Core/Data/WorkerQueryKey.cs @@ -64,12 +64,12 @@ public bool Equals(WorkerQueryKey other) { return false; } - + if (_parameters != null || other._parameters != null) { return SameParameters(_parameters, other._parameters); } - + if (_ids != null || other._ids != null) { return SameIds(_ids, other._ids); diff --git a/src/YesSql.Core/Provider/BaseDialect.cs b/src/YesSql.Core/Provider/BaseDialect.cs index 9e904359..82f9d7a2 100644 --- a/src/YesSql.Core/Provider/BaseDialect.cs +++ b/src/YesSql.Core/Provider/BaseDialect.cs @@ -75,7 +75,7 @@ public virtual object TryConvert(object source) public abstract string Name { get; } public virtual string InOperator(string values) { - if (values.StartsWith("@") && !values.Contains(',')) + if (values.StartsWith('@') && !values.Contains(',')) { return " IN " + values; } @@ -106,7 +106,7 @@ public virtual string NotInSelectOperator(string values) public abstract string IdentitySelectString { get; } public abstract string IdentityLastId { get; } - + public abstract string IdentityColumnString { get; } public abstract string LegacyIdentityColumnString { get; } @@ -286,7 +286,7 @@ public void ResetTypeHandlers() _typeHandlers.Clear(); } - public void AddTypeHandler(Func handler) + public void AddTypeHandler(Func handler) { if (!_typeHandlers.TryGetValue(typeof(T), out var handlers)) { diff --git a/src/YesSql.Core/Provider/ServiceCollectionExtensions.cs b/src/YesSql.Core/Provider/ServiceCollectionExtensions.cs index e085c3c8..b80b4e3c 100644 --- a/src/YesSql.Core/Provider/ServiceCollectionExtensions.cs +++ b/src/YesSql.Core/Provider/ServiceCollectionExtensions.cs @@ -9,15 +9,9 @@ public static IServiceCollection AddDbProvider( this IServiceCollection services, Action setupAction) { - if (services == null) - { - throw new ArgumentNullException(nameof(services)); - } + ArgumentNullException.ThrowIfNull(services); - if (setupAction == null) - { - throw new ArgumentNullException(nameof(setupAction)); - } + ArgumentNullException.ThrowIfNull(setupAction); var config = new Configuration(); setupAction.Invoke(config); diff --git a/src/YesSql.Core/Serialization/DefaultContentSerializer.cs b/src/YesSql.Core/Serialization/DefaultContentSerializer.cs index 3515a57e..aeb1234b 100644 --- a/src/YesSql.Core/Serialization/DefaultContentSerializer.cs +++ b/src/YesSql.Core/Serialization/DefaultContentSerializer.cs @@ -10,8 +10,10 @@ public class DefaultContentSerializer : IContentSerializer public DefaultContentSerializer() { - _options = new(); - _options.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull; + _options = new() + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull + }; _options.Converters.Add(UtcDateTimeJsonConverter.Instance); _options.Converters.Add(DynamicJsonConverter.Instance); } diff --git a/src/YesSql.Core/Services/DbBlockIdGenerator.cs b/src/YesSql.Core/Services/DbBlockIdGenerator.cs index 8b95f7e1..8a0d230b 100644 --- a/src/YesSql.Core/Services/DbBlockIdGenerator.cs +++ b/src/YesSql.Core/Services/DbBlockIdGenerator.cs @@ -260,7 +260,7 @@ public async Task InitializeCollectionAsync(IConfiguration configuration, string _ranges[collection] = new Range(collection); } - private class Range + private sealed class Range { public Range(string collection) { diff --git a/src/YesSql.Core/Services/DefaultQuery.cs b/src/YesSql.Core/Services/DefaultQuery.cs index 542c2ee6..04ad5667 100644 --- a/src/YesSql.Core/Services/DefaultQuery.cs +++ b/src/YesSql.Core/Services/DefaultQuery.cs @@ -169,6 +169,40 @@ static DefaultQuery() builder.Append(")"); }; + MethodMappings[typeof(String).GetMethod("StartsWith", new Type[] { typeof(char) })] = static (query, builder, dialect, expression) => + { + builder.Append("("); + query.ConvertFragment(builder, expression.Object); + builder.Append(" like "); + query.ConvertFragment(builder, expression.Arguments[0]); + var parameter = query._queryState._sqlBuilder.Parameters[query._queryState._lastParameterName]; + query._queryState._sqlBuilder.Parameters[query._queryState._lastParameterName] = parameter.ToString() + "%"; + builder.Append(")"); + }; + + MethodMappings[typeof(String).GetMethod("EndsWith", new Type[] { typeof(char) })] = static (query, builder, dialect, expression) => + { + builder.Append("("); + query.ConvertFragment(builder, expression.Object); + builder.Append(" like "); + query.ConvertFragment(builder, expression.Arguments[0]); + var parameter = query._queryState._sqlBuilder.Parameters[query._queryState._lastParameterName]; + query._queryState._sqlBuilder.Parameters[query._queryState._lastParameterName] = "%" + parameter.ToString(); + builder.Append(")"); + + }; + + MethodMappings[typeof(String).GetMethod("Contains", new Type[] { typeof(char) })] = static (query, builder, dialect, expression) => + { + builder.Append("("); + query.ConvertFragment(builder, expression.Object); + builder.Append(" like "); + query.ConvertFragment(builder, expression.Arguments[0]); + var parameter = query._queryState._sqlBuilder.Parameters[query._queryState._lastParameterName]; + query._queryState._sqlBuilder.Parameters[query._queryState._lastParameterName] = "%" + parameter.ToString() + "%"; + builder.Append(")"); + }; + MethodMappings[typeof(String).GetMethod(nameof(string.Concat), new Type[] { typeof(string[]) })] = MethodMappings[typeof(String).GetMethod(nameof(string.Concat), new Type[] { typeof(string), typeof(string) })] = MethodMappings[typeof(String).GetMethod(nameof(string.Concat), new Type[] { typeof(string), typeof(string), typeof(string) })] = @@ -790,7 +824,7 @@ public void ConvertFragment(IStringBuilder builder, Expression expression) var methodInfo = methodCallExpression.Method; Action action; if (MethodMappings.TryGetValue(methodInfo, out action) - || MethodMappings.TryGetValue(methodInfo.GetGenericMethodDefinition(), out action)) + || (methodInfo.IsGenericMethod && MethodMappings.TryGetValue(methodInfo.GetGenericMethodDefinition(), out action))) { action(this, builder, _dialect, methodCallExpression); } @@ -874,7 +908,7 @@ public void ConvertPredicate(IStringBuilder builder, Expression expression) /// /// /// - private bool IsParameterBased(Expression expression) + private static bool IsParameterBased(Expression expression) { switch (expression.NodeType) { @@ -1396,12 +1430,12 @@ private string GetDeduplicatedQuery() sqlBuilder.Selector(selector); sqlBuilder.GroupBy(selector); - var aggregates = _query._dialect.GetAggregateOrders(sqlBuilder.GetSelectors().ToList(), sqlBuilder.GetOrders().ToList()); + var results = _query._dialect.GetAggregateOrders(sqlBuilder.GetSelectors().ToList(), sqlBuilder.GetOrders().ToList()); if (sqlBuilder.HasOrder) { sqlBuilder.ClearOrder(); - foreach (var result in aggregates) + foreach (var result in results) { sqlBuilder.AddSelector(", "); sqlBuilder.AddSelector(result.aggregate); @@ -1423,7 +1457,7 @@ private string GetDeduplicatedQuery() if (sqlBuilder.HasOrder) { - sql += $" ORDER BY {string.Join(", ", aggregates.Select(x => x.alias).ToList())}"; + sql += $" ORDER BY {string.Join(", ", results.Select(x => x.alias).ToList())}"; } return sql; @@ -1500,7 +1534,7 @@ async ValueTask> IQuery.AllAsync(params Func, ValueTask ComposeQuery(Func, IQuery>[] predicates, CompositeNode predicate) + private Query ComposeQuery(Func, IQuery>[] predicates, CompositeNode predicate) { _query._queryState._currentPredicate.Children.Add(predicate); diff --git a/src/YesSql.Core/Services/IndexProviderRegisterExtensions.cs b/src/YesSql.Core/Services/IndexProviderRegisterExtensions.cs index d40f6d85..f575cd61 100644 --- a/src/YesSql.Core/Services/IndexProviderRegisterExtensions.cs +++ b/src/YesSql.Core/Services/IndexProviderRegisterExtensions.cs @@ -17,10 +17,10 @@ public static IStore RegisterIndexes(this IStore store, IIndexProvider indexProv { if (indexProvider != null) { - return store.RegisterIndexes(new[] { indexProvider }, collection); + return store.RegisterIndexes([indexProvider], collection); } - return store.RegisterIndexes(new IIndexProvider[0], collection); + return store.RegisterIndexes([], collection); } public static IStore RegisterIndexes(this IStore store, Type type, string collection = null) @@ -37,7 +37,7 @@ public static IStore RegisterIndexes(this IStore store, IEnumerable types, store.RegisterIndexes(type, collection); } - return store.RegisterIndexes(new IIndexProvider[0], collection); + return store.RegisterIndexes([], collection); } public static IStore RegisterIndexes(this IStore store, Assembly assembly, string collection = null) diff --git a/src/YesSql.Core/Services/PredicateNodes.cs b/src/YesSql.Core/Services/PredicateNodes.cs index f30640e0..73638f2a 100644 --- a/src/YesSql.Core/Services/PredicateNodes.cs +++ b/src/YesSql.Core/Services/PredicateNodes.cs @@ -16,7 +16,7 @@ internal abstract class CompositeNode : PredicateNode public List Children = new(); } - internal class AndNode : CompositeNode + internal sealed class AndNode : CompositeNode { public override void Build(RentedStringBuilder builder) { @@ -48,14 +48,16 @@ public override void Build(RentedStringBuilder builder) public override PredicateNode Clone() { var children = Children.Select(x => x.Clone()).ToList(); - var clone = new AndNode(); - clone.Children = children; + var clone = new AndNode + { + Children = children + }; return clone; } } - internal class OrNode : CompositeNode + internal sealed class OrNode : CompositeNode { public override void Build(RentedStringBuilder builder) { @@ -96,7 +98,7 @@ public override PredicateNode Clone() } } - internal class FilterNode : CompositeNode + internal sealed class FilterNode : CompositeNode { public FilterNode(string filter) { diff --git a/src/YesSql.Core/Services/TypeService.cs b/src/YesSql.Core/Services/TypeService.cs index eb1a73e4..7792496f 100644 --- a/src/YesSql.Core/Services/TypeService.cs +++ b/src/YesSql.Core/Services/TypeService.cs @@ -22,7 +22,7 @@ public string this[Type t] return "dynamic"; } - var customName = typeInfo.GetCustomAttribute(); + var customName = typeInfo.GetCustomAttribute(); var calculatedName = string.IsNullOrEmpty(customName?.Name) ? $"{type.FullName}, {typeInfo.Assembly.GetName().Name}" : customName.Name; nameTypes[calculatedName] = t; diff --git a/src/YesSql.Core/Session.cs b/src/YesSql.Core/Session.cs index 0544f024..a3647505 100644 --- a/src/YesSql.Core/Session.cs +++ b/src/YesSql.Core/Session.cs @@ -255,10 +255,7 @@ private static void DetachInternal(object entity, SessionState state) private async Task SaveEntityAsync(object entity, string collection) { - if (entity == null) - { - throw new ArgumentNullException(nameof(entity)); - } + ArgumentNullException.ThrowIfNull(entity); if (entity is Document) { @@ -312,17 +309,14 @@ private async Task SaveEntityAsync(object entity, string collection) private async Task UpdateEntityAsync(object entity, bool tracked, string collection) { - if (entity == null) - { - throw new ArgumentNullException(nameof(entity)); - } + ArgumentNullException.ThrowIfNull(entity); if (entity is Document) { throw new ArgumentException("A document should not be saved explicitly"); } - if (entity is IIndex index) + if (entity is IIndex) { throw new ArgumentException("An index should not be saved explicitly"); } @@ -349,7 +343,7 @@ private async Task UpdateEntityAsync(object entity, bool tracked, string collect // if the document has already been updated or saved with this session (auto or intentional flush), ensure it has // been changed before doing another query - if (tracked && string.Equals(newContent, oldDoc.Content)) + if (tracked && string.Equals(newContent, oldDoc.Content, StringComparison.Ordinal)) { return; } @@ -445,10 +439,7 @@ public void Delete(object obj, string collection = null) private async Task DeleteEntityAsync(object obj, string collection) { - if (obj == null) - { - throw new ArgumentNullException(nameof(obj)); - } + ArgumentNullException.ThrowIfNull(obj); if (obj is IIndex) { @@ -459,11 +450,8 @@ private async Task DeleteEntityAsync(object obj, string collection) if (!state.IdentityMap.TryGetDocumentId(obj, out var id)) { - var accessor = _store.GetIdAccessor(obj.GetType()); - if (accessor == null) - { - throw new InvalidOperationException("Could not delete object as it doesn't have an Id property"); - } + var accessor = _store.GetIdAccessor(obj.GetType()) + ?? throw new InvalidOperationException("Could not delete object as it doesn't have an Id property"); id = accessor.Get(obj); } @@ -604,10 +592,7 @@ public IQuery Query(string collection = null) public IQuery ExecuteQuery(ICompiledQuery compiledQuery, string collection = null) where T : class { - if (compiledQuery == null) - { - throw new ArgumentNullException(nameof(compiledQuery)); - } + ArgumentNullException.ThrowIfNull(compiledQuery); var compiledQueryType = compiledQuery.GetType(); @@ -627,10 +612,12 @@ public IQuery ExecuteQuery(ICompiledQuery compiledQuery, string collect private void CheckDisposed() { +#pragma warning disable CA1513 // Use ObjectDisposedException throw helper if (_disposed) { throw new ObjectDisposedException(nameof(Session)); } +#pragma warning restore CA1513 // Use ObjectDisposedException throw helper } ~Session() @@ -700,7 +687,7 @@ private async Task FlushInternalAsync(bool saving) { EnterAsyncExecution(); } - + try { // saving all tracked entities @@ -789,7 +776,7 @@ private async Task FlushInternalAsync(bool saving) if (!saving) { ExitAsyncExecution(); - } + } } } @@ -1135,13 +1122,8 @@ private async Task ReduceAsync() // reduce over the two objects var reductions = new[] { dbIndex, index }; - var groupedReductions = reductions.GroupBy(descriptorGroup).SingleOrDefault(); - - if (groupedReductions == null) - { - throw new InvalidOperationException( - "The grouping on the db and in memory set should have resulted in a unique result"); - } + var groupedReductions = reductions.GroupBy(descriptorGroup).SingleOrDefault() + ?? throw new InvalidOperationException("The grouping on the db and in memory set should have resulted in a unique result"); index = descriptor.Reduce(groupedReductions); diff --git a/src/YesSql.Core/SessionState.cs b/src/YesSql.Core/SessionState.cs index 96548d79..5f844569 100644 --- a/src/YesSql.Core/SessionState.cs +++ b/src/YesSql.Core/SessionState.cs @@ -4,7 +4,7 @@ namespace YesSql { - internal class SessionState + internal sealed class SessionState { internal Dictionary> _maps; public Dictionary> Maps => _maps ??= new Dictionary>(); diff --git a/src/YesSql.Core/Sql/BaseComandInterpreter.cs b/src/YesSql.Core/Sql/BaseComandInterpreter.cs index 4c9311e3..4ef1922a 100644 --- a/src/YesSql.Core/Sql/BaseComandInterpreter.cs +++ b/src/YesSql.Core/Sql/BaseComandInterpreter.cs @@ -305,7 +305,7 @@ private void Run(StringBuilder builder, ICreateColumnCommand command) ? _dialect.NullColumnString : string.Empty); - // append unique if handled, otherwise at the end of the satement + // append unique if handled, otherwise at the end of the statement if (command.IsUnique && _dialect.SupportsUnique) { builder.Append(" unique"); @@ -319,7 +319,7 @@ private void Run(StringBuilder builder, ICreateColumnCommand command) /// /// /// - private string GetRawColumnName(string name) + private static string GetRawColumnName(string name) { var index = name.IndexOf('('); diff --git a/src/YesSql.Core/Sql/SqlBuilder.cs b/src/YesSql.Core/Sql/SqlBuilder.cs index eb53e886..b1608f2f 100644 --- a/src/YesSql.Core/Sql/SqlBuilder.cs +++ b/src/YesSql.Core/Sql/SqlBuilder.cs @@ -425,23 +425,25 @@ public virtual string ToSqlString() public ISqlBuilder Clone() { - var clone = new SqlBuilder(_tablePrefix, _dialect); - - clone._clause = _clause; - clone._table = _table; - - clone._select = _select == null ? null : new List(_select); - clone._from = _from == null ? null : new List(_from); - clone._join = _join == null ? null : new List(_join); - clone._where = _where == null ? null : new List(_where); - clone._group = _group == null ? null : new List(_group); - clone._having = _having == null ? null : new List(_having); - clone._order = _order == null ? null : new List(_order); - clone._trail = _trail == null ? null : new List(_trail); - clone._skip = _skip; - clone._count = _count; - - clone.Parameters = new Dictionary(Parameters); + var clone = new SqlBuilder(_tablePrefix, _dialect) + { + _clause = _clause, + _table = _table, + + _select = _select == null ? null : new List(_select), + _from = _from == null ? null : new List(_from), + _join = _join == null ? null : new List(_join), + _where = _where == null ? null : new List(_where), + _group = _group == null ? null : new List(_group), + _having = _having == null ? null : new List(_having), + _order = _order == null ? null : new List(_order), + _trail = _trail == null ? null : new List(_trail), + _skip = _skip, + _count = _count, + + Parameters = new Dictionary(Parameters) + }; + return clone; } } diff --git a/src/YesSql.Core/Store.cs b/src/YesSql.Core/Store.cs index 904ff779..d4bcf529 100644 --- a/src/YesSql.Core/Store.cs +++ b/src/YesSql.Core/Store.cs @@ -209,7 +209,9 @@ private void ValidateConfiguration() public ISession CreateSession(bool withTracking = true) => new Session(this, withTracking); +#pragma warning disable CA1816 // Dispose methods should call SuppressFinalize public void Dispose() +#pragma warning restore CA1816 // Dispose methods should call SuppressFinalize { } @@ -224,10 +226,7 @@ public IAccessor GetVersionAccessor(Type tContainer) /// public IEnumerable Describe(Type target, string collection) { - if (target == null) - { - throw new ArgumentNullException(nameof(target)); - } + ArgumentNullException.ThrowIfNull(target); var cacheKey = string.IsNullOrEmpty(collection) ? target.FullName diff --git a/src/YesSql.Core/Utils/HashHelper.cs b/src/YesSql.Core/Utils/HashHelper.cs index 8ce421df..6e0a72ba 100644 --- a/src/YesSql.Core/Utils/HashHelper.cs +++ b/src/YesSql.Core/Utils/HashHelper.cs @@ -20,25 +20,22 @@ public static string HashName(string prefix, string name) throw new ArgumentNullException("A prefix is required"); } - using (var hash = SHA256.Create()) - { - var bytes = Encoding.UTF8.GetBytes(name); - var hashed = hash.ComputeHash(bytes); + var bytes = Encoding.UTF8.GetBytes(name); + var hashed = SHA256.HashData(bytes); - var long1 = BitConverter.ToInt64(hashed, 0); - var long2 = BitConverter.ToInt64(hashed, 8); - var long3 = BitConverter.ToInt64(hashed, 16); - var long4 = BitConverter.ToInt64(hashed, 24); + var long1 = BitConverter.ToInt64(hashed, 0); + var long2 = BitConverter.ToInt64(hashed, 8); + var long3 = BitConverter.ToInt64(hashed, 16); + var long4 = BitConverter.ToInt64(hashed, 24); - return prefix + ToBase32(long1, long2, long3, long4); - } + return prefix + ToBase32(long1, long2, long3, long4); } private static string ToBase32(long long1, long long2, long long3, long long4) { var charBuffer = new char[52]; - int i = 0; + var i = 0; i = EncodeSegment(charBuffer, i, long1); @@ -49,7 +46,7 @@ private static string ToBase32(long long1, long long2, long long3, long long4) EncodeSegment(charBuffer, i, long4); return new string(charBuffer); - } + } private static int EncodeSegment(char[] charBuffer, int startIndex, long lng) { diff --git a/src/YesSql.Provider.MySql/MySqlCommandInterpreter.cs b/src/YesSql.Provider.MySql/MySqlCommandInterpreter.cs index a5fadd34..891b2916 100644 --- a/src/YesSql.Provider.MySql/MySqlCommandInterpreter.cs +++ b/src/YesSql.Provider.MySql/MySqlCommandInterpreter.cs @@ -48,7 +48,7 @@ public override void Run(StringBuilder builder, IAlterColumnCommand command) if (command.Default != null) { - builder2.Append(" set default ").Append(_dialect.GetSqlValue(command.Default)).Append(" "); + builder2.Append(" set default ").Append(_dialect.GetSqlValue(command.Default)).Append(' '); } // result diff --git a/src/YesSql.Provider.MySql/MySqlDbProviderOptionsExtensions.cs b/src/YesSql.Provider.MySql/MySqlDbProviderOptionsExtensions.cs index 3c9ea99e..a14041d4 100644 --- a/src/YesSql.Provider.MySql/MySqlDbProviderOptionsExtensions.cs +++ b/src/YesSql.Provider.MySql/MySqlDbProviderOptionsExtensions.cs @@ -1,6 +1,6 @@ +using MySqlConnector; using System; using System.Data; -using MySqlConnector; namespace YesSql.Provider.MySql { @@ -20,10 +20,7 @@ public static IConfiguration UseMySql( IsolationLevel isolationLevel, string schema = null) { - if (configuration == null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); if (string.IsNullOrWhiteSpace(connectionString)) { diff --git a/src/YesSql.Provider.PostgreSql/PostgreSqlDbProviderOptionsExtensions.cs b/src/YesSql.Provider.PostgreSql/PostgreSqlDbProviderOptionsExtensions.cs index 3a9d62ff..25f48e8c 100644 --- a/src/YesSql.Provider.PostgreSql/PostgreSqlDbProviderOptionsExtensions.cs +++ b/src/YesSql.Provider.PostgreSql/PostgreSqlDbProviderOptionsExtensions.cs @@ -20,10 +20,7 @@ public static IConfiguration UsePostgreSql( IsolationLevel isolationLevel, string schema = null) { - if (configuration == null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); if (string.IsNullOrWhiteSpace(connectionString)) { diff --git a/src/YesSql.Provider.SqlServer/SqlServerDbProviderOptionsExtensions.cs b/src/YesSql.Provider.SqlServer/SqlServerDbProviderOptionsExtensions.cs index 12a4fd5f..04b714db 100644 --- a/src/YesSql.Provider.SqlServer/SqlServerDbProviderOptionsExtensions.cs +++ b/src/YesSql.Provider.SqlServer/SqlServerDbProviderOptionsExtensions.cs @@ -1,6 +1,6 @@ +using Microsoft.Data.SqlClient; using System; using System.Data; -using Microsoft.Data.SqlClient; namespace YesSql.Provider.SqlServer { @@ -20,10 +20,7 @@ public static IConfiguration UseSqlServer( IsolationLevel isolationLevel, string schema = null) { - if (configuration == null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); if (string.IsNullOrWhiteSpace(connectionString)) { diff --git a/src/YesSql.Provider.Sqlite/SqliteDbProviderOptionsExtensions.cs b/src/YesSql.Provider.Sqlite/SqliteDbProviderOptionsExtensions.cs index 43508951..dc9d7771 100644 --- a/src/YesSql.Provider.Sqlite/SqliteDbProviderOptionsExtensions.cs +++ b/src/YesSql.Provider.Sqlite/SqliteDbProviderOptionsExtensions.cs @@ -11,8 +11,8 @@ public static IConfiguration UseSqLite( string connectionString) { return UseSqLite( - configuration, - connectionString, + configuration, + connectionString, IsolationLevel.Serializable); } @@ -21,10 +21,7 @@ public static IConfiguration UseSqLite( string connectionString, IsolationLevel isolationLevel) { - if (configuration == null) - { - throw new ArgumentNullException(nameof(configuration)); - } + ArgumentNullException.ThrowIfNull(configuration); if (string.IsNullOrWhiteSpace(connectionString)) { diff --git a/test/YesSql.Tests/CoreTests.cs b/test/YesSql.Tests/CoreTests.cs index ff537ef6..6e097749 100644 --- a/test/YesSql.Tests/CoreTests.cs +++ b/test/YesSql.Tests/CoreTests.cs @@ -53,7 +53,7 @@ public async Task InitializeAsync() await _store.InitializeCollectionAsync("Col1"); _store.TypeNames[typeof(Person)] = "People"; - await CreateTablesAsync(_configuration); + await CoreTests.CreateTablesAsync(_configuration); } else { @@ -204,7 +204,7 @@ protected virtual Task OnCleanDatabaseAsync(SchemaBuilder builder, DbTransaction protected virtual Task OnClearTablesAsync(DbConnection connection) => Task.CompletedTask; - public async Task CreateTablesAsync(IConfiguration configuration) + public static async Task CreateTablesAsync(IConfiguration configuration) { await using var connection = configuration.ConnectionFactory.CreateConnection(); await connection.OpenAsync(); @@ -1346,11 +1346,11 @@ public async Task ShouldQueryInnerSelect() await using (var session = _store.CreateSession()) { - Assert.Equal(1, await session.Query().Where(x => x.Name.IsIn(y => y.SomeName, y => y.SomeName.StartsWith("B") || y.SomeName.StartsWith("C"))).CountAsync()); - Assert.Equal(2, await session.Query().Where(x => x.Name.IsIn(y => y.SomeName, y => y.SomeName.StartsWith("B") || y.SomeName.Contains("lo"))).CountAsync()); + Assert.Equal(1, await session.Query().Where(x => x.Name.IsIn(y => y.SomeName, y => y.SomeName.StartsWith('B') || y.SomeName.StartsWith('C'))).CountAsync()); + Assert.Equal(2, await session.Query().Where(x => x.Name.IsIn(y => y.SomeName, y => y.SomeName.StartsWith('B') || y.SomeName.Contains("lo"))).CountAsync()); - Assert.Equal(1, await session.Query().Where(x => x.Name.IsNotIn(y => y.SomeName, y => y.SomeName.StartsWith("B") || y.SomeName.StartsWith("C"))).CountAsync()); - Assert.Equal(0, await session.Query().Where(x => x.Name.IsNotIn(y => y.SomeName, y => y.SomeName.StartsWith("B") || y.SomeName.Contains("lo"))).CountAsync()); + Assert.Equal(1, await session.Query().Where(x => x.Name.IsNotIn(y => y.SomeName, y => y.SomeName.StartsWith('B') || y.SomeName.StartsWith('C'))).CountAsync()); + Assert.Equal(0, await session.Query().Where(x => x.Name.IsNotIn(y => y.SomeName, y => y.SomeName.StartsWith('B') || y.SomeName.Contains("lo"))).CountAsync()); } } @@ -1498,7 +1498,7 @@ public async Task ShouldQueryWithLike() Assert.Equal(2, await session.Query().Where(x => x.Name.IsLike("%l%")).CountAsync()); Assert.Equal(1, await session.Query().Where(x => x.Name.IsNotLike("%B%")).CountAsync()); - Assert.Equal(2, await session.Query().Where(x => x.Name.Contains("l")).CountAsync()); + Assert.Equal(2, await session.Query().Where(x => x.Name.Contains('l')).CountAsync()); Assert.Equal(1, await session.Query().Where(x => x.Name.NotContains("B")).CountAsync()); } } @@ -1966,19 +1966,19 @@ public async Task ShouldOrderJoinedMapIndexes() await using (var session = _store.CreateSession()) { Assert.Equal(2, await session.Query().For() - .With(x => x.SomeName.StartsWith("S")) + .With(x => x.SomeName.StartsWith('S')) .With(x => x.Age == 2) .CountAsync()); Assert.Equal("Scott", (await session.Query().For() - .With(x => x.SomeName.StartsWith("S")) + .With(x => x.SomeName.StartsWith('S')) .OrderBy(x => x.SomeName) .With(x => x.Age == 2) .FirstOrDefaultAsync()) .Firstname); Assert.Equal("Steve", (await session.Query().For() - .With(x => x.SomeName.StartsWith("S")) + .With(x => x.SomeName.StartsWith('S')) .OrderByDescending(x => x.SomeName) .With(x => x.Age == 2) .FirstOrDefaultAsync()) @@ -2108,9 +2108,9 @@ public async Task JoinOrderShouldNotMatter() await using (var session = _store.CreateSession()) { Assert.Equal("Steve", (await session.Query().For() - .With(x => x.SomeName.StartsWith("S")) + .With(x => x.SomeName.StartsWith('S')) .With(x => x.Age == 2) - .With(x => x.SomeName.EndsWith("e")) + .With(x => x.SomeName.EndsWith('e')) .FirstOrDefaultAsync()).Firstname); } } @@ -2752,7 +2752,7 @@ public async Task AutoflushCanHappenMultipleTimes() } [Fact] - public async Task ChangesAfterAutoflushAreSaved() + public async Task ChangesAfterAutoFlushAreSaved() { _store.RegisterIndexes(); @@ -4180,9 +4180,9 @@ public async Task ShouldQueryInnerSelectWithCollection() Assert.Equal(1, await session.Query(x => x.Name == "Bill", "Col1").CountAsync()); Assert.Equal(1, await session.Query(x => x.Lastname == "Gates", "Col1").CountAsync()); - Assert.Equal(1, await session.Query(collection: "Col1").Where(x => x.Name.IsIn(y => y.Firstname, y => y.Lastname.StartsWith("G"))).CountAsync()); + Assert.Equal(1, await session.Query(collection: "Col1").Where(x => x.Name.IsIn(y => y.Firstname, y => y.Lastname.StartsWith('G'))).CountAsync()); - Assert.Equal(0, await session.Query(collection: "Col1").Where(x => x.Name.IsNotIn(y => y.Firstname, y => y.Lastname.StartsWith("G") || y.Lastname.StartsWith("M"))).CountAsync()); + Assert.Equal(0, await session.Query(collection: "Col1").Where(x => x.Name.IsNotIn(y => y.Firstname, y => y.Lastname.StartsWith('G') || y.Lastname.StartsWith('M'))).CountAsync()); Assert.Equal(2, await session.Query(collection: "Col1").Where(x => x.Name.IsInAny(y => y.Firstname)).CountAsync()); Assert.Equal(0, await session.Query(collection: "Col1").Where(x => x.Name.IsNotInAny(y => y.Firstname)).CountAsync()); @@ -6044,13 +6044,14 @@ public async Task AllDataTypesShouldBeQueryableWithProperties() await using (var session = _store.CreateSession()) { - var index = new TypesIndex(); - - index.ValueDateTime = valueDateTime; - index.ValueGuid = valueGuid; - index.ValueBool = valueBool; - index.ValueDateTimeOffset = valueDateTimeOffset; - index.ValueTimeSpan = valueTimeSpan; + var index = new TypesIndex + { + ValueDateTime = valueDateTime, + ValueGuid = valueGuid, + ValueBool = valueBool, + ValueDateTimeOffset = valueDateTimeOffset, + ValueTimeSpan = valueTimeSpan + }; ((IIndex)index).AddDocument(new Document { Id = dummy.Id }); @@ -6108,13 +6109,14 @@ public async Task AllDataTypesShouldBeQueryableWithConstants() await using (var session = _store.CreateSession()) { - var index = new TypesIndex(); - - index.ValueDateTime = valueDateTime; - index.ValueGuid = valueGuid; - index.ValueBool = valueBool; - index.ValueDateTimeOffset = valueDateTimeOffset; - index.ValueTimeSpan = valueTimeSpan; + var index = new TypesIndex + { + ValueDateTime = valueDateTime, + ValueGuid = valueGuid, + ValueBool = valueBool, + ValueDateTimeOffset = valueDateTimeOffset, + ValueTimeSpan = valueTimeSpan + }; ((IIndex)index).AddDocument(new Document { Id = dummy.Id }); diff --git a/test/YesSql.Tests/DecimalPrecisionAndScaleDataGenerator.cs b/test/YesSql.Tests/DecimalPrecisionAndScaleDataGenerator.cs index 435abfa8..0d8a541d 100644 --- a/test/YesSql.Tests/DecimalPrecisionAndScaleDataGenerator.cs +++ b/test/YesSql.Tests/DecimalPrecisionAndScaleDataGenerator.cs @@ -3,7 +3,7 @@ namespace YesSql.Tests { - internal class DecimalPrecisionAndScaleDataGenerator : TheoryData + internal sealed class DecimalPrecisionAndScaleDataGenerator : TheoryData { public DecimalPrecisionAndScaleDataGenerator() {