Relatude Help

Transaction plugins

A transaction plugin runs your code in every transaction that writes nodes of a type T, or of a type that inherits from it. Use it for rules that must hold however a node is written: checks, derived values, audit trails.

public class EventRules : NodeTransactionPlugin<IEvent> {
    public override void OnBeforeNodeAction(NodeKey id, NodeOperation operation,
            Transaction transaction, NodeHelper<IEvent> helper) {
        if (operation is NodeOperation.DeleteOrFail or NodeOperation.DeleteIfExists
                      or NodeOperation.ReIndex or NodeOperation.ChangeType) return;
        var ev = helper.GetNode();                         // the values being written
        if (ev.Status == EventStatus.Published && ev.StartsUtc == default)
            throw new InvalidOperationException($"\"{ev.Title}\" has no start time.");
        helper.SetProperty(e => e.Title, (ev.Title ?? "").Trim());
    }

    public override void OnAfterNodeAction(NodeKey id, NodeOperation operation,
            ResultingOperation result) {
        if (result == ResultingOperation.CreateNode) Console.WriteLine($"Event {id.Guid} created");
    }
}

Register it while the store is still closed, in OnStoreInit:

builder.AddRelatudeDB(options => {
    options.OnStoreInit = db => db.RegisterTransactionPlugin(new EventRules());
});

OnBeforeNodeAction runs before the commit for each insert, update or delete of a whole node. OnBeforePropertyAction does the same for writes of single properties: UpdateProperty, file copies, addresses. In these hooks you can throw to cancel the transaction, change what is written through helper, or add actions to transaction, such as transaction.UpdateAddress(id.Guid, slug). The OnAfter… hooks run after the commit, and the OnError… hooks when it fails.

  • A rule about values needs both Before hooks, as a value can be written either way.
  • Make Before hooks repeatable. One can run more than once for the same action.
  • Plugins run on the synchronous write path: Execute and the methods built on it. The …Async write methods and Transaction.ExecuteAsync skip them.