Advanced Plugin

The article describes other ways to create plugin.

Plugin Based On IRowsIterator

Since IRowsInput is low-level interface, for some plugins it might be difficult to use. Instead, you can use IRowsIterator. It doesn't have open/close functionality, and requires developer to provide Row instance for Current.

/// <summary>
/// Example simple rows input iterator.
/// </summary>
public class SamplePluginRowsIterator : IRowsIterator
{
    private const long MaxValue = 9;

    [Description("Sample iterator.")]
    [FunctionSignature("plugin(start: integer = 0): object<IRowsIterator>")]
    public static VariantValue SamplePlugin(IExecutionThread thread)
    {
        var startValue = thread.Stack.Pop().AsInteger;
        var rowsSource = new SamplePluginRowsIterator(startValue ?? 0);
        return VariantValue.CreateFromObject(rowsSource);
    }

    private long _currentState;

    /// <inheritdoc />
    public Column[] Columns { get; } =
    [
        new("id", DataType.Integer, "Key.")
    ];

    /// <inheritdoc />
    public Row Current { get; }

    public SamplePluginRowsIterator(long initialValue)
    {
        Current = new Row(Columns);
        _currentState = initialValue;
    }

    /// <inheritdoc />
    public ValueTask<bool> MoveNextAsync(CancellationToken cancellationToken = default)
    {
        Trace.WriteLine(nameof(MoveNextAsync));
        if (_currentState >= MaxValue)
        {
            return ValueTask.FromResult(false);
        }
        _currentState++;
        Current["id"] = new VariantValue(_currentState);
        return ValueTask.FromResult(true);
    }

    /// <inheritdoc />
    public Task ResetAsync(CancellationToken cancellationToken = default)
    {
        Trace.WriteLine(nameof(ResetAsync));
        _currentState = 0;
        return Task.CompletedTask;
    }

    /// <inheritdoc />
    public void Explain(IndentedStringBuilder stringBuilder)
    {
        Trace.WriteLine(nameof(Explain));
        stringBuilder.AppendRowsIteratorsWithIndent("Sample Plugin");
    }
}

Plugin Based On FetchRowsInput

Another way to define plugin. It is high-level wrapper for rows input. The main purpose is to provide convenience wrapper for inputs that do external calls (API clients, etc).

/// <summary>
/// Example simple rows input plugin based on <see cref="FetchRowsInput{TClass}" />.
/// </summary>
public class SamplePluginInput : EnumerableRowsInput<TestClass>
{
    private const long MaxValue = 9;

    [Description("Sample input.")]
    [FunctionSignature("plugin(): object<IRowsInput>")]
    public static VariantValue SamplePlugin(IExecutionThread thread)
    {
        var rowsSource = new SamplePluginInput();
        return VariantValue.CreateFromObject(rowsSource);
    }

    private long _currentState;

    /// <inheritdoc />
    protected override void Initialize(ClassRowsFrameBuilder<TestClass> builder)
    {
        Trace.WriteLine(nameof(Initialize));
        builder
            .AddProperty(b => b.Key)
            .AddKeyColumn("key",
                isRequired: false,
                operation: VariantValue.Operation.Equals);
    }

    /// <inheritdoc />
    protected override IEnumerable<TestClass> GetData(Fetcher<TestClass> fetcher)
    {
        Trace.WriteLine(nameof(GetData));
        var key = GetKeyColumnValue("key");
        for (var i = 0; i < MaxValue; i++)
        {
            yield return new TestClass(++_currentState);
        }
    }
}