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 CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
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
- where(key: any, value: any): Collection;
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: any;
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: any;
552
- get(key: any): any;
553
- set(key: any, value: any, ttl?: any): void;
554
- has(key: any): any;
555
- delete(key: any): any;
556
- clear(): void;
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
- * Get value or compute + store it
559
- * Supports async functions
568
+ * Set cache value
569
+ * @param {string} key
570
+ * @param {*} value
571
+ * @param {number} ttl Optional TTL in ms
560
572
  */
561
- getOrSet(key: any, fetchFn: any, ttl?: any): Promise<any>;
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
- * Basic cache stats
584
+ * Get cache stats (optional utility)
564
585
  */
565
586
  stats(): {
566
- size: any;
567
- calculatedSize: any;
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
- max = 1000, // max number of items
36
- ttl = 0, // default TTL (ms)
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
- max,
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
- updateAgeOnGet: false,
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
- set(key, value, ttl = null) {
58
- if (ttl !== null) {
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
- has(key) {
66
- return this.cache.has(key);
67
- }
68
-
69
- delete(key) {
70
- return this.cache.delete(key);
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
- * Get value or compute + store it
79
- * Supports async functions
90
+ * Clear entire cache
80
91
  */
81
- async getOrSet(key, fetchFn, ttl = null) {
82
- const existing = this.get(key);
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
- * Basic cache stats
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({ max: 1000, ttl: 60_000 });
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
- where(key, value) {
933
- return new Collection(this.filter(item => item?.[key] === value));
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 new Collection(this.filter(item => item?.[key] !== value));
1006
+ return this.filter(item => item?.[key] !== value);
938
1007
  }
939
1008
 
940
1009
  filterNull() {
941
- return new Collection(this.filter(v => v !== null && v !== undefined));
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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lamix",
3
- "version": "4.2.18",
3
+ "version": "4.2.20",
4
4
  "description": "lamix - ORM for Node-express js",
5
5
  "main": "./lib",
6
6
  "type": "commonjs",