lamix 4.2.18 → 4.2.20
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/bin/cli.js +1 -1
- package/lib/index.d.ts +37 -14
- package/lib/index.js +118 -40
- package/package.json +1 -1
package/bin/cli.js
CHANGED
package/lib/index.d.ts
CHANGED
|
@@ -67,6 +67,7 @@ export class Model {
|
|
|
67
67
|
static whereNot(...args: any[]): QueryBuilder;
|
|
68
68
|
static whereNotIn(col: any, arr: any): QueryBuilder;
|
|
69
69
|
static whereNull(col: any): QueryBuilder;
|
|
70
|
+
static filter(...args: any[]): QueryBuilder;
|
|
70
71
|
static find(value: any): Promise<any>;
|
|
71
72
|
static findOrFail(value: any): Promise<any>;
|
|
72
73
|
static findBy(col: any, value: any): Promise<any>;
|
|
@@ -212,7 +213,15 @@ export class Collection extends Array<any> {
|
|
|
212
213
|
clone(): Collection;
|
|
213
214
|
each(fn: any): Promise<this>;
|
|
214
215
|
mapAsync(fn: any): Promise<Collection>;
|
|
215
|
-
|
|
216
|
+
/**
|
|
217
|
+
* Enhanced filter:
|
|
218
|
+
* - filter(fn)
|
|
219
|
+
* - filter({ key: value })
|
|
220
|
+
* - filter('key', value)
|
|
221
|
+
* - filter('key', '>', value)
|
|
222
|
+
*/
|
|
223
|
+
filter(condition: any, operator?: any, value?: any): Collection;
|
|
224
|
+
where(key: any, operator: any, value?: any): Collection;
|
|
216
225
|
whereNot(key: any, value: any): Collection;
|
|
217
226
|
filterNull(): Collection;
|
|
218
227
|
onlyKeys(keys: any): Collection;
|
|
@@ -494,7 +503,7 @@ export class LamixSessionStore {
|
|
|
494
503
|
cleanupInterval: any;
|
|
495
504
|
logger: any;
|
|
496
505
|
compress: any;
|
|
497
|
-
cache:
|
|
506
|
+
cache: LRUCache<{}, {}, unknown>;
|
|
498
507
|
redisEnabled: boolean;
|
|
499
508
|
redisRetryAt: number;
|
|
500
509
|
redisCooldown: any;
|
|
@@ -548,23 +557,36 @@ export class BaseModel extends Model {
|
|
|
548
557
|
}
|
|
549
558
|
declare class SimpleCache {
|
|
550
559
|
constructor(options?: {});
|
|
551
|
-
cache:
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
560
|
+
cache: LRUCache<{}, {}, unknown>;
|
|
561
|
+
/**
|
|
562
|
+
* Get cached value
|
|
563
|
+
* @param {string} key
|
|
564
|
+
* @returns {*} value or null
|
|
565
|
+
*/
|
|
566
|
+
get(key: string): any;
|
|
557
567
|
/**
|
|
558
|
-
*
|
|
559
|
-
*
|
|
568
|
+
* Set cache value
|
|
569
|
+
* @param {string} key
|
|
570
|
+
* @param {*} value
|
|
571
|
+
* @param {number} ttl Optional TTL in ms
|
|
560
572
|
*/
|
|
561
|
-
|
|
573
|
+
set(key: string, value: any, ttl?: number): void;
|
|
574
|
+
/**
|
|
575
|
+
* Delete a key
|
|
576
|
+
* @param {string} key
|
|
577
|
+
*/
|
|
578
|
+
del(key: string): void;
|
|
579
|
+
/**
|
|
580
|
+
* Clear entire cache
|
|
581
|
+
*/
|
|
582
|
+
clear(): void;
|
|
562
583
|
/**
|
|
563
|
-
*
|
|
584
|
+
* Get cache stats (optional utility)
|
|
564
585
|
*/
|
|
565
586
|
stats(): {
|
|
566
|
-
size:
|
|
567
|
-
calculatedSize:
|
|
587
|
+
size: number;
|
|
588
|
+
calculatedSize: number;
|
|
589
|
+
maxSize: number;
|
|
568
590
|
};
|
|
569
591
|
}
|
|
570
592
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -625,4 +647,5 @@ declare class Relation {
|
|
|
625
647
|
deleteBehavior: any;
|
|
626
648
|
onDelete(behavior: any): this;
|
|
627
649
|
}
|
|
650
|
+
import { LRUCache } from "lru-cache";
|
|
628
651
|
export {};
|
package/lib/index.js
CHANGED
|
@@ -6,7 +6,7 @@ const { AsyncLocalStorage } = require('async_hooks');
|
|
|
6
6
|
require('dotenv').config();
|
|
7
7
|
const session = require('express-session');
|
|
8
8
|
const Redis = require('ioredis');
|
|
9
|
-
const LRUCache = require('lru-cache');
|
|
9
|
+
const { LRUCache } = require('lru-cache');
|
|
10
10
|
const zlib = require('zlib');
|
|
11
11
|
|
|
12
12
|
/* ---------------- Utilities ---------------- */
|
|
@@ -32,68 +32,75 @@ class DBError extends Error {
|
|
|
32
32
|
class SimpleCache {
|
|
33
33
|
constructor(options = {}) {
|
|
34
34
|
const {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
maxSize, // optional size-based eviction
|
|
38
|
-
sizeCalculation, // function(value, key)
|
|
35
|
+
maxSizeMB = 50, // total memory cap
|
|
36
|
+
defaultTTL = 1000 * 60 * 5, // 5 minutes
|
|
39
37
|
} = options;
|
|
40
38
|
|
|
41
39
|
this.cache = new LRUCache({
|
|
42
|
-
|
|
43
|
-
ttl,
|
|
40
|
+
maxSize: maxSizeMB * 1024 * 1024, // convert MB → bytes
|
|
41
|
+
ttl: defaultTTL,
|
|
44
42
|
ttlAutopurge: true,
|
|
45
|
-
maxSize,
|
|
46
|
-
sizeCalculation,
|
|
47
43
|
allowStale: false,
|
|
48
|
-
|
|
44
|
+
|
|
45
|
+
// Estimate memory usage per entry
|
|
46
|
+
sizeCalculation: (value, key) => {
|
|
47
|
+
try {
|
|
48
|
+
return Buffer.byteLength(JSON.stringify(value));
|
|
49
|
+
} catch (err) {
|
|
50
|
+
// fallback small size if stringify fails
|
|
51
|
+
return 1024;
|
|
52
|
+
}
|
|
53
|
+
},
|
|
49
54
|
});
|
|
50
55
|
}
|
|
51
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Get cached value
|
|
59
|
+
* @param {string} key
|
|
60
|
+
* @returns {*} value or null
|
|
61
|
+
*/
|
|
52
62
|
get(key) {
|
|
53
63
|
const value = this.cache.get(key);
|
|
54
64
|
return value === undefined ? null : value;
|
|
55
65
|
}
|
|
56
66
|
|
|
57
|
-
|
|
58
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Set cache value
|
|
69
|
+
* @param {string} key
|
|
70
|
+
* @param {*} value
|
|
71
|
+
* @param {number} ttl Optional TTL in ms
|
|
72
|
+
*/
|
|
73
|
+
set(key, value, ttl = 0) {
|
|
74
|
+
if (ttl > 0) {
|
|
59
75
|
this.cache.set(key, value, { ttl });
|
|
60
76
|
} else {
|
|
61
77
|
this.cache.set(key, value);
|
|
62
78
|
}
|
|
63
79
|
}
|
|
64
80
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
clear() {
|
|
74
|
-
this.cache.clear();
|
|
81
|
+
/**
|
|
82
|
+
* Delete a key
|
|
83
|
+
* @param {string} key
|
|
84
|
+
*/
|
|
85
|
+
del(key) {
|
|
86
|
+
this.cache.delete(key);
|
|
75
87
|
}
|
|
76
88
|
|
|
77
89
|
/**
|
|
78
|
-
*
|
|
79
|
-
* Supports async functions
|
|
90
|
+
* Clear entire cache
|
|
80
91
|
*/
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (existing !== null) return existing;
|
|
84
|
-
|
|
85
|
-
const value = await fetchFn();
|
|
86
|
-
this.set(key, value, ttl);
|
|
87
|
-
return value;
|
|
92
|
+
clear() {
|
|
93
|
+
this.cache.clear();
|
|
88
94
|
}
|
|
89
95
|
|
|
90
96
|
/**
|
|
91
|
-
*
|
|
97
|
+
* Get cache stats (optional utility)
|
|
92
98
|
*/
|
|
93
99
|
stats() {
|
|
94
100
|
return {
|
|
95
101
|
size: this.cache.size,
|
|
96
102
|
calculatedSize: this.cache.calculatedSize,
|
|
103
|
+
maxSize: this.cache.maxSize,
|
|
97
104
|
};
|
|
98
105
|
}
|
|
99
106
|
}
|
|
@@ -124,7 +131,7 @@ class DB {
|
|
|
124
131
|
static config = null;
|
|
125
132
|
static pool = null;
|
|
126
133
|
|
|
127
|
-
static cache = new SimpleCache({
|
|
134
|
+
static cache = new SimpleCache({ maxSizeMB: 500, defaultTTL: 1000 * 60 * 2});
|
|
128
135
|
static retryAttempts = 1;
|
|
129
136
|
|
|
130
137
|
static eventHandlers = { query: [], error: [], reconnect: [] };
|
|
@@ -929,16 +936,78 @@ class Collection extends Array {
|
|
|
929
936
|
// -------------------------
|
|
930
937
|
// Filtering
|
|
931
938
|
// -------------------------
|
|
932
|
-
|
|
933
|
-
|
|
939
|
+
/**
|
|
940
|
+
* Enhanced filter:
|
|
941
|
+
* - filter(fn)
|
|
942
|
+
* - filter({ key: value })
|
|
943
|
+
* - filter('key', value)
|
|
944
|
+
* - filter('key', '>', value)
|
|
945
|
+
*/
|
|
946
|
+
filter(condition, operator = null, value = null) {
|
|
947
|
+
|
|
948
|
+
// 1️⃣ Callback style
|
|
949
|
+
if (typeof condition === 'function') {
|
|
950
|
+
return new Collection(
|
|
951
|
+
Array.prototype.filter.call(this, condition)
|
|
952
|
+
);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// 2️⃣ Object style
|
|
956
|
+
if (typeof condition === 'object' && !Array.isArray(condition)) {
|
|
957
|
+
return new Collection(
|
|
958
|
+
Array.prototype.filter.call(this, item =>
|
|
959
|
+
Object.entries(condition).every(
|
|
960
|
+
([k, v]) => item?.[k] === v
|
|
961
|
+
)
|
|
962
|
+
)
|
|
963
|
+
);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
// 3️⃣ Key/value or key/operator/value
|
|
967
|
+
if (typeof condition === 'string') {
|
|
968
|
+
|
|
969
|
+
// If only 2 args → assume "="
|
|
970
|
+
if (value === null) {
|
|
971
|
+
value = operator;
|
|
972
|
+
operator = '=';
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
return new Collection(
|
|
976
|
+
Array.prototype.filter.call(this, item => {
|
|
977
|
+
const field = item?.[condition];
|
|
978
|
+
|
|
979
|
+
switch (operator) {
|
|
980
|
+
case '=':
|
|
981
|
+
case '==': return field == value;
|
|
982
|
+
case '===': return field === value;
|
|
983
|
+
case '!=': return field != value;
|
|
984
|
+
case '!==': return field !== value;
|
|
985
|
+
case '>': return field > value;
|
|
986
|
+
case '>=': return field >= value;
|
|
987
|
+
case '<': return field < value;
|
|
988
|
+
case '<=': return field <= value;
|
|
989
|
+
case 'in': return Array.isArray(value) && value.includes(field);
|
|
990
|
+
case 'not in': return Array.isArray(value) && !value.includes(field);
|
|
991
|
+
default: return false;
|
|
992
|
+
}
|
|
993
|
+
})
|
|
994
|
+
);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
return new Collection();
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
// Laravel-style aliases
|
|
1001
|
+
where(key, operator, value = null) {
|
|
1002
|
+
return this.filter(key, operator, value);
|
|
934
1003
|
}
|
|
935
1004
|
|
|
936
1005
|
whereNot(key, value) {
|
|
937
|
-
return
|
|
1006
|
+
return this.filter(item => item?.[key] !== value);
|
|
938
1007
|
}
|
|
939
1008
|
|
|
940
1009
|
filterNull() {
|
|
941
|
-
return
|
|
1010
|
+
return this.filter(v => v !== null && v !== undefined);
|
|
942
1011
|
}
|
|
943
1012
|
|
|
944
1013
|
onlyKeys(keys) {
|
|
@@ -3217,22 +3286,31 @@ class Model {
|
|
|
3217
3286
|
// ──────────────────────────────
|
|
3218
3287
|
static async all() { return await this.query().get(); }
|
|
3219
3288
|
static where(...args) { return this.query().where(...args); }
|
|
3289
|
+
// static filter(...args) { return this.query().where(...args); }
|
|
3220
3290
|
static whereIn(col, arr) { return this.query().whereIn(col, arr); }
|
|
3221
3291
|
static whereNot(...args) { return this.query().whereNot(...args); }
|
|
3222
3292
|
static whereNotIn(col, arr) { return this.query().whereNotIn(col, arr); }
|
|
3223
3293
|
static whereNull(col) { return this.query().whereNull(col); }
|
|
3224
3294
|
|
|
3295
|
+
static filter(...args) {
|
|
3296
|
+
const qb = this.query();
|
|
3297
|
+
if (args.length === 1 && typeof args[0] === 'object' && !Array.isArray(args[0])) {
|
|
3298
|
+
for (const [key, value] of Object.entries(args[0])) {
|
|
3299
|
+
qb.where(key, value);
|
|
3300
|
+
}
|
|
3301
|
+
return qb;
|
|
3302
|
+
}
|
|
3303
|
+
return qb.where(...args);
|
|
3304
|
+
}
|
|
3305
|
+
|
|
3225
3306
|
static async find(value) {
|
|
3226
3307
|
if (value === undefined || value === null) return null;
|
|
3227
|
-
|
|
3228
3308
|
const query = this.query();
|
|
3229
|
-
|
|
3230
3309
|
// If numeric → try primary key first
|
|
3231
3310
|
if (!isNaN(value)) {
|
|
3232
3311
|
const row = await query.where(this.primaryKey, value).first();
|
|
3233
3312
|
if (row) return row;
|
|
3234
3313
|
}
|
|
3235
|
-
|
|
3236
3314
|
// Fallback or non-numeric → try slug
|
|
3237
3315
|
return await this.query()
|
|
3238
3316
|
.where(this.slugKey, value)
|