Skip to content

Commit

Permalink
Moved annotations and linq expressions projects to the utilities solu…
Browse files Browse the repository at this point in the history
…tion. (#45)
  • Loading branch information
mgernand authored Apr 18, 2024
1 parent 0d65654 commit 9ca3562
Show file tree
Hide file tree
Showing 58 changed files with 2,818 additions and 5 deletions.
28 changes: 28 additions & 0 deletions Fluxera.Utilities.sln
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fluxera.Utilities", "src\Fl
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fluxera.Utilities.UnitTests", "tests\Fluxera.Utilities.UnitTests\Fluxera.Utilities.UnitTests.csproj", "{8FF21466-9BAF-4C83-B451-3050BE0F18FA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fluxera.ComponentModel.Annotations", "src\Fluxera.ComponentModel.Annotations\Fluxera.ComponentModel.Annotations.csproj", "{F319E595-6EEA-4DBE-9387-CA9A0E42363A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fluxera.Linq.Expressions", "src\Fluxera.Linq.Expressions\Fluxera.Linq.Expressions.csproj", "{4959E267-54F8-4911-8C66-4AB2BC0FAD06}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fluxera.ComponentModel.Annotations.UnitTests", "tests\Fluxera.ComponentModel.Annotations.UnitTests\Fluxera.ComponentModel.Annotations.UnitTests.csproj", "{807DEF3A-08DA-4B16-868D-9BFDB757CEFD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fluxera.Linq.Expressions.UnitTests", "tests\Fluxera.Linq.Expressions.UnitTests\Fluxera.Linq.Expressions.UnitTests.csproj", "{DB1D33D9-A4CC-4ADC-ADA8-D40394DC1EDA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -42,13 +50,33 @@ Global
{8FF21466-9BAF-4C83-B451-3050BE0F18FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8FF21466-9BAF-4C83-B451-3050BE0F18FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8FF21466-9BAF-4C83-B451-3050BE0F18FA}.Release|Any CPU.Build.0 = Release|Any CPU
{F319E595-6EEA-4DBE-9387-CA9A0E42363A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F319E595-6EEA-4DBE-9387-CA9A0E42363A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F319E595-6EEA-4DBE-9387-CA9A0E42363A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F319E595-6EEA-4DBE-9387-CA9A0E42363A}.Release|Any CPU.Build.0 = Release|Any CPU
{4959E267-54F8-4911-8C66-4AB2BC0FAD06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4959E267-54F8-4911-8C66-4AB2BC0FAD06}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4959E267-54F8-4911-8C66-4AB2BC0FAD06}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4959E267-54F8-4911-8C66-4AB2BC0FAD06}.Release|Any CPU.Build.0 = Release|Any CPU
{807DEF3A-08DA-4B16-868D-9BFDB757CEFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{807DEF3A-08DA-4B16-868D-9BFDB757CEFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{807DEF3A-08DA-4B16-868D-9BFDB757CEFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{807DEF3A-08DA-4B16-868D-9BFDB757CEFD}.Release|Any CPU.Build.0 = Release|Any CPU
{DB1D33D9-A4CC-4ADC-ADA8-D40394DC1EDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DB1D33D9-A4CC-4ADC-ADA8-D40394DC1EDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DB1D33D9-A4CC-4ADC-ADA8-D40394DC1EDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DB1D33D9-A4CC-4ADC-ADA8-D40394DC1EDA}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{28FBC6F0-459F-4DB0-9D91-B981A30257E3} = {DF28D730-99B3-4811-AAC7-725A73B3F668}
{8FF21466-9BAF-4C83-B451-3050BE0F18FA} = {F18D2D58-282C-4D93-8D9A-3A76CF98F018}
{F319E595-6EEA-4DBE-9387-CA9A0E42363A} = {DF28D730-99B3-4811-AAC7-725A73B3F668}
{4959E267-54F8-4911-8C66-4AB2BC0FAD06} = {DF28D730-99B3-4811-AAC7-725A73B3F668}
{807DEF3A-08DA-4B16-868D-9BFDB757CEFD} = {F18D2D58-282C-4D93-8D9A-3A76CF98F018}
{DB1D33D9-A4CC-4ADC-ADA8-D40394DC1EDA} = {F18D2D58-282C-4D93-8D9A-3A76CF98F018}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D97BF2AF-6E68-4E88-BF70-773A86E26013}
Expand Down
155 changes: 154 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![Build Status](https://dev.azure.com/fluxera/Foundation/_apis/build/status/GitHub/fluxera.Fluxera.Utilities?branchName=main&stageName=BuildAndTest)](https://dev.azure.com/fluxera/Foundation/_build/latest?definitionId=76&branchName=main)

# Utilities
# Fluxera.Utilities

A collection of common utilities and extension methods.

Expand Down Expand Up @@ -248,3 +248,156 @@ The numeric extensions methods are available for the following primitives: ```by
- **```IsDefault```** Determines if a value is empty (```default(T)```).
- **```IsNullable```** Determines if a type is a nullable.
- **```ToNullable```** onverts a value to a corresponding nullable type.


# Fluxera.ComponentModel.Annotations
A collection of custom data annotations.

## Available Attributes

### Datastore related attributes

- **```[CompositeIndex]```**
- An attribute to provide the composite indices of an entity.
- Targets classes.
- Allows multiple.
- **```[DateOnly]```**
- A marker attribute to signal potential data stores to only store the date.
- Targets properties and fields.
- Denys multiple.
- **```[DatePrecision]```**
- An attribute to provide the date precision to potential data stores.
- Targets properties and fields.
- Denys multiple.
- **```[Ignore]```**
- A marker attribute to signal potential data stores to ignore this value.
- Targets properties and fields.
- Denys multiple.
- **```[Index]```**
- An attribute to provide an index of the entity.
- Targets properties and fields.
- Denys multiple.
- **```[Reference]```**
- An attribute to signal potential data stores that this property should be stored as database reference.
- Targets properties and fields.
- Denys multiple.

## Validation attributes

- **```[Contains]```**
- A validation that checks if the annotated property contains the given check value.
- Targets properties and fields.
- Denys multiple.
- **```[EndsWith]```**
- A validation attribute that checks if the value end with the given value.
- Targets properties and fields.
- Denys multiple.
- **```[EnforceTrue]```**
- A validation attribute that checks if the value is ```true```.
- Targets properties and fields.
- Denys multiple.
- **```[ListLength]```**
- A validation attribute to check the length of a list.
- Targets properties and fields.
- Denys multiple.
- **```[ListMaxLength]```**
- A validation attribute to check the maximum length of a list.
- Targets properties and fields.
- Denys multiple.
- **```[ListMinLength]```**
- A validation attribute to check the minimum length of a list.
- Targets properties and fields.
- Denys multiple.
- **```[NotEmpty]```**
- A validation attribute to check if an enumerable contains at least one element.
- Targets properties and fields.
- Denys multiple.
- **```[RequiredIf]```**
- A validation attribute that checks if the value is required when a condition is met.
- Targets properties and fields.
- Denys multiple.
- **```[StartsWith]```**
- A validation attribute that checks if the value starts with the given value.
- Targets properties and fields.
- Denys multiple.

## Datatype attributes

- **```[Currency]```**
- A data-type attribute for currency values.
- Targets properties, fields and parameters.
- Denys multiple.
- **```[Date]```**
- A data-type attribute for date values.
- Targets properties, fields and parameters.
- Denys multiple.
- **```[DateTime]```**
- A data-type attribute for date-time values.
- Targets properties, fields and parameters.
- Denys multiple.
- **```[Duration]```**
- A data-type attribute for duration (timespan) values.
- Targets properties, fields and parameters.
- Denys multiple.
- **```[ImageUrl]```**
- A data-type attribute for image-url values.
- Targets properties, fields and parameters.
- Denys multiple.
- **```[MultilineText]```**
- A data-type attribute for multiline text values.
- Targets properties, fields and parameters.
- Denys multiple.
- **```[Password]```**
- A data-type attribute for password values.
- Targets properties, fields and parameters.
- Denys multiple.
- **```[PostalCode]```**
- A data-type attribute for postal code values.
- Targets properties, fields and parameters.
- Denys multiple.
- **```[Select]```**
- A data-type attribute to signal that the values comes from a selection of values.
- Targets properties, fields and parameters.
- Denys multiple.
- **```[Text]```**
- A data-type attribute for text values.
- Targets properties, fields and parameters.
- Denys multiple.
- **```[Time]```**
- A data-type attribute for time values.
- Targets properties, fields and parameters.
- Denys multiple.
- **```[Upload]```**
- A data-type attribute for upload values.
- Targets properties, fields and parameters.
- Denys multiple.


# Fluxera.Linq.Expressions

A collection of LINQ expression utilities and extension methods.

## Usage

The extenions methods use several utility classes that are publicly available through
this library to be used forother use-cases:

- **```Evaluator```** Enables the partial evaluation of queries.
- **```LocalCollectionExpander```** Expands local collection values.
- **```ParameterRebinder```** Used for rebinding of parameters.

The utility classes are used to evaludate as much as possible to create a string representation of an ```Expression```.
The result of the extension can f.e. be used to create cache keys for expression-based data queries.

```c#
Expression<Func<Person, string>> expression = x => x.Name;
string? str = expression.ToExpressionString();
```

The other extension methods can be used to compose given expressions.

- **```And```** Creates an ```Expression``` that represents an bitwise AND operation.
- **```AndAlso```** Creates an ```Expression``` that represents a conditional AND operation that evaluates the second operand only if it has to.
- **```Or```** Creates an ```Expression``` that represents an bitwise OR operation.
- **```OrElse```** Creates an ```Expression``` that represents a conditional OR operation that evaluates the second operand only if it has to.

4 changes: 2 additions & 2 deletions src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

<PropertyGroup>
<Authors>Matthias Gernand</Authors>
<RepositoryUrl>https://github.com/fluxera/Fluxera.Guard</RepositoryUrl>
<PackageProjectUrl>https://github.com/fluxera/Fluxera.Guard</PackageProjectUrl>
<RepositoryUrl>https://github.com/fluxera/Fluxera.Utilities</RepositoryUrl>
<PackageProjectUrl>https://github.com/fluxera/Fluxera.Utilities</PackageProjectUrl>
<PackageIcon>icon.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
Expand Down
40 changes: 40 additions & 0 deletions src/Fluxera.ComponentModel.Annotations/CompositeIndexAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
namespace Fluxera.ComponentModel.Annotations
{
using System;
using JetBrains.Annotations;

/// <summary>
/// An attribute to provide the composite indices of an entity. <br />
/// To create the actual indices consult the underlying stores documentation.
/// </summary>
/// <seealso cref="Attribute" />
[PublicAPI]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public sealed class CompositeIndexAttribute : Attribute
{
/// <summary>
/// Creates a new instance of the <see cref="CompositeIndexAttribute" /> type.
/// </summary>
/// <param name="propertyNames"></param>
public CompositeIndexAttribute(params string[] propertyNames)
{
this.PropertyNames = propertyNames;
this.IsUnique = false;
}

/// <summary>
/// Gets the property names for the index.
/// </summary>
public string[] PropertyNames { get; }

/// <summary>
/// Flag, indicating if the index is unique.
/// </summary>
public bool IsUnique { get; set; }

/// <summary>
/// Gets the ordering for the index.
/// </summary>
public IndexOrder Order { get; set; } = IndexOrder.Ascending;
}
}
44 changes: 44 additions & 0 deletions src/Fluxera.ComponentModel.Annotations/ContainsAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
namespace Fluxera.ComponentModel.Annotations
{
using System;
using System.ComponentModel.DataAnnotations;
using Fluxera.Guards;
using JetBrains.Annotations;

/// <summary>
/// A validation that checks if the annotated property contains the given check value.
/// </summary>
[PublicAPI]
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public sealed class ContainsAttribute : ValidationAttribute
{
/// <summary>
/// Creates a new instance of the <see cref="ContainsAttribute" /> type.
/// </summary>
/// <param name="part"></param>
public ContainsAttribute(string part)
{
Guard.Against.NullOrEmpty(part, nameof(part));

this.Part = part;
}

/// <summary>
/// Gets the string that should be contained in the property value.
/// </summary>
public string Part { get; }


/// <inheritdoc />
public override bool IsValid(object value)
{
if(value is string stringValue)
{
bool contains = !string.IsNullOrWhiteSpace(stringValue) && stringValue.Contains(this.Part);
return contains;
}

throw new InvalidOperationException("The attribute can only be used with string properties.");
}
}
}
19 changes: 19 additions & 0 deletions src/Fluxera.ComponentModel.Annotations/CurrencyAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// ReSharper disable once CheckNamespace

namespace System.ComponentModel.DataAnnotations
{
using JetBrains.Annotations;

/// <summary>
/// A data-type attribute for currency values.
/// </summary>
[PublicAPI]
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
public sealed class CurrencyAttribute : DataTypeAttribute
{
/// <inheritdoc />
public CurrencyAttribute() : base(DataType.Currency)
{
}
}
}
19 changes: 19 additions & 0 deletions src/Fluxera.ComponentModel.Annotations/DateAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// ReSharper disable once CheckNamespace

namespace System.ComponentModel.DataAnnotations
{
using JetBrains.Annotations;

/// <summary>
/// A data-type attribute for date values.
/// </summary>
[PublicAPI]
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)]
public sealed class DateAttribute : DataTypeAttribute
{
/// <inheritdoc />
public DateAttribute() : base(DataType.Date)
{
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
namespace Fluxera.ComponentModel.Annotations{ using System; using JetBrains.Annotations; /// <summary> /// A marker attribute to signal potential data stores to only store the date. /// </summary> [PublicAPI] [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] public sealed class DateOnlyAttribute : Attribute { }}
Expand Down
27 changes: 27 additions & 0 deletions src/Fluxera.ComponentModel.Annotations/DatePrecisionAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Fluxera.ComponentModel.Annotations
{
using System;
using JetBrains.Annotations;

/// <summary>
/// An attribute to provide the date precision to potential data stores.
/// </summary>
[PublicAPI]
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public sealed class DatePrecisionAttribute : Attribute
{
/// <summary>
/// Creates a new instance of the <see cref="DatePrecisionAttribute" /> type.
/// </summary>
/// <param name="precision"></param>
public DatePrecisionAttribute(byte precision)
{
this.Precision = precision;
}

/// <summary>
/// Gets the precision.
/// </summary>
public byte Precision { get; }
}
}
Loading

0 comments on commit 9ca3562

Please sign in to comment.