• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

b1f6c1c4 / ProfessionalAccounting / 327

28 Apr 2025 05:37PM UTC coverage: 51.346% (-3.0%) from 54.325%
327

push

appveyor

b1f6c1c4
ci buildx

6620 of 12893 relevant lines covered (51.35%)

126.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

6.59
/AccountingServer.Shell/DistributedShell.cs
1
/* Copyright (C) 2020-2025 b1f6c1c4
2
 *
3
 * This file is part of ProfessionalAccounting.
4
 *
5
 * ProfessionalAccounting is free software: you can redistribute it and/or
6
 * modify it under the terms of the GNU Affero General Public License as
7
 * published by the Free Software Foundation, version 3.
8
 *
9
 * ProfessionalAccounting is distributed in the hope that it will be useful, but
10
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License
12
 * for more details.
13
 *
14
 * You should have received a copy of the GNU Affero General Public License
15
 * along with ProfessionalAccounting.  If not, see
16
 * <https://www.gnu.org/licenses/>.
17
 */
18

19
using System;
20
using System.Collections.Generic;
21
using System.Security;
22
using AccountingServer.Entities;
23
using AccountingServer.Entities.Util;
24
using AccountingServer.Shell.Util;
25
using static AccountingServer.BLL.Parsing.Facade;
26

27
namespace AccountingServer.Shell;
28

29
/// <summary>
30
///     分期表达式解释器
31
/// </summary>
32
internal abstract class DistributedShell : IShellComponent
33
{
34
    /// <summary>
35
    ///     复合表达式解释器
36
    /// </summary>
37
    private readonly IShellComponent m_Composer;
38

39
    protected DistributedShell()
20✔
40
    {
20✔
41
        var resetComposer =
20✔
42
            new ShellComposer
43
                {
44
                    new ShellComponent(
45
                        "soft",
46
                        (expr, ctx) =>
47
                            {
×
48
                                var dist = Parsing.DistributedQuery(ref expr, ctx.Client);
×
49
                                var rng = Parsing.Range(ref expr, ctx.Client) ?? DateFilter.Unconstrained;
×
50
                                Parsing.Eof(expr);
×
51
                                return ExecuteResetSoft(dist, rng, ctx);
×
52
                            }),
×
53
                    new ShellComponent(
54
                        "mixed",
55
                        (expr, ctx) =>
56
                            {
×
57
                                var dist = Parsing.DistributedQuery(ref expr, ctx.Client);
×
58
                                var rng = Parsing.Range(ref expr, ctx.Client) ?? DateFilter.Unconstrained;
×
59
                                Parsing.Eof(expr);
×
60
                                return ExecuteResetMixed(dist, rng, ctx);
×
61
                            }),
×
62
                    new ShellComponent(
63
                        "hard",
64
                        (expr, ctx) =>
65
                            {
×
66
                                var dist = Parsing.DistributedQuery(ref expr, ctx.Client);
×
67
                                var vouchers = Parsing.OptColVouchers(ref expr, ctx.Client);
×
68
                                Parsing.Eof(expr);
×
69
                                return ExecuteResetHard(dist, vouchers, ctx);
×
70
                            }),
×
71
                };
72
        m_Composer =
20✔
73
            new ShellComposer
74
                {
75
                    new ShellComponent(
76
                        "all",
77
                        (expr, ctx) =>
78
                            {
×
79
                                var safe = Parsing.Token(ref expr, false, static t => t == "unsafe") == null;
×
80
                                var dist = Parsing.DistributedQuery(ref expr, ctx.Client);
×
81
                                Parsing.Eof(expr);
×
82
                                if (dist.IsDangerous() && safe)
×
83
                                    throw new SecurityException("检测到弱检索式");
×
84

85
                                return ExecuteList(dist, null, false, ctx);
×
86
                            }),
×
87
                    new ShellComponent(
88
                        "li",
89
                        (expr, ctx) =>
90
                            {
×
91
                                var safe = Parsing.Token(ref expr, false, static t => t == "unsafe") == null;
×
92
                                var dt = Parsing.UniqueTime(ref expr, ctx.Client) ?? ctx.Client.Today;
×
93
                                var dist = Parsing.DistributedQuery(ref expr, ctx.Client);
×
94
                                Parsing.Eof(expr);
×
95
                                if (dist.IsDangerous() && safe)
×
96
                                    throw new SecurityException("检测到弱检索式");
×
97

98
                                return ExecuteList(dist, dt, true, ctx);
×
99
                            }),
×
100
                    new ShellComponent(
101
                        "q",
102
                        (expr, ctx) =>
103
                            {
×
104
                                var safe = Parsing.Token(ref expr, false, static t => t == "unsafe") == null;
×
105
                                var dist = Parsing.DistributedQuery(ref expr, ctx.Client);
×
106
                                Parsing.Eof(expr);
×
107
                                if (dist.IsDangerous() && safe)
×
108
                                    throw new SecurityException("检测到弱检索式");
×
109

110
                                return ExecuteQuery(dist, ctx);
×
111
                            }),
×
112
                    new ShellComponent(
113
                        "reg",
114
                        (expr, ctx) =>
115
                            {
×
116
                                var dist = Parsing.DistributedQuery(ref expr, ctx.Client);
×
117
                                var rng = Parsing.Range(ref expr, ctx.Client) ?? DateFilter.Unconstrained;
×
118
                                var vouchers = Parsing.OptColVouchers(ref expr, ctx.Client);
×
119
                                Parsing.Eof(expr);
×
120
                                return ExecuteRegister(dist, rng, vouchers, ctx);
×
121
                            }),
×
122
                    new ShellComponent(
123
                        "unreg",
124
                        (expr, ctx) =>
125
                            {
×
126
                                var dist = Parsing.DistributedQuery(ref expr, ctx.Client);
×
127
                                var rng = Parsing.Range(ref expr, ctx.Client) ?? DateFilter.Unconstrained;
×
128
                                var vouchers = Parsing.OptColVouchers(ref expr, ctx.Client);
×
129
                                Parsing.Eof(expr);
×
130
                                return ExecuteUnregister(dist, rng, vouchers, ctx);
×
131
                            }),
×
132
                    new ShellComponent(
133
                        "recal",
134
                        (expr, ctx) =>
135
                            {
×
136
                                var dist = Parsing.DistributedQuery(ref expr, ctx.Client);
×
137
                                Parsing.Eof(expr);
×
138
                                return ExecuteRecal(dist, ctx);
×
139
                            }),
×
140
                    new ComponentAdapter("rst", resetComposer),
141
                    new ShellComponent(
142
                        "ap",
143
                        (expr, ctx) =>
144
                            {
×
145
                                var collapse = Parsing.Optional(ref expr, "col");
×
146
                                var dist = Parsing.DistributedQuery(ref expr, ctx.Client);
×
147
                                var rng = Parsing.Range(ref expr, ctx.Client) ?? DateFilter.Unconstrained;
×
148
                                Parsing.Eof(expr);
×
149
                                return ExecuteApply(dist, rng, collapse, ctx);
×
150
                            }),
×
151
                    new ShellComponent(
152
                        "chk",
153
                        (expr, ctx) =>
154
                            {
×
155
                                var dist = Parsing.DistributedQuery(ref expr, ctx.Client);
×
156
                                Parsing.Eof(expr);
×
157
                                return ExecuteCheck(dist, new(null, ctx.Client.Today), ctx);
×
158
                            }),
×
159
                    new ShellComponent(
160
                        null,
161
                        (expr, ctx) =>
162
                            {
×
163
                                var dt = Parsing.UniqueTime(ref expr, ctx.Client) ?? ctx.Client.Today;
×
164
                                var dist = Parsing.DistributedQuery(ref expr, ctx.Client);
×
165
                                Parsing.Eof(expr);
×
166
                                return ExecuteList(dist, dt, false, ctx);
×
167
                            }),
×
168
                };
169
    }
20✔
170

171
    /// <summary>
172
    ///     首字母
173
    /// </summary>
174
    protected abstract string Initial { get; }
175

176
    /// <inheritdoc />
177
    public IAsyncEnumerable<string> Execute(string expr, Context ctx, string term)
178
    {
×
179
        var next = string.IsNullOrEmpty(term) ? Initial : $"{term}-{Initial}";
×
180
        ctx.Identity.WillInvoke(next);
×
181
        return m_Composer.Execute(expr.Rest(), ctx, next);
×
182
    }
×
183

184
    /// <inheritdoc />
185
    public bool IsExecutable(string expr) => expr.Initial() == Initial;
12✔
186

187
    /// <summary>
188
    ///     执行列表表达式
189
    /// </summary>
190
    /// <param name="distQuery">分期检索式</param>
191
    /// <param name="dt">计算账面价值的时间</param>
192
    /// <param name="showSchedule">是否显示折旧计算表</param>
193
    /// <param name="ctx">客户端上下文</param>
194
    /// <returns>执行结果</returns>
195
    protected abstract IAsyncEnumerable<string> ExecuteList(IQueryCompounded<IDistributedQueryAtom> distQuery,
196
        DateTime? dt, bool showSchedule, Context ctx);
197

198
    /// <summary>
199
    ///     执行查询表达式
200
    /// </summary>
201
    /// <param name="distQuery">分期检索式</param>
202
    /// <param name="ctx">客户端上下文</param>
203
    /// <returns>执行结果</returns>
204
    protected abstract IAsyncEnumerable<string> ExecuteQuery(IQueryCompounded<IDistributedQueryAtom> distQuery,
205
        Context ctx);
206

207
    /// <summary>
208
    ///     执行注册表达式
209
    /// </summary>
210
    /// <param name="distQuery">分期检索式</param>
211
    /// <param name="rng">日期过滤器</param>
212
    /// <param name="query">记账凭证检索式</param>
213
    /// <param name="ctx">客户端上下文</param>
214
    /// <returns>执行结果</returns>
215
    protected abstract IAsyncEnumerable<string> ExecuteRegister(IQueryCompounded<IDistributedQueryAtom> distQuery,
216
        DateFilter rng, IQueryCompounded<IVoucherQueryAtom> query, Context ctx);
217

218
    /// <summary>
219
    ///     执行解除注册表达式
220
    /// </summary>
221
    /// <param name="distQuery">分期检索式</param>
222
    /// <param name="rng">日期过滤器</param>
223
    /// <param name="query">记账凭证检索式</param>
224
    /// <param name="ctx">客户端上下文</param>
225
    /// <returns>执行结果</returns>
226
    protected abstract IAsyncEnumerable<string> ExecuteUnregister(IQueryCompounded<IDistributedQueryAtom> distQuery,
227
        DateFilter rng, IQueryCompounded<IVoucherQueryAtom> query, Context ctx);
228

229
    /// <summary>
230
    ///     执行重新计算表达式
231
    /// </summary>
232
    /// <param name="distQuery">分期检索式</param>
233
    /// <param name="ctx">客户端上下文</param>
234
    /// <returns>执行结果</returns>
235
    protected abstract IAsyncEnumerable<string> ExecuteRecal(IQueryCompounded<IDistributedQueryAtom> distQuery,
236
        Context ctx);
237

238
    /// <summary>
239
    ///     执行软重置表达式
240
    /// </summary>
241
    /// <param name="distQuery">分期检索式</param>
242
    /// <param name="rng">日期过滤器</param>
243
    /// <param name="ctx">客户端上下文</param>
244
    /// <returns>执行结果</returns>
245
    protected abstract IAsyncEnumerable<string> ExecuteResetSoft(IQueryCompounded<IDistributedQueryAtom> distQuery,
246
        DateFilter rng, Context ctx);
247

248
    /// <summary>
249
    ///     执行混合重置表达式
250
    /// </summary>
251
    /// <param name="distQuery">分期检索式</param>
252
    /// <param name="rng">日期过滤器</param>
253
    /// <param name="ctx">客户端上下文</param>
254
    /// <returns>执行结果</returns>
255
    protected abstract IAsyncEnumerable<string> ExecuteResetMixed(IQueryCompounded<IDistributedQueryAtom> distQuery,
256
        DateFilter rng, Context ctx);
257

258
    /// <summary>
259
    ///     执行硬重置表达式
260
    /// </summary>
261
    /// <param name="distQuery">分期检索式</param>
262
    /// <param name="query">记账凭证检索式</param>
263
    /// <param name="ctx">客户端上下文</param>
264
    /// <returns>执行结果</returns>
265
    protected abstract IAsyncEnumerable<string> ExecuteResetHard(IQueryCompounded<IDistributedQueryAtom> distQuery,
266
        IQueryCompounded<IVoucherQueryAtom> query, Context ctx);
267

268
    /// <summary>
269
    ///     执行应用表达式
270
    /// </summary>
271
    /// <param name="distQuery">分期检索式</param>
272
    /// <param name="rng">日期过滤器</param>
273
    /// <param name="isCollapsed">是否压缩</param>
274
    /// <param name="ctx">客户端上下文</param>
275
    /// <returns>执行结果</returns>
276
    protected abstract IAsyncEnumerable<string> ExecuteApply(IQueryCompounded<IDistributedQueryAtom> distQuery,
277
        DateFilter rng, bool isCollapsed, Context ctx);
278

279
    /// <summary>
280
    ///     执行检查表达式
281
    /// </summary>
282
    /// <param name="distQuery">分期检索式</param>
283
    /// <param name="rng">日期过滤器</param>
284
    /// <param name="ctx">客户端上下文</param>
285
    /// <returns>执行结果</returns>
286
    protected abstract IAsyncEnumerable<string> ExecuteCheck(IQueryCompounded<IDistributedQueryAtom> distQuery,
287
        DateFilter rng, Context ctx);
288
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc