@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
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
class CollectionManager{
|
|
2
|
+
constructor(db, collection){
|
|
3
|
+
this.db = db;
|
|
4
|
+
this.collection = collection;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Add data to a database.
|
|
9
|
+
*
|
|
10
|
+
* @async
|
|
11
|
+
* @function
|
|
12
|
+
* @param {Object} data - The data to add.
|
|
13
|
+
* @param {boolean} id_gen - Whether to generate an ID for the entry. Default is true.
|
|
14
|
+
* @returns {Promise<Object>} A Promise that resolves with the added data.
|
|
15
|
+
*/
|
|
16
|
+
async add(data, id_gen=true){
|
|
17
|
+
return await this.db.add(this.collection, data, id_gen);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Find data in a database.
|
|
22
|
+
*
|
|
23
|
+
* @async
|
|
24
|
+
* @function
|
|
25
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
26
|
+
* @param {Object} context - The context object (for functions).
|
|
27
|
+
* @param {Object} options - The options for the search.
|
|
28
|
+
* @param {number} options.max - The maximum number of entries to return. Default is -1, meaning no limit.
|
|
29
|
+
* @param {boolean} options.reverse - Whether to reverse the order of returned entries. Default is false.
|
|
30
|
+
* @returns {Promise<Array<Object>>} A Promise that resolves with the matching data.
|
|
31
|
+
*/
|
|
32
|
+
async find(search, context={}, options={}){
|
|
33
|
+
return await this.db.find(this.collection, search, context, options);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Find one data entry in a database.
|
|
38
|
+
*
|
|
39
|
+
* @async
|
|
40
|
+
* @function
|
|
41
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
42
|
+
* @param {Object} context - The context object (for functions).
|
|
43
|
+
* @returns {Promise<Object|null>} A Promise that resolves with the first matching data entry.
|
|
44
|
+
*/
|
|
45
|
+
async findOne(search, context={}){
|
|
46
|
+
return await this.db.findOne(this.collection, search, context);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Update data in a database.
|
|
51
|
+
*
|
|
52
|
+
* @async
|
|
53
|
+
* @function
|
|
54
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
55
|
+
* @param {function|Object} arg - Update arguments.
|
|
56
|
+
* @param {Object} context - The context object (for functions).
|
|
57
|
+
* @returns {Promise<boolean>} A Promise that resolves when the data is updated.
|
|
58
|
+
*/
|
|
59
|
+
async update(search, arg, context={}){
|
|
60
|
+
return await this.db.update(this.collection, search, arg, context);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Update one data entry in a database.
|
|
65
|
+
*
|
|
66
|
+
* @async
|
|
67
|
+
* @function
|
|
68
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
69
|
+
* @param {function|Object} arg - The query.
|
|
70
|
+
* @param {Object} context - The context object (for functions).
|
|
71
|
+
* @returns {Promise<boolean>} A Promise that resolves when the data entry is updated.
|
|
72
|
+
*/
|
|
73
|
+
async updateOne(search, arg, context={}){
|
|
74
|
+
return await this.db.updateOne(this.collection, search, arg, context);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Remove data from a database.
|
|
79
|
+
*
|
|
80
|
+
* @async
|
|
81
|
+
* @function
|
|
82
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
83
|
+
* @param {Object} context - The context object (for functions).
|
|
84
|
+
* @returns {Promise<boolean>} A Promise that resolves when the data is removed.
|
|
85
|
+
*/
|
|
86
|
+
|
|
87
|
+
async remove(search, context={}){
|
|
88
|
+
return await this.db.remove(this.collection, search, context);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Remove one data entry from a database.
|
|
93
|
+
*
|
|
94
|
+
* @async
|
|
95
|
+
* @function
|
|
96
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
97
|
+
* @param {Object} context - The context object (for functions).
|
|
98
|
+
* @returns {Promise<boolean>} A Promise that resolves when the data entry is removed.
|
|
99
|
+
*/
|
|
100
|
+
async removeOne(search, context={}){
|
|
101
|
+
return await this.db.removeOne(this.collection, search, context);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Asynchronously updates one entry in a database or adds a new one if it doesn't exist.
|
|
106
|
+
*
|
|
107
|
+
* @param {function|Object} search - The query. It can be an object or a function.
|
|
108
|
+
* @param {function|Object} arg - The search criteria for the update.
|
|
109
|
+
* @param {function|Object} add_arg - The arguments to be added to the new entry.
|
|
110
|
+
* @param {Object} context - The context object (for functions).
|
|
111
|
+
* @param {boolean} id_gen - Whether to generate an ID for the entry. Default is true.
|
|
112
|
+
* @return {Promise<boolean>} A Promise that resolves to `true` if the entry was updated, or `false` if it was added.
|
|
113
|
+
*/
|
|
114
|
+
async updateOneOrAdd(search, arg, add_arg={}, context={}, id_gen=true){
|
|
115
|
+
return await this.db.updateOneOrAdd(this.collection, search, arg, add_arg, context, id_gen);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export default CollectionManager;
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 wxn0brP
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# DataBase Class
|
|
2
|
+
|
|
3
|
+
The `DataBase` class simplifies managing data with a file-based database, providing an easy way to perform CRUD operations, caching, and custom queries.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Ensure you have Node.js installed. To install the `DataBase` package, run:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @wxn0brp/database
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage Example
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
import DataBase from '@wxn0brp/database/database.js';
|
|
17
|
+
|
|
18
|
+
async function main(){
|
|
19
|
+
// Initialize the database with a folder path and optional cache settings
|
|
20
|
+
const db = new DataBase('./data');
|
|
21
|
+
|
|
22
|
+
// Create or check a collection
|
|
23
|
+
await db.checkCollection('users');
|
|
24
|
+
|
|
25
|
+
// Add a new user to the collection
|
|
26
|
+
await db.add('users', { name: 'Alice', age: 30 });
|
|
27
|
+
|
|
28
|
+
// Find users based on search criteria
|
|
29
|
+
const users = await db.find('users', { age: 30 });
|
|
30
|
+
console.log(users);
|
|
31
|
+
|
|
32
|
+
// Update a user's data
|
|
33
|
+
await db.update('users', { name: 'Alice' }, { age: 31 });
|
|
34
|
+
|
|
35
|
+
// Remove a user
|
|
36
|
+
await db.remove('users', { name: 'Alice' });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
main().catch(console.error);
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Methods Overview
|
|
44
|
+
|
|
45
|
+
| Method Name | Description | Parameters | Returns |
|
|
46
|
+
| ----------- | ----------- | ---------- | ------- |
|
|
47
|
+
| `getCollections` | Retrieves the names of all available collections. | None | `string[]` |
|
|
48
|
+
| `checkCollection` | Ensures that a collection exists, creating it if necessary. | `collection` (string): Name of the collection | `Promise<void>` |
|
|
49
|
+
| `issetCollection` | Checks if a collection exists. | `collection` (string): Name of the collection | `Promise<boolean>` |
|
|
50
|
+
| `add` | Adds data to a collection, optionally generating an ID. | `collection` (string), `data` (Object), `id_gen` (boolean) | `Promise<Object>` |
|
|
51
|
+
| `find` | Finds data entries matching a query. | `collection` (string), `search` (function/Object), `context` (Object), `options` (Object) - { max, reverse } | `Promise<Array<Object>>` |
|
|
52
|
+
| `findOne` | Finds the first data entry matching a query. | `collection` (string), `search` (function/Object), `context` (Object) | `Promise<Object\|null>` |
|
|
53
|
+
| `update` | Updates data entries matching a query. | `collection` (string), `search` (function/Object), `arg` (function/Object), `context` (Object) | `Promise<boolean>` |
|
|
54
|
+
| `updateOne` | Updates the first data entry matching a query. | `collection` (string), `search` (function/Object), `arg` (function/Object), `context` (Object) | `Promise<boolean>` |
|
|
55
|
+
| `remove` | Removes data entries matching a query. | `collection` (string), `search` (function/Object), `context` (Object) | `Promise<boolean>` |
|
|
56
|
+
| `removeOne` | Removes the first data entry matching a query. | `collection` (string), `search` (function/Object), `context` (Object) | `Promise<boolean>` |
|
|
57
|
+
| `updateOneOrAdd` | Updates one entry or adds a new one if no match is found. | `collection` (string), `search` (function/Object), `arg` (function/Object), `add_arg` (function/Object), `context` (Object), `id_gen` (boolean) | `Promise<boolean>` |
|
|
58
|
+
| `removeDb` | Removes an entire database collection from the file system. | `collection` (string) | `void` |
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### Querying Data
|
|
63
|
+
|
|
64
|
+
The `DataBase` class offers flexibility for querying collections using either an object or a function as the `search` parameter in methods like `find`, `findOne`, `update`, and `remove`.
|
|
65
|
+
|
|
66
|
+
#### Object-Based Queries
|
|
67
|
+
|
|
68
|
+
You can use the following operators to build your queries:
|
|
69
|
+
|
|
70
|
+
- **`$or`**: Matches if at least one condition is true.
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
const result = await db.find('users', {
|
|
74
|
+
$or: [{ status: 'active' }, { role: 'admin' }]
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
- **`$not`**: Matches if the condition is false.
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
const result = await db.find('users', {
|
|
82
|
+
$not: { status: 'inactive' }
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- **`$and`**: Combines multiple conditions, all of which must be true. Useful for complex queries involving other operators.
|
|
87
|
+
|
|
88
|
+
```javascript
|
|
89
|
+
const result = await db.find('users', {
|
|
90
|
+
$and: [
|
|
91
|
+
{ age: 25 },
|
|
92
|
+
{ $or: [{ status: 'active' }, { status: 'away' }] }
|
|
93
|
+
]
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
- **`$set`**: Ensures that specified fields are present in the document.
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
const result = await db.find('users', {
|
|
101
|
+
$set: { name: true }
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### Search as a Function
|
|
106
|
+
|
|
107
|
+
Alternatively, you can use a function for more dynamic queries. The function receives each document as an argument and should return `true` for documents that match the criteria.
|
|
108
|
+
|
|
109
|
+
```javascript
|
|
110
|
+
const results = await db.find('users', obj => obj.age > 30);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
This approach is powerful for cases where the query logic is too complex to be represented as an object.
|
|
114
|
+
|
|
115
|
+
### Update Argument
|
|
116
|
+
|
|
117
|
+
When updating data, the `update` argument can also be either an object or a function.
|
|
118
|
+
|
|
119
|
+
#### Update as an Object
|
|
120
|
+
|
|
121
|
+
If you pass an object as the `update` argument, it will directly set the new values for the specified fields.
|
|
122
|
+
|
|
123
|
+
##### Example: Update with Object
|
|
124
|
+
|
|
125
|
+
```javascript
|
|
126
|
+
// Updates the age of all users named 'Alice' to 31
|
|
127
|
+
await db.update('users', { name: 'Alice' }, { age: 31 });
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### Update as a Function
|
|
131
|
+
|
|
132
|
+
If you pass a function, it receives the current object as an argument and should return the updated object. This allows for dynamic updates based on the current state of the object.
|
|
133
|
+
|
|
134
|
+
##### Example: Update with Function
|
|
135
|
+
|
|
136
|
+
```javascript
|
|
137
|
+
// Increments the age of all users named 'Alice' by 1
|
|
138
|
+
await db.update('users', { name: 'Alice' }, obj => {
|
|
139
|
+
obj.age++;
|
|
140
|
+
return obj;
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
This method is useful when you need to compute new values based on existing ones.
|
|
145
|
+
|
|
146
|
+
## Other Features
|
|
147
|
+
|
|
148
|
+
### Graph.js
|
|
149
|
+
|
|
150
|
+
The `Graph` class extends the functionality of the `DataBase` class to handle graph-like structures, where relationships (edges) between nodes (vertices) are stored in collections.
|
|
151
|
+
|
|
152
|
+
#### Methods
|
|
153
|
+
|
|
154
|
+
- **`add(collection, a, b)`**: Adds an edge between `a` and `b` in the specified collection. The nodes are sorted to ensure consistency in the storage format.
|
|
155
|
+
|
|
156
|
+
```javascript
|
|
157
|
+
// Adds a friendship between Alice and Bob
|
|
158
|
+
await graph.add('friends', 'Alice', 'Bob');
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
- **`remove(collection, a, b)`**: Removes the edge between `a` and `b`.
|
|
162
|
+
|
|
163
|
+
```javascript
|
|
164
|
+
// Removes the friendship between Alice and Bob
|
|
165
|
+
await graph.remove('friends', 'Alice', 'Bob');
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
- **`find(collection, d)`**: Finds all edges where `d` is one of the nodes.
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
// Returns all friends of Alice
|
|
172
|
+
const friends = await graph.find('friends', 'Alice');
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
- **`findOne(collection, d, e)`**: Finds the edge between `d` and `e`.
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
// Returns the friendship between Alice and Bob, if it exists
|
|
179
|
+
const relation = await graph.findOne('friends', 'Alice', 'Bob');
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Gen.js
|
|
183
|
+
|
|
184
|
+
The `gen.js` file contains a utility function `genId`, which generates a unique identifier.
|
|
185
|
+
|
|
186
|
+
#### Example: Generating an ID
|
|
187
|
+
|
|
188
|
+
```javascript
|
|
189
|
+
const id = genId();
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
|
|
194
|
+
This project is licensed under the [MIT License](https://opensource.org/licenses/MIT). See the [LICENSE](./LICENSE) file for details.
|
package/action.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readdirSync, appendFileSync, rmSync, writeFileSync, statSync } from "fs";
|
|
2
|
+
import gen from "./gen.js";
|
|
3
|
+
import { stringify } from "./format.js";
|
|
4
|
+
import { find as _find, findOne as _findOne, update as _update, remove as _remove } from "./file/index.js";
|
|
5
|
+
|
|
6
|
+
const maxFileSize = 2 * 1024 * 1024; //2 MB
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A class representing database actions on files.
|
|
10
|
+
* @class
|
|
11
|
+
*/
|
|
12
|
+
class dbActionC{
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new instance of dbActionC.
|
|
15
|
+
* @constructor
|
|
16
|
+
* @param {string} folder - The folder where database files are stored.
|
|
17
|
+
* @param {object} options - The options object.
|
|
18
|
+
*/
|
|
19
|
+
constructor(folder, options){
|
|
20
|
+
this.folder = folder;
|
|
21
|
+
// this.cacheManager = new CacheManager(options.cacheThreshold, options.cacheTTL);
|
|
22
|
+
|
|
23
|
+
if(!existsSync(folder)) mkdirSync(folder, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Get a list of available databases in the specified folder.
|
|
28
|
+
* @returns {string[]} An array of database names.
|
|
29
|
+
*/
|
|
30
|
+
getCollections(){
|
|
31
|
+
const collections = readdirSync(this.folder, { recursive: true, withFileTypes: true })
|
|
32
|
+
.filter(dirent => dirent.isDirectory())
|
|
33
|
+
.map(dirent => {
|
|
34
|
+
if(dirent.parentPath === this.folder) return dirent.name;
|
|
35
|
+
return dirent.parentPath.replace(this.folder + "/", "") + "/" + dirent.name
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
return collections;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Check and create the specified collection if it doesn't exist.
|
|
43
|
+
* @function
|
|
44
|
+
* @param {string} collection - The collection to check.
|
|
45
|
+
*/
|
|
46
|
+
checkCollection(collection){
|
|
47
|
+
const path = this.folder + "/" + collection;
|
|
48
|
+
if(!existsSync(path)) mkdirSync(path, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check if a collection exists.
|
|
53
|
+
* @function
|
|
54
|
+
* @param {string} collection - The name of the collection.
|
|
55
|
+
* @returns {boolean} True if the collection exists, false otherwise.
|
|
56
|
+
*/
|
|
57
|
+
issetCollection(collection){
|
|
58
|
+
const path = this.folder + "/" + collection;
|
|
59
|
+
return existsSync(path);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Add a new entry to the specified database.
|
|
64
|
+
* @async
|
|
65
|
+
* @param {string} collection - The name of the collection.
|
|
66
|
+
* @param {Object} arg - The data to be added to the database.
|
|
67
|
+
* @param {boolean} id_gen - Whether to generate an ID for the entry. Default is true.
|
|
68
|
+
* @returns {Promise<Object>} A Promise that resolves to the added data.
|
|
69
|
+
*/
|
|
70
|
+
async add(collection, arg, id_gen=true){
|
|
71
|
+
await this.checkCollection(collection);
|
|
72
|
+
const file = this.folder + "/" + collection + "/" + getLastFile(this.folder + "/" + collection);
|
|
73
|
+
|
|
74
|
+
if(id_gen) arg._id = arg._id || gen();
|
|
75
|
+
const data = stringify(arg);
|
|
76
|
+
appendFileSync(file, data+"\n");
|
|
77
|
+
return arg;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Find entries in the specified database based on search criteria.
|
|
82
|
+
* @async
|
|
83
|
+
* @param {string} collection - The name of the collection.
|
|
84
|
+
* @param {function|Object} arg - The search criteria. It can be a function or an object.
|
|
85
|
+
* @param {Object} context - The context object (for functions).
|
|
86
|
+
* @param {Object} options - The options for the search.
|
|
87
|
+
* @param {number} options.max - The maximum number of entries to return. Default is -1, meaning no limit.
|
|
88
|
+
* @param {boolean} options.reverse - Whether to reverse the order of returned entries. Default is false.
|
|
89
|
+
* @param {Object} findOpts - Update result object with findOpts options.
|
|
90
|
+
* @returns {Promise<Object[]>} A Promise that resolves to an array of matching entries.
|
|
91
|
+
*/
|
|
92
|
+
async find(collection, arg, context={}, options={}, findOpts={}){
|
|
93
|
+
options.reverse = options.reverse || false;
|
|
94
|
+
options.max = options.max || -1;
|
|
95
|
+
|
|
96
|
+
await this.checkCollection(collection);
|
|
97
|
+
const files = getSortedFiles(this.folder + "/" + collection).map(f => f.f);
|
|
98
|
+
if(options.reverse) files.reverse();
|
|
99
|
+
let datas = [];
|
|
100
|
+
|
|
101
|
+
let totalEntries = 0;
|
|
102
|
+
|
|
103
|
+
for(let f of files){
|
|
104
|
+
let data = await _find(this.folder + "/" + collection + "/" + f, arg, context, findOpts);
|
|
105
|
+
if(options.reverse) data.reverse();
|
|
106
|
+
|
|
107
|
+
if(options.max !== -1){
|
|
108
|
+
if(totalEntries + data.length > options.max){
|
|
109
|
+
let remainingEntries = options.max - totalEntries;
|
|
110
|
+
data = data.slice(0, remainingEntries);
|
|
111
|
+
totalEntries = options.max;
|
|
112
|
+
}else{
|
|
113
|
+
totalEntries += data.length;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
datas = datas.concat(data);
|
|
118
|
+
|
|
119
|
+
if(options.max !== -1 && totalEntries >= options.max) break;
|
|
120
|
+
}
|
|
121
|
+
return datas;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Find the first matching entry in the specified database based on search criteria.
|
|
126
|
+
* @async
|
|
127
|
+
* @param {string} collection - Name of the database collection.
|
|
128
|
+
* @param {function|Object} arg - The search criteria. It can be a function or an object.
|
|
129
|
+
* @param {Object} context - The context object (for functions).
|
|
130
|
+
* @param {Object} findOpts - Update result object with findOpts options.
|
|
131
|
+
* @returns {Promise<Object|null>} A Promise that resolves to the first matching entry or null if not found.
|
|
132
|
+
*/
|
|
133
|
+
async findOne(collection, arg, context={}, findOpts={}){
|
|
134
|
+
await this.checkCollection(collection);
|
|
135
|
+
const files = getSortedFiles(this.folder + "/" + collection).map(f => f.f);
|
|
136
|
+
files.reverse();
|
|
137
|
+
|
|
138
|
+
for(let f of files){
|
|
139
|
+
let data = await _findOne(this.folder + "/" + collection + "/" + f, arg, context, findOpts);
|
|
140
|
+
if(data){
|
|
141
|
+
return data;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Update entries in the specified database based on search criteria and an updater function or object.
|
|
149
|
+
* @async
|
|
150
|
+
* @param {string} collection - Name of the database collection.
|
|
151
|
+
* @param {function|Object} arg - The search criteria. It can be a function or an object.
|
|
152
|
+
* @param {function|Object} obj - The updater function or object.
|
|
153
|
+
* @param {Object} context - The context object (for functions).
|
|
154
|
+
* @returns {Promise<boolean>} A Promise that resolves to `true` if entries were updated, or `false` otherwise.
|
|
155
|
+
*/
|
|
156
|
+
async update(collection, arg, obj, context={}){
|
|
157
|
+
await this.checkCollection(collection);
|
|
158
|
+
return await _update(this.folder, collection, arg, obj, context);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Update the first matching entry in the specified database based on search criteria and an updater function or object.
|
|
163
|
+
* @async
|
|
164
|
+
* @param {string} collection - Name of the database collection.
|
|
165
|
+
* @param {function|Object} arg - The search criteria. It can be a function or an object.
|
|
166
|
+
* @param {function|Object} obj - The updater function or object.
|
|
167
|
+
* @param {Object} context - The context object (for functions).
|
|
168
|
+
* @returns {Promise<boolean>} A Promise that resolves to `true` if one entry was updated, or `false` otherwise.
|
|
169
|
+
*/
|
|
170
|
+
async updateOne(collection, arg, obj, context={}){
|
|
171
|
+
await this.checkCollection(collection);
|
|
172
|
+
return await _update(this.folder, collection, arg, obj, context, true);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Remove entries from the specified database based on search criteria.
|
|
177
|
+
* @async
|
|
178
|
+
* @param {string} collection - Name of the database collection.
|
|
179
|
+
* @param {function|Object} arg - The search criteria. It can be a function or an object.
|
|
180
|
+
* @param {Object} context - The context object (for functions).
|
|
181
|
+
* @returns {Promise<boolean>} A Promise that resolves to `true` if entries were removed, or `false` otherwise.
|
|
182
|
+
*/
|
|
183
|
+
async remove(collection, arg, context={}){
|
|
184
|
+
await this.checkCollection(collection);
|
|
185
|
+
return await _remove(this.folder, collection, arg, context);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Remove the first matching entry from the specified database based on search criteria.
|
|
190
|
+
* @async
|
|
191
|
+
* @param {string} collection - Name of the database collection.
|
|
192
|
+
* @param {function|Object} arg - The search criteria. It can be a function or an object.
|
|
193
|
+
* @param {Object} context - The context object (for functions).
|
|
194
|
+
* @returns {Promise<boolean>} A Promise that resolves to `true` if one entry was removed, or `false` otherwise.
|
|
195
|
+
*/
|
|
196
|
+
async removeOne(collection, arg, context={}){
|
|
197
|
+
await this.checkCollection(collection);
|
|
198
|
+
return await _remove(this.folder, collection, arg, context, true);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Removes a database collection from the file system.
|
|
203
|
+
*
|
|
204
|
+
* @param {string} collection - The name of the collection to remove.
|
|
205
|
+
* @return {void}
|
|
206
|
+
*/
|
|
207
|
+
removeDb(collection){
|
|
208
|
+
rmSync(this.folder + "/" + collection, { recursive: true, force: true });
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Get the last file in the specified directory.
|
|
214
|
+
* @param {string} path - The directory path.
|
|
215
|
+
* @returns {string} The name of the last file in the directory.
|
|
216
|
+
*/
|
|
217
|
+
function getLastFile(path){
|
|
218
|
+
if(!existsSync(path)) mkdirSync(path, { recursive: true });
|
|
219
|
+
const files = getSortedFiles(path);
|
|
220
|
+
|
|
221
|
+
if(files.length == 0){
|
|
222
|
+
writeFileSync(path+"/1.db", "");
|
|
223
|
+
return "1.db";
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const last = files[files.length-1];
|
|
227
|
+
const info = path + "/" + last.f;
|
|
228
|
+
|
|
229
|
+
if(statSync(info).size < maxFileSize) return last.f;
|
|
230
|
+
|
|
231
|
+
const num = last.i + 1;
|
|
232
|
+
writeFileSync(path + "/" + num + ".db", "");
|
|
233
|
+
return num+".db";
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get all files in a directory sorted by name.
|
|
238
|
+
* @param {string} path - The path to the directory.
|
|
239
|
+
* @return {string[]} An array of file names sorted by name.
|
|
240
|
+
*/
|
|
241
|
+
function getSortedFiles(path){
|
|
242
|
+
let files = readdirSync(path).filter(file => file.endsWith(".db"));
|
|
243
|
+
if(files.length == 0) return [];
|
|
244
|
+
files = files.map(file => parseInt(file.replace(".db", "")))
|
|
245
|
+
files = files.sort();
|
|
246
|
+
files = files.map(file => { return { i: file, f: file+".db" } });
|
|
247
|
+
return files;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export default dbActionC;
|
package/cacheManager.js
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A cache manager for storing and managing cached data.
|
|
3
|
+
* @class
|
|
4
|
+
*/
|
|
5
|
+
class CacheManager{
|
|
6
|
+
/**
|
|
7
|
+
* Create a new cache manager instance.
|
|
8
|
+
* @constructor
|
|
9
|
+
* @param {number} cacheThreshold - The threshold for caching query results.
|
|
10
|
+
* @param {number} ttl - The time-to-live (TTL) for cached data in milliseconds.
|
|
11
|
+
*/
|
|
12
|
+
constructor(cacheThreshold, ttl){
|
|
13
|
+
this.queryCounterCache = {};
|
|
14
|
+
this.dataCache = {};
|
|
15
|
+
this.cacheThreshold = cacheThreshold;
|
|
16
|
+
this.ttl = ttl;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Increment the query counter for a specific cache key.
|
|
21
|
+
* @private
|
|
22
|
+
* @param {string} key - The cache key.
|
|
23
|
+
* @returns {number} The updated query count for the cache key.
|
|
24
|
+
*/
|
|
25
|
+
_incrementQueryCounter(key){
|
|
26
|
+
if(!this.queryCounterCache[key]){
|
|
27
|
+
this.queryCounterCache[key] = 1;
|
|
28
|
+
}else{
|
|
29
|
+
this.queryCounterCache[key]++;
|
|
30
|
+
}
|
|
31
|
+
return this.queryCounterCache[key];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Set data in the cache for a specific cache key.
|
|
36
|
+
* @private
|
|
37
|
+
* @param {string} key - The cache key.
|
|
38
|
+
* @param {*} data - The data to be cached.
|
|
39
|
+
*/
|
|
40
|
+
_setCache(key, data){
|
|
41
|
+
this.dataCache[key] = { data, expires: Date.now() + this.ttl };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get data from the cache for a specific cache key if it is not expired.
|
|
46
|
+
* @param {string} key - The cache key.
|
|
47
|
+
* @returns {*} The cached data if not expired, otherwise null.
|
|
48
|
+
*/
|
|
49
|
+
getFromCache(key){
|
|
50
|
+
const item = this.dataCache[key];
|
|
51
|
+
if(item && Date.now() < item.expires){
|
|
52
|
+
return item.data;
|
|
53
|
+
}
|
|
54
|
+
delete this.dataCache[key];
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Add data to the cache if the query count exceeds the cache threshold.
|
|
60
|
+
* @param {string} key - The cache key.
|
|
61
|
+
* @param {*} data - The data to be cached.
|
|
62
|
+
*/
|
|
63
|
+
addToCacheIfNeeded(key, data){
|
|
64
|
+
const queryCount = this._incrementQueryCounter(key);
|
|
65
|
+
if(queryCount > this.cacheThreshold){
|
|
66
|
+
this._setCache(key, data);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Invalidate cache entries matching a specific key pattern.
|
|
72
|
+
* @param {string} keyPattern - The key pattern to match and invalidate cache entries.
|
|
73
|
+
*/
|
|
74
|
+
invalidateCache(keyPattern){
|
|
75
|
+
Object.keys(this.dataCache).forEach(key => {
|
|
76
|
+
if(key.startsWith(keyPattern)){
|
|
77
|
+
delete this.dataCache[key];
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export default CacheManager;
|