-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathfriendlyId.ts
More file actions
119 lines (92 loc) · 2.92 KB
/
friendlyId.ts
File metadata and controls
119 lines (92 loc) · 2.92 KB
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
import { customAlphabet } from "nanoid";
import cuid from "@bugsnag/cuid";
const idGenerator = customAlphabet("123456789abcdefghijkmnopqrstuvwxyz", 21);
export function generateFriendlyId(prefix: string, size?: number) {
return `${prefix}_${idGenerator(size)}`;
}
export function generateInternalId() {
return cuid();
}
/** Convert an internal ID to a friendly ID */
export function toFriendlyId(entityName: string, internalId: string): string {
if (!entityName) {
throw new Error("Entity name cannot be empty");
}
if (!internalId) {
throw new Error("Internal ID cannot be empty");
}
if (internalId.startsWith(`${entityName}_`)) {
return internalId;
}
return `${entityName}_${internalId}`;
}
/** Convert a friendly ID to an internal ID */
export function fromFriendlyId(friendlyId: string, expectedEntityName?: string): string {
if (!friendlyId) {
throw new Error("Friendly ID cannot be empty");
}
const parts = friendlyId.split("_");
// If there's no underscore, assume it's already an internal ID
if (parts.length === 1) {
return friendlyId;
}
if (parts.length !== 2) {
throw new Error("Invalid friendly ID format");
}
const [entityName, internalId] = parts;
if (!entityName) {
throw new Error("Entity name cannot be empty");
}
if (!internalId) {
throw new Error("Internal ID cannot be empty");
}
if (expectedEntityName && entityName !== expectedEntityName) {
throw new Error(`Invalid entity name: ${entityName}`);
}
return internalId;
}
export class IdUtil {
constructor(private entityName: string) {}
generate() {
const internalId = generateInternalId();
return {
id: internalId,
friendlyId: this.toFriendlyId(internalId),
};
}
toFriendlyId(internalId: string) {
return toFriendlyId(this.entityName, internalId);
}
fromFriendlyId(friendlyId: string) {
return fromFriendlyId(friendlyId);
}
/** Will convert friendlyIds, and will leave ids as they are */
toId(value: string) {
if (value.startsWith(`${this.entityName}_`)) {
return fromFriendlyId(value);
}
return value;
}
}
export const BackgroundWorkerId = new IdUtil("worker");
export const CheckpointId = new IdUtil("checkpoint");
export const QueueId = new IdUtil("queue");
export const RunId = new IdUtil("run");
export const SnapshotId = new IdUtil("snapshot");
export const WaitpointId = new IdUtil("waitpoint");
export const BatchId = new IdUtil("batch");
export const BulkActionId = new IdUtil("bulk");
export const AttemptId = new IdUtil("attempt");
export class IdGenerator {
private alphabet: string;
private length: number;
private prefix: string;
constructor({ alphabet, length, prefix }: { alphabet: string; length: number; prefix: string }) {
this.alphabet = alphabet;
this.length = length;
this.prefix = prefix;
}
generate(): string {
return `${this.prefix}${customAlphabet(this.alphabet, this.length)()}`;
}
}