LabelKit.EFCore.Pomelo.MySql 3.0.0

dotnet add package LabelKit.EFCore.Pomelo.MySql --version 3.0.0
NuGet\Install-Package LabelKit.EFCore.Pomelo.MySql -Version 3.0.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="LabelKit.EFCore.Pomelo.MySql" Version="3.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add LabelKit.EFCore.Pomelo.MySql --version 3.0.0
#r "nuget: LabelKit.EFCore.Pomelo.MySql, 3.0.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install LabelKit.EFCore.Pomelo.MySql as a Cake Addin
#addin nuget:?package=LabelKit.EFCore.Pomelo.MySql&version=3.0.0

// Install LabelKit.EFCore.Pomelo.MySql as a Cake Tool
#tool nuget:?package=LabelKit.EFCore.Pomelo.MySql&version=3.0.0

LabelKit

LabelKit is a .NET toolkit for parsing kubernetes-like label-selectors and using them to build filters, including query-expressions for EFCore (PostgreSQL, MySql, SqlServer, Sqlite). Labels are name/value pairs that can be represented as dictionaries (name->value) or simple string collections (name+delimiter+value).

Packages

The majority of packages support netstandard2.0.

The following NuGet packages are provided:

Examples

EFCore PostgreSQL:

public class Entity
{
  // Stored as JSONB
  public Dictionary<string, string> Labels { get; set; }
}

dotnet add package LabelKit.Parser

LabelKit.Parser offers a default parser built with Pidgin.

The parser is able to parse raw label-selectors adhering to the kubernetes syntax.

using LabelKit;

var selector = LabelSelectorParser.Parse(
  "label1 = value, label2 = value, label3 in (value1, value2)");

dotnet add package LabelKit.EFCore.PostgreSQL

var expressionBuilder = NpgsqlLabelSelectorExpressionBuilders.Jsonb<Dictionary<string, string>>();

var entities = await dbContext.Set<Entity>()
  .MatchLabels(e => e.Labels, selector, expressionBuilder)
  .ToListAsync();

Executed SQL:

-- @__json_1='{"label1":"value","label2":"value"}' (DbType = Object)
-- @__Format_2='{"label3":"value1"}' (DbType = Object)
-- @__Format_3='{"label3":"value2"}' (DbType = Object)
SELECT t."Id", t."Labels"
FROM "TestEntity" AS t
WHERE t."Labels" @> @__json_1 AND (t."Labels" @> @__Format_2 OR t."Labels" @> @__Format_3)

Label-Selectors

Label-selectors can be easily created and extended...

var selector = LabelSelector.New()
  .Match("label1").Exact("value")
  .Match("label2").Not("value")
  .Match("label3").In("value1", "value2")
  .Match("label4").NotIn("value1", "value2")
  .Match("label5").Exists()
  .Match("label6").NotExists();

They can be merged...

var selector1 = LabelSelector.New()
  .Match("label1").Exact("value");

var selector2 = LabelSelector.New()
  .Match("label2").Exact("value");

// Contains a fully copy of all expressions
var merged = selector1.Merge(selector2);

// You can merge an arbitrary number of selectors

merged = LabelSelector.Merge(selector1, selector2, ...);

They can be rendered...

// label1 = value, label2 = value
merged.ToString();

Matching Labels Offline

You can also use label-selectors offline without any database interaction.

dotnet add package LabelKit

var selector = LabelSelector.New()
  .Match("label1").Exact("value")
  .Match("label2").Exact("value");

string[] labels = [ "label1:value", "label2:value" ];

// Default delimiter is ':'
// -> true
var doesMatch = selector.Matches(labels);

The same can be done with dictionary-like labels:

var selector = LabelSelector.New()
  .Match("label1").Exact("value")
  .Match("label2").Exact("value");

var labels = new Dictionary<string, string()
{
  ["label1"] = "value",
  ["label2"] = "value"
};

// -> true
var doesMatch = selector.Matches(labels);

[!TIP]

Any component implementing ILabelSelector (meaning it can provide a collection of selector-expressions) can be used to match offline.

Expressions (EFCore)

LabelKit supports infrastructure for building expression-trees that can be used to filter IQueryables. Components implementing ILabelSelectorExpressionBuilder are responsible for creating Expressions from label-selectors. Different expression-builders are needed for different scenarios.

Example: If your labels are stored as JSONB (PostgreSQL), the resulting SQL query has to be vastly different from if they were stored as an array. Therefore, you need a different expression.

Supported EFCore Providers

Provided Expression-Builders

  • NpgsqlJsonbLabelSelectorExpressionBuilder (NpgsqlLabelSelectorExpressionBuilders.Jsonb())
    • Builds expression specifically suited for PostgreSQL JSONB columns.
  • MySqlJsonLabelSelectorExpressionBuilder (MySqlLabelSelectorExpressionBuilders.Json())
    • Builds expression specifically suited for MySql JSON columns.
  • CollectionLabelSelectorExpressionBuilder (LabelSelectorExpressionBuilders.Collection())
    • Builds generic expression suitable for any collection of strings.
    • Supported by PostgreSQL, SqlServer, Sqlite (and MySql).
    • Available in package LabelKit.Expressions.

[!IMPORTANT]

CollectionLabelSelectorExpressionBuilder produces expressions that should be translatable to SQL by EFCore providers supporting primitive-collections. However, you should also be able to use those expressions offline (compiled).

Filter IQueryables

dotnet add package LabelKit.Expressions

using LabelKit;

var expressionBuilder = LabelSelectorExpressionBuilders.Collection<string[]>();

// e => e.Labels is an expression representing the labels to match.
// You can also mark your entity as ILabelledEntity to avoid having to specify this every time.
var entities = await dbContext.Set<Entity>()
  .MatchLabels(e => e.Labels,
    selector => selector
        .Match("label1").Exact("value")
        .Match("label2").Exact("value")
    , expressionBuilder)
  .ToListAsync();
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
3.0.0 84 5/5/2024
3.0.0-alpha.1003 57 4/30/2024