Skip to content
Permalink
Browse files

Add bulk operations for linked facts. Closes #185

  • Loading branch information...
snikolayev committed Apr 2, 2019
1 parent 655f5f5 commit e2adfbeb95a4caf5f1597c0d728cb5266006d1b4
Showing with 116 additions and 48 deletions.
  1. +23 −0 src/NRules/NRules.RuleModel/IContext.cs
  2. +36 −3 src/NRules/NRules/ActionContext.cs
  3. +57 −45 src/NRules/NRules/Session.cs
@@ -108,13 +108,26 @@ public interface IContext
/// <param name="fact">Fact to insert.</param>
void InsertLinked(object key, object fact);

/// <summary>
/// Inserts new facts and links them to the current rule activation.
/// The facts will be automatically retracted if this activation is removed.
/// </summary>
/// <param name="keyedFacts">Keyed facts to insert. Keys must be unique for a given rule.</param>
void InsertAllLinked(IEnumerable<KeyValuePair<object, object>> keyedFacts);

/// <summary>
/// Updates existing fact that's linked to the current rule activation.
/// </summary>
/// <param name="key">Key for the linked fact. Must be unique for a given rule.</param>
/// <param name="fact">Fact to update.</param>
void UpdateLinked(object key, object fact);

/// <summary>
/// Updates existing facts that are linked to the current rule activation.
/// </summary>
/// <param name="keyedFacts">Keyed facts to update. Keys must be unique for a given rule.</param>
void UpdateAllLinked(IEnumerable<KeyValuePair<object, object>> keyedFacts);

/// <summary>
/// Retracts existing fact that's linked to the current rule activation.
/// </summary>
@@ -126,6 +139,16 @@ public interface IContext
/// <param name="fact">Fact to retract.</param>
void RetractLinked(object key, object fact);

/// <summary>
/// Retracts existing facts that are linked to the current rule activation.
/// </summary>
/// <remarks>Linked facts are retracted automatically, when activation is deleted, but
/// this method can be used in complex scenarios, when linked facts need to be retracted explicitly,
/// prior to activation getting deleted.
/// </remarks>
/// <param name="keyedFacts">Keyed facts to retract. Keys must be unique for a given rule.</param>
void RetractAllLinked(IEnumerable<KeyValuePair<object, object>> keyedFacts);

/// <summary>
/// Resolves a registered service (normally via an IoC container).
/// </summary>
@@ -92,17 +92,50 @@ public object GetLinked(object key)

public void InsertLinked(object key, object fact)
{
_session.InsertLinked(Activation, key, fact);
if (key == null)
throw new ArgumentNullException(nameof(key));
if (fact == null)
throw new ArgumentNullException(nameof(fact));

var keyedFact = new KeyValuePair<object, object>(key, fact);
InsertAllLinked(new[] {keyedFact});
}

public void InsertAllLinked(IEnumerable<KeyValuePair<object, object>> keyedFacts)
{
_session.InsertLinked(Activation, keyedFacts);
}

public void UpdateLinked(object key, object fact)
{
_session.UpdateLinked(Activation, key, fact);
if (key == null)
throw new ArgumentNullException(nameof(key));
if (fact == null)
throw new ArgumentNullException(nameof(fact));

var keyedFact = new KeyValuePair<object, object>(key, fact);
UpdateAllLinked(new[] {keyedFact});
}

public void UpdateAllLinked(IEnumerable<KeyValuePair<object, object>> keyedFacts)
{
_session.UpdateLinked(Activation, keyedFacts);
}

public void RetractLinked(object key, object fact)
{
_session.RetractLinked(Activation, key, fact);
if (key == null)
throw new ArgumentNullException(nameof(key));
if (fact == null)
throw new ArgumentNullException(nameof(fact));

var keyedFact = new KeyValuePair<object, object>(key, fact);
RetractAllLinked(new[] {keyedFact});
}

public void RetractAllLinked(IEnumerable<KeyValuePair<object, object>> keyedFacts)
{
_session.RetractLinked(Activation, keyedFacts);
}

public object Resolve(Type serviceType)
@@ -191,9 +191,9 @@ internal interface ISessionInternal : ISession

IEnumerable<object> GetLinkedKeys(Activation activation);
object GetLinked(Activation activation, object key);
void InsertLinked(Activation activation, object key, object fact);
void UpdateLinked(Activation activation, object key, object fact);
void RetractLinked(Activation activation, object key, object fact);
void InsertLinked(Activation activation, IEnumerable<KeyValuePair<object, object>> keyedFacts);
void UpdateLinked(Activation activation, IEnumerable<KeyValuePair<object, object>> keyedFacts);
void RetractLinked(Activation activation, IEnumerable<KeyValuePair<object, object>> keyedFacts);
}

/// <summary>
@@ -425,65 +425,75 @@ public object GetLinked(Activation activation, object key)
return factWrapper?.Object;
}

public void InsertLinked(Activation activation, object key, object fact)
public void InsertLinked(Activation activation, IEnumerable<KeyValuePair<object, object>> keyedFacts)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (fact == null)
var toAdd = new List<Tuple<object, Fact>>();
var toPropagate = new List<Fact>();
foreach (var keyedFact in keyedFacts)
{
throw new ArgumentNullException(nameof(fact));
var key = keyedFact.Key;
var factWrapper = _workingMemory.GetLinkedFact(activation, key);
if (factWrapper != null)
{
throw new ArgumentException($"Linked fact already exists. Key={key}");
}
factWrapper = new SyntheticFact(keyedFact.Value);
factWrapper.Source = new LinkedFactSource(activation);
toAdd.Add(System.Tuple.Create(key, factWrapper));
toPropagate.Add(factWrapper);
}
var factWrapper = _workingMemory.GetLinkedFact(activation, key);
if (factWrapper != null)
foreach (var item in toAdd)
{
throw new ArgumentException($"Linked fact already exists. Key={key}", nameof(fact));
_workingMemory.AddLinkedFact(activation, item.Item1, item.Item2);
}
factWrapper = new SyntheticFact(fact);
factWrapper.Source = new LinkedFactSource(activation);
_workingMemory.AddLinkedFact(activation, key, factWrapper);
_network.PropagateAssert(_executionContext, new List<Fact> {factWrapper});
_network.PropagateAssert(_executionContext, toPropagate);
}

public void UpdateLinked(Activation activation, object key, object fact)
public void UpdateLinked(Activation activation, IEnumerable<KeyValuePair<object, object>> keyedFacts)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (fact == null)
var toUpdate = new List<Tuple<object, Fact, object>>();
var toPropagate = new List<Fact>();
foreach (var keyedFact in keyedFacts)
{
throw new ArgumentNullException(nameof(fact));
var key = keyedFact.Key;
var factWrapper = _workingMemory.GetLinkedFact(activation, key);
if (factWrapper == null)
{
throw new ArgumentException($"Linked fact does not exist. Key={key}");
}
factWrapper.Source = new LinkedFactSource(activation);
toUpdate.Add(System.Tuple.Create(key, factWrapper, keyedFact.Value));
toPropagate.Add(factWrapper);
}
var factWrapper = _workingMemory.GetLinkedFact(activation, key);
if (factWrapper == null)
foreach (var item in toUpdate)
{
throw new ArgumentException($"Linked fact does not exist. Key={key}", nameof(fact));
_workingMemory.UpdateLinkedFact(activation, item.Item1, item.Item2, item.Item3);
}
factWrapper.Source = new LinkedFactSource(activation);
_workingMemory.UpdateLinkedFact(activation, key, factWrapper, fact);
_network.PropagateUpdate(_executionContext, new List<Fact> {factWrapper});
_network.PropagateUpdate(_executionContext, toPropagate);
}

public void RetractLinked(Activation activation, object key, object fact)
public void RetractLinked(Activation activation, IEnumerable<KeyValuePair<object, object>> keyedFacts)
{
if (key == null)
{
throw new ArgumentNullException(nameof(key));
}
if (fact == null)
var toRemove = new List<Tuple<object, Fact>>();
var toPropagate = new List<Fact>();
foreach (var keyedFact in keyedFacts)
{
throw new ArgumentNullException(nameof(fact));
var key = keyedFact.Key;
var factWrapper = _workingMemory.GetFact(keyedFact.Value);
if (factWrapper == null)
{
throw new ArgumentException($"Linked fact does not exist. Key={key}");
}
factWrapper.Source = new LinkedFactSource(activation);
toRemove.Add(System.Tuple.Create(key, factWrapper));
toPropagate.Add(factWrapper);
}
var factWrapper = _workingMemory.GetFact(fact);
if (factWrapper == null)
_network.PropagateRetract(_executionContext, toPropagate);
foreach (var item in toRemove)
{
throw new ArgumentException($"Linked fact does not exist. Key={key}", nameof(fact));
_workingMemory.RemoveLinkedFact(activation, item.Item1, item.Item2);
item.Item2.Source = null;
}
_network.PropagateRetract(_executionContext, new List<Fact> {factWrapper});
_workingMemory.RemoveLinkedFact(activation, key, factWrapper);
factWrapper.Source = null;
}

private void UnlinkFacts()
@@ -492,12 +502,14 @@ private void UnlinkFacts()
while (unlinkQueue.Count > 0)
{
var activation = unlinkQueue.Dequeue();
var linkedKeys = GetLinkedKeys(activation).ToList();
var linkedKeys = GetLinkedKeys(activation);
var keyedFacts = new List<KeyValuePair<object, object>>();
foreach (var key in linkedKeys)
{
var linkedFact = GetLinked(activation, key);
RetractLinked(activation, key, linkedFact);
keyedFacts.Add(new KeyValuePair<object, object>(key, linkedFact));
}
RetractLinked(activation, keyedFacts);
}
}

0 comments on commit e2adfbe

Please sign in to comment.
You can’t perform that action at this time.