PetaPoco icon indicating copy to clipboard operation
PetaPoco copied to clipboard

IAsyncReader CancellationToken support

Open dje1990 opened this issue 3 years ago • 4 comments

Hi, It looks like IAsyncReader is a good candidate to add CancellationToken support: Task<bool> ReadAsync(CancellationToken cancellationToken);

Then the first lines of the implementations of this method can check if cancellation has been requested, and call the dispose method of the IAsyncReader implementation:

        if (cancellationToken.IsCancellationRequested)
        {
            this.Dispose();
            cancellationToken.ThrowIfCancellationRequested();
        }
        else
        {
            ....
        }

A simple example of how this would make using PetaPoco more elegant, Instead of:

    public static async IAsyncEnumerable<TProjection> QueryAsyncEnumerable<TProjection>(this IDatabase database,
        [EnumeratorCancellation] CancellationToken cancellationToken, string sql, params object[] args)
    {
        using var asyncReader =
            await database.QueryAsync<TProjection>(cancellationToken, sql, args).ConfigureAwait(false);

        if (cancellationToken.IsCancellationRequested)
        {
            asyncReader.Dispose();
            cancellationToken.ThrowIfCancellationRequested();
        }
        else
        {
            // todo: why does ReadAsync not accept a cancellationToken ? then remove these two ThrowIfCancellationRequested checks
            // todo: see https://github.com/CollaboratingPlatypus/PetaPoco/issues/638
            while (await asyncReader.ReadAsync().ConfigureAwait(false))
            {
                yield return asyncReader.Poco;

                if (!cancellationToken.IsCancellationRequested) continue;
                asyncReader.Dispose();
                cancellationToken.ThrowIfCancellationRequested();
            }
        }
    }

Use the new CancellationToken support:

    public static async IAsyncEnumerable<TProjection> QueryAsyncEnumerable<TProjection>(this IDatabase database,
        [EnumeratorCancellation] CancellationToken cancellationToken, string sql, params object[] args)
    {
        using var asyncReader = await database.QueryAsync<TProjection>(cancellationToken, sql, args).ConfigureAwait(false);

        while (await asyncReader.ReadAsync(cancellationToken).ConfigureAwait(false))
        {
            yield return asyncReader.Poco;
        }
    }

Thanks for your help and support.

dje1990 avatar May 01 '22 22:05 dje1990

The async methods were added before IAsyncEnumerable was added to the framework. It would be nice to add support for IAsyncEnumerable and update the current methods to use IAsyncEnumerable internally. The only problem would be the current target is netstandard 2.0 and IAsyncEnumerable is supported in netstandard 2.1 and above.

🤔 Maybe time for a version bump

pleb avatar May 06 '22 00:05 pleb

Oh, I didn't realise @asherber added support for netstandard 2.1... well this changes my view ;)

pleb avatar May 06 '22 06:05 pleb

Hi Wade, Thanks for your response. Adding support for IAsyncEnumerable would indeed resolve my original need, so that's great news if it's something that can be considered now that netstandard 2.1 is supported. I saw the use of IAsyncEnumerable was previously discussed before on https://github.com/CollaboratingPlatypus/PetaPoco/issues/600 I opened this ticket specifically about adding CancellationToken support to the existing IAsyncReader interface, which I think would still be a separate change to adding IAsyncEnumerable (and wouldn't require netstandard 2.1 support I think?). (My example IAsyncReader to IAsyncEnumerable extension method was just an example of how CancellationToken support for IAsyncReader would be useful). However I would vote to prioritise adding IAsyncEnumerable as you suggested if it's possible, rather than adding CancellationToken support to the IAsyncReader interface. Thanks for your help.

dje1990 avatar May 06 '22 06:05 dje1990

Although PP targets 2.1 as well as 2.0, changing the method signature for 2.1 would involve more #ifs, and I think would be a breaking change anyway -- an application targeting net5.0 (for example) which used to link to the netstandard2.0 library would now link to the netstandard2.1 library and see the new methods in place of the old.

asherber avatar May 06 '22 13:05 asherber