@wxn0brp/db 0.4.1 → 0.5.1
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/dist/action.d.ts +5 -0
- package/dist/action.js +17 -0
- package/dist/client/database.d.ts +5 -0
- package/dist/client/database.js +6 -0
- package/dist/database.d.ts +10 -2
- package/dist/database.js +46 -17
- package/dist/file/customFileCpu.d.ts +2 -0
- package/dist/file/customFileCpu.js +3 -0
- package/dist/file/index.js +3 -1
- package/dist/file/transactions.d.ts +3 -0
- package/dist/file/transactions.js +119 -0
- package/dist/index.d.ts +15 -8
- package/dist/index.js +2 -2
- package/dist/memory.d.ts +4 -0
- package/dist/memory.js +16 -0
- package/dist/relation.d.ts +23 -27
- package/dist/relation.js +70 -52
- package/dist/types/fileCpu.d.ts +8 -0
- package/dist/types/transactions.d.ts +10 -0
- package/dist/types/transactions.js +1 -0
- package/package.json +1 -1
package/dist/action.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Context } from "./types/types.js";
|
|
|
4
4
|
import { SearchOptions } from "./types/searchOpts.js";
|
|
5
5
|
import Data from "./types/data.js";
|
|
6
6
|
import FileCpu from "./types/fileCpu.js";
|
|
7
|
+
import { Transaction } from "./types/transactions.js";
|
|
7
8
|
/**
|
|
8
9
|
* A class representing database actions on files.
|
|
9
10
|
* @class
|
|
@@ -64,5 +65,9 @@ declare class dbActionC {
|
|
|
64
65
|
* Removes a database collection from the file system.
|
|
65
66
|
*/
|
|
66
67
|
removeCollection(collection: string): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Apply a series of transactions to a database collection.
|
|
70
|
+
*/
|
|
71
|
+
transaction(collection: string, transactions: Transaction[]): Promise<void>;
|
|
67
72
|
}
|
|
68
73
|
export default dbActionC;
|
package/dist/action.js
CHANGED
|
@@ -156,6 +156,23 @@ class dbActionC {
|
|
|
156
156
|
async removeCollection(collection) {
|
|
157
157
|
await promises.rm(this.folder + "/" + collection, { recursive: true, force: true });
|
|
158
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Apply a series of transactions to a database collection.
|
|
161
|
+
*/
|
|
162
|
+
async transaction(collection, transactions) {
|
|
163
|
+
await this.checkCollection(collection);
|
|
164
|
+
const files = await getSortedFiles(this._getCollectionPath(collection));
|
|
165
|
+
if (files.length == 0) {
|
|
166
|
+
await promises.writeFile(this._getCollectionPath(collection) + "1.db", "");
|
|
167
|
+
files.push("1.db");
|
|
168
|
+
}
|
|
169
|
+
for (const file of files) {
|
|
170
|
+
await this.fileCpu.transactions(this._getCollectionPath(collection) + file, transactions);
|
|
171
|
+
}
|
|
172
|
+
console.log("Transactions applied successfully.");
|
|
173
|
+
console.log("Files:", files);
|
|
174
|
+
console.log("Transactions:", transactions);
|
|
175
|
+
}
|
|
159
176
|
}
|
|
160
177
|
/**
|
|
161
178
|
* Get the last file in the specified directory.
|
|
@@ -4,6 +4,7 @@ import { Arg, Search, Updater } from "../types/arg.js";
|
|
|
4
4
|
import { DbFindOpts, FindOpts } from "../types/options.js";
|
|
5
5
|
import { Context } from "../types/types.js";
|
|
6
6
|
import Data from "../types/data.js";
|
|
7
|
+
import { Transaction } from "../types/transactions.js";
|
|
7
8
|
/**
|
|
8
9
|
* Represents a database management class for performing CRUD operations.
|
|
9
10
|
* Uses a remote database.
|
|
@@ -68,5 +69,9 @@ declare class DataBaseRemote {
|
|
|
68
69
|
* Removes a database collection from the file system.
|
|
69
70
|
*/
|
|
70
71
|
removeCollection(name: string): Promise<boolean>;
|
|
72
|
+
/**
|
|
73
|
+
* Execute a transaction.
|
|
74
|
+
*/
|
|
75
|
+
transaction(collection: string, transaction: Transaction[]): Promise<boolean>;
|
|
71
76
|
}
|
|
72
77
|
export default DataBaseRemote;
|
package/dist/client/database.js
CHANGED
|
@@ -110,5 +110,11 @@ class DataBaseRemote {
|
|
|
110
110
|
async removeCollection(name) {
|
|
111
111
|
return await this._request("removeCollection", [name]);
|
|
112
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Execute a transaction.
|
|
115
|
+
*/
|
|
116
|
+
async transaction(collection, transaction) {
|
|
117
|
+
return await this._request("transaction", [collection, transaction]);
|
|
118
|
+
}
|
|
113
119
|
}
|
|
114
120
|
export default DataBaseRemote;
|
package/dist/database.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ import { Arg, Search, Updater } from "./types/arg.js";
|
|
|
6
6
|
import Data from "./types/data.js";
|
|
7
7
|
import { Context } from "./types/types.js";
|
|
8
8
|
import FileCpu from "./types/fileCpu.js";
|
|
9
|
+
import { Transaction } from "./types/transactions.js";
|
|
10
|
+
import { EventEmitter } from "events";
|
|
9
11
|
/**
|
|
10
12
|
* Represents a database management class for performing CRUD operations.
|
|
11
13
|
* @class
|
|
@@ -13,7 +15,9 @@ import FileCpu from "./types/fileCpu.js";
|
|
|
13
15
|
declare class DataBase {
|
|
14
16
|
dbAction: dbActionC;
|
|
15
17
|
executor: executorC;
|
|
18
|
+
emiter: EventEmitter;
|
|
16
19
|
constructor(folder: string, options?: DbOpts, fileCpu?: FileCpu);
|
|
20
|
+
private execute;
|
|
17
21
|
/**
|
|
18
22
|
* Create a new instance of a CollectionManager class.
|
|
19
23
|
*/
|
|
@@ -25,7 +29,7 @@ declare class DataBase {
|
|
|
25
29
|
/**
|
|
26
30
|
* Check and create the specified collection if it doesn't exist.
|
|
27
31
|
*/
|
|
28
|
-
checkCollection(collection: string): Promise<
|
|
32
|
+
checkCollection(collection: string): Promise<boolean>;
|
|
29
33
|
/**
|
|
30
34
|
* Check if a collection exists.
|
|
31
35
|
*/
|
|
@@ -65,6 +69,10 @@ declare class DataBase {
|
|
|
65
69
|
/**
|
|
66
70
|
* Removes a database collection from the file system.
|
|
67
71
|
*/
|
|
68
|
-
removeCollection(collection: string): Promise<
|
|
72
|
+
removeCollection(collection: string): Promise<boolean>;
|
|
73
|
+
/**
|
|
74
|
+
* Execute a transaction.
|
|
75
|
+
*/
|
|
76
|
+
transaction(collection: string, transaction: Transaction[]): Promise<boolean>;
|
|
69
77
|
}
|
|
70
78
|
export default DataBase;
|
package/dist/database.js
CHANGED
|
@@ -2,6 +2,7 @@ import dbActionC from "./action.js";
|
|
|
2
2
|
import executorC from "./executor.js";
|
|
3
3
|
import CollectionManager from "./CollectionManager.js";
|
|
4
4
|
import vFileCpu from "./file/index.js";
|
|
5
|
+
import { EventEmitter } from "events";
|
|
5
6
|
/**
|
|
6
7
|
* Represents a database management class for performing CRUD operations.
|
|
7
8
|
* @class
|
|
@@ -9,11 +10,21 @@ import vFileCpu from "./file/index.js";
|
|
|
9
10
|
class DataBase {
|
|
10
11
|
dbAction;
|
|
11
12
|
executor;
|
|
13
|
+
emiter;
|
|
12
14
|
constructor(folder, options = {}, fileCpu) {
|
|
13
15
|
if (!fileCpu)
|
|
14
16
|
fileCpu = vFileCpu;
|
|
15
17
|
this.dbAction = options.dbAction || new dbActionC(folder, options, fileCpu);
|
|
16
18
|
this.executor = options.executor || new executorC();
|
|
19
|
+
this.emiter = new EventEmitter();
|
|
20
|
+
}
|
|
21
|
+
async execute(name, ...args) {
|
|
22
|
+
const result = await this.executor.addOp(this.dbAction[name].bind(this.dbAction), ...args);
|
|
23
|
+
if (this.emiter.listeners(name).length !== 0)
|
|
24
|
+
this.emiter.emit(name, args, result);
|
|
25
|
+
if (this.emiter.listeners("*").length !== 0)
|
|
26
|
+
this.emiter.emit("*", name, args, result);
|
|
27
|
+
return result;
|
|
17
28
|
}
|
|
18
29
|
/**
|
|
19
30
|
* Create a new instance of a CollectionManager class.
|
|
@@ -25,61 +36,61 @@ class DataBase {
|
|
|
25
36
|
* Get the names of all available databases.
|
|
26
37
|
*/
|
|
27
38
|
async getCollections() {
|
|
28
|
-
return await this.
|
|
39
|
+
return await this.execute("getCollections");
|
|
29
40
|
}
|
|
30
41
|
/**
|
|
31
42
|
* Check and create the specified collection if it doesn't exist.
|
|
32
43
|
*/
|
|
33
44
|
async checkCollection(collection) {
|
|
34
|
-
await this.
|
|
45
|
+
return await this.execute("checkCollection", collection);
|
|
35
46
|
}
|
|
36
47
|
/**
|
|
37
48
|
* Check if a collection exists.
|
|
38
49
|
*/
|
|
39
50
|
async issetCollection(collection) {
|
|
40
|
-
return await this.
|
|
51
|
+
return await this.execute("issetCollection", collection);
|
|
41
52
|
}
|
|
42
53
|
/**
|
|
43
54
|
* Add data to a database.
|
|
44
55
|
*/
|
|
45
56
|
async add(collection, data, id_gen = true) {
|
|
46
|
-
return await this.
|
|
57
|
+
return await this.execute("add", collection, data, id_gen);
|
|
47
58
|
}
|
|
48
59
|
/**
|
|
49
60
|
* Find data in a database.
|
|
50
61
|
*/
|
|
51
62
|
async find(collection, search, context = {}, options = {}, findOpts = {}) {
|
|
52
|
-
return await this.
|
|
63
|
+
return await this.execute("find", collection, search, context, options, findOpts);
|
|
53
64
|
}
|
|
54
65
|
/**
|
|
55
66
|
* Find one data entry in a database.
|
|
56
67
|
*/
|
|
57
68
|
async findOne(collection, search, context = {}, findOpts = {}) {
|
|
58
|
-
return await this.
|
|
69
|
+
return await this.execute("findOne", collection, search, context, findOpts);
|
|
59
70
|
}
|
|
60
71
|
/**
|
|
61
72
|
* Update data in a database.
|
|
62
73
|
*/
|
|
63
74
|
async update(collection, search, updater, context = {}) {
|
|
64
|
-
return await this.
|
|
75
|
+
return await this.execute("update", collection, search, updater, context);
|
|
65
76
|
}
|
|
66
77
|
/**
|
|
67
78
|
* Update one data entry in a database.
|
|
68
79
|
*/
|
|
69
80
|
async updateOne(collection, search, updater, context = {}) {
|
|
70
|
-
return await this.
|
|
81
|
+
return await this.execute("updateOne", collection, search, updater, context);
|
|
71
82
|
}
|
|
72
83
|
/**
|
|
73
84
|
* Remove data from a database.
|
|
74
85
|
*/
|
|
75
86
|
async remove(collection, search, context = {}) {
|
|
76
|
-
return await this.
|
|
87
|
+
return await this.execute("remove", collection, search, context);
|
|
77
88
|
}
|
|
78
89
|
/**
|
|
79
90
|
* Remove one data entry from a database.
|
|
80
91
|
*/
|
|
81
92
|
async removeOne(collection, search, context = {}) {
|
|
82
|
-
return await this.
|
|
93
|
+
return await this.execute("removeOne", collection, search, context);
|
|
83
94
|
}
|
|
84
95
|
/**
|
|
85
96
|
* Asynchronously updates one entry in a database or adds a new one if it doesn't exist.
|
|
@@ -88,12 +99,24 @@ class DataBase {
|
|
|
88
99
|
const res = await this.updateOne(collection, search, updater, context);
|
|
89
100
|
if (!res) {
|
|
90
101
|
const assignData = [];
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
function assignDataPush(data) {
|
|
103
|
+
if (typeof data !== "object" || Array.isArray(data))
|
|
104
|
+
return;
|
|
105
|
+
const obj = {};
|
|
106
|
+
for (const key of Object.keys(data)) {
|
|
107
|
+
if (key.startsWith("$")) {
|
|
108
|
+
Object.keys(data[key]).forEach((k) => {
|
|
109
|
+
obj[k] = data[key][k];
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
else
|
|
113
|
+
obj[key] = data[key];
|
|
114
|
+
}
|
|
115
|
+
assignData.push(obj);
|
|
116
|
+
}
|
|
117
|
+
assignDataPush(search);
|
|
118
|
+
assignDataPush(updater);
|
|
119
|
+
assignDataPush(add_arg);
|
|
97
120
|
await this.add(collection, Object.assign({}, ...assignData), id_gen);
|
|
98
121
|
}
|
|
99
122
|
return res;
|
|
@@ -102,7 +125,13 @@ class DataBase {
|
|
|
102
125
|
* Removes a database collection from the file system.
|
|
103
126
|
*/
|
|
104
127
|
async removeCollection(collection) {
|
|
105
|
-
await this.
|
|
128
|
+
return await this.execute("removeCollection", collection);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Execute a transaction.
|
|
132
|
+
*/
|
|
133
|
+
async transaction(collection, transaction) {
|
|
134
|
+
return await this.execute("transaction", collection, transaction);
|
|
106
135
|
}
|
|
107
136
|
}
|
|
108
137
|
export default DataBase;
|
|
@@ -3,6 +3,7 @@ import { Search, Updater } from "../types/arg.js";
|
|
|
3
3
|
import Data from "../types/data.js";
|
|
4
4
|
import FileCpu from "../types/fileCpu.js";
|
|
5
5
|
import { FindOpts } from "../types/options.js";
|
|
6
|
+
import { Transaction } from "../types/transactions.js";
|
|
6
7
|
export type WriteFile = (file: string, data: any[]) => Promise<void>;
|
|
7
8
|
export type ReadFile = (file: string) => Promise<any[]>;
|
|
8
9
|
declare class CustomFileCpu implements FileCpu {
|
|
@@ -14,5 +15,6 @@ declare class CustomFileCpu implements FileCpu {
|
|
|
14
15
|
findOne(file: string, arg: Search, context?: Context, findOpts?: FindOpts): Promise<any | false>;
|
|
15
16
|
remove(file: string, one: boolean, arg: Search, context?: Context): Promise<boolean>;
|
|
16
17
|
update(file: string, one: boolean, arg: Search, updater: Updater, context?: Context): Promise<boolean>;
|
|
18
|
+
transactions(file: string, transactions: Transaction[]): Promise<void>;
|
|
17
19
|
}
|
|
18
20
|
export default CustomFileCpu;
|
package/dist/file/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import remove from "./remove.js";
|
|
|
3
3
|
import { find, findOne } from "./find.js";
|
|
4
4
|
import { appendFileSync } from "fs";
|
|
5
5
|
import { stringify } from "../format.js";
|
|
6
|
+
import transactions from "./transactions.js";
|
|
6
7
|
const vFileCpu = {
|
|
7
8
|
add: async (file, data) => {
|
|
8
9
|
const dataString = stringify(data);
|
|
@@ -11,6 +12,7 @@ const vFileCpu = {
|
|
|
11
12
|
find,
|
|
12
13
|
findOne,
|
|
13
14
|
update,
|
|
14
|
-
remove
|
|
15
|
+
remove,
|
|
16
|
+
transactions
|
|
15
17
|
};
|
|
16
18
|
export default vFileCpu;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { existsSync, promises } from "fs";
|
|
2
|
+
import { parse, stringify } from "../format.js";
|
|
3
|
+
import genId from "../gen.js";
|
|
4
|
+
import hasFieldsAdvanced from "../utils/hasFieldsAdvanced.js";
|
|
5
|
+
import updateObjectAdvanced from "../utils/updateObject.js";
|
|
6
|
+
import { createRL, pathRepair } from "./utils.js";
|
|
7
|
+
async function processTransactions(file, transactions) {
|
|
8
|
+
file = pathRepair(file);
|
|
9
|
+
const tempFile = file + ".tmp";
|
|
10
|
+
const processedTransactions = transactions.map(t => ({
|
|
11
|
+
...t,
|
|
12
|
+
applied: false
|
|
13
|
+
}));
|
|
14
|
+
if (existsSync(file)) {
|
|
15
|
+
await promises.copyFile(file, tempFile);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
await promises.writeFile(file, "");
|
|
19
|
+
await promises.writeFile(tempFile, "");
|
|
20
|
+
}
|
|
21
|
+
await promises.writeFile(file, "");
|
|
22
|
+
const rl = createRL(tempFile);
|
|
23
|
+
for await (const line of rl) {
|
|
24
|
+
const originalLine = line.trim();
|
|
25
|
+
if (!originalLine)
|
|
26
|
+
continue;
|
|
27
|
+
let data = parse(originalLine);
|
|
28
|
+
let shouldRemove = false;
|
|
29
|
+
let modified = false;
|
|
30
|
+
for (const transaction of processedTransactions) {
|
|
31
|
+
if (shouldRemove)
|
|
32
|
+
break;
|
|
33
|
+
let matches = false;
|
|
34
|
+
if (typeof transaction.search === 'function') {
|
|
35
|
+
matches = transaction.search(data, transaction.context || {}) || false;
|
|
36
|
+
}
|
|
37
|
+
else if (typeof transaction.search === 'object') {
|
|
38
|
+
matches = hasFieldsAdvanced(data, transaction.search);
|
|
39
|
+
}
|
|
40
|
+
if (!matches)
|
|
41
|
+
continue;
|
|
42
|
+
switch (transaction.type) {
|
|
43
|
+
case 'update':
|
|
44
|
+
if (transaction.updater) {
|
|
45
|
+
data = applyUpdater(data, transaction.updater, transaction.context || {});
|
|
46
|
+
modified = true;
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
case 'updateOne':
|
|
50
|
+
if (!transaction.applied && transaction.updater) {
|
|
51
|
+
data = applyUpdater(data, transaction.updater, transaction.context || {});
|
|
52
|
+
modified = true;
|
|
53
|
+
transaction.applied = true;
|
|
54
|
+
}
|
|
55
|
+
break;
|
|
56
|
+
case 'updateOneOrAdd':
|
|
57
|
+
if (!transaction.applied && transaction.updater) {
|
|
58
|
+
data = applyUpdater(data, transaction.updater, transaction.context || {});
|
|
59
|
+
modified = true;
|
|
60
|
+
transaction.applied = true;
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
case 'remove':
|
|
64
|
+
shouldRemove = true;
|
|
65
|
+
modified = true;
|
|
66
|
+
break;
|
|
67
|
+
case 'removeOne':
|
|
68
|
+
if (!transaction.applied) {
|
|
69
|
+
shouldRemove = true;
|
|
70
|
+
modified = true;
|
|
71
|
+
transaction.applied = true;
|
|
72
|
+
}
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (!shouldRemove) {
|
|
77
|
+
const outputLine = modified ? await stringify(data) : originalLine;
|
|
78
|
+
await promises.appendFile(file, outputLine + "\n");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
for (const transaction of processedTransactions) {
|
|
82
|
+
if (transaction.type === 'updateOneOrAdd' && !transaction.applied) {
|
|
83
|
+
const assignData = [];
|
|
84
|
+
if (typeof transaction.search === 'object' && !Array.isArray(transaction.search)) {
|
|
85
|
+
assignData.push(transaction.search);
|
|
86
|
+
}
|
|
87
|
+
if (transaction.updater && typeof transaction.updater === 'object' && !Array.isArray(transaction.updater)) {
|
|
88
|
+
const newData = {};
|
|
89
|
+
Object.keys(transaction.updater).filter(key => !key.startsWith('$')).forEach(key => newData[key] = transaction.updater[key]);
|
|
90
|
+
assignData.push(newData);
|
|
91
|
+
}
|
|
92
|
+
if (transaction.addArg && typeof transaction.addArg === 'object' && !Array.isArray(transaction.addArg)) {
|
|
93
|
+
assignData.push(transaction.addArg);
|
|
94
|
+
}
|
|
95
|
+
let newData = Object.assign({}, ...assignData);
|
|
96
|
+
if (transaction.updater && typeof transaction.updater === 'object' && !Array.isArray(transaction.updater)) {
|
|
97
|
+
newData = applyUpdater(newData, transaction.updater, transaction.context || {});
|
|
98
|
+
}
|
|
99
|
+
await add(file, newData, transaction.idGen !== false);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
await promises.unlink(tempFile);
|
|
103
|
+
}
|
|
104
|
+
function applyUpdater(data, updater, context = {}) {
|
|
105
|
+
if (typeof updater === 'function') {
|
|
106
|
+
const result = updater(data, context);
|
|
107
|
+
return data === null ? result : (result || data);
|
|
108
|
+
}
|
|
109
|
+
if (typeof updater === 'object' && !Array.isArray(updater)) {
|
|
110
|
+
return updateObjectAdvanced(data || {}, updater);
|
|
111
|
+
}
|
|
112
|
+
return data;
|
|
113
|
+
}
|
|
114
|
+
async function add(file, data, idGen) {
|
|
115
|
+
if (idGen && !data._id)
|
|
116
|
+
data._id = genId();
|
|
117
|
+
await promises.appendFile(file, await stringify(data) + "\n");
|
|
118
|
+
}
|
|
119
|
+
export default processTransactions;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,11 +5,18 @@ import GraphRemote from "./client/graph.js";
|
|
|
5
5
|
import genId from "./gen.js";
|
|
6
6
|
import Relation from "./relation.js";
|
|
7
7
|
import CustomFileCpu from "./file/customFileCpu.js";
|
|
8
|
-
import ValtheraMemory from "./memory.js";
|
|
9
|
-
export { DataBase
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
import ValtheraMemory, { createMemoryValthera } from "./memory.js";
|
|
9
|
+
export { DataBase as Valthera, Graph, DataBaseRemote as ValtheraRemote, GraphRemote, Relation, genId, CustomFileCpu, ValtheraMemory, createMemoryValthera };
|
|
10
|
+
export type Id = import("./types/Id.js").Id;
|
|
11
|
+
export declare namespace ValtheraTypes {
|
|
12
|
+
type Arg = import("./types/arg.js").Arg;
|
|
13
|
+
type Search = import("./types/arg.js").Search;
|
|
14
|
+
type Updater = import("./types/arg.js").Updater;
|
|
15
|
+
type DbFindOpts = import("./types/options.js").DbFindOpts;
|
|
16
|
+
type FindOpts = import("./types/options.js").FindOpts;
|
|
17
|
+
type DbOpts = import("./types/options.js").DbOpts;
|
|
18
|
+
type Data = import("./types/data.js").Data;
|
|
19
|
+
type SearchOptions = import("./types/searchOpts.js").SearchOptions;
|
|
20
|
+
}
|
|
21
|
+
import type { RelationTypes } from "./relation.js";
|
|
22
|
+
export type { RelationTypes };
|
package/dist/index.js
CHANGED
|
@@ -5,5 +5,5 @@ import GraphRemote from "./client/graph.js";
|
|
|
5
5
|
import genId from "./gen.js";
|
|
6
6
|
import Relation from "./relation.js";
|
|
7
7
|
import CustomFileCpu from "./file/customFileCpu.js";
|
|
8
|
-
import ValtheraMemory from "./memory.js";
|
|
9
|
-
export { DataBase
|
|
8
|
+
import ValtheraMemory, { createMemoryValthera } from "./memory.js";
|
|
9
|
+
export { DataBase as Valthera, Graph, DataBaseRemote as ValtheraRemote, GraphRemote, Relation, genId, CustomFileCpu, ValtheraMemory, createMemoryValthera };
|
package/dist/memory.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import DataBase from "./database.js";
|
|
2
|
+
import Data from "./types/data.js";
|
|
2
3
|
export default class ValtheraMemory extends DataBase {
|
|
3
4
|
constructor(...args: any[]);
|
|
4
5
|
}
|
|
6
|
+
export declare function createMemoryValthera(data?: {
|
|
7
|
+
[key: string]: Data[];
|
|
8
|
+
}): ValtheraMemory;
|
package/dist/memory.js
CHANGED
|
@@ -114,9 +114,25 @@ class MemoryAction {
|
|
|
114
114
|
async removeCollection(collection) {
|
|
115
115
|
this.memory.delete(collection);
|
|
116
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Executes a list of transactions on the specified database collection.
|
|
119
|
+
* @throws Error - Method not supported in memory.
|
|
120
|
+
*/
|
|
121
|
+
transaction(collection, transactions) {
|
|
122
|
+
throw new Error("Method not supported in memory.");
|
|
123
|
+
}
|
|
117
124
|
}
|
|
118
125
|
export default class ValtheraMemory extends DataBase {
|
|
119
126
|
constructor(...args) {
|
|
120
127
|
super("", { dbAction: new MemoryAction() });
|
|
121
128
|
}
|
|
122
129
|
}
|
|
130
|
+
export function createMemoryValthera(data) {
|
|
131
|
+
const db = new ValtheraMemory();
|
|
132
|
+
if (!data)
|
|
133
|
+
return db;
|
|
134
|
+
for (const collection of Object.keys(data)) {
|
|
135
|
+
db.dbAction.memory.set(collection, data[collection]);
|
|
136
|
+
}
|
|
137
|
+
return db;
|
|
138
|
+
}
|
package/dist/relation.d.ts
CHANGED
|
@@ -1,34 +1,30 @@
|
|
|
1
1
|
import DataBase from "./database.js";
|
|
2
2
|
import { Search } from "./types/arg.js";
|
|
3
3
|
import { DbFindOpts } from "./types/options.js";
|
|
4
|
-
export
|
|
5
|
-
[
|
|
6
|
-
|
|
7
|
-
interface
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
export declare namespace RelationTypes {
|
|
5
|
+
type Path = [string, string];
|
|
6
|
+
type FieldPath = string[];
|
|
7
|
+
interface DBS {
|
|
8
|
+
[key: string]: DataBase;
|
|
9
|
+
}
|
|
10
|
+
interface Relation {
|
|
11
|
+
[key: string]: RelationConfig;
|
|
12
|
+
}
|
|
13
|
+
interface RelationConfig {
|
|
14
|
+
path: Path;
|
|
15
|
+
pk?: string;
|
|
16
|
+
fk?: string;
|
|
17
|
+
as?: string;
|
|
18
|
+
select?: string[];
|
|
19
|
+
findOpts?: DbFindOpts;
|
|
20
|
+
type?: "1" | "1n" | "nm";
|
|
21
|
+
relations?: Relation;
|
|
22
|
+
}
|
|
13
23
|
}
|
|
14
24
|
declare class Relation {
|
|
15
|
-
|
|
16
|
-
constructor(
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*/
|
|
20
|
-
private _resolvePath;
|
|
21
|
-
/**
|
|
22
|
-
* Processes relations for a single item.
|
|
23
|
-
*/
|
|
24
|
-
private _processItemRelations;
|
|
25
|
-
/**
|
|
26
|
-
* Finds multiple items with relations.
|
|
27
|
-
*/
|
|
28
|
-
find(path: string, search: Search, relations?: Record<string, RelationConfig>, options?: DbFindOpts): Promise<Record<string, any>[]>;
|
|
29
|
-
/**
|
|
30
|
-
* Finds a single item with relations.
|
|
31
|
-
*/
|
|
32
|
-
findOne(path: string, search: Search, relations?: Record<string, RelationConfig>): Promise<Record<string, any> | null>;
|
|
25
|
+
dbs: RelationTypes.DBS;
|
|
26
|
+
constructor(dbs: RelationTypes.DBS);
|
|
27
|
+
findOne(path: RelationTypes.Path, search: Search, relations: RelationTypes.Relation, select: RelationTypes.FieldPath[]): Promise<any>;
|
|
28
|
+
find(path: RelationTypes.Path, search: Search, relations: RelationTypes.Relation, select: RelationTypes.FieldPath[], findOpts?: DbFindOpts): Promise<any[]>;
|
|
33
29
|
}
|
|
34
30
|
export default Relation;
|
package/dist/relation.js
CHANGED
|
@@ -1,62 +1,80 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
throw new Error(`Invalid path format "${path}". Expected format 'dbName.collectionName'.`);
|
|
12
|
-
}
|
|
13
|
-
const sanitizedPath = path.replace(/\\\./g, "\uffff");
|
|
14
|
-
const [dbName, collectionName] = sanitizedPath.split(".", 2).map(part => part.replace(/\uffff/g, "."));
|
|
15
|
-
const db = this.databases[dbName];
|
|
16
|
-
if (!db) {
|
|
17
|
-
throw new Error(`Database "${dbName}" not found.`);
|
|
18
|
-
}
|
|
19
|
-
return { db, collection: collectionName };
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Processes relations for a single item.
|
|
23
|
-
*/
|
|
24
|
-
async _processItemRelations(item, relations) {
|
|
25
|
-
if (!item || typeof item !== "object")
|
|
26
|
-
return item;
|
|
27
|
-
const result = { ...item };
|
|
28
|
-
for (const [field, relationConfig] of Object.entries(relations)) {
|
|
29
|
-
if (!relationConfig.from || !relationConfig.localField || !relationConfig.foreignField) {
|
|
30
|
-
console.warn(`Skipping invalid relation configuration for field: "${field}"`);
|
|
1
|
+
async function processRelations(dbs, cfg, data) {
|
|
2
|
+
for (const [key, relation] of Object.entries(cfg)) {
|
|
3
|
+
const { pk = "_id", fk = "_id", type = "1" } = relation;
|
|
4
|
+
if (type === "1") {
|
|
5
|
+
const db = dbs[relation.path[0]];
|
|
6
|
+
const collection = relation.path[1];
|
|
7
|
+
const item = await db.findOne(collection, { [fk]: data[pk] }, {}, { select: relation.select || null });
|
|
8
|
+
const field = relation.as || key;
|
|
9
|
+
if (!item) {
|
|
10
|
+
data[field] = null;
|
|
31
11
|
continue;
|
|
32
12
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
13
|
+
if (relation.relations) {
|
|
14
|
+
await processRelations(dbs, relation.relations, item);
|
|
15
|
+
}
|
|
16
|
+
data[field] = item;
|
|
17
|
+
}
|
|
18
|
+
else if (type === "1n") {
|
|
19
|
+
const db = dbs[relation.path[0]];
|
|
20
|
+
const collection = relation.path[1];
|
|
21
|
+
const items = await db.find(collection, { [fk]: data[pk] }, {}, relation.findOpts || {}, { select: relation.select || null });
|
|
22
|
+
const field = relation.as || key;
|
|
23
|
+
if (relation.relations) {
|
|
24
|
+
await Promise.all(items.map(item => processRelations(dbs, relation.relations, item)));
|
|
38
25
|
}
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
data[field] = items;
|
|
27
|
+
}
|
|
28
|
+
else if (type === "nm") {
|
|
29
|
+
const db = dbs[relation.path[0]];
|
|
30
|
+
const collection = relation.path[1];
|
|
31
|
+
const items = await db.find(collection, {}, {}, {}, { select: relation.select || null });
|
|
32
|
+
const field = relation.as || key;
|
|
33
|
+
if (relation.relations) {
|
|
34
|
+
await Promise.all(items.map(item => processRelations(dbs, relation.relations, item)));
|
|
41
35
|
}
|
|
36
|
+
data[field] = items;
|
|
42
37
|
}
|
|
43
|
-
|
|
38
|
+
else {
|
|
39
|
+
throw new Error(`Unknown relation type: ${relation.type}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function selectDataSelf(data, select) {
|
|
44
|
+
if (!data)
|
|
45
|
+
return null;
|
|
46
|
+
if (select.length === 0)
|
|
47
|
+
return data;
|
|
48
|
+
if (Array.isArray(data))
|
|
49
|
+
return data.map(item => selectDataSelf(item, select));
|
|
50
|
+
return selectDataSelf(data[select[0]], select.slice(1));
|
|
51
|
+
}
|
|
52
|
+
function selectData(data, select) {
|
|
53
|
+
if (select.length === 0)
|
|
54
|
+
return data;
|
|
55
|
+
const newData = {};
|
|
56
|
+
for (const field of select) {
|
|
57
|
+
const key = field.map(f => f.replaceAll(".", "\\.")).join(".");
|
|
58
|
+
newData[key] = selectDataSelf(data, field);
|
|
59
|
+
}
|
|
60
|
+
return newData;
|
|
61
|
+
}
|
|
62
|
+
class Relation {
|
|
63
|
+
dbs;
|
|
64
|
+
constructor(dbs) {
|
|
65
|
+
this.dbs = dbs;
|
|
44
66
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const items = await db.find(collection, search, {}, options);
|
|
51
|
-
return Promise.all(items.map(item => this._processItemRelations(item, relations)));
|
|
67
|
+
async findOne(path, search, relations, select) {
|
|
68
|
+
const db = this.dbs[path[0]];
|
|
69
|
+
const data = await db.findOne(path[1], search);
|
|
70
|
+
await processRelations(this.dbs, relations, data);
|
|
71
|
+
return selectData(data, select);
|
|
52
72
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const item = await db.findOne(collection, search);
|
|
59
|
-
return item ? this._processItemRelations(item, relations) : null;
|
|
73
|
+
async find(path, search, relations, select, findOpts = {}) {
|
|
74
|
+
const db = this.dbs[path[0]];
|
|
75
|
+
const data = await db.find(path[1], search, {}, findOpts);
|
|
76
|
+
await Promise.all(data.map(item => processRelations(this.dbs, relations, item)));
|
|
77
|
+
return data.map(item => selectData(item, select));
|
|
60
78
|
}
|
|
61
79
|
}
|
|
62
80
|
export default Relation;
|
package/dist/types/fileCpu.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Search, Updater } from "./arg.js";
|
|
2
2
|
import Data from "./data.js";
|
|
3
3
|
import { FindOpts } from "./options.js";
|
|
4
|
+
import { Transaction } from "./transactions.js";
|
|
4
5
|
import { Context } from "./types.js";
|
|
5
6
|
interface FileCpu {
|
|
6
7
|
/**
|
|
@@ -47,5 +48,12 @@ interface FileCpu {
|
|
|
47
48
|
* @returns A promise resolving to `true` if at least one entry was updated, otherwise `false`.
|
|
48
49
|
*/
|
|
49
50
|
update(file: string, one: boolean, arg: Search, updater: Updater, context?: Context): Promise<boolean>;
|
|
51
|
+
/**
|
|
52
|
+
* Executes a list of transactions on the specified database collection.
|
|
53
|
+
* @param file The path to the file.
|
|
54
|
+
* @param transactions An array of transactions to execute.
|
|
55
|
+
* @returns A promise resolved when all transactions have been executed.
|
|
56
|
+
*/
|
|
57
|
+
transactions(file: string, transactions: Transaction[]): Promise<void>;
|
|
50
58
|
}
|
|
51
59
|
export default FileCpu;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Arg, Search, Updater } from "./arg.js";
|
|
2
|
+
import { Context } from "./types.js";
|
|
3
|
+
export interface Transaction {
|
|
4
|
+
type: 'update' | 'updateOne' | 'updateOneOrAdd' | 'remove' | 'removeOne';
|
|
5
|
+
search: Search;
|
|
6
|
+
updater?: Updater;
|
|
7
|
+
addArg?: Arg;
|
|
8
|
+
idGen?: boolean;
|
|
9
|
+
context?: Context;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED