@ruiapp/rapid-core 0.1.26 → 0.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/core/pluginManager.d.ts +3 -1
  2. package/dist/core/server.d.ts +4 -1
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +565 -80
  5. package/dist/plugins/auth/actionHandlers/changePassword.d.ts +4 -0
  6. package/dist/plugins/auth/actionHandlers/index.d.ts +2 -1
  7. package/dist/plugins/auth/actionHandlers/resetPassword.d.ts +4 -0
  8. package/dist/plugins/sequence/SequencePlugin.d.ts +18 -0
  9. package/dist/plugins/sequence/SequenceService.d.ts +15 -0
  10. package/dist/plugins/sequence/actionHandlers/generateSn.d.ts +7 -0
  11. package/dist/plugins/sequence/actionHandlers/index.d.ts +3 -0
  12. package/dist/plugins/sequence/models/SequenceAutoIncrementRecord.d.ts +3 -0
  13. package/dist/plugins/sequence/models/SequenceRule.d.ts +3 -0
  14. package/dist/plugins/sequence/models/index.d.ts +2 -0
  15. package/dist/plugins/sequence/routes/generateSn.d.ts +12 -0
  16. package/dist/plugins/sequence/routes/index.d.ts +12 -0
  17. package/dist/plugins/sequence/segment-utility.d.ts +1 -0
  18. package/dist/plugins/sequence/segments/autoIncrement.d.ts +5 -0
  19. package/dist/plugins/sequence/segments/dayOfMonth.d.ts +5 -0
  20. package/dist/plugins/sequence/segments/index.d.ts +8 -0
  21. package/dist/plugins/sequence/segments/literal.d.ts +5 -0
  22. package/dist/plugins/sequence/segments/month.d.ts +5 -0
  23. package/dist/plugins/sequence/segments/parameter.d.ts +5 -0
  24. package/dist/plugins/sequence/segments/year.d.ts +5 -0
  25. package/dist/plugins/sequence/sequence-types.d.ts +8 -0
  26. package/dist/server.d.ts +3 -2
  27. package/dist/types.d.ts +43 -0
  28. package/package.json +3 -1
  29. package/src/core/pluginManager.ts +13 -1
  30. package/src/core/response.ts +1 -0
  31. package/src/core/server.ts +4 -1
  32. package/src/dataAccess/entityManager.ts +3 -0
  33. package/src/index.ts +1 -0
  34. package/src/plugins/auth/actionHandlers/changePassword.ts +58 -0
  35. package/src/plugins/auth/actionHandlers/createSession.ts +7 -1
  36. package/src/plugins/auth/actionHandlers/index.ts +2 -0
  37. package/src/plugins/auth/actionHandlers/resetPassword.ts +42 -0
  38. package/src/plugins/sequence/SequencePlugin.ts +122 -0
  39. package/src/plugins/sequence/SequenceService.ts +72 -0
  40. package/src/plugins/sequence/actionHandlers/generateSn.ts +36 -0
  41. package/src/plugins/sequence/actionHandlers/index.ts +6 -0
  42. package/src/plugins/sequence/models/SequenceAutoIncrementRecord.ts +49 -0
  43. package/src/plugins/sequence/models/SequenceRule.ts +42 -0
  44. package/src/plugins/sequence/models/index.ts +7 -0
  45. package/src/plugins/sequence/routes/generateSn.ts +15 -0
  46. package/src/plugins/sequence/routes/index.ts +5 -0
  47. package/src/plugins/sequence/segment-utility.ts +11 -0
  48. package/src/plugins/sequence/segments/autoIncrement.ts +77 -0
  49. package/src/plugins/sequence/segments/dayOfMonth.ts +16 -0
  50. package/src/plugins/sequence/segments/index.ts +16 -0
  51. package/src/plugins/sequence/segments/literal.ts +9 -0
  52. package/src/plugins/sequence/segments/month.ts +16 -0
  53. package/src/plugins/sequence/segments/parameter.ts +17 -0
  54. package/src/plugins/sequence/segments/year.ts +16 -0
  55. package/src/plugins/sequence/sequence-types.ts +10 -0
  56. package/src/server.ts +17 -3
  57. package/src/types.ts +62 -0
@@ -0,0 +1,72 @@
1
+ import { IRpdServer } from "~/core/server";
2
+ import { SequenceSegmentConfig } from "~/types";
3
+ import segmentResolvers from "./segments";
4
+ import { find } from "lodash";
5
+ import { SequenceRuleConfig } from "./sequence-types";
6
+
7
+ export interface GenerateSequenceNumbersInput {
8
+ ruleCode: string;
9
+ parameters: Record<string, string>;
10
+ amount: number;
11
+ }
12
+
13
+ export interface GenerateSequenceNumbersOutput {
14
+ sequences: string[];
15
+ }
16
+
17
+ export interface SegmentResolver {
18
+ segmentType: string;
19
+ resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string>;
20
+ }
21
+
22
+ export async function generateSn(server: IRpdServer, input: GenerateSequenceNumbersInput): Promise<string[]> {
23
+ const sequenceNumbers = [];
24
+ const { ruleCode, parameters } = input;
25
+ let { amount } = input;
26
+
27
+ if (!amount) {
28
+ amount = 1;
29
+ }
30
+
31
+ const sequenceRuleDataAccessor = server.getDataAccessor({
32
+ singularCode: "sequence_rule",
33
+ });
34
+
35
+ const sequenceRule = await sequenceRuleDataAccessor.findOne({
36
+ filters: [
37
+ {
38
+ operator: "eq",
39
+ field: "code",
40
+ value: ruleCode,
41
+ }
42
+ ]
43
+ });
44
+
45
+ if (!sequenceRule) {
46
+ throw new Error(`Failed to generate sequence number. Sequence with code '${sequenceRule.code}' not found.`);
47
+ }
48
+
49
+ const sequenceConfig: SequenceRuleConfig = sequenceRule.config;
50
+ if (!sequenceConfig || !sequenceConfig.segments) {
51
+ throw new Error("Failed to generate sequence number. Sequence not configured.");
52
+ }
53
+
54
+ for (let i = 0; i < amount; i++) {
55
+ let sequenceNumber: string = "";
56
+
57
+ for (const segmentConfig of sequenceConfig.segments) {
58
+ const segmentResolver: SegmentResolver = find(segmentResolvers, (item) => item.segmentType === segmentConfig.type);
59
+ if (!segmentResolver) {
60
+ // TODO: deal with unkown segment type
61
+ continue;
62
+ }
63
+
64
+ const segment = await segmentResolver.resolveSegmentValue(server, ruleCode, segmentConfig, input);
65
+ sequenceNumber += segment;
66
+ }
67
+
68
+ sequenceNumbers.push(sequenceNumber);
69
+ }
70
+
71
+ return sequenceNumbers;
72
+ }
@@ -0,0 +1,36 @@
1
+ import { ActionHandlerContext } from "~/core/actionHandler";
2
+ import { RapidPlugin } from "~/core/server";
3
+ import { GenerateSequenceNumbersInput, GenerateSequenceNumbersOutput, generateSn } from "../SequenceService";
4
+
5
+ export interface GenerateSequenceNumbersOptions {
6
+ ruleCode: string;
7
+ }
8
+
9
+
10
+ export const code = "generateSn";
11
+
12
+ export async function handler(
13
+ plugin: RapidPlugin,
14
+ ctx: ActionHandlerContext,
15
+ options: GenerateSequenceNumbersOptions,
16
+ ) {
17
+ const { server, routerContext } = ctx;
18
+ const { response } = routerContext;
19
+
20
+ const input: GenerateSequenceNumbersInput = ctx.input;
21
+ const { parameters, amount } = input;
22
+
23
+ if (options?.ruleCode) {
24
+ input.ruleCode = options.ruleCode;
25
+ }
26
+
27
+ if (!input.ruleCode) {
28
+ throw new Error(`Rule code is required when generating sequence numbers.`);
29
+ }
30
+
31
+ const sequences = await generateSn(server, input);
32
+
33
+ ctx.output = {
34
+ sequences,
35
+ } satisfies GenerateSequenceNumbersOutput;
36
+ }
@@ -0,0 +1,6 @@
1
+ import { IPluginActionHandler } from "~/core/actionHandler";
2
+ import * as generateSn from "./generateSn";
3
+
4
+ export default [
5
+ generateSn,
6
+ ] satisfies IPluginActionHandler[];
@@ -0,0 +1,49 @@
1
+ import { RpdDataModel } from "~/types";
2
+
3
+ export default {
4
+ maintainedBy: "sequencePlugin",
5
+ namespace: "svc",
6
+ name: "sequence_auto_increment_record",
7
+ singularCode: "sequence_auto_increment_record",
8
+ pluralCode: "sequence_auto_increment_records",
9
+ schema: "public",
10
+ tableName: "sequence_auto_increment_records",
11
+ properties: [
12
+ {
13
+ name: "id",
14
+ code: "id",
15
+ columnName: "id",
16
+ type: "integer",
17
+ required: true,
18
+ autoIncrement: true,
19
+ },
20
+ {
21
+ name: "ruleCode",
22
+ code: "ruleCode",
23
+ columnName: "rule_code",
24
+ type: "text",
25
+ required: true,
26
+ },
27
+ {
28
+ name: "scope",
29
+ code: "scope",
30
+ columnName: "scope",
31
+ type: "text",
32
+ required: false,
33
+ },
34
+ {
35
+ name: "currentValue",
36
+ code: "currentValue",
37
+ columnName: "current_value",
38
+ type: "integer",
39
+ required: true,
40
+ },
41
+ {
42
+ name: "updatedAt",
43
+ code: "updatedAt",
44
+ columnName: "updated_at",
45
+ type: "datetime",
46
+ required: true,
47
+ },
48
+ ],
49
+ } as RpdDataModel;
@@ -0,0 +1,42 @@
1
+ import { RpdDataModel } from "~/types";
2
+
3
+ export default {
4
+ maintainedBy: "sequencePlugin",
5
+ namespace: "svc",
6
+ name: "sequence_rule",
7
+ singularCode: "sequence_rule",
8
+ pluralCode: "sequence_rules",
9
+ schema: "public",
10
+ tableName: "sequence_rules",
11
+ properties: [
12
+ {
13
+ name: "id",
14
+ code: "id",
15
+ columnName: "id",
16
+ type: "integer",
17
+ required: true,
18
+ autoIncrement: true,
19
+ },
20
+ {
21
+ name: "code",
22
+ code: "code",
23
+ columnName: "code",
24
+ type: "text",
25
+ required: true,
26
+ },
27
+ {
28
+ name: "description",
29
+ code: "description",
30
+ columnName: "description",
31
+ type: "text",
32
+ required: false,
33
+ },
34
+ {
35
+ name: "config",
36
+ code: "config",
37
+ columnName: "config",
38
+ type: "json",
39
+ required: false,
40
+ },
41
+ ],
42
+ } as RpdDataModel;
@@ -0,0 +1,7 @@
1
+ import SequenceRule from "./SequenceRule";
2
+ import SequenceAutoIncrementRecord from "./SequenceAutoIncrementRecord";
3
+
4
+ export default [
5
+ SequenceRule,
6
+ SequenceAutoIncrementRecord,
7
+ ]
@@ -0,0 +1,15 @@
1
+ import { RpdRoute } from "~/types";
2
+
3
+ export default {
4
+ namespace: "svc",
5
+ name: "svc.generateSn",
6
+ code: "svc.generateSn",
7
+ type: "RESTful",
8
+ method: "POST",
9
+ endpoint: "/svc/generateSn",
10
+ actions: [
11
+ {
12
+ code: "generateSn",
13
+ },
14
+ ],
15
+ } satisfies RpdRoute;
@@ -0,0 +1,5 @@
1
+ import generateSn from "./generateSn";
2
+
3
+ export default [
4
+ generateSn,
5
+ ]
@@ -0,0 +1,11 @@
1
+ export function padSegment(segment: string, length?: number, fillString?: string) {
2
+ if (!length) {
3
+ return segment;
4
+ }
5
+
6
+ if (segment.length > length) {
7
+ return segment.substring(segment.length - length);
8
+ } else {
9
+ return segment.padStart(length, fillString || " ");
10
+ }
11
+ }
@@ -0,0 +1,77 @@
1
+ import { SequenceAutoIncrementSegmentConfig } from "~/types";
2
+ import { GenerateSequenceNumbersInput } from "../SequenceService";
3
+ import { padSegment } from "../segment-utility";
4
+ import { IRpdServer } from "~/core/server";
5
+ import { get } from "lodash";
6
+ import dayjs from "dayjs";
7
+
8
+ export const segmentType = "autoIncrement";
9
+
10
+ export async function resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceAutoIncrementSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string> {
11
+ const autoIncrementRecordDataAccessor = server.getDataAccessor({
12
+ singularCode: "sequence_auto_increment_record",
13
+ });
14
+
15
+ const scope = get(input.parameters, config.scope, "");
16
+
17
+ const autoIncrementRecord = await autoIncrementRecordDataAccessor.findOne({
18
+ filters: [
19
+ {
20
+ operator: "eq",
21
+ field: "rule_code",
22
+ value: ruleCode,
23
+ },
24
+ {
25
+ operator: "eq",
26
+ field: "scope",
27
+ value: scope,
28
+ },
29
+ ],
30
+ });
31
+
32
+ let now = dayjs();
33
+ let nowString = now.format("YYYY-MM-DD HH:mm:ss.SSS Z");
34
+
35
+ let nextValue = 1;
36
+ if (autoIncrementRecord) {
37
+ let shouldReset = false;
38
+ const period = config.period || "forever";
39
+ const lastUpdate = dayjs(autoIncrementRecord.updated_at);
40
+ if (period === "year") {
41
+ if (now.year() > lastUpdate.year()) {
42
+ shouldReset = true;
43
+ }
44
+ } else if (period === "month") {
45
+ if (now.year() !== lastUpdate.year() || now.month() !== lastUpdate.month()) {
46
+ shouldReset = true;
47
+ }
48
+ } else if (period === "day") {
49
+ if (now.year() !== lastUpdate.year() || now.month() !== lastUpdate.month() || now.date() !== lastUpdate.date()) {
50
+ shouldReset = true;
51
+ }
52
+ }
53
+
54
+ if (!shouldReset) {
55
+ nextValue = autoIncrementRecord.current_value + 1;
56
+ }
57
+ await autoIncrementRecordDataAccessor.updateById(autoIncrementRecord.id, {
58
+ current_value: nextValue,
59
+ updated_at: nowString,
60
+ });
61
+ } else {
62
+ await autoIncrementRecordDataAccessor.create({
63
+ rule_code: ruleCode,
64
+ scope: scope,
65
+ current_value: nextValue,
66
+ updated_at: nowString,
67
+ })
68
+ }
69
+
70
+ const segmentValue = nextValue.toString();
71
+
72
+ return padSegment(
73
+ segmentValue,
74
+ config.length,
75
+ config.padding || "0",
76
+ );
77
+ }
@@ -0,0 +1,16 @@
1
+ import { SequenceDayOfMonthSegmentConfig } from "~/types";
2
+ import { GenerateSequenceNumbersInput } from "../SequenceService";
3
+ import { padSegment } from "../segment-utility";
4
+ import { IRpdServer } from "~/core/server";
5
+
6
+ export const segmentType = "dayOfMonth";
7
+
8
+ export async function resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceDayOfMonthSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string> {
9
+ const segmentValue = (new Date).getDate().toString();
10
+
11
+ return padSegment(
12
+ segmentValue,
13
+ config.length || 2,
14
+ config.padding || "0",
15
+ );
16
+ }
@@ -0,0 +1,16 @@
1
+ import { SegmentResolver } from "../SequenceService";
2
+ import * as literal from "./literal";
3
+ import * as year from "./year";
4
+ import * as month from "./month";
5
+ import * as dayOfMonth from "./dayOfMonth";
6
+ import * as parameter from "./parameter";
7
+ import * as autoIncrement from "./autoIncrement";
8
+
9
+ export default [
10
+ literal,
11
+ year,
12
+ month,
13
+ dayOfMonth,
14
+ parameter,
15
+ autoIncrement,
16
+ ] satisfies SegmentResolver[];
@@ -0,0 +1,9 @@
1
+ import { SequenceLiteralSegmentConfig } from "~/types";
2
+ import { GenerateSequenceNumbersInput } from "../SequenceService";
3
+ import { IRpdServer } from "~/core/server";
4
+
5
+ export const segmentType = "literal";
6
+
7
+ export async function resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceLiteralSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string> {
8
+ return config.content || "";
9
+ }
@@ -0,0 +1,16 @@
1
+ import { SequenceMonthSegmentConfig } from "~/types";
2
+ import { GenerateSequenceNumbersInput } from "../SequenceService";
3
+ import { padSegment } from "../segment-utility";
4
+ import { IRpdServer } from "~/core/server";
5
+
6
+ export const segmentType = "month";
7
+
8
+ export async function resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceMonthSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string> {
9
+ const segmentValue = ((new Date).getMonth() + 1).toString();
10
+
11
+ return padSegment(
12
+ segmentValue,
13
+ config.length || 2,
14
+ config.padding || "0",
15
+ );
16
+ }
@@ -0,0 +1,17 @@
1
+ import { SequenceParameterSegmentConfig } from "~/types";
2
+ import { GenerateSequenceNumbersInput } from "../SequenceService";
3
+ import { padSegment } from "../segment-utility";
4
+ import { get } from "lodash";
5
+ import { IRpdServer } from "~/core/server";
6
+
7
+ export const segmentType = "parameter";
8
+
9
+ export async function resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceParameterSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string> {
10
+ const segmentValue = get(input.parameters, config.parameterName, "");
11
+
12
+ return padSegment(
13
+ segmentValue,
14
+ config.length,
15
+ config.padding,
16
+ );
17
+ }
@@ -0,0 +1,16 @@
1
+ import { SequenceYearSegmentConfig } from "~/types";
2
+ import { GenerateSequenceNumbersInput } from "../SequenceService";
3
+ import { padSegment } from "../segment-utility";
4
+ import { IRpdServer } from "~/core/server";
5
+
6
+ export const segmentType = "year";
7
+
8
+ export async function resolveSegmentValue(server: IRpdServer, ruleCode: string, config: SequenceYearSegmentConfig, input: GenerateSequenceNumbersInput): Promise<string> {
9
+ const segmentValue = (new Date).getFullYear().toString();
10
+
11
+ return padSegment(
12
+ segmentValue,
13
+ config.length || 4,
14
+ config.padding || "0",
15
+ );
16
+ }
@@ -0,0 +1,10 @@
1
+ import { SequenceSegmentConfig } from "~/types";
2
+
3
+ export type PropertySequenceConfig = {
4
+ autoGenerate: boolean;
5
+ ruleConfig: SequenceRuleConfig;
6
+ }
7
+
8
+ export type SequenceRuleConfig = {
9
+ segments: SequenceSegmentConfig[];
10
+ }
package/src/server.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  RpdServerEventTypes,
12
12
  RapidServerConfig,
13
13
  RpdDataModelProperty,
14
+ CreateEntityOptions,
14
15
  } from "./types";
15
16
 
16
17
  import QueryBuilder from "./queryBuilder/queryBuilder";
@@ -311,14 +312,27 @@ export class RapidServer implements IRpdServer {
311
312
  async handleRequest(request: Request, next: Next) {
312
313
  const rapidRequest = new RapidRequest(this, request);
313
314
  await rapidRequest.parseBody();
314
- const routeContext = new RouteContext(this, rapidRequest);
315
- await this.#pluginManager.onPrepareRouteContext(routeContext);
315
+ const routeContext: RouteContext = new RouteContext(this, rapidRequest);
316
316
 
317
- await this.#buildedRoutes(routeContext, next);
317
+ try {
318
+ await this.#pluginManager.onPrepareRouteContext(routeContext);
319
+ await this.#buildedRoutes(routeContext, next);
320
+ } catch (ex) {
321
+ this.#logger.error('handle request error:', ex)
322
+ routeContext.response.json({
323
+ error: {
324
+ message: ex.message || ex,
325
+ },
326
+ }, 500);
327
+ }
318
328
  return routeContext.response.getResponse();
319
329
  }
320
330
 
321
331
  async beforeRunRouteActions(handlerContext: ActionHandlerContext) {
322
332
  await this.#pluginManager.beforeRunRouteActions(handlerContext);
323
333
  }
334
+
335
+ async beforeCreateEntity(model: RpdDataModel, options: CreateEntityOptions) {
336
+ await this.#pluginManager.beforeCreateEntity(model, options);
337
+ }
324
338
  }
package/src/types.ts CHANGED
@@ -468,3 +468,65 @@ export interface RemoveEntityRelationsOptions {
468
468
  property: string;
469
469
  relations: {id?: number, [k: string]: any}[];
470
470
  }
471
+
472
+
473
+ export type SequenceSegmentConfig =
474
+ | SequenceLiteralSegmentConfig
475
+ | SequenceYearSegmentConfig
476
+ | SequenceMonthSegmentConfig
477
+ | SequenceDayOfMonthSegmentConfig
478
+ | SequenceDayOfWeekSegmentConfig
479
+ | SequenceDayOfYearSegmentConfig
480
+ | SequenceParameterSegmentConfig
481
+ | SequenceAutoIncrementSegmentConfig
482
+ ;
483
+
484
+ export type SequenceLiteralSegmentConfig = {
485
+ type: "literal",
486
+ content: string;
487
+ }
488
+
489
+ export type SequenceYearSegmentConfig = {
490
+ type: "year",
491
+ padding?: string;
492
+ length?: number;
493
+ }
494
+
495
+ export type SequenceMonthSegmentConfig = {
496
+ type: "month",
497
+ padding?: string;
498
+ length?: number;
499
+ }
500
+
501
+ export type SequenceDayOfMonthSegmentConfig = {
502
+ type: "dayOfMonth",
503
+ padding?: string;
504
+ length?: number;
505
+ }
506
+
507
+ export type SequenceDayOfWeekSegmentConfig = {
508
+ type: "dayOfWeek",
509
+ padding?: string;
510
+ length?: number;
511
+ }
512
+
513
+ export type SequenceDayOfYearSegmentConfig = {
514
+ type: "dayOfYear",
515
+ padding?: string;
516
+ length?: number;
517
+ }
518
+
519
+ export type SequenceParameterSegmentConfig = {
520
+ type: "parameter",
521
+ parameterName: string;
522
+ padding?: string;
523
+ length?: number;
524
+ }
525
+
526
+ export type SequenceAutoIncrementSegmentConfig = {
527
+ type: "autoIncrement",
528
+ scope: string;
529
+ period: "forever" | "day" | "month" | "year";
530
+ padding?: string;
531
+ length?: number;
532
+ }