This repository was archived by the owner on Dec 17, 2025. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 188
Expand file tree
/
Copy pathBulkUpdateDecorator.ts
More file actions
125 lines (101 loc) · 3.24 KB
/
BulkUpdateDecorator.ts
File metadata and controls
125 lines (101 loc) · 3.24 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
120
121
122
123
124
125
import type { Hash, Encoding, BinaryToTextEncoding } from "crypto";
type HashOrFactory = Hash | (() => Hash);
const BULK_SIZE = 2000;
// We are using an object instead of a Map as this will stay static during the runtime
// so access to it can be optimized by v8
const digestCaches: { [key: string]: any } = {};
export default class BulkUpdateDecorator {
/**
* @param {HashOrFactory} hashOrFactory function to create a hash
* @param {string=} hashKey key for caching
*/
hash?: Hash;
hashFactory?: () => Hash;
hashKey: string;
buffer: string;
constructor(hashOrFactory: HashOrFactory, hashKey: string) {
this.hashKey = hashKey;
if (typeof hashOrFactory === "function") {
this.hashFactory = hashOrFactory;
this.hash = undefined;
} else {
this.hashFactory = undefined;
this.hash = hashOrFactory;
}
this.buffer = "";
}
/**
* Update hash {@link https://nodejs.org/api/crypto.html#crypto_hash_update_data_inputencoding}
* @param {string|Buffer} data data
* @param {string=} inputEncoding data encoding
* @returns {this} updated hash
*/
update(data: string | Buffer, inputEncoding?: Encoding): this {
if (
inputEncoding !== undefined ||
typeof data !== "string" ||
data.length > BULK_SIZE
) {
if (this.hash === undefined) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.hash = this.hashFactory!();
}
if (this.buffer.length > 0) {
this.hash.update(this.buffer);
this.buffer = "";
}
if (inputEncoding === undefined) {
this.hash.update(data);
} else {
this.hash.update(data as string, inputEncoding);
}
} else {
this.buffer += data;
if (this.buffer.length > BULK_SIZE) {
if (this.hash === undefined) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.hash = this.hashFactory!();
}
this.hash.update(this.buffer);
this.buffer = "";
}
}
return this;
}
/**
* Calculates the digest {@link https://nodejs.org/api/crypto.html#crypto_hash_digest_encoding}
* @param {string=} encoding encoding of the return value
* @returns {string|Buffer} digest
*/
digest(encoding?: BinaryToTextEncoding): string | Buffer {
let digestCache;
let digestResult: string | Buffer;
const buffer = this.buffer;
if (this.hash === undefined) {
// short data for hash, we can use caching
const cacheKey = `${this.hashKey}-${encoding}`;
digestCache = digestCaches[cacheKey];
if (digestCache === undefined) {
digestCache = digestCaches[cacheKey] = new Map();
}
const cacheEntry = digestCache.get(buffer);
if (cacheEntry !== undefined) {
return cacheEntry;
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
this.hash = this.hashFactory!();
}
if (buffer.length > 0) {
this.hash.update(buffer);
}
if (encoding !== undefined) {
digestResult = this.hash.digest(encoding);
} else {
digestResult = this.hash.digest();
}
if (digestCache !== undefined) {
digestCache.set(buffer, digestResult);
}
return digestResult;
}
}