@wxn0brp/db 0.0.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/CollectionManager.js +119 -0
- package/LICENSE +21 -0
- package/README.md +194 -0
- package/action.js +250 -0
- package/cacheManager.js +83 -0
- package/database.js +208 -0
- package/executor.js +54 -0
- package/file/find.js +88 -0
- package/file/index.js +3 -0
- package/file/remove.js +75 -0
- package/file/update.js +83 -0
- package/file/utils.js +27 -0
- package/format.js +29 -0
- package/gen.js +97 -0
- package/graph.js +130 -0
- package/more.js +103 -0
- package/package.json +32 -0
- package/remote/client/database.js +229 -0
- package/remote/client/graph.js +139 -0
- package/remote/client/index.js +10 -0
- package/remote/server/auth.js +100 -0
- package/remote/server/db.js +197 -0
- package/remote/server/function.js +43 -0
- package/remote/server/graph.js +121 -0
- package/remote/server/gui/css/main.css +130 -0
- package/remote/server/gui/css/scrool.css +81 -0
- package/remote/server/gui/css/style.css +61 -0
- package/remote/server/gui/favicon.svg +12 -0
- package/remote/server/gui/html/data.html +15 -0
- package/remote/server/gui/html/main.html +46 -0
- package/remote/server/gui/html/nav.html +25 -0
- package/remote/server/gui/html/popup.html +51 -0
- package/remote/server/gui/index.html +49 -0
- package/remote/server/gui/js/api.js +166 -0
- package/remote/server/gui/js/index.js +17 -0
- package/remote/server/gui/js/loadHTML.js +16 -0
- package/remote/server/gui/js/popUp.js +72 -0
- package/remote/server/gui/js/queryApi.js +51 -0
- package/remote/server/gui/js/queryDb.js +79 -0
- package/remote/server/gui/js/queryGraph.js +144 -0
- package/remote/server/gui/js/render.js +64 -0
- package/remote/server/gui/js/templates.js +31 -0
- package/remote/server/gui/js/utils.js +36 -0
- package/remote/server/gui/js/vars.js +9 -0
- package/remote/server/gui/libs/core.js +176 -0
- package/remote/server/gui/libs/d3.v7.min.js +2 -0
- package/remote/server/gui/libs/handlebars.min.js +29 -0
- package/remote/server/gui/libs/json5.min.js +1 -0
- package/remote/server/index.js +63 -0
- package/remote/server/initDataBases.js +20 -0
- package/remote/server/pathUtils.js +7 -0
- package/remote/server/secret.js +23 -0
- package/remote/serverMgmt/index.js +86 -0
package/database.js
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import dbActionC from "./action.js";
|
|
2
|
+
import executorC from "./executor.js";
|
|
3
|
+
import CollectionManager from "./CollectionManager.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Represents a database management class for performing CRUD operations.
|
|
7
|
+
* @class
|
|
8
|
+
*/
|
|
9
|
+
class DataBase{
|
|
10
|
+
/**
|
|
11
|
+
* Create a new database instance.
|
|
12
|
+
* @constructor
|
|
13
|
+
* @param {string} folder - The folder path where the database files are stored.
|
|
14
|
+
* @param {object} [options] - The options object.
|
|
15
|
+
* @param {number} [options.cacheThreshold=3] - The cache threshold for database entries (default: 3).
|
|
16
|
+
* @param {number} [options.cacheTTL=300000] - The time-to-live (TTL) for cached entries in milliseconds (default: 300,000 milliseconds or 5 minutes).
|
|
17
|
+
*/
|
|
18
|
+
constructor(folder, options={}){
|
|
19
|
+
options = {
|
|
20
|
+
cacheThreshold: 3,
|
|
21
|
+
cacheTTL: 300_000,
|
|
22
|
+
...options
|
|
23
|
+
}
|
|
24
|
+
this.dbAction = new dbActionC(folder, options);
|
|
25
|
+
this.executor = new executorC();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Create a new instance of a CollectionManager class.
|
|
30
|
+
* @function
|
|
31
|
+
* @param {string} collection - The name of the collection.
|
|
32
|
+
* @returns {CollectionManager} A new instance of CollectionManager.
|
|
33
|
+
*/
|
|
34
|
+
c(collection){
|
|
35
|
+
return new CollectionManager(this, collection);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get the names of all available databases.
|
|
40
|
+
*
|
|
41
|
+
* @function
|
|
42
|
+
* @returns {string[]} An array of database names.
|
|
43
|
+
*/
|
|
44
|
+
async getCollections(){
|
|
45
|
+
return await this.dbAction.getCollections();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check and create the specified collection if it doesn't exist.
|
|
50
|
+
*
|
|
51
|
+
* @function
|
|
52
|
+
* @param {string} collection - The collection to check.
|
|
53
|
+
*/
|
|
54
|
+
async checkCollection(collection){
|
|
55
|
+
await this.dbAction.checkCollection(collection);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Check if a collection exists.
|
|
60
|
+
*
|
|
61
|
+
* @function
|
|
62
|
+
* @param {string} collection - The name of the collection.
|
|
63
|
+
* @returns {boolean} True if the collection exists, false otherwise.
|
|
64
|
+
*/
|
|
65
|
+
async issetCollection(collection){
|
|
66
|
+
return await this.dbAction.issetCollection(collection);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Add data to a database.
|
|
71
|
+
*
|
|
72
|
+
* @async
|
|
73
|
+
* @function
|
|
74
|
+
* @param {string} collection - The name of the collection.
|
|
75
|
+
* @param {Object} data - The data to add.
|
|
76
|
+
* @param {boolean} id_gen - Whether to generate an ID for the entry. Default is true.
|
|
77
|
+
* @returns {Promise<Object>} A Promise that resolves with the added data.
|
|
78
|
+
*/
|
|
79
|
+
async add(collection, data, id_gen=true){
|
|
80
|
+
return await this.executor.addOp(this.dbAction.add.bind(this.dbAction), collection, data, id_gen);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Find data in a database.
|
|
85
|
+
*
|
|
86
|
+
* @async
|
|
87
|
+
* @function
|
|
88
|
+
* @param {string} collection - Name of the database collection.
|
|
89
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
90
|
+
* @param {Object} context - The context object (for functions).
|
|
91
|
+
* @param {Object} options - The options for the search.
|
|
92
|
+
* @param {number} options.max - The maximum number of entries to return. Default is -1, meaning no limit.
|
|
93
|
+
* @param {boolean} options.reverse - Whether to reverse the order of returned entries. Default is false.
|
|
94
|
+
* @param {Object} findOpts - Update result object with findOpts options.
|
|
95
|
+
* @returns {Promise<Array<Object>>} A Promise that resolves with the matching data.
|
|
96
|
+
*/
|
|
97
|
+
async find(collection, search, context={}, options={}, findOpts={}){
|
|
98
|
+
return await this.executor.addOp(this.dbAction.find.bind(this.dbAction), collection, search, context, options, findOpts);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Find one data entry in a database.
|
|
103
|
+
*
|
|
104
|
+
* @async
|
|
105
|
+
* @function
|
|
106
|
+
* @param {string} collection - Name of the database collection.
|
|
107
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
108
|
+
* @param {Object} context - The context object (for functions).
|
|
109
|
+
* @param {Object} findOpts - Update result object with findOpts options.
|
|
110
|
+
* @returns {Promise<Object|null>} A Promise that resolves with the first matching data entry.
|
|
111
|
+
*/
|
|
112
|
+
async findOne(collection, search, context={}, findOpts={}){
|
|
113
|
+
return await this.executor.addOp(this.dbAction.findOne.bind(this.dbAction), collection, search, context, findOpts);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Update data in a database.
|
|
118
|
+
*
|
|
119
|
+
* @async
|
|
120
|
+
* @function
|
|
121
|
+
* @param {string} collection - Name of the database collection.
|
|
122
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
123
|
+
* @param {function|Object} arg - Update arguments.
|
|
124
|
+
* @param {Object} context - The context object (for functions).
|
|
125
|
+
* @returns {Promise<boolean>} A Promise that resolves when the data is updated.
|
|
126
|
+
*/
|
|
127
|
+
async update(collection, search, arg, context={}){
|
|
128
|
+
return await this.executor.addOp(this.dbAction.update.bind(this.dbAction), collection, search, arg, context);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Update one data entry in a database.
|
|
133
|
+
*
|
|
134
|
+
* @async
|
|
135
|
+
* @function
|
|
136
|
+
* @param {string} collection - Name of the database collection.
|
|
137
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
138
|
+
* @param {function|Object} arg - The query.
|
|
139
|
+
* @param {Object} context - The context object (for functions).
|
|
140
|
+
* @returns {Promise<boolean>} A Promise that resolves when the data entry is updated.
|
|
141
|
+
*/
|
|
142
|
+
async updateOne(collection, search, arg, context={}){
|
|
143
|
+
return await this.executor.addOp(this.dbAction.updateOne.bind(this.dbAction), collection, search, arg, context);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Remove data from a database.
|
|
148
|
+
*
|
|
149
|
+
* @async
|
|
150
|
+
* @function
|
|
151
|
+
* @param {string} collection - Name of the database collection.
|
|
152
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
153
|
+
* @param {Object} context - The context object (for functions).
|
|
154
|
+
* @returns {Promise<boolean>} A Promise that resolves when the data is removed.
|
|
155
|
+
*/
|
|
156
|
+
async remove(collection, search, context={}){
|
|
157
|
+
return await this.executor.addOp(this.dbAction.remove.bind(this.dbAction), collection, search, context);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Remove one data entry from a database.
|
|
162
|
+
*
|
|
163
|
+
* @async
|
|
164
|
+
* @function
|
|
165
|
+
* @param {string} collection - Name of the database collection.
|
|
166
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
167
|
+
* @param {Object} context - The context object (for functions).
|
|
168
|
+
* @returns {Promise<boolean>} A Promise that resolves when the data entry is removed.
|
|
169
|
+
*/
|
|
170
|
+
async removeOne(collection, search, context={}){
|
|
171
|
+
return await this.executor.addOp(this.dbAction.removeOne.bind(this.dbAction), collection, search, context);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Asynchronously updates one entry in a database or adds a new one if it doesn't exist.
|
|
176
|
+
*
|
|
177
|
+
* @param {string} collection - Name of the database collection.
|
|
178
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
179
|
+
* @param {function|Object} arg - The search criteria for the update.
|
|
180
|
+
* @param {function|Object} add_arg - The arguments to be added to the new entry.
|
|
181
|
+
* @param {Object} context - The context object (for functions).
|
|
182
|
+
* @param {boolean} id_gen - Whether to generate an ID for the entry. Default is true.
|
|
183
|
+
* @return {Promise<boolean>} A Promise that resolves to `true` if the entry was updated, or `false` if it was added.
|
|
184
|
+
*/
|
|
185
|
+
async updateOneOrAdd(collection, search, arg, add_arg={}, context={}, id_gen=true){
|
|
186
|
+
const res = await this.updateOne(collection, search, arg, context);
|
|
187
|
+
if(!res){
|
|
188
|
+
const assignData = [];
|
|
189
|
+
if(typeof search === "object" && !Array.isArray(search)) assignData.push(search);
|
|
190
|
+
if(typeof arg === "object" && !Array.isArray(arg)) assignData.push(arg);
|
|
191
|
+
if(typeof add_arg === "object" && !Array.isArray(add_arg)) assignData.push(add_arg);
|
|
192
|
+
await this.add(collection, Object.assign({}, ...assignData), id_gen);
|
|
193
|
+
}
|
|
194
|
+
return res;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Removes a database collection from the file system.
|
|
199
|
+
*
|
|
200
|
+
* @param {string} collection - The name of the collection to remove.
|
|
201
|
+
* @return {void}
|
|
202
|
+
*/
|
|
203
|
+
removeDb(collection){
|
|
204
|
+
this.dbAction.removeDb(collection);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export default DataBase;
|
package/executor.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple executor for queuing and executing asynchronous operations sequentially.
|
|
3
|
+
* @class
|
|
4
|
+
*/
|
|
5
|
+
class executorC{
|
|
6
|
+
/**
|
|
7
|
+
* Create a new executor instance.
|
|
8
|
+
* @constructor
|
|
9
|
+
*/
|
|
10
|
+
constructor(){
|
|
11
|
+
this.quote = [];
|
|
12
|
+
this.isExecuting = false;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Add an asynchronous operation to the execution queue.
|
|
17
|
+
*
|
|
18
|
+
* @async
|
|
19
|
+
* @function
|
|
20
|
+
* @param {Function} func - The asynchronous function to execute.
|
|
21
|
+
* @param {...*} param - Parameters to pass to the function.
|
|
22
|
+
* @returns {Promise} A Promise that resolves when the operation is executed.
|
|
23
|
+
*/
|
|
24
|
+
async addOp(func, ...param){
|
|
25
|
+
return await new Promise((resolve, reject) => {
|
|
26
|
+
this.quote.push({
|
|
27
|
+
func,
|
|
28
|
+
param,
|
|
29
|
+
resolve,
|
|
30
|
+
reject
|
|
31
|
+
});
|
|
32
|
+
this.execute();
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Execute the queued asynchronous operations sequentially.
|
|
38
|
+
*
|
|
39
|
+
* @async
|
|
40
|
+
* @function
|
|
41
|
+
*/
|
|
42
|
+
async execute(){
|
|
43
|
+
if(this.isExecuting) return;
|
|
44
|
+
this.isExecuting = true;
|
|
45
|
+
while(this.quote.length > 0){
|
|
46
|
+
let q = this.quote.shift();
|
|
47
|
+
let res = await q.func(...q.param);
|
|
48
|
+
q.resolve(res)
|
|
49
|
+
}
|
|
50
|
+
this.isExecuting = false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default executorC;
|
package/file/find.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { existsSync, promises } from "fs";
|
|
2
|
+
import { pathRepair, createRL } from "./utils.js";
|
|
3
|
+
import { parse } from "../format.js";
|
|
4
|
+
import { hasFieldsAdvanced, updateFindObject } from "../more.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Processes a line of text from a file and checks if it matches the search criteria.
|
|
8
|
+
* @private
|
|
9
|
+
* @param {function|Object} arg - The search criteria. It can be a function or an object.
|
|
10
|
+
* @param {string} line - The line of text from the file.
|
|
11
|
+
* @param {Object} context - The context object (for functions).
|
|
12
|
+
* @param {Object} findOpts - Update result object with findOpts options.
|
|
13
|
+
* @returns {Promise<Object|null>} A Promise that resolves to the matching object or null.
|
|
14
|
+
*/
|
|
15
|
+
async function findProcesLine(arg, line, context={}, findOpts={}){
|
|
16
|
+
const ob = parse(line);
|
|
17
|
+
let res = false;
|
|
18
|
+
|
|
19
|
+
if(typeof arg === "function"){
|
|
20
|
+
if(arg(ob, context)) res = true;
|
|
21
|
+
}else if(typeof arg === "object" && !Array.isArray(arg)){
|
|
22
|
+
if(hasFieldsAdvanced(ob, arg)) res = true;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if(res) return updateFindObject(ob, findOpts);
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Asynchronously finds entries in a file based on search criteria.
|
|
31
|
+
* @function
|
|
32
|
+
* @param {string} file - The file path to search in.
|
|
33
|
+
* @param {function|Object} arg - The search criteria. It can be a function or an object.
|
|
34
|
+
* @param {Object} context - The context object (for functions).
|
|
35
|
+
* @param {Object} findOpts - Update result object with findOpts options.
|
|
36
|
+
* @returns {Promise<Object[]>} A Promise that resolves to an array of matching objects.
|
|
37
|
+
*/
|
|
38
|
+
export async function find(file, arg, context={}, findOpts={}){
|
|
39
|
+
file = pathRepair(file);
|
|
40
|
+
return await new Promise(async (resolve) => {
|
|
41
|
+
if(!existsSync(file)){
|
|
42
|
+
await promises.writeFile(file, "");
|
|
43
|
+
resolve(false);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const rl = createRL(file);
|
|
47
|
+
const resF = [];
|
|
48
|
+
for await(const line of rl){
|
|
49
|
+
if(line == "" || !line) continue;
|
|
50
|
+
|
|
51
|
+
const res = await findProcesLine(arg, line, context, findOpts);
|
|
52
|
+
if(res) resF.push(res);
|
|
53
|
+
};
|
|
54
|
+
resolve(resF);
|
|
55
|
+
rl.close();
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Asynchronously finds one entry in a file based on search criteria.
|
|
61
|
+
* @function
|
|
62
|
+
* @param {string} file - The file path to search in.
|
|
63
|
+
* @param {function|Object} arg - The search criteria. It can be a function or an object.
|
|
64
|
+
* @param {Object} context - The context object (for functions).
|
|
65
|
+
* @param {Object} findOpts - Update result object with findOpts options.
|
|
66
|
+
* @returns {Promise<Object>} A Promise that resolves to the first matching object found or an empty array.
|
|
67
|
+
*/
|
|
68
|
+
export async function findOne(file, arg, context={}, findOpts={}){
|
|
69
|
+
file = pathRepair(file);
|
|
70
|
+
return await new Promise(async (resolve) => {
|
|
71
|
+
if(!existsSync(file)){
|
|
72
|
+
await promises.writeFile(file, "");
|
|
73
|
+
resolve(false);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const rl = createRL(file);
|
|
77
|
+
for await(const line of rl){
|
|
78
|
+
if(line == "" || !line) continue;
|
|
79
|
+
|
|
80
|
+
const res = await findProcesLine(arg, line, context, findOpts);
|
|
81
|
+
if(res){
|
|
82
|
+
resolve(res);
|
|
83
|
+
rl.close();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
resolve(false);
|
|
87
|
+
});
|
|
88
|
+
}
|
package/file/index.js
ADDED
package/file/remove.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { existsSync, promises, appendFileSync, readdirSync } from "fs";
|
|
2
|
+
import { pathRepair, createRL } from "./utils.js";
|
|
3
|
+
import { parse } from "../format.js";
|
|
4
|
+
import { hasFieldsAdvanced } from "../more.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Removes entries from a file based on search criteria.
|
|
8
|
+
* @private
|
|
9
|
+
* @param {string} file - The file path to remove entries from.
|
|
10
|
+
* @param {function|Object} search - The search criteria. It can be a function or an object.
|
|
11
|
+
* @param {Object} context - The context object (for functions).
|
|
12
|
+
* @param {boolean} [one=false] - Indicates whether to remove only one matching entry (default: false).
|
|
13
|
+
* @returns {Promise<boolean>} A Promise that resolves to `true` if entries were removed, or `false` otherwise.
|
|
14
|
+
*/
|
|
15
|
+
async function removeWorker(file, search, context={}, one=false){
|
|
16
|
+
file = pathRepair(file);
|
|
17
|
+
if(!existsSync(file)){
|
|
18
|
+
await promises.writeFile(file, "");
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
await promises.copyFile(file, file+".tmp");
|
|
22
|
+
await promises.writeFile(file, "");
|
|
23
|
+
|
|
24
|
+
const rl = createRL(file+".tmp");
|
|
25
|
+
|
|
26
|
+
let removed = false;
|
|
27
|
+
for await(let line of rl){
|
|
28
|
+
if(one && removed){
|
|
29
|
+
appendFileSync(file, line+"\n");
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const data = parse(line);
|
|
34
|
+
|
|
35
|
+
if(typeof search === "function"){
|
|
36
|
+
if(search(data, context)){
|
|
37
|
+
removed = true;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
}else if(typeof search === "object" && !Array.isArray(search)){
|
|
41
|
+
if(hasFieldsAdvanced(data, search)){
|
|
42
|
+
removed = true;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
appendFileSync(file, line+"\n");
|
|
48
|
+
}
|
|
49
|
+
await promises.writeFile(file+".tmp", "");
|
|
50
|
+
return removed;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Asynchronously removes entries from a file based on search criteria.
|
|
55
|
+
* @function
|
|
56
|
+
* @param {string} folder - The folder containing the file.
|
|
57
|
+
* @param {string} name - The name of the file to remove entries from.
|
|
58
|
+
* @param {function|Object} arg - The search criteria. It can be a function or an object.
|
|
59
|
+
* @param {Object} context - The context object (for functions).
|
|
60
|
+
* @param {boolean} one - Indicates whether to remove only one matching entry (default: false).
|
|
61
|
+
* @returns {Promise<boolean>} A Promise that resolves to `true` if entries were removed, or `false` otherwise.
|
|
62
|
+
*/
|
|
63
|
+
async function remove(folder, name, arg, context={}, one){
|
|
64
|
+
let files = readdirSync(folder + "/" + name).filter(file => !/\.tmp$/.test(file));
|
|
65
|
+
files.reverse();
|
|
66
|
+
let remove = false;
|
|
67
|
+
for(const file of files){
|
|
68
|
+
const removed = await removeWorker(folder + "/" + name + "/" + file, arg, context, one);
|
|
69
|
+
if(one && removed) break;
|
|
70
|
+
remove = remove || removed;
|
|
71
|
+
}
|
|
72
|
+
return remove;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export default remove;
|
package/file/update.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { existsSync, promises, appendFileSync, readdirSync } from "fs";
|
|
2
|
+
import { pathRepair, createRL } from "./utils.js";
|
|
3
|
+
import { parse, stringify } from "../format.js";
|
|
4
|
+
import { hasFieldsAdvanced, updateObject } from "../more.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Updates a file based on search criteria and an updater function or object.
|
|
8
|
+
* @private
|
|
9
|
+
* @param {string} file - The file path to update.
|
|
10
|
+
* @param {function|Object} search - The search criteria. It can be a function or an object.
|
|
11
|
+
* @param {function|Object} updater - The updater function or object.
|
|
12
|
+
* @param {Object} context - The context object (for functions).
|
|
13
|
+
* @param {boolean} [one=false] - Indicates whether to update only one matching entry (default: false).
|
|
14
|
+
* @returns {Promise<boolean>} A Promise that resolves to `true` if the file was updated, or `false` otherwise.
|
|
15
|
+
*/
|
|
16
|
+
async function updateWorker(file, search, updater, context={}, one=false){
|
|
17
|
+
file = pathRepair(file);
|
|
18
|
+
if(!existsSync(file)){
|
|
19
|
+
await promises.writeFile(file, "");
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
await promises.copyFile(file, file+".tmp");
|
|
23
|
+
await promises.writeFile(file, "");
|
|
24
|
+
|
|
25
|
+
const rl = createRL(file+".tmp");
|
|
26
|
+
|
|
27
|
+
let updated = false;
|
|
28
|
+
for await(let line of rl){
|
|
29
|
+
if(one && updated){
|
|
30
|
+
appendFileSync(file, line+"\n");
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const data = parse(line);
|
|
35
|
+
let ob = false;
|
|
36
|
+
|
|
37
|
+
if(typeof search === "function"){
|
|
38
|
+
ob = search(data, context) || false;
|
|
39
|
+
}else if(typeof search === "object" && !Array.isArray(search)){
|
|
40
|
+
ob = hasFieldsAdvanced(data, search);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if(ob){
|
|
44
|
+
let updateObj;
|
|
45
|
+
if(typeof updater === "function"){
|
|
46
|
+
updateObj = updater(data, context);
|
|
47
|
+
}else if(typeof updater === "object" && !Array.isArray(updater)){
|
|
48
|
+
updateObj = updateObject(data, updater);
|
|
49
|
+
}
|
|
50
|
+
line = await stringify(updateObj);
|
|
51
|
+
updated = true;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
appendFileSync(file, line+"\n");
|
|
55
|
+
}
|
|
56
|
+
await promises.writeFile(file+".tmp", "");
|
|
57
|
+
return updated;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Asynchronously updates entries in a file based on search criteria and an updater function or object.
|
|
62
|
+
* @function
|
|
63
|
+
* @param {string} folder - The folder containing the file.
|
|
64
|
+
* @param {string} name - The name of the file to update.
|
|
65
|
+
* @param {function|Object} arg - The search criteria. It can be a function or an object.
|
|
66
|
+
* @param {function|Object} obj - The updater function or object.
|
|
67
|
+
* @param {Object} context - The context object (for functions).
|
|
68
|
+
* @param {boolean} one - Indicates whether to update only one matching entry (default: false).
|
|
69
|
+
* @returns {Promise<boolean>} A Promise that resolves to `true` if entries were updated, or `false` otherwise.
|
|
70
|
+
*/
|
|
71
|
+
async function update(folder, name, arg, obj, context={}, one){
|
|
72
|
+
let files = readdirSync(folder + "/" + name).filter(file => !/\.tmp$/.test(file));
|
|
73
|
+
files.reverse();
|
|
74
|
+
let update = false;
|
|
75
|
+
for(const file of files){
|
|
76
|
+
const updated = await updateWorker(folder + "/" + name + "/" + file, arg, obj, context, one);
|
|
77
|
+
if(one && updated) return true;
|
|
78
|
+
update = update || updated;
|
|
79
|
+
}
|
|
80
|
+
return update;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export default update;
|
package/file/utils.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createReadStream } from "fs";
|
|
2
|
+
import { createInterface } from "readline";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Repairs a file path by replacing double slashes
|
|
6
|
+
* @private
|
|
7
|
+
* @param {string} path - The file path to repair.
|
|
8
|
+
* @returns {string} The repaired file path.
|
|
9
|
+
*/
|
|
10
|
+
export function pathRepair(path){
|
|
11
|
+
return path.replaceAll("//", "/");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Creates a Readline interface for reading large files with a specified high water mark.
|
|
16
|
+
* @private
|
|
17
|
+
* @param {string} file - The file path to create a Readline interface for.
|
|
18
|
+
* @returns {readline.Interface} The Readline interface.
|
|
19
|
+
*/
|
|
20
|
+
export function createRL(file){
|
|
21
|
+
const read_stream = createReadStream(file, { highWaterMark: 10 * 1024 * 1024 }); //10MB
|
|
22
|
+
const rl = createInterface({
|
|
23
|
+
input: read_stream,
|
|
24
|
+
crlfDelay: Infinity
|
|
25
|
+
});
|
|
26
|
+
return rl;
|
|
27
|
+
}
|
package/format.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import json5 from "json5";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Parses given string into a JSON object. If the string does not start with
|
|
5
|
+
* a {, it is wrapped in one. This allows for a shorthand when
|
|
6
|
+
* storing/reading data from a file.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} data
|
|
9
|
+
* @returns {Object}
|
|
10
|
+
*/
|
|
11
|
+
export function parse(data){
|
|
12
|
+
if(!data.startsWith("{")) data = "{" + data + "}";
|
|
13
|
+
return json5.parse(data);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Converts given object to a string. If the string is a valid json5, it is
|
|
17
|
+
* returned as is. If it is a valid json5 wrapped in {}, the curly brackets
|
|
18
|
+
* are removed. Otherwise the string is wrapped in {}.
|
|
19
|
+
*
|
|
20
|
+
* @param {Object} data
|
|
21
|
+
* @return {String}
|
|
22
|
+
*/
|
|
23
|
+
export function stringify(data){
|
|
24
|
+
data = json5.stringify(data);
|
|
25
|
+
if(data.startsWith("{")){
|
|
26
|
+
data = data.slice(1, -1);
|
|
27
|
+
}
|
|
28
|
+
return data;
|
|
29
|
+
}
|
package/gen.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const usedIdsMap = new Map();
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Generates a unique identifier based on specified parts.
|
|
5
|
+
* @function
|
|
6
|
+
* @param {number|number[]} parts - The number of parts or an array of parts.
|
|
7
|
+
* @param {number} [fill=1] - The fill value for each part (default: 1).
|
|
8
|
+
* @returns {string} The generated unique identifier.
|
|
9
|
+
*/
|
|
10
|
+
export default function genId(parts, fill=1){
|
|
11
|
+
parts = changeInputToPartsArray(parts, fill);
|
|
12
|
+
const time = getTime();
|
|
13
|
+
const id = getUniqueRandom(time, parts);
|
|
14
|
+
return id;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Generates a unique random identifier based on time and parts.
|
|
19
|
+
* @private
|
|
20
|
+
* @param {string} time - The current time in a base36 string format.
|
|
21
|
+
* @param {number[]} parts - An array of parts to be used for generating the identifier.
|
|
22
|
+
* @param {number} [s=0] - Recursion counter for handling collision (default: 0).
|
|
23
|
+
* @returns {string} The unique random identifier.
|
|
24
|
+
*/
|
|
25
|
+
function getUniqueRandom(time, partsA, s=0){
|
|
26
|
+
const parts = partsA.map(l => getRandom(l));
|
|
27
|
+
const id = [time, ...parts].join("-");
|
|
28
|
+
if(usedIdsMap.has(id)){
|
|
29
|
+
s++;
|
|
30
|
+
if(s < 25) return getUniqueRandom(time, partsA, s);
|
|
31
|
+
partsA = addOneToPods(partsA);
|
|
32
|
+
time = getTime();
|
|
33
|
+
return getUniqueRandom(time, partsA);
|
|
34
|
+
}
|
|
35
|
+
usedIdsMap.set(id, Date.now() + 2000);
|
|
36
|
+
|
|
37
|
+
usedIdsMap.forEach((value, key) => {
|
|
38
|
+
if(value < Date.now()) usedIdsMap.delete(key);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
return id;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Generates a random string of base36 characters.
|
|
46
|
+
* @private
|
|
47
|
+
* @param {string} unix - The Unix timestamp used for generating the random string.
|
|
48
|
+
* @returns {string} The random string.
|
|
49
|
+
*/
|
|
50
|
+
function getRandom(unix){
|
|
51
|
+
return (Math.floor(Math.random() * Math.pow(36, unix))).toString(36);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Gets the current time in a base36 string format.
|
|
56
|
+
* @private
|
|
57
|
+
* @returns {string} The current time in base36.
|
|
58
|
+
*/
|
|
59
|
+
function getTime(){
|
|
60
|
+
return Math.floor(new Date().getTime() / 1000).toString(36);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Adds one to each part of the input array.
|
|
65
|
+
* @private
|
|
66
|
+
* @param {number[]} array - The input array.
|
|
67
|
+
* @returns {number[]} An array with one added to each element.
|
|
68
|
+
*/
|
|
69
|
+
function addOneToPods(array){
|
|
70
|
+
const sum = array.reduce((acc, current) => acc + current, 0);
|
|
71
|
+
const num = sum + 1;
|
|
72
|
+
const len = array.length;
|
|
73
|
+
|
|
74
|
+
const result = [];
|
|
75
|
+
const quotient = Math.floor(num / len);
|
|
76
|
+
const remainder = num % len;
|
|
77
|
+
|
|
78
|
+
for(let i=0; i<len; i++){
|
|
79
|
+
if(i < remainder) result.push(quotient + 1);
|
|
80
|
+
else result.push(quotient);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Converts input to an array of parts.
|
|
88
|
+
* @private
|
|
89
|
+
* @param {number|number[]} parts - The number of parts or an array of parts.
|
|
90
|
+
* @param {number} [fill=1] - The fill value for each part (default: 1).
|
|
91
|
+
* @returns {number[]} An array of parts.
|
|
92
|
+
*/
|
|
93
|
+
function changeInputToPartsArray(parts, fill=1){
|
|
94
|
+
if(Array.isArray(parts)) return parts;
|
|
95
|
+
if(typeof parts == "number") return Array(parts).fill(fill);
|
|
96
|
+
return [1, 1];
|
|
97
|
+
}
|