Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch implementation using pure PL/pgSQL #2923

Merged
merged 9 commits into from Jan 26, 2024
8 changes: 7 additions & 1 deletion build/build.cs
Expand Up @@ -98,6 +98,12 @@ private static async Task Main(string[] args)
Target("test-linq", DependsOn("compile-linq-tests"), () =>
RunTests("LinqTests"));

Target("compile-patching-tests", DependsOn("clean"), () =>
Run("dotnet", $"build src/PatchingTests/PatchingTests.csproj --framework {_framework} --configuration {configuration}"));

Target("test-patching", DependsOn("compile-patching-tests"), () =>
RunTests("PatchingTests"));

Target("test-codegen", () =>
{
var projectPath = "src/CommandLineRunner";
Expand All @@ -118,7 +124,7 @@ private static async Task Main(string[] args)
Target("test-plv8", DependsOn("compile", "compile-plv8"), () =>
RunTests("Marten.PLv8.Testing"));

Target("test", DependsOn("test-base-lib", "test-core", "test-document-db", "test-event-sourcing", "test-cli", "test-linq", "test-codegen"));
Target("test", DependsOn("test-base-lib", "test-core", "test-document-db", "test-event-sourcing", "test-cli", "test-linq", "test-codegen", "test-patching"));

Target("test-extension-libs-without-plv8", DependsOn("test-noda-time", "test-aspnetcore"));

Expand Down
7 changes: 7 additions & 0 deletions src/Marten.sln
Expand Up @@ -93,6 +93,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Helpdesk.Api", "samples\Hel
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Helpdesk.Api.Tests", "samples\Helpdesk\Helpdesk.Api.Tests\Helpdesk.Api.Tests.csproj", "{B0629D41-CA4E-4123-BC98-79A04D708A3E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PatchingTests", "PatchingTests\PatchingTests.csproj", "{EE82EFC4-FBC1-4181-9AB8-671222B60C3F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -219,6 +221,10 @@ Global
{B0629D41-CA4E-4123-BC98-79A04D708A3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B0629D41-CA4E-4123-BC98-79A04D708A3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0629D41-CA4E-4123-BC98-79A04D708A3E}.Release|Any CPU.Build.0 = Release|Any CPU
{EE82EFC4-FBC1-4181-9AB8-671222B60C3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EE82EFC4-FBC1-4181-9AB8-671222B60C3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EE82EFC4-FBC1-4181-9AB8-671222B60C3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EE82EFC4-FBC1-4181-9AB8-671222B60C3F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -255,5 +261,6 @@ Global
{F3DADE49-9C89-4F74-BCCE-7DAFD35675E9} = {79961196-DB50-4AD3-B749-D231799BCF2E}
{5E18DEBD-C768-4636-B167-7DA2A4954F43} = {F3DADE49-9C89-4F74-BCCE-7DAFD35675E9}
{B0629D41-CA4E-4123-BC98-79A04D708A3E} = {F3DADE49-9C89-4F74-BCCE-7DAFD35675E9}
{EE82EFC4-FBC1-4181-9AB8-671222B60C3F} = {91D87D73-EC07-4067-8A64-26A2E4F6BC83}
EndGlobalSection
EndGlobal
149 changes: 149 additions & 0 deletions src/Marten/Patching/IPatchExpression.cs
@@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;

#nullable enable
namespace Marten.Patching;

public interface IPatchExpression<T>
{
/// <summary>
/// Set a single field or property value within the persisted JSON data
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="name"></param>
/// <param name="value"></param>
void Set<TValue>(string name, TValue value);

/// <summary>
/// Set a single field or property value within the persisted JSON data
/// </summary>
/// <typeparam name="TParent"></typeparam>
/// <typeparam name="TValue"></typeparam>
/// <param name="name"></param>
/// <param name="expression">Path to the parent location</param>
/// <param name="value"></param>
void Set<TParent, TValue>(string name, Expression<Func<T, TParent>> expression, TValue value);

/// <summary>
/// Set a single field or property value within the persisted JSON data
/// </summary>
/// <typeparam name="TValue"></typeparam>
/// <param name="expression"></param>
/// <param name="value"></param>
void Set<TValue>(Expression<Func<T, TValue>> expression, TValue value);

/// <summary>
/// Copy a single field or property value within the persisted JSON data to one or more destinations
/// </summary>
/// <typeparam name="TElement"></typeparam>
/// <param name="expression"></param>
/// <param name="destinations"></param>
void Duplicate<TElement>(Expression<Func<T, TElement>> expression, params Expression<Func<T, TElement>>[] destinations);

/// <summary>
/// Increment a single field or property by adding the increment value
/// to the persisted value
/// </summary>
/// <param name="expression"></param>
/// <param name="increment"></param>
void Increment(Expression<Func<T, int>> expression, int increment = 1);

/// <summary>
/// Increment a single field or property by adding the increment value
/// to the persisted value
/// </summary>
/// <param name="expression"></param>
/// <param name="increment"></param>
void Increment(Expression<Func<T, long>> expression, long increment = 1);

/// <summary>
/// Increment a single field or property by adding the increment value
/// to the persisted value
/// </summary>
/// <param name="expression"></param>
/// <param name="increment"></param>
void Increment(Expression<Func<T, double>> expression, double increment = 1);

/// <summary>
/// Increment a single field or property by adding the increment value
/// to the persisted value
/// </summary>
/// <param name="expression"></param>
/// <param name="increment"></param>
void Increment(Expression<Func<T, float>> expression, float increment = 1);

/// <summary>
/// Append an element to the end of a child collection on the persisted
/// document
/// </summary>
/// <typeparam name="TElement"></typeparam>
/// <param name="expression"></param>
/// <param name="element"></param>
void Append<TElement>(Expression<Func<T, IEnumerable<TElement>>> expression, TElement element);

/// <summary>
/// Append an element to the end of a child collection on the persisted
/// document if the element does not already exist
/// </summary>
/// <typeparam name="TElement"></typeparam>
/// <param name="expression"></param>
/// <param name="element"></param>
void AppendIfNotExists<TElement>(Expression<Func<T, IEnumerable<TElement>>> expression, TElement element);

/// <summary>
/// Insert an element at the designated index to a child collection on the persisted document
/// </summary>
/// <typeparam name="TElement"></typeparam>
/// <param name="expression"></param>
/// <param name="element"></param>
/// <param name="index"></param>
void Insert<TElement>(Expression<Func<T, IEnumerable<TElement>>> expression, TElement element, int? index = null);

/// <summary>
/// Insert an element at the designated index to a child collection on the persisted document
/// if the value does not already exist at that index
/// </summary>
/// <typeparam name="TElement"></typeparam>
/// <param name="expression"></param>
/// <param name="element"></param>
/// <param name="index"></param>
void InsertIfNotExists<TElement>(Expression<Func<T, IEnumerable<TElement>>> expression, TElement element, int? index = null);

/// <summary>
/// Remove element from a child collection on the persisted document
/// </summary>
/// <typeparam name="TElement"></typeparam>
/// <param name="expression"></param>
/// <param name="element"></param>
/// <param name="action"></param>
void Remove<TElement>(Expression<Func<T, IEnumerable<TElement>>> expression, TElement element, RemoveAction action = RemoveAction.RemoveFirst);

/// <summary>
/// Rename a property or field in the persisted JSON document
/// </summary>
/// <param name="oldName"></param>
/// <param name="expression"></param>
void Rename(string oldName, Expression<Func<T, object>> expression);

/// <summary>
/// Delete a removed property or field in the persisted JSON data
/// </summary>
/// <param name="name">Redundant property or field name</param>
void Delete(string name);

/// <summary>
/// Delete a removed property or field in the persisted JSON data
/// </summary>
/// <typeparam name="TParent"></typeparam>
/// <param name="name">Redundant property or field name</param>
/// <param name="expression">Path to the parent location</param>
void Delete<TParent>(string name, Expression<Func<T, TParent>> expression);

/// <summary>
/// Delete an existing property or field in the persisted JSON data
/// </summary>
/// <typeparam name="TElement"></typeparam>
/// <param name="expression">Path to the property or field to delete</param>
void Delete<TElement>(Expression<Func<T, TElement>> expression);
}