Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
olmobrutall committed Jun 5, 2020
2 parents 240377d + b8280ae commit b8713c3
Show file tree
Hide file tree
Showing 57 changed files with 958 additions and 619 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ Signum Framework doesn't use any numeric versioning, since is distributed as sou

Whenever there are big changes worth to mention, we typicaly write it in the related commit. Here is the list of the relevant changes:


* [2020.05.22 From react-rte to draft-js-plugins](https://github.com/signumsoftware/framework/commit/0f01c7a7d6a24ff8bab1046f136de36de4a93b4a#commitcomment-39362952)
* [2020.05.17 Update to Typescript 3.9.... Is MUCH faster!!!!](https://github.com/signumsoftware/framework/commit/da3afe553537ed18d5e5cb0df32b00f70052223f#comments)
* [2020.05.16 Pivot Table Chart](https://github.com/signumsoftware/framework/commit/91330aad5405df50cd7cc8fc42de36bbfc759b70#comments)
* [2020.05.14 Slimming Signum.React](https://github.com/signumsoftware/framework/commit/31c91dad34f251f0c728cad426d5f5db9e496261#comments)
* [2020.02.27 Updates package.json](https://github.com/signumsoftware/framework/commit/08f78128326fad5eaf80f184d67f76863f5aa8a9#comments)
Expand Down
14 changes: 14 additions & 0 deletions Signum.Engine/Basics/QueryLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,20 @@ public static object ToQueryName(this QueryEntity query)
return QueryNames.GetOrThrow(query.Key, "QueryName with key {0} not found");
}

public static object? ToQueryNameCatch(this QueryEntity query)
{
try
{
return query.ToQueryName();
}
catch (KeyNotFoundException ex) when (StartParameters.IgnoredCodeErrors != null)
{
StartParameters.IgnoredCodeErrors.Add(ex);

return null;
}
}

public static object ToQueryName(string queryKey)
{
return QueryNames.GetOrThrow(queryKey, "QueryName with unique name {0} not found");
Expand Down
2 changes: 1 addition & 1 deletion Signum.Engine/DynamicQuery/ColumnDescriptionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class ColumnDescriptionFactory
{
readonly internal Meta? Meta;
public Func<string>? OverrideDisplayName { get; set; }
public Func<string>? OverrideIsAllowed { get; set; }
public Func<string?>? OverrideIsAllowed { get; set; }

public string Name { get; internal set; }
public Type Type { get; internal set; }
Expand Down
344 changes: 172 additions & 172 deletions Signum.Engine/Engine/Saver.cs
Original file line number Diff line number Diff line change
@@ -1,173 +1,173 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Signum.Utilities;
using Signum.Entities;
using Signum.Utilities.DataStructures;
using Signum.Entities.Reflection;
using Signum.Engine.Maps;

namespace Signum.Engine
{
internal static class Saver
{
public static void Save(Entity entity)
{
Save(new[] { entity });
}

static readonly Entity[] None = new Entity[0];

public static void Save(Entity[] entities)
{
if (entities == null || entities.Any(e => e == null))
throw new ArgumentNullException("entity");

using (var log = HeavyProfiler.LogNoStackTrace("PreSaving"))
{
Schema schema = Schema.Current;
DirectedGraph<Modifiable> modifiables = PreSaving(() => GraphExplorer.FromRoots(entities));

HashSet<Entity> wasNew = modifiables.OfType<Entity>().Where(a => a.IsNew).ToHashSet(ReferenceEqualityComparer<Entity>.Default);
HashSet<Entity> wasSelfModified = modifiables.OfType<Entity>().Where(a => a.Modified == ModifiedState.SelfModified).ToHashSet(ReferenceEqualityComparer<Entity>.Default);

log.Switch("Integrity");

var error = GraphExplorer.FullIntegrityCheck(modifiables);
if (error != null)
{
using System;
using System.Collections.Generic;
using System.Linq;
using Signum.Utilities;
using Signum.Entities;
using Signum.Utilities.DataStructures;
using Signum.Entities.Reflection;
using Signum.Engine.Maps;

namespace Signum.Engine
{
internal static class Saver
{
public static void Save(Entity entity)
{
Save(new[] { entity });
}

static readonly Entity[] None = new Entity[0];

public static void Save(Entity[] entities)
{
if (entities == null || entities.Any(e => e == null))
throw new ArgumentNullException("entity");

using (var log = HeavyProfiler.LogNoStackTrace("PreSaving"))
{
Schema schema = Schema.Current;
DirectedGraph<Modifiable> modifiables = PreSaving(() => GraphExplorer.FromRoots(entities));

HashSet<Entity> wasNew = modifiables.OfType<Entity>().Where(a => a.IsNew).ToHashSet(ReferenceEqualityComparer<Entity>.Default);
HashSet<Entity> wasSelfModified = modifiables.OfType<Entity>().Where(a => a.Modified == ModifiedState.SelfModified).ToHashSet(ReferenceEqualityComparer<Entity>.Default);

log.Switch("Integrity");

var error = GraphExplorer.FullIntegrityCheck(modifiables);
if (error != null)
{
#if DEBUG
var withEntities = error.WithEntities(modifiables);
throw new IntegrityCheckException(withEntities);
#else
throw new IntegrityCheckException(error);
#endif
}

log.Switch("Graph");

GraphExplorer.PropagateModifications(modifiables.Inverse());

//colapsa modifiables (collections and embeddeds) keeping indentifiables only
DirectedGraph<Entity> identifiables = GraphExplorer.ColapseIdentifiables(modifiables);

foreach (var node in identifiables)
schema.OnSaving(node);

//Remove all the edges that doesn't mean a dependency
identifiables.RemoveEdges(identifiables.Edges.Where(e => !e.To.IsNew).ToList());

//Remove all the nodes that are not modified
List<Entity> notModified = identifiables.Where(node => !node.IsGraphModified).ToList();

notModified.ForEach(node => identifiables.RemoveFullNode(node, None));

log.Switch("SaveGroups");

SaveGraph(schema, identifiables);

foreach (var node in identifiables)
schema.OnSaved(node, new SavedEventArgs
{
IsRoot = entities.Contains(node),
WasNew = wasNew.Contains(node),
WasSelfModified = wasSelfModified.Contains(node),
});

EntityCache.Add(identifiables);
EntityCache.Add(notModified);

GraphExplorer.CleanModifications(modifiables);
}
}

private static void SaveGraph(Schema schema, DirectedGraph<Entity> identifiables)
{
//takes apart the 'forbidden' connections from the good ones
DirectedGraph<Entity>? backEdges = identifiables.FeedbackEdgeSet();

if (backEdges.IsEmpty())
backEdges = null;
else
identifiables.RemoveEdges(backEdges.Edges);

Dictionary<TypeNew, int> stats = identifiables.GroupCount(ident => new TypeNew(ident.GetType(), ident.IsNew));

DirectedGraph<Entity> clone = identifiables.Clone();
DirectedGraph<Entity> inv = identifiables.Inverse();

while (clone.Count > 0)
{
IGrouping<TypeNew, Entity> group = clone.Sinks()
.GroupBy(ident => new TypeNew(ident.GetType(), ident.IsNew))
.WithMin(g => stats[g.Key] - g.Count());

foreach (var node in group)
clone.RemoveFullNode(node, inv.RelatedTo(node));

stats[group.Key] -= group.Count();

SaveGroup(schema, group, backEdges);
}

if (backEdges != null)
{
foreach (var gr in backEdges.Edges.Select(e => e.From).Distinct().GroupBy(ident => new TypeNew(ident.GetType(), ident.IsNew)))
SaveGroup(schema, gr, null);
}
}

private static void SaveGroup(Schema schema, IGrouping<TypeNew, Entity> group, DirectedGraph<Entity>? backEdges)
{
Table table = schema.Table(group.Key.Type);

if (group.Key.IsNew)
table.InsertMany(group.ToList(), backEdges);
else
table.UpdateMany(group.ToList(), backEdges);
}

struct TypeNew : IEquatable<TypeNew>
{
public readonly Type Type;
public readonly bool IsNew;

public TypeNew(Type type, bool isNew)
{
this.Type = type;
this.IsNew = isNew;
}

public bool Equals(TypeNew other)
{
return Type == other.Type &&
IsNew == other.IsNew;
}

public override int GetHashCode()
{
return Type.GetHashCode() ^ (IsNew ? 1 : 0);
}

public override string ToString()
{
return $"{Type} IsNew={IsNew}";
}
}

internal static DirectedGraph<Modifiable> PreSaving(Func<DirectedGraph<Modifiable>> recreate)
{
Schema schema = Schema.Current;
return GraphExplorer.PreSaving(recreate, (Modifiable m, PreSavingContext ctx) =>
{
if (m is ModifiableEntity me)
me.SetTemporalErrors(null);

m.PreSaving(ctx);

if (m is Entity ident)
schema.OnPreSaving(ident, ctx);
});
}
}
}
var withEntities = error.WithEntities(modifiables);
throw new IntegrityCheckException(withEntities);
#else
throw new IntegrityCheckException(error);
#endif
}

log.Switch("Graph");

GraphExplorer.PropagateModifications(modifiables.Inverse());

//colapsa modifiables (collections and embeddeds) keeping indentifiables only
DirectedGraph<Entity> identifiables = GraphExplorer.ColapseIdentifiables(modifiables);

foreach (var node in identifiables)
schema.OnSaving(node);

//Remove all the edges that doesn't mean a dependency
identifiables.RemoveEdges(identifiables.Edges.Where(e => !e.To.IsNew).ToList());

//Remove all the nodes that are not modified
List<Entity> notModified = identifiables.Where(node => !node.IsGraphModified).ToList();

notModified.ForEach(node => identifiables.RemoveFullNode(node, None));

log.Switch("SaveGroups");

SaveGraph(schema, identifiables);

foreach (var node in identifiables)
schema.OnSaved(node, new SavedEventArgs
{
IsRoot = entities.Contains(node),
WasNew = wasNew.Contains(node),
WasSelfModified = wasSelfModified.Contains(node),
});

EntityCache.Add(identifiables);
EntityCache.Add(notModified);

GraphExplorer.CleanModifications(modifiables);
}
}

private static void SaveGraph(Schema schema, DirectedGraph<Entity> identifiables)
{
//takes apart the 'forbidden' connections from the good ones
DirectedGraph<Entity>? backEdges = identifiables.FeedbackEdgeSet();

if (backEdges.IsEmpty())
backEdges = null;
else
identifiables.RemoveEdges(backEdges.Edges);

Dictionary<TypeNew, int> stats = identifiables.GroupCount(ident => new TypeNew(ident.GetType(), ident.IsNew));

DirectedGraph<Entity> clone = identifiables.Clone();
DirectedGraph<Entity> inv = identifiables.Inverse();

while (clone.Count > 0)
{
IGrouping<TypeNew, Entity> group = clone.Sinks()
.GroupBy(ident => new TypeNew(ident.GetType(), ident.IsNew))
.WithMin(g => stats[g.Key] - g.Count());

foreach (var node in group)
clone.RemoveFullNode(node, inv.RelatedTo(node));

stats[group.Key] -= group.Count();

SaveGroup(schema, group, backEdges);
}

if (backEdges != null)
{
foreach (var gr in backEdges.Edges.Select(e => e.From).Distinct().GroupBy(ident => new TypeNew(ident.GetType(), ident.IsNew)))
SaveGroup(schema, gr, null);
}
}

private static void SaveGroup(Schema schema, IGrouping<TypeNew, Entity> group, DirectedGraph<Entity>? backEdges)
{
Table table = schema.Table(group.Key.Type);

if (group.Key.IsNew)
table.InsertMany(group.ToList(), backEdges);
else
table.UpdateMany(group.ToList(), backEdges);
}

struct TypeNew : IEquatable<TypeNew>
{
public readonly Type Type;
public readonly bool IsNew;

public TypeNew(Type type, bool isNew)
{
this.Type = type;
this.IsNew = isNew;
}

public bool Equals(TypeNew other)
{
return Type == other.Type &&
IsNew == other.IsNew;
}

public override int GetHashCode()
{
return Type.GetHashCode() ^ (IsNew ? 1 : 0);
}

public override string ToString()
{
return $"{Type} IsNew={IsNew}";
}
}

internal static DirectedGraph<Modifiable> PreSaving(Func<DirectedGraph<Modifiable>> recreate)
{
Schema schema = Schema.Current;
return GraphExplorer.PreSaving(recreate, (Modifiable m, PreSavingContext ctx) =>
{
if (m is ModifiableEntity me)
me.SetTemporalErrors(null);

m.PreSaving(ctx);

if (m is Entity ident)
schema.OnPreSaving(ident, ctx);
});
}
}
}
Loading

0 comments on commit b8713c3

Please sign in to comment.