@kidus.dev/flowdb 1.0.0
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.
- package/README.md +15 -0
- package/dist/core/blob/blob.d.ts +25 -0
- package/dist/core/blob/blob.d.ts.map +1 -0
- package/dist/core/blob/blob.js +57 -0
- package/dist/core/blob/blob_disk_driver.d.ts +27 -0
- package/dist/core/blob/blob_disk_driver.d.ts.map +1 -0
- package/dist/core/blob/blob_disk_driver.js +179 -0
- package/dist/core/blob/blob_storage.d.ts +90 -0
- package/dist/core/blob/blob_storage.d.ts.map +1 -0
- package/dist/core/blob/blob_storage.js +248 -0
- package/dist/core/collection/collection.d.ts +99 -0
- package/dist/core/collection/collection.d.ts.map +1 -0
- package/dist/core/collection/collection.js +226 -0
- package/dist/core/collection/document.d.ts +24 -0
- package/dist/core/collection/document.d.ts.map +1 -0
- package/dist/core/collection/document.js +86 -0
- package/dist/core/collection/driver/collection_file_driver.d.ts +20 -0
- package/dist/core/collection/driver/collection_file_driver.d.ts.map +1 -0
- package/dist/core/collection/driver/collection_file_driver.js +90 -0
- package/dist/core/collection/driver/collection_operations.d.ts +43 -0
- package/dist/core/collection/driver/collection_operations.d.ts.map +1 -0
- package/dist/core/collection/driver/collection_operations.js +278 -0
- package/dist/core/collection/query/compares.d.ts +90 -0
- package/dist/core/collection/query/compares.d.ts.map +1 -0
- package/dist/core/collection/query/compares.js +362 -0
- package/dist/core/collection/query/filtering.d.ts +14 -0
- package/dist/core/collection/query/filtering.d.ts.map +1 -0
- package/dist/core/collection/query/filtering.js +176 -0
- package/dist/core/collection/query/query_builder.d.ts +145 -0
- package/dist/core/collection/query/query_builder.d.ts.map +1 -0
- package/dist/core/collection/query/query_builder.js +196 -0
- package/dist/core/collection/query/query_executor.d.ts +87 -0
- package/dist/core/collection/query/query_executor.d.ts.map +1 -0
- package/dist/core/collection/query/query_executor.js +348 -0
- package/dist/core/collection/query/relation.d.ts +29 -0
- package/dist/core/collection/query/relation.d.ts.map +1 -0
- package/dist/core/collection/query/relation.js +40 -0
- package/dist/core/database/backup.d.ts +26 -0
- package/dist/core/database/backup.d.ts.map +1 -0
- package/dist/core/database/backup.js +114 -0
- package/dist/core/database/database.d.ts +57 -0
- package/dist/core/database/database.d.ts.map +1 -0
- package/dist/core/database/database.js +179 -0
- package/dist/core/database/database_file_driver.d.ts +27 -0
- package/dist/core/database/database_file_driver.d.ts.map +1 -0
- package/dist/core/database/database_file_driver.js +135 -0
- package/dist/core/store/store.d.ts +24 -0
- package/dist/core/store/store.d.ts.map +1 -0
- package/dist/core/store/store.js +54 -0
- package/dist/core/store/store_file_driver.d.ts +26 -0
- package/dist/core/store/store_file_driver.d.ts.map +1 -0
- package/dist/core/store/store_file_driver.js +87 -0
- package/dist/tools/encryptor.d.ts +17 -0
- package/dist/tools/encryptor.d.ts.map +1 -0
- package/dist/tools/encryptor.js +80 -0
- package/dist/tools/format.d.ts +10 -0
- package/dist/tools/format.d.ts.map +1 -0
- package/dist/tools/format.js +40 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +6 -0
- package/dist/tools/json.d.ts +19 -0
- package/dist/tools/json.d.ts.map +1 -0
- package/dist/tools/json.js +232 -0
- package/dist/tools/performance.d.ts +20 -0
- package/dist/tools/performance.d.ts.map +1 -0
- package/dist/tools/performance.js +53 -0
- package/dist/tools/print_colored.d.ts +47 -0
- package/dist/tools/print_colored.d.ts.map +1 -0
- package/dist/tools/print_colored.js +119 -0
- package/dist/tools/random.d.ts +46 -0
- package/dist/tools/random.d.ts.map +1 -0
- package/dist/tools/random.js +214 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type Document from "../collection/document";
|
|
2
|
+
import { BlobDiskDriver } from "./blob_disk_driver";
|
|
3
|
+
export default class Blob {
|
|
4
|
+
private _id;
|
|
5
|
+
private _metadata?;
|
|
6
|
+
private _chunks?;
|
|
7
|
+
private _blobDiskDriver;
|
|
8
|
+
constructor(opts: {
|
|
9
|
+
id: string;
|
|
10
|
+
blobDiskDriver: BlobDiskDriver;
|
|
11
|
+
metadata?: Document;
|
|
12
|
+
chunks?: Buffer;
|
|
13
|
+
});
|
|
14
|
+
get id(): string;
|
|
15
|
+
get metadata(): Document | undefined;
|
|
16
|
+
get chunks(): Buffer | null;
|
|
17
|
+
getBytes(): Promise<Buffer | null>;
|
|
18
|
+
get bytesSync(): Buffer | null;
|
|
19
|
+
get bytesAsStream(): AsyncGenerator<Buffer | null>;
|
|
20
|
+
get size(): number;
|
|
21
|
+
get sizeAsHumanReadable(): string;
|
|
22
|
+
private formatSize;
|
|
23
|
+
toString(): string;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=blob.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob.d.ts","sourceRoot":"","sources":["../../../src/core/blob/blob.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,MAAM,CAAC,OAAO,OAAO,IAAI;IACvB,OAAO,CAAC,GAAG,CAAS;IACpB,OAAO,CAAC,SAAS,CAAC,CAAW;IAC7B,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,OAAO,CAAC,eAAe,CAAiB;gBAE5B,IAAI,EAAE;QAChB,EAAE,EAAE,MAAM,CAAC;QACX,cAAc,EAAE,cAAc,CAAC;QAC/B,QAAQ,CAAC,EAAE,QAAQ,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB;IAOD,IAAI,EAAE,IAAI,MAAM,CAEf;IACD,IAAI,QAAQ,IAAI,QAAQ,GAAG,SAAS,CAEnC;IACD,IAAI,MAAM,IAAI,MAAM,GAAG,IAAI,CAE1B;IAEK,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAGxC,IAAI,SAAS,IAAI,MAAM,GAAG,IAAI,CAE7B;IACD,IAAI,aAAa,IAAI,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC,CAEjD;IACD,IAAI,IAAI,IAAI,MAAM,CAEjB;IACD,IAAI,mBAAmB,IAAI,MAAM,CAEhC;IAED,OAAO,CAAC,UAAU;IAWlB,QAAQ,IAAI,MAAM;CASnB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { BlobDiskDriver } from "./blob_disk_driver";
|
|
2
|
+
export default class Blob {
|
|
3
|
+
_id;
|
|
4
|
+
_metadata;
|
|
5
|
+
_chunks;
|
|
6
|
+
_blobDiskDriver;
|
|
7
|
+
constructor(opts) {
|
|
8
|
+
this._id = opts.id;
|
|
9
|
+
this._metadata = opts.metadata;
|
|
10
|
+
this._blobDiskDriver = opts.blobDiskDriver;
|
|
11
|
+
this._chunks = opts.chunks;
|
|
12
|
+
}
|
|
13
|
+
get id() {
|
|
14
|
+
return this._id;
|
|
15
|
+
}
|
|
16
|
+
get metadata() {
|
|
17
|
+
return this._metadata;
|
|
18
|
+
}
|
|
19
|
+
get chunks() {
|
|
20
|
+
return this._chunks ?? this.bytesSync;
|
|
21
|
+
}
|
|
22
|
+
async getBytes() {
|
|
23
|
+
return await this._blobDiskDriver.mergeChunks(this.id);
|
|
24
|
+
}
|
|
25
|
+
get bytesSync() {
|
|
26
|
+
return this._blobDiskDriver.mergeChunksSync(this.id);
|
|
27
|
+
}
|
|
28
|
+
get bytesAsStream() {
|
|
29
|
+
return this._blobDiskDriver.mergeChunksAsStream(this.id);
|
|
30
|
+
}
|
|
31
|
+
get size() {
|
|
32
|
+
return this._blobDiskDriver.getFileSize(this.id);
|
|
33
|
+
}
|
|
34
|
+
get sizeAsHumanReadable() {
|
|
35
|
+
return this.formatSize(this.size);
|
|
36
|
+
}
|
|
37
|
+
formatSize(bytes) {
|
|
38
|
+
if (bytes < 1024)
|
|
39
|
+
return `${bytes} B`;
|
|
40
|
+
const units = ["KB", "MB", "GB", "TB"];
|
|
41
|
+
let i = -1;
|
|
42
|
+
do {
|
|
43
|
+
bytes = bytes / 1024;
|
|
44
|
+
i++;
|
|
45
|
+
} while (bytes >= 1024 && i < units.length - 1);
|
|
46
|
+
return `${bytes.toFixed(2)} ${units[i]}`;
|
|
47
|
+
}
|
|
48
|
+
toString() {
|
|
49
|
+
return `
|
|
50
|
+
Blob {
|
|
51
|
+
id: ${this._id},
|
|
52
|
+
metadata: ${JSON.stringify(this._metadata)},
|
|
53
|
+
size: ${this.size} (${this.sizeAsHumanReadable})
|
|
54
|
+
length: ${(this.bytesSync && this.bytesSync.length) || 0}
|
|
55
|
+
}`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export declare class BlobDiskDriver {
|
|
2
|
+
private _directory;
|
|
3
|
+
encrypted: boolean;
|
|
4
|
+
constructor(directoryPath: string, encrypted: boolean);
|
|
5
|
+
create(): Promise<void>;
|
|
6
|
+
createSync(): void;
|
|
7
|
+
destroy(force?: boolean): Promise<void>;
|
|
8
|
+
destroySync(force?: boolean): void;
|
|
9
|
+
add(bytes: Buffer, fileId: string, chunkSize: number): Promise<Buffer>;
|
|
10
|
+
addSync(bytes: Buffer, fileId: string, chunkSize: number): Buffer;
|
|
11
|
+
mergeChunks(fileId: string): Promise<Buffer | null>;
|
|
12
|
+
mergeChunksSync(fileId: string): Buffer | null;
|
|
13
|
+
mergeChunksAsStream(fileId: string): AsyncGenerator<Buffer | null>;
|
|
14
|
+
private _chunkIndexFromPath;
|
|
15
|
+
getFileSize(fileId: string): number;
|
|
16
|
+
updateChunks(fileId: string, bytes: Buffer, chunkSize: number): Promise<Buffer | null>;
|
|
17
|
+
updateChunksSync(fileId: string, bytes: Buffer, chunkSize: number): Buffer | null;
|
|
18
|
+
deleteChunks(fileId: string): Promise<void>;
|
|
19
|
+
deleteChunksSync(fileId: string): void;
|
|
20
|
+
exists(fileId: string): Promise<boolean>;
|
|
21
|
+
existsSync(fileId: string): boolean;
|
|
22
|
+
getCount(): Promise<number>;
|
|
23
|
+
getCountSync(): number;
|
|
24
|
+
getSize(): Promise<number>;
|
|
25
|
+
getSizeSync(): number;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=blob_disk_driver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob_disk_driver.d.ts","sourceRoot":"","sources":["../../../src/core/blob/blob_disk_driver.ts"],"names":[],"mappings":"AAGA,qBAAa,cAAc;IACzB,OAAO,CAAC,UAAU,CAAS;IACpB,SAAS,EAAE,OAAO,CAAC;gBAEd,aAAa,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO;IAK/C,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7B,UAAU,IAAI,IAAI;IAIZ,OAAO,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBpD,WAAW,CAAC,KAAK,GAAE,OAAe,GAAG,IAAI;IAiBnC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAa5E,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAa3D,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAgBzD,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAgBvC,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAAC,MAAM,GAAG,IAAI,CAAC;IAezE,OAAO,CAAC,mBAAmB;IAM3B,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAU7B,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAMzB,gBAAgB,CACd,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,IAAI;IAMV,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMjD,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAMhC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO9C,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAQ7B,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAIjC,YAAY,IAAI,MAAM;IAIhB,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAchC,WAAW,IAAI,MAAM;CAOtB"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import * as fs from "fs";
|
|
2
|
+
import * as path from "path";
|
|
3
|
+
export class BlobDiskDriver {
|
|
4
|
+
_directory;
|
|
5
|
+
encrypted;
|
|
6
|
+
constructor(directoryPath, encrypted) {
|
|
7
|
+
this._directory = directoryPath;
|
|
8
|
+
this.encrypted = encrypted;
|
|
9
|
+
}
|
|
10
|
+
async create() {
|
|
11
|
+
await fs.promises.mkdir(this._directory, { recursive: true });
|
|
12
|
+
}
|
|
13
|
+
createSync() {
|
|
14
|
+
fs.mkdirSync(this._directory, { recursive: true });
|
|
15
|
+
}
|
|
16
|
+
async destroy(force = false) {
|
|
17
|
+
if (!fs.existsSync(this._directory))
|
|
18
|
+
return;
|
|
19
|
+
const entities = fs.readdirSync(this._directory);
|
|
20
|
+
for (const name of entities) {
|
|
21
|
+
const entityPath = path.join(this._directory, name);
|
|
22
|
+
if (fs.lstatSync(entityPath).isDirectory() &&
|
|
23
|
+
path.basename(entityPath) === "_metadata")
|
|
24
|
+
continue;
|
|
25
|
+
await fs.promises.rm(entityPath, { recursive: force, force: true });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
destroySync(force = false) {
|
|
29
|
+
if (!fs.existsSync(this._directory))
|
|
30
|
+
return;
|
|
31
|
+
const entities = fs.readdirSync(this._directory);
|
|
32
|
+
for (const name of entities) {
|
|
33
|
+
const entityPath = path.join(this._directory, name);
|
|
34
|
+
if (fs.lstatSync(entityPath).isDirectory() &&
|
|
35
|
+
path.basename(entityPath) === "_metadata")
|
|
36
|
+
continue;
|
|
37
|
+
fs.rmSync(entityPath, { recursive: force, force: true });
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async add(bytes, fileId, chunkSize) {
|
|
41
|
+
const blobDirectory = path.join(this._directory, fileId);
|
|
42
|
+
await fs.promises.mkdir(blobDirectory, { recursive: true });
|
|
43
|
+
let chunkIndex = 0;
|
|
44
|
+
for (let i = 0; i < bytes.length; i += chunkSize, chunkIndex++) {
|
|
45
|
+
const end = i + chunkSize < bytes.length ? i + chunkSize : bytes.length;
|
|
46
|
+
const chunk = bytes.subarray(i, end);
|
|
47
|
+
const chunkFile = path.join(blobDirectory, `c_${chunkIndex}`);
|
|
48
|
+
await fs.promises.writeFile(chunkFile, chunk, { flag: "w" });
|
|
49
|
+
}
|
|
50
|
+
return bytes;
|
|
51
|
+
}
|
|
52
|
+
addSync(bytes, fileId, chunkSize) {
|
|
53
|
+
const blobDirectory = path.join(this._directory, fileId);
|
|
54
|
+
fs.mkdirSync(blobDirectory, { recursive: true });
|
|
55
|
+
let chunkIndex = 0;
|
|
56
|
+
for (let i = 0; i < bytes.length; i += chunkSize, chunkIndex++) {
|
|
57
|
+
const end = i + chunkSize < bytes.length ? i + chunkSize : bytes.length;
|
|
58
|
+
const chunk = bytes.subarray(i, end);
|
|
59
|
+
const chunkFile = path.join(blobDirectory, `c_${chunkIndex}`);
|
|
60
|
+
fs.writeFileSync(chunkFile, chunk, { flag: "w" });
|
|
61
|
+
}
|
|
62
|
+
return bytes;
|
|
63
|
+
}
|
|
64
|
+
async mergeChunks(fileId) {
|
|
65
|
+
const dir = path.join(this._directory, fileId);
|
|
66
|
+
if (!fs.existsSync(dir))
|
|
67
|
+
return null;
|
|
68
|
+
const files = fs
|
|
69
|
+
.readdirSync(dir)
|
|
70
|
+
.filter((f) => f.startsWith("c_"))
|
|
71
|
+
.sort((a, b) => this._chunkIndexFromPath(a) - this._chunkIndexFromPath(b));
|
|
72
|
+
const buffers = [];
|
|
73
|
+
for (const file of files) {
|
|
74
|
+
buffers.push(await fs.promises.readFile(path.join(dir, file)));
|
|
75
|
+
}
|
|
76
|
+
return Buffer.concat(buffers);
|
|
77
|
+
}
|
|
78
|
+
mergeChunksSync(fileId) {
|
|
79
|
+
const dir = path.join(this._directory, fileId);
|
|
80
|
+
if (!fs.existsSync(dir))
|
|
81
|
+
return null;
|
|
82
|
+
const files = fs
|
|
83
|
+
.readdirSync(dir)
|
|
84
|
+
.filter((f) => f.startsWith("c_"))
|
|
85
|
+
.sort((a, b) => this._chunkIndexFromPath(a) - this._chunkIndexFromPath(b));
|
|
86
|
+
const buffers = [];
|
|
87
|
+
for (const file of files) {
|
|
88
|
+
buffers.push(fs.readFileSync(path.join(dir, file)));
|
|
89
|
+
}
|
|
90
|
+
return Buffer.concat(buffers);
|
|
91
|
+
}
|
|
92
|
+
async *mergeChunksAsStream(fileId) {
|
|
93
|
+
const dir = path.join(this._directory, fileId);
|
|
94
|
+
if (!fs.existsSync(dir))
|
|
95
|
+
return;
|
|
96
|
+
const files = fs
|
|
97
|
+
.readdirSync(dir)
|
|
98
|
+
.filter((f) => f.startsWith("c_"))
|
|
99
|
+
.sort((a, b) => this._chunkIndexFromPath(a) - this._chunkIndexFromPath(b));
|
|
100
|
+
for (const file of files) {
|
|
101
|
+
yield await fs.promises.readFile(path.join(dir, file));
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
_chunkIndexFromPath(filepath) {
|
|
106
|
+
const name = path.basename(filepath);
|
|
107
|
+
const idx = name.substring(2); // after 'c_'
|
|
108
|
+
return Number.parseInt(idx, 10) || 0;
|
|
109
|
+
}
|
|
110
|
+
getFileSize(fileId) {
|
|
111
|
+
const dir = path.join(this._directory, fileId);
|
|
112
|
+
if (!fs.existsSync(dir))
|
|
113
|
+
return 0;
|
|
114
|
+
return fs
|
|
115
|
+
.readdirSync(dir)
|
|
116
|
+
.filter((f) => f.startsWith("c_"))
|
|
117
|
+
.map((f) => fs.statSync(path.join(dir, f)).size)
|
|
118
|
+
.reduce((sum, curr) => sum + curr, 0);
|
|
119
|
+
}
|
|
120
|
+
async updateChunks(fileId, bytes, chunkSize) {
|
|
121
|
+
if (!(await this.exists(fileId)))
|
|
122
|
+
return null;
|
|
123
|
+
await this.deleteChunks(fileId);
|
|
124
|
+
return await this.add(bytes, fileId, chunkSize);
|
|
125
|
+
}
|
|
126
|
+
updateChunksSync(fileId, bytes, chunkSize) {
|
|
127
|
+
if (!this.existsSync(fileId))
|
|
128
|
+
return null;
|
|
129
|
+
this.deleteChunksSync(fileId);
|
|
130
|
+
return this.addSync(bytes, fileId, chunkSize);
|
|
131
|
+
}
|
|
132
|
+
async deleteChunks(fileId) {
|
|
133
|
+
if (await this.exists(fileId))
|
|
134
|
+
return;
|
|
135
|
+
const dir = path.join(this._directory, fileId);
|
|
136
|
+
await fs.promises.rm(dir, { recursive: true, force: true });
|
|
137
|
+
}
|
|
138
|
+
deleteChunksSync(fileId) {
|
|
139
|
+
if (this.existsSync(fileId))
|
|
140
|
+
return;
|
|
141
|
+
const dir = path.join(this._directory, fileId);
|
|
142
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
143
|
+
}
|
|
144
|
+
async exists(fileId) {
|
|
145
|
+
return await fs.promises.stat(path.join(this._directory, fileId)).then((stat) => stat.isDirectory(), () => false);
|
|
146
|
+
}
|
|
147
|
+
existsSync(fileId) {
|
|
148
|
+
try {
|
|
149
|
+
return fs.statSync(path.join(this._directory, fileId)).isDirectory();
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async getCount() {
|
|
156
|
+
return (await fs.promises.readdir(this._directory)).length;
|
|
157
|
+
}
|
|
158
|
+
getCountSync() {
|
|
159
|
+
return fs.readdirSync(this._directory).length;
|
|
160
|
+
}
|
|
161
|
+
async getSize() {
|
|
162
|
+
let total = 0;
|
|
163
|
+
for await (const entry of await fs.promises.readdir(this._directory, {
|
|
164
|
+
withFileTypes: true,
|
|
165
|
+
})) {
|
|
166
|
+
if (entry.isFile()) {
|
|
167
|
+
total += (await fs.promises.stat(path.join(this._directory, entry.name))).size;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return total;
|
|
171
|
+
}
|
|
172
|
+
getSizeSync() {
|
|
173
|
+
return fs
|
|
174
|
+
.readdirSync(this._directory, { withFileTypes: true })
|
|
175
|
+
.filter((entry) => entry.isFile())
|
|
176
|
+
.map((entry) => fs.statSync(path.join(this._directory, entry.name)).size)
|
|
177
|
+
.reduce((sum, size) => sum + size, 0);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import Collection from "../collection/collection";
|
|
2
|
+
import { Buffer } from "buffer";
|
|
3
|
+
import Blob from "./blob";
|
|
4
|
+
import QueryBuilder from "../collection/query/query_builder";
|
|
5
|
+
export default class BlobStorage {
|
|
6
|
+
private _name;
|
|
7
|
+
private _chunksSize;
|
|
8
|
+
private _collection;
|
|
9
|
+
private _blobDiskDriver;
|
|
10
|
+
constructor(opts: {
|
|
11
|
+
name: string;
|
|
12
|
+
path: string;
|
|
13
|
+
chunksSize: number;
|
|
14
|
+
encrypted: boolean;
|
|
15
|
+
});
|
|
16
|
+
add(bytes: Buffer, metadata?: {
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
addSync(bytes: Buffer, metadata?: {
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
}): void;
|
|
22
|
+
get(params?: {
|
|
23
|
+
query?: (collection: Collection) => QueryBuilder;
|
|
24
|
+
count?: number;
|
|
25
|
+
}): Promise<Blob[]>;
|
|
26
|
+
getSync(params?: {
|
|
27
|
+
query?: (collection: Collection) => QueryBuilder;
|
|
28
|
+
count?: number;
|
|
29
|
+
}): Blob[];
|
|
30
|
+
update(opts: {
|
|
31
|
+
query: (collection: Collection) => QueryBuilder;
|
|
32
|
+
metadata?: {
|
|
33
|
+
[key: string]: any;
|
|
34
|
+
};
|
|
35
|
+
bytes?: Buffer;
|
|
36
|
+
}): Promise<Blob[]>;
|
|
37
|
+
updateById(id: string, opts: {
|
|
38
|
+
metadata?: {
|
|
39
|
+
[key: string]: any;
|
|
40
|
+
};
|
|
41
|
+
bytes?: Buffer;
|
|
42
|
+
}): Promise<Blob | null>;
|
|
43
|
+
updateSync(opts: {
|
|
44
|
+
query: (collection: Collection) => QueryBuilder;
|
|
45
|
+
metadata?: {
|
|
46
|
+
[key: string]: any;
|
|
47
|
+
};
|
|
48
|
+
bytes?: Buffer;
|
|
49
|
+
}): Blob[];
|
|
50
|
+
updateSyncById(id: string, opts: {
|
|
51
|
+
metadata?: {
|
|
52
|
+
[key: string]: any;
|
|
53
|
+
};
|
|
54
|
+
bytes?: Buffer;
|
|
55
|
+
}): Blob | null;
|
|
56
|
+
delete(opts: {
|
|
57
|
+
query: (collection: Collection) => QueryBuilder;
|
|
58
|
+
}): Promise<void>;
|
|
59
|
+
deleteById(id: string): Promise<void>;
|
|
60
|
+
deleteSync(opts: {
|
|
61
|
+
query: (collection: Collection) => QueryBuilder;
|
|
62
|
+
}): void;
|
|
63
|
+
deleteSyncById(id: string): void;
|
|
64
|
+
clear(opts?: {
|
|
65
|
+
force?: boolean;
|
|
66
|
+
}): Promise<void>;
|
|
67
|
+
clearSync(opts?: {
|
|
68
|
+
force?: boolean;
|
|
69
|
+
}): void;
|
|
70
|
+
reset(opts?: {
|
|
71
|
+
force?: boolean;
|
|
72
|
+
}): Promise<void>;
|
|
73
|
+
resetSync(opts?: {
|
|
74
|
+
force?: boolean;
|
|
75
|
+
}): void;
|
|
76
|
+
isEmpty(): Promise<boolean>;
|
|
77
|
+
isEmptySync(): boolean;
|
|
78
|
+
size(): Promise<number>;
|
|
79
|
+
sizeSync(): number;
|
|
80
|
+
sizeAsHumanReadable(): Promise<string>;
|
|
81
|
+
sizeAsHumanReadableSync(): string;
|
|
82
|
+
count(): Promise<number>;
|
|
83
|
+
countSync(): number;
|
|
84
|
+
countAsHumanReadable(): Promise<string>;
|
|
85
|
+
countAsHumanReadableSync(): string;
|
|
86
|
+
private formatSize;
|
|
87
|
+
private formatNumber;
|
|
88
|
+
toString(): string;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=blob_storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blob_storage.d.ts","sourceRoot":"","sources":["../../../src/core/blob/blob_storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import Collection from "../collection/collection";
|
|
2
|
+
import { BlobDiskDriver } from "./blob_disk_driver";
|
|
3
|
+
import { Buffer } from "buffer";
|
|
4
|
+
import Blob from "./blob";
|
|
5
|
+
import QueryBuilder from "../collection/query/query_builder";
|
|
6
|
+
export default class BlobStorage {
|
|
7
|
+
_name;
|
|
8
|
+
_chunksSize;
|
|
9
|
+
_collection;
|
|
10
|
+
_blobDiskDriver;
|
|
11
|
+
constructor(opts) {
|
|
12
|
+
this._name = opts.name;
|
|
13
|
+
this._chunksSize = opts.chunksSize;
|
|
14
|
+
this._collection = new Collection({
|
|
15
|
+
name: opts.name,
|
|
16
|
+
path: `${opts.path}/_metadata`,
|
|
17
|
+
encrypted: false,
|
|
18
|
+
});
|
|
19
|
+
this._blobDiskDriver = new BlobDiskDriver(opts.path, opts.encrypted);
|
|
20
|
+
this._blobDiskDriver.createSync();
|
|
21
|
+
}
|
|
22
|
+
// ADD
|
|
23
|
+
async add(bytes, metadata) {
|
|
24
|
+
const document = await this._collection.add({
|
|
25
|
+
created_at: new Date().toISOString(),
|
|
26
|
+
updated_at: new Date().toISOString(),
|
|
27
|
+
...(metadata || {}),
|
|
28
|
+
});
|
|
29
|
+
await this._blobDiskDriver.add(bytes, document.id, this._chunksSize);
|
|
30
|
+
}
|
|
31
|
+
addSync(bytes, metadata) {
|
|
32
|
+
const document = this._collection.addSync({
|
|
33
|
+
created_at: new Date().toISOString(),
|
|
34
|
+
updated_at: new Date().toISOString(),
|
|
35
|
+
...(metadata || {}),
|
|
36
|
+
});
|
|
37
|
+
this._blobDiskDriver.addSync(bytes, document.id, this._chunksSize);
|
|
38
|
+
}
|
|
39
|
+
// GET
|
|
40
|
+
async get(params) {
|
|
41
|
+
let builder = params && params.query
|
|
42
|
+
? params.query(this._collection)
|
|
43
|
+
: this._collection.builder;
|
|
44
|
+
if (params && params.count !== undefined)
|
|
45
|
+
builder = builder.limit(params.count);
|
|
46
|
+
const documents = await builder.get();
|
|
47
|
+
return documents.map((doc) => new Blob({
|
|
48
|
+
id: doc.id,
|
|
49
|
+
metadata: doc,
|
|
50
|
+
blobDiskDriver: this._blobDiskDriver,
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
getSync(params) {
|
|
54
|
+
let builder = params && params.query
|
|
55
|
+
? params.query(this._collection)
|
|
56
|
+
: this._collection.builder;
|
|
57
|
+
if (params && params.count !== undefined)
|
|
58
|
+
builder = builder.limit(params.count);
|
|
59
|
+
const rows = builder.getSync();
|
|
60
|
+
return rows.map((doc) => new Blob({
|
|
61
|
+
id: doc.id,
|
|
62
|
+
metadata: doc,
|
|
63
|
+
blobDiskDriver: this._blobDiskDriver,
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
// UPDATE
|
|
67
|
+
async update(opts) {
|
|
68
|
+
const rows = await opts.query(this._collection).get();
|
|
69
|
+
const updatedRows = [];
|
|
70
|
+
for (const row of rows) {
|
|
71
|
+
let updatedRow;
|
|
72
|
+
if (opts.metadata && Object.keys(opts.metadata).length > 0) {
|
|
73
|
+
const data = { ...row.data, ...opts.metadata };
|
|
74
|
+
updatedRow = await this._collection.updateById(row.id, data);
|
|
75
|
+
if (updatedRow)
|
|
76
|
+
updatedRows.push(updatedRow);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
updatedRow = row;
|
|
80
|
+
}
|
|
81
|
+
if (opts.bytes && opts.bytes.length > 0) {
|
|
82
|
+
await this._blobDiskDriver.updateChunks(row.id, opts.bytes, this._chunksSize);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return updatedRows.map((row) => new Blob({
|
|
86
|
+
id: row.id,
|
|
87
|
+
metadata: row,
|
|
88
|
+
blobDiskDriver: this._blobDiskDriver,
|
|
89
|
+
}));
|
|
90
|
+
}
|
|
91
|
+
async updateById(id, opts) {
|
|
92
|
+
const row = await this._collection.getById(id);
|
|
93
|
+
if (!row)
|
|
94
|
+
return null;
|
|
95
|
+
let updatedRow = row;
|
|
96
|
+
if (opts.metadata && Object.keys(opts.metadata).length > 0) {
|
|
97
|
+
const data = { ...row.data, ...opts.metadata };
|
|
98
|
+
const temp = await this._collection.updateById(row.id, data);
|
|
99
|
+
if (!temp)
|
|
100
|
+
return null;
|
|
101
|
+
updatedRow = temp;
|
|
102
|
+
}
|
|
103
|
+
if (opts.bytes && opts.bytes.length > 0) {
|
|
104
|
+
await this._blobDiskDriver.updateChunks(row.id, opts.bytes, this._chunksSize);
|
|
105
|
+
}
|
|
106
|
+
return new Blob({
|
|
107
|
+
id: updatedRow.id,
|
|
108
|
+
metadata: updatedRow,
|
|
109
|
+
blobDiskDriver: this._blobDiskDriver,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
updateSync(opts) {
|
|
113
|
+
const rows = opts.query(this._collection).getSync();
|
|
114
|
+
const updatedBlobs = [];
|
|
115
|
+
for (const row of rows) {
|
|
116
|
+
let updatedRow = row;
|
|
117
|
+
if (opts.metadata && Object.keys(opts.metadata).length > 0) {
|
|
118
|
+
const data = { ...row.data, ...opts.metadata };
|
|
119
|
+
const temp = this._collection.updateByIdSync(row.id, data);
|
|
120
|
+
if (!temp)
|
|
121
|
+
continue;
|
|
122
|
+
updatedRow = temp;
|
|
123
|
+
}
|
|
124
|
+
if (opts.bytes && opts.bytes.length > 0) {
|
|
125
|
+
this._blobDiskDriver.updateChunksSync(row.id, opts.bytes, this._chunksSize);
|
|
126
|
+
}
|
|
127
|
+
updatedBlobs.push(new Blob({
|
|
128
|
+
id: updatedRow.id,
|
|
129
|
+
metadata: updatedRow,
|
|
130
|
+
blobDiskDriver: this._blobDiskDriver,
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
return updatedBlobs;
|
|
134
|
+
}
|
|
135
|
+
updateSyncById(id, opts) {
|
|
136
|
+
const row = this._collection.getByIdSync(id);
|
|
137
|
+
if (!row)
|
|
138
|
+
return null;
|
|
139
|
+
let updatedRow = row;
|
|
140
|
+
if (opts.metadata && Object.keys(opts.metadata).length > 0) {
|
|
141
|
+
const data = { ...row.data, ...opts.metadata };
|
|
142
|
+
const temp = this._collection.updateByIdSync(row.id, data);
|
|
143
|
+
if (!temp)
|
|
144
|
+
return null;
|
|
145
|
+
updatedRow = temp;
|
|
146
|
+
}
|
|
147
|
+
if (opts.bytes && opts.bytes.length > 0) {
|
|
148
|
+
this._blobDiskDriver.updateChunksSync(row.id, opts.bytes, this._chunksSize);
|
|
149
|
+
}
|
|
150
|
+
return new Blob({
|
|
151
|
+
id: updatedRow.id,
|
|
152
|
+
metadata: updatedRow,
|
|
153
|
+
blobDiskDriver: this._blobDiskDriver,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
// DELETE
|
|
157
|
+
async delete(opts) {
|
|
158
|
+
const rows = await opts.query(this._collection).get();
|
|
159
|
+
for (const row of rows) {
|
|
160
|
+
await this._blobDiskDriver.deleteChunks(row.id);
|
|
161
|
+
await this._collection.deleteById(row.id);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
async deleteById(id) {
|
|
165
|
+
await this._blobDiskDriver.deleteChunks(id);
|
|
166
|
+
await this._collection.deleteById(id);
|
|
167
|
+
}
|
|
168
|
+
deleteSync(opts) {
|
|
169
|
+
const rows = opts.query(this._collection).getSync();
|
|
170
|
+
for (const row of rows) {
|
|
171
|
+
this._blobDiskDriver.deleteChunksSync(row.id);
|
|
172
|
+
this._collection.deleteByIdSync(row.id);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
deleteSyncById(id) {
|
|
176
|
+
this._blobDiskDriver.deleteChunksSync(id);
|
|
177
|
+
this._collection.deleteByIdSync(id);
|
|
178
|
+
}
|
|
179
|
+
// CLEAR
|
|
180
|
+
async clear(opts) {
|
|
181
|
+
await this._blobDiskDriver.destroy(opts?.force ?? false);
|
|
182
|
+
await this._collection.clear();
|
|
183
|
+
}
|
|
184
|
+
clearSync(opts) {
|
|
185
|
+
this._blobDiskDriver.destroySync(opts?.force ?? false);
|
|
186
|
+
this._collection.clearSync();
|
|
187
|
+
}
|
|
188
|
+
// RESET
|
|
189
|
+
async reset(opts) {
|
|
190
|
+
await this.clear(opts);
|
|
191
|
+
}
|
|
192
|
+
resetSync(opts) {
|
|
193
|
+
this.clearSync(opts);
|
|
194
|
+
}
|
|
195
|
+
// EMPTY
|
|
196
|
+
async isEmpty() {
|
|
197
|
+
return await this._collection.isEmpty();
|
|
198
|
+
}
|
|
199
|
+
isEmptySync() {
|
|
200
|
+
return this._collection.isEmptySync();
|
|
201
|
+
}
|
|
202
|
+
// Size
|
|
203
|
+
async size() {
|
|
204
|
+
return await this._blobDiskDriver.getSize();
|
|
205
|
+
}
|
|
206
|
+
sizeSync() {
|
|
207
|
+
return this._blobDiskDriver.getSizeSync();
|
|
208
|
+
}
|
|
209
|
+
async sizeAsHumanReadable() {
|
|
210
|
+
const size = await this.size();
|
|
211
|
+
return this.formatSize(size);
|
|
212
|
+
}
|
|
213
|
+
sizeAsHumanReadableSync() {
|
|
214
|
+
return this.formatSize(this.sizeSync());
|
|
215
|
+
}
|
|
216
|
+
// Count
|
|
217
|
+
async count() {
|
|
218
|
+
return await this._blobDiskDriver.getCount();
|
|
219
|
+
}
|
|
220
|
+
countSync() {
|
|
221
|
+
return this._blobDiskDriver.getCountSync();
|
|
222
|
+
}
|
|
223
|
+
async countAsHumanReadable() {
|
|
224
|
+
const count = await this.count();
|
|
225
|
+
return this.formatNumber(count);
|
|
226
|
+
}
|
|
227
|
+
countAsHumanReadableSync() {
|
|
228
|
+
return this.formatNumber(this.countSync());
|
|
229
|
+
}
|
|
230
|
+
formatSize(bytes) {
|
|
231
|
+
if (bytes < 1024)
|
|
232
|
+
return `${bytes} B`;
|
|
233
|
+
let kb = bytes / 1024;
|
|
234
|
+
if (kb < 1024)
|
|
235
|
+
return `${kb.toFixed(2)} KB`;
|
|
236
|
+
let mb = kb / 1024;
|
|
237
|
+
if (mb < 1024)
|
|
238
|
+
return `${mb.toFixed(2)} MB`;
|
|
239
|
+
let gb = mb / 1024;
|
|
240
|
+
return `${gb.toFixed(2)} GB`;
|
|
241
|
+
}
|
|
242
|
+
formatNumber(n) {
|
|
243
|
+
return n.toLocaleString("en-US");
|
|
244
|
+
}
|
|
245
|
+
toString() {
|
|
246
|
+
return `BlobStorage [ ${this._name} • ${this.sizeAsHumanReadableSync()} • ${this.countSync()} rows ]`;
|
|
247
|
+
}
|
|
248
|
+
}
|