twin-db 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -17
- package/dist/index.cjs +312 -78
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -14
- package/dist/index.d.ts +75 -14
- package/dist/index.js +297 -76
- package/dist/index.js.map +1 -1
- package/package.json +11 -6
package/dist/index.js
CHANGED
|
@@ -1,79 +1,277 @@
|
|
|
1
|
-
// src/structures/
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
1
|
+
// src/structures/TwinDB.ts
|
|
2
|
+
import lodash from "lodash";
|
|
3
|
+
|
|
4
|
+
// src/storages/JSONStorage.ts
|
|
5
|
+
import { readFileSync, writeFileSync, existsSync } from "node:fs";
|
|
6
|
+
var JSONStorage = class {
|
|
7
|
+
constructor(path2) {
|
|
8
|
+
if (!path2.endsWith(".json")) path2 += ".json";
|
|
9
|
+
this.path = path2;
|
|
10
|
+
if (!existsSync(path2)) writeFileSync(path2, "{}", "utf8");
|
|
11
|
+
else {
|
|
12
|
+
const data = readFileSync(path2, "utf8");
|
|
13
|
+
let parsedData;
|
|
14
|
+
try {
|
|
15
|
+
parsedData = JSON.parse(data);
|
|
16
|
+
} catch (_) {
|
|
17
|
+
}
|
|
18
|
+
if (!data || !parsedData || typeof parsedData !== "object" || Array.isArray(parsedData))
|
|
19
|
+
writeFileSync(path2, "{}", "utf8");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
get() {
|
|
13
23
|
let data;
|
|
14
24
|
try {
|
|
15
25
|
data = readFileSync(this.path, "utf8");
|
|
16
|
-
} catch (
|
|
17
|
-
|
|
26
|
+
} catch (_) {
|
|
27
|
+
}
|
|
28
|
+
let parsedData;
|
|
29
|
+
try {
|
|
30
|
+
if (data) parsedData = JSON.parse(data);
|
|
31
|
+
} catch (_) {
|
|
18
32
|
}
|
|
19
|
-
|
|
20
|
-
if (!
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
33
|
+
const checkedData = data && parsedData && typeof parsedData === "object" && !Array.isArray(parsedData);
|
|
34
|
+
if (!checkedData) writeFileSync(this.path, "{}", "utf8");
|
|
35
|
+
return checkedData ? parsedData : {};
|
|
36
|
+
}
|
|
37
|
+
set(value) {
|
|
38
|
+
writeFileSync(this.path, value, "utf8");
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// src/storages/SqliteStorage.ts
|
|
44
|
+
import { DatabaseSync } from "node:sqlite";
|
|
45
|
+
|
|
46
|
+
// src/utils/vars.ts
|
|
47
|
+
var DEFAULT_KEY = "data";
|
|
48
|
+
var DEFAULT_NAME = "twin";
|
|
49
|
+
var pathErrorMessage = "The path must be a string or you dont provided a path";
|
|
50
|
+
|
|
51
|
+
// src/storages/SqliteStorage.ts
|
|
52
|
+
var SqliteStorage = class {
|
|
53
|
+
constructor(path2, table = DEFAULT_NAME, key = DEFAULT_KEY) {
|
|
54
|
+
if (!table || typeof table !== "string") table = DEFAULT_NAME;
|
|
55
|
+
if (!key || typeof key !== "string") key = DEFAULT_KEY;
|
|
56
|
+
this.table = table;
|
|
57
|
+
this.key = key;
|
|
58
|
+
if (!path2.endsWith(".db")) path2 += ".db";
|
|
59
|
+
this.db = new DatabaseSync(path2);
|
|
60
|
+
this.db.exec(`
|
|
61
|
+
CREATE TABLE IF NOT EXISTS ${table} (
|
|
62
|
+
key TEXT PRIMARY KEY,
|
|
63
|
+
value TEXT
|
|
64
|
+
)
|
|
65
|
+
`);
|
|
66
|
+
}
|
|
67
|
+
set(value) {
|
|
68
|
+
this.db.prepare(
|
|
69
|
+
`INSERT OR REPLACE INTO ${this.table} (key, value) VALUES (?, ?)`
|
|
70
|
+
).run(this.key, value);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
get() {
|
|
74
|
+
const row = this.db.prepare(`SELECT value FROM ${this.table} WHERE key = ?`).get(this.key);
|
|
75
|
+
return row ? JSON.parse(row.value) : {};
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// src/structures/TwinDB.ts
|
|
80
|
+
import path from "node:path";
|
|
81
|
+
import { mkdirSync } from "node:fs";
|
|
82
|
+
var TwinDB = class {
|
|
83
|
+
constructor(argPath = "database/twin", options = { storage: JSONStorage }) {
|
|
84
|
+
this.remove = this.delete;
|
|
85
|
+
this.add = this.sum;
|
|
86
|
+
this.subtract = this.sub;
|
|
87
|
+
if (!argPath || typeof argPath !== "string")
|
|
88
|
+
throw new Error(pathErrorMessage);
|
|
89
|
+
const solvedPath = path.resolve(process.cwd(), argPath);
|
|
90
|
+
mkdirSync(path.dirname(solvedPath), { recursive: true });
|
|
91
|
+
if (!options || typeof options !== "object" || Array.isArray(options))
|
|
92
|
+
options = { storage: JSONStorage };
|
|
93
|
+
options.storage || (options.storage = JSONStorage);
|
|
94
|
+
if (![JSONStorage, SqliteStorage].includes(options.storage))
|
|
95
|
+
throw new Error("Invalid storage type passed in options");
|
|
96
|
+
this.storage = options.storage === SqliteStorage ? new options.storage(solvedPath, options.table, options.key) : new options.storage(solvedPath);
|
|
97
|
+
this.cache = this.storage.get();
|
|
98
|
+
}
|
|
99
|
+
update(path2, value, fetch = false) {
|
|
100
|
+
if (fetch) this.cache = this.storage.get();
|
|
101
|
+
lodash.set(this.cache, path2, value);
|
|
102
|
+
this.storage.set(JSON.stringify(this.cache));
|
|
103
|
+
return this.cache;
|
|
104
|
+
}
|
|
105
|
+
set(path2, value, fetch = false) {
|
|
106
|
+
if (!path2 || typeof path2 !== "string")
|
|
107
|
+
throw new Error(pathErrorMessage);
|
|
108
|
+
if (value === void 0)
|
|
109
|
+
throw new Error("You must provide a value to update");
|
|
110
|
+
return this.update(path2, value, fetch);
|
|
111
|
+
}
|
|
112
|
+
get(path2, fetch = false) {
|
|
113
|
+
if (!path2 || typeof path2 !== "string")
|
|
114
|
+
throw new Error(pathErrorMessage);
|
|
115
|
+
if (fetch) this.cache = this.storage.get();
|
|
116
|
+
return lodash.get(this.cache, path2, null);
|
|
117
|
+
}
|
|
118
|
+
delete(path2, fetch = false) {
|
|
119
|
+
if (!path2 || typeof path2 !== "string")
|
|
120
|
+
throw new Error(pathErrorMessage);
|
|
121
|
+
if (fetch) this.cache = this.storage.get();
|
|
122
|
+
const pathExists = this.get(path2);
|
|
123
|
+
if (pathExists === null)
|
|
124
|
+
throw new Error("The path does not exists or its value is null");
|
|
125
|
+
return this.update(path2, null);
|
|
126
|
+
}
|
|
127
|
+
sumOrSub(path2, value, type, fetch = false) {
|
|
128
|
+
if (!path2 || typeof path2 !== "string")
|
|
129
|
+
throw new Error(pathErrorMessage);
|
|
130
|
+
if (!type || !["sum", "sub"].includes(type))
|
|
131
|
+
throw new Error('The type must be "sum" or "sub"');
|
|
132
|
+
const isSum = type === "sum";
|
|
133
|
+
if (!value || typeof value !== "number")
|
|
134
|
+
throw new Error(
|
|
135
|
+
`The value to ${isSum ? "sum" : "sub"} must be a number`
|
|
25
136
|
);
|
|
137
|
+
if (fetch) this.cache = this.storage.get();
|
|
138
|
+
let currentValue = this.get(path2) || 0;
|
|
139
|
+
if (typeof currentValue !== "number") currentValue = 0;
|
|
140
|
+
return this.update(
|
|
141
|
+
path2,
|
|
142
|
+
isSum ? currentValue + value : currentValue - value
|
|
143
|
+
);
|
|
26
144
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
145
|
+
sum(path2, value, fetch = false) {
|
|
146
|
+
return this.sumOrSub(path2, value, "sum", fetch);
|
|
147
|
+
}
|
|
148
|
+
sub(path2, value, fetch = false) {
|
|
149
|
+
return this.sumOrSub(path2, value, "sub", fetch);
|
|
150
|
+
}
|
|
151
|
+
concat(path2, value, fetch = false) {
|
|
152
|
+
if (!path2 || typeof path2 !== "string")
|
|
153
|
+
throw new Error(pathErrorMessage);
|
|
154
|
+
if (!value || typeof value !== "string")
|
|
155
|
+
throw new Error("You must provide a string value to update");
|
|
156
|
+
if (fetch) this.cache = this.storage.get();
|
|
157
|
+
const currentValue = this.get(path2);
|
|
158
|
+
if (typeof currentValue !== "string")
|
|
159
|
+
throw new Error(
|
|
160
|
+
"The value to concat is not a string or the path does not exists"
|
|
161
|
+
);
|
|
162
|
+
return this.update(path2, currentValue + value);
|
|
163
|
+
}
|
|
164
|
+
push(path2, values, fetch = false) {
|
|
165
|
+
if (!path2 || typeof path2 !== "string")
|
|
166
|
+
throw new Error(pathErrorMessage);
|
|
167
|
+
if (!values || values.length === 0)
|
|
168
|
+
throw new Error("You must provide a value to update");
|
|
169
|
+
if (fetch) this.cache = this.storage.get();
|
|
170
|
+
let currentValue = this.get(path2) || [];
|
|
171
|
+
if (!Array.isArray(currentValue)) currentValue = [];
|
|
172
|
+
currentValue.push(...values);
|
|
173
|
+
return this.update(path2, currentValue);
|
|
174
|
+
}
|
|
175
|
+
pull(path2, values, fetch = false) {
|
|
176
|
+
if (!path2 || typeof path2 !== "string")
|
|
177
|
+
throw new Error(pathErrorMessage);
|
|
178
|
+
if (!values || values.length === 0)
|
|
179
|
+
throw new Error("You must provide a value to update");
|
|
180
|
+
if (fetch) this.cache = this.storage.get();
|
|
181
|
+
const currentValue = this.get(path2);
|
|
182
|
+
if (!Array.isArray(currentValue))
|
|
183
|
+
throw new Error(
|
|
184
|
+
"The current value of this path is not an array or the path does not exists"
|
|
185
|
+
);
|
|
186
|
+
for (const value of values) {
|
|
187
|
+
const index = currentValue.indexOf(value);
|
|
188
|
+
if (index < 0) continue;
|
|
189
|
+
currentValue.splice(index, 1);
|
|
190
|
+
}
|
|
191
|
+
return this.update(path2, currentValue);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// src/structures/TwinMongoDB.ts
|
|
196
|
+
import lodash2 from "lodash";
|
|
197
|
+
import { MongoClient } from "mongodb";
|
|
198
|
+
var TwinMongoDB = class {
|
|
199
|
+
constructor(connectionURI, modelName = DEFAULT_NAME, id = DEFAULT_KEY) {
|
|
200
|
+
this.remove = this.delete;
|
|
201
|
+
this.add = this.sum;
|
|
202
|
+
this.subtract = this.sub;
|
|
203
|
+
if (!modelName || typeof modelName !== "string")
|
|
204
|
+
modelName = DEFAULT_NAME;
|
|
205
|
+
if (!id || typeof id !== "string") id = DEFAULT_KEY;
|
|
206
|
+
this.client = new MongoClient(connectionURI);
|
|
207
|
+
this.cache = {};
|
|
208
|
+
this.id = id;
|
|
209
|
+
this.initPromise = this.init(modelName);
|
|
210
|
+
}
|
|
211
|
+
async init(modelName) {
|
|
212
|
+
await this.client.connect();
|
|
213
|
+
this.collection = this.client.db().collection(modelName);
|
|
214
|
+
const data = await this.collection.findOne({ _id: this.id });
|
|
215
|
+
if (!data) {
|
|
216
|
+
const created = { _id: this.id, data: {} };
|
|
217
|
+
await this.collection.insertOne(created);
|
|
218
|
+
this.cache = created.data;
|
|
219
|
+
return;
|
|
40
220
|
}
|
|
41
|
-
|
|
42
|
-
return this.data;
|
|
221
|
+
this.cache = data.data;
|
|
43
222
|
}
|
|
44
|
-
|
|
45
|
-
|
|
223
|
+
async close() {
|
|
224
|
+
await this.client.close();
|
|
225
|
+
}
|
|
226
|
+
async ready() {
|
|
227
|
+
await this.initPromise;
|
|
228
|
+
}
|
|
229
|
+
async update(path2, value, fetch = false) {
|
|
230
|
+
await this.ready();
|
|
231
|
+
if (fetch) {
|
|
232
|
+
const data = await this.collection.findOne({ _id: this.id });
|
|
233
|
+
this.cache = data ? data.data : {};
|
|
234
|
+
}
|
|
235
|
+
lodash2.set(this.cache, path2, value);
|
|
236
|
+
await this.collection.updateOne(
|
|
237
|
+
{ _id: this.id },
|
|
238
|
+
{ $set: { data: this.cache } },
|
|
239
|
+
{ upsert: true }
|
|
240
|
+
);
|
|
241
|
+
return this.cache;
|
|
242
|
+
}
|
|
243
|
+
async set(path2, value, fetch = false) {
|
|
244
|
+
if (!path2 || typeof path2 !== "string")
|
|
46
245
|
throw new Error(pathErrorMessage);
|
|
47
246
|
if (value === void 0)
|
|
48
247
|
throw new Error("You must provide a value to update");
|
|
49
|
-
return this.update(
|
|
248
|
+
return this.update(path2, value, fetch);
|
|
50
249
|
}
|
|
51
|
-
get(
|
|
52
|
-
if (!
|
|
250
|
+
async get(path2, fetch = false) {
|
|
251
|
+
if (!path2 || typeof path2 !== "string")
|
|
53
252
|
throw new Error(pathErrorMessage);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
i++;
|
|
59
|
-
if (i === keys.length) return current[key] ?? null;
|
|
60
|
-
if (typeof current[key] !== "object") return null;
|
|
61
|
-
current = current[key];
|
|
253
|
+
await this.ready();
|
|
254
|
+
if (fetch) {
|
|
255
|
+
const data = await this.collection.findOne({ _id: this.id });
|
|
256
|
+
this.cache = data ? data.data : {};
|
|
62
257
|
}
|
|
258
|
+
return lodash2.get(this.cache, path2, null);
|
|
63
259
|
}
|
|
64
|
-
delete(
|
|
65
|
-
if (!
|
|
260
|
+
async delete(path2, fetch = false) {
|
|
261
|
+
if (!path2 || typeof path2 !== "string")
|
|
66
262
|
throw new Error(pathErrorMessage);
|
|
67
|
-
|
|
68
|
-
|
|
263
|
+
await this.ready();
|
|
264
|
+
if (fetch) {
|
|
265
|
+
const data = await this.collection.findOne({ _id: this.id });
|
|
266
|
+
this.cache = data ? data.data : {};
|
|
267
|
+
}
|
|
268
|
+
const pathExists = await this.get(path2);
|
|
69
269
|
if (pathExists === null)
|
|
70
270
|
throw new Error("The path does not exists or its value is null");
|
|
71
|
-
this.update(
|
|
72
|
-
writeFileSync(this.path, JSON.stringify(this.data, null, 2), "utf8");
|
|
73
|
-
return this.data;
|
|
271
|
+
return this.update(path2, null);
|
|
74
272
|
}
|
|
75
|
-
sumOrSub(
|
|
76
|
-
if (!
|
|
273
|
+
async sumOrSub(path2, value, type, fetch = false) {
|
|
274
|
+
if (!path2 || typeof path2 !== "string")
|
|
77
275
|
throw new Error(pathErrorMessage);
|
|
78
276
|
if (!type || !["sum", "sub"].includes(type))
|
|
79
277
|
throw new Error('The type must be "sum" or "sub"');
|
|
@@ -82,47 +280,67 @@ var TwinDB = class {
|
|
|
82
280
|
throw new Error(
|
|
83
281
|
`The value to ${isSum ? "sum" : "sub"} must be a number`
|
|
84
282
|
);
|
|
85
|
-
|
|
283
|
+
await this.ready();
|
|
284
|
+
if (fetch) {
|
|
285
|
+
const data = await this.collection.findOne({ _id: this.id });
|
|
286
|
+
this.cache = data ? data.data : {};
|
|
287
|
+
}
|
|
288
|
+
let currentValue = await this.get(path2) || 0;
|
|
86
289
|
if (typeof currentValue !== "number") currentValue = 0;
|
|
87
290
|
return this.update(
|
|
88
|
-
|
|
291
|
+
path2,
|
|
89
292
|
isSum ? currentValue + value : currentValue - value
|
|
90
293
|
);
|
|
91
294
|
}
|
|
92
|
-
sum(
|
|
93
|
-
return this.sumOrSub(
|
|
295
|
+
async sum(path2, value, fetch = false) {
|
|
296
|
+
return this.sumOrSub(path2, value, "sum", fetch);
|
|
94
297
|
}
|
|
95
|
-
sub(
|
|
96
|
-
return this.sumOrSub(
|
|
298
|
+
async sub(path2, value, fetch = false) {
|
|
299
|
+
return this.sumOrSub(path2, value, "sub", fetch);
|
|
97
300
|
}
|
|
98
|
-
concat(
|
|
99
|
-
if (!
|
|
301
|
+
async concat(path2, value, fetch = false) {
|
|
302
|
+
if (!path2 || typeof path2 !== "string")
|
|
100
303
|
throw new Error(pathErrorMessage);
|
|
101
304
|
if (!value || typeof value !== "string")
|
|
102
305
|
throw new Error("You must provide a string value to update");
|
|
103
|
-
|
|
306
|
+
await this.ready();
|
|
307
|
+
if (fetch) {
|
|
308
|
+
const data = await this.collection.findOne({ _id: this.id });
|
|
309
|
+
this.cache = data ? data.data : {};
|
|
310
|
+
}
|
|
311
|
+
const currentValue = await this.get(path2);
|
|
104
312
|
if (typeof currentValue !== "string")
|
|
105
313
|
throw new Error(
|
|
106
314
|
"The value to concat is not a string or the path does not exists"
|
|
107
315
|
);
|
|
108
|
-
return this.update(
|
|
316
|
+
return this.update(path2, currentValue + value);
|
|
109
317
|
}
|
|
110
|
-
push(
|
|
111
|
-
if (!
|
|
318
|
+
async push(path2, values, fetch = false) {
|
|
319
|
+
if (!path2 || typeof path2 !== "string")
|
|
112
320
|
throw new Error(pathErrorMessage);
|
|
113
321
|
if (!values || values.length === 0)
|
|
114
322
|
throw new Error("You must provide a value to update");
|
|
115
|
-
|
|
323
|
+
await this.ready();
|
|
324
|
+
if (fetch) {
|
|
325
|
+
const data = await this.collection.findOne({ _id: this.id });
|
|
326
|
+
this.cache = data ? data.data : {};
|
|
327
|
+
}
|
|
328
|
+
let currentValue = await this.get(path2) || [];
|
|
116
329
|
if (!Array.isArray(currentValue)) currentValue = [];
|
|
117
330
|
currentValue.push(...values);
|
|
118
|
-
return this.update(
|
|
331
|
+
return this.update(path2, currentValue);
|
|
119
332
|
}
|
|
120
|
-
pull(
|
|
121
|
-
if (!
|
|
333
|
+
async pull(path2, values, fetch = false) {
|
|
334
|
+
if (!path2 || typeof path2 !== "string")
|
|
122
335
|
throw new Error(pathErrorMessage);
|
|
123
336
|
if (!values || values.length === 0)
|
|
124
337
|
throw new Error("You must provide a value to update");
|
|
125
|
-
|
|
338
|
+
await this.ready();
|
|
339
|
+
if (fetch) {
|
|
340
|
+
const data = await this.collection.findOne({ _id: this.id });
|
|
341
|
+
this.cache = data ? data.data : {};
|
|
342
|
+
}
|
|
343
|
+
const currentValue = await this.get(path2);
|
|
126
344
|
if (!Array.isArray(currentValue))
|
|
127
345
|
throw new Error(
|
|
128
346
|
"The current value of this path is not an array or the path does not exists"
|
|
@@ -132,10 +350,13 @@ var TwinDB = class {
|
|
|
132
350
|
if (index < 0) continue;
|
|
133
351
|
currentValue.splice(index, 1);
|
|
134
352
|
}
|
|
135
|
-
return this.update(
|
|
353
|
+
return this.update(path2, currentValue);
|
|
136
354
|
}
|
|
137
355
|
};
|
|
138
356
|
export {
|
|
139
|
-
|
|
357
|
+
JSONStorage,
|
|
358
|
+
SqliteStorage,
|
|
359
|
+
TwinDB,
|
|
360
|
+
TwinMongoDB
|
|
140
361
|
};
|
|
141
362
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/structures/database.ts"],"sourcesContent":["import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';\n\nconst pathErrorMessage = 'The path must be a string or you dont provide a path';\n\nexport class TwinDB {\n public data: Record<string, unknown>;\n public path: string;\n public name: string;\n\n public constructor(name: string = 'db') {\n this.path = 'database/' + name + '.json';\n this.name = name;\n this.data = {};\n\n if (!existsSync('database')) mkdirSync('database');\n this.load();\n }\n\n private load() {\n let data: string;\n try {\n data = readFileSync(this.path, 'utf8');\n } catch (e) {\n data = '';\n }\n this.data = data ? JSON.parse(data) : {};\n\n if (!data)\n writeFileSync(\n this.path,\n JSON.stringify(this.data, null, 2),\n 'utf8',\n );\n }\n\n private update(path: string /*user.info.name*/, value: unknown) {\n const keys = path.split('.');\n\n let current = this.data;\n for (let i = 0; i < keys.length; i++) {\n let key = keys[i];\n\n if (i === keys.length - 1) {\n current[key] = value;\n break;\n } \n \n if (typeof current[key] !== 'object' || Array.isArray(current[key]) || !current[key]) {\n current[key] = {};\n }\n\n current = current[key] as Record<string, unknown>;\n }\n\n writeFileSync(this.path, JSON.stringify(this.data, null, 2), 'utf8');\n\n return this.data;\n }\n\n public set(path: string, value: unknown) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (value === undefined)\n throw new Error('You must provide a value to update');\n\n return this.update(path, value);\n }\n\n public get(path: string): unknown | null {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n const keys = path.split('.');\n let current = this.data;\n let i = 0;\n\n for (const key of keys) {\n i++;\n\n if (i === keys.length) return current[key] ?? null;\n\n if (typeof current[key] !== 'object') return null;\n\n current = current[key] as Record<string, unknown>;\n }\n }\n\n public delete(path: string) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n const keys = path.split('.');\n const pathExists = this.get(path);\n if (pathExists === null)\n throw new Error('The path does not exists or its value is null');\n\n this.update(path, null);\n\n writeFileSync(this.path, JSON.stringify(this.data, null, 2), 'utf8');\n\n return this.data;\n }\n\n private sumOrSub(path: string, value: number, type: SumOrSub) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (!type || !['sum', 'sub'].includes(type))\n throw new Error('The type must be \"sum\" or \"sub\"');\n const isSum = type === 'sum';\n if (!value || typeof value !== 'number')\n throw new Error(\n `The value to ${isSum ? 'sum' : 'sub'} must be a number`,\n );\n\n let currentValue = (this.get(path) || 0) as unknown as number;\n if (typeof currentValue !== 'number') currentValue = 0;\n\n return this.update(\n path,\n isSum ? currentValue + value : currentValue - value,\n );\n }\n\n public sum(path: string, value: number) {\n return this.sumOrSub(path, value, 'sum');\n }\n\n public sub(path: string, value: number) {\n return this.sumOrSub(path, value, 'sub');\n }\n\n public concat(path: string, value: string) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (!value || typeof value !== 'string')\n throw new Error('You must provide a string value to update');\n\n const currentValue = this.get(path);\n if (typeof currentValue !== 'string')\n throw new Error(\n 'The value to concat is not a string or the path does not exists',\n );\n\n return this.update(path, currentValue + value);\n }\n\n public push(path: string, ...values: unknown[]) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (!values || values.length === 0)\n throw new Error('You must provide a value to update');\n\n let currentValue = (this.get(path) || []) as unknown as unknown[];\n if (!Array.isArray(currentValue)) currentValue = [];\n\n currentValue.push(...values);\n return this.update(path, currentValue);\n }\n\n public pull(path: string, ...values: unknown[]) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (!values || values.length === 0)\n throw new Error('You must provide a value to update');\n\n const currentValue = this.get(path);\n if (!Array.isArray(currentValue))\n throw new Error(\n 'The current value of this path is not an array or the path does not exists',\n );\n\n for (const value of values) {\n const index = currentValue.indexOf(value);\n if (index < 0) continue;\n\n currentValue.splice(index, 1);\n }\n\n return this.update(path, currentValue);\n }\n}\n\nexport type SumOrSub = 'sum' | 'sub';\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/structures/TwinDB.ts","../src/storages/JSONStorage.ts","../src/storages/SqliteStorage.ts","../src/utils/vars.ts","../src/structures/TwinMongoDB.ts"],"sourcesContent":["import lodash from 'lodash';\nimport {\n SumOrSub,\n TwinDBOptions,\n StorageInstanceType,\n} from '../types/global.js';\nimport { JSONStorage } from '../storages/JSONStorage.js';\nimport { SqliteStorage } from '../storages/SqliteStorage.js';\nimport path from 'node:path';\nimport { mkdirSync } from 'node:fs';\nimport { pathErrorMessage } from '../utils/vars.js';\n\nexport class TwinDB {\n public cache: Record<string, unknown>;\n private storage: StorageInstanceType;\n\n public constructor(\n argPath: string = 'database/twin',\n options: TwinDBOptions = { storage: JSONStorage },\n ) {\n if (!argPath || typeof argPath !== 'string')\n throw new Error(pathErrorMessage);\n\n const solvedPath = path.resolve(process.cwd(), argPath);\n mkdirSync(path.dirname(solvedPath), { recursive: true });\n\n if (!options || typeof options !== 'object' || Array.isArray(options))\n options = { storage: JSONStorage };\n\n options.storage ||= JSONStorage;\n\n if (![JSONStorage, SqliteStorage].includes(options.storage))\n throw new Error('Invalid storage type passed in options');\n\n this.storage =\n options.storage === SqliteStorage\n // @ts-expect-error - table and key exists here\n ? new options.storage(solvedPath, options.table, options.key)\n : new options.storage(solvedPath);\n\n this.cache = this.storage.get();\n }\n\n private update(\n path: string /*user.info.name*/,\n value: unknown,\n fetch: boolean = false,\n ) {\n if (fetch) this.cache = this.storage.get();\n\n lodash.set(this.cache, path, value);\n\n this.storage.set(JSON.stringify(this.cache));\n\n return this.cache;\n }\n\n public set(path: string, value: unknown, fetch: boolean = false) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (value === undefined)\n throw new Error('You must provide a value to update');\n\n return this.update(path, value, fetch);\n }\n\n public get(path: string, fetch: boolean = false): unknown | null {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n\n if (fetch) this.cache = this.storage.get();\n\n return lodash.get(this.cache, path, null);\n }\n\n public delete(path: string, fetch: boolean = false) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n\n if (fetch) this.cache = this.storage.get();\n\n const pathExists = this.get(path);\n if (pathExists === null)\n throw new Error('The path does not exists or its value is null');\n\n return this.update(path, null);\n }\n\n public remove = this.delete;\n\n private sumOrSub(\n path: string,\n value: number,\n type: SumOrSub,\n fetch: boolean = false,\n ) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (!type || !['sum', 'sub'].includes(type))\n throw new Error('The type must be \"sum\" or \"sub\"');\n const isSum = type === 'sum';\n if (!value || typeof value !== 'number')\n throw new Error(\n `The value to ${isSum ? 'sum' : 'sub'} must be a number`,\n );\n\n if (fetch) this.cache = this.storage.get();\n\n let currentValue = (this.get(path) || 0) as unknown as number;\n if (typeof currentValue !== 'number') currentValue = 0;\n\n return this.update(\n path,\n isSum ? currentValue + value : currentValue - value,\n );\n }\n\n public sum(path: string, value: number, fetch: boolean = false) {\n return this.sumOrSub(path, value, 'sum', fetch);\n }\n\n public add = this.sum;\n\n public sub(path: string, value: number, fetch: boolean = false) {\n return this.sumOrSub(path, value, 'sub', fetch);\n }\n\n public subtract = this.sub;\n\n public concat(path: string, value: string, fetch: boolean = false) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (!value || typeof value !== 'string')\n throw new Error('You must provide a string value to update');\n\n if (fetch) this.cache = this.storage.get();\n\n const currentValue = this.get(path);\n if (typeof currentValue !== 'string')\n throw new Error(\n 'The value to concat is not a string or the path does not exists',\n );\n\n return this.update(path, currentValue + value);\n }\n\n public push(path: string, values: unknown[], fetch: boolean = false) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (!values || values.length === 0)\n throw new Error('You must provide a value to update');\n\n if (fetch) this.cache = this.storage.get();\n\n let currentValue = (this.get(path) || []) as unknown as unknown[];\n if (!Array.isArray(currentValue)) currentValue = [];\n\n currentValue.push(...values);\n return this.update(path, currentValue);\n }\n\n public pull(path: string, values: unknown[], fetch: boolean = false) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (!values || values.length === 0)\n throw new Error('You must provide a value to update');\n\n if (fetch) this.cache = this.storage.get();\n\n const currentValue = this.get(path);\n if (!Array.isArray(currentValue))\n throw new Error(\n 'The current value of this path is not an array or the path does not exists',\n );\n\n for (const value of values) {\n const index = currentValue.indexOf(value);\n if (index < 0) continue;\n\n currentValue.splice(index, 1);\n }\n\n return this.update(path, currentValue);\n }\n}\n","import { readFileSync, writeFileSync, existsSync } from 'node:fs';\nimport { Storage } from '../types/Storage.js';\n\nexport class JSONStorage implements Storage {\n public readonly path: string;\n\n public constructor(path: string) {\n if (!path.endsWith('.json')) path += '.json';\n this.path = path;\n\n if (!existsSync(path)) writeFileSync(path, '{}', 'utf8');\n else {\n const data = readFileSync(path, 'utf8');\n let parsedData;\n try {\n parsedData = JSON.parse(data);\n } catch (_) {}\n\n if (\n !data ||\n !parsedData ||\n typeof parsedData !== 'object' ||\n Array.isArray(parsedData)\n )\n writeFileSync(path, '{}', 'utf8');\n }\n }\n\n public get() {\n let data;\n try {\n data = readFileSync(this.path, 'utf8');\n } catch (_) {}\n\n let parsedData;\n try {\n if (data) parsedData = JSON.parse(data);\n } catch (_) {}\n\n const checkedData =\n data &&\n parsedData &&\n typeof parsedData === 'object' &&\n !Array.isArray(parsedData);\n if (!checkedData) writeFileSync(this.path, '{}', 'utf8');\n\n return checkedData ? parsedData : {};\n }\n\n public set(value: string) {\n writeFileSync(this.path, value, 'utf8');\n\n return true;\n }\n}\n","import { Storage } from '../types/Storage.js';\nimport { DatabaseSync } from 'node:sqlite';\nimport { DEFAULT_KEY, DEFAULT_NAME } from '../utils/vars.js';\n\nexport class SqliteStorage implements Storage {\n private readonly db: DatabaseSync;\n private readonly table: string;\n private readonly key: string;\n\n public constructor(\n path: string,\n table: string = DEFAULT_NAME,\n key: string = DEFAULT_KEY,\n ) {\n if (!table || typeof table !== 'string') table = DEFAULT_NAME;\n if (!key || typeof key !== 'string') key = DEFAULT_KEY;\n\n this.table = table;\n this.key = key;\n\n if (!path.endsWith('.db')) path += '.db';\n this.db = new DatabaseSync(path);\n\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS ${table} (\n key TEXT PRIMARY KEY,\n value TEXT\n )\n `);\n }\n\n public set(value: string /*json strringfyed value*/) {\n this.db\n .prepare(\n `INSERT OR REPLACE INTO ${this.table} (key, value) VALUES (?, ?)`,\n )\n .run(this.key, value);\n\n return true;\n }\n\n public get() {\n const row = this.db\n .prepare(`SELECT value FROM ${this.table} WHERE key = ?`)\n .get(this.key) as unknown as { value: string } | undefined;\n\n return row ? JSON.parse(row.value) : {};\n }\n}\n","export const DEFAULT_KEY = 'data';\n\nexport const DEFAULT_NAME = 'twin';\n\nexport const pathErrorMessage =\n 'The path must be a string or you dont provided a path';\n","import lodash from 'lodash';\nimport { MongoClient, Collection } from 'mongodb';\nimport { SumOrSub, DefaultSchemaType } from '../types/global.js';\nimport { DEFAULT_KEY, DEFAULT_NAME, pathErrorMessage } from '../utils/vars.js';\n\nexport class TwinMongoDB {\n private readonly client: MongoClient;\n private collection!: Collection<DefaultSchemaType>;\n public cache: Record<string, unknown>;\n private initPromise: Promise<void>;\n private readonly id: string;\n\n public constructor(\n connectionURI: string,\n modelName: string = DEFAULT_NAME,\n id: string = DEFAULT_KEY,\n ) {\n if (!modelName || typeof modelName !== 'string')\n modelName = DEFAULT_NAME;\n if (!id || typeof id !== 'string') id = DEFAULT_KEY;\n\n this.client = new MongoClient(connectionURI);\n this.cache = {};\n this.id = id;\n\n this.initPromise = this.init(modelName);\n }\n\n private async init(modelName: string) {\n await this.client.connect();\n\n this.collection = this.client\n .db()\n .collection<DefaultSchemaType>(modelName);\n\n const data = await this.collection.findOne({ _id: this.id });\n\n if (!data) {\n const created: DefaultSchemaType = { _id: this.id, data: {} };\n await this.collection.insertOne(created);\n\n this.cache = created.data;\n return;\n }\n\n this.cache = data.data;\n }\n\n public async close() {\n await this.client.close();\n }\n\n private async ready() {\n await this.initPromise;\n }\n\n private async update(path: string, value: unknown, fetch: boolean = false) {\n await this.ready();\n if (fetch) {\n const data = await this.collection.findOne({ _id: this.id });\n this.cache = data ? data.data : {};\n }\n\n lodash.set(this.cache, path, value);\n\n await this.collection.updateOne(\n { _id: this.id },\n { $set: { data: this.cache } },\n { upsert: true },\n );\n\n return this.cache;\n }\n\n public async set(path: string, value: unknown, fetch: boolean = false) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (value === undefined)\n throw new Error('You must provide a value to update');\n\n return this.update(path, value, fetch);\n }\n\n public async get(\n path: string,\n fetch: boolean = false,\n ): Promise<unknown | null> {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n\n await this.ready();\n if (fetch) {\n const data = await this.collection.findOne({ _id: this.id });\n this.cache = data ? data.data : {};\n }\n\n return lodash.get(this.cache, path, null);\n }\n\n public async delete(path: string, fetch: boolean = false) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n\n await this.ready();\n if (fetch) {\n const data = await this.collection.findOne({ _id: this.id });\n this.cache = data ? data.data : {};\n }\n\n const pathExists = await this.get(path);\n if (pathExists === null)\n throw new Error('The path does not exists or its value is null');\n\n return this.update(path, null);\n }\n\n public remove = this.delete;\n\n private async sumOrSub(\n path: string,\n value: number,\n type: SumOrSub,\n fetch: boolean = false,\n ) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (!type || !['sum', 'sub'].includes(type))\n throw new Error('The type must be \"sum\" or \"sub\"');\n const isSum = type === 'sum';\n if (!value || typeof value !== 'number')\n throw new Error(\n `The value to ${isSum ? 'sum' : 'sub'} must be a number`,\n );\n\n await this.ready();\n if (fetch) {\n const data = await this.collection.findOne({ _id: this.id });\n this.cache = data ? data.data : {};\n }\n\n let currentValue = ((await this.get(path)) || 0) as unknown as number;\n if (typeof currentValue !== 'number') currentValue = 0;\n\n return this.update(\n path,\n isSum ? currentValue + value : currentValue - value,\n );\n }\n\n public async sum(path: string, value: number, fetch: boolean = false) {\n return this.sumOrSub(path, value, 'sum', fetch);\n }\n\n public add = this.sum;\n\n public async sub(path: string, value: number, fetch: boolean = false) {\n return this.sumOrSub(path, value, 'sub', fetch);\n }\n\n public subtract = this.sub;\n\n public async concat(path: string, value: string, fetch: boolean = false) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (!value || typeof value !== 'string')\n throw new Error('You must provide a string value to update');\n\n await this.ready();\n if (fetch) {\n const data = await this.collection.findOne({ _id: this.id });\n this.cache = data ? data.data : {};\n }\n\n const currentValue = await this.get(path);\n if (typeof currentValue !== 'string')\n throw new Error(\n 'The value to concat is not a string or the path does not exists',\n );\n\n return this.update(path, currentValue + value);\n }\n\n public async push(path: string, values: unknown[], fetch: boolean = false) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (!values || values.length === 0)\n throw new Error('You must provide a value to update');\n\n await this.ready();\n if (fetch) {\n const data = await this.collection.findOne({ _id: this.id });\n this.cache = data ? data.data : {};\n }\n\n let currentValue = ((await this.get(path)) ||\n []) as unknown as unknown[];\n if (!Array.isArray(currentValue)) currentValue = [];\n\n currentValue.push(...values);\n return this.update(path, currentValue);\n }\n\n public async pull(path: string, values: unknown[], fetch: boolean = false) {\n if (!path || typeof path !== 'string')\n throw new Error(pathErrorMessage);\n if (!values || values.length === 0)\n throw new Error('You must provide a value to update');\n\n await this.ready();\n if (fetch) {\n const data = await this.collection.findOne({ _id: this.id });\n this.cache = data ? data.data : {};\n }\n\n const currentValue = await this.get(path);\n if (!Array.isArray(currentValue))\n throw new Error(\n 'The current value of this path is not an array or the path does not exists',\n );\n\n for (const value of values) {\n const index = currentValue.indexOf(value);\n if (index < 0) continue;\n\n currentValue.splice(index, 1);\n }\n\n return this.update(path, currentValue);\n }\n}\n"],"mappings":"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","names":["path","path","path","lodash","path","lodash"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "twin-db",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A usefully local database.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
"exports": {
|
|
13
13
|
".": {
|
|
14
14
|
"import": {
|
|
15
|
-
"types": "./dist/index.d.mts",
|
|
16
|
-
"default": "./dist/index.mjs"
|
|
17
|
-
},
|
|
18
|
-
"require": {
|
|
19
15
|
"types": "./dist/index.d.ts",
|
|
20
16
|
"default": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"require": {
|
|
19
|
+
"types": "./dist/index.d.cts",
|
|
20
|
+
"default": "./dist/index.cjs"
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
},
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
],
|
|
42
42
|
"license": "MIT",
|
|
43
43
|
"devDependencies": {
|
|
44
|
+
"@types/lodash": "^4.17.24",
|
|
44
45
|
"@types/node": "^25.6.0",
|
|
45
46
|
"prettier": "^3.8.1",
|
|
46
47
|
"tsup": "^8.5.1",
|
|
@@ -52,6 +53,10 @@
|
|
|
52
53
|
"url": "https://github.com/toddy007/twin-db.git"
|
|
53
54
|
},
|
|
54
55
|
"engines": {
|
|
55
|
-
"node": ">=
|
|
56
|
+
"node": ">=22.13.0"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"lodash": "^4.18.1",
|
|
60
|
+
"mongodb": "^7.5.0"
|
|
56
61
|
}
|
|
57
62
|
}
|