aboutsummaryrefslogtreecommitdiff
path: root/lib/VNLib.Plugins.Extensions.Data/src/ProtectedEntityExtensions.cs
blob: ec7b4f5aea57e6403bb0d3acba7f93bbaf43e4ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
* Copyright (c) 2023 Vaughn Nugent
* 
* Library: VNLib
* Package: VNLib.Plugins.Extensions.Data
* File: ProtectedEntityExtensions.cs 
*
* ProtectedEntityExtensions.cs is part of VNLib.Plugins.Extensions.Data which is part of the larger 
* VNLib collection of libraries and utilities.
*
* VNLib.Plugins.Extensions.Data is free software: you can redistribute it and/or modify 
* it under the terms of the GNU Affero General Public License as 
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* VNLib.Plugins.Extensions.Data is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see https://www.gnu.org/licenses/.
*/

using System.Linq;
using System.Threading;
using System.Transactions;
using System.Threading.Tasks;
using System.Collections.Generic;

using VNLib.Utils;
using VNLib.Plugins.Extensions.Data.Abstractions;

namespace VNLib.Plugins.Extensions.Data
{
    public static class ProtectedEntityExtensions
    {
        /// <summary>
        /// Updates the specified record within the store
        /// </summary>
        /// <param name="store"></param>
        /// <param name="record">The record to update</param>
        /// <param name="userId">The userid of the record owner</param>
        /// <param name="cancellation">A token to cancel the operation</param>
        /// <returns>A task that evaluates to the number of records modified</returns>
        public static Task<ERRNO> UpdateUserRecordAsync<TEntity>(this IDataStore<TEntity> store, TEntity record, string userId, CancellationToken cancellation = default) 
            where TEntity : class, IDbModel, IUserEntity
        {
            record.UserId = userId;
            return store.UpdateAsync(record, cancellation);
        }

        /// <summary>
        /// Updates the specified record within the store
        /// </summary>
        /// <param name="store"></param>
        /// <param name="record">The record to update</param>
        /// <param name="userId">The userid of the record owner</param>
        /// <param name="cancellation">A token to cancel the operation</param>
        /// <returns>A task that evaluates to the number of records modified</returns>
        public static Task<ERRNO> CreateUserRecordAsync<TEntity>(this IDataStore<TEntity> store, TEntity record, string userId, CancellationToken cancellation = default) 
            where TEntity : class, IDbModel, IUserEntity
        {
            record.UserId = userId;
            return store.CreateAsync(record, cancellation);
        }

        /// <summary>
        /// Gets a single entity from its ID and user-id
        /// </summary>
        /// <param name="store"></param>
        /// <param name="key">The unique id of the entity</param>
        /// <param name="userId">The user's id that owns the resource</param>
        /// <returns>A task that resolves the entity or null if not found</returns>
        public static Task<TEntity?> GetSingleUserRecordAsync<TEntity>(this IDataStore<TEntity> store, string key, string userId) where TEntity : class, IDbModel, IUserEntity
        {
            return store.GetSingleAsync(key, userId);
        }

        /// <summary>
        /// Gets a page by its number offset constrained by its limit, 
        /// for the given user id
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="store"></param>
        /// <param name="collection">The collection to store found records</param>
        /// <param name="userId">The user to get the page for</param>
        /// <param name="page">The page offset</param>
        /// <param name="limit">The record limit for the page</param>
        /// <returns>A task that resolves the number of entities added to the collection</returns>
        public static Task<int> GetUserPageAsync<TEntity>(this IPaginatedDataStore<TEntity> store, ICollection<TEntity> collection, string userId, int page, int limit) 
            where TEntity : class, IDbModel, IUserEntity
        {
            return store.GetPageAsync(collection, page, limit, userId);
        }

        /// <summary>
        /// Deletes a single entiry by its ID only if it belongs to the speicifed user
        /// </summary>
        /// <param name="store"></param>
        /// <param name="key">The unique id of the entity</param>
        /// <param name="userId">The user's id that owns the resource</param>
        /// <returns>A task the resolves the number of eneities deleted (should evaluate to true or false)</returns>
        public static Task<ERRNO> DeleteUserRecordAsync<TEntity>(this IDataStore<TEntity> store, string key, string userId) where TEntity : class, IDbModel, IUserEntity
        {
            return store.DeleteAsync(key, userId);
        }

        /// <summary>
        /// Gets the record count for the specified userId
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="store"></param>
        /// <param name="userId">The unique id of the user to query record count</param>
        /// <param name="cancellation">A token to cancel the operation</param>
        /// <returns>A task that resolves the number of records belonging to the specified user</returns>
        public static Task<long> GetUserRecordCountAsync<TEntity>(this IDataStore<TEntity> store, string userId, CancellationToken cancellation = default)
            where TEntity : class, IDbModel, IUserEntity
        {
            return store.GetCountAsync(userId, cancellation);
        }

        /// <summary>
        /// If the current context instance inherits the <see cref="IConcurrentDbContext"/> interface,
        /// attempts to open a transaction with the specified isolation level.
        /// </summary>
        /// <param name="tdb"></param>
        /// <param name="isolationLevel">The transaction isolation level</param>
        /// <param name="cancellationToken">A token to cancel the operation</param>
        /// <returns></returns>
        internal static Task OpenTransactionAsync(this ITransactionalDbContext tdb, IsolationLevel isolationLevel, CancellationToken cancellationToken = default)
        {
            if(tdb is IConcurrentDbContext ccdb)
            {
                return ccdb.OpenTransactionAsync(isolationLevel, cancellationToken);
            }
            else
            {
                //Just ignore the isolation level
                return tdb.OpenTransactionAsync(cancellationToken);
            }
        }
    }
}